@claudian-collab/protocol 1.0.0 → 2.0.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/README.md +8 -8
- package/dist/CollabAuthorityTransfer.d.ts +296 -0
- package/dist/CollabAuthorityTransfer.js +877 -0
- package/dist/CollabCloudBinding.d.ts +43 -3
- package/dist/CollabCloudBinding.js +151 -10
- package/dist/CollabCloudProjectEvent.d.ts +12 -1
- package/dist/CollabCloudProjectEvent.js +21 -0
- package/dist/CollabConstants.d.ts +1 -1
- package/dist/CollabConstants.js +1 -1
- package/dist/CollabControlOperationCodecs.d.ts +17 -0
- package/dist/CollabControlOperationCodecs.js +44 -0
- package/dist/CollabError.d.ts +1 -1
- package/dist/CollabError.js +16 -0
- package/dist/CollabProjectCheckpoint.d.ts +275 -0
- package/dist/CollabProjectCheckpoint.js +1336 -0
- package/dist/CollabProjectRetirement.d.ts +44 -0
- package/dist/CollabProjectRetirement.js +127 -0
- package/dist/CollabProtocol.d.ts +3 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +49 -2
- package/package.json +1 -1
|
@@ -0,0 +1,877 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.COLLAB_AUTHORITY_TRANSFER_OPERATIONS = exports.COLLAB_AUTHORITY_TRANSFER_CANCELLABLE_PHASES = exports.COLLAB_AUTHORITY_TRANSFER_CANCELLATION_PHASES = exports.COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES = exports.COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES = void 0;
|
|
4
|
+
exports.decodeCollabAuthorityTransferProposal = decodeCollabAuthorityTransferProposal;
|
|
5
|
+
exports.decodeCollabTransferredMembershipClaimBatch = decodeCollabTransferredMembershipClaimBatch;
|
|
6
|
+
exports.encodeCollabTransferredMembershipClaimBatchDigestInput = encodeCollabTransferredMembershipClaimBatchDigestInput;
|
|
7
|
+
exports.decodeCollabTransferredMembershipClaimCustodyReceipt = decodeCollabTransferredMembershipClaimCustodyReceipt;
|
|
8
|
+
exports.decodeCollabTransferredMembershipClaim = decodeCollabTransferredMembershipClaim;
|
|
9
|
+
exports.encodeCollabTransferredMembershipRedemptionReceiptSigningInput = encodeCollabTransferredMembershipRedemptionReceiptSigningInput;
|
|
10
|
+
exports.decodeCollabTransferredMembershipRedemptionReceipt = decodeCollabTransferredMembershipRedemptionReceipt;
|
|
11
|
+
exports.encodeCollabAuthorityRelinquishmentProofSigningInput = encodeCollabAuthorityRelinquishmentProofSigningInput;
|
|
12
|
+
exports.decodeCollabAuthorityRelinquishmentProof = decodeCollabAuthorityRelinquishmentProof;
|
|
13
|
+
exports.decodeCollabAuthorityTransferLifecycleFence = decodeCollabAuthorityTransferLifecycleFence;
|
|
14
|
+
exports.decodeCollabAuthorityTransferStatus = decodeCollabAuthorityTransferStatus;
|
|
15
|
+
exports.decodeCollabAuthorityTransferOperationRequest = decodeCollabAuthorityTransferOperationRequest;
|
|
16
|
+
exports.decodeCollabAuthorityTransferOperationResponse = decodeCollabAuthorityTransferOperationResponse;
|
|
17
|
+
const CollabError_1 = require("./CollabError");
|
|
18
|
+
const CollabValidation_1 = require("./CollabValidation");
|
|
19
|
+
exports.COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES = Object.freeze([
|
|
20
|
+
'collecting-readiness',
|
|
21
|
+
'source-quiesced',
|
|
22
|
+
'checkpoint-received',
|
|
23
|
+
'checkpoint-validated',
|
|
24
|
+
'claims-retained',
|
|
25
|
+
'repository-published',
|
|
26
|
+
'source-relinquished',
|
|
27
|
+
'cloud-activated',
|
|
28
|
+
'completed',
|
|
29
|
+
]);
|
|
30
|
+
exports.COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES = Object.freeze([
|
|
31
|
+
'collecting-readiness',
|
|
32
|
+
'cloud-quiesced',
|
|
33
|
+
'checkpoint-captured',
|
|
34
|
+
'target-staged',
|
|
35
|
+
'claims-retained',
|
|
36
|
+
'cloud-relinquished',
|
|
37
|
+
'lan-activated',
|
|
38
|
+
'completed',
|
|
39
|
+
]);
|
|
40
|
+
exports.COLLAB_AUTHORITY_TRANSFER_CANCELLATION_PHASES = Object.freeze([
|
|
41
|
+
'cancel-intent',
|
|
42
|
+
'target-invalidated',
|
|
43
|
+
'target-cleaned',
|
|
44
|
+
'source-reopened',
|
|
45
|
+
'cancelled',
|
|
46
|
+
]);
|
|
47
|
+
exports.COLLAB_AUTHORITY_TRANSFER_CANCELLABLE_PHASES = Object.freeze([
|
|
48
|
+
'collecting-readiness',
|
|
49
|
+
'source-quiesced',
|
|
50
|
+
'checkpoint-received',
|
|
51
|
+
'checkpoint-validated',
|
|
52
|
+
'claims-retained',
|
|
53
|
+
'repository-published',
|
|
54
|
+
'cloud-quiesced',
|
|
55
|
+
'checkpoint-captured',
|
|
56
|
+
'target-staged',
|
|
57
|
+
'cancel-intent',
|
|
58
|
+
'target-invalidated',
|
|
59
|
+
'target-cleaned',
|
|
60
|
+
'source-reopened',
|
|
61
|
+
]);
|
|
62
|
+
exports.COLLAB_AUTHORITY_TRANSFER_OPERATIONS = Object.freeze([
|
|
63
|
+
'requestLanToCloudTransfer',
|
|
64
|
+
'acceptLanToCloudTransferTarget',
|
|
65
|
+
'beginLanToCloudTransfer',
|
|
66
|
+
'getProjectAuthorityTransfer',
|
|
67
|
+
'rotateTransferredMembershipClaims',
|
|
68
|
+
'acknowledgeTransferredMembershipClaimBatch',
|
|
69
|
+
'getTransferredMembershipClaim',
|
|
70
|
+
'claimTransferredMembership',
|
|
71
|
+
'acknowledgeTransferredMembershipClaimRedemption',
|
|
72
|
+
'commitLanToCloudRelinquishment',
|
|
73
|
+
'beginCloudToLanTransfer',
|
|
74
|
+
'acceptCloudToLanTransferTarget',
|
|
75
|
+
'reportCloudToLanTargetStaged',
|
|
76
|
+
'confirmCloudToLanTargetActive',
|
|
77
|
+
'cancelProjectAuthorityTransfer',
|
|
78
|
+
]);
|
|
79
|
+
const SHA256_PATTERN = /^[0-9a-f]{64}$/u;
|
|
80
|
+
const BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/u;
|
|
81
|
+
const BASE64URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
82
|
+
function invalidPayload(field) {
|
|
83
|
+
return new CollabError_1.CollabError({ code: 'protocol-payload-invalid', safeContext: { field } });
|
|
84
|
+
}
|
|
85
|
+
function record(value, field) {
|
|
86
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
87
|
+
throw invalidPayload(field);
|
|
88
|
+
}
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
function exactRecord(value, field, keys) {
|
|
92
|
+
const source = record(value, field);
|
|
93
|
+
const expected = new Set(keys);
|
|
94
|
+
if (!keys.every(key => Object.hasOwn(source, key))
|
|
95
|
+
|| Object.keys(source).some(key => !expected.has(key)))
|
|
96
|
+
throw invalidPayload(field);
|
|
97
|
+
return source;
|
|
98
|
+
}
|
|
99
|
+
function token(source, field, validate = CollabValidation_1.isCollabOpaqueId) {
|
|
100
|
+
const value = source[field];
|
|
101
|
+
if (typeof value !== 'string' || !validate(value))
|
|
102
|
+
throw invalidPayload(field);
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
function boundedString(source, field, maximumBytes) {
|
|
106
|
+
const value = source[field];
|
|
107
|
+
if (typeof value !== 'string'
|
|
108
|
+
|| value.length === 0
|
|
109
|
+
|| !(0, CollabValidation_1.hasUtf8ByteLengthAtMost)(value, maximumBytes))
|
|
110
|
+
throw invalidPayload(field);
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
function positiveInteger(source, field) {
|
|
114
|
+
const value = source[field];
|
|
115
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) {
|
|
116
|
+
throw invalidPayload(field);
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
function timestamp(source, field) {
|
|
121
|
+
const value = source[field];
|
|
122
|
+
if (typeof value !== 'string'
|
|
123
|
+
|| value.length > 64
|
|
124
|
+
|| Number.isNaN(Date.parse(value))
|
|
125
|
+
|| new Date(value).toISOString() !== value)
|
|
126
|
+
throw invalidPayload(field);
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
function sha256(source, field) {
|
|
130
|
+
const value = source[field];
|
|
131
|
+
if (typeof value !== 'string' || !SHA256_PATTERN.test(value))
|
|
132
|
+
throw invalidPayload(field);
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
function base64url(source, field, maximumBytes = 4096) {
|
|
136
|
+
const value = boundedString(source, field, maximumBytes);
|
|
137
|
+
if (!BASE64URL_PATTERN.test(value))
|
|
138
|
+
throw invalidPayload(field);
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
141
|
+
function fixedBase64url(source, field, decodedBytes) {
|
|
142
|
+
const encodedLength = Math.ceil(decodedBytes * 4 / 3);
|
|
143
|
+
const value = base64url(source, field, encodedLength);
|
|
144
|
+
const finalIndex = BASE64URL_ALPHABET.indexOf(value[value.length - 1]);
|
|
145
|
+
const remainder = value.length % 4;
|
|
146
|
+
if (value.length !== encodedLength
|
|
147
|
+
|| remainder === 1
|
|
148
|
+
|| (remainder === 2 && (finalIndex & 15) !== 0)
|
|
149
|
+
|| (remainder === 3 && (finalIndex & 3) !== 0))
|
|
150
|
+
throw invalidPayload(field);
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
function literal(source, field, values) {
|
|
154
|
+
const value = source[field];
|
|
155
|
+
if (typeof value !== 'string' || !values.includes(value))
|
|
156
|
+
throw invalidPayload(field);
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
function authority(value, field) {
|
|
160
|
+
const source = exactRecord(value, field, ['generation', 'kind']);
|
|
161
|
+
return {
|
|
162
|
+
generation: positiveInteger(source, 'generation'),
|
|
163
|
+
kind: literal(source, 'kind', ['cloud', 'lan']),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function absoluteTargetUrl(source) {
|
|
167
|
+
const targetUrl = boundedString(source, 'targetUrl', 2048);
|
|
168
|
+
let parsed;
|
|
169
|
+
try {
|
|
170
|
+
parsed = new URL(targetUrl);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
throw invalidPayload('targetUrl');
|
|
174
|
+
}
|
|
175
|
+
if ((parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
|
|
176
|
+
|| parsed.username.length > 0
|
|
177
|
+
|| parsed.password.length > 0
|
|
178
|
+
|| targetUrl.includes('?')
|
|
179
|
+
|| targetUrl.includes('#'))
|
|
180
|
+
throw invalidPayload('targetUrl');
|
|
181
|
+
return targetUrl;
|
|
182
|
+
}
|
|
183
|
+
function decodeCollabAuthorityTransferProposal(value) {
|
|
184
|
+
const source = exactRecord(value, 'proposal', [
|
|
185
|
+
'expectedSourceAuthority',
|
|
186
|
+
'idempotencyKey',
|
|
187
|
+
'projectId',
|
|
188
|
+
'proposedByMemberId',
|
|
189
|
+
'proposedAt',
|
|
190
|
+
'targetAuthorityKind',
|
|
191
|
+
'targetUrl',
|
|
192
|
+
]);
|
|
193
|
+
const expectedSourceAuthority = authority(source.expectedSourceAuthority, 'expectedSourceAuthority');
|
|
194
|
+
const targetAuthorityKind = literal(source, 'targetAuthorityKind', ['cloud', 'lan']);
|
|
195
|
+
if (expectedSourceAuthority.kind === targetAuthorityKind) {
|
|
196
|
+
throw invalidPayload('targetAuthorityKind');
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
expectedSourceAuthority,
|
|
200
|
+
idempotencyKey: token(source, 'idempotencyKey'),
|
|
201
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
202
|
+
proposedByMemberId: token(source, 'proposedByMemberId', CollabValidation_1.isCollabMemberId),
|
|
203
|
+
proposedAt: timestamp(source, 'proposedAt'),
|
|
204
|
+
targetAuthorityKind,
|
|
205
|
+
targetUrl: absoluteTargetUrl(source),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function claimItem(value) {
|
|
209
|
+
const source = exactRecord(value, 'claim', ['claim', 'memberId']);
|
|
210
|
+
return {
|
|
211
|
+
claim: base64url(source, 'claim'),
|
|
212
|
+
memberId: token(source, 'memberId', CollabValidation_1.isCollabMemberId),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function decodeCollabTransferredMembershipClaimBatch(value) {
|
|
216
|
+
const source = exactRecord(value, 'claimBatch', [
|
|
217
|
+
'batchRevision',
|
|
218
|
+
'batchSha256',
|
|
219
|
+
'checkpointSha256',
|
|
220
|
+
'claims',
|
|
221
|
+
'expiresAt',
|
|
222
|
+
'projectId',
|
|
223
|
+
'targetAuthorityGeneration',
|
|
224
|
+
'transferId',
|
|
225
|
+
]);
|
|
226
|
+
if (!Array.isArray(source.claims) || source.claims.length === 0) {
|
|
227
|
+
throw invalidPayload('claims');
|
|
228
|
+
}
|
|
229
|
+
const claims = source.claims.map(claimItem);
|
|
230
|
+
if (claims.some((item, index) => index > 0
|
|
231
|
+
&& claims[index - 1].memberId.localeCompare(item.memberId, 'en-US') >= 0)
|
|
232
|
+
|| new Set(claims.map(item => item.claim)).size !== claims.length)
|
|
233
|
+
throw invalidPayload('claims');
|
|
234
|
+
return {
|
|
235
|
+
batchRevision: positiveInteger(source, 'batchRevision'),
|
|
236
|
+
batchSha256: sha256(source, 'batchSha256'),
|
|
237
|
+
checkpointSha256: sha256(source, 'checkpointSha256'),
|
|
238
|
+
claims: Object.freeze(claims),
|
|
239
|
+
expiresAt: timestamp(source, 'expiresAt'),
|
|
240
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
241
|
+
targetAuthorityGeneration: positiveInteger(source, 'targetAuthorityGeneration'),
|
|
242
|
+
transferId: token(source, 'transferId'),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function encodeCollabTransferredMembershipClaimBatchDigestInput(batch) {
|
|
246
|
+
const decoded = decodeCollabTransferredMembershipClaimBatch(batch);
|
|
247
|
+
return JSON.stringify({
|
|
248
|
+
batchRevision: decoded.batchRevision,
|
|
249
|
+
checkpointSha256: decoded.checkpointSha256,
|
|
250
|
+
claims: decoded.claims,
|
|
251
|
+
expiresAt: decoded.expiresAt,
|
|
252
|
+
projectId: decoded.projectId,
|
|
253
|
+
targetAuthorityGeneration: decoded.targetAuthorityGeneration,
|
|
254
|
+
transferId: decoded.transferId,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function decodeCollabTransferredMembershipClaimCustodyReceipt(value) {
|
|
258
|
+
const source = exactRecord(value, 'custodyReceipt', [
|
|
259
|
+
'batchRevision',
|
|
260
|
+
'batchSha256',
|
|
261
|
+
'checkpointSha256',
|
|
262
|
+
'committedAt',
|
|
263
|
+
'custodyAuthority',
|
|
264
|
+
'operationIntentId',
|
|
265
|
+
'projectId',
|
|
266
|
+
'receiptId',
|
|
267
|
+
'submittedByMemberId',
|
|
268
|
+
'targetAuthorityGeneration',
|
|
269
|
+
'transferId',
|
|
270
|
+
]);
|
|
271
|
+
const custodyAuthority = authority(source.custodyAuthority, 'custodyAuthority');
|
|
272
|
+
const targetAuthorityGeneration = positiveInteger(source, 'targetAuthorityGeneration');
|
|
273
|
+
if (targetAuthorityGeneration !== custodyAuthority.generation + 1) {
|
|
274
|
+
throw invalidPayload('targetAuthorityGeneration');
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
batchRevision: positiveInteger(source, 'batchRevision'),
|
|
278
|
+
batchSha256: sha256(source, 'batchSha256'),
|
|
279
|
+
checkpointSha256: sha256(source, 'checkpointSha256'),
|
|
280
|
+
committedAt: timestamp(source, 'committedAt'),
|
|
281
|
+
custodyAuthority,
|
|
282
|
+
operationIntentId: token(source, 'operationIntentId'),
|
|
283
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
284
|
+
receiptId: token(source, 'receiptId'),
|
|
285
|
+
submittedByMemberId: token(source, 'submittedByMemberId', CollabValidation_1.isCollabMemberId),
|
|
286
|
+
targetAuthorityGeneration,
|
|
287
|
+
transferId: token(source, 'transferId'),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function decodeCollabTransferredMembershipClaim(value) {
|
|
291
|
+
const source = exactRecord(value, 'claim', [
|
|
292
|
+
'claim',
|
|
293
|
+
'expiresAt',
|
|
294
|
+
'memberId',
|
|
295
|
+
'projectId',
|
|
296
|
+
'targetAuthorityGeneration',
|
|
297
|
+
'transferId',
|
|
298
|
+
]);
|
|
299
|
+
return {
|
|
300
|
+
claim: base64url(source, 'claim'),
|
|
301
|
+
expiresAt: timestamp(source, 'expiresAt'),
|
|
302
|
+
memberId: token(source, 'memberId', CollabValidation_1.isCollabMemberId),
|
|
303
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
304
|
+
targetAuthorityGeneration: positiveInteger(source, 'targetAuthorityGeneration'),
|
|
305
|
+
transferId: token(source, 'transferId'),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
const REDEMPTION_RECEIPT_SIGNING_PAYLOAD_KEYS = [
|
|
309
|
+
'checkpointSha256',
|
|
310
|
+
'claimSha256',
|
|
311
|
+
'memberId',
|
|
312
|
+
'operationIntentId',
|
|
313
|
+
'projectId',
|
|
314
|
+
'receiptId',
|
|
315
|
+
'receiptKeyId',
|
|
316
|
+
'redeemedAt',
|
|
317
|
+
'signatureAlgorithm',
|
|
318
|
+
'targetAuthorityGeneration',
|
|
319
|
+
'transferId',
|
|
320
|
+
];
|
|
321
|
+
function redemptionReceiptSigningPayload(source) {
|
|
322
|
+
return {
|
|
323
|
+
checkpointSha256: sha256(source, 'checkpointSha256'),
|
|
324
|
+
claimSha256: sha256(source, 'claimSha256'),
|
|
325
|
+
memberId: token(source, 'memberId', CollabValidation_1.isCollabMemberId),
|
|
326
|
+
operationIntentId: token(source, 'operationIntentId'),
|
|
327
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
328
|
+
receiptId: token(source, 'receiptId'),
|
|
329
|
+
receiptKeyId: boundedString(source, 'receiptKeyId', 256),
|
|
330
|
+
redeemedAt: timestamp(source, 'redeemedAt'),
|
|
331
|
+
signatureAlgorithm: literal(source, 'signatureAlgorithm', ['ed25519']),
|
|
332
|
+
targetAuthorityGeneration: positiveInteger(source, 'targetAuthorityGeneration'),
|
|
333
|
+
transferId: token(source, 'transferId'),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function encodeCollabTransferredMembershipRedemptionReceiptSigningInput(payload) {
|
|
337
|
+
const source = exactRecord(payload, 'redemptionReceiptSigningPayload', REDEMPTION_RECEIPT_SIGNING_PAYLOAD_KEYS);
|
|
338
|
+
return JSON.stringify({
|
|
339
|
+
domain: 'claudian-collab.transferred-membership-redemption-receipt.v1',
|
|
340
|
+
payload: redemptionReceiptSigningPayload(source),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function decodeCollabTransferredMembershipRedemptionReceipt(value) {
|
|
344
|
+
const source = exactRecord(value, 'redemptionReceipt', [
|
|
345
|
+
...REDEMPTION_RECEIPT_SIGNING_PAYLOAD_KEYS,
|
|
346
|
+
'signature',
|
|
347
|
+
]);
|
|
348
|
+
const payload = redemptionReceiptSigningPayload(source);
|
|
349
|
+
return {
|
|
350
|
+
checkpointSha256: payload.checkpointSha256,
|
|
351
|
+
claimSha256: payload.claimSha256,
|
|
352
|
+
memberId: payload.memberId,
|
|
353
|
+
operationIntentId: payload.operationIntentId,
|
|
354
|
+
projectId: payload.projectId,
|
|
355
|
+
receiptId: payload.receiptId,
|
|
356
|
+
receiptKeyId: payload.receiptKeyId,
|
|
357
|
+
redeemedAt: payload.redeemedAt,
|
|
358
|
+
signature: fixedBase64url(source, 'signature', 64),
|
|
359
|
+
signatureAlgorithm: payload.signatureAlgorithm,
|
|
360
|
+
targetAuthorityGeneration: payload.targetAuthorityGeneration,
|
|
361
|
+
transferId: payload.transferId,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const RELINQUISHMENT_PROOF_SIGNING_PAYLOAD_KEYS = [
|
|
365
|
+
'batchRevision',
|
|
366
|
+
'batchSha256',
|
|
367
|
+
'certificateAlgorithm',
|
|
368
|
+
'checkpointSha256',
|
|
369
|
+
'committedAt',
|
|
370
|
+
'operationIntentId',
|
|
371
|
+
'projectId',
|
|
372
|
+
'sourceAuthority',
|
|
373
|
+
'sourceHostMemberId',
|
|
374
|
+
'targetAuthority',
|
|
375
|
+
'transferId',
|
|
376
|
+
];
|
|
377
|
+
function authorityRelinquishmentProofSigningPayload(source) {
|
|
378
|
+
const sourceAuthority = authority(source.sourceAuthority, 'sourceAuthority');
|
|
379
|
+
const targetAuthority = authority(source.targetAuthority, 'targetAuthority');
|
|
380
|
+
const sourceHostMemberId = source.sourceHostMemberId === null
|
|
381
|
+
? null
|
|
382
|
+
: token(source, 'sourceHostMemberId', CollabValidation_1.isCollabMemberId);
|
|
383
|
+
if (sourceAuthority.kind === targetAuthority.kind
|
|
384
|
+
|| targetAuthority.generation !== sourceAuthority.generation + 1
|
|
385
|
+
|| (sourceAuthority.kind === 'lan') !== (sourceHostMemberId !== null))
|
|
386
|
+
throw invalidPayload('targetAuthority');
|
|
387
|
+
return {
|
|
388
|
+
batchRevision: positiveInteger(source, 'batchRevision'),
|
|
389
|
+
batchSha256: sha256(source, 'batchSha256'),
|
|
390
|
+
certificateAlgorithm: literal(source, 'certificateAlgorithm', ['ed25519']),
|
|
391
|
+
checkpointSha256: sha256(source, 'checkpointSha256'),
|
|
392
|
+
committedAt: timestamp(source, 'committedAt'),
|
|
393
|
+
operationIntentId: token(source, 'operationIntentId'),
|
|
394
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
395
|
+
sourceAuthority,
|
|
396
|
+
sourceHostMemberId,
|
|
397
|
+
targetAuthority,
|
|
398
|
+
transferId: token(source, 'transferId'),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function encodeCollabAuthorityRelinquishmentProofSigningInput(payload) {
|
|
402
|
+
const source = exactRecord(payload, 'relinquishmentProofSigningPayload', RELINQUISHMENT_PROOF_SIGNING_PAYLOAD_KEYS);
|
|
403
|
+
return JSON.stringify({
|
|
404
|
+
domain: 'claudian-collab.authority-relinquishment-proof.v1',
|
|
405
|
+
payload: authorityRelinquishmentProofSigningPayload(source),
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function decodeCollabAuthorityRelinquishmentProof(value) {
|
|
409
|
+
const source = exactRecord(value, 'relinquishmentProof', [
|
|
410
|
+
...RELINQUISHMENT_PROOF_SIGNING_PAYLOAD_KEYS,
|
|
411
|
+
'certificate',
|
|
412
|
+
]);
|
|
413
|
+
const payload = authorityRelinquishmentProofSigningPayload(source);
|
|
414
|
+
return {
|
|
415
|
+
batchRevision: payload.batchRevision,
|
|
416
|
+
batchSha256: payload.batchSha256,
|
|
417
|
+
certificate: fixedBase64url(source, 'certificate', 64),
|
|
418
|
+
certificateAlgorithm: payload.certificateAlgorithm,
|
|
419
|
+
checkpointSha256: payload.checkpointSha256,
|
|
420
|
+
committedAt: payload.committedAt,
|
|
421
|
+
operationIntentId: payload.operationIntentId,
|
|
422
|
+
projectId: payload.projectId,
|
|
423
|
+
sourceAuthority: payload.sourceAuthority,
|
|
424
|
+
sourceHostMemberId: payload.sourceHostMemberId,
|
|
425
|
+
targetAuthority: payload.targetAuthority,
|
|
426
|
+
transferId: payload.transferId,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const LAN_TO_CLOUD_PHASE_SET = new Set(exports.COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES);
|
|
430
|
+
const CLOUD_TO_LAN_PHASE_SET = new Set(exports.COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES);
|
|
431
|
+
const CANCELLATION_PHASE_SET = new Set(exports.COLLAB_AUTHORITY_TRANSFER_CANCELLATION_PHASES);
|
|
432
|
+
const CANCELLABLE_PHASE_SET = new Set(exports.COLLAB_AUTHORITY_TRANSFER_CANCELLABLE_PHASES);
|
|
433
|
+
const LAN_TO_CLOUD_CHECKPOINT_REQUIRED_PHASE_SET = new Set(exports.COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES.slice(2));
|
|
434
|
+
const CLOUD_TO_LAN_CHECKPOINT_REQUIRED_PHASE_SET = new Set(exports.COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES.slice(2));
|
|
435
|
+
const LAN_TO_CLOUD_BATCH_REQUIRED_PHASE_SET = new Set(exports.COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES.slice(4));
|
|
436
|
+
const CLOUD_TO_LAN_BATCH_REQUIRED_PHASE_SET = new Set(exports.COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES.slice(4));
|
|
437
|
+
const LAN_TO_CLOUD_RELINQUISHMENT_REQUIRED_PHASE_SET = new Set(exports.COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES.slice(6));
|
|
438
|
+
const CLOUD_TO_LAN_RELINQUISHMENT_REQUIRED_PHASE_SET = new Set(exports.COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES.slice(5));
|
|
439
|
+
function transferPhase(source, direction) {
|
|
440
|
+
const value = source.phase;
|
|
441
|
+
const directionSet = direction === 'lan-to-cloud'
|
|
442
|
+
? LAN_TO_CLOUD_PHASE_SET
|
|
443
|
+
: CLOUD_TO_LAN_PHASE_SET;
|
|
444
|
+
if (typeof value !== 'string' || (!directionSet.has(value) && !CANCELLATION_PHASE_SET.has(value))) {
|
|
445
|
+
throw invalidPayload('phase');
|
|
446
|
+
}
|
|
447
|
+
return value;
|
|
448
|
+
}
|
|
449
|
+
function decodeCollabAuthorityTransferLifecycleFence(value) {
|
|
450
|
+
const source = exactRecord(value, 'transferLifecycleFence', [
|
|
451
|
+
'batchRevision',
|
|
452
|
+
'batchSha256',
|
|
453
|
+
'checkpointSha256',
|
|
454
|
+
'direction',
|
|
455
|
+
'phase',
|
|
456
|
+
]);
|
|
457
|
+
const direction = literal(source, 'direction', ['cloud-to-lan', 'lan-to-cloud']);
|
|
458
|
+
const phase = transferPhase(source, direction);
|
|
459
|
+
const checkpointSha256 = source.checkpointSha256 === null
|
|
460
|
+
? null
|
|
461
|
+
: sha256(source, 'checkpointSha256');
|
|
462
|
+
const batchRevision = source.batchRevision === null
|
|
463
|
+
? null
|
|
464
|
+
: positiveInteger(source, 'batchRevision');
|
|
465
|
+
const batchSha256 = source.batchSha256 === null
|
|
466
|
+
? null
|
|
467
|
+
: sha256(source, 'batchSha256');
|
|
468
|
+
if ((batchRevision === null) !== (batchSha256 === null)
|
|
469
|
+
|| (batchRevision !== null && checkpointSha256 === null)
|
|
470
|
+
|| ((direction === 'lan-to-cloud'
|
|
471
|
+
? LAN_TO_CLOUD_CHECKPOINT_REQUIRED_PHASE_SET
|
|
472
|
+
: CLOUD_TO_LAN_CHECKPOINT_REQUIRED_PHASE_SET).has(phase)
|
|
473
|
+
&& checkpointSha256 === null)
|
|
474
|
+
|| ((direction === 'lan-to-cloud'
|
|
475
|
+
? LAN_TO_CLOUD_BATCH_REQUIRED_PHASE_SET
|
|
476
|
+
: CLOUD_TO_LAN_BATCH_REQUIRED_PHASE_SET).has(phase)
|
|
477
|
+
&& batchRevision === null))
|
|
478
|
+
throw invalidPayload('claimBatch');
|
|
479
|
+
const relinquishmentRequired = (direction === 'lan-to-cloud'
|
|
480
|
+
? LAN_TO_CLOUD_RELINQUISHMENT_REQUIRED_PHASE_SET
|
|
481
|
+
: CLOUD_TO_LAN_RELINQUISHMENT_REQUIRED_PHASE_SET).has(phase);
|
|
482
|
+
return {
|
|
483
|
+
batchRevision,
|
|
484
|
+
batchSha256,
|
|
485
|
+
checkpointSha256,
|
|
486
|
+
direction,
|
|
487
|
+
phase,
|
|
488
|
+
relinquishmentRequired,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function decodeCollabAuthorityTransferStatus(value) {
|
|
492
|
+
const source = exactRecord(value, 'transferStatus', [
|
|
493
|
+
'batchRevision',
|
|
494
|
+
'batchSha256',
|
|
495
|
+
'checkpointSha256',
|
|
496
|
+
'createdAt',
|
|
497
|
+
'direction',
|
|
498
|
+
'expiresAt',
|
|
499
|
+
'phase',
|
|
500
|
+
'projectId',
|
|
501
|
+
'relinquishmentProof',
|
|
502
|
+
'sourceAuthority',
|
|
503
|
+
'state',
|
|
504
|
+
'targetAuthority',
|
|
505
|
+
'targetUrl',
|
|
506
|
+
'transferId',
|
|
507
|
+
'updatedAt',
|
|
508
|
+
]);
|
|
509
|
+
const lifecycleFence = decodeCollabAuthorityTransferLifecycleFence({
|
|
510
|
+
batchRevision: source.batchRevision,
|
|
511
|
+
batchSha256: source.batchSha256,
|
|
512
|
+
checkpointSha256: source.checkpointSha256,
|
|
513
|
+
direction: source.direction,
|
|
514
|
+
phase: source.phase,
|
|
515
|
+
});
|
|
516
|
+
const { batchRevision, batchSha256, checkpointSha256, direction, phase, relinquishmentRequired, } = lifecycleFence;
|
|
517
|
+
const sourceAuthority = authority(source.sourceAuthority, 'sourceAuthority');
|
|
518
|
+
const targetAuthority = authority(source.targetAuthority, 'targetAuthority');
|
|
519
|
+
const state = literal(source, 'state', ['active', 'cancelled', 'completed']);
|
|
520
|
+
if (sourceAuthority.kind === targetAuthority.kind
|
|
521
|
+
|| targetAuthority.generation !== sourceAuthority.generation + 1
|
|
522
|
+
|| (direction === 'lan-to-cloud'
|
|
523
|
+
&& (sourceAuthority.kind !== 'lan' || targetAuthority.kind !== 'cloud'))
|
|
524
|
+
|| (direction === 'cloud-to-lan'
|
|
525
|
+
&& (sourceAuthority.kind !== 'cloud' || targetAuthority.kind !== 'lan'))
|
|
526
|
+
|| (state === 'cancelled' && phase !== 'cancelled')
|
|
527
|
+
|| (state === 'completed' && phase !== 'completed')
|
|
528
|
+
|| (state === 'active' && (phase === 'cancelled' || phase === 'completed')))
|
|
529
|
+
throw invalidPayload('transferStatus');
|
|
530
|
+
const relinquishmentProof = source.relinquishmentProof === null
|
|
531
|
+
? null
|
|
532
|
+
: decodeCollabAuthorityRelinquishmentProof(source.relinquishmentProof);
|
|
533
|
+
if (relinquishmentRequired !== (relinquishmentProof !== null)
|
|
534
|
+
|| (relinquishmentProof !== null && (relinquishmentProof.batchRevision !== batchRevision
|
|
535
|
+
|| relinquishmentProof.batchSha256 !== batchSha256
|
|
536
|
+
|| relinquishmentProof.checkpointSha256 !== checkpointSha256
|
|
537
|
+
|| relinquishmentProof.projectId !== source.projectId
|
|
538
|
+
|| relinquishmentProof.sourceAuthority.generation !== sourceAuthority.generation
|
|
539
|
+
|| relinquishmentProof.sourceAuthority.kind !== sourceAuthority.kind
|
|
540
|
+
|| relinquishmentProof.targetAuthority.generation !== targetAuthority.generation
|
|
541
|
+
|| relinquishmentProof.targetAuthority.kind !== targetAuthority.kind
|
|
542
|
+
|| relinquishmentProof.transferId !== source.transferId)))
|
|
543
|
+
throw invalidPayload('relinquishmentProof');
|
|
544
|
+
const createdAt = timestamp(source, 'createdAt');
|
|
545
|
+
const updatedAt = timestamp(source, 'updatedAt');
|
|
546
|
+
const expiresAt = timestamp(source, 'expiresAt');
|
|
547
|
+
if (Date.parse(updatedAt) < Date.parse(createdAt)
|
|
548
|
+
|| Date.parse(expiresAt) <= Date.parse(updatedAt))
|
|
549
|
+
throw invalidPayload('transferStatus');
|
|
550
|
+
return {
|
|
551
|
+
batchRevision,
|
|
552
|
+
batchSha256,
|
|
553
|
+
checkpointSha256,
|
|
554
|
+
createdAt,
|
|
555
|
+
direction,
|
|
556
|
+
expiresAt,
|
|
557
|
+
phase,
|
|
558
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
559
|
+
relinquishmentProof,
|
|
560
|
+
sourceAuthority,
|
|
561
|
+
state,
|
|
562
|
+
targetAuthority,
|
|
563
|
+
targetUrl: absoluteTargetUrl(source),
|
|
564
|
+
transferId: token(source, 'transferId'),
|
|
565
|
+
updatedAt,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function mutationFields(source) {
|
|
569
|
+
return {
|
|
570
|
+
idempotencyKey: token(source, 'idempotencyKey'),
|
|
571
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function decodeRequestLanToCloudTransfer(value) {
|
|
575
|
+
const source = exactRecord(value, 'request', [
|
|
576
|
+
'expectedAuthorityGeneration',
|
|
577
|
+
'idempotencyKey',
|
|
578
|
+
'projectId',
|
|
579
|
+
'targetUrl',
|
|
580
|
+
]);
|
|
581
|
+
return {
|
|
582
|
+
expectedAuthorityGeneration: positiveInteger(source, 'expectedAuthorityGeneration'),
|
|
583
|
+
...mutationFields(source),
|
|
584
|
+
targetUrl: absoluteTargetUrl(source),
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function decodeAcceptLanToCloudTransferTarget(value) {
|
|
588
|
+
const source = exactRecord(value, 'request', [
|
|
589
|
+
'expectedAuthorityGeneration',
|
|
590
|
+
'idempotencyKey',
|
|
591
|
+
'projectId',
|
|
592
|
+
'targetUrl',
|
|
593
|
+
'transferId',
|
|
594
|
+
]);
|
|
595
|
+
return {
|
|
596
|
+
expectedAuthorityGeneration: positiveInteger(source, 'expectedAuthorityGeneration'),
|
|
597
|
+
...mutationFields(source),
|
|
598
|
+
targetUrl: absoluteTargetUrl(source),
|
|
599
|
+
transferId: token(source, 'transferId'),
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function decodeBeginLanToCloudTransfer(value) {
|
|
603
|
+
const source = exactRecord(value, 'request', [
|
|
604
|
+
'checkpointManifestSha256',
|
|
605
|
+
'expectedSourceAuthorityGeneration',
|
|
606
|
+
'idempotencyKey',
|
|
607
|
+
'projectId',
|
|
608
|
+
'sourceHostMemberId',
|
|
609
|
+
'sourceProof',
|
|
610
|
+
'targetUrl',
|
|
611
|
+
'transferId',
|
|
612
|
+
]);
|
|
613
|
+
return {
|
|
614
|
+
checkpointManifestSha256: sha256(source, 'checkpointManifestSha256'),
|
|
615
|
+
expectedSourceAuthorityGeneration: positiveInteger(source, 'expectedSourceAuthorityGeneration'),
|
|
616
|
+
...mutationFields(source),
|
|
617
|
+
sourceHostMemberId: token(source, 'sourceHostMemberId', CollabValidation_1.isCollabMemberId),
|
|
618
|
+
sourceProof: base64url(source, 'sourceProof'),
|
|
619
|
+
targetUrl: absoluteTargetUrl(source),
|
|
620
|
+
transferId: token(source, 'transferId'),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function decodeGetProjectAuthorityTransfer(value) {
|
|
624
|
+
const source = exactRecord(value, 'request', ['projectId', 'transferId']);
|
|
625
|
+
return {
|
|
626
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
627
|
+
transferId: token(source, 'transferId'),
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function decodeRotateTransferredMembershipClaims(value) {
|
|
631
|
+
const source = exactRecord(value, 'request', [
|
|
632
|
+
'expectedBatchRevision',
|
|
633
|
+
'expectedBatchSha256',
|
|
634
|
+
'idempotencyKey',
|
|
635
|
+
'projectId',
|
|
636
|
+
'transferId',
|
|
637
|
+
]);
|
|
638
|
+
return {
|
|
639
|
+
expectedBatchRevision: positiveInteger(source, 'expectedBatchRevision'),
|
|
640
|
+
expectedBatchSha256: sha256(source, 'expectedBatchSha256'),
|
|
641
|
+
...mutationFields(source),
|
|
642
|
+
transferId: token(source, 'transferId'),
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function decodeAcknowledgeTransferredMembershipClaimBatch(value) {
|
|
646
|
+
const source = exactRecord(value, 'request', [
|
|
647
|
+
'batchRevision',
|
|
648
|
+
'batchSha256',
|
|
649
|
+
'idempotencyKey',
|
|
650
|
+
'operationIntentId',
|
|
651
|
+
'projectId',
|
|
652
|
+
'transferId',
|
|
653
|
+
]);
|
|
654
|
+
return {
|
|
655
|
+
batchRevision: positiveInteger(source, 'batchRevision'),
|
|
656
|
+
batchSha256: sha256(source, 'batchSha256'),
|
|
657
|
+
...mutationFields(source),
|
|
658
|
+
operationIntentId: token(source, 'operationIntentId'),
|
|
659
|
+
transferId: token(source, 'transferId'),
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function decodeGetTransferredMembershipClaim(value) {
|
|
663
|
+
return decodeGetProjectAuthorityTransfer(value);
|
|
664
|
+
}
|
|
665
|
+
function decodeClaimTransferredMembership(value) {
|
|
666
|
+
const raw = record(value, 'request');
|
|
667
|
+
const hasCredentialHash = Object.hasOwn(raw, 'credentialHash');
|
|
668
|
+
const source = exactRecord(value, 'request', hasCredentialHash
|
|
669
|
+
? ['claim', 'credentialHash', 'idempotencyKey', 'projectId', 'transferId']
|
|
670
|
+
: ['claim', 'idempotencyKey', 'projectId', 'transferId']);
|
|
671
|
+
const common = {
|
|
672
|
+
claim: base64url(source, 'claim'),
|
|
673
|
+
...mutationFields(source),
|
|
674
|
+
transferId: token(source, 'transferId'),
|
|
675
|
+
};
|
|
676
|
+
return hasCredentialHash
|
|
677
|
+
? {
|
|
678
|
+
...common,
|
|
679
|
+
credentialHash: sha256(source, 'credentialHash'),
|
|
680
|
+
}
|
|
681
|
+
: common;
|
|
682
|
+
}
|
|
683
|
+
function decodeAcknowledgeTransferredMembershipClaimRedemption(value) {
|
|
684
|
+
const source = exactRecord(value, 'request', [
|
|
685
|
+
'idempotencyKey',
|
|
686
|
+
'projectId',
|
|
687
|
+
'receipt',
|
|
688
|
+
'transferId',
|
|
689
|
+
]);
|
|
690
|
+
const common = mutationFields(source);
|
|
691
|
+
const transferId = token(source, 'transferId');
|
|
692
|
+
const receipt = decodeCollabTransferredMembershipRedemptionReceipt(source.receipt);
|
|
693
|
+
if (receipt.projectId !== common.projectId || receipt.transferId !== transferId) {
|
|
694
|
+
throw invalidPayload('receipt');
|
|
695
|
+
}
|
|
696
|
+
return { ...common, receipt, transferId };
|
|
697
|
+
}
|
|
698
|
+
function decodeCommitLanToCloudRelinquishment(value) {
|
|
699
|
+
const source = exactRecord(value, 'request', [
|
|
700
|
+
'idempotencyKey',
|
|
701
|
+
'projectId',
|
|
702
|
+
'proof',
|
|
703
|
+
'transferId',
|
|
704
|
+
]);
|
|
705
|
+
const common = mutationFields(source);
|
|
706
|
+
const transferId = token(source, 'transferId');
|
|
707
|
+
const proof = decodeCollabAuthorityRelinquishmentProof(source.proof);
|
|
708
|
+
if (proof.projectId !== common.projectId || proof.transferId !== transferId) {
|
|
709
|
+
throw invalidPayload('proof');
|
|
710
|
+
}
|
|
711
|
+
return { ...common, proof, transferId };
|
|
712
|
+
}
|
|
713
|
+
function decodeBeginCloudToLanTransfer(value) {
|
|
714
|
+
const source = exactRecord(value, 'request', [
|
|
715
|
+
'expectedAuthorityGeneration',
|
|
716
|
+
'idempotencyKey',
|
|
717
|
+
'projectId',
|
|
718
|
+
'targetHostMemberId',
|
|
719
|
+
'targetUrl',
|
|
720
|
+
]);
|
|
721
|
+
return {
|
|
722
|
+
expectedAuthorityGeneration: positiveInteger(source, 'expectedAuthorityGeneration'),
|
|
723
|
+
...mutationFields(source),
|
|
724
|
+
targetHostMemberId: token(source, 'targetHostMemberId', CollabValidation_1.isCollabMemberId),
|
|
725
|
+
targetUrl: absoluteTargetUrl(source),
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function decodeAcceptCloudToLanTransferTarget(value) {
|
|
729
|
+
const source = exactRecord(value, 'request', [
|
|
730
|
+
'idempotencyKey',
|
|
731
|
+
'projectId',
|
|
732
|
+
'targetHostMemberId',
|
|
733
|
+
'targetProof',
|
|
734
|
+
'transferId',
|
|
735
|
+
]);
|
|
736
|
+
return {
|
|
737
|
+
...mutationFields(source),
|
|
738
|
+
targetHostMemberId: token(source, 'targetHostMemberId', CollabValidation_1.isCollabMemberId),
|
|
739
|
+
targetProof: base64url(source, 'targetProof'),
|
|
740
|
+
transferId: token(source, 'transferId'),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function decodeReportCloudToLanTargetStaged(value) {
|
|
744
|
+
const source = exactRecord(value, 'request', [
|
|
745
|
+
'checkpointSha256',
|
|
746
|
+
'claimBatch',
|
|
747
|
+
'idempotencyKey',
|
|
748
|
+
'projectId',
|
|
749
|
+
'stageSha256',
|
|
750
|
+
'targetAuthority',
|
|
751
|
+
'targetProof',
|
|
752
|
+
'transferId',
|
|
753
|
+
]);
|
|
754
|
+
const targetAuthority = authority(source.targetAuthority, 'targetAuthority');
|
|
755
|
+
if (targetAuthority.kind !== 'lan')
|
|
756
|
+
throw invalidPayload('targetAuthority');
|
|
757
|
+
const common = mutationFields(source);
|
|
758
|
+
const transferId = token(source, 'transferId');
|
|
759
|
+
const checkpointSha256 = sha256(source, 'checkpointSha256');
|
|
760
|
+
const claimBatch = decodeCollabTransferredMembershipClaimBatch(source.claimBatch);
|
|
761
|
+
if (claimBatch.projectId !== common.projectId
|
|
762
|
+
|| claimBatch.transferId !== transferId
|
|
763
|
+
|| claimBatch.checkpointSha256 !== checkpointSha256
|
|
764
|
+
|| claimBatch.targetAuthorityGeneration !== targetAuthority.generation)
|
|
765
|
+
throw invalidPayload('claimBatch');
|
|
766
|
+
return {
|
|
767
|
+
checkpointSha256,
|
|
768
|
+
claimBatch,
|
|
769
|
+
...common,
|
|
770
|
+
stageSha256: sha256(source, 'stageSha256'),
|
|
771
|
+
targetAuthority,
|
|
772
|
+
targetProof: base64url(source, 'targetProof'),
|
|
773
|
+
transferId,
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function decodeConfirmCloudToLanTargetActive(value) {
|
|
777
|
+
const source = exactRecord(value, 'request', [
|
|
778
|
+
'idempotencyKey',
|
|
779
|
+
'projectId',
|
|
780
|
+
'relinquishmentProof',
|
|
781
|
+
'targetActivationProof',
|
|
782
|
+
'transferId',
|
|
783
|
+
]);
|
|
784
|
+
const common = mutationFields(source);
|
|
785
|
+
const transferId = token(source, 'transferId');
|
|
786
|
+
const relinquishmentProof = decodeCollabAuthorityRelinquishmentProof(source.relinquishmentProof);
|
|
787
|
+
if (relinquishmentProof.projectId !== common.projectId
|
|
788
|
+
|| relinquishmentProof.transferId !== transferId
|
|
789
|
+
|| relinquishmentProof.sourceAuthority.kind !== 'cloud'
|
|
790
|
+
|| relinquishmentProof.targetAuthority.kind !== 'lan')
|
|
791
|
+
throw invalidPayload('relinquishmentProof');
|
|
792
|
+
return {
|
|
793
|
+
...common,
|
|
794
|
+
relinquishmentProof,
|
|
795
|
+
targetActivationProof: base64url(source, 'targetActivationProof'),
|
|
796
|
+
transferId,
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
function decodeCancelProjectAuthorityTransfer(value) {
|
|
800
|
+
const source = exactRecord(value, 'request', [
|
|
801
|
+
'expectedPhase',
|
|
802
|
+
'idempotencyKey',
|
|
803
|
+
'projectId',
|
|
804
|
+
'transferId',
|
|
805
|
+
]);
|
|
806
|
+
const expectedPhase = source.expectedPhase;
|
|
807
|
+
if (typeof expectedPhase !== 'string'
|
|
808
|
+
|| !CANCELLABLE_PHASE_SET.has(expectedPhase))
|
|
809
|
+
throw invalidPayload('expectedPhase');
|
|
810
|
+
return {
|
|
811
|
+
expectedPhase: expectedPhase,
|
|
812
|
+
...mutationFields(source),
|
|
813
|
+
transferId: token(source, 'transferId'),
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function decodeCollabAuthorityTransferOperationRequest(operation, value) {
|
|
817
|
+
const decoded = (() => {
|
|
818
|
+
switch (operation) {
|
|
819
|
+
case 'requestLanToCloudTransfer': return decodeRequestLanToCloudTransfer(value);
|
|
820
|
+
case 'acceptLanToCloudTransferTarget': return decodeAcceptLanToCloudTransferTarget(value);
|
|
821
|
+
case 'beginLanToCloudTransfer': return decodeBeginLanToCloudTransfer(value);
|
|
822
|
+
case 'getProjectAuthorityTransfer': return decodeGetProjectAuthorityTransfer(value);
|
|
823
|
+
case 'rotateTransferredMembershipClaims':
|
|
824
|
+
return decodeRotateTransferredMembershipClaims(value);
|
|
825
|
+
case 'acknowledgeTransferredMembershipClaimBatch':
|
|
826
|
+
return decodeAcknowledgeTransferredMembershipClaimBatch(value);
|
|
827
|
+
case 'getTransferredMembershipClaim': return decodeGetTransferredMembershipClaim(value);
|
|
828
|
+
case 'claimTransferredMembership': return decodeClaimTransferredMembership(value);
|
|
829
|
+
case 'acknowledgeTransferredMembershipClaimRedemption':
|
|
830
|
+
return decodeAcknowledgeTransferredMembershipClaimRedemption(value);
|
|
831
|
+
case 'commitLanToCloudRelinquishment':
|
|
832
|
+
return decodeCommitLanToCloudRelinquishment(value);
|
|
833
|
+
case 'beginCloudToLanTransfer': return decodeBeginCloudToLanTransfer(value);
|
|
834
|
+
case 'acceptCloudToLanTransferTarget': return decodeAcceptCloudToLanTransferTarget(value);
|
|
835
|
+
case 'reportCloudToLanTargetStaged': return decodeReportCloudToLanTargetStaged(value);
|
|
836
|
+
case 'confirmCloudToLanTargetActive': return decodeConfirmCloudToLanTargetActive(value);
|
|
837
|
+
case 'cancelProjectAuthorityTransfer': return decodeCancelProjectAuthorityTransfer(value);
|
|
838
|
+
}
|
|
839
|
+
})();
|
|
840
|
+
return decoded;
|
|
841
|
+
}
|
|
842
|
+
function decodeRedemptionAcknowledgement(value) {
|
|
843
|
+
const source = exactRecord(value, 'redemptionAcknowledgement', [
|
|
844
|
+
'acknowledgedAt',
|
|
845
|
+
'memberId',
|
|
846
|
+
'projectId',
|
|
847
|
+
'receiptId',
|
|
848
|
+
'transferId',
|
|
849
|
+
]);
|
|
850
|
+
return {
|
|
851
|
+
acknowledgedAt: timestamp(source, 'acknowledgedAt'),
|
|
852
|
+
memberId: token(source, 'memberId', CollabValidation_1.isCollabMemberId),
|
|
853
|
+
projectId: token(source, 'projectId', CollabValidation_1.isCollabProjectId),
|
|
854
|
+
receiptId: token(source, 'receiptId'),
|
|
855
|
+
transferId: token(source, 'transferId'),
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
function decodeCollabAuthorityTransferOperationResponse(operation, value) {
|
|
859
|
+
const decoded = (() => {
|
|
860
|
+
switch (operation) {
|
|
861
|
+
case 'rotateTransferredMembershipClaims':
|
|
862
|
+
return decodeCollabTransferredMembershipClaimBatch(value);
|
|
863
|
+
case 'acknowledgeTransferredMembershipClaimBatch':
|
|
864
|
+
case 'reportCloudToLanTargetStaged':
|
|
865
|
+
return decodeCollabTransferredMembershipClaimCustodyReceipt(value);
|
|
866
|
+
case 'getTransferredMembershipClaim':
|
|
867
|
+
return decodeCollabTransferredMembershipClaim(value);
|
|
868
|
+
case 'claimTransferredMembership':
|
|
869
|
+
return decodeCollabTransferredMembershipRedemptionReceipt(value);
|
|
870
|
+
case 'acknowledgeTransferredMembershipClaimRedemption':
|
|
871
|
+
return decodeRedemptionAcknowledgement(value);
|
|
872
|
+
default:
|
|
873
|
+
return decodeCollabAuthorityTransferStatus(value);
|
|
874
|
+
}
|
|
875
|
+
})();
|
|
876
|
+
return decoded;
|
|
877
|
+
}
|