@docknetwork/wallet-sdk-core 1.7.6 → 1.9.0
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.
- package/lib/cloud-wallet.d.ts +79 -3
- package/lib/cloud-wallet.d.ts.map +1 -1
- package/lib/cloud-wallet.js +147 -14
- package/lib/cloud-wallet.js.map +1 -1
- package/lib/credential-provider.d.ts.map +1 -1
- package/lib/credential-provider.js +10 -4
- package/lib/credential-provider.js.map +1 -1
- package/lib/delegation/delegation-chain.d.ts +8 -0
- package/lib/delegation/delegation-chain.d.ts.map +1 -0
- package/lib/delegation/delegation-chain.js +33 -0
- package/lib/delegation/delegation-chain.js.map +1 -0
- package/lib/delegation/delegation-fixtures.d.ts +69 -0
- package/lib/delegation/delegation-fixtures.d.ts.map +1 -0
- package/lib/delegation/delegation-fixtures.js +553 -0
- package/lib/delegation/delegation-fixtures.js.map +1 -0
- package/lib/delegation/delegation-issuance.d.ts +19 -0
- package/lib/delegation/delegation-issuance.d.ts.map +1 -0
- package/lib/delegation/delegation-issuance.js +60 -0
- package/lib/delegation/delegation-issuance.js.map +1 -0
- package/lib/delegation/delegation-offer.d.ts +84 -0
- package/lib/delegation/delegation-offer.d.ts.map +1 -0
- package/lib/delegation/delegation-offer.js +349 -0
- package/lib/delegation/delegation-offer.js.map +1 -0
- package/lib/delegation/delegation-policy-validation.d.ts +28 -0
- package/lib/delegation/delegation-policy-validation.d.ts.map +1 -0
- package/lib/delegation/delegation-policy-validation.js +170 -0
- package/lib/delegation/delegation-policy-validation.js.map +1 -0
- package/lib/delegation/delegation-policy.d.ts +21 -0
- package/lib/delegation/delegation-policy.d.ts.map +1 -0
- package/lib/delegation/delegation-policy.js +73 -0
- package/lib/delegation/delegation-policy.js.map +1 -0
- package/lib/delegation/delegation-tree.d.ts +17 -0
- package/lib/delegation/delegation-tree.d.ts.map +1 -0
- package/lib/delegation/delegation-tree.js +58 -0
- package/lib/delegation/delegation-tree.js.map +1 -0
- package/lib/delegation/delegation-types.d.ts +56 -0
- package/lib/delegation/delegation-types.d.ts.map +1 -0
- package/lib/delegation/delegation-types.js +3 -0
- package/lib/delegation/delegation-types.js.map +1 -0
- package/lib/delegation/delegation-utils.d.ts +3 -0
- package/lib/delegation/delegation-utils.d.ts.map +1 -0
- package/lib/delegation/delegation-utils.js +10 -0
- package/lib/delegation/delegation-utils.js.map +1 -0
- package/lib/did-provider.d.ts +2 -1
- package/lib/did-provider.d.ts.map +1 -1
- package/lib/did-provider.js +11 -7
- package/lib/did-provider.js.map +1 -1
- package/lib/message-provider.js +1 -1
- package/lib/message-provider.js.map +1 -1
- package/lib/verification-controller.d.ts +30 -11
- package/lib/verification-controller.d.ts.map +1 -1
- package/lib/verification-controller.js +372 -68
- package/lib/verification-controller.js.map +1 -1
- package/package.json +3 -3
- package/src/cloud-wallet.test.js +369 -0
- package/src/cloud-wallet.ts +206 -18
- package/src/credential-provider.ts +13 -4
- package/src/delegation/delegation-chain.test.ts +64 -0
- package/src/delegation/delegation-chain.ts +34 -0
- package/src/delegation/delegation-fixtures.ts +552 -0
- package/src/delegation/delegation-issuance.ts +92 -0
- package/src/delegation/delegation-offer.ts +488 -0
- package/src/delegation/delegation-policy-validation.test.ts +237 -0
- package/src/delegation/delegation-policy-validation.ts +281 -0
- package/src/delegation/delegation-policy.ts +100 -0
- package/src/delegation/delegation-tree.test.ts +110 -0
- package/src/delegation/delegation-tree.ts +60 -0
- package/src/delegation/delegation-types.ts +65 -0
- package/src/delegation/delegation-utils.ts +10 -0
- package/src/did-provider.ts +10 -6
- package/src/globals.d.ts +6 -0
- package/src/message-provider.ts +1 -1
- package/src/verification-controller.test.ts +23 -0
- package/src/verification-controller.ts +534 -82
- package/tsconfig.build.json +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
type DelegationOffer = {
|
|
2
|
+
id: string;
|
|
3
|
+
messageId?: string;
|
|
4
|
+
issuerDID?: string;
|
|
5
|
+
status: 'sent' | 'requested' | 'accepted' | 'rejected';
|
|
6
|
+
expiresAt?: string;
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
};
|
|
9
|
+
export type DelegationOfferPreview = {
|
|
10
|
+
id: string;
|
|
11
|
+
issuerDID: string;
|
|
12
|
+
issuerName?: string;
|
|
13
|
+
role: string;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
expiresAt?: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function createDelegationOffer({ wallet, issuerDID, delegationPolicy, delegationRole, credentialId, expiresInMs, }: {
|
|
18
|
+
wallet: any;
|
|
19
|
+
issuerDID: string;
|
|
20
|
+
delegationPolicy: any;
|
|
21
|
+
delegationRole: string;
|
|
22
|
+
credentialId?: string;
|
|
23
|
+
expiresInMs?: number;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
id: string;
|
|
26
|
+
credentialId: string;
|
|
27
|
+
issuerDID: string;
|
|
28
|
+
issuerName: any;
|
|
29
|
+
issuer: {
|
|
30
|
+
did: string;
|
|
31
|
+
};
|
|
32
|
+
to: any;
|
|
33
|
+
delegationPolicy: import("./delegation-types").DelegationPolicy;
|
|
34
|
+
delegationRole: string;
|
|
35
|
+
capabilities: any[];
|
|
36
|
+
attributes: any[];
|
|
37
|
+
delegationConstraints: {};
|
|
38
|
+
sentAt: string;
|
|
39
|
+
expiresAt: string;
|
|
40
|
+
updatedAt: any;
|
|
41
|
+
status: string;
|
|
42
|
+
}>;
|
|
43
|
+
export declare function createOOBInvitation(issuerDID: any, delegationOffer: any, { goal, issuerName }: {
|
|
44
|
+
goal: string;
|
|
45
|
+
issuerName?: string;
|
|
46
|
+
}): string;
|
|
47
|
+
export declare function decodeMessage(message: any): any;
|
|
48
|
+
export declare function acceptDelegationOffer({ delegationOffer, wallet, messageProvider, }: {
|
|
49
|
+
delegationOffer: DelegationOffer;
|
|
50
|
+
wallet: any;
|
|
51
|
+
messageProvider: any;
|
|
52
|
+
}): Promise<void>;
|
|
53
|
+
export declare const INVITATION_HANDLER: {
|
|
54
|
+
check: (message: any) => boolean;
|
|
55
|
+
handle: (message: any, { wallet }: {
|
|
56
|
+
wallet: any;
|
|
57
|
+
}) => Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
export declare const DELEGATION_REQUEST_HANDLER: {
|
|
60
|
+
check: (message: any) => boolean;
|
|
61
|
+
handle: (message: any, { wallet, messageProvider }: {
|
|
62
|
+
wallet: any;
|
|
63
|
+
messageProvider: any;
|
|
64
|
+
}) => Promise<void>;
|
|
65
|
+
};
|
|
66
|
+
export declare const ISSUE_CREDENTIAL_HANDLER: {
|
|
67
|
+
check: (message: any) => boolean;
|
|
68
|
+
handle: (message: any, { wallet, messageProvider }: {
|
|
69
|
+
wallet: any;
|
|
70
|
+
messageProvider: any;
|
|
71
|
+
}) => Promise<void>;
|
|
72
|
+
};
|
|
73
|
+
export declare const messageHandlers: {
|
|
74
|
+
check: (message: any) => boolean;
|
|
75
|
+
handle: (message: any, { wallet }: {
|
|
76
|
+
wallet: any;
|
|
77
|
+
}) => Promise<void>;
|
|
78
|
+
}[];
|
|
79
|
+
export declare function handleMessage(message: any, context: {
|
|
80
|
+
wallet: any;
|
|
81
|
+
messageProvider: any;
|
|
82
|
+
}): Promise<void>;
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=delegation-offer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-offer.d.ts","sourceRoot":"","sources":["../../src/delegation/delegation-offer.ts"],"names":[],"mappings":"AAwCA,KAAK,eAAe,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,wBAAsB,qBAAqB,CAAC,EAC1C,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,WAAyC,GAC1C,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,GAAG,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;;;;;;;;;;;;;;;GA0DA;AAGD,wBAAgB,mBAAmB,CACjC,SAAS,KAAA,EACT,eAAe,KAAA,EACf,EAAC,IAAI,EAAE,UAAU,EAAC,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAC,UAsCxD;AAID,wBAAgB,aAAa,CAAC,OAAO,KAAA,OAkBpC;AAED,wBAAsB,qBAAqB,CAAC,EAC1C,eAAe,EACf,MAAM,EACN,eAAe,GAChB,EAAE;IACD,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,GAAG,CAAC;IACZ,eAAe,EAAE,GAAG,CAAC;CACtB,iBA6BA;AAGD,eAAO,MAAM,kBAAkB;;;;;CA0B9B,CAAC;AAEF,eAAO,MAAM,0BAA0B;;;;;;CA0GtC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;CAiFpC,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;GAI3B,CAAC;AAEF,wBAAsB,aAAa,CACjC,OAAO,KAAA,EACP,OAAO,EAAE;IACP,MAAM,MAAC;IACP,eAAe,MAAC;CACjB,iBAiBF"}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.messageHandlers = exports.ISSUE_CREDENTIAL_HANDLER = exports.DELEGATION_REQUEST_HANDLER = exports.INVITATION_HANDLER = void 0;
|
|
7
|
+
exports.createDelegationOffer = createDelegationOffer;
|
|
8
|
+
exports.createOOBInvitation = createOOBInvitation;
|
|
9
|
+
exports.decodeMessage = decodeMessage;
|
|
10
|
+
exports.acceptDelegationOffer = acceptDelegationOffer;
|
|
11
|
+
exports.handleMessage = handleMessage;
|
|
12
|
+
const assert_1 = __importDefault(require("assert"));
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
const logger_1 = require("@docknetwork/wallet-sdk-data-store/lib/logger");
|
|
15
|
+
const did_provider_1 = require("../did-provider");
|
|
16
|
+
const delegation_issuance_1 = require("./delegation-issuance");
|
|
17
|
+
const delegation_chain_1 = require("./delegation-chain");
|
|
18
|
+
const delegation_policy_1 = require("./delegation-policy");
|
|
19
|
+
const delegation_utils_1 = require("./delegation-utils");
|
|
20
|
+
const delegation_policy_validation_1 = require("./delegation-policy-validation");
|
|
21
|
+
const GOAL_CODE = 'dock.offer-delegation';
|
|
22
|
+
const OOB_INVITATION = 'https://didcomm.org/out-of-band/2.0/invitation';
|
|
23
|
+
const REQUEST_CREDENTIAL = 'https://didcomm.org/issue-credential/3.0/request-credential';
|
|
24
|
+
const ISSUE_CREDENTIAL = 'https://didcomm.org/issue-credential/3.0/issue-credential';
|
|
25
|
+
const ACK = 'https://didcomm.org/issue-credential/3.0/ack';
|
|
26
|
+
function base64urlEncode(input) {
|
|
27
|
+
return Buffer.from(input, 'utf8')
|
|
28
|
+
.toString('base64')
|
|
29
|
+
.replace(/\+/g, '-')
|
|
30
|
+
.replace(/\//g, '_')
|
|
31
|
+
.replace(/=+$/, '');
|
|
32
|
+
}
|
|
33
|
+
function base64urlDecode(input) {
|
|
34
|
+
const padded = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
35
|
+
const padLen = (4 - (padded.length % 4)) % 4;
|
|
36
|
+
return Buffer.from(padded + '='.repeat(padLen), 'base64').toString('utf8');
|
|
37
|
+
}
|
|
38
|
+
function pickDID(value) {
|
|
39
|
+
if (!value)
|
|
40
|
+
return undefined;
|
|
41
|
+
return Array.isArray(value) ? value[0] : value;
|
|
42
|
+
}
|
|
43
|
+
const DEFAULT_OFFER_EXPIRATION_MS = 24 * 60 * 60 * 1000;
|
|
44
|
+
async function createDelegationOffer({ wallet, issuerDID, delegationPolicy, delegationRole, credentialId, expiresInMs = DEFAULT_OFFER_EXPIRATION_MS, }) {
|
|
45
|
+
(0, delegation_policy_validation_1.validateDelegationPolicy)(delegationPolicy);
|
|
46
|
+
(0, assert_1.default)(delegationPolicy.ruleset.roles.some(r => r.roleId === delegationRole), `delegationRole "${delegationRole}" not found in delegationPolicy.ruleset.roles`);
|
|
47
|
+
if (credentialId) {
|
|
48
|
+
const parentCredential = await wallet.getDocumentById(credentialId);
|
|
49
|
+
if (parentCredential) {
|
|
50
|
+
(0, assert_1.default)((0, delegation_utils_1.isDelegatableCredential)(parentCredential), `Credential ${credentialId} is not delegatable`);
|
|
51
|
+
const parentDetails = await (0, delegation_policy_1.getDelegationDetails)(parentCredential, wallet);
|
|
52
|
+
if (parentDetails.delegationPolicy) {
|
|
53
|
+
(0, delegation_policy_validation_1.assertPolicyConformsToParent)(delegationPolicy, parentDetails.delegationPolicy, {
|
|
54
|
+
delegationRole,
|
|
55
|
+
remainingDepth: parentDetails.remainingDelegationDepth,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const dids = await (0, did_provider_1.getAllDIDs)({ wallet });
|
|
61
|
+
const issuer = dids.find(d => d.didDocument.id === issuerDID);
|
|
62
|
+
const issuerName = issuer?.name;
|
|
63
|
+
const offerId = (0, uuid_1.v4)();
|
|
64
|
+
const sentAt = new Date();
|
|
65
|
+
const delegationOffer = {
|
|
66
|
+
id: offerId,
|
|
67
|
+
credentialId: credentialId,
|
|
68
|
+
issuerDID,
|
|
69
|
+
issuerName,
|
|
70
|
+
issuer: {
|
|
71
|
+
did: issuerDID,
|
|
72
|
+
},
|
|
73
|
+
to: undefined,
|
|
74
|
+
delegationPolicy,
|
|
75
|
+
delegationRole,
|
|
76
|
+
capabilities: [],
|
|
77
|
+
attributes: [],
|
|
78
|
+
delegationConstraints: {},
|
|
79
|
+
sentAt: sentAt.toISOString(),
|
|
80
|
+
expiresAt: new Date(sentAt.getTime() + expiresInMs).toISOString(),
|
|
81
|
+
updatedAt: null,
|
|
82
|
+
status: 'sent',
|
|
83
|
+
};
|
|
84
|
+
// Persist on the issuer side so DELEGATION_REQUEST_HANDLER can look it up
|
|
85
|
+
// when the holder replies with a credential request.
|
|
86
|
+
await wallet.addDocument({
|
|
87
|
+
type: 'DelegationOffer',
|
|
88
|
+
...delegationOffer,
|
|
89
|
+
});
|
|
90
|
+
return delegationOffer;
|
|
91
|
+
}
|
|
92
|
+
// OOB invitation (issuer → holder via QR/link)
|
|
93
|
+
function createOOBInvitation(issuerDID, delegationOffer, { goal, issuerName }) {
|
|
94
|
+
(0, assert_1.default)(!!goal, 'goal is required');
|
|
95
|
+
const finalIssuerName = issuerName ?? delegationOffer.issuerName;
|
|
96
|
+
const preview = {
|
|
97
|
+
id: delegationOffer.id,
|
|
98
|
+
issuerDID: issuerDID,
|
|
99
|
+
issuerName: finalIssuerName,
|
|
100
|
+
role: delegationOffer.delegationRole,
|
|
101
|
+
createdAt: delegationOffer.sentAt,
|
|
102
|
+
expiresAt: delegationOffer.expiresAt,
|
|
103
|
+
};
|
|
104
|
+
const delegationOfferMessage = {
|
|
105
|
+
type: OOB_INVITATION,
|
|
106
|
+
id: delegationOffer.id,
|
|
107
|
+
from: issuerDID,
|
|
108
|
+
body: {
|
|
109
|
+
goal_code: GOAL_CODE,
|
|
110
|
+
goal,
|
|
111
|
+
offer_id: delegationOffer.id,
|
|
112
|
+
},
|
|
113
|
+
attachments: [
|
|
114
|
+
{
|
|
115
|
+
id: delegationOffer.id,
|
|
116
|
+
media_type: 'application/json',
|
|
117
|
+
data: { json: preview },
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
const offerUrl = 'didcomm://?_oob=' +
|
|
122
|
+
base64urlEncode(JSON.stringify(delegationOfferMessage));
|
|
123
|
+
return offerUrl;
|
|
124
|
+
}
|
|
125
|
+
// Decode an OOB invitation URL into a DIDComm message object.
|
|
126
|
+
// Returns the input unchanged if it's already an object.
|
|
127
|
+
function decodeMessage(message) {
|
|
128
|
+
if (typeof message !== 'string') {
|
|
129
|
+
return message;
|
|
130
|
+
}
|
|
131
|
+
const oobPrefix = 'didcomm://?_oob=';
|
|
132
|
+
if (!message.startsWith(oobPrefix)) {
|
|
133
|
+
logger_1.logger.debug('decodeMessage: unrecognized URL scheme, skipping');
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const encoded = message.slice(oobPrefix.length);
|
|
137
|
+
try {
|
|
138
|
+
return JSON.parse(base64urlDecode(encoded));
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
logger_1.logger.error(`decodeMessage: failed to decode OOB payload: ${err}`);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function acceptDelegationOffer({ delegationOffer, wallet, messageProvider, }) {
|
|
146
|
+
const issuerDID = delegationOffer.issuerDID;
|
|
147
|
+
const holderDID = await (0, did_provider_1.getDefaultDID)({ wallet });
|
|
148
|
+
const dids = await (0, did_provider_1.getAllDIDs)({ wallet });
|
|
149
|
+
const holderName = dids.find(d => d.didDocument.id === holderDID)?.name;
|
|
150
|
+
const requestCredentialMessage = {
|
|
151
|
+
type: REQUEST_CREDENTIAL,
|
|
152
|
+
pthid: delegationOffer.messageId, // parent thread = the OOB invitation
|
|
153
|
+
from: holderDID,
|
|
154
|
+
to: issuerDID,
|
|
155
|
+
body: {
|
|
156
|
+
goal_code: GOAL_CODE,
|
|
157
|
+
sender_profile: { name: holderName },
|
|
158
|
+
offer_id: delegationOffer.id,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
await messageProvider.sendMessage(requestCredentialMessage);
|
|
162
|
+
// Mirror issuer-side bookkeeping: mark the holder's stored offer as accepted.
|
|
163
|
+
const storedOffer = await wallet.getDocumentById(delegationOffer.id);
|
|
164
|
+
if (storedOffer) {
|
|
165
|
+
await wallet.updateDocument({
|
|
166
|
+
...storedOffer,
|
|
167
|
+
status: 'requested',
|
|
168
|
+
updatedAt: new Date().toISOString(),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Delegation message handlers
|
|
173
|
+
exports.INVITATION_HANDLER = {
|
|
174
|
+
check: function (message) {
|
|
175
|
+
return (message.type === OOB_INVITATION && message.body?.goal_code === GOAL_CODE);
|
|
176
|
+
},
|
|
177
|
+
handle: async function (message, { wallet }) {
|
|
178
|
+
const offerAttachment = message.attachments?.[0]?.data?.json ?? {};
|
|
179
|
+
const delegationOffer = {
|
|
180
|
+
...offerAttachment,
|
|
181
|
+
id: message.body.offer_id,
|
|
182
|
+
messageId: message.id,
|
|
183
|
+
issuerDID: message.from,
|
|
184
|
+
status: 'sent',
|
|
185
|
+
};
|
|
186
|
+
await wallet.addDocument({
|
|
187
|
+
type: 'DelegationOffer',
|
|
188
|
+
...delegationOffer,
|
|
189
|
+
});
|
|
190
|
+
logger_1.logger.debug(`INVITATION_HANDLER: emitting delegationOfferReceived for offer ${delegationOffer.id}`);
|
|
191
|
+
wallet.eventManager.emit('delegationOfferReceived', delegationOffer);
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
exports.DELEGATION_REQUEST_HANDLER = {
|
|
195
|
+
check: function (message) {
|
|
196
|
+
return (message.type === REQUEST_CREDENTIAL &&
|
|
197
|
+
message.body?.goal_code === GOAL_CODE);
|
|
198
|
+
},
|
|
199
|
+
handle: async function (message, { wallet, messageProvider }) {
|
|
200
|
+
const offerId = message.body.offer_id;
|
|
201
|
+
const delegationOffer = await wallet.getDocumentById(offerId);
|
|
202
|
+
if (!delegationOffer) {
|
|
203
|
+
logger_1.logger.debug(`DELEGATION_REQUEST_HANDLER: no matching delegation offer found for request ${offerId}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Authorization checks: only the targeted holder (if any) may accept,
|
|
207
|
+
// and the offer must still be in the 'sent' state to prevent replay.
|
|
208
|
+
if (delegationOffer.status !== 'sent') {
|
|
209
|
+
logger_1.logger.warn(`DELEGATION_REQUEST_HANDLER: rejecting request for offer ${offerId} — already ${delegationOffer.status}`);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (delegationOffer.to) {
|
|
213
|
+
const targets = Array.isArray(delegationOffer.to)
|
|
214
|
+
? delegationOffer.to
|
|
215
|
+
: [delegationOffer.to];
|
|
216
|
+
if (!targets.includes(message.from)) {
|
|
217
|
+
logger_1.logger.warn(`DELEGATION_REQUEST_HANDLER: rejecting request for offer ${offerId} — sender does not match offer.to`);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (delegationOffer.expiresAt &&
|
|
222
|
+
new Date(delegationOffer.expiresAt) < new Date()) {
|
|
223
|
+
logger_1.logger.debug(`DELEGATION_REQUEST_HANDLER: rejecting expired offer ${offerId}`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const parentCredential = await wallet.getDocumentById(delegationOffer.credentialId);
|
|
227
|
+
try {
|
|
228
|
+
(0, delegation_policy_validation_1.validateDelegationPolicy)(delegationOffer.delegationPolicy);
|
|
229
|
+
if (parentCredential && (0, delegation_utils_1.isDelegatableCredential)(parentCredential)) {
|
|
230
|
+
const parentDetails = await (0, delegation_policy_1.getDelegationDetails)(parentCredential, wallet);
|
|
231
|
+
if (parentDetails.delegationPolicy) {
|
|
232
|
+
(0, delegation_policy_validation_1.assertPolicyConformsToParent)(delegationOffer.delegationPolicy, parentDetails.delegationPolicy, {
|
|
233
|
+
delegationRole: delegationOffer.delegationRole,
|
|
234
|
+
remainingDepth: parentDetails.remainingDelegationDepth,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
logger_1.logger.warn(`DELEGATION_REQUEST_HANDLER: rejecting offer ${offerId} — policy validation failed: ${err.message}`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const holderDID = message.from;
|
|
244
|
+
delegationOffer.status = 'accepted';
|
|
245
|
+
delegationOffer.holderDID = holderDID;
|
|
246
|
+
delegationOffer.updatedAt = new Date().toISOString();
|
|
247
|
+
await wallet.updateDocument(delegationOffer);
|
|
248
|
+
const issuerDID = pickDID(message.to);
|
|
249
|
+
const delegatedCredential = await (0, delegation_issuance_1.delegateCredential)({
|
|
250
|
+
credential: parentCredential,
|
|
251
|
+
wallet,
|
|
252
|
+
delegationPolicy: delegationOffer.delegationPolicy,
|
|
253
|
+
roleId: delegationOffer.delegationRole,
|
|
254
|
+
delegatorDID: delegationOffer.issuerDID || issuerDID,
|
|
255
|
+
});
|
|
256
|
+
const delegationChain = await (0, delegation_chain_1.getDelegationChain)(parentCredential, wallet);
|
|
257
|
+
await messageProvider.sendMessage({
|
|
258
|
+
type: ISSUE_CREDENTIAL,
|
|
259
|
+
from: issuerDID,
|
|
260
|
+
to: holderDID,
|
|
261
|
+
message: {
|
|
262
|
+
goal_code: GOAL_CODE,
|
|
263
|
+
delegationOfferId: delegationOffer.id,
|
|
264
|
+
credentials: [delegatedCredential],
|
|
265
|
+
delegationChain,
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
exports.ISSUE_CREDENTIAL_HANDLER = {
|
|
271
|
+
check: function (message) {
|
|
272
|
+
return (message.type === ISSUE_CREDENTIAL &&
|
|
273
|
+
message.body?.goal_code === GOAL_CODE);
|
|
274
|
+
},
|
|
275
|
+
handle: async function (message, { wallet, messageProvider }) {
|
|
276
|
+
const offerId = message.body.delegationOfferId;
|
|
277
|
+
if (!offerId) {
|
|
278
|
+
logger_1.logger.debug('ISSUE_CREDENTIAL_HANDLER: missing delegationOfferId in message body');
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const storedOffer = await wallet.getDocumentById(offerId);
|
|
282
|
+
if (!storedOffer) {
|
|
283
|
+
logger_1.logger.debug(`ISSUE_CREDENTIAL_HANDLER: no stored offer found for ${offerId}`);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// SECURITY: only accept credentials from the DID that originally made the offer
|
|
287
|
+
if (message.from !== storedOffer.issuerDID) {
|
|
288
|
+
logger_1.logger.debug(`ISSUE_CREDENTIAL_HANDLER: rejecting credential for offer ${offerId} — sender ${message.from} does not match stored issuerDID ${storedOffer.issuerDID}`);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const credentials = message.body.credentials ?? [];
|
|
292
|
+
const delegationChain = message.body.delegationChain ?? [];
|
|
293
|
+
if (credentials.length === 0) {
|
|
294
|
+
logger_1.logger.debug(`ISSUE_CREDENTIAL_HANDLER: no credentials in message for offer ${offerId}`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
for (const credential of credentials) {
|
|
298
|
+
await wallet.addDocument(credential);
|
|
299
|
+
}
|
|
300
|
+
for (const ancestor of delegationChain) {
|
|
301
|
+
const existing = await wallet.getDocumentById(ancestor.id);
|
|
302
|
+
if (!existing) {
|
|
303
|
+
await wallet.addDocument(ancestor);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
await wallet.updateDocument({
|
|
307
|
+
...storedOffer,
|
|
308
|
+
status: 'accepted',
|
|
309
|
+
updatedAt: new Date().toISOString(),
|
|
310
|
+
});
|
|
311
|
+
const holderDID = pickDID(message.to);
|
|
312
|
+
const issuerDID = message.from;
|
|
313
|
+
await messageProvider.sendMessage({
|
|
314
|
+
type: ACK,
|
|
315
|
+
from: holderDID,
|
|
316
|
+
to: issuerDID,
|
|
317
|
+
pthid: message.id,
|
|
318
|
+
body: {
|
|
319
|
+
goal_code: GOAL_CODE,
|
|
320
|
+
delegationOfferId: offerId,
|
|
321
|
+
status: 'OK',
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
wallet.eventManager.emit('delegatedCredentialReceived', {
|
|
325
|
+
delegationOfferId: offerId,
|
|
326
|
+
credentials,
|
|
327
|
+
delegationChain,
|
|
328
|
+
});
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
exports.messageHandlers = [
|
|
332
|
+
exports.INVITATION_HANDLER,
|
|
333
|
+
exports.DELEGATION_REQUEST_HANDLER,
|
|
334
|
+
exports.ISSUE_CREDENTIAL_HANDLER,
|
|
335
|
+
];
|
|
336
|
+
async function handleMessage(message, context) {
|
|
337
|
+
const decoded = decodeMessage(message);
|
|
338
|
+
if (!decoded) {
|
|
339
|
+
logger_1.logger.debug('handleMessage: message could not be decoded, skipping');
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const handler = exports.messageHandlers.find(h => h.check(decoded));
|
|
343
|
+
if (!handler) {
|
|
344
|
+
logger_1.logger.debug(`handleMessage: no handler matched message type ${decoded.type}`);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
return handler.handle(decoded, context);
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=delegation-offer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-offer.js","sourceRoot":"","sources":["../../src/delegation/delegation-offer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DelegationPolicy } from './delegation-types';
|
|
2
|
+
export declare const MAX_DELEGATION_DEPTH = 9;
|
|
3
|
+
export declare const ALLOWED_LIFETIME_UNITS: readonly ["days", "months", "years"];
|
|
4
|
+
export declare const ALLOWED_GRANT_TYPES: readonly ["boolean", "array", "integer"];
|
|
5
|
+
export declare const ALLOWED_DELEGATION_TARGETS: readonly ["single-credential"];
|
|
6
|
+
export declare function lifetimeToDays(lifetime: {
|
|
7
|
+
value: number;
|
|
8
|
+
unit: string;
|
|
9
|
+
}): number;
|
|
10
|
+
/**
|
|
11
|
+
* Validate the structural integrity of a delegation policy.
|
|
12
|
+
*
|
|
13
|
+
* Throws on the first failure. Only checks invariants that downstream code
|
|
14
|
+
* relies on or that have security implications — fields like display labels
|
|
15
|
+
* and metadata strings are left to the type contract.
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateDelegationPolicy(policy: any): asserts policy is DelegationPolicy;
|
|
18
|
+
/**
|
|
19
|
+
* Assert that a delegation policy is a valid narrowing of a parent policy.
|
|
20
|
+
*
|
|
21
|
+
* Run after `validateDelegationPolicy(policy)` succeeds. The parent policy is
|
|
22
|
+
* trusted to already be valid (it came from a credential we issued or accepted).
|
|
23
|
+
*/
|
|
24
|
+
export declare function assertPolicyConformsToParent(policy: DelegationPolicy, parentPolicy: DelegationPolicy, { delegationRole, remainingDepth, }: {
|
|
25
|
+
delegationRole: string;
|
|
26
|
+
remainingDepth: number;
|
|
27
|
+
}): void;
|
|
28
|
+
//# sourceMappingURL=delegation-policy-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-policy-validation.d.ts","sourceRoot":"","sources":["../../src/delegation/delegation-policy-validation.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,gBAAgB,EAEjB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,sBAAsB,sCAAuC,CAAC;AAC3E,eAAO,MAAM,mBAAmB,0CAA2C,CAAC;AAC5E,eAAO,MAAM,0BAA0B,gCAAiC,CAAC;AAMzE,wBAAgB,cAAc,CAAC,QAAQ,EAAE;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAAG,MAAM,CAM9E;AA8DD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,gBAAgB,CA0HxF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,gBAAgB,EACxB,YAAY,EAAE,gBAAgB,EAC9B,EACE,cAAc,EACd,cAAc,GACf,EAAE;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAC,QAqDpD"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ALLOWED_DELEGATION_TARGETS = exports.ALLOWED_GRANT_TYPES = exports.ALLOWED_LIFETIME_UNITS = exports.MAX_DELEGATION_DEPTH = void 0;
|
|
7
|
+
exports.lifetimeToDays = lifetimeToDays;
|
|
8
|
+
exports.validateDelegationPolicy = validateDelegationPolicy;
|
|
9
|
+
exports.assertPolicyConformsToParent = assertPolicyConformsToParent;
|
|
10
|
+
const assert_1 = __importDefault(require("assert"));
|
|
11
|
+
exports.MAX_DELEGATION_DEPTH = 9;
|
|
12
|
+
exports.ALLOWED_LIFETIME_UNITS = ['days', 'months', 'years'];
|
|
13
|
+
exports.ALLOWED_GRANT_TYPES = ['boolean', 'array', 'integer'];
|
|
14
|
+
exports.ALLOWED_DELEGATION_TARGETS = ['single-credential'];
|
|
15
|
+
function isPlainObject(value) {
|
|
16
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function lifetimeToDays(lifetime) {
|
|
19
|
+
const numeric = Number(lifetime?.value);
|
|
20
|
+
if (!Number.isFinite(numeric))
|
|
21
|
+
return 0;
|
|
22
|
+
if (lifetime.unit === 'months')
|
|
23
|
+
return numeric * 30;
|
|
24
|
+
if (lifetime.unit === 'years')
|
|
25
|
+
return numeric * 365;
|
|
26
|
+
return numeric;
|
|
27
|
+
}
|
|
28
|
+
function getGrantsByCapability(role) {
|
|
29
|
+
const out = {};
|
|
30
|
+
for (const grant of role.capabilityGrants || []) {
|
|
31
|
+
out[grant.capability] = grant;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function getAncestorChain(role, rolesById) {
|
|
36
|
+
const chain = [];
|
|
37
|
+
let cursor = role.parentRoleId ? rolesById[role.parentRoleId] : null;
|
|
38
|
+
const visited = new Set();
|
|
39
|
+
while (cursor && !visited.has(cursor.roleId)) {
|
|
40
|
+
visited.add(cursor.roleId);
|
|
41
|
+
chain.push(cursor);
|
|
42
|
+
cursor = cursor.parentRoleId ? rolesById[cursor.parentRoleId] : null;
|
|
43
|
+
}
|
|
44
|
+
return chain;
|
|
45
|
+
}
|
|
46
|
+
function isSubset(child, parent) {
|
|
47
|
+
const set = new Set(parent);
|
|
48
|
+
return child.every(v => set.has(v));
|
|
49
|
+
}
|
|
50
|
+
function getEnum(schema) {
|
|
51
|
+
if (schema?.type === 'array' && Array.isArray(schema?.items?.enum)) {
|
|
52
|
+
return schema.items.enum;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function isWildcardAttrs(attrs) {
|
|
57
|
+
return attrs.length === 1 && attrs[0] === '*';
|
|
58
|
+
}
|
|
59
|
+
function assertGrantNarrows(childSchema, parentSchema, describe) {
|
|
60
|
+
if (childSchema.type === 'integer' && parentSchema.maximum !== undefined) {
|
|
61
|
+
(0, assert_1.default)(childSchema.maximum !== undefined && childSchema.maximum <= parentSchema.maximum, describe(`maximum exceeds parent ${parentSchema.maximum}`));
|
|
62
|
+
}
|
|
63
|
+
if (childSchema.type === 'array') {
|
|
64
|
+
const parentEnum = getEnum(parentSchema);
|
|
65
|
+
if (parentEnum) {
|
|
66
|
+
const childEnum = getEnum(childSchema);
|
|
67
|
+
(0, assert_1.default)(childEnum && isSubset(childEnum, parentEnum), describe('items.enum is not a subset of parent'));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate the structural integrity of a delegation policy.
|
|
73
|
+
*
|
|
74
|
+
* Throws on the first failure. Only checks invariants that downstream code
|
|
75
|
+
* relies on or that have security implications — fields like display labels
|
|
76
|
+
* and metadata strings are left to the type contract.
|
|
77
|
+
*/
|
|
78
|
+
function validateDelegationPolicy(policy) {
|
|
79
|
+
(0, assert_1.default)(isPlainObject(policy), 'delegationPolicy must be an object');
|
|
80
|
+
(0, assert_1.default)(policy.type === 'DelegationPolicy', `delegationPolicy.type must be 'DelegationPolicy'`);
|
|
81
|
+
(0, assert_1.default)(policy.name === undefined || typeof policy.name === 'string', 'delegationPolicy.name must be a string when present');
|
|
82
|
+
(0, assert_1.default)(isPlainObject(policy.ruleset), 'delegationPolicy.ruleset must be an object');
|
|
83
|
+
const ruleset = policy.ruleset;
|
|
84
|
+
(0, assert_1.default)(Array.isArray(ruleset.roles) && ruleset.roles.length > 0, 'delegationPolicy.ruleset.roles must be a non-empty array');
|
|
85
|
+
(0, assert_1.default)(Array.isArray(ruleset.capabilities), 'delegationPolicy.ruleset.capabilities must be an array');
|
|
86
|
+
(0, assert_1.default)(exports.ALLOWED_DELEGATION_TARGETS.includes(ruleset.delegationTarget), `delegationPolicy.ruleset.delegationTarget must be one of: ${exports.ALLOWED_DELEGATION_TARGETS.join(', ')}`);
|
|
87
|
+
(0, assert_1.default)(isPlainObject(ruleset.overallConstraints), 'overallConstraints must be an object');
|
|
88
|
+
const constraints = ruleset.overallConstraints;
|
|
89
|
+
(0, assert_1.default)(Number.isInteger(constraints.maxDelegationDepth) &&
|
|
90
|
+
constraints.maxDelegationDepth >= 0 &&
|
|
91
|
+
constraints.maxDelegationDepth <= exports.MAX_DELEGATION_DEPTH, `maxDelegationDepth must be an integer in [0, ${exports.MAX_DELEGATION_DEPTH}]`);
|
|
92
|
+
(0, assert_1.default)(isPlainObject(constraints.delegatedCredentialLifetime), 'delegatedCredentialLifetime must be an object');
|
|
93
|
+
const lifetime = constraints.delegatedCredentialLifetime;
|
|
94
|
+
(0, assert_1.default)(Number.isInteger(lifetime.value) && lifetime.value > 0, 'delegatedCredentialLifetime.value must be a positive integer');
|
|
95
|
+
(0, assert_1.default)(exports.ALLOWED_LIFETIME_UNITS.includes(lifetime.unit), `delegatedCredentialLifetime.unit must be one of: ${exports.ALLOWED_LIFETIME_UNITS.join(', ')}`);
|
|
96
|
+
const capabilitiesByName = {};
|
|
97
|
+
for (const cap of ruleset.capabilities) {
|
|
98
|
+
(0, assert_1.default)(!capabilitiesByName[cap.name], `duplicate capability name: ${cap.name}`);
|
|
99
|
+
(0, assert_1.default)(exports.ALLOWED_GRANT_TYPES.includes(cap.schema?.type), `capability "${cap.name}" schema.type must be one of: ${exports.ALLOWED_GRANT_TYPES.join(', ')}`);
|
|
100
|
+
capabilitiesByName[cap.name] = cap;
|
|
101
|
+
}
|
|
102
|
+
const rolesById = {};
|
|
103
|
+
let rootCount = 0;
|
|
104
|
+
for (const role of ruleset.roles) {
|
|
105
|
+
(0, assert_1.default)(!rolesById[role.roleId], `duplicate roleId: ${role.roleId}`);
|
|
106
|
+
rolesById[role.roleId] = role;
|
|
107
|
+
if (role.parentRoleId === null)
|
|
108
|
+
rootCount++;
|
|
109
|
+
}
|
|
110
|
+
(0, assert_1.default)(rootCount === 1, `ruleset must have exactly one root role, found ${rootCount}`);
|
|
111
|
+
for (const role of ruleset.roles) {
|
|
112
|
+
if (role.parentRoleId !== null) {
|
|
113
|
+
(0, assert_1.default)(rolesById[role.parentRoleId], `role ${role.roleId} references unknown parentRoleId ${role.parentRoleId}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
for (const role of ruleset.roles) {
|
|
117
|
+
for (const grant of role.capabilityGrants) {
|
|
118
|
+
const cap = capabilitiesByName[grant.capability];
|
|
119
|
+
(0, assert_1.default)(cap, `role ${role.roleId} grants unknown capability "${grant.capability}"`);
|
|
120
|
+
(0, assert_1.default)(grant.schema?.type === cap.schema.type, `role ${role.roleId} grant "${grant.capability}" schema.type must be "${cap.schema.type}"`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const role of ruleset.roles) {
|
|
124
|
+
const ancestors = getAncestorChain(role, rolesById);
|
|
125
|
+
if (ancestors.length === 0)
|
|
126
|
+
continue;
|
|
127
|
+
const childGrants = getGrantsByCapability(role);
|
|
128
|
+
for (const ancestor of ancestors) {
|
|
129
|
+
const ancestorGrants = getGrantsByCapability(ancestor);
|
|
130
|
+
for (const capName of Object.keys(childGrants)) {
|
|
131
|
+
(0, assert_1.default)(ancestorGrants[capName], `role ${role.roleId} grants "${capName}" but ancestor ${ancestor.roleId} does not`);
|
|
132
|
+
assertGrantNarrows(childGrants[capName].schema, ancestorGrants[capName].schema, suffix => `role ${role.roleId} grant "${capName}" ${suffix}`);
|
|
133
|
+
}
|
|
134
|
+
if (!isWildcardAttrs(ancestor.attributes) && !isWildcardAttrs(role.attributes)) {
|
|
135
|
+
(0, assert_1.default)(isSubset(role.attributes, ancestor.attributes), `role ${role.roleId} attributes are not a subset of ancestor ${ancestor.roleId} attributes`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Assert that a delegation policy is a valid narrowing of a parent policy.
|
|
142
|
+
*
|
|
143
|
+
* Run after `validateDelegationPolicy(policy)` succeeds. The parent policy is
|
|
144
|
+
* trusted to already be valid (it came from a credential we issued or accepted).
|
|
145
|
+
*/
|
|
146
|
+
function assertPolicyConformsToParent(policy, parentPolicy, { delegationRole, remainingDepth, }) {
|
|
147
|
+
(0, assert_1.default)(remainingDepth > 0, 'parent credential has no remaining delegation depth');
|
|
148
|
+
const childConstraints = policy.ruleset.overallConstraints;
|
|
149
|
+
const parentConstraints = parentPolicy.ruleset.overallConstraints;
|
|
150
|
+
(0, assert_1.default)(childConstraints.maxDelegationDepth <= parentConstraints.maxDelegationDepth, `maxDelegationDepth ${childConstraints.maxDelegationDepth} exceeds parent ${parentConstraints.maxDelegationDepth}`);
|
|
151
|
+
const parentDays = lifetimeToDays(parentConstraints.delegatedCredentialLifetime);
|
|
152
|
+
const childDays = lifetimeToDays(childConstraints.delegatedCredentialLifetime);
|
|
153
|
+
if (parentDays > 0) {
|
|
154
|
+
(0, assert_1.default)(childDays <= parentDays, `delegatedCredentialLifetime exceeds parent (${parentConstraints.delegatedCredentialLifetime.value} ${parentConstraints.delegatedCredentialLifetime.unit})`);
|
|
155
|
+
}
|
|
156
|
+
const childRole = policy.ruleset.roles.find(r => r.roleId === delegationRole);
|
|
157
|
+
(0, assert_1.default)(childRole, `delegationRole "${delegationRole}" not found in delegationPolicy.ruleset.roles`);
|
|
158
|
+
const parentRole = parentPolicy.ruleset.roles.find(r => r.roleId === delegationRole);
|
|
159
|
+
(0, assert_1.default)(parentRole, `delegationRole "${delegationRole}" not found in parent credential's policy`);
|
|
160
|
+
if (!isWildcardAttrs(parentRole.attributes) && !isWildcardAttrs(childRole.attributes)) {
|
|
161
|
+
(0, assert_1.default)(isSubset(childRole.attributes, parentRole.attributes), `delegationRole "${delegationRole}" attributes are not a subset of parent's attributes`);
|
|
162
|
+
}
|
|
163
|
+
const parentGrants = getGrantsByCapability(parentRole);
|
|
164
|
+
for (const grant of childRole.capabilityGrants) {
|
|
165
|
+
const parentGrant = parentGrants[grant.capability];
|
|
166
|
+
(0, assert_1.default)(parentGrant, `delegationRole "${delegationRole}" grants "${grant.capability}" which the parent does not`);
|
|
167
|
+
assertGrantNarrows(grant.schema, parentGrant.schema, suffix => `delegationRole "${delegationRole}" grant "${grant.capability}" ${suffix}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=delegation-policy-validation.js.map
|