@virtru/dsp-sdk 0.5.0 → 0.7.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 +15 -1
- package/README.md +81 -3
- package/dist/src/fips.d.ts +7 -0
- package/dist/src/fips.js +12 -0
- package/dist/src/lib/dsp.d.ts +17 -1
- package/dist/src/lib/dsp.js +28 -5
- package/package.json +25 -4
- package/.prettierrc +0 -3
- package/.rush/temp/chunked-rush-logs/dsp-sdk._phase_build.chunks.jsonl +0 -12
- package/.rush/temp/chunked-rush-logs/dsp-sdk._phase_test.chunks.jsonl +0 -383
- package/.rush/temp/package-deps__phase_build.json +0 -76
- package/.rush/temp/shrinkwrap-deps.json +0 -1262
- package/CHANGELOG.json +0 -299
- package/buf.gen.yaml +0 -17
- package/buf.yaml +0 -4
- package/config/jest.config.json +0 -6
- package/config/rig.json +0 -8
- package/dist/tests/dsp-client.test.d.ts +0 -1
- package/dist/tests/dsp-client.test.js +0 -73
- package/dist/tests/dsp.test.d.ts +0 -1
- package/dist/tests/dsp.test.js +0 -92
- package/dist/tests/fips-crypto.unit.test.d.ts +0 -1
- package/dist/tests/fips-crypto.unit.test.js +0 -258
- package/dist/tests/mocks/create-export-artifacts.d.ts +0 -2
- package/dist/tests/mocks/create-export-artifacts.js +0 -13
- package/dist/tests/mocks/tagging-pdp-tag.d.ts +0 -2
- package/dist/tests/mocks/tagging-pdp-tag.js +0 -11
- package/dist/tests/mocks/well-known-configuration.d.ts +0 -2
- package/dist/tests/mocks/well-known-configuration.js +0 -12
- package/dist/tests/setup-msw.d.ts +0 -9
- package/dist/tests/setup-msw.js +0 -30
- package/dist/tests/setup-unit.d.ts +0 -7
- package/dist/tests/setup-unit.js +0 -70
- package/eslint.config.mjs +0 -28
- package/lib-commonjs/src/gen/buf/validate/validate_pb.js +0 -487
- package/lib-commonjs/src/gen/config/v1/config_pb.js +0 -142
- package/lib-commonjs/src/gen/config/v1/kas_config_pb.js +0 -72
- package/lib-commonjs/src/gen/config/v1/meta_pb.js +0 -36
- package/lib-commonjs/src/gen/config/v1/outlook_config_pb.js +0 -67
- package/lib-commonjs/src/gen/config/v1/secureviewer_config_pb.js +0 -67
- package/lib-commonjs/src/gen/config/v1/tagging_pb.js +0 -246
- package/lib-commonjs/src/gen/google/api/annotations_pb.js +0 -33
- package/lib-commonjs/src/gen/google/api/http_pb.js +0 -44
- package/lib-commonjs/src/gen/policyimportexport/v1/policy_import_export_pb.js +0 -93
- package/lib-commonjs/src/gen/shared/v1/shared_pb.js +0 -95
- package/lib-commonjs/src/gen/tagging/pdp/v2/tagging_pb.js +0 -277
- package/lib-commonjs/src/gen/version/v1/version_pb.js +0 -40
- package/lib-commonjs/src/gen/virtru/common/common_pb.js +0 -76
- package/lib-commonjs/src/gen/virtru/policy/certificates/v1/certificates_pb.js +0 -77
- package/lib-commonjs/src/gen/virtru/policy/objects_pb.js +0 -143
- package/lib-commonjs/src/index.js +0 -48
- package/lib-commonjs/src/lib/client.js +0 -66
- package/lib-commonjs/src/lib/consts.js +0 -10
- package/lib-commonjs/src/lib/dsp.js +0 -49
- package/lib-commonjs/src/lib/fips-crypto/asymmetric.js +0 -126
- package/lib-commonjs/src/lib/fips-crypto/key-format.js +0 -243
- package/lib-commonjs/src/lib/fips-crypto/keys.js +0 -134
- package/lib-commonjs/src/lib/fips-crypto/primitives.js +0 -112
- package/lib-commonjs/src/lib/fips-crypto/symmetric.js +0 -162
- package/lib-commonjs/src/lib/fips-crypto-service.js +0 -57
- package/lib-commonjs/src/lib/utils.js +0 -401
- package/lib-commonjs/tests/dsp-client.test.js +0 -75
- package/lib-commonjs/tests/dsp.test.js +0 -94
- package/lib-commonjs/tests/fips-crypto.unit.test.js +0 -260
- package/lib-commonjs/tests/mocks/create-export-artifacts.js +0 -17
- package/lib-commonjs/tests/mocks/tagging-pdp-tag.js +0 -15
- package/lib-commonjs/tests/mocks/well-known-configuration.js +0 -16
- package/lib-commonjs/tests/setup-msw.js +0 -33
- package/lib-commonjs/tests/setup-unit.js +0 -72
- package/public/virtru.wasm +0 -0
- package/src/gen/buf/validate/validate_pb.ts +0 -4879
- package/src/gen/config/formatters/testdata/v1/test_pb.ts +0 -287
- package/src/gen/config/v1/config_connect.ts +0 -111
- package/src/gen/config/v1/config_pb.ts +0 -439
- package/src/gen/config/v1/kas_config_pb.ts +0 -183
- package/src/gen/config/v1/meta_pb.ts +0 -72
- package/src/gen/config/v1/outlook_config_pb.ts +0 -242
- package/src/gen/config/v1/secureviewer_config_pb.ts +0 -161
- package/src/gen/config/v1/tagging_pb.ts +0 -456
- package/src/gen/google/api/annotations_pb.ts +0 -43
- package/src/gen/google/api/http_pb.ts +0 -486
- package/src/gen/helloworld/v1/helloworld_connect.ts +0 -49
- package/src/gen/helloworld/v1/helloworld_pb.ts +0 -104
- package/src/gen/kas/nanotdf/v1/nanotdf_rewrap_connect.ts +0 -39
- package/src/gen/kas/nanotdf/v1/nanotdf_rewrap_pb.ts +0 -207
- package/src/gen/policyimportexport/v1/policy_import_export_connect.ts +0 -56
- package/src/gen/policyimportexport/v1/policy_import_export_pb.ts +0 -332
- package/src/gen/shared/v1/shared_connect.ts +0 -61
- package/src/gen/shared/v1/shared_pb.ts +0 -240
- package/src/gen/shared/v2/shared_connect.ts +0 -39
- package/src/gen/shared/v2/shared_pb.ts +0 -122
- package/src/gen/tagging/pdp/v2/externalprocessors/processor_connect.ts +0 -156
- package/src/gen/tagging/pdp/v2/externalprocessors/processor_pb.ts +0 -709
- package/src/gen/tagging/pdp/v2/stanag/stanag_pb.ts +0 -953
- package/src/gen/tagging/pdp/v2/tagging_connect.ts +0 -73
- package/src/gen/tagging/pdp/v2/tagging_pb.ts +0 -1064
- package/src/gen/version/v1/version_connect.ts +0 -31
- package/src/gen/version/v1/version_pb.ts +0 -143
- package/src/gen/virtru/common/common_pb.ts +0 -201
- package/src/gen/virtru/policy/certificates/v1/certificates_connect.ts +0 -44
- package/src/gen/virtru/policy/certificates/v1/certificates_pb.ts +0 -305
- package/src/gen/virtru/policy/objects_pb.ts +0 -253
- package/src/gen/web-admin/v1/config_connect.ts +0 -52
- package/src/gen/web-admin/v1/config_pb.ts +0 -173
- package/src/index.ts +0 -62
- package/src/lib/client.ts +0 -90
- package/src/lib/consts.ts +0 -8
- package/src/lib/dsp.ts +0 -65
- package/src/lib/fips-crypto/asymmetric.ts +0 -162
- package/src/lib/fips-crypto/key-format.ts +0 -287
- package/src/lib/fips-crypto/keys.ts +0 -190
- package/src/lib/fips-crypto/primitives.ts +0 -197
- package/src/lib/fips-crypto/symmetric.ts +0 -213
- package/src/lib/fips-crypto-service.ts +0 -58
- package/src/lib/utils.test.ts +0 -415
- package/src/lib/utils.ts +0 -525
- package/src/vite-env.d.ts +0 -7
- package/temp/build/lint/_eslint-5eVG3S6w.json +0 -38
- package/temp/test/jest/haste-map-b055a9550e6d9f9b43d8ad29b1607278-49d19aee56a0732eca9c014a51272338-8710993d07b75a801b0956e67ffc46fa +0 -0
- package/tests/dsp-client.test.ts +0 -95
- package/tests/dsp.test.ts +0 -119
- package/tests/fips-crypto.unit.test.ts +0 -412
- package/tests/mocks/create-export-artifacts.ts +0 -16
- package/tests/mocks/tagging-pdp-tag.ts +0 -13
- package/tests/mocks/well-known-configuration.ts +0 -15
- package/tests/setup-msw.ts +0 -35
- package/tests/setup-unit.ts +0 -108
- package/tsconfig.json +0 -32
- package/update-protos.sh +0 -63
- package/vitest.config.ts +0 -48
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.FipsCryptoService = exports.exportPrivateKeyPem = exports.importPrivateKey = exports.unwrapSymmetricKey = exports.unwrapPrivateKey = exports.unwrapPublicKey = exports.wrapKeyPair = exports.wrapSymmetricKey = exports.wrapPrivateKey = exports.wrapPublicKey = exports.initializeFipsCrypto = void 0;
|
|
9
|
-
const singlecontainer_1 = require("@opentdf/sdk/singlecontainer");
|
|
10
|
-
var primitives_1 = require("./fips-crypto/primitives");
|
|
11
|
-
Object.defineProperty(exports, "initializeFipsCrypto", { enumerable: true, get: function () { return primitives_1.initializeFipsCrypto; } });
|
|
12
|
-
var keys_1 = require("./fips-crypto/keys");
|
|
13
|
-
Object.defineProperty(exports, "wrapPublicKey", { enumerable: true, get: function () { return keys_1.wrapPublicKey; } });
|
|
14
|
-
Object.defineProperty(exports, "wrapPrivateKey", { enumerable: true, get: function () { return keys_1.wrapPrivateKey; } });
|
|
15
|
-
Object.defineProperty(exports, "wrapSymmetricKey", { enumerable: true, get: function () { return keys_1.wrapSymmetricKey; } });
|
|
16
|
-
Object.defineProperty(exports, "wrapKeyPair", { enumerable: true, get: function () { return keys_1.wrapKeyPair; } });
|
|
17
|
-
Object.defineProperty(exports, "unwrapPublicKey", { enumerable: true, get: function () { return keys_1.unwrapPublicKey; } });
|
|
18
|
-
Object.defineProperty(exports, "unwrapPrivateKey", { enumerable: true, get: function () { return keys_1.unwrapPrivateKey; } });
|
|
19
|
-
Object.defineProperty(exports, "unwrapSymmetricKey", { enumerable: true, get: function () { return keys_1.unwrapSymmetricKey; } });
|
|
20
|
-
const primitives_2 = require("./fips-crypto/primitives");
|
|
21
|
-
const symmetric_1 = require("./fips-crypto/symmetric");
|
|
22
|
-
const asymmetric_1 = require("./fips-crypto/asymmetric");
|
|
23
|
-
const key_format_1 = require("./fips-crypto/key-format");
|
|
24
|
-
var key_format_2 = require("./fips-crypto/key-format");
|
|
25
|
-
Object.defineProperty(exports, "importPrivateKey", { enumerable: true, get: function () { return key_format_2.importPrivateKey; } });
|
|
26
|
-
Object.defineProperty(exports, "exportPrivateKeyPem", { enumerable: true, get: function () { return key_format_2.exportPrivateKeyPem; } });
|
|
27
|
-
// ─── FipsCryptoService ────────────────────────────────────────────────────────
|
|
28
|
-
exports.FipsCryptoService = {
|
|
29
|
-
name: 'FipsCryptoService',
|
|
30
|
-
method: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
|
|
31
|
-
decrypt: symmetric_1.decrypt,
|
|
32
|
-
decryptWithPrivateKey: asymmetric_1.decryptWithPrivateKey,
|
|
33
|
-
encrypt: symmetric_1.encrypt,
|
|
34
|
-
encryptWithPublicKey: asymmetric_1.encryptWithPublicKey,
|
|
35
|
-
generateKey: symmetric_1.generateKey,
|
|
36
|
-
generateKeyPair: asymmetric_1.generateKeyPair,
|
|
37
|
-
generateSigningKeyPair: asymmetric_1.generateSigningKeyPair,
|
|
38
|
-
randomBytes: primitives_2.randomBytes,
|
|
39
|
-
sign: asymmetric_1.sign,
|
|
40
|
-
verify: asymmetric_1.verify,
|
|
41
|
-
hmac: symmetric_1.hmac,
|
|
42
|
-
verifyHmac: symmetric_1.verifyHmac,
|
|
43
|
-
digest: primitives_2.digest,
|
|
44
|
-
generateECKeyPair: asymmetric_1.generateECKeyPair,
|
|
45
|
-
deriveKeyFromECDH: asymmetric_1.deriveKeyFromECDH,
|
|
46
|
-
importPublicKey: key_format_1.importPublicKey,
|
|
47
|
-
importPrivateKey: key_format_1.importPrivateKey,
|
|
48
|
-
exportPublicKeyPem: key_format_1.exportPublicKeyPem,
|
|
49
|
-
exportPrivateKeyPem: key_format_1.exportPrivateKeyPem,
|
|
50
|
-
exportPublicKeyJwk: key_format_1.exportPublicKeyJwk,
|
|
51
|
-
parsePublicKeyPem: key_format_1.parsePublicKeyPem,
|
|
52
|
-
extractPublicKeyPem: key_format_1.extractPublicKeyPem,
|
|
53
|
-
jwkToPublicKeyPem: key_format_1.jwkToPublicKeyPem,
|
|
54
|
-
importSymmetricKey: symmetric_1.importSymmetricKey,
|
|
55
|
-
splitSymmetricKey: symmetric_1.splitSymmetricKey,
|
|
56
|
-
mergeSymmetricKeys: symmetric_1.mergeSymmetricKeys,
|
|
57
|
-
};
|
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.flattenObligations = exports.getObligations = void 0;
|
|
9
|
-
exports.createAuthInterceptor = createAuthInterceptor;
|
|
10
|
-
exports.createAuthProvider = createAuthProvider;
|
|
11
|
-
exports.createOpenTDFClient = createOpenTDFClient;
|
|
12
|
-
exports.getUserEntitlements = getUserEntitlements;
|
|
13
|
-
exports.getTrustedCertificates = getTrustedCertificates;
|
|
14
|
-
exports.validateJWSCertificateChain = validateJWSCertificateChain;
|
|
15
|
-
const sdk_1 = require("@opentdf/sdk");
|
|
16
|
-
const singlecontainer_1 = require("@opentdf/sdk/singlecontainer");
|
|
17
|
-
const platform_1 = require("@opentdf/sdk/platform");
|
|
18
|
-
const common_pb_js_1 = require("@opentdf/sdk/platform/common/common_pb.js");
|
|
19
|
-
const asn1js = require("asn1js");
|
|
20
|
-
const pkijs = require("pkijs");
|
|
21
|
-
const consts_1 = require("./consts");
|
|
22
|
-
const client_1 = require("./client");
|
|
23
|
-
/**
|
|
24
|
-
* Creates an interceptor that adds authentication headers to outgoing requests.
|
|
25
|
-
*
|
|
26
|
-
* This function uses the provided `AuthProvider` to generate authentication credentials
|
|
27
|
-
* for each request. The `AuthProvider` is expected to implement a `withCreds` method
|
|
28
|
-
* that returns an object containing authentication headers. These headers are then
|
|
29
|
-
* added to the request before it is sent to the server.
|
|
30
|
-
*
|
|
31
|
-
* @param authProvider - An instance of `AuthProvider` used to generate authentication credentials.
|
|
32
|
-
* @returns An `Interceptor` function that modifies requests to include authentication headers.
|
|
33
|
-
*/
|
|
34
|
-
function createAuthInterceptor(authProvider, _cryptoService) {
|
|
35
|
-
return (next) => async (req) => {
|
|
36
|
-
const url = new URL(req.url);
|
|
37
|
-
const pathOnly = url.pathname;
|
|
38
|
-
// Signs only the path of the url in the request
|
|
39
|
-
const token = await authProvider.withCreds({
|
|
40
|
-
url: pathOnly,
|
|
41
|
-
method: 'POST',
|
|
42
|
-
headers: {
|
|
43
|
-
'Content-Type': 'application/json',
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
Object.entries(token.headers).forEach(([key, value]) => {
|
|
47
|
-
req.header.set(key, value);
|
|
48
|
-
});
|
|
49
|
-
return await next(req);
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
/** Creates a new instance of an OIDC Auth Provider consumed by the TDF Clients */
|
|
53
|
-
async function createAuthProvider(options) {
|
|
54
|
-
const { oidc, refreshToken } = options;
|
|
55
|
-
return await sdk_1.AuthProviders.refreshAuthProvider({
|
|
56
|
-
clientId: oidc.clientId,
|
|
57
|
-
exchange: 'refresh',
|
|
58
|
-
refreshToken: refreshToken,
|
|
59
|
-
// TODO(DSPX-1559): Clean up these URLs.
|
|
60
|
-
oidcOrigin: 'https://only-required-for-back-compat.invalid',
|
|
61
|
-
oidcTokenEndpoint: oidc.tokenEndpoint,
|
|
62
|
-
oidcUserInfoEndpoint: oidc.userInfoEndpoint,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
async function createOpenTDFClient(options) {
|
|
66
|
-
const { platformEndpoint, obligations, ...authProviderOptions } = options;
|
|
67
|
-
return new sdk_1.OpenTDF({
|
|
68
|
-
authProvider: await createAuthProvider(authProviderOptions),
|
|
69
|
-
platformUrl: platformEndpoint,
|
|
70
|
-
policyEndpoint: platformEndpoint,
|
|
71
|
-
defaultCreateOptions: {
|
|
72
|
-
defaultKASEndpoint: `${platformEndpoint}/kas`,
|
|
73
|
-
},
|
|
74
|
-
defaultReadOptions: {
|
|
75
|
-
fulfillableObligationFQNs: obligations,
|
|
76
|
-
// NOTE(DSP-249): Disabling assertion verification until all generated assertions are supported.
|
|
77
|
-
noVerify: true,
|
|
78
|
-
},
|
|
79
|
-
disableDPoP: true,
|
|
80
|
-
cryptoService: options.cryptoService,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
const getObligations = async (ciphertext, options) => {
|
|
84
|
-
const client = await createOpenTDFClient(options);
|
|
85
|
-
const source = {
|
|
86
|
-
type: 'buffer',
|
|
87
|
-
location: new Uint8Array(ciphertext),
|
|
88
|
-
};
|
|
89
|
-
const tdfReader = client.open({ source });
|
|
90
|
-
let obligations = [];
|
|
91
|
-
try {
|
|
92
|
-
obligations = (await tdfReader.obligations()).fqns;
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
if (error instanceof sdk_1.PermissionDeniedError) {
|
|
96
|
-
obligations = error.requiredObligations || [];
|
|
97
|
-
}
|
|
98
|
-
// Swallow other errors and return empty obligations.
|
|
99
|
-
}
|
|
100
|
-
return obligations;
|
|
101
|
-
};
|
|
102
|
-
exports.getObligations = getObligations;
|
|
103
|
-
async function getUserEntitlements(options) {
|
|
104
|
-
const authProvider = await createAuthProvider({
|
|
105
|
-
oidc: options.oidc,
|
|
106
|
-
refreshToken: options.refreshToken,
|
|
107
|
-
cryptoService: options.cryptoService,
|
|
108
|
-
});
|
|
109
|
-
const accessToken = await authProvider.oidcAuth.get();
|
|
110
|
-
const userEntitlementsResponse = await fetch(`${options.platformEndpoint}/shared/entitlements`, {
|
|
111
|
-
body: JSON.stringify({}),
|
|
112
|
-
headers: {
|
|
113
|
-
Authorization: `Bearer ${accessToken}`,
|
|
114
|
-
'Content-Type': 'application/json',
|
|
115
|
-
},
|
|
116
|
-
method: 'POST',
|
|
117
|
-
});
|
|
118
|
-
return (await userEntitlementsResponse.json());
|
|
119
|
-
}
|
|
120
|
-
const flattenObligations = (obligations) => Object.values(obligations).flatMap((feature) => feature?.fully_qualified_names || []);
|
|
121
|
-
exports.flattenObligations = flattenObligations;
|
|
122
|
-
/**
|
|
123
|
-
* Helper function to retrieve certificates for a specific namespace with pagination handling.
|
|
124
|
-
*
|
|
125
|
-
* This function automatically handles pagination to retrieve all certificates for a namespace,
|
|
126
|
-
* making multiple requests if necessary.
|
|
127
|
-
*
|
|
128
|
-
* @param dspClient - The DSP client instance.
|
|
129
|
-
* @param namespaceId - The namespace UUID.
|
|
130
|
-
* @returns A promise that resolves to an array of certificates for the namespace.
|
|
131
|
-
* @throws If there is an error retrieving the certificates from the CertificateService.
|
|
132
|
-
*/
|
|
133
|
-
async function getCertificatesForNamespace(dspClient, namespaceId) {
|
|
134
|
-
const certificates = [];
|
|
135
|
-
let offset = 0;
|
|
136
|
-
const limit = 100;
|
|
137
|
-
while (true) {
|
|
138
|
-
const response = await dspClient.v1.certificateService.listCertificatesByNamespace({
|
|
139
|
-
namespaceId,
|
|
140
|
-
pagination: { limit, offset },
|
|
141
|
-
});
|
|
142
|
-
if (response.certificates?.length > 0) {
|
|
143
|
-
certificates.push(...response.certificates);
|
|
144
|
-
}
|
|
145
|
-
// Check for more pages
|
|
146
|
-
if (response.pagination?.nextOffset && response.pagination.nextOffset > 0) {
|
|
147
|
-
offset = response.pagination.nextOffset;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return certificates;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Retrieves all trusted certificates from active namespaces in the platform.
|
|
157
|
-
*
|
|
158
|
-
* This function uses the new CertificateService API to retrieve certificates from all active
|
|
159
|
-
* namespaces. It automatically handles pagination to ensure all certificates are retrieved.
|
|
160
|
-
*
|
|
161
|
-
* The function performs the following steps:
|
|
162
|
-
* 1. Creates an authenticated auth provider with DPoP signing keys
|
|
163
|
-
* 2. Lists all active namespaces using the PlatformClient
|
|
164
|
-
* 3. For each namespace, retrieves all associated certificates using the CertificateService
|
|
165
|
-
* 4. Aggregates and returns all certificates from all namespaces
|
|
166
|
-
*
|
|
167
|
-
* @param options - The options object containing the platform endpoint, OIDC configuration, and refresh token.
|
|
168
|
-
* @param options.oidc - The OIDC configuration object.
|
|
169
|
-
* @param options.oidc.clientId - The OIDC client ID.
|
|
170
|
-
* @param options.oidc.tokenEndpoint - The OIDC token endpoint URL.
|
|
171
|
-
* @param options.oidc.userInfoEndpoint - The OIDC user info endpoint URL.
|
|
172
|
-
* @param options.platformEndpoint - The base URL of the platform.
|
|
173
|
-
* @param options.refreshToken - The refresh token for authentication.
|
|
174
|
-
* @returns A promise that resolves to an array of trusted certificates from all active namespaces.
|
|
175
|
-
* @throws If there is an error retrieving namespaces or certificates.
|
|
176
|
-
*
|
|
177
|
-
* @example
|
|
178
|
-
* ```typescript
|
|
179
|
-
* const certificates = await getTrustedCertificates({
|
|
180
|
-
* oidc: {
|
|
181
|
-
* clientId: 'my-client-id',
|
|
182
|
-
* tokenEndpoint: 'https://auth.example.com/token',
|
|
183
|
-
* userInfoEndpoint: 'https://auth.example.com/userinfo',
|
|
184
|
-
* },
|
|
185
|
-
* platformEndpoint: 'https://platform.example.com',
|
|
186
|
-
* refreshToken: 'my-refresh-token',
|
|
187
|
-
* });
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
async function getTrustedCertificates(options) {
|
|
191
|
-
const cs = options.cryptoService ?? singlecontainer_1.WebCryptoService;
|
|
192
|
-
const authProvider = await createAuthProvider({
|
|
193
|
-
oidc: options.oidc,
|
|
194
|
-
refreshToken: options.refreshToken,
|
|
195
|
-
cryptoService: options.cryptoService,
|
|
196
|
-
});
|
|
197
|
-
await authProvider.updateClientPublicKey(await cs.generateSigningKeyPair());
|
|
198
|
-
// Create both clients
|
|
199
|
-
const platform = new platform_1.PlatformClient({
|
|
200
|
-
authProvider,
|
|
201
|
-
platformUrl: options.platformEndpoint,
|
|
202
|
-
});
|
|
203
|
-
const dspClient = new client_1.DSPClient({
|
|
204
|
-
platformUrl: options.platformEndpoint,
|
|
205
|
-
authProvider,
|
|
206
|
-
});
|
|
207
|
-
const certificates = [];
|
|
208
|
-
try {
|
|
209
|
-
// Get active namespaces (still using namespace API)
|
|
210
|
-
const namespaces = await platform.v1.namespace.listNamespaces({
|
|
211
|
-
state: common_pb_js_1.ActiveStateEnum.ACTIVE,
|
|
212
|
-
});
|
|
213
|
-
// Get certificates using new CertificateService API
|
|
214
|
-
for (const namespace of namespaces.namespaces) {
|
|
215
|
-
const namespaceCerts = await getCertificatesForNamespace(dspClient, namespace.id);
|
|
216
|
-
certificates.push(...namespaceCerts);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
throw error;
|
|
221
|
-
}
|
|
222
|
-
return certificates;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Helper to get a string representation of a pkijs Name.
|
|
226
|
-
*/
|
|
227
|
-
function getNameStringSafe(name) {
|
|
228
|
-
if (!name)
|
|
229
|
-
return '';
|
|
230
|
-
try {
|
|
231
|
-
// pkijs Name to string can be derived from typesAndValues
|
|
232
|
-
const parts = (name.typesAndValues || []).map((tv) => {
|
|
233
|
-
const type = tv?.type ?? 'unknownType';
|
|
234
|
-
// tv.value is an ASN.1 value; best-effort toString fallback
|
|
235
|
-
let value;
|
|
236
|
-
try {
|
|
237
|
-
const block = tv?.value?.valueBlock;
|
|
238
|
-
const v = block?.value;
|
|
239
|
-
value = typeof v === 'string' ? v : String(tv?.value);
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
value = '<?>';
|
|
243
|
-
}
|
|
244
|
-
return `${type}=${value}`;
|
|
245
|
-
});
|
|
246
|
-
return parts.join(', ');
|
|
247
|
-
}
|
|
248
|
-
catch {
|
|
249
|
-
return '';
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
function base64ToArrayBuffer(b64) {
|
|
253
|
-
const normalized = b64.replace(/\s+/g, '');
|
|
254
|
-
// Basic sanity check; allow trailing '=' padding
|
|
255
|
-
if (!/^[-A-Za-z0-9+/]*=*$/.test(normalized)) {
|
|
256
|
-
throw new Error('Invalid base64 characters');
|
|
257
|
-
}
|
|
258
|
-
// Optional size guard (approx: 3/4 of base64 length is bytes)
|
|
259
|
-
const approxBytes = Math.floor((normalized.length * 3) / 4);
|
|
260
|
-
if (approxBytes === 0) {
|
|
261
|
-
throw new Error('Empty base64 data');
|
|
262
|
-
}
|
|
263
|
-
if (approxBytes > consts_1.MAX_CERT_BYTES) {
|
|
264
|
-
throw new Error(`Certificate exceeds maximum allowed size of ${consts_1.MAX_CERT_BYTES} bytes`);
|
|
265
|
-
}
|
|
266
|
-
const binaryString = atob(normalized);
|
|
267
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
268
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
269
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
270
|
-
}
|
|
271
|
-
return bytes.buffer; // bytes is freshly allocated; buffer is tightly packed
|
|
272
|
-
}
|
|
273
|
-
function pemToArrayBuffer(pem) {
|
|
274
|
-
const base64Der = pem
|
|
275
|
-
.replace(/-----BEGIN CERTIFICATE-----/g, '')
|
|
276
|
-
.replace(/-----END CERTIFICATE-----/g, '')
|
|
277
|
-
.replace(/\r?\n|\r|\s/g, '');
|
|
278
|
-
return base64ToArrayBuffer(base64Der);
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Validate that a certificate chain from JWS x5c header chains to a trusted root.
|
|
282
|
-
*
|
|
283
|
-
* This function is designed to be portable and can be moved to another repository.
|
|
284
|
-
* It validates that the certificate chain presented in a JWS x5c header builds a
|
|
285
|
-
* valid chain to one of the provided trusted root certificates.
|
|
286
|
-
*
|
|
287
|
-
* Expectations and behavior:
|
|
288
|
-
* - `x5c` must be ordered leaf-first and contain base64-encoded DER certs.
|
|
289
|
-
* - `trustedRootCertificates` should contain PEM-encoded root certificates.
|
|
290
|
-
* - Performs basic input size checks and safe base64 decoding.
|
|
291
|
-
* - Uses PKI.js `CertificateChainValidationEngine` for comprehensive path validation
|
|
292
|
-
* (validity dates, signatures, policies when present, etc.).
|
|
293
|
-
* - Returns detailed error messages including the leaf subject/issuer and parsing warnings.
|
|
294
|
-
*
|
|
295
|
-
* @param x5c - Array of base64-encoded DER certificates from JWS header (leaf first)
|
|
296
|
-
* @param trustedRootCertificates - Array of Certificate objects containing trusted roots in PEM format
|
|
297
|
-
* @returns Object with validation result and warnings
|
|
298
|
-
* @throws {Error} if validation fails
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* ```typescript
|
|
302
|
-
* try {
|
|
303
|
-
* const result = await validateJWSCertificateChain(
|
|
304
|
-
* jwsHeader.x5c,
|
|
305
|
-
* namespaceCertificates
|
|
306
|
-
* );
|
|
307
|
-
* console.log('Chain validates to trusted root', result.validationResult.warnings);
|
|
308
|
-
* } catch (error) {
|
|
309
|
-
* console.error('Validation failed:', error.message);
|
|
310
|
-
* }
|
|
311
|
-
* ```
|
|
312
|
-
*/
|
|
313
|
-
async function validateJWSCertificateChain(x5c, trustedRootCertificates, _cryptoService) {
|
|
314
|
-
const warnings = [];
|
|
315
|
-
try {
|
|
316
|
-
// Validate inputs
|
|
317
|
-
if (!Array.isArray(x5c) || x5c.length === 0) {
|
|
318
|
-
throw new Error('No certificates provided in x5c array');
|
|
319
|
-
}
|
|
320
|
-
if (x5c.length > consts_1.MAX_CERTS) {
|
|
321
|
-
throw new Error(`Too many certificates in x5c (max ${consts_1.MAX_CERTS})`);
|
|
322
|
-
}
|
|
323
|
-
if (!Array.isArray(trustedRootCertificates) ||
|
|
324
|
-
trustedRootCertificates.length === 0) {
|
|
325
|
-
throw new Error('No trusted root certificates provided');
|
|
326
|
-
}
|
|
327
|
-
// Parse chain certs (base64 DER)
|
|
328
|
-
const chainCertificates = [];
|
|
329
|
-
for (let i = 0; i < x5c.length; i++) {
|
|
330
|
-
const certBase64 = x5c[i];
|
|
331
|
-
try {
|
|
332
|
-
const certBuffer = base64ToArrayBuffer(certBase64);
|
|
333
|
-
const asn1 = asn1js.fromBER(certBuffer);
|
|
334
|
-
if (asn1.offset === -1) {
|
|
335
|
-
throw new Error(`Invalid DER encoding for certificate at x5c[${i}]`);
|
|
336
|
-
}
|
|
337
|
-
chainCertificates.push(new pkijs.Certificate({ schema: asn1.result }));
|
|
338
|
-
}
|
|
339
|
-
catch (err) {
|
|
340
|
-
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
341
|
-
throw new Error(`Failed to parse certificate at x5c[${i}]: ${msg}`);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
// Parse trusted roots (PEM)
|
|
345
|
-
const trustedCerts = [];
|
|
346
|
-
for (let i = 0; i < trustedRootCertificates.length; i++) {
|
|
347
|
-
const rootCert = trustedRootCertificates[i];
|
|
348
|
-
try {
|
|
349
|
-
const pem = rootCert.pem;
|
|
350
|
-
if (!pem || pem.trim().length === 0) {
|
|
351
|
-
warnings.push(`Trusted root at index ${i} has no PEM data; skipping`);
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
const certBuffer = pemToArrayBuffer(pem);
|
|
355
|
-
const asn1 = asn1js.fromBER(certBuffer);
|
|
356
|
-
if (asn1.offset === -1) {
|
|
357
|
-
warnings.push(`Trusted root at index ${i} has invalid DER; skipping`);
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
trustedCerts.push(new pkijs.Certificate({ schema: asn1.result }));
|
|
361
|
-
}
|
|
362
|
-
catch (err) {
|
|
363
|
-
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
364
|
-
warnings.push(`Failed to parse trusted root at index ${i}: ${msg}`);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if (trustedCerts.length === 0) {
|
|
368
|
-
throw new Error('No valid trusted root certificates could be parsed');
|
|
369
|
-
}
|
|
370
|
-
// Build and verify certificate chain using PKI.js
|
|
371
|
-
const chainEngine = new pkijs.CertificateChainValidationEngine({
|
|
372
|
-
trustedCerts,
|
|
373
|
-
certs: chainCertificates,
|
|
374
|
-
checkDate: new Date(),
|
|
375
|
-
});
|
|
376
|
-
const verificationResult = await chainEngine.verify();
|
|
377
|
-
if (!verificationResult.result) {
|
|
378
|
-
// Compose detailed message
|
|
379
|
-
const leaf = chainCertificates[0];
|
|
380
|
-
const leafSubject = getNameStringSafe(leaf.subject);
|
|
381
|
-
const leafIssuer = getNameStringSafe(leaf.issuer);
|
|
382
|
-
const baseMsg = verificationResult.resultMessage ||
|
|
383
|
-
'Certificate chain validation failed';
|
|
384
|
-
throw new Error(`${baseMsg} (leaf subject='${leafSubject}', issuer='${leafIssuer}')`);
|
|
385
|
-
}
|
|
386
|
-
return {
|
|
387
|
-
valid: true,
|
|
388
|
-
validationResult: {
|
|
389
|
-
warnings,
|
|
390
|
-
errors: [],
|
|
391
|
-
},
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
catch (error) {
|
|
395
|
-
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
396
|
-
const warnSuffix = warnings.length
|
|
397
|
-
? `; warnings: ${warnings.join(' | ')}`
|
|
398
|
-
: '';
|
|
399
|
-
throw new Error(`Validation error: ${msg}${warnSuffix}`);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
const vitest_1 = require("vitest");
|
|
9
|
-
const index_1 = require("../src/index");
|
|
10
|
-
const tagging_pdp_tag_1 = require("./mocks/tagging-pdp-tag");
|
|
11
|
-
const create_export_artifacts_1 = require("./mocks/create-export-artifacts");
|
|
12
|
-
const platformUrl = 'https://dsp.example.com';
|
|
13
|
-
// Mock fetch globally
|
|
14
|
-
const mockFetch = vitest_1.vi.fn();
|
|
15
|
-
global.fetch = mockFetch;
|
|
16
|
-
(0, vitest_1.beforeEach)(() => {
|
|
17
|
-
mockFetch.mockReset();
|
|
18
|
-
// Setup default mock responses
|
|
19
|
-
mockFetch.mockImplementation(async (url) => {
|
|
20
|
-
if (url.includes('/tagging.pdp.v2.TaggingPDPService/Tag')) {
|
|
21
|
-
return {
|
|
22
|
-
ok: true,
|
|
23
|
-
status: 200,
|
|
24
|
-
json: async () => (0, tagging_pdp_tag_1.mockTaggingPDPResponse)(),
|
|
25
|
-
headers: new Headers({
|
|
26
|
-
'Content-Type': 'application/json',
|
|
27
|
-
}),
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
if (url.includes('/policyimportexport.v1.PolicyArtifactService/CreateExportArtifacts')) {
|
|
31
|
-
return {
|
|
32
|
-
ok: true,
|
|
33
|
-
status: 200,
|
|
34
|
-
json: async () => (0, create_export_artifacts_1.mockCreateExportArtifactsResponse)(),
|
|
35
|
-
headers: new Headers({
|
|
36
|
-
'Content-Type': 'application/json',
|
|
37
|
-
}),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
return {
|
|
41
|
-
ok: false,
|
|
42
|
-
status: 404,
|
|
43
|
-
json: async () => ({}),
|
|
44
|
-
headers: new Headers(),
|
|
45
|
-
};
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
(0, vitest_1.test)('should create a new DSPClient instance with platformUrl', async () => {
|
|
49
|
-
const client = new index_1.DSPClient({ platformUrl });
|
|
50
|
-
(0, vitest_1.expect)(client).toBeInstanceOf(index_1.DSPClient);
|
|
51
|
-
});
|
|
52
|
-
(0, vitest_1.test)('should throw an error if platformUrl is not provided', async () => {
|
|
53
|
-
(0, vitest_1.expect)(() => new index_1.DSPClient({})).toThrowError('platformUrl is required for DSP client');
|
|
54
|
-
});
|
|
55
|
-
(0, vitest_1.test)('should perform RPC calls using the taggingPDPService', async () => {
|
|
56
|
-
const client = new index_1.DSPClient({ platformUrl });
|
|
57
|
-
(0, vitest_1.expect)(client).toBeInstanceOf(index_1.DSPClient);
|
|
58
|
-
const result = await client.v2.taggingPDPService.tag({});
|
|
59
|
-
(0, vitest_1.expect)(result.$typeName).toBe('tagging.pdp.v2.TaggingPDPResponse');
|
|
60
|
-
});
|
|
61
|
-
(0, vitest_1.test)('should perform RPC calls using the policyArtifactService', async () => {
|
|
62
|
-
const client = new index_1.DSPClient({ platformUrl });
|
|
63
|
-
(0, vitest_1.expect)(client).toBeInstanceOf(index_1.DSPClient);
|
|
64
|
-
const result = await client.v1.policyArtifactService.createExportArtifacts({});
|
|
65
|
-
(0, vitest_1.expect)(result.$typeName).toBe('policyimportexport.v1.CreateExportArtifactsResponse');
|
|
66
|
-
});
|
|
67
|
-
(0, vitest_1.test)('should use provided interceptors when making RPC calls', async () => {
|
|
68
|
-
const mockInterceptor = vitest_1.vi.fn((next) => next);
|
|
69
|
-
const client = new index_1.DSPClient({
|
|
70
|
-
platformUrl,
|
|
71
|
-
interceptors: [mockInterceptor],
|
|
72
|
-
});
|
|
73
|
-
await client.v2.taggingPDPService.tag({});
|
|
74
|
-
(0, vitest_1.expect)(mockInterceptor).toHaveBeenCalled();
|
|
75
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
const vitest_1 = require("vitest");
|
|
9
|
-
const src_1 = require("../src");
|
|
10
|
-
const tagging_pdp_tag_1 = require("./mocks/tagging-pdp-tag");
|
|
11
|
-
const sdk_1 = require("@opentdf/sdk");
|
|
12
|
-
const well_known_configuration_1 = require("./mocks/well-known-configuration");
|
|
13
|
-
const platformUrl = 'https://dsp.example.com';
|
|
14
|
-
// Mock fetch globally
|
|
15
|
-
const mockFetch = vitest_1.vi.fn();
|
|
16
|
-
global.fetch = mockFetch;
|
|
17
|
-
const authProvider = {
|
|
18
|
-
updateClientPublicKey: async () => { },
|
|
19
|
-
withCreds: async (req) => (0, sdk_1.withHeaders)(req, {
|
|
20
|
-
Authorization: 'Bearer dummy auth token for testing purposes',
|
|
21
|
-
}),
|
|
22
|
-
};
|
|
23
|
-
(0, vitest_1.beforeEach)(() => {
|
|
24
|
-
mockFetch.mockReset();
|
|
25
|
-
// Setup default mock responses
|
|
26
|
-
mockFetch.mockImplementation(async (url) => {
|
|
27
|
-
if (url.includes('/tagging.pdp.v2.TaggingPDPService/Tag')) {
|
|
28
|
-
return {
|
|
29
|
-
ok: true,
|
|
30
|
-
status: 200,
|
|
31
|
-
json: async () => (0, tagging_pdp_tag_1.mockTaggingPDPResponse)(),
|
|
32
|
-
headers: new Headers({
|
|
33
|
-
'Content-Type': 'application/json',
|
|
34
|
-
}),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
if (url.includes('/wellknownconfiguration.WellKnownService/GetWellKnownConfiguration')) {
|
|
38
|
-
return {
|
|
39
|
-
ok: true,
|
|
40
|
-
status: 200,
|
|
41
|
-
json: async () => (0, well_known_configuration_1.mockWellKnownConfiguration)(),
|
|
42
|
-
headers: new Headers({
|
|
43
|
-
'Content-Type': 'application/json',
|
|
44
|
-
}),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
ok: false,
|
|
49
|
-
status: 404,
|
|
50
|
-
json: async () => ({}),
|
|
51
|
-
headers: new Headers(),
|
|
52
|
-
};
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
(0, vitest_1.test)('should create a new DSP instance with platformUrl', () => {
|
|
56
|
-
const dsp = new src_1.DSP({ platformUrl, authProvider });
|
|
57
|
-
(0, vitest_1.expect)(dsp).toBeInstanceOf(src_1.DSP);
|
|
58
|
-
});
|
|
59
|
-
(0, vitest_1.test)('should throw an error if platformUrl is not provided', () => {
|
|
60
|
-
(0, vitest_1.expect)(() => new src_1.DSP({ authProvider })).toThrowError('platformUrl is required for DSP client');
|
|
61
|
-
});
|
|
62
|
-
(0, vitest_1.test)('should create a new DSP instance with platformUrl and authProvider', () => {
|
|
63
|
-
const dsp = new src_1.DSP({ platformUrl, authProvider });
|
|
64
|
-
(0, vitest_1.expect)(dsp).toBeInstanceOf(src_1.DSP);
|
|
65
|
-
});
|
|
66
|
-
(0, vitest_1.test)('should perform RPC calls using the DSP client service', async () => {
|
|
67
|
-
const dsp = new src_1.DSP({ platformUrl, authProvider });
|
|
68
|
-
const result = await dsp.services.v2.taggingPDPService.tag({});
|
|
69
|
-
(0, vitest_1.expect)(result.$typeName).toBe('tagging.pdp.v2.TaggingPDPResponse');
|
|
70
|
-
});
|
|
71
|
-
(0, vitest_1.test)('should perform RPC calls via internal PlatformClient service', async () => {
|
|
72
|
-
const dsp = new src_1.DSP({ platformUrl, authProvider });
|
|
73
|
-
const result = await dsp.services.v1.wellknown.getWellKnownConfiguration({});
|
|
74
|
-
(0, vitest_1.expect)(result.$typeName).toBe('wellknownconfiguration.GetWellKnownConfigurationResponse');
|
|
75
|
-
});
|
|
76
|
-
(0, vitest_1.test)('should use provided interceptors when making RPC calls', async () => {
|
|
77
|
-
const mockInterceptor = vitest_1.vi.fn((next) => next);
|
|
78
|
-
const dsp = new src_1.DSP({
|
|
79
|
-
platformUrl,
|
|
80
|
-
authProvider,
|
|
81
|
-
interceptors: [mockInterceptor],
|
|
82
|
-
});
|
|
83
|
-
await dsp.services.v2.taggingPDPService.tag({});
|
|
84
|
-
(0, vitest_1.expect)(mockInterceptor).toHaveBeenCalled();
|
|
85
|
-
});
|
|
86
|
-
(0, vitest_1.test)('should expose expected service structure', () => {
|
|
87
|
-
const dsp = new src_1.DSP({ platformUrl, authProvider });
|
|
88
|
-
(0, vitest_1.expect)(dsp.services).toHaveProperty('v1');
|
|
89
|
-
(0, vitest_1.expect)(dsp.services.v2).toHaveProperty('taggingPDPService');
|
|
90
|
-
(0, vitest_1.expect)(dsp.services.v1).toHaveProperty('wellknown');
|
|
91
|
-
});
|
|
92
|
-
(0, vitest_1.test)('should throw if authProvider is missing', () => {
|
|
93
|
-
(0, vitest_1.expect)(() => new src_1.DSP({ platformUrl })).toThrowError('Client ID or custom AuthProvider must be defined');
|
|
94
|
-
});
|