Browse Source

Merge branch 'main' into task/upgrade-nestjs-to-version-11.2

pull/7779/head
Thomas Kaul 7 days ago
committed by GitHub
parent
commit
d0973240f2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 5
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts
  3. 2
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
  4. 21
      libs/common/src/lib/scopes.ts

1
CHANGELOG.md

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Restricted the _Restricted view and manage_ permission of the access to share the portfolio to the Model Context Protocol (MCP) (experimental)
- Upgraded `nestjs` from version `11.1.28` to `11.2.1`
### Fixed

5
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 {
Scope,
canGrantRestrictedWriteAccess,
getAccessLevel,
getScopesOfAccess,
getScopesOfAccessLevel,
@ -125,6 +126,10 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
return this.hasExperimentalFeatures && this.hasPermissionToEnableMcp;
}
public get canGrantRestrictedWriteAccess() {
return canGrantRestrictedWriteAccess({ type: this.accessType });
}
public get canGrantWriteAccess() {
return this.hasExperimentalFeatures;
}

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">
<gf-access-level-icon accessLevel="READ_RESTRICTED" />
</mat-option>
@if (!isPublicAccess) {
@if (canGrantRestrictedWriteAccess) {
<mat-option
value="CREATE_READ_RESTRICTED_UPDATE_DELETE"
[disabled]="!canGrantWriteAccess"

21
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
* 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[]> = {
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
};
/**
* 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
*/
@ -96,9 +106,16 @@ export function getScopesOfAccess({
}): string[] {
const scopesToEvaluate = scopesOfAccess ?? [];
const permitsWriteAccess =
canGrantRestrictedWriteAccess({ type }) ||
hasScope(scopesToEvaluate, scopes.portfolioReadValues);
// An unknown scope is dropped
return SCOPES_OF_TYPE[type].filter((scope) => {
return scopesToEvaluate.includes(scope);
return (
scopesToEvaluate.includes(scope) &&
(permitsWriteAccess || !SCOPES_OF_WRITE_ACCESS.includes(scope))
);
});
}

Loading…
Cancel
Save