@@ -13,7 +13,12 @@ import {
13
13
AssertionConfig ,
14
14
AssertionVerificationKeys ,
15
15
} from '../tdf3/src/assertions.js' ;
16
- import { type KasPublicKeyAlgorithm , OriginAllowList , isPublicKeyAlgorithm } from './access.js' ;
16
+ import {
17
+ type KasPublicKeyAlgorithm ,
18
+ OriginAllowList ,
19
+ fetchKeyAccessServers ,
20
+ isPublicKeyAlgorithm ,
21
+ } from './access.js' ;
17
22
import { type Manifest } from '../tdf3/src/models/manifest.js' ;
18
23
import { type Payload } from '../tdf3/src/models/payload.js' ;
19
24
import {
@@ -87,6 +92,7 @@ export type CreateNanoTDFOptions = CreateOptions & {
87
92
} ;
88
93
89
94
export type CreateNanoTDFCollectionOptions = CreateNanoTDFOptions & {
95
+ platformUrl : string ;
90
96
// The maximum number of key iterations to use for a single DEK.
91
97
maxKeyIterations ?: number ;
92
98
} ;
@@ -136,6 +142,8 @@ export type CreateZTDFOptions = CreateOptions & {
136
142
export type ReadOptions = {
137
143
// ciphertext
138
144
source : Source ;
145
+ // Platform URL
146
+ platformUrl ?: string ;
139
147
// list of KASes that may be contacted for a rewrap
140
148
allowedKASEndpoints ?: string [ ] ;
141
149
// Optionally disable checking the allowlist
@@ -157,6 +165,9 @@ export type OpenTDFOptions = {
157
165
// Policy service endpoint
158
166
policyEndpoint ?: string ;
159
167
168
+ // Platform URL
169
+ platformUrl ?: string ;
170
+
160
171
// Auth provider for connections to the policy service and KASes.
161
172
authProvider : AuthProvider ;
162
173
@@ -286,6 +297,7 @@ export type TDFReader = {
286
297
// SDK for dealing with OpenTDF data and policy services.
287
298
export class OpenTDF {
288
299
// Configuration service and more is at this URL/connectRPC endpoint
300
+ readonly platformUrl : string ;
289
301
readonly policyEndpoint : string ;
290
302
readonly authProvider : AuthProvider ;
291
303
readonly dpopEnabled : boolean ;
@@ -305,11 +317,19 @@ export class OpenTDF {
305
317
disableDPoP,
306
318
policyEndpoint,
307
319
rewrapCacheOptions,
320
+ platformUrl,
308
321
} : OpenTDFOptions ) {
309
322
this . authProvider = authProvider ;
310
323
this . defaultCreateOptions = defaultCreateOptions || { } ;
311
324
this . defaultReadOptions = defaultReadOptions || { } ;
312
325
this . dpopEnabled = ! ! disableDPoP ;
326
+ if ( platformUrl ) {
327
+ this . platformUrl = platformUrl ;
328
+ } else {
329
+ console . warn (
330
+ "Warning: 'platformUrl' is required for security to ensure the SDK uses the platform-configured Key Access Server list"
331
+ ) ;
332
+ }
313
333
this . policyEndpoint = policyEndpoint || '' ;
314
334
this . rewrapCache = new RewrapCache ( rewrapCacheOptions ) ;
315
335
this . tdf3Client = new TDF3Client ( {
@@ -333,8 +353,14 @@ export class OpenTDF {
333
353
}
334
354
335
355
async createNanoTDF ( opts : CreateNanoTDFOptions ) : Promise < DecoratedStream > {
336
- opts = { ...this . defaultCreateOptions , ...opts } ;
337
- const collection = await this . createNanoTDFCollection ( opts ) ;
356
+ opts = {
357
+ ...this . defaultCreateOptions ,
358
+ ...opts ,
359
+ } ;
360
+ const collection = await this . createNanoTDFCollection ( {
361
+ ...opts ,
362
+ platformUrl : this . platformUrl ,
363
+ } ) ;
338
364
try {
339
365
return await collection . encrypt ( opts . source ) ;
340
366
} finally {
@@ -415,6 +441,9 @@ class UnknownTypeReader {
415
441
this . state = 'resolving' ;
416
442
const chunker = await fromSource ( this . opts . source ) ;
417
443
const prefix = await chunker ( 0 , 3 ) ;
444
+ if ( ! this . opts . platformUrl && this . outer . platformUrl ) {
445
+ this . opts . platformUrl = this . outer . platformUrl ;
446
+ }
418
447
if ( prefix [ 0 ] === 0x50 && prefix [ 1 ] === 0x4b ) {
419
448
this . state = 'loaded' ;
420
449
return new ZTDFReader ( this . outer . tdf3Client , this . opts , chunker ) ;
@@ -466,6 +495,13 @@ class NanoTDFReader {
466
495
readonly chunker : Chunker ,
467
496
private readonly rewrapCache : RewrapCache
468
497
) {
498
+ if (
499
+ ! this . opts . ignoreAllowlist &&
500
+ ! this . outer . platformUrl &&
501
+ ! this . opts . allowedKASEndpoints ?. length
502
+ ) {
503
+ throw new ConfigurationError ( 'platformUrl is required when allowedKasEndpoints is empty' ) ;
504
+ }
469
505
// lazily load the container
470
506
this . container = new Promise ( async ( resolve , reject ) => {
471
507
try {
@@ -493,6 +529,7 @@ class NanoTDFReader {
493
529
dpopEnabled : this . outer . dpopEnabled ,
494
530
dpopKeys : this . outer . dpopKeys ,
495
531
kasEndpoint : this . opts . allowedKASEndpoints ?. [ 0 ] || 'https://disallow.all.invalid' ,
532
+ platformUrl : this . outer . platformUrl ,
496
533
} ) ;
497
534
// TODO: The version number should be fetched from the API
498
535
const version = '0.0.1' ;
@@ -550,17 +587,29 @@ class ZTDFReader {
550
587
noVerify : noVerifyAssertions ,
551
588
wrappingKeyAlgorithm,
552
589
} = this . opts ;
553
- const allowList = new OriginAllowList (
554
- this . opts . allowedKASEndpoints ?? [ ] ,
555
- this . opts . ignoreAllowlist
556
- ) ;
590
+
591
+ if ( ! this . opts . ignoreAllowlist && ! this . opts . allowedKASEndpoints && ! this . opts . platformUrl ) {
592
+ throw new ConfigurationError ( 'platformUrl is required when allowedKasEndpoints is empty' ) ;
593
+ }
594
+
557
595
const dpopKeys = await this . client . dpopKeys ;
558
596
559
597
const { authProvider, cryptoService } = this . client ;
560
598
if ( ! authProvider ) {
561
599
throw new ConfigurationError ( 'authProvider is required' ) ;
562
600
}
563
601
602
+ let allowList : OriginAllowList | undefined ;
603
+
604
+ if ( this . opts . allowedKASEndpoints ?. length || this . opts . ignoreAllowlist ) {
605
+ allowList = new OriginAllowList (
606
+ this . opts . allowedKASEndpoints || [ ] ,
607
+ this . opts . ignoreAllowlist
608
+ ) ;
609
+ } else if ( this . opts . platformUrl ) {
610
+ allowList = await fetchKeyAccessServers ( this . opts . platformUrl , authProvider ) ;
611
+ }
612
+
564
613
const overview = await this . overview ;
565
614
const oldStream = await decryptStreamFrom (
566
615
{
@@ -646,6 +695,7 @@ class Collection {
646
695
authProvider,
647
696
kasEndpoint : opts . defaultKASEndpoint ?? 'https://disallow.all.invalid' ,
648
697
maxKeyIterations : opts . maxKeyIterations ,
698
+ platformUrl : opts . platformUrl ,
649
699
} ) ;
650
700
}
651
701
0 commit comments