@sphereon/ssi-sdk.ebsi-support
Version:
229 lines • 12.2 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.siopDoneCallback = exports.reviewCredentialsCallback = exports.authorizationCodeUrlCallback = exports.selectCredentialsCallback = exports.handleErrorCallback = exports.addContactCallback = void 0;
const did_auth_siop_1 = require("@sphereon/did-auth-siop");
const oid4vci_common_1 = require("@sphereon/oid4vci-common");
const ssi_sdk_data_store_1 = require("@sphereon/ssi-sdk.data-store");
const ssi_sdk_oid4vci_holder_1 = require("@sphereon/ssi-sdk.oid4vci-holder");
const cross_fetch_1 = __importDefault(require("cross-fetch"));
const index_1 = require("../index");
const addContactCallback = (context) => {
return (oid4vciMachine, state) => __awaiter(void 0, void 0, void 0, function* () {
const { serverMetadata, hasContactConsent, contactAlias } = state.context;
if (!serverMetadata) {
return Promise.reject(Error('Missing serverMetadata in context'));
}
const issuerUrl = new URL(serverMetadata.issuer);
const correlationId = `${issuerUrl.protocol}//${issuerUrl.hostname}`;
let issuerName = (0, oid4vci_common_1.getIssuerName)(correlationId, serverMetadata.credentialIssuerMetadata);
const party = {
contact: {
displayName: issuerName,
legalName: issuerName,
},
// FIXME maybe its nicer if we can also just use the id only
// TODO using the predefined party type from the contact migrations here
// TODO this is not used as the screen itself adds one, look at the params of the screen, this is not being passed in
partyType: {
id: '3875c12e-fdaa-4ef6-a340-c936e054b627',
origin: ssi_sdk_data_store_1.PartyOrigin.EXTERNAL,
type: ssi_sdk_data_store_1.PartyTypeType.ORGANIZATION,
name: 'Sphereon_default_type',
tenantId: '95e09cfc-c974-4174-86aa-7bf1d5251fb4',
},
uri: correlationId,
identities: [
{
alias: correlationId,
roles: [ssi_sdk_data_store_1.CredentialRole.ISSUER],
origin: ssi_sdk_data_store_1.IdentityOrigin.EXTERNAL,
identifier: {
type: ssi_sdk_data_store_1.CorrelationIdentifierType.URL,
correlationId: issuerUrl.hostname,
},
// TODO WAL-476 add support for correct connection
connection: {
type: ssi_sdk_data_store_1.ConnectionType.OPENID_CONNECT,
config: {
clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01',
clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0',
scopes: ['auth'],
issuer: 'https://example.com/app-test',
redirectUrl: 'app:/callback',
dangerouslyAllowInsecureHttpRequests: true,
clientAuthMethod: 'post',
},
},
},
],
};
const onCreate = (_a) => __awaiter(void 0, [_a], void 0, function* ({ party, issuerUrl, issuerName, correlationId, }) {
var _b, _c, _d;
const displayName = (_b = party.contact.displayName) !== null && _b !== void 0 ? _b : issuerName;
const contacts = yield context.agent.cmGetContacts({
filter: [
{
contact: {
// Searching on legalName as displayName is not unique, and we only support organizations for now
legalName: displayName,
},
},
],
});
if (contacts.length === 0 || !((_c = contacts[0]) === null || _c === void 0 ? void 0 : _c.contact)) {
const contact = yield context.agent.cmAddContact(Object.assign(Object.assign({}, party), { displayName, legalName: displayName, contactType: {
type: ssi_sdk_data_store_1.PartyTypeType.ORGANIZATION,
name: displayName,
origin: ssi_sdk_data_store_1.PartyOrigin.EXTERNAL,
tenantId: (_d = party.tenantId) !== null && _d !== void 0 ? _d : '1',
} }));
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.CREATE_CONTACT,
data: contact,
});
}
});
const onConsentChange = (hasConsent) => __awaiter(void 0, void 0, void 0, function* () {
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.SET_CONTACT_CONSENT,
data: hasConsent,
});
});
const onAliasChange = (alias) => __awaiter(void 0, void 0, void 0, function* () {
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.SET_CONTACT_ALIAS,
data: alias,
});
});
if (!issuerName) {
issuerName = `EBSI unknown (${issuerUrl})`;
}
else if (issuerName.startsWith('http')) {
issuerName = `EBSI ${issuerName.replace(/https?:\/\//, '')}`;
}
if (!contactAlias) {
return yield onAliasChange(issuerName);
}
issuerName = contactAlias;
if (!hasContactConsent) {
return yield onConsentChange(true);
}
yield onCreate({ party, issuerName, issuerUrl: issuerUrl.toString(), correlationId });
});
};
exports.addContactCallback = addContactCallback;
const handleErrorCallback = (context) => {
return (oid4vciMachine, state) => __awaiter(void 0, void 0, void 0, function* () {
console.error(`error callback event: ${state.event}`, state.context.error);
index_1.logger.trace(state.event);
});
};
exports.handleErrorCallback = handleErrorCallback;
const selectCredentialsCallback = (context) => {
return (oid4vciMachine, state) => __awaiter(void 0, void 0, void 0, function* () {
const { contact, credentialToSelectFrom, selectedCredentials } = state.context;
if (selectedCredentials && selectedCredentials.length > 0) {
index_1.logger.info(`selected: ${selectedCredentials.join(', ')}`);
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.NEXT,
});
return;
}
else if (!contact) {
return Promise.reject(Error('Missing contact in context'));
}
const onSelectType = (selectedCredentials) => __awaiter(void 0, void 0, void 0, function* () {
console.log(`Selected credentials: ${selectedCredentials.join(', ')}`);
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.SET_SELECTED_CREDENTIALS,
data: selectedCredentials,
});
});
yield onSelectType(credentialToSelectFrom.map((sel) => sel.credentialId));
});
};
exports.selectCredentialsCallback = selectCredentialsCallback;
const authorizationCodeUrlCallback = ({ authReqResult, vpLinkHandler, }, context) => {
return (oid4vciMachine, state) => __awaiter(void 0, void 0, void 0, function* () {
const url = state.context.authorizationCodeURL;
console.log('navigateAuthorizationCodeURL: ', url);
if (!url) {
return Promise.reject(Error('Missing authorization URL in context'));
}
const onOpenAuthorizationUrl = (url) => __awaiter(void 0, void 0, void 0, function* () {
var _a;
console.log('onOpenAuthorizationUrl being invoked: ', url);
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.INVOKED_AUTHORIZATION_CODE_REQUEST,
data: url,
});
const response = yield (0, cross_fetch_1.default)(url, { redirect: 'manual' });
if (response.status < 301 || response.status > 302) {
throw Error(`When doing a headless auth, we expect to be redirected on getting the authz URL`);
}
const openidUri = response.headers.get('location');
if (!openidUri || !openidUri.startsWith('openid://')) {
let error = undefined;
if (openidUri) {
if (openidUri.includes('error')) {
error = 'Authorization server error: ';
const decoded = (0, did_auth_siop_1.decodeUriAsJson)(openidUri);
if ('error' in decoded && decoded.error) {
error += decoded.error + ', ';
}
if ('error_description' in decoded && decoded.error_description) {
error += decoded.error_description;
}
}
}
throw Error(error !== null && error !== void 0 ? error : `Expected a openid:// URI to be returned from EBSI in headless mode. Returned: ${openidUri}, ${JSON.stringify(yield response.text())}`);
}
console.log(`onOpenAuthorizationUrl after openUrl: ${url}`);
const kid = ((_a = authReqResult.authKey.meta) === null || _a === void 0 ? void 0 : _a.jwkThumbprint)
? `${authReqResult.identifier.did}#${authReqResult.authKey.meta.jwkThumbprint}`
: authReqResult.identifier.kid;
yield vpLinkHandler.handle(openidUri, { idOpts: Object.assign(Object.assign({}, authReqResult.identifier), { kmsKeyRef: kid }) });
});
yield onOpenAuthorizationUrl(url);
});
};
exports.authorizationCodeUrlCallback = authorizationCodeUrlCallback;
const reviewCredentialsCallback = (context) => {
return (oid4vciMachine, state) => __awaiter(void 0, void 0, void 0, function* () {
console.log(`# REVIEW CREDENTIALS:`);
console.log(JSON.stringify(state.context.credentialsToAccept, null, 2));
oid4vciMachine.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.NEXT,
});
});
};
exports.reviewCredentialsCallback = reviewCredentialsCallback;
const siopDoneCallback = ({ oid4vciMachine }, context) => {
return (oid4vpMachine, state) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
// console.log('SIOP result:')
// console.log(JSON.stringify(state.context, null , 2))
if (!((_b = (_a = state.context.authorizationResponseData) === null || _a === void 0 ? void 0 : _a.queryParams) === null || _b === void 0 ? void 0 : _b.code)) {
throw Error(`No code was returned from the authorization step`);
}
oid4vciMachine.interpreter.send({
type: ssi_sdk_oid4vci_holder_1.OID4VCIMachineEvents.PROVIDE_AUTHORIZATION_CODE_RESPONSE,
data: state.context.authorizationResponseData.url,
});
console.log(`SIOP DONE!`);
});
};
exports.siopDoneCallback = siopDoneCallback;
//# sourceMappingURL=AttestationHeadlessCallbacks.js.map