@twin.org/identity-service 0.11.0 → 0.11.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
  // Copyright 2024 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
- import { BaseError, GeneralError, Guards, Is, NotFoundError } from "@twin.org/core";
3
+ import { HttpContextIdKeys, ScopeHelper } from "@twin.org/api-models";
4
+ import { ContextIdStore } from "@twin.org/context";
5
+ import { BaseError, GeneralError, Guards, Is, NotFoundError, ObjectHelper, UnauthorizedError } from "@twin.org/core";
4
6
  import { IdentityProfileConnectorFactory } from "@twin.org/identity-models";
5
7
  import { IdentityService } from "./identityService.js";
6
8
  /**
@@ -16,12 +18,24 @@ export class IdentityProfileService {
16
18
  * @internal
17
19
  */
18
20
  _identityProfileConnector;
21
+ /**
22
+ * The profile properties which can only be modified with an admin scope.
23
+ * @internal
24
+ */
25
+ _selfUpdateDeniedProperties;
26
+ /**
27
+ * The scopes which allow the denied properties to be modified.
28
+ * @internal
29
+ */
30
+ _adminScopes;
19
31
  /**
20
32
  * Create a new instance of IdentityProfileService.
21
33
  * @param options The dependencies for the identity profile service.
22
34
  */
23
35
  constructor(options) {
24
36
  this._identityProfileConnector = IdentityProfileConnectorFactory.get(options?.profileEntityConnectorType ?? "identity-profile");
37
+ this._selfUpdateDeniedProperties = options?.config?.selfUpdateDeniedProperties ?? [];
38
+ this._adminScopes = options?.config?.adminScopes ?? ["user-admin", "global-admin"];
25
39
  }
26
40
  /**
27
41
  * Returns the class name of the component.
@@ -40,6 +54,7 @@ export class IdentityProfileService {
40
54
  async create(publicProfile, privateProfile, identity) {
41
55
  Guards.stringValue(IdentityProfileService.CLASS_NAME, "identity", identity);
42
56
  try {
57
+ await this.assertSelfUpdateAllowed(identity, undefined, publicProfile, privateProfile);
43
58
  await this._identityProfileConnector.create(identity, publicProfile, privateProfile);
44
59
  }
45
60
  catch (error) {
@@ -112,6 +127,7 @@ export class IdentityProfileService {
112
127
  if (Is.undefined(result)) {
113
128
  throw new NotFoundError(IdentityProfileService.CLASS_NAME, "notFound", identity);
114
129
  }
130
+ await this.assertSelfUpdateAllowed(identity, result, publicProfile, privateProfile);
115
131
  await this._identityProfileConnector.update(identity, publicProfile, privateProfile);
116
132
  }
117
133
  catch (error) {
@@ -185,5 +201,51 @@ export class IdentityProfileService {
185
201
  throw new GeneralError(IdentityProfileService.CLASS_NAME, "listAdminFailed", undefined, error);
186
202
  }
187
203
  }
204
+ /**
205
+ * Reject changes to denied properties when the caller does not have an admin scope.
206
+ * @param identity The identity of the profile being modified.
207
+ * @param existing The currently stored profile.
208
+ * @param publicProfile The new public profile, undefined leaves the stored profile unchanged.
209
+ * @param privateProfile The new private profile, undefined leaves the stored profile unchanged.
210
+ * @internal
211
+ */
212
+ async assertSelfUpdateAllowed(identity, existing, publicProfile, privateProfile) {
213
+ // If there are no self-update denied properties, any update is allowed.
214
+ if (this._selfUpdateDeniedProperties.length === 0) {
215
+ return;
216
+ }
217
+ // If the user has one of the admin scopes, they are allowed to update denied properties, so just return.
218
+ const contextIds = await ContextIdStore.getContextIds();
219
+ if (this._adminScopes.some(adminScope => ScopeHelper.includes(contextIds?.[HttpContextIdKeys.Scope], adminScope))) {
220
+ return;
221
+ }
222
+ const deniedProperties = [
223
+ ...this.findChangedProperties("publicProfile", existing?.publicProfile, publicProfile),
224
+ ...this.findChangedProperties("privateProfile", existing?.privateProfile, privateProfile)
225
+ ];
226
+ if (deniedProperties.length > 0) {
227
+ throw new UnauthorizedError(IdentityProfileService.CLASS_NAME, "selfUpdateDenied", {
228
+ identity,
229
+ properties: deniedProperties.join(", ")
230
+ });
231
+ }
232
+ }
233
+ /**
234
+ * Find the denied properties which differ between the stored and new profile.
235
+ * @param profileName The name of the profile used to prefix the property names.
236
+ * @param existingProfile The currently stored profile.
237
+ * @param profile The new profile, undefined leaves the stored profile unchanged.
238
+ * @returns The prefixed names of the changed denied properties.
239
+ * @internal
240
+ */
241
+ findChangedProperties(profileName, existingProfile, profile) {
242
+ if (!Is.object(profile)) {
243
+ return [];
244
+ }
245
+ const hasExisting = Is.objectValue(existingProfile);
246
+ return this._selfUpdateDeniedProperties
247
+ .filter(propertyName => !ObjectHelper.equal(hasExisting ? ObjectHelper.propertyGet(existingProfile, propertyName) : undefined, ObjectHelper.propertyGet(profile, propertyName), false))
248
+ .map(propertyName => `${profileName}.${propertyName}`);
249
+ }
188
250
  }
189
251
  //# sourceMappingURL=identityProfileService.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"identityProfileService.js","sourceRoot":"","sources":["../../src/identityProfileService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { BaseError, GeneralError, Guards, Is, NotFoundError } from \"@twin.org/core\";\nimport type { IJsonLdDocument } from \"@twin.org/data-json-ld\";\nimport {\n\tIdentityProfileConnectorFactory,\n\ttype IIdentityProfileComponent,\n\ttype IIdentityProfileConnector\n} from \"@twin.org/identity-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { IdentityService } from \"./identityService.js\";\nimport type { IIdentityProfileServiceConstructorOptions } from \"./models/IIdentityProfileServiceConstructorOptions.js\";\n\n/**\n * Class which implements the identity profile contract.\n */\nexport class IdentityProfileService<\n\tT extends IJsonLdDocument = IJsonLdDocument,\n\tU extends IJsonLdDocument = IJsonLdDocument\n> implements IIdentityProfileComponent<T, U> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<IdentityProfileService>();\n\n\t/**\n\t * The identity profile connector.\n\t * @internal\n\t */\n\tprivate readonly _identityProfileConnector: IIdentityProfileConnector<T, U>;\n\n\t/**\n\t * Create a new instance of IdentityProfileService.\n\t * @param options The dependencies for the identity profile service.\n\t */\n\tconstructor(options?: IIdentityProfileServiceConstructorOptions) {\n\t\tthis._identityProfileConnector = IdentityProfileConnectorFactory.get<\n\t\t\tIIdentityProfileConnector<T, U>\n\t\t>(options?.profileEntityConnectorType ?? \"identity-profile\");\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn IdentityService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Create the profile properties for an identity.\n\t * @param publicProfile The public profile data as JSON-LD.\n\t * @param privateProfile The private profile data as JSON-LD.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns A promise that resolves when the profile has been created.\n\t */\n\tpublic async create(publicProfile?: T, privateProfile?: U, identity?: string): Promise<void> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tawait this._identityProfileConnector.create(identity, publicProfile, privateProfile);\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"createFailed\",\n\t\t\t\t{ identity },\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get the profile properties for an identity.\n\t * @param publicPropertyNames The public properties to get for the profile, defaults to all.\n\t * @param privatePropertyNames The private properties to get for the profile, defaults to all.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns The items identity and the properties.\n\t */\n\tpublic async get(\n\t\tpublicPropertyNames?: (keyof T)[],\n\t\tprivatePropertyNames?: (keyof U)[],\n\t\tidentity?: string\n\t): Promise<{\n\t\tidentity: string;\n\t\tpublicProfile?: Partial<T>;\n\t\tprivateProfile?: Partial<U>;\n\t}> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(\n\t\t\t\tidentity,\n\t\t\t\tpublicPropertyNames,\n\t\t\t\tprivatePropertyNames\n\t\t\t);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tidentity,\n\t\t\t\tpublicProfile: result.publicProfile,\n\t\t\t\tprivateProfile: result.privateProfile\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(IdentityProfileService.CLASS_NAME, \"getFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Get the public profile properties for an identity.\n\t * @param identity The identity to perform the profile operation on.\n\t * @param propertyNames The properties to get for the item, defaults to all.\n\t * @returns The items properties.\n\t */\n\tpublic async getPublic(identity: string, propertyNames?: (keyof T)[]): Promise<Partial<T>> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(identity, propertyNames);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\treturn result.publicProfile;\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"getPublicFailed\",\n\t\t\t\tundefined,\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Update the profile properties of an identity.\n\t * @param publicProfile The public profile data as JSON-LD.\n\t * @param privateProfile The private profile data as JSON-LD.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns A promise that resolves when the profile has been updated.\n\t */\n\tpublic async update(publicProfile?: T, privateProfile?: U, identity?: string): Promise<void> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(identity);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\tawait this._identityProfileConnector.update(identity, publicProfile, privateProfile);\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"updateFailed\",\n\t\t\t\t{ identity },\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Delete the profile for an identity.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns A promise that resolves when the profile has been removed.\n\t */\n\tpublic async remove(identity?: string): Promise<void> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(identity);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\tawait this._identityProfileConnector.remove(identity);\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"removeFailed\",\n\t\t\t\t{ identity },\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get a list of the requested types.\n\t * @param publicFilters The filters to apply to the identities public profiles.\n\t * @param publicPropertyNames The public properties to get for the profile, defaults to all.\n\t * @param cursor The cursor for paged requests.\n\t * @param limit The maximum number of items in a page.\n\t * @returns The list of items and cursor for paging.\n\t */\n\tpublic async list(\n\t\tpublicFilters?: {\n\t\t\tpropertyName: string;\n\t\t\tpropertyValue: unknown;\n\t\t}[],\n\t\tpublicPropertyNames?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The identities.\n\t\t */\n\t\titems: { identity: string; publicProfile?: Partial<T> }[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\ttry {\n\t\t\t// We don't want to return private profile for this type of query\n\t\t\t// as it would expose the values to the REST api\n\t\t\tconst result = await this._identityProfileConnector.list(\n\t\t\t\tpublicFilters,\n\t\t\t\tundefined,\n\t\t\t\tpublicPropertyNames,\n\t\t\t\tundefined,\n\t\t\t\tcursor,\n\t\t\t\tlimit\n\t\t\t);\n\t\t\treturn {\n\t\t\t\titems: result.items.map(item => ({\n\t\t\t\t\tidentity: item.identity,\n\t\t\t\t\tpublicProfile: item.publicProfile\n\t\t\t\t})),\n\t\t\t\tcursor: result.cursor\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(IdentityProfileService.CLASS_NAME, \"listFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Get a list of identities including private profile data.\n\t * @param publicFilters The filters to apply to the identities public profiles.\n\t * @param privateFilters The filters to apply to the identities private profiles.\n\t * @param publicPropertyNames The public properties to get for the profile, defaults to all.\n\t * @param privatePropertyNames The private properties to get for the profile, defaults to none.\n\t * @param cursor The cursor for paged requests.\n\t * @param limit The maximum number of items in a page.\n\t * @returns The list of items and cursor for paging.\n\t */\n\tpublic async listAdmin(\n\t\tpublicFilters?: {\n\t\t\tpropertyName: string;\n\t\t\tpropertyValue: unknown;\n\t\t}[],\n\t\tprivateFilters?: {\n\t\t\tpropertyName: string;\n\t\t\tpropertyValue: unknown;\n\t\t}[],\n\t\tpublicPropertyNames?: (keyof T)[],\n\t\tprivatePropertyNames?: (keyof U)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The identities.\n\t\t */\n\t\titems: { identity: string; publicProfile?: Partial<T>; privateProfile?: Partial<U> }[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\ttry {\n\t\t\treturn await this._identityProfileConnector.list(\n\t\t\t\tpublicFilters,\n\t\t\t\tprivateFilters,\n\t\t\t\tpublicPropertyNames,\n\t\t\t\tprivatePropertyNames,\n\t\t\t\tcursor,\n\t\t\t\tlimit\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"listAdminFailed\",\n\t\t\t\tundefined,\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"identityProfileService.js","sourceRoot":"","sources":["../../src/identityProfileService.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACN,SAAS,EACT,YAAY,EACZ,MAAM,EACN,EAAE,EACF,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACN,+BAA+B,EAG/B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;GAEG;AACH,MAAM,OAAO,sBAAsB;IAIlC;;OAEG;IACI,MAAM,CAAU,UAAU,4BAA4C;IAE7E;;;OAGG;IACc,yBAAyB,CAAkC;IAE5E;;;OAGG;IACc,2BAA2B,CAAW;IAEvD;;;OAGG;IACc,YAAY,CAAW;IAExC;;;OAGG;IACH,YAAY,OAAmD;QAC9D,IAAI,CAAC,yBAAyB,GAAG,+BAA+B,CAAC,GAAG,CAElE,OAAO,EAAE,0BAA0B,IAAI,kBAAkB,CAAC,CAAC;QAC7D,IAAI,CAAC,2BAA2B,GAAG,OAAO,EAAE,MAAM,EAAE,0BAA0B,IAAI,EAAE,CAAC;QACrF,IAAI,CAAC,YAAY,GAAG,OAAO,EAAE,MAAM,EAAE,WAAW,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IACpF,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,eAAe,CAAC,UAAU,CAAC;IACnC,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,MAAM,CAAC,aAAiB,EAAE,cAAkB,EAAE,QAAiB;QAC3E,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAElF,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;YACvF,MAAM,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;QACtF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxE,MAAM,KAAK,CAAC;YACb,CAAC;YACD,MAAM,IAAI,YAAY,CACrB,sBAAsB,CAAC,UAAU,EACjC,cAAc,EACd,EAAE,QAAQ,EAAE,EACZ,KAAK,CACL,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,GAAG,CACf,mBAAiC,EACjC,oBAAkC,EAClC,QAAiB;QAMjB,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAElF,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,GAAG,CACtD,QAAQ,EACR,mBAAmB,EACnB,oBAAoB,CACpB,CAAC;YACF,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,aAAa,CAAC,sBAAsB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAClF,CAAC;YACD,OAAO;gBACN,QAAQ;gBACR,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,cAAc,EAAE,MAAM,CAAC,cAAc;aACrC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxE,MAAM,KAAK,CAAC;YACb,CAAC;YACD,MAAM,IAAI,YAAY,CAAC,sBAAsB,CAAC,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC1F,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,aAA2B;QACnE,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAElF,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YACjF,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,aAAa,CAAC,sBAAsB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAClF,CAAC;YACD,OAAO,MAAM,CAAC,aAAa,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxE,MAAM,KAAK,CAAC;YACb,CAAC;YACD,MAAM,IAAI,YAAY,CACrB,sBAAsB,CAAC,UAAU,EACjC,iBAAiB,EACjB,SAAS,EACT,KAAK,CACL,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,MAAM,CAAC,aAAiB,EAAE,cAAkB,EAAE,QAAiB;QAC3E,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAElF,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,aAAa,CAAC,sBAAsB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAClF,CAAC;YACD,MAAM,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;YACpF,MAAM,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;QACtF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxE,MAAM,KAAK,CAAC;YACb,CAAC;YACD,MAAM,IAAI,YAAY,CACrB,sBAAsB,CAAC,UAAU,EACjC,cAAc,EACd,EAAE,QAAQ,EAAE,EACZ,KAAK,CACL,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,MAAM,CAAC,QAAiB;QACpC,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAElF,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,aAAa,CAAC,sBAAsB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAClF,CAAC;YACD,MAAM,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxE,MAAM,KAAK,CAAC;YACb,CAAC;YACD,MAAM,IAAI,YAAY,CACrB,sBAAsB,CAAC,UAAU,EACjC,cAAc,EACd,EAAE,QAAQ,EAAE,EACZ,KAAK,CACL,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,IAAI,CAChB,aAGG,EACH,mBAAiC,EACjC,MAAe,EACf,KAAc;QAWd,IAAI,CAAC;YACJ,iEAAiE;YACjE,gDAAgD;YAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,IAAI,CACvD,aAAa,EACb,SAAS,EACT,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,KAAK,CACL,CAAC;YACF,OAAO;gBACN,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,aAAa,EAAE,IAAI,CAAC,aAAa;iBACjC,CAAC,CAAC;gBACH,MAAM,EAAE,MAAM,CAAC,MAAM;aACrB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,YAAY,CAAC,sBAAsB,CAAC,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC3F,CAAC;IACF,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,SAAS,CACrB,aAGG,EACH,cAGG,EACH,mBAAiC,EACjC,oBAAkC,EAClC,MAAe,EACf,KAAc;QAWd,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAC/C,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,MAAM,EACN,KAAK,CACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,YAAY,CACrB,sBAAsB,CAAC,UAAU,EACjC,iBAAiB,EACjB,SAAS,EACT,KAAK,CACL,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,uBAAuB,CACpC,QAAgB,EAChB,QAAiF,EACjF,aAA4B,EAC5B,cAA6B;QAE7B,wEAAwE;QACxE,IAAI,IAAI,CAAC,2BAA2B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,OAAO;QACR,CAAC;QAED,yGAAyG;QACzG,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,IACC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CACnC,WAAW,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CACvE,EACA,CAAC;YACF,OAAO;QACR,CAAC;QAED,MAAM,gBAAgB,GAAG;YACxB,GAAG,IAAI,CAAC,qBAAqB,CAAC,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,CAAC;YACtF,GAAG,IAAI,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,CAAC;SACzF,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,iBAAiB,CAAC,sBAAsB,CAAC,UAAU,EAAE,kBAAkB,EAAE;gBAClF,QAAQ;gBACR,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;aACvC,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACK,qBAAqB,CAC5B,WAAmB,EACnB,eAAuC,EACvC,OAAsB;QAEtB,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,WAAW,GAAG,EAAE,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QAEpD,OAAO,IAAI,CAAC,2BAA2B;aACrC,MAAM,CACN,YAAY,CAAC,EAAE,CACd,CAAC,YAAY,CAAC,KAAK,CAClB,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EACjF,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,EAC/C,KAAK,CACL,CACF;aACA,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,WAAW,IAAI,YAAY,EAAE,CAAC,CAAC;IACzD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { HttpContextIdKeys, ScopeHelper } from \"@twin.org/api-models\";\nimport { ContextIdStore } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tNotFoundError,\n\tObjectHelper,\n\tUnauthorizedError\n} from \"@twin.org/core\";\nimport type { IJsonLdDocument } from \"@twin.org/data-json-ld\";\nimport {\n\tIdentityProfileConnectorFactory,\n\ttype IIdentityProfileComponent,\n\ttype IIdentityProfileConnector\n} from \"@twin.org/identity-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { IdentityService } from \"./identityService.js\";\nimport type { IIdentityProfileServiceConstructorOptions } from \"./models/IIdentityProfileServiceConstructorOptions.js\";\n\n/**\n * Class which implements the identity profile contract.\n */\nexport class IdentityProfileService<\n\tT extends IJsonLdDocument = IJsonLdDocument,\n\tU extends IJsonLdDocument = IJsonLdDocument\n> implements IIdentityProfileComponent<T, U> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<IdentityProfileService>();\n\n\t/**\n\t * The identity profile connector.\n\t * @internal\n\t */\n\tprivate readonly _identityProfileConnector: IIdentityProfileConnector<T, U>;\n\n\t/**\n\t * The profile properties which can only be modified with an admin scope.\n\t * @internal\n\t */\n\tprivate readonly _selfUpdateDeniedProperties: string[];\n\n\t/**\n\t * The scopes which allow the denied properties to be modified.\n\t * @internal\n\t */\n\tprivate readonly _adminScopes: string[];\n\n\t/**\n\t * Create a new instance of IdentityProfileService.\n\t * @param options The dependencies for the identity profile service.\n\t */\n\tconstructor(options?: IIdentityProfileServiceConstructorOptions) {\n\t\tthis._identityProfileConnector = IdentityProfileConnectorFactory.get<\n\t\t\tIIdentityProfileConnector<T, U>\n\t\t>(options?.profileEntityConnectorType ?? \"identity-profile\");\n\t\tthis._selfUpdateDeniedProperties = options?.config?.selfUpdateDeniedProperties ?? [];\n\t\tthis._adminScopes = options?.config?.adminScopes ?? [\"user-admin\", \"global-admin\"];\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn IdentityService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Create the profile properties for an identity.\n\t * @param publicProfile The public profile data as JSON-LD.\n\t * @param privateProfile The private profile data as JSON-LD.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns A promise that resolves when the profile has been created.\n\t */\n\tpublic async create(publicProfile?: T, privateProfile?: U, identity?: string): Promise<void> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tawait this.assertSelfUpdateAllowed(identity, undefined, publicProfile, privateProfile);\n\t\t\tawait this._identityProfileConnector.create(identity, publicProfile, privateProfile);\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"createFailed\",\n\t\t\t\t{ identity },\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get the profile properties for an identity.\n\t * @param publicPropertyNames The public properties to get for the profile, defaults to all.\n\t * @param privatePropertyNames The private properties to get for the profile, defaults to all.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns The items identity and the properties.\n\t */\n\tpublic async get(\n\t\tpublicPropertyNames?: (keyof T)[],\n\t\tprivatePropertyNames?: (keyof U)[],\n\t\tidentity?: string\n\t): Promise<{\n\t\tidentity: string;\n\t\tpublicProfile?: Partial<T>;\n\t\tprivateProfile?: Partial<U>;\n\t}> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(\n\t\t\t\tidentity,\n\t\t\t\tpublicPropertyNames,\n\t\t\t\tprivatePropertyNames\n\t\t\t);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tidentity,\n\t\t\t\tpublicProfile: result.publicProfile,\n\t\t\t\tprivateProfile: result.privateProfile\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(IdentityProfileService.CLASS_NAME, \"getFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Get the public profile properties for an identity.\n\t * @param identity The identity to perform the profile operation on.\n\t * @param propertyNames The properties to get for the item, defaults to all.\n\t * @returns The items properties.\n\t */\n\tpublic async getPublic(identity: string, propertyNames?: (keyof T)[]): Promise<Partial<T>> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(identity, propertyNames);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\treturn result.publicProfile;\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"getPublicFailed\",\n\t\t\t\tundefined,\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Update the profile properties of an identity.\n\t * @param publicProfile The public profile data as JSON-LD.\n\t * @param privateProfile The private profile data as JSON-LD.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns A promise that resolves when the profile has been updated.\n\t */\n\tpublic async update(publicProfile?: T, privateProfile?: U, identity?: string): Promise<void> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(identity);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\tawait this.assertSelfUpdateAllowed(identity, result, publicProfile, privateProfile);\n\t\t\tawait this._identityProfileConnector.update(identity, publicProfile, privateProfile);\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"updateFailed\",\n\t\t\t\t{ identity },\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Delete the profile for an identity.\n\t * @param identity The identity to perform the profile operation on.\n\t * @returns A promise that resolves when the profile has been removed.\n\t */\n\tpublic async remove(identity?: string): Promise<void> {\n\t\tGuards.stringValue(IdentityProfileService.CLASS_NAME, nameof(identity), identity);\n\n\t\ttry {\n\t\t\tconst result = await this._identityProfileConnector.get(identity);\n\t\t\tif (Is.undefined(result)) {\n\t\t\t\tthrow new NotFoundError(IdentityProfileService.CLASS_NAME, \"notFound\", identity);\n\t\t\t}\n\t\t\tawait this._identityProfileConnector.remove(identity);\n\t\t} catch (error) {\n\t\t\tif (BaseError.someErrorClass(error, IdentityProfileService.CLASS_NAME)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"removeFailed\",\n\t\t\t\t{ identity },\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get a list of the requested types.\n\t * @param publicFilters The filters to apply to the identities public profiles.\n\t * @param publicPropertyNames The public properties to get for the profile, defaults to all.\n\t * @param cursor The cursor for paged requests.\n\t * @param limit The maximum number of items in a page.\n\t * @returns The list of items and cursor for paging.\n\t */\n\tpublic async list(\n\t\tpublicFilters?: {\n\t\t\tpropertyName: string;\n\t\t\tpropertyValue: unknown;\n\t\t}[],\n\t\tpublicPropertyNames?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The identities.\n\t\t */\n\t\titems: { identity: string; publicProfile?: Partial<T> }[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\ttry {\n\t\t\t// We don't want to return private profile for this type of query\n\t\t\t// as it would expose the values to the REST api\n\t\t\tconst result = await this._identityProfileConnector.list(\n\t\t\t\tpublicFilters,\n\t\t\t\tundefined,\n\t\t\t\tpublicPropertyNames,\n\t\t\t\tundefined,\n\t\t\t\tcursor,\n\t\t\t\tlimit\n\t\t\t);\n\t\t\treturn {\n\t\t\t\titems: result.items.map(item => ({\n\t\t\t\t\tidentity: item.identity,\n\t\t\t\t\tpublicProfile: item.publicProfile\n\t\t\t\t})),\n\t\t\t\tcursor: result.cursor\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(IdentityProfileService.CLASS_NAME, \"listFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Get a list of identities including private profile data.\n\t * @param publicFilters The filters to apply to the identities public profiles.\n\t * @param privateFilters The filters to apply to the identities private profiles.\n\t * @param publicPropertyNames The public properties to get for the profile, defaults to all.\n\t * @param privatePropertyNames The private properties to get for the profile, defaults to none.\n\t * @param cursor The cursor for paged requests.\n\t * @param limit The maximum number of items in a page.\n\t * @returns The list of items and cursor for paging.\n\t */\n\tpublic async listAdmin(\n\t\tpublicFilters?: {\n\t\t\tpropertyName: string;\n\t\t\tpropertyValue: unknown;\n\t\t}[],\n\t\tprivateFilters?: {\n\t\t\tpropertyName: string;\n\t\t\tpropertyValue: unknown;\n\t\t}[],\n\t\tpublicPropertyNames?: (keyof T)[],\n\t\tprivatePropertyNames?: (keyof U)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The identities.\n\t\t */\n\t\titems: { identity: string; publicProfile?: Partial<T>; privateProfile?: Partial<U> }[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\ttry {\n\t\t\treturn await this._identityProfileConnector.list(\n\t\t\t\tpublicFilters,\n\t\t\t\tprivateFilters,\n\t\t\t\tpublicPropertyNames,\n\t\t\t\tprivatePropertyNames,\n\t\t\t\tcursor,\n\t\t\t\tlimit\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tIdentityProfileService.CLASS_NAME,\n\t\t\t\t\"listAdminFailed\",\n\t\t\t\tundefined,\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Reject changes to denied properties when the caller does not have an admin scope.\n\t * @param identity The identity of the profile being modified.\n\t * @param existing The currently stored profile.\n\t * @param publicProfile The new public profile, undefined leaves the stored profile unchanged.\n\t * @param privateProfile The new private profile, undefined leaves the stored profile unchanged.\n\t * @internal\n\t */\n\tprivate async assertSelfUpdateAllowed(\n\t\tidentity: string,\n\t\texisting: { publicProfile?: Partial<T>; privateProfile?: Partial<U> } | undefined,\n\t\tpublicProfile: T | undefined,\n\t\tprivateProfile: U | undefined\n\t): Promise<void> {\n\t\t// If there are no self-update denied properties, any update is allowed.\n\t\tif (this._selfUpdateDeniedProperties.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the user has one of the admin scopes, they are allowed to update denied properties, so just return.\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tif (\n\t\t\tthis._adminScopes.some(adminScope =>\n\t\t\t\tScopeHelper.includes(contextIds?.[HttpContextIdKeys.Scope], adminScope)\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst deniedProperties = [\n\t\t\t...this.findChangedProperties(\"publicProfile\", existing?.publicProfile, publicProfile),\n\t\t\t...this.findChangedProperties(\"privateProfile\", existing?.privateProfile, privateProfile)\n\t\t];\n\n\t\tif (deniedProperties.length > 0) {\n\t\t\tthrow new UnauthorizedError(IdentityProfileService.CLASS_NAME, \"selfUpdateDenied\", {\n\t\t\t\tidentity,\n\t\t\t\tproperties: deniedProperties.join(\", \")\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Find the denied properties which differ between the stored and new profile.\n\t * @param profileName The name of the profile used to prefix the property names.\n\t * @param existingProfile The currently stored profile.\n\t * @param profile The new profile, undefined leaves the stored profile unchanged.\n\t * @returns The prefixed names of the changed denied properties.\n\t * @internal\n\t */\n\tprivate findChangedProperties<V extends IJsonLdDocument>(\n\t\tprofileName: string,\n\t\texistingProfile: Partial<V> | undefined,\n\t\tprofile: V | undefined\n\t): string[] {\n\t\tif (!Is.object(profile)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst hasExisting = Is.objectValue(existingProfile);\n\n\t\treturn this._selfUpdateDeniedProperties\n\t\t\t.filter(\n\t\t\t\tpropertyName =>\n\t\t\t\t\t!ObjectHelper.equal(\n\t\t\t\t\t\thasExisting ? ObjectHelper.propertyGet(existingProfile, propertyName) : undefined,\n\t\t\t\t\t\tObjectHelper.propertyGet(profile, propertyName),\n\t\t\t\t\t\tfalse\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.map(propertyName => `${profileName}.${propertyName}`);\n\t}\n}\n"]}
package/dist/es/index.js CHANGED
@@ -6,6 +6,7 @@ export * from "./identityResolverRoutes.js";
6
6
  export * from "./identityResolverService.js";
7
7
  export * from "./identityRoutes.js";
8
8
  export * from "./identityService.js";
9
+ export * from "./models/IIdentityProfileServiceConfig.js";
9
10
  export * from "./models/IIdentityProfileServiceConstructorOptions.js";
10
11
  export * from "./models/IIdentityResolverServiceConfig.js";
11
12
  export * from "./models/IIdentityResolverServiceConstructorOptions.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uDAAuD,CAAC;AACtE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wDAAwD,CAAC;AACvE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sBAAsB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./identityProfileRoutes.js\";\nexport * from \"./identityProfileService.js\";\nexport * from \"./identityResolverRoutes.js\";\nexport * from \"./identityResolverService.js\";\nexport * from \"./identityRoutes.js\";\nexport * from \"./identityService.js\";\nexport * from \"./models/IIdentityProfileServiceConstructorOptions.js\";\nexport * from \"./models/IIdentityResolverServiceConfig.js\";\nexport * from \"./models/IIdentityResolverServiceConstructorOptions.js\";\nexport * from \"./models/IIdentityServiceConfig.js\";\nexport * from \"./models/IIdentityServiceConstructorOptions.js\";\nexport * from \"./restEntryPoints.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2CAA2C,CAAC;AAC1D,cAAc,uDAAuD,CAAC;AACtE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wDAAwD,CAAC;AACvE,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sBAAsB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./identityProfileRoutes.js\";\nexport * from \"./identityProfileService.js\";\nexport * from \"./identityResolverRoutes.js\";\nexport * from \"./identityResolverService.js\";\nexport * from \"./identityRoutes.js\";\nexport * from \"./identityService.js\";\nexport * from \"./models/IIdentityProfileServiceConfig.js\";\nexport * from \"./models/IIdentityProfileServiceConstructorOptions.js\";\nexport * from \"./models/IIdentityResolverServiceConfig.js\";\nexport * from \"./models/IIdentityResolverServiceConstructorOptions.js\";\nexport * from \"./models/IIdentityServiceConfig.js\";\nexport * from \"./models/IIdentityServiceConstructorOptions.js\";\nexport * from \"./restEntryPoints.js\";\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=IIdentityProfileServiceConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IIdentityProfileServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IIdentityProfileServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the Identity Profile Service.\n */\nexport interface IIdentityProfileServiceConfig {\n\t/**\n\t * The public and private profile properties which can only be added, changed or removed by callers with an admin scope.\n\t * @default []\n\t */\n\tselfUpdateDeniedProperties?: string[];\n\n\t/**\n\t * The scopes which allow the denied properties to be modified, any one is sufficient.\n\t * @default [\"user-admin\", \"global-admin\"]\n\t */\n\tadminScopes?: string[];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IIdentityProfileServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IIdentityProfileServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/**\n * Options for the identity profile service constructor.\n */\nexport interface IIdentityProfileServiceConstructorOptions {\n\t/**\n\t * The storage connector for the profiles.\n\t * @default identity-profile\n\t */\n\tprofileEntityConnectorType?: string;\n}\n"]}
1
+ {"version":3,"file":"IIdentityProfileServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IIdentityProfileServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IIdentityProfileServiceConfig } from \"./IIdentityProfileServiceConfig.js\";\n\n/**\n * Options for the identity profile service constructor.\n */\nexport interface IIdentityProfileServiceConstructorOptions {\n\t/**\n\t * The storage connector for the profiles.\n\t * @default identity-profile\n\t */\n\tprofileEntityConnectorType?: string;\n\n\t/**\n\t * The configuration for the identity profile service.\n\t */\n\tconfig?: IIdentityProfileServiceConfig;\n}\n"]}
@@ -4,6 +4,7 @@ export * from "./identityResolverRoutes.js";
4
4
  export * from "./identityResolverService.js";
5
5
  export * from "./identityRoutes.js";
6
6
  export * from "./identityService.js";
7
+ export * from "./models/IIdentityProfileServiceConfig.js";
7
8
  export * from "./models/IIdentityProfileServiceConstructorOptions.js";
8
9
  export * from "./models/IIdentityResolverServiceConfig.js";
9
10
  export * from "./models/IIdentityResolverServiceConstructorOptions.js";
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Configuration for the Identity Profile Service.
3
+ */
4
+ export interface IIdentityProfileServiceConfig {
5
+ /**
6
+ * The public and private profile properties which can only be added, changed or removed by callers with an admin scope.
7
+ * @default []
8
+ */
9
+ selfUpdateDeniedProperties?: string[];
10
+ /**
11
+ * The scopes which allow the denied properties to be modified, any one is sufficient.
12
+ * @default ["user-admin", "global-admin"]
13
+ */
14
+ adminScopes?: string[];
15
+ }
@@ -1,3 +1,4 @@
1
+ import type { IIdentityProfileServiceConfig } from "./IIdentityProfileServiceConfig.js";
1
2
  /**
2
3
  * Options for the identity profile service constructor.
3
4
  */
@@ -7,4 +8,8 @@ export interface IIdentityProfileServiceConstructorOptions {
7
8
  * @default identity-profile
8
9
  */
9
10
  profileEntityConnectorType?: string;
11
+ /**
12
+ * The configuration for the identity profile service.
13
+ */
14
+ config?: IIdentityProfileServiceConfig;
10
15
  }
package/docs/changelog.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.1-next.1](https://github.com/iotaledger/twin-identity/compare/identity-service-v0.11.1-next.0...identity-service-v0.11.1-next.1) (2026-10-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * add addAlsoKnownAs to identity connector ([#117](https://github.com/iotaledger/twin-identity/issues/117)) ([aa27cff](https://github.com/iotaledger/twin-identity/commit/aa27cff88e61e7c8c6e32aeb437fb01c6ee9f57a))
9
+ * add context id features ([#62](https://github.com/iotaledger/twin-identity/issues/62)) ([e02ecca](https://github.com/iotaledger/twin-identity/commit/e02ecca9c45a849104bfbf7bc18a1f44e6eea8a1))
10
+ * add expiration date option to vc creation ([73e05e1](https://github.com/iotaledger/twin-identity/commit/73e05e1ae61112c7e056889969751f4ff82d9f29))
11
+ * add identity remove ([eebc13f](https://github.com/iotaledger/twin-identity/commit/eebc13f4c2cd994d2d9cce4da2128fb346c80ba7))
12
+ * add optional jwt payload and headers to vc and vp tokens ([#135](https://github.com/iotaledger/twin-identity/issues/135)) ([aa1de0f](https://github.com/iotaledger/twin-identity/commit/aa1de0f63be95ff62bae3c699aabc85ea93d74c2))
13
+ * add own-DID resolution caching to EntityStorageIdentityConnector ([#216](https://github.com/iotaledger/twin-identity/issues/216)) ([a4c170b](https://github.com/iotaledger/twin-identity/commit/a4c170be83d00f2bf53d70056321d53a3b22f940))
14
+ * add proof to vcs and verify vs documents ([#103](https://github.com/iotaledger/twin-identity/issues/103)) ([b60bf0c](https://github.com/iotaledger/twin-identity/commit/b60bf0cb7d453d67574c5c0e4f769e67cf7cd6d1))
15
+ * add telemetry metrics ([#132](https://github.com/iotaledger/twin-identity/issues/132)) ([b51cd78](https://github.com/iotaledger/twin-identity/commit/b51cd7816905fd55e250035daf1b8f2047cba83d))
16
+ * add validate-locales ([04d74b4](https://github.com/iotaledger/twin-identity/commit/04d74b4d1ebe42672e8ca75a7bdb8e3556afd0be))
17
+ * admin endpoints ([#199](https://github.com/iotaledger/twin-identity/issues/199)) ([da6c189](https://github.com/iotaledger/twin-identity/commit/da6c18963ed551451d919e36aedc1dd8b005a12f))
18
+ * application health ([#188](https://github.com/iotaledger/twin-identity/issues/188)) ([a7f0c3e](https://github.com/iotaledger/twin-identity/commit/a7f0c3e919d8a77b7d2661ec33742f1cc1889751))
19
+ * common connector tests ([4f9642c](https://github.com/iotaledger/twin-identity/commit/4f9642ceb09843870909fc6819bf69fb20ef952a))
20
+ * did resolver caching ([#220](https://github.com/iotaledger/twin-identity/issues/220)) ([fdcbf65](https://github.com/iotaledger/twin-identity/commit/fdcbf65fb6f9deef82e8c32a98835edaf6608e90))
21
+ * eslint migration to flat config ([fd6246d](https://github.com/iotaledger/twin-identity/commit/fd6246d566280b6d5d10a108eb1e92c4b510f2f2))
22
+ * expanded cli methods ([#121](https://github.com/iotaledger/twin-identity/issues/121)) ([80a52b7](https://github.com/iotaledger/twin-identity/commit/80a52b779237cd633d1f2813fa976585cef6e551))
23
+ * health and key removal ([934391f](https://github.com/iotaledger/twin-identity/commit/934391f9307beda34bc594e3aa506137e3df631b))
24
+ * health and key removal ([#191](https://github.com/iotaledger/twin-identity/issues/191)) ([8504101](https://github.com/iotaledger/twin-identity/commit/8504101a7a08b2a042a4e59f666c245308527088))
25
+ * identity key separator use slash ([1319d0d](https://github.com/iotaledger/twin-identity/commit/1319d0d07164a36b3ec279e6421b8835ffefc3d3))
26
+ * remove auth generator ([#98](https://github.com/iotaledger/twin-identity/issues/98)) ([a8969e8](https://github.com/iotaledger/twin-identity/commit/a8969e85a5a2804abfc787406e2d12eb168dd978))
27
+ * remove document key option ([#251](https://github.com/iotaledger/twin-identity/issues/251)) ([06d0141](https://github.com/iotaledger/twin-identity/commit/06d01414cae275702fe94b8b7694c43ca13a95f7))
28
+ * remove inline service tracing in favour of the tracing facade ([#228](https://github.com/iotaledger/twin-identity/issues/228)) ([583e587](https://github.com/iotaledger/twin-identity/commit/583e5873fa396b26207db5ac0ae9a1779866853c))
29
+ * remove skipAuth from routes ([a2f8921](https://github.com/iotaledger/twin-identity/commit/a2f892133360a25cb7b6668342e5dad852c3a908))
30
+ * remove unused namespace ([1987f72](https://github.com/iotaledger/twin-identity/commit/1987f72089be5ece10aa96b1fb9c386221c95c75))
31
+ * rest enhancements ([f2307ff](https://github.com/iotaledger/twin-identity/commit/f2307ff6605ba87ac5bf991bdaa69ac7d8bbd56d))
32
+ * separate vc verification routes with query and body ([ea7d891](https://github.com/iotaledger/twin-identity/commit/ea7d8910472150cf76dbd51e282625e70226d9b3))
33
+ * tracing ([#205](https://github.com/iotaledger/twin-identity/issues/205)) ([add81ab](https://github.com/iotaledger/twin-identity/commit/add81ab4a258078c34ef0c57681d1675c81f8e2c))
34
+ * typescript 6 update ([e8806ad](https://github.com/iotaledger/twin-identity/commit/e8806ad6858c37be3c0f54c41cf654023773bef3))
35
+ * update contexts ([#100](https://github.com/iotaledger/twin-identity/issues/100)) ([7c17f98](https://github.com/iotaledger/twin-identity/commit/7c17f983110b2fc5db1b19531d0b2a7c53e02aaa))
36
+ * update framework core ([c824497](https://github.com/iotaledger/twin-identity/commit/c82449709af0215eb7af496cf687c93fb30b5ae0))
37
+ * update namespaces and contexts ([#90](https://github.com/iotaledger/twin-identity/issues/90)) ([0c34d64](https://github.com/iotaledger/twin-identity/commit/0c34d64add8cca77856fa2d0357e774d72fbbfc1))
38
+ * update twindev schemas ([f5b2735](https://github.com/iotaledger/twin-identity/commit/f5b273561b52fa75e654e074927c164a465aa510))
39
+ * use new generateKid method ([f0fe779](https://github.com/iotaledger/twin-identity/commit/f0fe779323b675575bb9f80aa74f1957dc57a094))
40
+ * use shared store mechanism ([#27](https://github.com/iotaledger/twin-identity/issues/27)) ([ce41f3f](https://github.com/iotaledger/twin-identity/commit/ce41f3fc3da1b206ec06da7ea5b2c968f788804d))
41
+
42
+
43
+ ### Bug Fixes
44
+
45
+ * allow empty subject data in vc ([5bbf14e](https://github.com/iotaledger/twin-identity/commit/5bbf14eefd3c99b6cdca1af0ca741954d1b02cd3))
46
+ * identity controller check ([#240](https://github.com/iotaledger/twin-identity/issues/240)) ([6bb8bc4](https://github.com/iotaledger/twin-identity/commit/6bb8bc448d8fcd96280062eeb37abb08b2a28081))
47
+ * identity routes missing jwt fields ([b47470a](https://github.com/iotaledger/twin-identity/commit/b47470a8e59881d877c84f114892ee290d4254ca))
48
+ * identity subject type property ([#146](https://github.com/iotaledger/twin-identity/issues/146)) ([fe71dc6](https://github.com/iotaledger/twin-identity/commit/fe71dc66972120b42f1ff0e1dc8732cb48e1dd2a))
49
+ * Import path and bump version ([#21](https://github.com/iotaledger/twin-identity/issues/21)) ([ccea845](https://github.com/iotaledger/twin-identity/commit/ccea845bf32562267280bc1b3dde1c9af1a00360))
50
+ * Install sdk-wasm ([#20](https://github.com/iotaledger/twin-identity/issues/20)) ([75ec14e](https://github.com/iotaledger/twin-identity/commit/75ec14e072f8c219863a1c028a3b0783802086e9))
51
+ * missing path params ([02acbde](https://github.com/iotaledger/twin-identity/commit/02acbde3033bf5d5435dca0bd8187cabad8f3028))
52
+ * profile update deny list ([#260](https://github.com/iotaledger/twin-identity/issues/260)) ([4126ec4](https://github.com/iotaledger/twin-identity/commit/4126ec4b98a52687e55b405c576595af476a84a5))
53
+ * proof create rest route identifier ([395dc57](https://github.com/iotaledger/twin-identity/commit/395dc5700f8ec1b3a607d18ffb68c8eec8ee751c))
54
+ * query params force coercion ([d9347d2](https://github.com/iotaledger/twin-identity/commit/d9347d29d4a9cc58759f30f5d8526de864ea7522))
55
+ * stricter pathParam types ([a174cdf](https://github.com/iotaledger/twin-identity/commit/a174cdf0ca4272bee35fcf20ab7e8e4e17b8b6f4))
56
+ * use async getStore in tests ([cfc0d87](https://github.com/iotaledger/twin-identity/commit/cfc0d873532e8ab2010f86f05bffaad3bbaf5786))
57
+ * use async getStore in tests ([3424c81](https://github.com/iotaledger/twin-identity/commit/3424c81cf7407ede4a89a026072720d52bf689b2))
58
+
59
+
60
+ ### Dependencies
61
+
62
+ * The following workspace dependencies were updated
63
+ * dependencies
64
+ * @twin.org/identity-models bumped from 0.11.1-next.0 to 0.11.1-next.1
65
+ * devDependencies
66
+ * @twin.org/identity-connector-entity-storage bumped from 0.11.1-next.0 to 0.11.1-next.1
67
+
3
68
  ## [0.11.0](https://github.com/iotaledger/twin-identity/compare/identity-service-v0.11.0...identity-service-v0.11.0) (2026-09-29)
4
69
 
5
70
 
@@ -8,6 +8,7 @@
8
8
 
9
9
  ## Interfaces
10
10
 
11
+ - [IIdentityProfileServiceConfig](interfaces/IIdentityProfileServiceConfig.md)
11
12
  - [IIdentityProfileServiceConstructorOptions](interfaces/IIdentityProfileServiceConstructorOptions.md)
12
13
  - [IIdentityResolverServiceConfig](interfaces/IIdentityResolverServiceConfig.md)
13
14
  - [IIdentityResolverServiceConstructorOptions](interfaces/IIdentityResolverServiceConstructorOptions.md)
@@ -0,0 +1,31 @@
1
+ # Interface: IIdentityProfileServiceConfig
2
+
3
+ Configuration for the Identity Profile Service.
4
+
5
+ ## Properties
6
+
7
+ ### selfUpdateDeniedProperties? {#selfupdatedeniedproperties}
8
+
9
+ > `optional` **selfUpdateDeniedProperties?**: `string`[]
10
+
11
+ The public and private profile properties which can only be added, changed or removed by callers with an admin scope.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ []
17
+ ```
18
+
19
+ ***
20
+
21
+ ### adminScopes? {#adminscopes}
22
+
23
+ > `optional` **adminScopes?**: `string`[]
24
+
25
+ The scopes which allow the denied properties to be modified, any one is sufficient.
26
+
27
+ #### Default
28
+
29
+ ```ts
30
+ ["user-admin", "global-admin"]
31
+ ```
@@ -15,3 +15,11 @@ The storage connector for the profiles.
15
15
  ```ts
16
16
  identity-profile
17
17
  ```
18
+
19
+ ***
20
+
21
+ ### config? {#config}
22
+
23
+ > `optional` **config?**: [`IIdentityProfileServiceConfig`](IIdentityProfileServiceConfig.md)
24
+
25
+ The configuration for the identity profile service.
package/locales/en.json CHANGED
@@ -43,7 +43,8 @@
43
43
  "notFound": "The identity profile could not be found \"{notFoundId}\"",
44
44
  "removeFailed": "Removing the identity profile failed \"{identity}\"",
45
45
  "listFailed": "Failed listing identities",
46
- "listAdminFailed": "Failed listing identities with private data"
46
+ "listAdminFailed": "Failed listing identities with private data",
47
+ "selfUpdateDenied": "The profile properties \"{properties}\" cannot be modified on the profile \"{identity}\" without an admin scope"
47
48
  }
48
49
  }
49
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/identity-service",
3
- "version": "0.11.0",
3
+ "version": "0.11.1-next.1",
4
4
  "description": "Service contracts and REST endpoint definitions for exposing identity workflows through stable interfaces.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,20 +14,20 @@
14
14
  "node": ">=24.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/api-models": "^0.11.0",
18
- "@twin.org/context": "^0.11.0",
19
- "@twin.org/core": "^0.11.0",
20
- "@twin.org/data-core": "^0.11.0",
21
- "@twin.org/data-json-ld": "^0.11.0",
22
- "@twin.org/dlt-account": "^0.11.0",
23
- "@twin.org/entity": "^0.11.0",
24
- "@twin.org/identity-models": "^0.11.0",
25
- "@twin.org/nameof": "^0.11.0",
26
- "@twin.org/standards-w3c-did": "^0.11.0",
27
- "@twin.org/telemetry-models": "^0.11.0",
28
- "@twin.org/vault-models": "^0.11.0",
29
- "@twin.org/wallet-models": "^0.11.0",
30
- "@twin.org/web": "^0.11.0"
17
+ "@twin.org/api-models": "next",
18
+ "@twin.org/context": "next",
19
+ "@twin.org/core": "next",
20
+ "@twin.org/data-core": "next",
21
+ "@twin.org/data-json-ld": "next",
22
+ "@twin.org/dlt-account": "next",
23
+ "@twin.org/entity": "next",
24
+ "@twin.org/identity-models": "0.11.1-next.1",
25
+ "@twin.org/nameof": "next",
26
+ "@twin.org/standards-w3c-did": "next",
27
+ "@twin.org/telemetry-models": "next",
28
+ "@twin.org/vault-models": "next",
29
+ "@twin.org/wallet-models": "next",
30
+ "@twin.org/web": "next"
31
31
  },
32
32
  "main": "./dist/es/index.js",
33
33
  "types": "./dist/types/index.d.ts",