import type { Result } from '../../framework/types/result.js' import type { License, LicenseJwt } from '../../domain/license.js' import type { DeviceRegistrationManifest, DeviceRegistration, } from '../../domain/device-registration-manifest.js' import { BaseError } from '../../framework/error/mod.js' import { isError, makeError, makeSuccess, unwrapResult, } from '../../framework/types/result.js' import { decodeDeviceRegistrationManifest } from '../../domain/device-registration-manifest.js' import { buildCryptoService } from '../crypto/mod.js' import { decodeJson } from '../../framework/json/mod.js' export class GetLicenseError extends BaseError { public readonly _tag = 'GetLicenseError' constructor(public readonly cause: unknown) { super(`failed to get license: ${cause}`) } } export function buildGetLicense() { return async function getLicense( manifest: DeviceRegistrationManifest, ): Promise> { // REFACTOR: Move Crypto Service into `infrastructure` layer const cryptoService = buildCryptoService() const resultOfDecodingDeviceRegistrationManifest = decodeDeviceRegistrationManifest(manifest) if (isError(resultOfDecodingDeviceRegistrationManifest)) { return makeError( new GetLicenseError(resultOfDecodingDeviceRegistrationManifest.error), ) } const decodedDeviceRegistrationManifest = unwrapResult( resultOfDecodingDeviceRegistrationManifest, ) const resultOfDecryptingDeviceRegistration = await cryptoService.decrypt({ privateJwk: decodedDeviceRegistrationManifest.encryption.keypair.privateKey, encryptedContents: decodedDeviceRegistrationManifest.registration, }) if (isError(resultOfDecryptingDeviceRegistration)) { return makeError( new GetLicenseError(resultOfDecryptingDeviceRegistration.error), ) } const jsonEncodedDeviceRegistration = unwrapResult( resultOfDecryptingDeviceRegistration, ) const resultOfDecodingDeviceRegistration = decodeJson( jsonEncodedDeviceRegistration, ) if (isError(resultOfDecodingDeviceRegistration)) { return makeError( new GetLicenseError(resultOfDecodingDeviceRegistration.error), ) } const { license, signing } = unwrapResult( resultOfDecodingDeviceRegistration, ) const resultOfVerifyingJwt = await cryptoService.verifySignedJwt({ jwt: license.jwt, publicJwk: signing.publicKey, }) if (isError(resultOfVerifyingJwt)) { return makeError(new GetLicenseError(resultOfVerifyingJwt.error)) } const jwt = unwrapResult(resultOfVerifyingJwt) return makeSuccess({ id: jwt.azp, supporter: { id: jwt.sub, name: jwt.name, avatarUrl: jwt['generous.builders:supporter-avatar-url'], }, flags: jwt['generous.builders:flags'], } as License) } }