@sphereon/ssi-sdk.wellknown-did-issuer
Version:
609 lines (599 loc) • 26.1 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// plugin.schema.json
var require_plugin_schema = __commonJS({
"plugin.schema.json"(exports, module2) {
module2.exports = {
IWellKnownDidIssuer: {
components: {
schemas: {
IIssueDidConfigurationResourceArgs: {
type: "object",
properties: {
issuances: {
type: "array",
items: {
type: "object",
properties: {
additionalProperties: true
}
}
},
credentialIssuance: {
type: "string"
},
save: {
type: "boolean"
},
additionalProperties: false
},
required: ["issuances", "credentialIssuance"],
description: "Arguments needed for {@link IWellKnownDidIssuer.addLinkedDomainsService } "
},
IIssueDomainLinkageCredentialArgs: {
type: "object",
properties: {
did: {
type: "string"
},
origin: {
type: "string"
},
serviceId: {
type: "string"
},
issuanceDate: {
type: "date"
},
expirationDate: {
type: "date"
},
save: {
type: "boolean"
},
options: {
type: "object",
properties: {
additionalProperties: true
}
},
credentialIssuance: {
type: "string"
},
additionalProperties: false
},
required: ["did", "origin", "expirationDate", "options"],
description: "Arguments needed for {@link IWellKnownDidIssuer.issueDomainLinkageCredential } "
},
IGetDidConfigurationResourceArgs: {
type: "object",
properties: {
origin: {
type: "string"
},
additionalProperties: false
},
required: ["origin"],
description: "Arguments needed for {@link IWellKnownDidIssuer.getDidConfigurationResource } "
},
IAddLinkedDomainsServiceArgs: {
type: "object",
properties: {
did: {
type: "string"
},
origin: {
type: "string"
},
serviceId: {
type: "string"
},
additionalProperties: false
},
required: ["did", "origin"],
description: "Arguments needed for {@link IWellKnownDidIssuer.addLinkedDomainsService } "
},
ISaveDidConfigurationResourceArgs: {
type: "object",
properties: {
origin: {
type: "string"
},
didConfigurationResource: {
type: "object",
properties: {
additionalProperties: true
}
},
additionalProperties: false
},
required: ["did", "origin"],
description: "Arguments needed for {@link IWellKnownDidIssuer.saveDidConfigurationResource } "
},
IRemoveCredentialIssuanceArgs: {
type: "object",
properties: {
origin: {
callbackName: "string"
},
additionalProperties: false
},
required: ["callbackName"],
description: "Arguments needed for {@link IWellKnownDidIssuer.removeCredentialIssuance } "
}
},
methods: {
addLinkedDomainsService: {
description: "Adds a LinkedDomains service to the DID",
arguments: {
$ref: "#/components/schemas/IAddLinkedDomainsServiceArgs"
}
},
getDidConfigurationResource: {
description: "Retrieves a DID configuration resource from the database",
arguments: {
$ref: "#/components/schemas/IGetDidConfigurationResourceArgs"
},
returnType: "object"
},
issueDidConfigurationResource: {
description: "Issues a DID configuration resource",
arguments: {
$ref: "#/components/schemas/IAddLinkedDomainsServiceArgs"
},
returnType: "object"
},
issueDomainLinkageCredential: {
description: "Retrieves a domain linkage credential",
arguments: {
$ref: "#/components/schemas/IIssueDomainLinkageCredentialArgs"
},
returnType: "object"
},
removeCredentialIssuance: {
description: "Removes a registered callback",
arguments: {
$ref: "#/components/schemas/IRemoveCredentialIssuanceArgs"
},
returnType: "boolean"
},
saveDidConfigurationResource: {
description: "Saves a DID configuration resource to the database",
arguments: {
$ref: "#/components/schemas/ISaveDidConfigurationResourceArgs"
}
}
}
}
}
};
}
});
// src/index.ts
var index_exports = {};
__export(index_exports, {
DidConfigurationResourceEntity: () => DidConfigurationResourceEntity,
WellKnownDidIssuer: () => WellKnownDidIssuer,
WellknownDidIssuerEntities: () => WellknownDidIssuerEntities,
WellknownDidIssuerMigrations: () => WellknownDidIssuerMigrations,
schema: () => schema
});
module.exports = __toCommonJS(index_exports);
// src/entities/DidConfigurationResourceEntity.ts
var import_data_store = require("@veramo/data-store");
var import_utils = require("@veramo/utils");
var import_typeorm = require("typeorm");
function _ts_decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
__name(_ts_decorate, "_ts_decorate");
function _ts_metadata(k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}
__name(_ts_metadata, "_ts_metadata");
var DidConfigurationResourceEntity = class extends import_typeorm.BaseEntity {
static {
__name(this, "DidConfigurationResourceEntity");
}
origin;
context;
// TODO cascade of delete should be true when the VC is only attached to one DID configuration resource
linkedDids;
createdAt;
lastUpdatedAt;
};
_ts_decorate([
(0, import_typeorm.PrimaryColumn)({
nullable: false
}),
_ts_metadata("design:type", String)
], DidConfigurationResourceEntity.prototype, "origin", void 0);
_ts_decorate([
(0, import_typeorm.Column)({
nullable: false
}),
_ts_metadata("design:type", String)
], DidConfigurationResourceEntity.prototype, "context", void 0);
_ts_decorate([
(0, import_typeorm.ManyToMany)(() => import_data_store.Credential, (credential) => credential.hash, {
nullable: false,
cascade: true,
onDelete: "NO ACTION"
}),
(0, import_typeorm.JoinTable)({
name: "DidConfigurationResourceCredentials"
}),
_ts_metadata("design:type", typeof Array === "undefined" ? Object : Array)
], DidConfigurationResourceEntity.prototype, "linkedDids", void 0);
_ts_decorate([
(0, import_typeorm.CreateDateColumn)({
name: "created_at",
nullable: false
}),
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
], DidConfigurationResourceEntity.prototype, "createdAt", void 0);
_ts_decorate([
(0, import_typeorm.UpdateDateColumn)({
name: "last_updated_at",
nullable: false
}),
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
], DidConfigurationResourceEntity.prototype, "lastUpdatedAt", void 0);
DidConfigurationResourceEntity = _ts_decorate([
(0, import_typeorm.Entity)("DidConfigurationResource")
], DidConfigurationResourceEntity);
var didConfigurationResourceFrom = /* @__PURE__ */ __name((didConfigurationResource) => {
return {
"@context": didConfigurationResource.context,
linked_dids: linkedDidsFrom(didConfigurationResource.linkedDids)
};
}, "didConfigurationResourceFrom");
var linkedDidsFrom = /* @__PURE__ */ __name((credentials) => {
return credentials.map((credential) => credential?.raw?.proof?.type === "JwtProof2020" && typeof credential?.raw?.proof?.jwt === "string" ? credential.raw.proof.jwt : credential.raw);
}, "linkedDidsFrom");
var createCredentialEntity = /* @__PURE__ */ __name((vci) => {
const vc = vci;
const credential = new import_data_store.Credential();
credential.context = (0, import_utils.asArray)(vc["@context"]);
credential.type = (0, import_utils.asArray)(vc.type || []);
credential.id = vc.id;
if (vc.issuanceDate) {
credential.issuanceDate = new Date(vc.issuanceDate);
}
if (vc.expirationDate) {
credential.expirationDate = new Date(vc.expirationDate);
}
const issuer = new import_data_store.Identifier();
issuer.did = (0, import_utils.extractIssuer)(vc);
credential.issuer = issuer;
if (vc.credentialSubject.id) {
const subject = new import_data_store.Identifier();
subject.did = vc.credentialSubject.id;
credential.subject = subject;
}
credential.claims = [];
for (const type in vc.credentialSubject) {
if (vc.credentialSubject.hasOwnProperty(type)) {
const value = vc.credentialSubject[type];
if (type !== "id") {
const isObj = typeof value === "function" || typeof value === "object" && !!value;
const claim = new import_data_store.Claim();
claim.hash = (0, import_utils.computeEntryHash)(JSON.stringify(vc) + type);
claim.type = type;
claim.value = isObj ? JSON.stringify(value) : value;
claim.isObj = isObj;
claim.issuer = credential.issuer;
claim.subject = credential.subject;
claim.expirationDate = credential.expirationDate;
claim.issuanceDate = credential.issuanceDate;
claim.credentialType = credential.type;
claim.context = credential.context;
credential.claims.push(claim);
}
}
}
credential.raw = vci;
return credential;
}, "createCredentialEntity");
// src/agent/WellKnownDidIssuer.ts
var import_ssi_sdk = require("@sphereon/ssi-sdk.credential-store");
var import_ssi_types = require("@sphereon/ssi-types");
var import_wellknown_dids_client = require("@sphereon/wellknown-dids-client");
var import_did_jwt_vc = require("did-jwt-vc");
var import_uuid = require("uuid");
var import_ssi_sdk2 = require("@sphereon/ssi-sdk.data-store-types");
var WellKnownDidIssuer = class {
static {
__name(this, "WellKnownDidIssuer");
}
dbConnection;
schema = schema.IWellKnownDidVerifier;
methods = {
addLinkedDomainsService: this.addLinkedDomainsService.bind(this),
getDidConfigurationResource: this.getDidConfigurationResource.bind(this),
issueDidConfigurationResource: this.issueDidConfigurationResource.bind(this),
issueDomainLinkageCredential: this.issueDomainLinkageCredential.bind(this),
registerCredentialIssuance: this.registerCredentialIssuance.bind(this),
removeCredentialIssuance: this.removeCredentialIssuance.bind(this),
saveDidConfigurationResource: this.saveDidConfigurationResource.bind(this)
};
credentialIssuances;
didConfigurationResourceRelations = [
"linkedDids"
];
constructor(dbConnection, args) {
this.dbConnection = dbConnection;
this.credentialIssuances = args && args.credentialIssuances || {};
}
/** {@inheritDoc IWellKnownDidIssuer.registerSignatureVerification} */
async registerCredentialIssuance(args, context) {
if (this.credentialIssuances[args.callbackName] !== void 0) {
return Promise.reject(new Error(`Credential issuance with callbackName: ${args.callbackName} already present`));
}
this.credentialIssuances[args.callbackName] = args.credentialIssuance;
}
/** {@inheritDoc IWellKnownDidIssuer.removeSignatureVerification} */
async removeCredentialIssuance(args, context) {
return delete this.credentialIssuances[args.callbackName];
}
/** {@inheritDoc IWellKnownDidIssuer.issueDidConfigurationResource} */
async issueDidConfigurationResource(args, context) {
if (!args.issuances.every((issuance) => issuance.origin === args.issuances[0].origin)) {
return Promise.reject(Error("All verifiableCredentials should be issued for the same origin"));
}
const addServices = args.issuances.map((issuance) => this.addLinkedDomainsService({
did: issuance.did,
origin: issuance.origin,
serviceId: issuance.serviceId
}, context));
return Promise.all(addServices).then(async () => new import_wellknown_dids_client.WellKnownDidIssuer().issueDidConfigurationResource({
issuances: await this.mapIssuances(args.issuances),
issueCallback: typeof args.credentialIssuance === "string" ? await this.getCredentialIssuance(args.credentialIssuance) : args.credentialIssuance
}).then(async (didConfigurationResource) => {
if (args.save) {
await this.saveDidConfigurationResource({
origin: args.issuances[0].origin,
didConfigurationResource
}, context);
}
return didConfigurationResource;
}).catch((error) => Promise.reject(Error(`Unable to issue DID configuration resource. Error: ${error.message}`))));
}
/** {@inheritDoc IWellKnownDidIssuer.saveDidConfigurationResource} */
async saveDidConfigurationResource(args, context) {
const didConfigurationEntity = {
origin: args.origin,
context: args.didConfigurationResource["@context"],
linkedDids: args.didConfigurationResource.linked_dids.map((credential) => createCredentialEntity(this.normalizeCredential(credential)))
};
await (await this.dbConnection).getRepository(DidConfigurationResourceEntity).save(didConfigurationEntity, {
transaction: true
});
}
/** {@inheritDoc IWellKnownDidIssuer.getDidConfigurationResource} */
async getDidConfigurationResource(args, context) {
const result = await (await this.dbConnection).getRepository(DidConfigurationResourceEntity).findOne({
where: {
origin: args.origin
},
relations: this.didConfigurationResourceRelations
});
if (!result) {
return Promise.reject(Error(`No DID configuration resource found for origin: ${args.origin}`));
}
return didConfigurationResourceFrom(result);
}
/** {@inheritDoc IWellKnownDidIssuer.issueDomainLinkageCredential} */
async issueDomainLinkageCredential(args, context) {
const did = (0, import_ssi_types.parseDid)(args.did).did;
if (new URL(args.origin).origin !== args.origin) {
return Promise.reject(Error(`Origin ${args.origin} is not valid`));
}
if (new URL(args.origin).protocol !== "https:") {
return Promise.reject(Error(`Origin ${args.origin} is not a https URL`));
}
if (args.issuanceDate && isNaN(Date.parse(args.issuanceDate))) {
return Promise.reject(Error(`IssuanceDate ${args.issuanceDate} is not a valid date`));
}
if (isNaN(Date.parse(args.expirationDate))) {
return Promise.reject(Error(`ExpirationDate ${args.expirationDate} is not a valid date`));
}
const credentialIssuance = typeof args.credentialIssuance === "string" ? await this.getCredentialIssuance(args.credentialIssuance) : args.credentialIssuance;
return new import_wellknown_dids_client.WellKnownDidIssuer().issueDomainLinkageCredential({
did,
origin: args.origin,
issuanceDate: args.issuanceDate,
expirationDate: args.expirationDate,
options: args.options,
issueCallback: credentialIssuance
}).then(async (credential) => {
if (args.save) {
await this.saveDomainLinkageCredential(credential, context);
}
return credential;
}).catch((error) => Promise.reject(Error(`Unable to issue domain linkage credential for DID: ${did}. Error: ${error.message}`)));
}
/** {@inheritDoc IWellKnownDidIssuer.addLinkedDomainsService} */
async addLinkedDomainsService(args, context) {
const did = (0, import_ssi_types.parseDid)(args.did).did;
if (new URL(args.origin).origin !== args.origin) {
return Promise.reject(Error(`Origin ${args.origin} is not valid`));
}
if (new URL(args.origin).protocol !== "https:") {
return Promise.reject(Error(`Origin ${args.origin} is not a https URL`));
}
context.agent.didManagerGet({
did
}).catch(() => Promise.reject(Error("DID cannot be found"))).then(async (identifier) => {
if (!identifier.services || identifier.services.filter(
// TODO we should also check for the origins in the serviceEndpoint objects when we start supporting multiple origins
(service) => service.type === import_wellknown_dids_client.ServiceTypesEnum.LINKED_DOMAINS && service.serviceEndpoint === args.origin
).length === 0) {
await context.agent.didManagerAddService({
did: identifier.did,
service: {
id: args.serviceId || (0, import_uuid.v4)(),
type: import_wellknown_dids_client.ServiceTypesEnum.LINKED_DOMAINS,
// TODO We should support a serviceEndpoint object here when we update to Veramo 3.1.6.next-165 or higher, as then we can support multiple origins
serviceEndpoint: args.origin
}
});
}
}).catch((error) => Promise.reject(Error(`Unable to add LinkedDomains service to DID: ${args.did}. Error: ${error.message}`)));
}
async getCredentialIssuance(callbackName) {
if (this.credentialIssuances[callbackName] === void 0) {
return Promise.reject(new Error(`Credential issuance not found for callbackName: ${callbackName}`));
}
return this.credentialIssuances[callbackName];
}
async saveDomainLinkageCredential(credential, context) {
const vc = this.normalizeCredential(credential);
return context.agent.crsAddCredential({
credential: {
rawDocument: JSON.stringify(vc),
credentialRole: import_ssi_sdk.CredentialRole.ISSUER,
regulationType: import_ssi_sdk2.RegulationType.NON_REGULATED,
kmsKeyRef: "FIXME",
identifierMethod: "did",
issuerCorrelationId: import_ssi_types.CredentialMapper.issuerCorrelationIdFromIssuerType(vc.issuer),
issuerCorrelationType: import_ssi_sdk.CredentialCorrelationType.DID,
subjectCorrelationId: import_ssi_types.CredentialMapper.issuerCorrelationIdFromIssuerType(vc.issuer),
subjectCorrelationType: import_ssi_sdk.CredentialCorrelationType.DID
}
});
}
normalizeCredential(credential) {
return typeof credential === "string" ? (0, import_did_jwt_vc.normalizeCredential)(credential) : credential;
}
async mapIssuances(issuances) {
const promises = issuances.map(async (issuance) => {
return {
...issuance,
issueCallback: typeof issuance.credentialIssuance === "string" ? await this.getCredentialIssuance(issuance.credentialIssuance) : issuance.credentialIssuance
};
});
return Promise.all(promises);
}
};
// src/migrations/generic/1-CreateWellknownDidIssuer.ts
var import_debug = __toESM(require("debug"), 1);
// src/migrations/postgres/1661165115000-CreateWellknownDidIssuer.ts
var CreateWellknownDidIssuer1661165115000 = class {
static {
__name(this, "CreateWellknownDidIssuer1661165115000");
}
name = "CreateWellknownDidIssuer1661165115000";
async up(queryRunner) {
await queryRunner.query(`CREATE TABLE "DidConfigurationResource" ("origin" varchar NOT NULL, "context" varchar NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_Origin" PRIMARY KEY ("origin"))`);
await queryRunner.query(`CREATE TABLE "DidConfigurationResourceCredentials" ("didConfigurationResourceOrigin" varchar NOT NULL, "credentialHash" varchar NOT NULL)`);
}
async down(queryRunner) {
await queryRunner.query(`DROP TABLE "DidConfigurationResource"`);
await queryRunner.query(`DROP TABLE "DidConfigurationResourceCredentials"`);
}
};
// src/migrations/sqlite/1661161799000-CreateWellknownDidIssuer.ts
var CreateWellknownDidIssuer1661161799000 = class {
static {
__name(this, "CreateWellknownDidIssuer1661161799000");
}
name = "CreateWellknownDidIssuer1661161799000";
async up(queryRunner) {
await queryRunner.query(`CREATE TABLE "DidConfigurationResource" ("origin" varchar PRIMARY KEY NOT NULL, "context" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
await queryRunner.query(`CREATE TABLE "DidConfigurationResourceCredentials" ("didConfigurationResourceOrigin" varchar NOT NULL, "credentialHash" varchar NOT NULL)`);
}
async down(queryRunner) {
await queryRunner.query(`DROP TABLE "DidConfigurationResource"`);
await queryRunner.query(`DROP TABLE "DidConfigurationResourceCredentials"`);
}
};
// src/migrations/generic/1-CreateWellknownDidIssuer.ts
var debug = (0, import_debug.default)("sphereon:ssi-sdk:migrations");
var CreateWellknownDidIssuer1661162010000 = class {
static {
__name(this, "CreateWellknownDidIssuer1661162010000");
}
name = "CreateWellknownDidIssuer1661162010000";
async up(queryRunner) {
debug("migration: creating well-known DID tables");
const dbType = queryRunner.connection.driver.options.type;
if (dbType === "postgres") {
debug("using postgres migration file");
const mig = new CreateWellknownDidIssuer1661165115000();
const up = await mig.up(queryRunner);
debug("Migration statements executed");
return up;
} else if (dbType === "sqlite" || dbType === "react-native" || dbType === "expo") {
debug("using sqlite/react-native migration file");
const mig = new CreateWellknownDidIssuer1661161799000();
const up = await mig.up(queryRunner);
debug("Migration statements executed");
return up;
} else {
return Promise.reject(`Migrations are currently only supported for sqlite, react-native, expor and postgres. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`);
}
}
async down(queryRunner) {
debug("reverting well-known DID tables");
const dbType = queryRunner.connection.driver.options.type;
if (dbType === "postgres") {
debug("using postgres migration file");
const mig = new CreateWellknownDidIssuer1661165115000();
const down = await mig.down(queryRunner);
debug("Migration statements executed");
return down;
} else if (dbType === "sqlite" || dbType === "react-native" || dbType === "expo") {
debug("using sqlite/react-native migration file");
const mig = new CreateWellknownDidIssuer1661161799000();
const down = await mig.down(queryRunner);
debug("Migration statements executed");
return down;
} else {
return Promise.reject(`Migrations are currently only supported for sqlite, react-native, expor and postgres. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`);
}
}
};
// src/migrations/generic/index.ts
var WellknownDidIssuerMigrations = [
CreateWellknownDidIssuer1661162010000
];
// src/index.ts
var schema = require_plugin_schema();
var WellknownDidIssuerEntities = [
DidConfigurationResourceEntity
];
//# sourceMappingURL=index.cjs.map