@opentdf/sdk 0.4.0-beta.13 → 0.4.0-beta.14
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-refreshtoken-provider.js +15 -1
- package/dist/cjs/src/index.js +4 -2
- package/dist/cjs/src/opentdf.js +64 -12
- package/dist/cjs/src/platform.js +14 -3
- package/dist/cjs/src/seekable.js +32 -1
- package/dist/cjs/src/utils.js +57 -3
- 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-refreshtoken-provider.d.ts +14 -0
- package/dist/types/src/auth/oidc-refreshtoken-provider.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.d.ts +16 -0
- package/dist/types/src/platform.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/web/src/access.js +16 -1
- package/dist/web/src/auth/oidc-refreshtoken-provider.js +15 -1
- package/dist/web/src/index.js +2 -1
- package/dist/web/src/opentdf.js +64 -12
- package/dist/web/src/platform.js +14 -3
- package/dist/web/src/seekable.js +32 -1
- package/dist/web/src/utils.js +57 -3
- package/package.json +5 -3
- package/src/access.ts +15 -0
- package/src/auth/oidc-refreshtoken-provider.ts +14 -0
- package/src/index.ts +1 -0
- package/src/opentdf.ts +147 -71
- package/src/platform.ts +17 -5
- package/src/seekable.ts +31 -0
- package/src/utils.ts +56 -2
package/src/opentdf.ts
CHANGED
|
@@ -50,162 +50,175 @@ export {
|
|
|
50
50
|
isPublicKeyAlgorithm,
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
/** A map of key identifiers to cryptographic keys. */
|
|
53
54
|
export type Keys = {
|
|
54
55
|
[keyID: string]: CryptoKey | CryptoKeyPair;
|
|
55
56
|
};
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
// that are shared between all container types.
|
|
58
|
+
/** Options for creating a new TDF object, shared between all container types. */
|
|
59
59
|
export type CreateOptions = {
|
|
60
|
-
|
|
60
|
+
/** If the policy service should be used to control creation options. */
|
|
61
61
|
autoconfigure?: boolean;
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
/** List of attributes that will be assigned to the object's policy. */
|
|
64
64
|
attributes?: string[];
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
/**
|
|
67
|
+
* If set and positive, this represents the maxiumum number of bytes to read from a stream to encrypt.
|
|
68
|
+
* This is helpful for enforcing size limits and preventing DoS attacks.
|
|
69
|
+
*/
|
|
68
70
|
byteLimit?: number;
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
/** The KAS to use for creation, if none is specified by the attribute service. */
|
|
71
73
|
defaultKASEndpoint?: string;
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
/** Private (or shared) keys for signing assertions and bindings. */
|
|
74
76
|
signers?: Keys;
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
/** Source of plaintext data. */
|
|
77
79
|
source: Source;
|
|
78
80
|
};
|
|
79
81
|
|
|
82
|
+
/** Options for creating a NanoTDF. */
|
|
80
83
|
export type CreateNanoTDFOptions = CreateOptions & {
|
|
84
|
+
/** The type of binding to use for the NanoTDF. */
|
|
81
85
|
bindingType?: 'ecdsa' | 'gmac';
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
// instead of the DEK.
|
|
87
|
+
/** When creating a new collection, use ECDSA binding with this key id from the signers, instead of the DEK. */
|
|
85
88
|
ecdsaBindingKeyID?: string;
|
|
86
89
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
/**
|
|
91
|
+
* When creating a new collection, use the key in the `signers` list with this id
|
|
92
|
+
* to generate a signature for each element. When absent, the nanotdf is unsigned.
|
|
93
|
+
*/
|
|
91
94
|
signingKeyID?: string;
|
|
92
95
|
};
|
|
93
96
|
|
|
97
|
+
/** Options for creating a NanoTDF collection. */
|
|
94
98
|
export type CreateNanoTDFCollectionOptions = CreateNanoTDFOptions & {
|
|
99
|
+
/** The platform URL. */
|
|
95
100
|
platformUrl: string;
|
|
96
|
-
|
|
101
|
+
/** The maximum number of key iterations to use for a single DEK. */
|
|
97
102
|
maxKeyIterations?: number;
|
|
98
103
|
};
|
|
99
104
|
|
|
100
|
-
|
|
105
|
+
/** Metadata for a TDF object. */
|
|
101
106
|
export type Metadata = object;
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
/** MIME type of the decrypted content. */
|
|
104
109
|
export type MimeType = `${string}/${string}`;
|
|
105
110
|
|
|
106
|
-
|
|
111
|
+
/** Template for a Key Access Object (KAO) to be filled in during encrypt. */
|
|
107
112
|
export type SplitStep = {
|
|
108
|
-
|
|
113
|
+
/** Which KAS to use to rewrap this segment of the key. */
|
|
109
114
|
kas: string;
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
/**
|
|
117
|
+
* An identifier for a key segment.
|
|
118
|
+
* Leave empty to share the key.
|
|
119
|
+
*/
|
|
113
120
|
sid?: string;
|
|
114
121
|
};
|
|
115
122
|
|
|
116
|
-
|
|
123
|
+
/** Options specific to the ZTDF container format. */
|
|
117
124
|
export type CreateZTDFOptions = CreateOptions & {
|
|
118
|
-
|
|
125
|
+
/** Configuration for bound metadata. */
|
|
119
126
|
assertionConfigs?: AssertionConfig[];
|
|
120
127
|
|
|
121
|
-
|
|
128
|
+
/** Unbound metadata (deprecated). */
|
|
122
129
|
metadata?: Metadata;
|
|
123
130
|
|
|
124
|
-
|
|
131
|
+
/** MIME type of the decrypted content. Used for display. */
|
|
125
132
|
mimeType?: MimeType;
|
|
126
133
|
|
|
127
|
-
|
|
134
|
+
/** How to split or share the data encryption key across multiple KASes. */
|
|
128
135
|
splitPlan?: SplitStep[];
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
|
|
137
|
+
/**
|
|
138
|
+
* The segment size for the content; smaller is slower, but allows faster random access.
|
|
139
|
+
* The current default is 1 MiB (2^20 bytes).
|
|
140
|
+
*/
|
|
132
141
|
windowSize?: number;
|
|
133
142
|
|
|
134
|
-
|
|
143
|
+
/** Preferred algorithm to use for Key Access Objects. */
|
|
135
144
|
wrappingKeyAlgorithm?: KasPublicKeyAlgorithm;
|
|
136
145
|
|
|
137
|
-
|
|
146
|
+
/** TDF spec version to target. */
|
|
138
147
|
tdfSpecVersion?: '4.2.2' | '4.3.0';
|
|
139
148
|
};
|
|
140
149
|
|
|
141
|
-
|
|
150
|
+
/** Settings for decrypting any variety of TDF file. */
|
|
142
151
|
export type ReadOptions = {
|
|
143
|
-
|
|
152
|
+
/** The ciphertext source. */
|
|
144
153
|
source: Source;
|
|
145
|
-
|
|
154
|
+
/** The platform URL. */
|
|
146
155
|
platformUrl?: string;
|
|
147
|
-
|
|
156
|
+
/** List of KASes that may be contacted for a rewrap. */
|
|
148
157
|
allowedKASEndpoints?: string[];
|
|
149
|
-
|
|
158
|
+
/** Optionally disable checking the allowlist. */
|
|
150
159
|
ignoreAllowlist?: boolean;
|
|
151
|
-
|
|
160
|
+
/** Public (or shared) keys for verifying assertions. */
|
|
152
161
|
assertionVerificationKeys?: AssertionVerificationKeys;
|
|
153
|
-
|
|
162
|
+
/** Optionally disable assertion verification. */
|
|
154
163
|
noVerify?: boolean;
|
|
155
164
|
|
|
156
|
-
|
|
165
|
+
/** If set, prevents more than this number of concurrent requests to the KAS. */
|
|
157
166
|
concurrencyLimit?: number;
|
|
158
167
|
|
|
159
|
-
|
|
168
|
+
/** Type of key to use for wrapping responses. */
|
|
160
169
|
wrappingKeyAlgorithm?: KasPublicKeyAlgorithm;
|
|
161
170
|
};
|
|
162
171
|
|
|
163
|
-
|
|
172
|
+
/** Defaults and shared settings that are relevant to creating TDF objects. */
|
|
164
173
|
export type OpenTDFOptions = {
|
|
165
|
-
|
|
174
|
+
/** Policy service endpoint. */
|
|
166
175
|
policyEndpoint?: string;
|
|
167
176
|
|
|
168
|
-
|
|
177
|
+
/** Platform URL. */
|
|
169
178
|
platformUrl?: string;
|
|
170
179
|
|
|
171
|
-
|
|
180
|
+
/** Auth provider for connections to the policy service and KASes. */
|
|
172
181
|
authProvider: AuthProvider;
|
|
173
182
|
|
|
174
|
-
|
|
183
|
+
/** Default settings for 'encrypt' type requests. */
|
|
175
184
|
defaultCreateOptions?: Omit<CreateOptions, 'source'>;
|
|
176
185
|
|
|
177
|
-
|
|
186
|
+
/** Default settings for 'decrypt' type requests. */
|
|
178
187
|
defaultReadOptions?: Omit<ReadOptions, 'source'>;
|
|
179
188
|
|
|
180
|
-
|
|
189
|
+
/** If we want to *not* send a DPoP token. */
|
|
181
190
|
disableDPoP?: boolean;
|
|
182
191
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Optional keys for DPoP requests to a server.
|
|
194
|
+
* These often must be registered via a DPoP flow with the IdP
|
|
195
|
+
* which is out of the scope of this library.
|
|
196
|
+
*/
|
|
186
197
|
dpopKeys?: Promise<CryptoKeyPair>;
|
|
187
198
|
|
|
188
|
-
|
|
199
|
+
/** Configuration options for the collection header cache. */
|
|
189
200
|
rewrapCacheOptions?: RewrapCacheOptions;
|
|
190
201
|
};
|
|
191
202
|
|
|
203
|
+
/** A decorated readable stream. */
|
|
192
204
|
export type DecoratedStream = ReadableStream<Uint8Array> & {
|
|
193
|
-
|
|
205
|
+
/** If the source is a TDF3/ZTDF, and includes metadata, and it has been read. */
|
|
194
206
|
metadata?: Promise<unknown>;
|
|
207
|
+
/** The TDF manifest. */
|
|
195
208
|
manifest?: Promise<Manifest>;
|
|
196
|
-
|
|
209
|
+
/** If the source is a NanoTDF, this will be set. */
|
|
197
210
|
header?: Header;
|
|
198
211
|
};
|
|
199
212
|
|
|
200
|
-
|
|
213
|
+
/** Configuration options for the collection header cache. */
|
|
201
214
|
export type RewrapCacheOptions = {
|
|
202
|
-
|
|
215
|
+
/** If we should disable (bypass) the cache. */
|
|
203
216
|
bypass?: boolean;
|
|
204
217
|
|
|
205
|
-
|
|
218
|
+
/** Evict keys after this many milliseconds. */
|
|
206
219
|
maxAge?: number;
|
|
207
220
|
|
|
208
|
-
|
|
221
|
+
/** Check for expired keys once every this many milliseconds. */
|
|
209
222
|
pollInterval?: number;
|
|
210
223
|
};
|
|
211
224
|
|
|
@@ -215,10 +228,11 @@ const defaultRewrapCacheOptions: Required<RewrapCacheOptions> = {
|
|
|
215
228
|
pollInterval: 500,
|
|
216
229
|
};
|
|
217
230
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
231
|
+
/**
|
|
232
|
+
* Cache for headers of nanotdf collections, to quickly open multiple entries of the same collection.
|
|
233
|
+
* It has a demon that removes all keys that have not been accessed in the last 5 minutes.
|
|
234
|
+
* To cancel the demon, and clear the cache, call `close()`.
|
|
235
|
+
* */
|
|
222
236
|
export class RewrapCache {
|
|
223
237
|
private cache?: Map<Uint8Array, { lastAccessTime: number; value: CryptoKey }>;
|
|
224
238
|
private closer?: ReturnType<typeof setInterval>;
|
|
@@ -254,6 +268,7 @@ export class RewrapCache {
|
|
|
254
268
|
return undefined;
|
|
255
269
|
}
|
|
256
270
|
|
|
271
|
+
/** Set a key in the cache. */
|
|
257
272
|
set(key: Uint8Array, value: CryptoKey) {
|
|
258
273
|
if (!this.cache) {
|
|
259
274
|
return;
|
|
@@ -261,6 +276,7 @@ export class RewrapCache {
|
|
|
261
276
|
this.cache.set(key, { lastAccessTime: Date.now(), value });
|
|
262
277
|
}
|
|
263
278
|
|
|
279
|
+
/** Close the cache and release any resources. */
|
|
264
280
|
close() {
|
|
265
281
|
if (this.closer !== undefined) {
|
|
266
282
|
clearInterval(this.closer);
|
|
@@ -294,19 +310,56 @@ export type TDFReader = {
|
|
|
294
310
|
attributes: () => Promise<string[]>;
|
|
295
311
|
};
|
|
296
312
|
|
|
297
|
-
|
|
313
|
+
/**
|
|
314
|
+
* The main OpenTDF class that provides methods for creating and reading TDF files.
|
|
315
|
+
* It supports both NanoTDF and ZTDF formats.
|
|
316
|
+
* It can be used to create new TDF files and read existing ones.
|
|
317
|
+
* This class is the entry point for using the OpenTDF SDK.
|
|
318
|
+
* It requires an authentication provider to be passed in the constructor.
|
|
319
|
+
* It also requires a platform URL to be set, which is used to fetch key access servers and policies.
|
|
320
|
+
* @example
|
|
321
|
+
* ```
|
|
322
|
+
* import { type Chunker, OpenTDF } from '@opentdf/sdk';
|
|
323
|
+
*
|
|
324
|
+
* const oidcCredentials: RefreshTokenCredentials = {
|
|
325
|
+
* clientId: keycloakClientId,
|
|
326
|
+
* exchange: 'refresh',
|
|
327
|
+
* refreshToken: refreshToken,
|
|
328
|
+
* oidcOrigin: keycloakUrl,
|
|
329
|
+
* };
|
|
330
|
+
* const authProvider = await AuthProviders.refreshAuthProvider(oidcCredentials);
|
|
331
|
+
*
|
|
332
|
+
* const client = new OpenTDF({
|
|
333
|
+
* authProvider,
|
|
334
|
+
* platformUrl: 'https://platform.example.com',
|
|
335
|
+
* });
|
|
336
|
+
*
|
|
337
|
+
* const cipherText = await client.createZTDF({
|
|
338
|
+
* source: { type: 'stream', location: source },
|
|
339
|
+
* autoconfigure: false,
|
|
340
|
+
* });
|
|
341
|
+
*
|
|
342
|
+
* const clearText = await client.read({ type: 'stream', location: cipherText });
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
298
345
|
export class OpenTDF {
|
|
299
|
-
|
|
346
|
+
/** The platform URL */
|
|
300
347
|
readonly platformUrl: string;
|
|
348
|
+
/** The policy service endpoint */
|
|
301
349
|
readonly policyEndpoint: string;
|
|
350
|
+
/** The auth provider for the OpenTDF instance. */
|
|
302
351
|
readonly authProvider: AuthProvider;
|
|
352
|
+
/** If DPoP is enabled for this instance. */
|
|
303
353
|
readonly dpopEnabled: boolean;
|
|
354
|
+
/** Default options for creating TDF objects. */
|
|
304
355
|
defaultCreateOptions: Omit<CreateOptions, 'source'>;
|
|
356
|
+
/** Default options for reading TDF objects. */
|
|
305
357
|
defaultReadOptions: Omit<ReadOptions, 'source'>;
|
|
358
|
+
/** The DPoP keys for this instance, if any. */
|
|
306
359
|
readonly dpopKeys: Promise<CryptoKeyPair>;
|
|
307
|
-
|
|
308
|
-
// Header cache for reading nanotdf collections
|
|
360
|
+
/** Cache for rewrapped keys */
|
|
309
361
|
private readonly rewrapCache: RewrapCache;
|
|
362
|
+
/** The TDF3 client for encrypting and decrypting ZTDF files. */
|
|
310
363
|
readonly tdf3Client: TDF3Client;
|
|
311
364
|
|
|
312
365
|
constructor({
|
|
@@ -352,6 +405,7 @@ export class OpenTDF {
|
|
|
352
405
|
);
|
|
353
406
|
}
|
|
354
407
|
|
|
408
|
+
/** Creates a new NanoTDF stream. */
|
|
355
409
|
async createNanoTDF(opts: CreateNanoTDFOptions): Promise<DecoratedStream> {
|
|
356
410
|
opts = {
|
|
357
411
|
...this.defaultCreateOptions,
|
|
@@ -370,7 +424,6 @@ export class OpenTDF {
|
|
|
370
424
|
|
|
371
425
|
/**
|
|
372
426
|
* Creates a new collection object, which can be used to encrypt a series of data with the same policy.
|
|
373
|
-
* @returns
|
|
374
427
|
*/
|
|
375
428
|
async createNanoTDFCollection(
|
|
376
429
|
opts: CreateNanoTDFCollectionOptions
|
|
@@ -379,6 +432,7 @@ export class OpenTDF {
|
|
|
379
432
|
return new Collection(this.authProvider, opts);
|
|
380
433
|
}
|
|
381
434
|
|
|
435
|
+
/** Creates a new ZTDF stream. */
|
|
382
436
|
async createZTDF(opts: CreateZTDFOptions): Promise<DecoratedStream> {
|
|
383
437
|
opts = { ...this.defaultCreateOptions, ...opts };
|
|
384
438
|
const oldStream = await this.tdf3Client.encrypt({
|
|
@@ -403,26 +457,25 @@ export class OpenTDF {
|
|
|
403
457
|
return stream;
|
|
404
458
|
}
|
|
405
459
|
|
|
406
|
-
/**
|
|
407
|
-
* Opens a TDF file for inspection and decryption.
|
|
408
|
-
* @param opts the file to open, and any appropriate configuration options
|
|
409
|
-
* @returns
|
|
410
|
-
*/
|
|
460
|
+
/** Opens a TDF file for inspection and decryption. */
|
|
411
461
|
open(opts: ReadOptions): TDFReader {
|
|
412
462
|
opts = { ...this.defaultReadOptions, ...opts };
|
|
413
463
|
return new UnknownTypeReader(this, opts, this.rewrapCache);
|
|
414
464
|
}
|
|
415
465
|
|
|
466
|
+
/** Decrypts a TDF file. */
|
|
416
467
|
async read(opts: ReadOptions): Promise<DecoratedStream> {
|
|
417
468
|
const reader = this.open(opts);
|
|
418
469
|
return reader.decrypt();
|
|
419
470
|
}
|
|
420
471
|
|
|
472
|
+
/** Closes the OpenTDF instance and releases any resources. */
|
|
421
473
|
close() {
|
|
422
474
|
this.rewrapCache.close();
|
|
423
475
|
}
|
|
424
476
|
}
|
|
425
477
|
|
|
478
|
+
/** A TDF reader that can automatically detect the TDF type. */
|
|
426
479
|
class UnknownTypeReader {
|
|
427
480
|
delegate: Promise<TDFReader>;
|
|
428
481
|
state: 'init' | 'resolving' | 'loaded' | 'decrypting' | 'closing' | 'done' | 'error' = 'init';
|
|
@@ -434,6 +487,7 @@ class UnknownTypeReader {
|
|
|
434
487
|
this.delegate = this.resolveType();
|
|
435
488
|
}
|
|
436
489
|
|
|
490
|
+
/** Resolves the TDF type based on the file prefix. */
|
|
437
491
|
async resolveType(): Promise<TDFReader> {
|
|
438
492
|
if (this.state === 'done') {
|
|
439
493
|
throw new ConfigurationError('reader is closed');
|
|
@@ -455,21 +509,25 @@ class UnknownTypeReader {
|
|
|
455
509
|
throw new InvalidFileError(`unsupported format; prefix not recognized ${prefix}`);
|
|
456
510
|
}
|
|
457
511
|
|
|
512
|
+
/** Decrypts the TDF file */
|
|
458
513
|
async decrypt(): Promise<DecoratedStream> {
|
|
459
514
|
const actual = await this.delegate;
|
|
460
515
|
return actual.decrypt();
|
|
461
516
|
}
|
|
462
517
|
|
|
518
|
+
/** Returns the attributes of the TDF file */
|
|
463
519
|
async attributes(): Promise<string[]> {
|
|
464
520
|
const actual = await this.delegate;
|
|
465
521
|
return actual.attributes();
|
|
466
522
|
}
|
|
467
523
|
|
|
524
|
+
/** Returns the manifest of the TDF file */
|
|
468
525
|
async manifest(): Promise<Manifest> {
|
|
469
526
|
const actual = await this.delegate;
|
|
470
527
|
return actual.manifest();
|
|
471
528
|
}
|
|
472
529
|
|
|
530
|
+
/** Closes the TDF reader */
|
|
473
531
|
async close() {
|
|
474
532
|
if (this.state === 'done') {
|
|
475
533
|
return;
|
|
@@ -487,6 +545,7 @@ class UnknownTypeReader {
|
|
|
487
545
|
}
|
|
488
546
|
}
|
|
489
547
|
|
|
548
|
+
/** A TDF reader for NanoTDF files. */
|
|
490
549
|
class NanoTDFReader {
|
|
491
550
|
container: Promise<NanoTDF>;
|
|
492
551
|
constructor(
|
|
@@ -514,6 +573,7 @@ class NanoTDFReader {
|
|
|
514
573
|
});
|
|
515
574
|
}
|
|
516
575
|
|
|
576
|
+
/** Decrypts the NanoTDF file and returns a decorated stream. */
|
|
517
577
|
async decrypt(): Promise<DecoratedStream> {
|
|
518
578
|
const nanotdf = await this.container;
|
|
519
579
|
const cachedDEK = this.rewrapCache.get(nanotdf.header.ephemeralPublicKey);
|
|
@@ -556,10 +616,12 @@ class NanoTDFReader {
|
|
|
556
616
|
|
|
557
617
|
async close() {}
|
|
558
618
|
|
|
619
|
+
/** Returns blank manifest. NanoTDF has no manifest. */
|
|
559
620
|
async manifest(): Promise<Manifest> {
|
|
560
621
|
return {} as Manifest;
|
|
561
622
|
}
|
|
562
623
|
|
|
624
|
+
/** Returns the attributes of the NanoTDF file. */
|
|
563
625
|
async attributes(): Promise<string[]> {
|
|
564
626
|
const nanotdf = await this.container;
|
|
565
627
|
if (!nanotdf.header.policy?.content) {
|
|
@@ -574,6 +636,7 @@ class NanoTDFReader {
|
|
|
574
636
|
}
|
|
575
637
|
}
|
|
576
638
|
|
|
639
|
+
/** A reader for TDF files. */
|
|
577
640
|
class ZTDFReader {
|
|
578
641
|
overview: Promise<InspectedTDFOverview>;
|
|
579
642
|
constructor(
|
|
@@ -584,6 +647,10 @@ class ZTDFReader {
|
|
|
584
647
|
this.overview = loadTDFStream(source);
|
|
585
648
|
}
|
|
586
649
|
|
|
650
|
+
/**
|
|
651
|
+
* Decrypts the TDF file and returns a decorated stream.
|
|
652
|
+
* The stream will have a manifest and metadata attached if available.
|
|
653
|
+
*/
|
|
587
654
|
async decrypt(): Promise<DecoratedStream> {
|
|
588
655
|
const {
|
|
589
656
|
assertionVerificationKeys,
|
|
@@ -641,11 +708,13 @@ class ZTDFReader {
|
|
|
641
708
|
// TODO figure out how to close a chunker, if we want to.
|
|
642
709
|
}
|
|
643
710
|
|
|
711
|
+
/** Returns the manifest of the TDF file. */
|
|
644
712
|
async manifest(): Promise<Manifest> {
|
|
645
713
|
const overview = await this.overview;
|
|
646
714
|
return overview.manifest;
|
|
647
715
|
}
|
|
648
716
|
|
|
717
|
+
/** Returns the attributes of the TDF file. */
|
|
649
718
|
async attributes(): Promise<string[]> {
|
|
650
719
|
const manifest = await this.manifest();
|
|
651
720
|
const policyJSON = base64.decode(manifest.encryptionInformation.policy);
|
|
@@ -666,13 +735,18 @@ async function streamify(ab: Promise<ArrayBuffer>): Promise<ReadableStream<Uint8
|
|
|
666
735
|
return stream;
|
|
667
736
|
}
|
|
668
737
|
|
|
738
|
+
/** A writer for NanoTDF collections. */
|
|
669
739
|
export type NanoTDFCollectionWriter = {
|
|
740
|
+
/** The NanoTDF client used for encrypting data in this collection. */
|
|
670
741
|
encrypt: (source: Source) => Promise<ReadableStream<Uint8Array>>;
|
|
742
|
+
/** Closes the collection and releases any resources. */
|
|
671
743
|
close: () => Promise<void>;
|
|
672
744
|
};
|
|
673
745
|
|
|
674
746
|
class Collection {
|
|
747
|
+
/** The NanoTDF client used for encrypting data in this collection. */
|
|
675
748
|
client?: NanoTDFDatasetClient;
|
|
749
|
+
/** Options for encrypting data in this collection. */
|
|
676
750
|
encryptOptions?: NanoEncryptOptions;
|
|
677
751
|
|
|
678
752
|
constructor(authProvider: AuthProvider, opts: CreateNanoTDFCollectionOptions) {
|
|
@@ -705,6 +779,7 @@ class Collection {
|
|
|
705
779
|
});
|
|
706
780
|
}
|
|
707
781
|
|
|
782
|
+
/** Encrypts a source into a NanoTDF stream. */
|
|
708
783
|
async encrypt(source: Source): Promise<DecoratedStream> {
|
|
709
784
|
if (!this.client) {
|
|
710
785
|
throw new ConfigurationError('Collection is closed');
|
|
@@ -722,6 +797,7 @@ class Collection {
|
|
|
722
797
|
return stream;
|
|
723
798
|
}
|
|
724
799
|
|
|
800
|
+
/** Releases client resources. */
|
|
725
801
|
async close() {
|
|
726
802
|
delete this.client;
|
|
727
803
|
}
|
package/src/platform.ts
CHANGED
|
@@ -33,11 +33,11 @@ export interface PlatformServices {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export interface PlatformClientOptions {
|
|
36
|
-
|
|
36
|
+
/** Optional authentication provider for generating auth interceptor. */
|
|
37
37
|
authProvider?: AuthProvider;
|
|
38
|
-
|
|
38
|
+
/** Array of custom interceptors to apply to rpc requests. */
|
|
39
39
|
interceptors?: Interceptor[];
|
|
40
|
-
|
|
40
|
+
/** Base URL of the platform API. */
|
|
41
41
|
platformUrl: string;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -50,8 +50,22 @@ export interface PlatformClientOptions {
|
|
|
50
50
|
*
|
|
51
51
|
* This client supports authentication via an `AuthProvider` or custom interceptors, which can
|
|
52
52
|
* be used to add authentication headers or other custom logic to outgoing requests.
|
|
53
|
+
* @example
|
|
54
|
+
* ```
|
|
55
|
+
* import { AuthProviders, OpenTDF } from '@opentdf/sdk';
|
|
56
|
+
* import { PlatformClient } from '@opentdf/sdk/platform';
|
|
53
57
|
*
|
|
58
|
+
* const authProvider: AuthProvider = await AuthProviders.refreshAuthProvider({...});
|
|
59
|
+
* const platform = new PlatformClient({
|
|
60
|
+
* authProvider,
|
|
61
|
+
* platformUrl: 'https://platform.example.com',
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* const wellKnownResponse = await platform.v1.wellknown.getWellKnownConfiguration({});
|
|
65
|
+
* console.log('Well-known configuration:', wellKnownResponse.configuration);
|
|
66
|
+
* ```
|
|
54
67
|
*/
|
|
68
|
+
|
|
55
69
|
export class PlatformClient {
|
|
56
70
|
readonly v1: PlatformServices;
|
|
57
71
|
|
|
@@ -96,8 +110,6 @@ export class PlatformClient {
|
|
|
96
110
|
* that returns an object containing authentication headers. These headers are then
|
|
97
111
|
* added to the request before it is sent to the server.
|
|
98
112
|
*
|
|
99
|
-
* @param authProvider - An instance of `AuthProvider` used to generate authentication credentials.
|
|
100
|
-
* @returns An `Interceptor` function that modifies requests to include authentication headers.
|
|
101
113
|
*/
|
|
102
114
|
function createAuthInterceptor(authProvider: AuthProvider): Interceptor {
|
|
103
115
|
const authInterceptor: Interceptor = (next) => async (req) => {
|
package/src/seekable.ts
CHANGED
|
@@ -33,12 +33,30 @@ export const fromBrowserFile = (fileRef: Blob): Chunker => {
|
|
|
33
33
|
};
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Creates a seekable object from a buffer.
|
|
38
|
+
* @param source A Uint8Array to read from.
|
|
39
|
+
* If byteStart and byteEnd are not provided, reads the entire array.
|
|
40
|
+
* If byteStart is provided, reads from that index to the end of the array.
|
|
41
|
+
* If byteEnd is provided, reads from byteStart to byteEnd (exclusive).
|
|
42
|
+
* If both byteStart and byteEnd are provided, reads from byteStart to byteEnd (exclusive).
|
|
43
|
+
* @returns A promise that resolves to a Uint8Array containing the requested data.
|
|
44
|
+
*/
|
|
36
45
|
export const fromBuffer = (source: Uint8Array): Chunker => {
|
|
37
46
|
return (byteStart?: number, byteEnd?: number) => {
|
|
38
47
|
return Promise.resolve(source.slice(byteStart, byteEnd));
|
|
39
48
|
};
|
|
40
49
|
};
|
|
41
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Creates a seekable object from a string.
|
|
53
|
+
* @param source A string to read from.
|
|
54
|
+
* If byteStart and byteEnd are not provided, reads the entire string.
|
|
55
|
+
* If byteStart is provided, reads from that index to the end of the string.
|
|
56
|
+
* If byteEnd is provided, reads from byteStart to byteEnd (exclusive).
|
|
57
|
+
* If both byteStart and byteEnd are provided, reads from byteStart to byteEnd (exclusive).
|
|
58
|
+
* @returns A promise that resolves to a Uint8Array containing the requested data.
|
|
59
|
+
*/
|
|
42
60
|
export const fromString = (source: string): Chunker => {
|
|
43
61
|
return fromBuffer(new TextEncoder().encode(source));
|
|
44
62
|
};
|
|
@@ -110,6 +128,12 @@ export const fromUrl = async (location: string): Promise<Chunker> => {
|
|
|
110
128
|
};
|
|
111
129
|
};
|
|
112
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Creates a seekable object from a source.
|
|
133
|
+
* @param source A Source object containing the type and location of the data.
|
|
134
|
+
* @returns A promise that resolves to a Chunker function.
|
|
135
|
+
* @throws ConfigurationError if the source type is not supported or the location is invalid.
|
|
136
|
+
*/
|
|
113
137
|
export const fromSource = async ({ type, location }: Source): Promise<Chunker> => {
|
|
114
138
|
switch (type) {
|
|
115
139
|
case 'buffer':
|
|
@@ -139,6 +163,13 @@ export const fromSource = async ({ type, location }: Source): Promise<Chunker> =
|
|
|
139
163
|
}
|
|
140
164
|
};
|
|
141
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Converts a Source object to a ReadableStream.
|
|
168
|
+
* @param source A Source object containing the type and location of the data.
|
|
169
|
+
* Converts the source to a ReadableStream of Uint8Array.
|
|
170
|
+
* This is useful for streaming data from various sources like files, remote URLs, or chunkers.
|
|
171
|
+
* @returns A ReadableStream of Uint8Array.
|
|
172
|
+
*/
|
|
142
173
|
export async function sourceToStream(source: Source): Promise<ReadableStream<Uint8Array>> {
|
|
143
174
|
switch (source.type) {
|
|
144
175
|
case 'stream':
|