From 56b83f1c831cf6621bddff38ce131bb500b78e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= <33655937+jkoenig134@users.noreply.github.com> Date: Tue, 16 Apr 2024 15:26:30 +0200 Subject: [PATCH] Feature/pass profile name in devicesharedsecret (#106) * feat: pass profile name in DeviceSharedSecret * chore: version bumps * chore: rebuild schemas --- package-lock.json | 6 +- packages/runtime/package.json | 4 +- .../transport/DeviceOnboardingInfoDTO.ts | 1 + .../runtime/src/useCases/common/Schemas.ts | 142 +++++++++++------- .../devices/CreateDeviceOnboardingToken.ts | 3 +- .../transport/devices/DeviceMapper.ts | 6 +- .../devices/GetDeviceOnboardingInfo.ts | 3 +- .../runtime/test/transport/account.test.ts | 21 ++- packages/transport/package.json | 2 +- .../modules/devices/DeviceSecretController.ts | 8 +- .../src/modules/devices/DevicesController.ts | 4 +- .../transmission/DeviceSharedSecret.ts | 7 +- 12 files changed, 129 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index 25b381fa9..318034046 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13220,7 +13220,7 @@ }, "packages/runtime": { "name": "@nmshd/runtime", - "version": "4.4.2", + "version": "4.5.0", "license": "MIT", "dependencies": { "@js-soft/docdb-querytranslator": "^1.1.4", @@ -13230,7 +13230,7 @@ "@nmshd/consumption": "3.9.7", "@nmshd/content": "2.8.11", "@nmshd/crypto": "2.0.6", - "@nmshd/transport": "2.4.2", + "@nmshd/transport": "2.5.0", "ajv": "^8.12.0", "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", @@ -13255,7 +13255,7 @@ }, "packages/transport": { "name": "@nmshd/transport", - "version": "2.4.2", + "version": "2.5.0", "license": "MIT", "dependencies": { "@js-soft/docdb-access-abstractions": "1.0.4", diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 1ce0ecbc8..ba11ecd53 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/runtime", - "version": "4.4.2", + "version": "4.5.0", "description": "The enmeshed client runtime.", "homepage": "https://enmeshed.eu", "repository": { @@ -68,7 +68,7 @@ "@nmshd/consumption": "3.9.7", "@nmshd/content": "2.8.11", "@nmshd/crypto": "2.0.6", - "@nmshd/transport": "2.4.2", + "@nmshd/transport": "2.5.0", "ajv": "^8.12.0", "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", diff --git a/packages/runtime/src/types/transport/DeviceOnboardingInfoDTO.ts b/packages/runtime/src/types/transport/DeviceOnboardingInfoDTO.ts index 0984582a9..12a3d8b25 100644 --- a/packages/runtime/src/types/transport/DeviceOnboardingInfoDTO.ts +++ b/packages/runtime/src/types/transport/DeviceOnboardingInfoDTO.ts @@ -6,6 +6,7 @@ export interface DeviceOnboardingInfoDTO { createdByDevice: string; name?: string; description?: string; + profileName?: string; secretBaseKey: string; deviceIndex: number; synchronizationKey: string; diff --git a/packages/runtime/src/useCases/common/Schemas.ts b/packages/runtime/src/useCases/common/Schemas.ts index 6365ed520..5f7b29403 100644 --- a/packages/runtime/src/useCases/common/Schemas.ts +++ b/packages/runtime/src/useCases/common/Schemas.ts @@ -16570,7 +16570,8 @@ export const GetOwnSharedAttributesRequest: any = { "type": "boolean" }, "onlyLatestVersions": { - "type": "boolean" + "type": "boolean", + "description": "default: true" } }, "required": [ @@ -16770,7 +16771,8 @@ export const GetPeerSharedAttributesRequest: any = { "type": "boolean" }, "onlyLatestVersions": { - "type": "boolean" + "type": "boolean", + "description": "default: true" } }, "required": [ @@ -16945,7 +16947,8 @@ export const GetRepositoryAttributesRequest: any = { "type": "object", "properties": { "onlyLatestVersions": { - "type": "boolean" + "type": "boolean", + "description": "default: true" }, "query": { "$ref": "#/definitions/GetRepositoryAttributesRequestQuery" @@ -16959,19 +16962,6 @@ export const GetRepositoryAttributesRequest: any = { "createdAt": { "type": "string" }, - "content.@type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, "content.tags": { "anyOf": [ { @@ -17011,45 +17001,6 @@ export const GetRepositoryAttributesRequest: any = { } ] }, - "content.key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, - "content.isTechnical": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, - "content.confidentiality": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, "content.value.@type": { "anyOf": [ { @@ -17086,7 +17037,8 @@ export const GetSharedVersionsOfRepositoryAttributeRequest: any = { } }, "onlyLatestVersions": { - "type": "boolean" + "type": "boolean", + "description": "default: true" } }, "required": [ @@ -19967,6 +19919,29 @@ export const CreateRelationshipChallengeRequest: any = { } } +export const isCreateRelationshipChallengeRequest: any = { + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/isCreateRelationshipChallengeRequest", + "definitions": { + "isCreateRelationshipChallengeRequest": { + "$comment": "(value: any) => value is CreateRelationshipChallengeRequest", + "type": "object", + "properties": { + "namedArgs": { + "type": "object", + "properties": { + "value": {} + }, + "required": [ + "value" + ], + "additionalProperties": false + } + } + } + } +} + export const CreateIdentityChallengeRequest: any = { "$schema": "http://json-schema.org/draft-07/schema#", "$ref": "#/definitions/CreateIdentityChallengeRequest", @@ -19987,6 +19962,29 @@ export const CreateIdentityChallengeRequest: any = { } } +export const isCreateIdentityChallengeRequest: any = { + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/isCreateIdentityChallengeRequest", + "definitions": { + "isCreateIdentityChallengeRequest": { + "$comment": "(value: any) => value is CreateIdentityChallengeRequest", + "type": "object", + "properties": { + "namedArgs": { + "type": "object", + "properties": { + "value": {} + }, + "required": [ + "value" + ], + "additionalProperties": false + } + } + } + } +} + export const CreateDeviceChallengeRequest: any = { "$schema": "http://json-schema.org/draft-07/schema#", "$ref": "#/definitions/CreateDeviceChallengeRequest", @@ -20007,6 +20005,29 @@ export const CreateDeviceChallengeRequest: any = { } } +export const isCreateDeviceChallengeRequest: any = { + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/isCreateDeviceChallengeRequest", + "definitions": { + "isCreateDeviceChallengeRequest": { + "$comment": "(value: any) => value is CreateDeviceChallengeRequest", + "type": "object", + "properties": { + "namedArgs": { + "type": "object", + "properties": { + "value": {} + }, + "required": [ + "value" + ], + "additionalProperties": false + } + } + } + } +} + export const CreateChallengeRequest: any = { "$schema": "http://json-schema.org/draft-07/schema#", "$ref": "#/definitions/CreateChallengeRequest", @@ -20131,6 +20152,9 @@ export const CreateDeviceOnboardingTokenRequest: any = { }, "expiresAt": { "$ref": "#/definitions/ISO8601DateTimeString" + }, + "profileName": { + "type": "string" } }, "required": [ @@ -20205,6 +20229,9 @@ export const GetDeviceOnboardingInfoRequest: any = { "properties": { "id": { "$ref": "#/definitions/GenericIdString" + }, + "profileName": { + "type": "string" } }, "required": [ @@ -21171,7 +21198,8 @@ export const GetAttributesForRelationshipRequest: any = { "type": "boolean" }, "onlyLatestVersions": { - "type": "boolean" + "type": "boolean", + "description": "default: true" } }, "required": [ diff --git a/packages/runtime/src/useCases/transport/devices/CreateDeviceOnboardingToken.ts b/packages/runtime/src/useCases/transport/devices/CreateDeviceOnboardingToken.ts index 9b01a86d1..fe6f021ec 100644 --- a/packages/runtime/src/useCases/transport/devices/CreateDeviceOnboardingToken.ts +++ b/packages/runtime/src/useCases/transport/devices/CreateDeviceOnboardingToken.ts @@ -8,6 +8,7 @@ import { TokenMapper } from "../tokens/TokenMapper"; export interface CreateDeviceOnboardingTokenRequest { id: DeviceIdString; expiresAt?: ISO8601DateTimeString; + profileName?: string; } class Validator extends SchemaValidator { @@ -26,7 +27,7 @@ export class CreateDeviceOnboardingTokenUseCase extends UseCase> { - const sharedSecret = await this.devicesController.getSharedSecret(CoreId.from(request.id)); + const sharedSecret = await this.devicesController.getSharedSecret(CoreId.from(request.id), request.profileName); const expiresAt = request.expiresAt ? CoreDate.from(request.expiresAt) : CoreDate.utc().add({ minutes: 5 }); const tokenContent = TokenContentDeviceSharedSecret.from({ sharedSecret }); diff --git a/packages/runtime/src/useCases/transport/devices/DeviceMapper.ts b/packages/runtime/src/useCases/transport/devices/DeviceMapper.ts index c66bd855f..aa72362f4 100644 --- a/packages/runtime/src/useCases/transport/devices/DeviceMapper.ts +++ b/packages/runtime/src/useCases/transport/devices/DeviceMapper.ts @@ -39,7 +39,8 @@ export class DeviceMapper { realm: deviceSharedSecret.identity.realm.toString() }, password: deviceSharedSecret.password, - username: deviceSharedSecret.username + username: deviceSharedSecret.username, + profileName: deviceSharedSecret.profileName }; } @@ -60,7 +61,8 @@ export class DeviceMapper { realm: deviceOnboardingDTO.identity.realm as Realm }, password: deviceOnboardingDTO.password, - username: deviceOnboardingDTO.username + username: deviceOnboardingDTO.username, + profileName: deviceOnboardingDTO.profileName }); return sharedSecret; } diff --git a/packages/runtime/src/useCases/transport/devices/GetDeviceOnboardingInfo.ts b/packages/runtime/src/useCases/transport/devices/GetDeviceOnboardingInfo.ts index 927b00b96..ef9dbc60f 100644 --- a/packages/runtime/src/useCases/transport/devices/GetDeviceOnboardingInfo.ts +++ b/packages/runtime/src/useCases/transport/devices/GetDeviceOnboardingInfo.ts @@ -7,6 +7,7 @@ import { DeviceMapper } from "./DeviceMapper"; export interface GetDeviceOnboardingInfoRequest { id: GenericIdString; + profileName?: string; } class Validator extends SchemaValidator { @@ -24,7 +25,7 @@ export class GetDeviceOnboardingInfoUseCase extends UseCase> { - const onboardingInfo = await this.devicesController.getSharedSecret(CoreId.from(request.id)); + const onboardingInfo = await this.devicesController.getSharedSecret(CoreId.from(request.id), request.profileName); return Result.ok(DeviceMapper.toDeviceOnboardingInfoDTO(onboardingInfo)); } diff --git a/packages/runtime/test/transport/account.test.ts b/packages/runtime/test/transport/account.test.ts index 208097a2c..bf4d60013 100644 --- a/packages/runtime/test/transport/account.test.ts +++ b/packages/runtime/test/transport/account.test.ts @@ -1,6 +1,6 @@ import { CoreDate } from "@nmshd/transport"; import { DateTime } from "luxon"; -import { TransportServices } from "../../src"; +import { DeviceDTO, DeviceOnboardingInfoDTO, TransportServices } from "../../src"; import { RuntimeServiceProvider, uploadFile } from "../lib"; const serviceProvider = new RuntimeServiceProvider(); @@ -148,17 +148,30 @@ describe("LoadItemFromTruncatedReference", () => { }); describe("DeviceOnboardingInfo", () => { - let deviceOnboardingInfoReference: string; + let device: DeviceDTO; beforeAll(async () => { - const device = (await sTransportServices.devices.createDevice({})).value; - deviceOnboardingInfoReference = (await sTransportServices.devices.getDeviceOnboardingToken({ id: device.id })).value.truncatedReference; + device = (await sTransportServices.devices.createDevice({})).value; }); test("loads the DeviceOnboardingInfo with the truncated reference", async () => { + const deviceOnboardingInfoReference = (await sTransportServices.devices.getDeviceOnboardingToken({ id: device.id })).value.truncatedReference; + const result = await sTransportServices.account.loadItemFromTruncatedReference({ reference: deviceOnboardingInfoReference }); + + expect(result).toBeSuccessful(); + expect(result.value.type).toBe("DeviceOnboardingInfo"); + }); + + test("loads the DeviceOnboardingInfo with the truncated reference including a profile name", async () => { + const profileName = "aProfileName"; + const deviceOnboardingInfoReference = (await sTransportServices.devices.getDeviceOnboardingToken({ id: device.id, profileName })).value.truncatedReference; + + const result = await sTransportServices.account.loadItemFromTruncatedReference({ reference: deviceOnboardingInfoReference }); + expect(result).toBeSuccessful(); expect(result.value.type).toBe("DeviceOnboardingInfo"); + expect((result.value.value as DeviceOnboardingInfoDTO).profileName).toBe(profileName); }); }); }); diff --git a/packages/transport/package.json b/packages/transport/package.json index 164b9dda6..e5b2b1838 100644 --- a/packages/transport/package.json +++ b/packages/transport/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/transport", - "version": "2.4.2", + "version": "2.5.0", "description": "The transport library handles backbone communication and content encryption.", "homepage": "https://enmeshed.eu", "repository": { diff --git a/packages/transport/src/modules/devices/DeviceSecretController.ts b/packages/transport/src/modules/devices/DeviceSecretController.ts index 599a5d265..f0669fab9 100644 --- a/packages/transport/src/modules/devices/DeviceSecretController.ts +++ b/packages/transport/src/modules/devices/DeviceSecretController.ts @@ -101,16 +101,15 @@ export class DeviceSecretController extends TransportController { public async deleteSecret(name: string): Promise { const secretObj = await this.secrets.get(name); - if (!secretObj) { - return false; - } + if (!secretObj) return false; + await this.secrets.delete(name); this.log.trace(`Deleted device secret id:${secretObj.id} name:${secretObj.name} on ${CoreDate.utc().toISOString()}.`); return true; } @log() - public async createDeviceSharedSecret(device: Device, deviceIndex: number, includeIdentityPrivateKey = false): Promise { + public async createDeviceSharedSecret(device: Device, deviceIndex: number, includeIdentityPrivateKey = false, profileName?: string): Promise { const synchronizationKey = await this.loadSecret(DeviceSecretType.IdentitySynchronizationMaster); if (!synchronizationKey || !(synchronizationKey.secret instanceof CryptoSecretKey)) { throw CoreErrors.secrets.secretNotFound("SynchronizationKey"); @@ -137,6 +136,7 @@ export class DeviceSecretController extends TransportController { secretBaseKey: baseKey.secret, name: device.name, description: device.description, + profileName, synchronizationKey: synchronizationKey.secret, identityPrivateKey: identityPrivateKey?.secret as CryptoSignaturePrivateKey, username: device.username, diff --git a/packages/transport/src/modules/devices/DevicesController.ts b/packages/transport/src/modules/devices/DevicesController.ts index a5d28686d..353b851cd 100644 --- a/packages/transport/src/modules/devices/DevicesController.ts +++ b/packages/transport/src/modules/devices/DevicesController.ts @@ -83,7 +83,7 @@ export class DevicesController extends TransportController { return device; } - public async getSharedSecret(id: CoreId): Promise { + public async getSharedSecret(id: CoreId, profileName?: string): Promise { const deviceDoc = await this.devices.read(id.toString()); if (!deviceDoc) { throw CoreErrors.general.recordNotFound(Device, id.toString()); @@ -98,7 +98,7 @@ export class DevicesController extends TransportController { const isAdmin = device.isAdmin === true; - const secret = await this.parent.activeDevice.secrets.createDeviceSharedSecret(device, count, isAdmin); + const secret = await this.parent.activeDevice.secrets.createDeviceSharedSecret(device, count, isAdmin, profileName); return secret; } diff --git a/packages/transport/src/modules/devices/transmission/DeviceSharedSecret.ts b/packages/transport/src/modules/devices/transmission/DeviceSharedSecret.ts index a5721fa87..8685e6971 100644 --- a/packages/transport/src/modules/devices/transmission/DeviceSharedSecret.ts +++ b/packages/transport/src/modules/devices/transmission/DeviceSharedSecret.ts @@ -1,7 +1,7 @@ import { serialize, type, validate } from "@js-soft/ts-serval"; import { CryptoSecretKey, CryptoSignaturePrivateKey, ICryptoSecretKey, ICryptoSignaturePrivateKey } from "@nmshd/crypto"; import { CoreDate, CoreId, CoreSerializable, ICoreId } from "../../../core"; -import { IIdentity, Identity } from "../../accounts/data/Identity"; +import { Identity, IIdentity } from "../../accounts/data/Identity"; export interface IDeviceSharedSecret { id: ICoreId; @@ -9,6 +9,7 @@ export interface IDeviceSharedSecret { createdByDevice: CoreId; name?: string; description?: string; + profileName?: string; secretBaseKey: CryptoSecretKey; deviceIndex: number; synchronizationKey: ICryptoSecretKey; @@ -40,6 +41,10 @@ export class DeviceSharedSecret extends CoreSerializable implements IDeviceShare @validate({ nullable: true }) public description?: string; + @serialize() + @validate({ nullable: true }) + public profileName?: string; + @serialize() @validate() public synchronizationKey: CryptoSecretKey;