You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

226 lines
6.7 KiB

import {
SCOPES_OF_READ_ACCESS,
SCOPES_OF_READ_RESTRICTED_ACCESS,
SCOPES_OF_WRITE_ACCESS,
getScopesOfAccess,
getScopesOfOwnAccess,
getScopesOfUnrestrictedImpersonation,
hasAnyScopeOfWriteAccess,
hasScope,
scopes
} from '@ghostfolio/common/scopes';
describe('Scopes', () => {
describe('Scopes of read access', () => {
// A new scope which reads data has to be added here deliberately, because
// an access which reads data receives this list
it('Covers every read scope', () => {
expect(SCOPES_OF_READ_ACCESS).toEqual([
scopes.accountRead,
scopes.activityRead,
scopes.portfolioRead,
scopes.portfolioReadValues,
scopes.watchlistRead
]);
});
});
describe('Scopes of write access', () => {
// A new scope which changes data has to be added here deliberately,
// because the ImpersonationWriteGuard blocks the writes it does not cover
it('Covers every write scope', () => {
expect(SCOPES_OF_WRITE_ACCESS).toEqual([
scopes.accountCreate,
scopes.accountDelete,
scopes.accountUpdate,
scopes.activityCreate,
scopes.activityDelete,
scopes.activityUpdate,
scopes.watchlistCreate,
scopes.watchlistDelete
]);
});
});
describe('Scopes of read and write access', () => {
// A new scope has to belong to exactly one of the two lists. A scope which
// belongs to neither list is granted to nobody, and a write scope which is
// missing from SCOPES_OF_WRITE_ACCESS is granted to every read access.
it('Cover every scope exactly once', () => {
const scopesOfReadAndWriteAccess = [
...SCOPES_OF_READ_ACCESS,
...SCOPES_OF_WRITE_ACCESS
].sort();
expect(scopesOfReadAndWriteAccess).toEqual(Object.values(scopes).sort());
});
});
describe('Get scopes of access', () => {
it('Gives the scopes of the access', () => {
expect(
getScopesOfAccess({
granteeUserId: 'ffb08949-2f8a-4b6e-88fd-0f1e6b6b5f5d',
scopes: [scopes.portfolioRead, scopes.portfolioReadValues]
})
).toEqual([scopes.portfolioRead, scopes.portfolioReadValues]);
});
it('Without the scope to read the values', () => {
expect(
getScopesOfAccess({
granteeUserId: 'ffb08949-2f8a-4b6e-88fd-0f1e6b6b5f5d',
scopes: [scopes.portfolioRead]
})
).not.toContain(scopes.portfolioReadValues);
});
it('Without scopes', () => {
expect(
getScopesOfAccess({
granteeUserId: 'ffb08949-2f8a-4b6e-88fd-0f1e6b6b5f5d'
})
).toEqual([]);
});
it('Gives the write scopes', () => {
const scopesOfAccess = getScopesOfAccess({
granteeUserId: 'ffb08949-2f8a-4b6e-88fd-0f1e6b6b5f5d',
scopes: [...SCOPES_OF_READ_ACCESS, ...SCOPES_OF_WRITE_ACCESS]
});
for (const scope of SCOPES_OF_WRITE_ACCESS) {
expect(scopesOfAccess).toContain(scope);
}
});
it('Drops an unknown scope', () => {
expect(
getScopesOfAccess({
granteeUserId: 'ffb08949-2f8a-4b6e-88fd-0f1e6b6b5f5d',
scopes: [scopes.portfolioRead, 'portfolio:write']
})
).toEqual([scopes.portfolioRead]);
});
});
describe('Get scopes of public access', () => {
it('Allows reading the portfolio', () => {
expect(
getScopesOfAccess({ scopes: [...SCOPES_OF_READ_RESTRICTED_ACCESS] })
).toContain(scopes.portfolioRead);
});
it('Excludes the accounts and the watchlist', () => {
const scopesOfAccess = getScopesOfAccess({
scopes: [...SCOPES_OF_READ_RESTRICTED_ACCESS]
});
expect(scopesOfAccess).not.toContain(scopes.accountRead);
expect(scopesOfAccess).not.toContain(scopes.watchlistRead);
});
it('Cannot be widened by the scopes', () => {
expect(
getScopesOfAccess({
scopes: [
scopes.portfolioRead,
scopes.portfolioReadValues,
scopes.watchlistRead
]
})
).toEqual([scopes.portfolioRead]);
});
it('Cannot expose the monetary values', () => {
expect(
getScopesOfAccess({ scopes: [...SCOPES_OF_READ_ACCESS] })
).not.toContain(scopes.portfolioReadValues);
});
// The dialog offers the write scopes for a private access only, hence this
// function is the sole barrier for a public access
it('Gives no write scope', () => {
expect(
getScopesOfAccess({ scopes: [...SCOPES_OF_WRITE_ACCESS] })
).toEqual([]);
});
});
describe('Get scopes of own access', () => {
// A new scope has to be added here deliberately to confirm that it is
// granted to the owner of the data
it('Covers every scope', () => {
expect(getScopesOfOwnAccess()).toEqual([
scopes.accountCreate,
scopes.accountDelete,
scopes.accountRead,
scopes.accountUpdate,
scopes.activityCreate,
scopes.activityDelete,
scopes.activityRead,
scopes.activityUpdate,
scopes.portfolioRead,
scopes.portfolioReadValues,
scopes.watchlistCreate,
scopes.watchlistDelete,
scopes.watchlistRead
]);
});
});
describe('Get scopes of unrestricted impersonation', () => {
// A new scope has to be added here deliberately to confirm that it is
// granted to an administrator impersonating an arbitrary user
it('Covers every read scope but the monetary values', () => {
expect(getScopesOfUnrestrictedImpersonation()).toEqual([
scopes.accountRead,
scopes.activityRead,
scopes.portfolioRead,
scopes.watchlistRead
]);
});
it('Gives no write scope', () => {
const scopesOfImpersonation = getScopesOfUnrestrictedImpersonation();
for (const scope of SCOPES_OF_WRITE_ACCESS) {
expect(scopesOfImpersonation).not.toContain(scope);
}
});
});
describe('Has any scope of write access', () => {
it('Single write scope', () => {
expect(hasAnyScopeOfWriteAccess([scopes.activityUpdate])).toEqual(true);
});
it('Read scopes only', () => {
expect(hasAnyScopeOfWriteAccess([...SCOPES_OF_READ_ACCESS])).toEqual(
false
);
});
it('Without scopes', () => {
expect(hasAnyScopeOfWriteAccess(undefined)).toEqual(false);
});
});
describe('Has scope', () => {
it('Present scope', () => {
expect(hasScope([scopes.portfolioRead], scopes.portfolioRead)).toEqual(
true
);
});
it('Absent scope', () => {
expect(
hasScope([scopes.portfolioRead], scopes.portfolioReadValues)
).toEqual(false);
});
it('Without scopes', () => {
expect(hasScope(undefined, scopes.portfolioRead)).toEqual(false);
});
});
});