Browse Source

Restrict restricted view and manage permission to MCP

pull/7783/head
Thomas Kaul 1 month ago
parent
commit
657e32bdeb
  1. 30
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts
  2. 2
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
  3. 16
      libs/common/src/lib/scopes.ts

30
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts

@ -6,6 +6,7 @@ import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { import {
Scope, Scope,
canGrantRestrictedWriteAccess,
getAccessLevel, getAccessLevel,
getScopesOfAccess, getScopesOfAccess,
getScopesOfAccessLevel, getScopesOfAccessLevel,
@ -125,6 +126,10 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
return this.hasExperimentalFeatures && this.hasPermissionToEnableMcp; return this.hasExperimentalFeatures && this.hasPermissionToEnableMcp;
} }
public get canGrantRestrictedWriteAccess() {
return canGrantRestrictedWriteAccess({ type: this.accessType });
}
public get canGrantWriteAccess() { public get canGrantWriteAccess() {
return this.hasExperimentalFeatures; return this.hasExperimentalFeatures;
} }
@ -195,25 +200,16 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
// Narrow the permission to the scopes which the type permits, because // Narrow the permission to the scopes which the type permits, because
// an access which is not granted to a user never exposes the monetary // an access which is not granted to a user never exposes the monetary
// values and a public access never changes data. The type PRIVATE has // values and a public access never changes data
// no restricted write level, hence the permission to change the data this.accessForm.get('accessLevel')?.setValue(
// exposes the monetary values getAccessLevel(
const accessLevelOfType = getAccessLevel( getScopesOfAccess({
getScopesOfAccess({ scopes: getScopesOfAccessLevel(this.accessLevel),
scopes: getScopesOfAccessLevel(this.accessLevel), type: accessType
type: accessType })
}) )
); );
this.accessForm
.get('accessLevel')
?.setValue(
accessType === 'PRIVATE' &&
this.accessLevel === 'CREATE_READ_RESTRICTED_UPDATE_DELETE'
? 'CREATE_READ_UPDATE_DELETE'
: accessLevelOfType
);
if (!canApplyFiltersToAccess({ type: accessType })) { if (!canApplyFiltersToAccess({ type: accessType })) {
this.accessForm.get('filters')?.setValue(null); this.accessForm.get('filters')?.setValue(null);
} }

2
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html

@ -82,7 +82,7 @@
<mat-option value="READ_RESTRICTED"> <mat-option value="READ_RESTRICTED">
<gf-access-level-icon accessLevel="READ_RESTRICTED" /> <gf-access-level-icon accessLevel="READ_RESTRICTED" />
</mat-option> </mat-option>
@if (accessForm.get('type')?.value === 'MCP') { @if (canGrantRestrictedWriteAccess) {
<mat-option <mat-option
value="CREATE_READ_RESTRICTED_UPDATE_DELETE" value="CREATE_READ_RESTRICTED_UPDATE_DELETE"
[disabled]="!canGrantWriteAccess" [disabled]="!canGrantWriteAccess"

16
libs/common/src/lib/scopes.ts

@ -64,7 +64,9 @@ export const SCOPES_OF_READ_RESTRICTED_ACCESS: readonly Scope[] =
/** /**
* Maximum scopes per access type. The scopes stored on an access are * Maximum scopes per access type. The scopes stored on an access are
* intersected with it, hence a scope which the type does not permit stays * intersected with it, hence a scope which the type does not permit stays
* ineffective even if it is stored. * ineffective even if it is stored. A type which cannot grant the restricted
* write access drops the write scopes in addition, unless the access reads the
* monetary values.
*/ */
const SCOPES_OF_TYPE: Record<AccessType, readonly Scope[]> = { const SCOPES_OF_TYPE: Record<AccessType, readonly Scope[]> = {
MCP: [...SCOPES_OF_READ_RESTRICTED_ACCESS, scopes.activityCreate], MCP: [...SCOPES_OF_READ_RESTRICTED_ACCESS, scopes.activityCreate],
@ -72,6 +74,14 @@ const SCOPES_OF_TYPE: Record<AccessType, readonly Scope[]> = {
PUBLIC: SCOPES_OF_PUBLIC_ACCESS PUBLIC: SCOPES_OF_PUBLIC_ACCESS
}; };
/**
* Access types which combine a write scope with the restricted read access,
* because their tools change data without exposing the monetary values
*/
export function canGrantRestrictedWriteAccess({ type }: { type: AccessType }) {
return type === 'MCP';
}
/** /**
* Access level which the scopes of an access grant * Access level which the scopes of an access grant
*/ */
@ -96,10 +106,8 @@ export function getScopesOfAccess({
}): string[] { }): string[] {
const scopesToEvaluate = scopesOfAccess ?? []; const scopesToEvaluate = scopesOfAccess ?? [];
// The type PRIVATE has no restricted write level, hence a write scope stays
// ineffective without the scope to read the monetary values
const permitsWriteAccess = const permitsWriteAccess =
type !== 'PRIVATE' || canGrantRestrictedWriteAccess({ type }) ||
hasScope(scopesToEvaluate, scopes.portfolioReadValues); hasScope(scopesToEvaluate, scopes.portfolioReadValues);
// An unknown scope is dropped // An unknown scope is dropped

Loading…
Cancel
Save