@serve.zone/interfaces 25.1.1 → 25.3.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/changelog.md +19 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/platform/index.d.ts +3 -1
- package/dist_ts/platform/index.js +4 -2
- package/dist_ts/platform/objectstorageretention.d.ts +63 -0
- package/dist_ts/platform/objectstorageretention.js +255 -0
- package/dist_ts/platform/types.d.ts +3 -0
- package/dist_ts/plugins.runtime.d.ts +2 -0
- package/dist_ts/plugins.runtime.js +4 -0
- package/dist_ts/requests/config.d.ts +3 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.d.ts +394 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.d.ts +35 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.js +315 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.js +1378 -0
- package/dist_ts/runtime.corestore.d.ts +204 -0
- package/dist_ts/runtime.corestore.js +620 -0
- package/dist_ts/runtime.d.ts +2 -0
- package/dist_ts/runtime.js +3 -1
- package/dist_ts/runtime.workloadinit.d.ts +1 -1
- package/package.json +5 -1
- package/readme.md +54 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/platform/index.ts +3 -0
- package/ts/platform/objectstorageretention.ts +372 -0
- package/ts/platform/types.ts +3 -0
- package/ts/plugins.runtime.ts +4 -0
- package/ts/requests/config.ts +3 -0
- package/ts/runtime.cloudlylegacydeploymentsettlement.golden.ts +421 -0
- package/ts/runtime.cloudlylegacydeploymentsettlement.ts +2884 -0
- package/ts/runtime.corestore.ts +909 -0
- package/ts/runtime.ts +2 -0
- package/ts/runtime.workloadinit.ts +1 -1
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { isSha256Digest } from './data/immutableimage.js';
|
|
3
|
+
import { validateSecretRecipientMetadata, verifySecretEnvelopeContext, } from './data/secret.js';
|
|
4
|
+
import { validateObjectStorageRetentionEvidence } from './platform/objectstorageretention.js';
|
|
5
|
+
export const corestoreProviderConfigIds = Object.freeze({
|
|
6
|
+
database: 'cloudly-corestore-database',
|
|
7
|
+
objectstorage: 'cloudly-corestore-objectstorage',
|
|
8
|
+
});
|
|
9
|
+
export const corestoreControlUrl = 'http://corestore:3000';
|
|
10
|
+
export const corestoreCredentialManagementScope = 'platform:cloudly-corestore';
|
|
11
|
+
export const corestoreControlCredentialKey = 'CORESTORE_API_TOKEN';
|
|
12
|
+
export const corestoreCredentialEnvironment = 'production';
|
|
13
|
+
export const corestoreCredentialRuntimeLimits = Object.freeze({
|
|
14
|
+
maximumIdentifierLength: 200,
|
|
15
|
+
maximumPublicationGrants: 256,
|
|
16
|
+
maximumGrantLifetimeMs: 24 * 60 * 60 * 1000,
|
|
17
|
+
maximumCredentialStringBytes: 8 * 1024,
|
|
18
|
+
maximumSealedMaterialBytes: 64 * 1024,
|
|
19
|
+
minimumControlTokenBytes: 32,
|
|
20
|
+
maximumControlTokenBytes: 4096,
|
|
21
|
+
maximumSealedControlCredentialBytes: 12 * 1024,
|
|
22
|
+
});
|
|
23
|
+
export const getCorestoreProviderConfigId = (capabilityArg) => {
|
|
24
|
+
if (capabilityArg !== 'database' && capabilityArg !== 'objectstorage') {
|
|
25
|
+
throw new Error('corestore capability must be database or objectstorage');
|
|
26
|
+
}
|
|
27
|
+
return corestoreProviderConfigIds[capabilityArg];
|
|
28
|
+
};
|
|
29
|
+
const identifierPattern = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
30
|
+
const bareSha256Pattern = /^[a-f0-9]{64}$/;
|
|
31
|
+
const environmentKeyPattern = /^[A-Z_][A-Z0-9_]{0,127}$/;
|
|
32
|
+
const isRecord = (valueArg) => (Boolean(valueArg)
|
|
33
|
+
&& typeof valueArg === 'object'
|
|
34
|
+
&& !Array.isArray(valueArg)
|
|
35
|
+
&& (Object.getPrototypeOf(valueArg) === Object.prototype
|
|
36
|
+
|| Object.getPrototypeOf(valueArg) === null));
|
|
37
|
+
const hasExactKeys = (valueArg, keysArg) => {
|
|
38
|
+
const actual = Object.keys(valueArg).sort();
|
|
39
|
+
const expected = [...keysArg].sort();
|
|
40
|
+
return actual.length === expected.length
|
|
41
|
+
&& actual.every((keyArg, indexArg) => keyArg === expected[indexArg]);
|
|
42
|
+
};
|
|
43
|
+
const hasKeys = (valueArg, requiredArg, optionalArg) => requiredArg.every((keyArg) => Object.hasOwn(valueArg, keyArg))
|
|
44
|
+
&& Object.keys(valueArg).every((keyArg) => requiredArg.includes(keyArg)
|
|
45
|
+
|| optionalArg.includes(keyArg));
|
|
46
|
+
const isIdentifier = (valueArg) => (typeof valueArg === 'string' && identifierPattern.test(valueArg));
|
|
47
|
+
const isPositiveSafeInteger = (valueArg) => (Number.isSafeInteger(valueArg) && valueArg > 0);
|
|
48
|
+
const isNonNegativeSafeInteger = (valueArg) => (Number.isSafeInteger(valueArg) && valueArg >= 0 && !Object.is(valueArg, -0));
|
|
49
|
+
const isJwtIdentity = (valueArg) => (isRecord(valueArg)
|
|
50
|
+
&& hasExactKeys(valueArg, ['jwt'])
|
|
51
|
+
&& typeof valueArg.jwt === 'string'
|
|
52
|
+
&& valueArg.jwt.length > 0);
|
|
53
|
+
const utf8ByteLength = (valueArg) => new TextEncoder().encode(valueArg).byteLength;
|
|
54
|
+
const isCorestoreControlToken = (valueArg) => {
|
|
55
|
+
if (typeof valueArg !== 'string' || valueArg.length === 0 || /\s/u.test(valueArg))
|
|
56
|
+
return false;
|
|
57
|
+
const encoded = new TextEncoder().encode(valueArg);
|
|
58
|
+
let roundTrip;
|
|
59
|
+
try {
|
|
60
|
+
roundTrip = new TextDecoder('utf-8', { fatal: true }).decode(encoded);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return roundTrip === valueArg
|
|
66
|
+
&& encoded.byteLength >= corestoreCredentialRuntimeLimits.minimumControlTokenBytes
|
|
67
|
+
&& encoded.byteLength <= corestoreCredentialRuntimeLimits.maximumControlTokenBytes;
|
|
68
|
+
};
|
|
69
|
+
export const validateGetCorestoreControlCredentialMaterialRequest = (requestArg, activeRecipientArg) => {
|
|
70
|
+
if (!isRecord(requestArg)
|
|
71
|
+
|| !hasExactKeys(requestArg, [
|
|
72
|
+
'identity',
|
|
73
|
+
'requestId',
|
|
74
|
+
'capability',
|
|
75
|
+
'expectedRecipientKeyId',
|
|
76
|
+
'expectedRecipientGeneration',
|
|
77
|
+
])) {
|
|
78
|
+
return ['corestore control credential request must use its exact schema'];
|
|
79
|
+
}
|
|
80
|
+
const errors = [];
|
|
81
|
+
if (!isJwtIdentity(requestArg.identity)) {
|
|
82
|
+
errors.push('corestore control credential request requires only a JWT identity');
|
|
83
|
+
}
|
|
84
|
+
if (!isIdentifier(requestArg.requestId)
|
|
85
|
+
|| !isIdentifier(requestArg.expectedRecipientKeyId)) {
|
|
86
|
+
errors.push('corestore control credential request identifiers must be canonical');
|
|
87
|
+
}
|
|
88
|
+
if (requestArg.capability !== 'database' && requestArg.capability !== 'objectstorage') {
|
|
89
|
+
errors.push('corestore control credential capability must be database or objectstorage');
|
|
90
|
+
}
|
|
91
|
+
if (!isPositiveSafeInteger(requestArg.expectedRecipientGeneration)) {
|
|
92
|
+
errors.push('corestore control credential recipient generation must be positive');
|
|
93
|
+
}
|
|
94
|
+
if (validateSecretRecipientMetadata(activeRecipientArg).length > 0
|
|
95
|
+
|| activeRecipientArg.lifecycleState !== 'active'
|
|
96
|
+
|| requestArg.expectedRecipientKeyId !== activeRecipientArg.recipientKeyId
|
|
97
|
+
|| requestArg.expectedRecipientGeneration !== activeRecipientArg.generation) {
|
|
98
|
+
errors.push('corestore control credential request must target the active recipient');
|
|
99
|
+
}
|
|
100
|
+
return errors;
|
|
101
|
+
};
|
|
102
|
+
export const createCorestoreControlCredentialMaterialEnvelopeContext = (materialArg) => new TextEncoder().encode(JSON.stringify({
|
|
103
|
+
schemaVersion: 1,
|
|
104
|
+
purpose: 'serve.zone/corestore-control-credential-material',
|
|
105
|
+
requestId: materialArg.requestId,
|
|
106
|
+
clusterId: materialArg.clusterId,
|
|
107
|
+
capability: materialArg.capability,
|
|
108
|
+
providerConfigId: getCorestoreProviderConfigId(materialArg.capability),
|
|
109
|
+
controlUrl: corestoreControlUrl,
|
|
110
|
+
managementScope: corestoreCredentialManagementScope,
|
|
111
|
+
key: corestoreControlCredentialKey,
|
|
112
|
+
environment: corestoreCredentialEnvironment,
|
|
113
|
+
recipientKeyId: materialArg.recipientKeyId,
|
|
114
|
+
recipientGeneration: materialArg.recipientGeneration,
|
|
115
|
+
}));
|
|
116
|
+
export const validateCorestoreControlCredentialPlaintext = (plaintextArg) => {
|
|
117
|
+
if (!isRecord(plaintextArg)
|
|
118
|
+
|| !hasExactKeys(plaintextArg, ['schemaVersion', 'key', 'environment', 'value'])) {
|
|
119
|
+
return ['corestore control credential plaintext must use its exact schema'];
|
|
120
|
+
}
|
|
121
|
+
const errors = [];
|
|
122
|
+
if (plaintextArg.schemaVersion !== 1
|
|
123
|
+
|| plaintextArg.key !== corestoreControlCredentialKey
|
|
124
|
+
|| plaintextArg.environment !== corestoreCredentialEnvironment) {
|
|
125
|
+
errors.push('corestore control credential plaintext constants must be canonical');
|
|
126
|
+
}
|
|
127
|
+
if (!isCorestoreControlToken(plaintextArg.value)) {
|
|
128
|
+
errors.push('corestore control credential value must be 32-4096 UTF-8 bytes without whitespace');
|
|
129
|
+
}
|
|
130
|
+
return errors;
|
|
131
|
+
};
|
|
132
|
+
export const validateCorestoreControlCredentialMaterial = async (materialArg, expectedArg) => {
|
|
133
|
+
if (!isRecord(materialArg)
|
|
134
|
+
|| !hasExactKeys(materialArg, [
|
|
135
|
+
'schemaVersion',
|
|
136
|
+
'requestId',
|
|
137
|
+
'clusterId',
|
|
138
|
+
'capability',
|
|
139
|
+
'providerConfigId',
|
|
140
|
+
'controlUrl',
|
|
141
|
+
'managementScope',
|
|
142
|
+
'key',
|
|
143
|
+
'environment',
|
|
144
|
+
'recipientKeyId',
|
|
145
|
+
'recipientGeneration',
|
|
146
|
+
'envelope',
|
|
147
|
+
])) {
|
|
148
|
+
return ['corestore control credential material must use its exact schema'];
|
|
149
|
+
}
|
|
150
|
+
const errors = [];
|
|
151
|
+
if (materialArg.schemaVersion !== 1
|
|
152
|
+
|| !isIdentifier(materialArg.requestId)
|
|
153
|
+
|| !isIdentifier(materialArg.clusterId)
|
|
154
|
+
|| !isIdentifier(materialArg.recipientKeyId)
|
|
155
|
+
|| !isPositiveSafeInteger(materialArg.recipientGeneration)) {
|
|
156
|
+
errors.push('corestore control credential material metadata must be canonical');
|
|
157
|
+
}
|
|
158
|
+
if (materialArg.capability !== 'database' && materialArg.capability !== 'objectstorage') {
|
|
159
|
+
errors.push('corestore control credential material capability must be canonical');
|
|
160
|
+
}
|
|
161
|
+
else if (materialArg.providerConfigId !== getCorestoreProviderConfigId(materialArg.capability)) {
|
|
162
|
+
errors.push('corestore control credential provider must be derived from capability');
|
|
163
|
+
}
|
|
164
|
+
if (materialArg.controlUrl !== corestoreControlUrl
|
|
165
|
+
|| materialArg.managementScope !== corestoreCredentialManagementScope
|
|
166
|
+
|| materialArg.key !== corestoreControlCredentialKey
|
|
167
|
+
|| materialArg.environment !== corestoreCredentialEnvironment) {
|
|
168
|
+
errors.push('corestore control credential material constants must be canonical');
|
|
169
|
+
}
|
|
170
|
+
if (materialArg.requestId !== expectedArg.requestId
|
|
171
|
+
|| materialArg.clusterId !== expectedArg.clusterId
|
|
172
|
+
|| materialArg.capability !== expectedArg.capability
|
|
173
|
+
|| materialArg.recipientKeyId !== expectedArg.expectedRecipientKeyId
|
|
174
|
+
|| materialArg.recipientGeneration !== expectedArg.expectedRecipientGeneration) {
|
|
175
|
+
errors.push('corestore control credential material does not match its request authority');
|
|
176
|
+
}
|
|
177
|
+
let envelope;
|
|
178
|
+
try {
|
|
179
|
+
envelope = plugins.smartcrypto.parseX25519Envelope(materialArg.envelope);
|
|
180
|
+
if (envelope.ciphertext.length
|
|
181
|
+
> Math.ceil(corestoreCredentialRuntimeLimits.maximumSealedControlCredentialBytes * 4 / 3)) {
|
|
182
|
+
errors.push('corestore control credential envelope exceeds its byte limit');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
errors.push('corestore control credential envelope must be strict');
|
|
187
|
+
}
|
|
188
|
+
if (envelope) {
|
|
189
|
+
if (envelope.recipientKeyId !== materialArg.recipientKeyId) {
|
|
190
|
+
errors.push('corestore control credential envelope recipient must match');
|
|
191
|
+
}
|
|
192
|
+
else if (errors.length === 0 && !await verifySecretEnvelopeContext(envelope, createCorestoreControlCredentialMaterialEnvelopeContext(materialArg))) {
|
|
193
|
+
errors.push('corestore control credential envelope context must match');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return errors;
|
|
197
|
+
};
|
|
198
|
+
export const validateCorestoreCredentialPublicationGrant = (grantArg, trustedNowArg) => {
|
|
199
|
+
if (!isRecord(grantArg)
|
|
200
|
+
|| !hasExactKeys(grantArg, [
|
|
201
|
+
'schemaVersion',
|
|
202
|
+
'operationId',
|
|
203
|
+
'serviceId',
|
|
204
|
+
'bindingId',
|
|
205
|
+
'capability',
|
|
206
|
+
'reconciliationGeneration',
|
|
207
|
+
'expectedTargetSecretsRevision',
|
|
208
|
+
'bindingRequestDigest',
|
|
209
|
+
'issuedAt',
|
|
210
|
+
'expiresAt',
|
|
211
|
+
])) {
|
|
212
|
+
return ['corestore credential publication grant must use its exact schema'];
|
|
213
|
+
}
|
|
214
|
+
const errors = [];
|
|
215
|
+
if (grantArg.schemaVersion !== 1) {
|
|
216
|
+
errors.push('corestore credential publication grant schemaVersion must be 1');
|
|
217
|
+
}
|
|
218
|
+
if (!isIdentifier(grantArg.operationId)
|
|
219
|
+
|| !isIdentifier(grantArg.serviceId)
|
|
220
|
+
|| !isIdentifier(grantArg.bindingId)) {
|
|
221
|
+
errors.push('corestore credential publication grant identifiers must be canonical');
|
|
222
|
+
}
|
|
223
|
+
if (grantArg.capability !== 'database' && grantArg.capability !== 'objectstorage') {
|
|
224
|
+
errors.push('corestore credential publication grant capability must be canonical');
|
|
225
|
+
}
|
|
226
|
+
if (!isPositiveSafeInteger(grantArg.reconciliationGeneration)
|
|
227
|
+
|| !isNonNegativeSafeInteger(grantArg.expectedTargetSecretsRevision)) {
|
|
228
|
+
errors.push('corestore credential publication grant revisions must be canonical');
|
|
229
|
+
}
|
|
230
|
+
if (typeof grantArg.bindingRequestDigest !== 'string'
|
|
231
|
+
|| !bareSha256Pattern.test(grantArg.bindingRequestDigest)) {
|
|
232
|
+
errors.push('corestore credential publication grant digest must be bare lowercase 64-hex');
|
|
233
|
+
}
|
|
234
|
+
if (!isPositiveSafeInteger(grantArg.issuedAt)
|
|
235
|
+
|| !isPositiveSafeInteger(grantArg.expiresAt)
|
|
236
|
+
|| grantArg.expiresAt <= grantArg.issuedAt
|
|
237
|
+
|| grantArg.expiresAt - grantArg.issuedAt
|
|
238
|
+
> corestoreCredentialRuntimeLimits.maximumGrantLifetimeMs) {
|
|
239
|
+
errors.push('corestore credential publication grant lifetime must be positive and bounded');
|
|
240
|
+
}
|
|
241
|
+
if (trustedNowArg !== undefined
|
|
242
|
+
&& (!isPositiveSafeInteger(trustedNowArg)
|
|
243
|
+
|| trustedNowArg < grantArg.issuedAt
|
|
244
|
+
|| trustedNowArg >= grantArg.expiresAt)) {
|
|
245
|
+
errors.push('corestore credential publication grant must be currently valid');
|
|
246
|
+
}
|
|
247
|
+
return errors;
|
|
248
|
+
};
|
|
249
|
+
export const corestoreCredentialPublicationGrantsEqual = (leftArg, rightArg) => validateCorestoreCredentialPublicationGrant(leftArg).length === 0
|
|
250
|
+
&& validateCorestoreCredentialPublicationGrant(rightArg).length === 0
|
|
251
|
+
&& leftArg.schemaVersion
|
|
252
|
+
=== rightArg.schemaVersion
|
|
253
|
+
&& leftArg.operationId
|
|
254
|
+
=== rightArg.operationId
|
|
255
|
+
&& leftArg.serviceId
|
|
256
|
+
=== rightArg.serviceId
|
|
257
|
+
&& leftArg.bindingId
|
|
258
|
+
=== rightArg.bindingId
|
|
259
|
+
&& leftArg.capability
|
|
260
|
+
=== rightArg.capability
|
|
261
|
+
&& leftArg.reconciliationGeneration
|
|
262
|
+
=== rightArg.reconciliationGeneration
|
|
263
|
+
&& leftArg.expectedTargetSecretsRevision
|
|
264
|
+
=== rightArg.expectedTargetSecretsRevision
|
|
265
|
+
&& leftArg.bindingRequestDigest
|
|
266
|
+
=== rightArg.bindingRequestDigest
|
|
267
|
+
&& leftArg.issuedAt
|
|
268
|
+
=== rightArg.issuedAt
|
|
269
|
+
&& leftArg.expiresAt
|
|
270
|
+
=== rightArg.expiresAt;
|
|
271
|
+
const comparePublicationGrants = (leftArg, rightArg) => leftArg.bindingId < rightArg.bindingId
|
|
272
|
+
? -1
|
|
273
|
+
: leftArg.bindingId > rightArg.bindingId
|
|
274
|
+
? 1
|
|
275
|
+
: leftArg.operationId < rightArg.operationId
|
|
276
|
+
? -1
|
|
277
|
+
: leftArg.operationId > rightArg.operationId
|
|
278
|
+
? 1
|
|
279
|
+
: 0;
|
|
280
|
+
export const validateCorestoreCredentialPublicationGrants = (grantsArg, trustedNowArg) => {
|
|
281
|
+
if (!Array.isArray(grantsArg)
|
|
282
|
+
|| grantsArg.length > corestoreCredentialRuntimeLimits.maximumPublicationGrants) {
|
|
283
|
+
return ['corestore credential publication grants must be a bounded array'];
|
|
284
|
+
}
|
|
285
|
+
const errors = [];
|
|
286
|
+
let previous;
|
|
287
|
+
for (const [index, grantArg] of grantsArg.entries()) {
|
|
288
|
+
const grantErrors = validateCorestoreCredentialPublicationGrant(grantArg, trustedNowArg);
|
|
289
|
+
errors.push(...grantErrors.map((errorArg) => `publication grants[${index}] ${errorArg}`));
|
|
290
|
+
if (grantErrors.length === 0) {
|
|
291
|
+
const grant = grantArg;
|
|
292
|
+
if (previous && comparePublicationGrants(previous, grant) >= 0) {
|
|
293
|
+
errors.push('corestore credential publication grants must be unique and sorted by bindingId then operationId');
|
|
294
|
+
}
|
|
295
|
+
previous = grant;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return errors;
|
|
299
|
+
};
|
|
300
|
+
export const corestoreDatabaseCredentialKeys = Object.freeze([
|
|
301
|
+
'MONGODB_URI',
|
|
302
|
+
'MONGODB_URL',
|
|
303
|
+
'MONGO_URL',
|
|
304
|
+
'MONGODB_HOST',
|
|
305
|
+
'MONGODB_PORT',
|
|
306
|
+
'MONGODB_DATABASE',
|
|
307
|
+
'MONGO_DBNAME',
|
|
308
|
+
'MONGODB_USERNAME',
|
|
309
|
+
'MONGO_DBUSER',
|
|
310
|
+
'MONGODB_PASSWORD',
|
|
311
|
+
'MONGO_DBPASS',
|
|
312
|
+
]);
|
|
313
|
+
export const corestoreObjectStorageCredentialKeys = Object.freeze([
|
|
314
|
+
'accessKeyId',
|
|
315
|
+
'secretAccessKey',
|
|
316
|
+
]);
|
|
317
|
+
const readCredentialString = (valueArg) => typeof valueArg === 'string'
|
|
318
|
+
&& valueArg.length > 0
|
|
319
|
+
&& utf8ByteLength(valueArg) <= corestoreCredentialRuntimeLimits.maximumCredentialStringBytes
|
|
320
|
+
&& !valueArg.includes('\0');
|
|
321
|
+
export const validateCorestoreDatabaseCredentialMaterial = (materialArg) => {
|
|
322
|
+
if (!isRecord(materialArg)
|
|
323
|
+
|| !hasExactKeys(materialArg, ['schemaVersion', 'capability', 'values'])
|
|
324
|
+
|| materialArg.schemaVersion !== 1
|
|
325
|
+
|| materialArg.capability !== 'database'
|
|
326
|
+
|| !isRecord(materialArg.values)
|
|
327
|
+
|| !hasExactKeys(materialArg.values, corestoreDatabaseCredentialKeys)) {
|
|
328
|
+
return ['corestore database credential material must use its exact schema'];
|
|
329
|
+
}
|
|
330
|
+
const values = materialArg.values;
|
|
331
|
+
const errors = [];
|
|
332
|
+
if (corestoreDatabaseCredentialKeys.some((keyArg) => !readCredentialString(values[keyArg]))) {
|
|
333
|
+
errors.push('corestore database credential values must be bounded non-empty strings');
|
|
334
|
+
}
|
|
335
|
+
if (values.MONGODB_URI !== values.MONGODB_URL
|
|
336
|
+
|| values.MONGODB_URI !== values.MONGO_URL) {
|
|
337
|
+
errors.push('corestore database URI aliases must be equal');
|
|
338
|
+
}
|
|
339
|
+
if (values.MONGODB_DATABASE !== values.MONGO_DBNAME) {
|
|
340
|
+
errors.push('corestore database name aliases must be equal');
|
|
341
|
+
}
|
|
342
|
+
if (values.MONGODB_USERNAME !== values.MONGO_DBUSER) {
|
|
343
|
+
errors.push('corestore database username aliases must be equal');
|
|
344
|
+
}
|
|
345
|
+
if (values.MONGODB_PASSWORD !== values.MONGO_DBPASS) {
|
|
346
|
+
errors.push('corestore database password aliases must be equal');
|
|
347
|
+
}
|
|
348
|
+
if (typeof values.MONGODB_PORT !== 'string'
|
|
349
|
+
|| !/^[1-9][0-9]{0,4}$/.test(values.MONGODB_PORT)
|
|
350
|
+
|| Number(values.MONGODB_PORT) > 65535) {
|
|
351
|
+
errors.push('corestore database port must be canonical');
|
|
352
|
+
}
|
|
353
|
+
return errors;
|
|
354
|
+
};
|
|
355
|
+
export const validateCorestoreObjectStorageCredentialMaterial = async (materialArg, retentionExpectationArg) => {
|
|
356
|
+
if (!isRecord(materialArg)
|
|
357
|
+
|| !hasKeys(materialArg, ['schemaVersion', 'capability', 'values'], ['retention'])
|
|
358
|
+
|| materialArg.schemaVersion !== 1
|
|
359
|
+
|| materialArg.capability !== 'objectstorage'
|
|
360
|
+
|| !isRecord(materialArg.values)
|
|
361
|
+
|| !hasExactKeys(materialArg.values, corestoreObjectStorageCredentialKeys)) {
|
|
362
|
+
return ['corestore objectstorage credential material must use its exact schema'];
|
|
363
|
+
}
|
|
364
|
+
const errors = [];
|
|
365
|
+
if (!readCredentialString(materialArg.values.accessKeyId)
|
|
366
|
+
|| !readCredentialString(materialArg.values.secretAccessKey)) {
|
|
367
|
+
errors.push('corestore objectstorage credential values must be bounded non-empty strings');
|
|
368
|
+
}
|
|
369
|
+
if (materialArg.retention !== undefined) {
|
|
370
|
+
if (!retentionExpectationArg) {
|
|
371
|
+
errors.push('corestore objectstorage retention evidence requires trusted binding authority');
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
errors.push(...await validateObjectStorageRetentionEvidence(materialArg.retention, retentionExpectationArg));
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return errors;
|
|
378
|
+
};
|
|
379
|
+
export const validateCorestoreCredentialPlaintextMaterial = async (materialArg, retentionExpectationArg) => isRecord(materialArg) && materialArg.capability === 'database'
|
|
380
|
+
? validateCorestoreDatabaseCredentialMaterial(materialArg)
|
|
381
|
+
: validateCorestoreObjectStorageCredentialMaterial(materialArg, retentionExpectationArg);
|
|
382
|
+
export const createPublishCorestoreCredentialMaterialEnvelopeContext = (requestArg) => new TextEncoder().encode(JSON.stringify({
|
|
383
|
+
schemaVersion: 1,
|
|
384
|
+
purpose: 'serve.zone/publish-corestore-credential-material',
|
|
385
|
+
mutationId: requestArg.mutationId,
|
|
386
|
+
grant: {
|
|
387
|
+
schemaVersion: requestArg.grant.schemaVersion,
|
|
388
|
+
operationId: requestArg.grant.operationId,
|
|
389
|
+
serviceId: requestArg.grant.serviceId,
|
|
390
|
+
bindingId: requestArg.grant.bindingId,
|
|
391
|
+
capability: requestArg.grant.capability,
|
|
392
|
+
reconciliationGeneration: requestArg.grant.reconciliationGeneration,
|
|
393
|
+
expectedTargetSecretsRevision: requestArg.grant.expectedTargetSecretsRevision,
|
|
394
|
+
bindingRequestDigest: requestArg.grant.bindingRequestDigest,
|
|
395
|
+
issuedAt: requestArg.grant.issuedAt,
|
|
396
|
+
expiresAt: requestArg.grant.expiresAt,
|
|
397
|
+
},
|
|
398
|
+
expectedIngressRecipientKeyId: requestArg.expectedIngressRecipientKeyId,
|
|
399
|
+
expectedIngressRecipientGeneration: requestArg.expectedIngressRecipientGeneration,
|
|
400
|
+
}));
|
|
401
|
+
export const validatePublishCorestoreCredentialMaterialRequest = async (requestArg, expectedGrantArg, activeRecipientArg, trustedNowArg) => {
|
|
402
|
+
if (!isRecord(requestArg)
|
|
403
|
+
|| !hasExactKeys(requestArg, [
|
|
404
|
+
'identity',
|
|
405
|
+
'mutationId',
|
|
406
|
+
'grant',
|
|
407
|
+
'expectedIngressRecipientKeyId',
|
|
408
|
+
'expectedIngressRecipientGeneration',
|
|
409
|
+
'envelope',
|
|
410
|
+
])) {
|
|
411
|
+
return ['publish corestore credential request must use its exact schema'];
|
|
412
|
+
}
|
|
413
|
+
const errors = validateCorestoreCredentialPublicationGrant(requestArg.grant, trustedNowArg);
|
|
414
|
+
if (!corestoreCredentialPublicationGrantsEqual(requestArg.grant, expectedGrantArg)) {
|
|
415
|
+
errors.push('publish corestore credential request grant must match current server authority');
|
|
416
|
+
}
|
|
417
|
+
if (!isJwtIdentity(requestArg.identity)) {
|
|
418
|
+
errors.push('publish corestore credential request requires only a JWT identity');
|
|
419
|
+
}
|
|
420
|
+
if (!isIdentifier(requestArg.mutationId)
|
|
421
|
+
|| !isIdentifier(requestArg.expectedIngressRecipientKeyId)
|
|
422
|
+
|| !isPositiveSafeInteger(requestArg.expectedIngressRecipientGeneration)) {
|
|
423
|
+
errors.push('publish corestore credential request recipient and mutation must be canonical');
|
|
424
|
+
}
|
|
425
|
+
let envelope;
|
|
426
|
+
try {
|
|
427
|
+
envelope = plugins.smartcrypto.parseX25519Envelope(requestArg.envelope);
|
|
428
|
+
if (envelope.ciphertext.length
|
|
429
|
+
> Math.ceil(corestoreCredentialRuntimeLimits.maximumSealedMaterialBytes * 4 / 3)) {
|
|
430
|
+
errors.push('publish corestore credential envelope exceeds its byte limit');
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
errors.push('publish corestore credential envelope must be strict');
|
|
435
|
+
}
|
|
436
|
+
if (validateSecretRecipientMetadata(activeRecipientArg).length > 0
|
|
437
|
+
|| activeRecipientArg.lifecycleState !== 'active'
|
|
438
|
+
|| activeRecipientArg.recipientKeyId !== requestArg.expectedIngressRecipientKeyId
|
|
439
|
+
|| activeRecipientArg.generation !== requestArg.expectedIngressRecipientGeneration) {
|
|
440
|
+
errors.push('publish corestore credential request must target the active ingress recipient');
|
|
441
|
+
}
|
|
442
|
+
if (envelope) {
|
|
443
|
+
if (envelope.recipientKeyId !== requestArg.expectedIngressRecipientKeyId) {
|
|
444
|
+
errors.push('publish corestore credential envelope recipient must match');
|
|
445
|
+
}
|
|
446
|
+
else if (errors.length === 0 && !await verifySecretEnvelopeContext(envelope, createPublishCorestoreCredentialMaterialEnvelopeContext(requestArg))) {
|
|
447
|
+
errors.push('publish corestore credential envelope context must match');
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return errors;
|
|
451
|
+
};
|
|
452
|
+
const expectedCoverageKeys = (capabilityArg) => capabilityArg === 'database'
|
|
453
|
+
? corestoreDatabaseCredentialKeys
|
|
454
|
+
: corestoreObjectStorageCredentialKeys;
|
|
455
|
+
const computeRuntimeSha256 = async (valueArg) => {
|
|
456
|
+
const digest = new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', new Uint8Array(valueArg)));
|
|
457
|
+
return [...digest].map((byteArg) => byteArg.toString(16).padStart(2, '0')).join('');
|
|
458
|
+
};
|
|
459
|
+
const verifyPublicationAdmissionBinding = async (bindingArg, envelopeArg, contextArg) => {
|
|
460
|
+
try {
|
|
461
|
+
const envelope = plugins.smartcrypto.parseX25519Envelope(envelopeArg);
|
|
462
|
+
if (envelope.recipientKeyId !== bindingArg.recipientKeyId
|
|
463
|
+
|| !await verifySecretEnvelopeContext(envelope, contextArg)) {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
const envelopeDigestInput = JSON.stringify({
|
|
467
|
+
schemaVersion: envelope.schemaVersion,
|
|
468
|
+
profile: envelope.profile,
|
|
469
|
+
recipientKeyId: envelope.recipientKeyId,
|
|
470
|
+
ephemeralPublicKey: envelope.ephemeralPublicKey,
|
|
471
|
+
nonce: envelope.nonce,
|
|
472
|
+
ciphertext: envelope.ciphertext,
|
|
473
|
+
tag: envelope.tag,
|
|
474
|
+
contextDigest: envelope.contextDigest,
|
|
475
|
+
});
|
|
476
|
+
return bindingArg.envelopeDigest
|
|
477
|
+
=== `sha256:${await computeRuntimeSha256(new TextEncoder().encode(envelopeDigestInput))}`
|
|
478
|
+
&& bindingArg.requestContextDigest
|
|
479
|
+
=== `sha256:${await computeRuntimeSha256(contextArg)}`;
|
|
480
|
+
}
|
|
481
|
+
catch {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
export const validateCorestoreCredentialPublicationReceipt = async (receiptArg, expectedArg) => {
|
|
486
|
+
if (!isRecord(receiptArg)
|
|
487
|
+
|| !hasExactKeys(receiptArg, [
|
|
488
|
+
'schemaVersion',
|
|
489
|
+
'mutationId',
|
|
490
|
+
'organizationId',
|
|
491
|
+
'clusterId',
|
|
492
|
+
'serviceId',
|
|
493
|
+
'bindingId',
|
|
494
|
+
'capability',
|
|
495
|
+
'grant',
|
|
496
|
+
'coverage',
|
|
497
|
+
'expectedTargetSecretsRevision',
|
|
498
|
+
'targetSecretsRevision',
|
|
499
|
+
'ingressAdmissionBinding',
|
|
500
|
+
'acceptedAt',
|
|
501
|
+
'replayed',
|
|
502
|
+
])) {
|
|
503
|
+
return ['corestore credential publication receipt must use its exact schema'];
|
|
504
|
+
}
|
|
505
|
+
const errors = validateCorestoreCredentialPublicationGrant(receiptArg.grant);
|
|
506
|
+
if (receiptArg.schemaVersion !== 1
|
|
507
|
+
|| !isIdentifier(receiptArg.mutationId)
|
|
508
|
+
|| !isIdentifier(receiptArg.organizationId)
|
|
509
|
+
|| !isIdentifier(receiptArg.clusterId)
|
|
510
|
+
|| !isIdentifier(receiptArg.serviceId)
|
|
511
|
+
|| !isIdentifier(receiptArg.bindingId)) {
|
|
512
|
+
errors.push('corestore credential publication receipt identifiers must be canonical');
|
|
513
|
+
}
|
|
514
|
+
const grant = receiptArg.grant;
|
|
515
|
+
if ((receiptArg.capability !== 'database' && receiptArg.capability !== 'objectstorage')
|
|
516
|
+
|| receiptArg.serviceId !== grant.serviceId
|
|
517
|
+
|| receiptArg.bindingId !== grant.bindingId
|
|
518
|
+
|| receiptArg.capability !== grant.capability
|
|
519
|
+
|| receiptArg.expectedTargetSecretsRevision !== grant.expectedTargetSecretsRevision) {
|
|
520
|
+
errors.push('corestore credential publication receipt must exactly bind its grant');
|
|
521
|
+
}
|
|
522
|
+
if (receiptArg.mutationId !== expectedArg.request.mutationId
|
|
523
|
+
|| receiptArg.organizationId !== expectedArg.organizationId
|
|
524
|
+
|| receiptArg.clusterId !== expectedArg.clusterId
|
|
525
|
+
|| !corestoreCredentialPublicationGrantsEqual(receiptArg.grant, expectedArg.request.grant)) {
|
|
526
|
+
errors.push('corestore credential publication receipt must match its trusted request scope');
|
|
527
|
+
}
|
|
528
|
+
if (!isRecord(receiptArg.coverage)
|
|
529
|
+
|| !hasExactKeys(receiptArg.coverage, ['keys', 'versionReferences'])
|
|
530
|
+
|| !Array.isArray(receiptArg.coverage.keys)
|
|
531
|
+
|| !Array.isArray(receiptArg.coverage.versionReferences)) {
|
|
532
|
+
errors.push('corestore credential publication coverage must use its exact schema');
|
|
533
|
+
}
|
|
534
|
+
else if (receiptArg.capability === 'database' || receiptArg.capability === 'objectstorage') {
|
|
535
|
+
const requiredKeys = expectedCoverageKeys(receiptArg.capability);
|
|
536
|
+
if (JSON.stringify(receiptArg.coverage.keys) !== JSON.stringify(requiredKeys)
|
|
537
|
+
|| receiptArg.coverage.versionReferences.length !== requiredKeys.length) {
|
|
538
|
+
errors.push('corestore credential publication coverage must be exact');
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
const secretIds = new Set();
|
|
542
|
+
const secretVersionIds = new Set();
|
|
543
|
+
for (const [index, referenceArg] of receiptArg.coverage.versionReferences.entries()) {
|
|
544
|
+
if (!isRecord(referenceArg)
|
|
545
|
+
|| !hasExactKeys(referenceArg, ['key', 'secretId', 'secretVersionId'])
|
|
546
|
+
|| referenceArg.key !== requiredKeys[index]
|
|
547
|
+
|| !isIdentifier(referenceArg.secretId)
|
|
548
|
+
|| !isIdentifier(referenceArg.secretVersionId)) {
|
|
549
|
+
errors.push('corestore credential publication version references must exactly cover keys');
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
if (secretIds.has(referenceArg.secretId)
|
|
553
|
+
|| secretVersionIds.has(referenceArg.secretVersionId)) {
|
|
554
|
+
errors.push('corestore credential publication version references must be unique');
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
secretIds.add(referenceArg.secretId);
|
|
558
|
+
secretVersionIds.add(referenceArg.secretVersionId);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const referenceCount = isRecord(receiptArg.coverage)
|
|
563
|
+
&& Array.isArray(receiptArg.coverage.versionReferences)
|
|
564
|
+
? receiptArg.coverage.versionReferences.length
|
|
565
|
+
: 0;
|
|
566
|
+
if (!isNonNegativeSafeInteger(receiptArg.expectedTargetSecretsRevision)
|
|
567
|
+
|| !isNonNegativeSafeInteger(receiptArg.targetSecretsRevision)
|
|
568
|
+
|| receiptArg.targetSecretsRevision !== receiptArg.expectedTargetSecretsRevision + referenceCount) {
|
|
569
|
+
errors.push('corestore credential publication target Secrets revision must exactly cover created versions');
|
|
570
|
+
}
|
|
571
|
+
const admission = receiptArg.ingressAdmissionBinding;
|
|
572
|
+
if (!isRecord(admission)
|
|
573
|
+
|| !hasExactKeys(admission, [
|
|
574
|
+
'schemaVersion',
|
|
575
|
+
'recipientKeyId',
|
|
576
|
+
'recipientGeneration',
|
|
577
|
+
'envelopeDigest',
|
|
578
|
+
'requestContextDigest',
|
|
579
|
+
])
|
|
580
|
+
|| admission.schemaVersion !== 1
|
|
581
|
+
|| !isIdentifier(admission.recipientKeyId)
|
|
582
|
+
|| !isPositiveSafeInteger(admission.recipientGeneration)
|
|
583
|
+
|| typeof admission.envelopeDigest !== 'string'
|
|
584
|
+
|| !isSha256Digest(admission.envelopeDigest)
|
|
585
|
+
|| typeof admission.requestContextDigest !== 'string'
|
|
586
|
+
|| !isSha256Digest(admission.requestContextDigest)) {
|
|
587
|
+
errors.push('corestore credential publication ingress admission binding must be canonical');
|
|
588
|
+
}
|
|
589
|
+
else if (admission.recipientKeyId !== expectedArg.request.expectedIngressRecipientKeyId
|
|
590
|
+
|| admission.recipientGeneration !== expectedArg.request.expectedIngressRecipientGeneration
|
|
591
|
+
|| !await verifyPublicationAdmissionBinding(admission, expectedArg.request.envelope, createPublishCorestoreCredentialMaterialEnvelopeContext(expectedArg.request))) {
|
|
592
|
+
errors.push('corestore credential publication ingress admission binding must match the request');
|
|
593
|
+
}
|
|
594
|
+
if (!isPositiveSafeInteger(receiptArg.acceptedAt)
|
|
595
|
+
|| receiptArg.acceptedAt < grant.issuedAt
|
|
596
|
+
|| receiptArg.acceptedAt >= grant.expiresAt
|
|
597
|
+
|| typeof receiptArg.replayed !== 'boolean') {
|
|
598
|
+
errors.push('corestore credential publication receipt acceptance must be canonical');
|
|
599
|
+
}
|
|
600
|
+
return errors;
|
|
601
|
+
};
|
|
602
|
+
export const corestoreCredentialPublicationErrorMetadata = Object.freeze({
|
|
603
|
+
INVALID_IDENTITY: Object.freeze({ retryable: false }),
|
|
604
|
+
INVALID_REQUEST: Object.freeze({ retryable: false }),
|
|
605
|
+
GRANT_EXPIRED: Object.freeze({ retryable: false }),
|
|
606
|
+
GRANT_SCOPE_MISMATCH: Object.freeze({ retryable: false }),
|
|
607
|
+
GRANT_REVISION_MISMATCH: Object.freeze({ retryable: true }),
|
|
608
|
+
INGRESS_RECIPIENT_MISMATCH: Object.freeze({ retryable: true }),
|
|
609
|
+
ENVELOPE_INVALID: Object.freeze({ retryable: false }),
|
|
610
|
+
MATERIAL_INVALID: Object.freeze({ retryable: false }),
|
|
611
|
+
SECRETS_REVISION_CONFLICT: Object.freeze({ retryable: true }),
|
|
612
|
+
REPLAY_CONFLICT: Object.freeze({ retryable: false }),
|
|
613
|
+
INTERNAL_ERROR: Object.freeze({ retryable: true }),
|
|
614
|
+
});
|
|
615
|
+
export const getCorestoreCredentialPublicationErrorMetadata = (codeArg) => ({
|
|
616
|
+
schemaVersion: 1,
|
|
617
|
+
code: codeArg,
|
|
618
|
+
retryable: corestoreCredentialPublicationErrorMetadata[codeArg].retryable,
|
|
619
|
+
});
|
|
620
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5jb3Jlc3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9ydW50aW1lLmNvcmVzdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQU14QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDMUQsT0FBTyxFQUNMLCtCQUErQixFQUMvQiwyQkFBMkIsR0FDNUIsTUFBTSxrQkFBa0IsQ0FBQztBQU0xQixPQUFPLEVBQUUsc0NBQXNDLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUk5RixNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3RELFFBQVEsRUFBRSw0QkFBNEI7SUFDdEMsYUFBYSxFQUFFLGlDQUFpQztDQUN4QyxDQUFDLENBQUM7QUFDWixNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyx1QkFBZ0MsQ0FBQztBQUNwRSxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyw0QkFBcUMsQ0FBQztBQUN4RixNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxxQkFBOEIsQ0FBQztBQUM1RSxNQUFNLENBQUMsTUFBTSw4QkFBOEIsR0FBRyxZQUFxQixDQUFDO0FBRXBFLE1BQU0sQ0FBQyxNQUFNLGdDQUFnQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDNUQsdUJBQXVCLEVBQUUsR0FBRztJQUM1Qix3QkFBd0IsRUFBRSxHQUFHO0lBQzdCLHNCQUFzQixFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUk7SUFDM0MsNEJBQTRCLEVBQUUsQ0FBQyxHQUFHLElBQUk7SUFDdEMsMEJBQTBCLEVBQUUsRUFBRSxHQUFHLElBQUk7SUFDckMsd0JBQXdCLEVBQUUsRUFBRTtJQUM1Qix3QkFBd0IsRUFBRSxJQUFJO0lBQzlCLG1DQUFtQyxFQUFFLEVBQUUsR0FBRyxJQUFJO0NBQy9D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
|