@opentdf/sdk 0.4.0-beta.4 → 0.4.0-beta.40
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/dist/cjs/src/access.js +16 -1
- package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +4 -2
- package/dist/cjs/src/auth/oidc-externaljwt-provider.js +5 -3
- package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +19 -3
- package/dist/cjs/src/auth/oidc.js +9 -8
- package/dist/cjs/src/auth/providers.js +7 -1
- package/dist/cjs/src/index.js +4 -2
- package/dist/cjs/src/opentdf.js +66 -12
- package/dist/cjs/src/platform/authorization/v2/authorization_pb.js +112 -0
- package/dist/cjs/src/platform/buf/validate/validate_pb.js +114 -170
- package/dist/cjs/src/platform/common/common_pb.js +16 -5
- package/dist/cjs/src/platform/entity/entity_pb.js +51 -0
- package/dist/cjs/src/platform/entityresolution/entity_resolution_pb.js +1 -1
- package/dist/cjs/src/platform/entityresolution/v2/entity_resolution_pb.js +49 -0
- package/dist/cjs/src/platform/google/api/annotations_pb.js +1 -1
- package/dist/cjs/src/platform/google/api/http_pb.js +3 -3
- package/dist/cjs/src/platform/kas/kas_pb.js +2 -2
- package/dist/cjs/src/platform/policy/attributes/attributes_pb.js +12 -2
- package/dist/cjs/src/platform/policy/kasregistry/key_access_server_registry_pb.js +57 -4
- package/dist/cjs/src/platform/policy/keymanagement/key_management_pb.js +2 -2
- package/dist/cjs/src/platform/policy/namespaces/namespaces_pb.js +31 -4
- package/dist/cjs/src/platform/policy/objects_pb.js +116 -42
- package/dist/cjs/src/platform/policy/obligations/obligations_pb.js +159 -0
- package/dist/cjs/src/platform/policy/registeredresources/registered_resources_pb.js +20 -15
- package/dist/cjs/src/platform/policy/resourcemapping/resource_mapping_pb.js +2 -3
- package/dist/cjs/src/platform/policy/selectors_pb.js +1 -1
- package/dist/cjs/src/platform/policy/subjectmapping/subject_mapping_pb.js +2 -3
- package/dist/cjs/src/platform/policy/unsafe/unsafe_pb.js +2 -4
- package/dist/cjs/src/platform.js +16 -3
- package/dist/cjs/src/policy/api.js +27 -7
- package/dist/cjs/src/policy/granter.js +75 -48
- package/dist/cjs/src/seekable.js +32 -1
- package/dist/cjs/src/utils.js +57 -3
- package/dist/cjs/tdf3/src/assertions.js +39 -2
- package/dist/cjs/tdf3/src/client/builders.js +13 -1
- package/dist/cjs/tdf3/src/client/index.js +200 -53
- package/dist/cjs/tdf3/src/client/validation.js +3 -3
- package/dist/cjs/tdf3/src/tdf.js +20 -2
- package/dist/cjs/tdf3/src/utils/unwrap.js +2 -2
- package/dist/types/src/access.d.ts +15 -0
- package/dist/types/src/access.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +1 -1
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +1 -1
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +15 -1
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc.d.ts +4 -0
- package/dist/types/src/auth/oidc.d.ts.map +1 -1
- package/dist/types/src/auth/providers.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/opentdf.d.ts +126 -6
- package/dist/types/src/opentdf.d.ts.map +1 -1
- package/dist/types/src/platform/authorization/v2/authorization_pb.d.ts +439 -0
- package/dist/types/src/platform/authorization/v2/authorization_pb.d.ts.map +1 -0
- package/dist/types/src/platform/buf/validate/validate_pb.d.ts +495 -370
- package/dist/types/src/platform/buf/validate/validate_pb.d.ts.map +1 -1
- package/dist/types/src/platform/common/common_pb.d.ts +36 -0
- package/dist/types/src/platform/common/common_pb.d.ts.map +1 -1
- package/dist/types/src/platform/entity/entity_pb.d.ts +130 -0
- package/dist/types/src/platform/entity/entity_pb.d.ts.map +1 -0
- package/dist/types/src/platform/entityresolution/entity_resolution_pb.d.ts +4 -0
- package/dist/types/src/platform/entityresolution/entity_resolution_pb.d.ts.map +1 -1
- package/dist/types/src/platform/entityresolution/v2/entity_resolution_pb.d.ts +136 -0
- package/dist/types/src/platform/entityresolution/v2/entity_resolution_pb.d.ts.map +1 -0
- package/dist/types/src/platform/google/api/http_pb.d.ts.map +1 -1
- package/dist/types/src/platform/kas/kas_pb.d.ts +5 -0
- package/dist/types/src/platform/kas/kas_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/attributes/attributes_pb.d.ts +44 -13
- package/dist/types/src/platform/policy/attributes/attributes_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts +329 -24
- package/dist/types/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/keymanagement/key_management_pb.d.ts +20 -1
- package/dist/types/src/platform/policy/keymanagement/key_management_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/namespaces/namespaces_pb.d.ts +143 -5
- package/dist/types/src/platform/policy/namespaces/namespaces_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/objects_pb.d.ts +382 -33
- package/dist/types/src/platform/policy/objects_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/obligations/obligations_pb.d.ts +670 -0
- package/dist/types/src/platform/policy/obligations/obligations_pb.d.ts.map +1 -0
- package/dist/types/src/platform/policy/registeredresources/registered_resources_pb.d.ts +67 -0
- package/dist/types/src/platform/policy/registeredresources/registered_resources_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/resourcemapping/resource_mapping_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/selectors_pb.d.ts +18 -0
- package/dist/types/src/platform/policy/selectors_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/subjectmapping/subject_mapping_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/unsafe/unsafe_pb.d.ts +18 -4
- package/dist/types/src/platform/policy/unsafe/unsafe_pb.d.ts.map +1 -1
- package/dist/types/src/platform.d.ts +16 -0
- package/dist/types/src/platform.d.ts.map +1 -1
- package/dist/types/src/policy/api.d.ts +2 -0
- package/dist/types/src/policy/api.d.ts.map +1 -1
- package/dist/types/src/policy/granter.d.ts +11 -6
- package/dist/types/src/policy/granter.d.ts.map +1 -1
- package/dist/types/src/seekable.d.ts +31 -0
- package/dist/types/src/seekable.d.ts.map +1 -1
- package/dist/types/src/utils.d.ts +56 -2
- package/dist/types/src/utils.d.ts.map +1 -1
- package/dist/types/tdf3/src/assertions.d.ts +4 -0
- package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/builders.d.ts +12 -0
- package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/index.d.ts +11 -3
- package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/validation.d.ts +3 -3
- package/dist/types/tdf3/src/client/validation.d.ts.map +1 -1
- package/dist/types/tdf3/src/tdf.d.ts +2 -1
- package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
- package/dist/types/tdf3/src/utils/unwrap.d.ts.map +1 -1
- package/dist/web/src/access.js +16 -1
- package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -2
- package/dist/web/src/auth/oidc-externaljwt-provider.js +5 -3
- package/dist/web/src/auth/oidc-refreshtoken-provider.js +19 -3
- package/dist/web/src/auth/oidc.js +9 -8
- package/dist/web/src/auth/providers.js +7 -1
- package/dist/web/src/index.js +2 -1
- package/dist/web/src/opentdf.js +66 -12
- package/dist/web/src/platform/authorization/v2/authorization_pb.js +109 -0
- package/dist/web/src/platform/buf/validate/validate_pb.js +113 -169
- package/dist/web/src/platform/common/common_pb.js +15 -4
- package/dist/web/src/platform/entity/entity_pb.js +48 -0
- package/dist/web/src/platform/entityresolution/entity_resolution_pb.js +1 -1
- package/dist/web/src/platform/entityresolution/v2/entity_resolution_pb.js +46 -0
- package/dist/web/src/platform/google/api/annotations_pb.js +1 -1
- package/dist/web/src/platform/google/api/http_pb.js +3 -3
- package/dist/web/src/platform/kas/kas_pb.js +2 -2
- package/dist/web/src/platform/policy/attributes/attributes_pb.js +12 -2
- package/dist/web/src/platform/policy/kasregistry/key_access_server_registry_pb.js +55 -3
- package/dist/web/src/platform/policy/keymanagement/key_management_pb.js +2 -2
- package/dist/web/src/platform/policy/namespaces/namespaces_pb.js +30 -3
- package/dist/web/src/platform/policy/objects_pb.js +114 -41
- package/dist/web/src/platform/policy/obligations/obligations_pb.js +156 -0
- package/dist/web/src/platform/policy/registeredresources/registered_resources_pb.js +19 -14
- package/dist/web/src/platform/policy/resourcemapping/resource_mapping_pb.js +2 -3
- package/dist/web/src/platform/policy/selectors_pb.js +1 -1
- package/dist/web/src/platform/policy/subjectmapping/subject_mapping_pb.js +2 -3
- package/dist/web/src/platform/policy/unsafe/unsafe_pb.js +2 -4
- package/dist/web/src/platform.js +16 -3
- package/dist/web/src/policy/api.js +26 -7
- package/dist/web/src/policy/granter.js +75 -48
- package/dist/web/src/seekable.js +32 -1
- package/dist/web/src/utils.js +57 -3
- package/dist/web/tdf3/src/assertions.js +38 -2
- package/dist/web/tdf3/src/client/builders.js +13 -1
- package/dist/web/tdf3/src/client/index.js +202 -56
- package/dist/web/tdf3/src/client/validation.js +3 -3
- package/dist/web/tdf3/src/tdf.js +20 -2
- package/dist/web/tdf3/src/utils/unwrap.js +2 -2
- package/package.json +7 -5
- package/src/access.ts +15 -0
- package/src/auth/oidc-clientcredentials-provider.ts +4 -0
- package/src/auth/oidc-externaljwt-provider.ts +5 -1
- package/src/auth/oidc-refreshtoken-provider.ts +19 -1
- package/src/auth/oidc.ts +12 -7
- package/src/auth/providers.ts +6 -0
- package/src/index.ts +1 -0
- package/src/opentdf.ts +149 -72
- package/src/platform/authorization/v2/authorization_pb.ts +503 -0
- package/src/platform/buf/validate/validate_pb.ts +529 -401
- package/src/platform/common/common_pb.ts +48 -3
- package/src/platform/entity/entity_pb.ts +154 -0
- package/src/platform/entityresolution/entity_resolution_pb.ts +4 -0
- package/src/platform/entityresolution/v2/entity_resolution_pb.ts +170 -0
- package/src/platform/google/api/annotations_pb.ts +1 -1
- package/src/platform/google/api/http_pb.ts +2 -2
- package/src/platform/kas/kas_pb.ts +6 -1
- package/src/platform/policy/attributes/attributes_pb.ts +46 -16
- package/src/platform/policy/kasregistry/key_access_server_registry_pb.ts +371 -27
- package/src/platform/policy/keymanagement/key_management_pb.ts +24 -2
- package/src/platform/policy/namespaces/namespaces_pb.ts +163 -7
- package/src/platform/policy/objects_pb.ts +474 -59
- package/src/platform/policy/obligations/obligations_pb.ts +788 -0
- package/src/platform/policy/registeredresources/registered_resources_pb.ts +80 -13
- package/src/platform/policy/resourcemapping/resource_mapping_pb.ts +1 -2
- package/src/platform/policy/selectors_pb.ts +18 -0
- package/src/platform/policy/subjectmapping/subject_mapping_pb.ts +1 -2
- package/src/platform/policy/unsafe/unsafe_pb.ts +21 -6
- package/src/platform.ts +19 -5
- package/src/policy/api.ts +37 -6
- package/src/policy/granter.ts +82 -56
- package/src/seekable.ts +31 -0
- package/src/utils.ts +56 -2
- package/tdf3/src/assertions.ts +52 -1
- package/tdf3/src/client/builders.ts +15 -0
- package/tdf3/src/client/index.ts +279 -73
- package/tdf3/src/client/validation.ts +2 -2
- package/tdf3/src/tdf.ts +26 -2
- package/tdf3/src/utils/unwrap.ts +2 -1
package/tdf3/src/client/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { v4 } from 'uuid';
|
|
2
2
|
import {
|
|
3
|
-
ZipReader,
|
|
4
|
-
streamToBuffer,
|
|
5
3
|
keyMiddleware as defaultKeyMiddleware,
|
|
4
|
+
streamToBuffer,
|
|
5
|
+
ZipReader,
|
|
6
6
|
} from '../utils/index.js';
|
|
7
7
|
import { base64 } from '../../../src/encodings/index.js';
|
|
8
8
|
import {
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
type EncryptConfiguration,
|
|
11
11
|
fetchKasPublicKey,
|
|
12
12
|
loadTDFStream,
|
|
13
|
-
validatePolicyObject,
|
|
14
13
|
readStream,
|
|
14
|
+
validatePolicyObject,
|
|
15
15
|
writeStream,
|
|
16
16
|
} from '../tdf.js';
|
|
17
17
|
import { unwrapHtml } from '../utils/unwrap.js';
|
|
@@ -27,22 +27,18 @@ import {
|
|
|
27
27
|
} from '../../../src/utils.js';
|
|
28
28
|
|
|
29
29
|
import {
|
|
30
|
-
type EncryptParams,
|
|
31
30
|
type DecryptParams,
|
|
32
|
-
|
|
31
|
+
DecryptParamsBuilder,
|
|
32
|
+
type DecryptSource,
|
|
33
33
|
type DecryptStreamMiddleware,
|
|
34
|
+
DEFAULT_SEGMENT_SIZE,
|
|
34
35
|
type EncryptKeyMiddleware,
|
|
36
|
+
type EncryptParams,
|
|
37
|
+
EncryptParamsBuilder,
|
|
35
38
|
type EncryptStreamMiddleware,
|
|
36
|
-
type
|
|
39
|
+
type Scope,
|
|
37
40
|
} from './builders.js';
|
|
38
41
|
import { DecoratedReadableStream } from './DecoratedReadableStream.js';
|
|
39
|
-
|
|
40
|
-
import {
|
|
41
|
-
DEFAULT_SEGMENT_SIZE,
|
|
42
|
-
DecryptParamsBuilder,
|
|
43
|
-
type DecryptSource,
|
|
44
|
-
EncryptParamsBuilder,
|
|
45
|
-
} from './builders.js';
|
|
46
42
|
import {
|
|
47
43
|
fetchKeyAccessServers,
|
|
48
44
|
type KasPublicKeyInfo,
|
|
@@ -62,8 +58,8 @@ import {
|
|
|
62
58
|
} from '../models/index.js';
|
|
63
59
|
import { plan } from '../../../src/policy/granter.js';
|
|
64
60
|
import { attributeFQNsAsValues } from '../../../src/policy/api.js';
|
|
65
|
-
import { type Value } from '../../../src/policy/attributes.js';
|
|
66
61
|
import { type Chunker, fromBuffer, fromSource } from '../../../src/seekable.js';
|
|
62
|
+
import { Algorithm, SimpleKasKey } from '../../../src/platform/policy/objects_pb.js';
|
|
67
63
|
|
|
68
64
|
const GLOBAL_BYTE_LIMIT = 64 * 1000 * 1000 * 1000; // 64 GB, see WS-9363.
|
|
69
65
|
|
|
@@ -72,6 +68,11 @@ const defaultClientConfig = { oidcOrigin: '', cryptoService: defaultCryptoServic
|
|
|
72
68
|
|
|
73
69
|
const getFirstTwoBytes = async (chunker: Chunker) => new TextDecoder().decode(await chunker(0, 2));
|
|
74
70
|
|
|
71
|
+
async function algorithmFromPEM(pem: string) {
|
|
72
|
+
const k: CryptoKey = await pemToCryptoPublicKey(pem);
|
|
73
|
+
return keyAlgorithmToPublicKeyAlgorithm(k);
|
|
74
|
+
}
|
|
75
|
+
|
|
75
76
|
// Convert a PEM string to a CryptoKey
|
|
76
77
|
export const resolveKasInfo = async (
|
|
77
78
|
pem: string,
|
|
@@ -227,6 +228,95 @@ function asPolicy(scope: Scope): Policy {
|
|
|
227
228
|
};
|
|
228
229
|
}
|
|
229
230
|
|
|
231
|
+
type KasKeyInfoCache = [
|
|
232
|
+
...Parameters<typeof fetchKasPublicKey>,
|
|
233
|
+
keyInfoPromise: ReturnType<typeof fetchKasPublicKey>,
|
|
234
|
+
][];
|
|
235
|
+
|
|
236
|
+
export function findEntryInCache(
|
|
237
|
+
cache: KasKeyInfoCache,
|
|
238
|
+
...params: Parameters<typeof fetchKasPublicKey>
|
|
239
|
+
) {
|
|
240
|
+
const [wantedKas, wantedAlgorithm, wantedKid] = params;
|
|
241
|
+
for (const item of cache) {
|
|
242
|
+
const [itemKas, itemAlgorithm, itemKid, itemKeyInfoPromise] = item;
|
|
243
|
+
if (itemKas !== wantedKas) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
// This makes undefined only match with undefined (base key).
|
|
247
|
+
// We could potentially consider any key a match if undefined algorithm?
|
|
248
|
+
if (itemAlgorithm !== wantedAlgorithm) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (wantedKid && itemKid !== wantedKid) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
return itemKeyInfoPromise;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const fetchKasKeyWithCache = (
|
|
260
|
+
cache: KasKeyInfoCache,
|
|
261
|
+
...params: Parameters<typeof fetchKasPublicKey>
|
|
262
|
+
): ReturnType<typeof fetchKasPublicKey> => {
|
|
263
|
+
const cachedEntry = findEntryInCache(cache, ...params);
|
|
264
|
+
if (cachedEntry !== null) {
|
|
265
|
+
return cachedEntry;
|
|
266
|
+
}
|
|
267
|
+
const keyInfoPromise = fetchKasPublicKey(...params);
|
|
268
|
+
cache.push([...params, keyInfoPromise]);
|
|
269
|
+
return keyInfoPromise;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
function algorithmEnumValueToString(algorithmEnumValue: Algorithm) {
|
|
273
|
+
switch (algorithmEnumValue) {
|
|
274
|
+
case Algorithm.RSA_2048:
|
|
275
|
+
return 'rsa:2048';
|
|
276
|
+
case Algorithm.RSA_4096:
|
|
277
|
+
return 'rsa:4096';
|
|
278
|
+
case Algorithm.EC_P256:
|
|
279
|
+
return 'ec:secp256r1';
|
|
280
|
+
case Algorithm.EC_P384:
|
|
281
|
+
return 'ec:secp384r1';
|
|
282
|
+
case Algorithm.EC_P521:
|
|
283
|
+
return 'ec:secp521r1';
|
|
284
|
+
case Algorithm.UNSPECIFIED:
|
|
285
|
+
// Not entirely sure undefined is correct here, but since we need to generate a key for our cache
|
|
286
|
+
// synchonously, it seems to be the best approach for now.
|
|
287
|
+
return undefined;
|
|
288
|
+
default:
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const putKasKeyIntoCache = (
|
|
294
|
+
cache: KasKeyInfoCache,
|
|
295
|
+
kasKey: Omit<SimpleKasKey, 'publicKey'> & {
|
|
296
|
+
publicKey: Exclude<SimpleKasKey['publicKey'], undefined>;
|
|
297
|
+
}
|
|
298
|
+
): ReturnType<typeof fetchKasPublicKey> => {
|
|
299
|
+
const algorithmString = algorithmEnumValueToString(kasKey.publicKey.algorithm);
|
|
300
|
+
const cachedEntry = findEntryInCache(cache, kasKey.kasUri, algorithmString, kasKey.publicKey.kid);
|
|
301
|
+
if (cachedEntry) {
|
|
302
|
+
return cachedEntry;
|
|
303
|
+
}
|
|
304
|
+
const keyInfoPromise = (async function () {
|
|
305
|
+
const keyPromise = pemToCryptoPublicKey(kasKey.publicKey.pem);
|
|
306
|
+
const key = await keyPromise;
|
|
307
|
+
const algorithm = keyAlgorithmToPublicKeyAlgorithm(key);
|
|
308
|
+
return {
|
|
309
|
+
algorithm: algorithm,
|
|
310
|
+
key: keyPromise,
|
|
311
|
+
kid: kasKey.publicKey.kid,
|
|
312
|
+
publicKey: kasKey.publicKey.pem,
|
|
313
|
+
url: kasKey.kasUri,
|
|
314
|
+
};
|
|
315
|
+
})();
|
|
316
|
+
cache.push([kasKey.kasUri, algorithmString, kasKey.publicKey.kid, keyInfoPromise]);
|
|
317
|
+
return keyInfoPromise;
|
|
318
|
+
};
|
|
319
|
+
|
|
230
320
|
export class Client {
|
|
231
321
|
readonly cryptoService: CryptoService;
|
|
232
322
|
|
|
@@ -252,7 +342,7 @@ export class Client {
|
|
|
252
342
|
*/
|
|
253
343
|
readonly platformUrl?: string;
|
|
254
344
|
|
|
255
|
-
readonly
|
|
345
|
+
readonly kasKeyInfoCache: KasKeyInfoCache = [];
|
|
256
346
|
|
|
257
347
|
readonly easEndpoint?: string;
|
|
258
348
|
|
|
@@ -360,11 +450,13 @@ export class Client {
|
|
|
360
450
|
cryptoService: this.cryptoService,
|
|
361
451
|
dpopKeys: clientConfig.dpopKeys,
|
|
362
452
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** Necessary only for testing. A dependency-injection approach should be preferred, but that is difficult currently */
|
|
456
|
+
_doFetchKasKeyWithCache(
|
|
457
|
+
...params: Parameters<typeof fetchKasKeyWithCache>
|
|
458
|
+
): ReturnType<typeof fetchKasKeyWithCache> {
|
|
459
|
+
return fetchKasKeyWithCache(...params);
|
|
368
460
|
}
|
|
369
461
|
|
|
370
462
|
/**
|
|
@@ -396,62 +488,165 @@ export class Client {
|
|
|
396
488
|
mimeType = 'unknown',
|
|
397
489
|
windowSize = DEFAULT_SEGMENT_SIZE,
|
|
398
490
|
keyMiddleware = defaultKeyMiddleware,
|
|
491
|
+
splitPlan: preconfiguredSplitPlan,
|
|
399
492
|
streamMiddleware = async (stream: DecoratedReadableStream) => stream,
|
|
400
493
|
tdfSpecVersion,
|
|
401
494
|
wrappingKeyAlgorithm,
|
|
402
495
|
} = opts;
|
|
403
496
|
const scope = opts.scope ?? { attributes: [], dissem: [] };
|
|
404
497
|
|
|
498
|
+
for (const attributeValue of scope.attributeValues || []) {
|
|
499
|
+
for (const kasKey of attributeValue.kasKeys) {
|
|
500
|
+
if (kasKey.publicKey !== undefined) {
|
|
501
|
+
await putKasKeyIntoCache(this.kasKeyInfoCache, {
|
|
502
|
+
// TypeScript is silly and cannot infer that publicKey is not undefined, without re-referencing it like this, even though we checked already.
|
|
503
|
+
...kasKey,
|
|
504
|
+
publicKey: kasKey.publicKey,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
405
510
|
const policyObject = asPolicy(scope);
|
|
406
511
|
validatePolicyObject(policyObject);
|
|
407
512
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
513
|
+
const splitPlan: {
|
|
514
|
+
kas: string;
|
|
515
|
+
kid?: string;
|
|
516
|
+
pem: string;
|
|
517
|
+
sid?: string;
|
|
518
|
+
}[] = [];
|
|
519
|
+
if (preconfiguredSplitPlan) {
|
|
520
|
+
for (const preconfiguredSplit of preconfiguredSplitPlan) {
|
|
521
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
522
|
+
this.kasKeyInfoCache,
|
|
523
|
+
preconfiguredSplit.kas,
|
|
524
|
+
wrappingKeyAlgorithm,
|
|
525
|
+
preconfiguredSplit.kid
|
|
526
|
+
);
|
|
527
|
+
splitPlan.push({
|
|
528
|
+
kas: kasPublicKeyInfo.url,
|
|
529
|
+
kid: kasPublicKeyInfo.kid,
|
|
530
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
531
|
+
sid: preconfiguredSplit.sid,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
} else if (autoconfigure) {
|
|
535
|
+
const attributeValues = scope.attributeValues ?? [];
|
|
536
|
+
if (!scope.attributes) {
|
|
537
|
+
scope.attributes = attributeValues.map(({ fqn }) => fqn);
|
|
538
|
+
}
|
|
539
|
+
const attributeFQNs = (scope.attributes ?? []).map((attribute) =>
|
|
540
|
+
typeof attribute === 'string' ? attribute : attribute.attribute
|
|
541
|
+
);
|
|
542
|
+
const fqnsWithoutValues = attributeFQNs.filter((fqn) =>
|
|
543
|
+
attributeValues.every((av) => av.fqn !== fqn)
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
if (fqnsWithoutValues.length) {
|
|
547
|
+
// Hydrate missing avs from policy endpoint given the fqns
|
|
548
|
+
if (!this.platformUrl) {
|
|
549
|
+
throw new ConfigurationError('platformUrl not set in TDF3 Client constructor');
|
|
421
550
|
}
|
|
422
|
-
|
|
423
|
-
this.
|
|
551
|
+
const fetchedFQNValues = await attributeFQNsAsValues(
|
|
552
|
+
this.platformUrl,
|
|
424
553
|
this.authProvider as AuthProvider,
|
|
425
|
-
...
|
|
554
|
+
...fqnsWithoutValues
|
|
426
555
|
);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
scope.attributes = avs.map(({ fqn }) => fqn);
|
|
431
|
-
}
|
|
556
|
+
fetchedFQNValues.forEach((fetchedValue) => {
|
|
557
|
+
attributeValues.push(fetchedValue);
|
|
558
|
+
});
|
|
432
559
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
560
|
+
|
|
561
|
+
const hasAllFQNs = attributeFQNs.every((fqn) =>
|
|
562
|
+
attributeValues.some((attributeValue) => attributeValue.fqn === fqn)
|
|
563
|
+
);
|
|
564
|
+
if (attributeFQNs.length != attributeValues.length || !hasAllFQNs) {
|
|
437
565
|
throw new ConfigurationError(
|
|
438
|
-
`Attribute mismatch between [${
|
|
439
|
-
|
|
566
|
+
`Attribute mismatch between [${attributeFQNs}] and explicit values ${JSON.stringify(
|
|
567
|
+
attributeValues.map(({ fqn }) => fqn)
|
|
440
568
|
)}`
|
|
441
569
|
);
|
|
442
570
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
571
|
+
|
|
572
|
+
for (const attributeValue of attributeValues) {
|
|
573
|
+
for (const kasKey of attributeValue.kasKeys) {
|
|
574
|
+
if (kasKey.publicKey !== undefined) {
|
|
575
|
+
await putKasKeyIntoCache(this.kasKeyInfoCache, {
|
|
576
|
+
// TypeScript is silly and cannot infer that publicKey is not undefined, without re-referencing it like this, even though we checked already.
|
|
577
|
+
...kasKey,
|
|
578
|
+
publicKey: kasKey.publicKey,
|
|
579
|
+
});
|
|
451
580
|
}
|
|
452
581
|
}
|
|
453
|
-
|
|
454
|
-
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const detailedPlan = plan(attributeValues);
|
|
585
|
+
for (const item of detailedPlan) {
|
|
586
|
+
if ('kid' in item.kas) {
|
|
587
|
+
const pemAlgorithm = await algorithmFromPEM(item.kas.pem);
|
|
588
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
589
|
+
this.kasKeyInfoCache,
|
|
590
|
+
item.kas.kasUri,
|
|
591
|
+
pemAlgorithm,
|
|
592
|
+
item.kas.kid
|
|
593
|
+
);
|
|
594
|
+
splitPlan.push({
|
|
595
|
+
kas: kasPublicKeyInfo.url,
|
|
596
|
+
kid: kasPublicKeyInfo.kid,
|
|
597
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
598
|
+
sid: item.sid,
|
|
599
|
+
});
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (!item.kas.publicKey) {
|
|
604
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
605
|
+
this.kasKeyInfoCache,
|
|
606
|
+
item.kas.uri,
|
|
607
|
+
wrappingKeyAlgorithm,
|
|
608
|
+
undefined
|
|
609
|
+
);
|
|
610
|
+
splitPlan.push({
|
|
611
|
+
kas: kasPublicKeyInfo.url,
|
|
612
|
+
kid: kasPublicKeyInfo.kid,
|
|
613
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
614
|
+
sid: item.sid,
|
|
615
|
+
});
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
switch (item.kas.publicKey.publicKey.case) {
|
|
620
|
+
case 'remote':
|
|
621
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
622
|
+
this.kasKeyInfoCache,
|
|
623
|
+
item.kas.publicKey.publicKey.value,
|
|
624
|
+
wrappingKeyAlgorithm,
|
|
625
|
+
undefined
|
|
626
|
+
);
|
|
627
|
+
splitPlan.push({
|
|
628
|
+
kas: kasPublicKeyInfo.url,
|
|
629
|
+
kid: kasPublicKeyInfo.kid,
|
|
630
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
631
|
+
sid: item.sid,
|
|
632
|
+
});
|
|
633
|
+
break;
|
|
634
|
+
|
|
635
|
+
case 'cached':
|
|
636
|
+
for (const cachedPublicKey of item.kas.publicKey.publicKey.value.keys) {
|
|
637
|
+
splitPlan.push({
|
|
638
|
+
kas: item.kas.uri,
|
|
639
|
+
kid: cachedPublicKey.kid,
|
|
640
|
+
pem: cachedPublicKey.pem,
|
|
641
|
+
sid: item.sid,
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
break;
|
|
645
|
+
|
|
646
|
+
default:
|
|
647
|
+
throw new Error(`Unknown public key type: ${item.kas.publicKey.publicKey.case}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
455
650
|
}
|
|
456
651
|
|
|
457
652
|
// TODO: Refactor underlying builder to remove some of this unnecessary config.
|
|
@@ -462,37 +657,47 @@ export class Client {
|
|
|
462
657
|
? maxByteLimit
|
|
463
658
|
: opts.byteLimit;
|
|
464
659
|
const encryptionInformation = new SplitKey(new AesGcmCipher(this.cryptoService));
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
660
|
+
if (splitPlan.length === 0) {
|
|
661
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
662
|
+
this.kasKeyInfoCache,
|
|
663
|
+
opts.defaultKASEndpoint ?? this.kasEndpoint,
|
|
664
|
+
wrappingKeyAlgorithm,
|
|
665
|
+
undefined
|
|
666
|
+
);
|
|
667
|
+
splitPlan.push({
|
|
668
|
+
kas: kasPublicKeyInfo.url,
|
|
669
|
+
kid: kasPublicKeyInfo.kid,
|
|
670
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
468
673
|
encryptionInformation.keyAccess = await Promise.all(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
473
|
-
const kasPublicKey = await Promise.any(this.kasKeys[kas]);
|
|
474
|
-
if (kasPublicKey.algorithm !== wrappingKeyAlgorithm) {
|
|
674
|
+
splitPlan.map(async ({ kas, kid, pem, sid }) => {
|
|
675
|
+
const algorithm = await algorithmFromPEM(pem);
|
|
676
|
+
if (algorithm !== wrappingKeyAlgorithm) {
|
|
475
677
|
console.warn(
|
|
476
|
-
`Mismatched wrapping key algorithm: [${
|
|
678
|
+
`Mismatched wrapping key algorithm: [${algorithm}] is not requested type, [${wrappingKeyAlgorithm}]`
|
|
477
679
|
);
|
|
478
680
|
}
|
|
479
681
|
let type: KeyAccessType;
|
|
480
|
-
switch (
|
|
682
|
+
switch (algorithm) {
|
|
481
683
|
case 'rsa:2048':
|
|
684
|
+
case 'rsa:4096':
|
|
482
685
|
type = 'wrapped';
|
|
483
686
|
break;
|
|
687
|
+
case 'ec:secp384r1':
|
|
688
|
+
case 'ec:secp521r1':
|
|
484
689
|
case 'ec:secp256r1':
|
|
485
690
|
type = 'ec-wrapped';
|
|
486
691
|
break;
|
|
487
692
|
default:
|
|
488
|
-
throw new ConfigurationError(`Unsupported algorithm ${
|
|
693
|
+
throw new ConfigurationError(`Unsupported algorithm ${algorithm}`);
|
|
489
694
|
}
|
|
490
695
|
return buildKeyAccess({
|
|
491
|
-
alg:
|
|
696
|
+
alg: algorithm,
|
|
492
697
|
type,
|
|
493
|
-
url:
|
|
494
|
-
kid:
|
|
495
|
-
publicKey:
|
|
698
|
+
url: kas,
|
|
699
|
+
kid: kid,
|
|
700
|
+
publicKey: pem,
|
|
496
701
|
metadata,
|
|
497
702
|
sid,
|
|
498
703
|
});
|
|
@@ -516,6 +721,7 @@ export class Client {
|
|
|
516
721
|
keyForEncryption,
|
|
517
722
|
keyForManifest,
|
|
518
723
|
assertionConfigs: opts.assertionConfigs,
|
|
724
|
+
systemMetadataAssertion: opts.systemMetadataAssertion,
|
|
519
725
|
tdfSpecVersion,
|
|
520
726
|
};
|
|
521
727
|
|
|
@@ -21,10 +21,10 @@ const IP_HOST_PORT = '([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}:[0-9]{1
|
|
|
21
21
|
const HOST = `(${HOST_PORT}|${WWW_HOST}|${IP_HOST_PORT})`;
|
|
22
22
|
|
|
23
23
|
// validate attr name be like `/attr/<attr_name>`
|
|
24
|
-
export const ATTR_NAME = `(/${ATTR_NAME_PROP_NAME}/[a-zA-Z0-9][a-zA-Z0-9-]
|
|
24
|
+
export const ATTR_NAME = `(/${ATTR_NAME_PROP_NAME}/(%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9])+((%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9-])+[a-zA-Z0-9])?)`;
|
|
25
25
|
|
|
26
26
|
// validate value pattern
|
|
27
|
-
export const ATTR_VALUE = `(/${ATTR_VALUE_PROP_NAME}/[a-zA-Z0-9][a-zA-Z0-9-]
|
|
27
|
+
export const ATTR_VALUE = `(/${ATTR_VALUE_PROP_NAME}/(%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9])+((%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9-])+[a-zA-Z0-9])?)`;
|
|
28
28
|
|
|
29
29
|
// validate attribute authority e.g. https://example.com
|
|
30
30
|
const ATTR_AUTHORITY_PATTERN = `(${SCHEME}${HOST})`;
|
package/tdf3/src/tdf.ts
CHANGED
|
@@ -147,6 +147,7 @@ export type EncryptConfiguration = {
|
|
|
147
147
|
keyForEncryption: KeyInfo;
|
|
148
148
|
keyForManifest: KeyInfo;
|
|
149
149
|
assertionConfigs?: AssertionConfig[];
|
|
150
|
+
systemMetadataAssertion?: boolean;
|
|
150
151
|
tdfSpecVersion?: string;
|
|
151
152
|
};
|
|
152
153
|
|
|
@@ -197,8 +198,15 @@ export type RewrapResponse = {
|
|
|
197
198
|
*/
|
|
198
199
|
export async function fetchKasPublicKey(
|
|
199
200
|
kas: string,
|
|
200
|
-
algorithm?: KasPublicKeyAlgorithm
|
|
201
|
+
algorithm?: KasPublicKeyAlgorithm,
|
|
202
|
+
kid?: string
|
|
201
203
|
): Promise<KasPublicKeyInfo> {
|
|
204
|
+
if (kid) {
|
|
205
|
+
// Some specific thing for fetching a key by kid?
|
|
206
|
+
// Currently this is just "using" `kid` so TypeScript doesn't complain and
|
|
207
|
+
// we can use the type for our cache parameters.
|
|
208
|
+
// So this empty `if` is actually doing something.
|
|
209
|
+
}
|
|
202
210
|
return fetchKasPubKeyV2(kas, algorithm);
|
|
203
211
|
}
|
|
204
212
|
|
|
@@ -527,8 +535,24 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
|
|
|
527
535
|
manifest.encryptionInformation.integrityInformation.segments = segmentInfos;
|
|
528
536
|
|
|
529
537
|
manifest.encryptionInformation.method.isStreamable = true;
|
|
530
|
-
|
|
531
538
|
const signedAssertions: assertions.Assertion[] = [];
|
|
539
|
+
if (cfg.systemMetadataAssertion) {
|
|
540
|
+
const systemMetadataConfigBase = assertions.getSystemMetadataAssertionConfig();
|
|
541
|
+
const signingKeyForSystemMetadata: AssertionKey = {
|
|
542
|
+
alg: 'HS256', // Default algorithm, can be configured if needed
|
|
543
|
+
key: new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
|
|
544
|
+
};
|
|
545
|
+
signedAssertions.push(
|
|
546
|
+
await assertions.CreateAssertion(
|
|
547
|
+
aggregateHash,
|
|
548
|
+
{
|
|
549
|
+
...systemMetadataConfigBase, // Spread the properties from the base config
|
|
550
|
+
signingKey: signingKeyForSystemMetadata, // Add the signing key
|
|
551
|
+
},
|
|
552
|
+
cfg.tdfSpecVersion // Pass the TDF spec version
|
|
553
|
+
)
|
|
554
|
+
);
|
|
555
|
+
}
|
|
532
556
|
if (cfg.assertionConfigs && cfg.assertionConfigs.length > 0) {
|
|
533
557
|
await Promise.all(
|
|
534
558
|
cfg.assertionConfigs.map(async (assertionConfig) => {
|
package/tdf3/src/utils/unwrap.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { InvalidFileError } from '../../../src/errors.js';
|
|
|
3
3
|
|
|
4
4
|
export function unwrapHtml(htmlPayload: Uint8Array): Uint8Array {
|
|
5
5
|
const html = new TextDecoder().decode(htmlPayload);
|
|
6
|
-
const payloadRe =
|
|
6
|
+
const payloadRe =
|
|
7
|
+
/<input\s+[^>]*id=(?:['"]?)data-input(?:['"]?)[^>]*value=(?:['"]?)([a-zA-Z0-9+/=\-_]+)(?:['"]?)/;
|
|
7
8
|
const reResult = payloadRe.exec(html);
|
|
8
9
|
if (!reResult) {
|
|
9
10
|
throw new InvalidFileError('Payload is missing');
|