mirror of https://github.com/ghostfolio/ghostfolio
21 changed files with 111 additions and 193 deletions
@ -0,0 +1,41 @@ |
|||
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; |
|||
import { ImpersonationGuard } from '@ghostfolio/api/guards/impersonation.guard'; |
|||
import { ScopeGuard } from '@ghostfolio/api/guards/scope.guard'; |
|||
import { scopes } from '@ghostfolio/common/scopes'; |
|||
|
|||
import { GUARDS_METADATA } from '@nestjs/common/constants'; |
|||
import { AuthGuard } from '@nestjs/passport'; |
|||
|
|||
import { REQUIRES_SCOPE_KEY, RequiresScope } from './requires-scope.decorator'; |
|||
|
|||
class TestController { |
|||
@RequiresScope(scopes.portfolioRead) |
|||
public getPortfolio() { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
describe('Requires scope', () => { |
|||
it('Sets the required scopes', () => { |
|||
expect( |
|||
Reflect.getMetadata( |
|||
REQUIRES_SCOPE_KEY, |
|||
TestController.prototype.getPortfolio |
|||
) |
|||
).toEqual([scopes.portfolioRead]); |
|||
}); |
|||
|
|||
it('Applies the guards in the required order', () => { |
|||
expect( |
|||
Reflect.getMetadata( |
|||
GUARDS_METADATA, |
|||
TestController.prototype.getPortfolio |
|||
) |
|||
).toEqual([ |
|||
AuthGuard('jwt'), |
|||
HasPermissionGuard, |
|||
ImpersonationGuard, |
|||
ScopeGuard |
|||
]); |
|||
}); |
|||
}); |
|||
@ -1,12 +1,26 @@ |
|||
import { SetMetadata } from '@nestjs/common'; |
|||
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; |
|||
import { ImpersonationGuard } from '@ghostfolio/api/guards/impersonation.guard'; |
|||
import { ScopeGuard } from '@ghostfolio/api/guards/scope.guard'; |
|||
import { Scope } from '@ghostfolio/common/scopes'; |
|||
|
|||
import { applyDecorators, SetMetadata, UseGuards } from '@nestjs/common'; |
|||
import { AuthGuard } from '@nestjs/passport'; |
|||
|
|||
export const REQUIRES_SCOPE_KEY = 'requires_scope'; |
|||
|
|||
/** |
|||
* Marks a controller or a route which requires the given scopes of the |
|||
* impersonation context, which requires the ImpersonationGuard and the |
|||
* ScopeGuard to be applied to the route |
|||
* Marks a route which requires the given scopes and applies the guards which |
|||
* resolve the impersonation context and evaluate it, hence the ScopeGuard |
|||
* cannot be applied without the ImpersonationGuard preceding it |
|||
*/ |
|||
export function RequiresScope(...requiredScopes: string[]) { |
|||
return SetMetadata(REQUIRES_SCOPE_KEY, requiredScopes); |
|||
export function RequiresScope(...requiredScopes: Scope[]) { |
|||
return applyDecorators( |
|||
SetMetadata(REQUIRES_SCOPE_KEY, requiredScopes), |
|||
UseGuards( |
|||
AuthGuard('jwt'), |
|||
HasPermissionGuard, |
|||
ImpersonationGuard, |
|||
ScopeGuard |
|||
) |
|||
); |
|||
} |
|||
|
|||
@ -1,5 +1,6 @@ |
|||
import { Access } from '@ghostfolio/common/interfaces'; |
|||
|
|||
export interface CreateOrUpdateAccessDialogParams { |
|||
access?: Access; |
|||
// TODO: Include the scopes once the dialog allows to configure them
|
|||
access?: Omit<Access, 'scopes'>; |
|||
} |
|||
|
|||
Loading…
Reference in new issue