@opentdf/sdk 0.3.0 → 0.3.2-beta.1

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.
Files changed (227) hide show
  1. package/dist/cjs/src/access/access-fetch.js +155 -0
  2. package/dist/cjs/src/access/access-rpc.js +131 -0
  3. package/dist/cjs/src/access.js +81 -107
  4. package/dist/cjs/src/auth/oidc.js +2 -2
  5. package/dist/cjs/src/nanotdf/Client.js +17 -13
  6. package/dist/cjs/src/nanotdf/models/Header.js +2 -2
  7. package/dist/cjs/src/nanotdf-crypto/keyAgreement.js +2 -2
  8. package/dist/cjs/src/opentdf.js +43 -9
  9. package/dist/cjs/src/platform/authorization/authorization_pb.js +138 -0
  10. package/dist/cjs/src/platform/buf/validate/validate_pb.js +410 -0
  11. package/dist/cjs/src/platform/common/common_pb.js +79 -0
  12. package/dist/cjs/src/platform/entityresolution/entity_resolution_pb.js +49 -0
  13. package/dist/cjs/src/platform/google/api/annotations_pb.js +30 -0
  14. package/dist/cjs/src/platform/google/api/http_pb.js +37 -0
  15. package/dist/cjs/src/platform/kas/kas_pb.js +96 -0
  16. package/dist/cjs/src/platform/policy/actions/actions_pb.js +70 -0
  17. package/dist/cjs/src/platform/policy/attributes/attributes_pb.js +240 -0
  18. package/dist/cjs/src/platform/policy/kasregistry/key_access_server_registry_pb.js +236 -0
  19. package/dist/cjs/src/platform/policy/keymanagement/key_management_pb.js +70 -0
  20. package/dist/cjs/src/platform/policy/namespaces/namespaces_pb.js +121 -0
  21. package/dist/cjs/src/platform/policy/objects_pb.js +395 -0
  22. package/dist/cjs/src/platform/policy/registeredresources/registered_resources_pb.js +132 -0
  23. package/dist/cjs/src/platform/policy/resourcemapping/resource_mapping_pb.js +139 -0
  24. package/dist/cjs/src/platform/policy/selectors_pb.js +67 -0
  25. package/dist/cjs/src/platform/policy/subjectmapping/subject_mapping_pb.js +146 -0
  26. package/dist/cjs/src/platform/policy/unsafe/unsafe_pb.js +124 -0
  27. package/dist/cjs/src/platform/protoc-gen-openapiv2/options/annotations_pb.js +68 -0
  28. package/dist/cjs/src/platform/protoc-gen-openapiv2/options/openapiv2_pb.js +307 -0
  29. package/dist/cjs/src/platform/wellknownconfiguration/wellknown_configuration_pb.js +33 -0
  30. package/dist/cjs/src/platform.js +124 -0
  31. package/dist/cjs/src/policy/api.js +21 -38
  32. package/dist/cjs/src/policy/attributes.js +4 -1
  33. package/dist/cjs/src/policy/granter.js +9 -9
  34. package/dist/cjs/src/utils.js +31 -1
  35. package/dist/cjs/src/version.js +2 -2
  36. package/dist/cjs/tdf3/src/assertions.js +5 -5
  37. package/dist/cjs/tdf3/src/client/index.js +24 -18
  38. package/dist/cjs/tdf3/src/tdf.js +16 -10
  39. package/dist/types/src/access/access-fetch.d.ts +21 -0
  40. package/dist/types/src/access/access-fetch.d.ts.map +1 -0
  41. package/dist/types/src/access/access-rpc.d.ts +22 -0
  42. package/dist/types/src/access/access-rpc.d.ts.map +1 -0
  43. package/dist/types/src/access.d.ts +19 -11
  44. package/dist/types/src/access.d.ts.map +1 -1
  45. package/dist/types/src/nanotdf/Client.d.ts +3 -1
  46. package/dist/types/src/nanotdf/Client.d.ts.map +1 -1
  47. package/dist/types/src/opentdf.d.ts +5 -1
  48. package/dist/types/src/opentdf.d.ts.map +1 -1
  49. package/dist/types/src/platform/authorization/authorization_pb.d.ts +609 -0
  50. package/dist/types/src/platform/authorization/authorization_pb.d.ts.map +1 -0
  51. package/dist/types/src/platform/buf/validate/validate_pb.d.ts +4466 -0
  52. package/dist/types/src/platform/buf/validate/validate_pb.d.ts.map +1 -0
  53. package/dist/types/src/platform/common/common_pb.d.ts +112 -0
  54. package/dist/types/src/platform/common/common_pb.d.ts.map +1 -0
  55. package/dist/types/src/platform/entityresolution/entity_resolution_pb.d.ts +199 -0
  56. package/dist/types/src/platform/entityresolution/entity_resolution_pb.d.ts.map +1 -0
  57. package/dist/types/src/platform/google/api/annotations_pb.d.ts +14 -0
  58. package/dist/types/src/platform/google/api/annotations_pb.d.ts.map +1 -0
  59. package/dist/types/src/platform/google/api/http_pb.d.ts +441 -0
  60. package/dist/types/src/platform/google/api/http_pb.d.ts.map +1 -0
  61. package/dist/types/src/platform/kas/kas_pb.d.ts +404 -0
  62. package/dist/types/src/platform/kas/kas_pb.d.ts.map +1 -0
  63. package/dist/types/src/platform/policy/actions/actions_pb.d.ts +265 -0
  64. package/dist/types/src/platform/policy/actions/actions_pb.d.ts.map +1 -0
  65. package/dist/types/src/platform/policy/attributes/attributes_pb.d.ts +1022 -0
  66. package/dist/types/src/platform/policy/attributes/attributes_pb.d.ts.map +1 -0
  67. package/dist/types/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts +1306 -0
  68. package/dist/types/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts.map +1 -0
  69. package/dist/types/src/platform/policy/keymanagement/key_management_pb.d.ts +269 -0
  70. package/dist/types/src/platform/policy/keymanagement/key_management_pb.d.ts.map +1 -0
  71. package/dist/types/src/platform/policy/namespaces/namespaces_pb.d.ts +448 -0
  72. package/dist/types/src/platform/policy/namespaces/namespaces_pb.d.ts.map +1 -0
  73. package/dist/types/src/platform/policy/objects_pb.d.ts +1112 -0
  74. package/dist/types/src/platform/policy/objects_pb.d.ts.map +1 -0
  75. package/dist/types/src/platform/policy/registeredresources/registered_resources_pb.d.ts +539 -0
  76. package/dist/types/src/platform/policy/registeredresources/registered_resources_pb.d.ts.map +1 -0
  77. package/dist/types/src/platform/policy/resourcemapping/resource_mapping_pb.d.ts +558 -0
  78. package/dist/types/src/platform/policy/resourcemapping/resource_mapping_pb.d.ts.map +1 -0
  79. package/dist/types/src/platform/policy/selectors_pb.d.ts +221 -0
  80. package/dist/types/src/platform/policy/selectors_pb.d.ts.map +1 -0
  81. package/dist/types/src/platform/policy/subjectmapping/subject_mapping_pb.d.ts +582 -0
  82. package/dist/types/src/platform/policy/subjectmapping/subject_mapping_pb.d.ts.map +1 -0
  83. package/dist/types/src/platform/policy/unsafe/unsafe_pb.d.ts +513 -0
  84. package/dist/types/src/platform/policy/unsafe/unsafe_pb.d.ts.map +1 -0
  85. package/dist/types/src/platform/protoc-gen-openapiv2/options/annotations_pb.d.ts +62 -0
  86. package/dist/types/src/platform/protoc-gen-openapiv2/options/annotations_pb.d.ts.map +1 -0
  87. package/dist/types/src/platform/protoc-gen-openapiv2/options/openapiv2_pb.d.ts +1441 -0
  88. package/dist/types/src/platform/protoc-gen-openapiv2/options/openapiv2_pb.d.ts.map +1 -0
  89. package/dist/types/src/platform/wellknownconfiguration/wellknown_configuration_pb.d.ts +59 -0
  90. package/dist/types/src/platform/wellknownconfiguration/wellknown_configuration_pb.d.ts.map +1 -0
  91. package/dist/types/src/platform.d.ts +49 -0
  92. package/dist/types/src/platform.d.ts.map +1 -0
  93. package/dist/types/src/policy/api.d.ts +1 -1
  94. package/dist/types/src/policy/api.d.ts.map +1 -1
  95. package/dist/types/src/policy/attributes.d.ts +10 -87
  96. package/dist/types/src/policy/attributes.d.ts.map +1 -1
  97. package/dist/types/src/policy/granter.d.ts.map +1 -1
  98. package/dist/types/src/utils.d.ts +10 -0
  99. package/dist/types/src/utils.d.ts.map +1 -1
  100. package/dist/types/src/version.d.ts +1 -1
  101. package/dist/types/tdf3/src/assertions.d.ts +1 -1
  102. package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
  103. package/dist/types/tdf3/src/client/index.d.ts +8 -3
  104. package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
  105. package/dist/types/tdf3/src/models/manifest.d.ts +1 -1
  106. package/dist/types/tdf3/src/models/manifest.d.ts.map +1 -1
  107. package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
  108. package/dist/web/src/access/access-fetch.js +150 -0
  109. package/dist/web/src/access/access-rpc.js +125 -0
  110. package/dist/web/src/access.js +82 -110
  111. package/dist/web/src/auth/oidc.js +2 -2
  112. package/dist/web/src/nanotdf/Client.js +18 -14
  113. package/dist/web/src/nanotdf/models/Header.js +2 -2
  114. package/dist/web/src/nanotdf-crypto/keyAgreement.js +2 -2
  115. package/dist/web/src/opentdf.js +44 -10
  116. package/dist/web/src/platform/authorization/authorization_pb.js +135 -0
  117. package/dist/web/src/platform/buf/validate/validate_pb.js +407 -0
  118. package/dist/web/src/platform/common/common_pb.js +76 -0
  119. package/dist/web/src/platform/entityresolution/entity_resolution_pb.js +46 -0
  120. package/dist/web/src/platform/google/api/annotations_pb.js +27 -0
  121. package/dist/web/src/platform/google/api/http_pb.js +34 -0
  122. package/dist/web/src/platform/kas/kas_pb.js +93 -0
  123. package/dist/web/src/platform/policy/actions/actions_pb.js +67 -0
  124. package/dist/web/src/platform/policy/attributes/attributes_pb.js +237 -0
  125. package/dist/web/src/platform/policy/kasregistry/key_access_server_registry_pb.js +233 -0
  126. package/dist/web/src/platform/policy/keymanagement/key_management_pb.js +67 -0
  127. package/dist/web/src/platform/policy/namespaces/namespaces_pb.js +118 -0
  128. package/dist/web/src/platform/policy/objects_pb.js +392 -0
  129. package/dist/web/src/platform/policy/registeredresources/registered_resources_pb.js +129 -0
  130. package/dist/web/src/platform/policy/resourcemapping/resource_mapping_pb.js +136 -0
  131. package/dist/web/src/platform/policy/selectors_pb.js +64 -0
  132. package/dist/web/src/platform/policy/subjectmapping/subject_mapping_pb.js +143 -0
  133. package/dist/web/src/platform/policy/unsafe/unsafe_pb.js +121 -0
  134. package/dist/web/src/platform/protoc-gen-openapiv2/options/annotations_pb.js +65 -0
  135. package/dist/web/src/platform/protoc-gen-openapiv2/options/openapiv2_pb.js +304 -0
  136. package/dist/web/src/platform/wellknownconfiguration/wellknown_configuration_pb.js +30 -0
  137. package/dist/web/src/platform.js +87 -0
  138. package/dist/web/src/policy/api.js +23 -40
  139. package/dist/web/src/policy/attributes.js +3 -2
  140. package/dist/web/src/policy/granter.js +9 -9
  141. package/dist/web/src/utils.js +29 -1
  142. package/dist/web/src/version.js +2 -2
  143. package/dist/web/tdf3/src/assertions.js +5 -5
  144. package/dist/web/tdf3/src/client/index.js +26 -20
  145. package/dist/web/tdf3/src/tdf.js +16 -10
  146. package/package.json +17 -1
  147. package/src/access/access-fetch.ts +202 -0
  148. package/src/access/access-rpc.ts +175 -0
  149. package/src/access.ts +113 -138
  150. package/src/auth/oidc.ts +1 -1
  151. package/src/nanotdf/Client.ts +28 -18
  152. package/src/nanotdf/models/Header.ts +1 -1
  153. package/src/nanotdf-crypto/keyAgreement.ts +1 -1
  154. package/src/opentdf.ts +67 -11
  155. package/src/platform/authorization/authorization_pb.ts +689 -0
  156. package/src/platform/buf/validate/validate_pb.ts +4626 -0
  157. package/src/platform/common/common_pb.ts +135 -0
  158. package/src/platform/entityresolution/entity_resolution_pb.ts +233 -0
  159. package/src/platform/google/api/annotations_pb.ts +39 -0
  160. package/src/platform/google/api/http_pb.ts +474 -0
  161. package/src/platform/kas/kas_pb.ts +484 -0
  162. package/src/platform/policy/actions/actions_pb.ts +312 -0
  163. package/src/platform/policy/attributes/attributes_pb.ts +1181 -0
  164. package/src/platform/policy/kasregistry/key_access_server_registry_pb.ts +1482 -0
  165. package/src/platform/policy/keymanagement/key_management_pb.ts +316 -0
  166. package/src/platform/policy/namespaces/namespaces_pb.ts +528 -0
  167. package/src/platform/policy/objects_pb.ts +1319 -0
  168. package/src/platform/policy/registeredresources/registered_resources_pb.ts +623 -0
  169. package/src/platform/policy/resourcemapping/resource_mapping_pb.ts +658 -0
  170. package/src/platform/policy/selectors_pb.ts +277 -0
  171. package/src/platform/policy/subjectmapping/subject_mapping_pb.ts +687 -0
  172. package/src/platform/policy/unsafe/unsafe_pb.ts +593 -0
  173. package/src/platform/protoc-gen-openapiv2/options/annotations_pb.ts +83 -0
  174. package/src/platform/protoc-gen-openapiv2/options/openapiv2_pb.ts +1615 -0
  175. package/src/platform/wellknownconfiguration/wellknown_configuration_pb.ts +78 -0
  176. package/src/platform.ts +122 -0
  177. package/src/policy/api.ts +29 -42
  178. package/src/policy/attributes.ts +12 -108
  179. package/src/policy/granter.ts +7 -8
  180. package/src/utils.ts +30 -0
  181. package/src/version.ts +1 -1
  182. package/tdf3/src/assertions.ts +4 -4
  183. package/tdf3/src/client/index.ts +42 -19
  184. package/tdf3/src/models/manifest.ts +2 -1
  185. package/tdf3/src/tdf.ts +25 -16
  186. package/src/platform/authorization/authorization_connect.d.ts +0 -44
  187. package/src/platform/authorization/authorization_connect.js +0 -44
  188. package/src/platform/authorization/authorization_pb.d.ts +0 -707
  189. package/src/platform/authorization/authorization_pb.js +0 -372
  190. package/src/platform/common/common_pb.d.ts +0 -129
  191. package/src/platform/common/common_pb.js +0 -58
  192. package/src/platform/entityresolution/entity_resolution_connect.d.ts +0 -35
  193. package/src/platform/entityresolution/entity_resolution_connect.js +0 -35
  194. package/src/platform/entityresolution/entity_resolution_pb.d.ts +0 -242
  195. package/src/platform/entityresolution/entity_resolution_pb.js +0 -139
  196. package/src/platform/kas/kas_connect.d.ts +0 -59
  197. package/src/platform/kas/kas_connect.js +0 -59
  198. package/src/platform/kas/kas_pb.d.ts +0 -200
  199. package/src/platform/kas/kas_pb.js +0 -84
  200. package/src/platform/policy/attributes/attributes_connect.d.ts +0 -168
  201. package/src/platform/policy/attributes/attributes_connect.js +0 -168
  202. package/src/platform/policy/attributes/attributes_pb.d.ts +0 -929
  203. package/src/platform/policy/attributes/attributes_pb.js +0 -363
  204. package/src/platform/policy/kasregistry/key_access_server_registry_connect.d.ts +0 -62
  205. package/src/platform/policy/kasregistry/key_access_server_registry_connect.js +0 -62
  206. package/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts +0 -283
  207. package/src/platform/policy/kasregistry/key_access_server_registry_pb.js +0 -113
  208. package/src/platform/policy/namespaces/namespaces_connect.d.ts +0 -62
  209. package/src/platform/policy/namespaces/namespaces_connect.js +0 -62
  210. package/src/platform/policy/namespaces/namespaces_pb.d.ts +0 -270
  211. package/src/platform/policy/namespaces/namespaces_pb.js +0 -110
  212. package/src/platform/policy/objects_pb.d.ts +0 -725
  213. package/src/platform/policy/objects_pb.js +0 -288
  214. package/src/platform/policy/resourcemapping/resource_mapping_connect.d.ts +0 -259
  215. package/src/platform/policy/resourcemapping/resource_mapping_connect.js +0 -259
  216. package/src/platform/policy/resourcemapping/resource_mapping_pb.d.ts +0 -314
  217. package/src/platform/policy/resourcemapping/resource_mapping_pb.js +0 -142
  218. package/src/platform/policy/selectors_pb.d.ts +0 -269
  219. package/src/platform/policy/selectors_pb.js +0 -110
  220. package/src/platform/policy/subjectmapping/subject_mapping_connect.d.ts +0 -118
  221. package/src/platform/policy/subjectmapping/subject_mapping_connect.js +0 -118
  222. package/src/platform/policy/subjectmapping/subject_mapping_pb.d.ts +0 -672
  223. package/src/platform/policy/subjectmapping/subject_mapping_pb.js +0 -260
  224. package/src/platform/wellknownconfiguration/wellknown_configuration_connect.d.ts +0 -26
  225. package/src/platform/wellknownconfiguration/wellknown_configuration_connect.js +0 -26
  226. package/src/platform/wellknownconfiguration/wellknown_configuration_pb.d.ts +0 -75
  227. package/src/platform/wellknownconfiguration/wellknown_configuration_pb.js +0 -35
package/src/access.ts CHANGED
@@ -1,25 +1,22 @@
1
1
  import { type AuthProvider } from './auth/auth.js';
2
+ import { ServiceError } from './errors.js';
3
+ import { RewrapResponse } from './platform/kas/kas_pb.js';
4
+ import { getPlatformUrlFromKasEndpoint, validateSecureUrl } from './utils.js';
5
+
2
6
  import {
3
- ConfigurationError,
4
- InvalidFileError,
5
- NetworkError,
6
- PermissionDeniedError,
7
- ServiceError,
8
- UnauthenticatedError,
9
- } from './errors.js';
10
- import { pemToCryptoPublicKey, validateSecureUrl } from './utils.js';
7
+ fetchKasBasePubKey,
8
+ fetchKeyAccessServers as fetchKeyAccessServersRpc,
9
+ } from './access/access-rpc.js';
10
+ import { fetchKeyAccessServers as fetchKeyAccessServersLegacy } from './access/access-fetch.js';
11
+ import { fetchWrappedKey as fetchWrappedKeysRpc } from './access/access-rpc.js';
12
+ import { fetchWrappedKey as fetchWrappedKeysLegacy } from './access/access-fetch.js';
13
+ import { fetchKasPubKey as fetchKasPubKeyRpc } from './access/access-rpc.js';
14
+ import { fetchKasPubKey as fetchKasPubKeyLegacy } from './access/access-fetch.js';
11
15
 
12
16
  export type RewrapRequest = {
13
17
  signedRequestToken: string;
14
18
  };
15
19
 
16
- export type RewrapResponse = {
17
- metadata: Record<string, unknown>;
18
- entityWrappedKey: string;
19
- sessionPublicKey: string;
20
- schemaVersion: string;
21
- };
22
-
23
20
  /**
24
21
  * Get a rewrapped access key to the document, if possible
25
22
  * @param url Key access server rewrap endpoint
@@ -29,85 +26,60 @@ export type RewrapResponse = {
29
26
  */
30
27
  export async function fetchWrappedKey(
31
28
  url: string,
32
- requestBody: RewrapRequest,
33
- authProvider: AuthProvider,
34
- clientVersion: string
29
+ signedRequestToken: string,
30
+ authProvider: AuthProvider
35
31
  ): Promise<RewrapResponse> {
36
- const req = await authProvider.withCreds({
37
- url,
38
- method: 'POST',
39
- headers: {
40
- 'Content-Type': 'application/json',
41
- },
42
- body: JSON.stringify(requestBody),
43
- });
44
-
45
- let response: Response;
46
-
47
- try {
48
- response = await fetch(req.url, {
49
- method: req.method,
50
- mode: 'cors', // no-cors, *cors, same-origin
51
- cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
52
- credentials: 'same-origin', // include, *same-origin, omit
53
- headers: req.headers,
54
- redirect: 'follow', // manual, *follow, error
55
- referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
56
- body: req.body as BodyInit,
57
- });
58
- } catch (e) {
59
- throw new NetworkError(`unable to fetch wrapped key from [${url}]`, e);
60
- }
61
-
62
- if (!response.ok) {
63
- switch (response.status) {
64
- case 400:
65
- throw new InvalidFileError(
66
- `400 for [${req.url}]: rewrap bad request [${await response.text()}]`
67
- );
68
- case 401:
69
- throw new UnauthenticatedError(`401 for [${req.url}]; rewrap auth failure`);
70
- case 403:
71
- throw new PermissionDeniedError(`403 for [${req.url}]; rewrap permission denied`);
72
- default:
73
- if (response.status >= 500) {
74
- throw new ServiceError(
75
- `${response.status} for [${req.url}]: rewrap failure due to service error [${await response.text()}]`
76
- );
77
- }
78
- throw new NetworkError(
79
- `${req.method} ${req.url} => ${response.status} ${response.statusText}`
80
- );
81
- }
82
- }
83
-
84
- return response.json();
32
+ const platformUrl = getPlatformUrlFromKasEndpoint(url);
33
+
34
+ return await tryPromisesUntilFirstSuccess(
35
+ () => fetchWrappedKeysRpc(platformUrl, signedRequestToken, authProvider),
36
+ () =>
37
+ fetchWrappedKeysLegacy(
38
+ url,
39
+ { signedRequestToken },
40
+ authProvider
41
+ ) as unknown as Promise<RewrapResponse>
42
+ );
85
43
  }
86
44
 
87
- export type KasPublicKeyAlgorithm = 'ec:secp256r1' | 'rsa:2048';
45
+ export type KasPublicKeyAlgorithm =
46
+ | 'ec:secp256r1'
47
+ | 'ec:secp384r1'
48
+ | 'ec:secp521r1'
49
+ | 'rsa:2048'
50
+ | 'rsa:4096';
88
51
 
89
52
  export const isPublicKeyAlgorithm = (a: string): a is KasPublicKeyAlgorithm => {
90
53
  return a === 'ec:secp256r1' || a === 'rsa:2048';
91
54
  };
92
55
 
93
- export const keyAlgorithmToPublicKeyAlgorithm = (a: KeyAlgorithm): KasPublicKeyAlgorithm => {
56
+ export const keyAlgorithmToPublicKeyAlgorithm = (k: CryptoKey): KasPublicKeyAlgorithm => {
57
+ const a = k.algorithm;
94
58
  if (a.name === 'ECDSA' || a.name === 'ECDH') {
95
59
  const eca = a as EcKeyAlgorithm;
96
- if (eca.namedCurve === 'P-256') {
97
- return 'ec:secp256r1';
60
+ switch (eca.namedCurve) {
61
+ case 'P-256':
62
+ return 'ec:secp256r1';
63
+ case 'P-384':
64
+ return 'ec:secp384r1';
65
+ case 'P-521':
66
+ return 'ec:secp521r1';
67
+ default:
68
+ throw new Error(`unsupported EC curve: ${eca.namedCurve}`);
98
69
  }
99
- throw new Error(`unsupported EC curve: ${eca.namedCurve}`);
100
70
  }
101
- if (a.name === 'RSA-OAEP') {
71
+ if (a.name === 'RSA-OAEP' || a.name === 'RSASSA-PKCS1-v1_5') {
102
72
  const rsaa = a as RsaHashedKeyAlgorithm;
103
- if (rsaa.modulusLength === 2048) {
104
- // if (rsaa.hash.name !== 'RSASSA-PKCS1-v1_5') {
105
- // throw new Error(`unsupported RSA hash: ${rsaa.hash.name}`);
106
- // }
107
- if (rsaa.publicExponent.toString() !== '1,0,1') {
108
- throw new Error(`unsupported RSA public exponent: ${rsaa.publicExponent}`);
109
- }
110
- return 'rsa:2048';
73
+ if (rsaa.publicExponent.toString() !== '1,0,1') {
74
+ throw new Error(`unsupported RSA public exponent: ${rsaa.publicExponent}`);
75
+ }
76
+ switch (rsaa.modulusLength) {
77
+ case 2048:
78
+ return 'rsa:2048';
79
+ case 4096:
80
+ return 'rsa:4096';
81
+ default:
82
+ throw new Error(`unsupported RSA modulus length: ${rsaa.modulusLength}`);
111
83
  }
112
84
  }
113
85
  throw new Error(`unsupported key algorithm: ${a.name}`);
@@ -119,6 +91,14 @@ export const publicKeyAlgorithmToJwa = (a: KasPublicKeyAlgorithm): string => {
119
91
  return 'ES256';
120
92
  case 'rsa:2048':
121
93
  return 'RS256';
94
+ case 'rsa:4096':
95
+ return 'RS512';
96
+ case 'ec:secp384r1':
97
+ return 'ES384';
98
+ case 'ec:secp521r1':
99
+ return 'ES512';
100
+ default:
101
+ throw new Error(`unsupported public key algorithm: ${a}`);
122
102
  }
123
103
  };
124
104
 
@@ -145,7 +125,7 @@ export type KasPublicKeyInfo = {
145
125
  key: Promise<CryptoKey>;
146
126
  };
147
127
 
148
- async function noteInvalidPublicKey(url: URL, r: Promise<CryptoKey>): Promise<CryptoKey> {
128
+ export async function noteInvalidPublicKey(url: URL, r: Promise<CryptoKey>): Promise<CryptoKey> {
149
129
  try {
150
130
  return await r;
151
131
  } catch (e) {
@@ -156,76 +136,49 @@ async function noteInvalidPublicKey(url: URL, r: Promise<CryptoKey>): Promise<Cr
156
136
  }
157
137
  }
158
138
 
139
+ export async function fetchKeyAccessServers(
140
+ platformUrl: string,
141
+ authProvider: AuthProvider
142
+ ): Promise<OriginAllowList> {
143
+ return await tryPromisesUntilFirstSuccess(
144
+ () => fetchKeyAccessServersRpc(platformUrl, authProvider),
145
+ () => fetchKeyAccessServersLegacy(platformUrl, authProvider)
146
+ );
147
+ }
148
+
159
149
  /**
160
- * If we have KAS url but not public key we can fetch it from KAS, fetching
161
- * the value from `${kas}/kas_public_key`.
150
+ * Fetch the EC (secp256r1) public key for a KAS endpoint.
151
+ * @param kasEndpoint The KAS endpoint URL.
152
+ * @returns The public key information for the KAS endpoint.
162
153
  */
163
154
  export async function fetchECKasPubKey(kasEndpoint: string): Promise<KasPublicKeyInfo> {
164
155
  return fetchKasPubKey(kasEndpoint, 'ec:secp256r1');
165
156
  }
166
157
 
158
+ /**
159
+ * Fetch the public key for a KAS endpoint.
160
+ * This function will first try to fetch the base public key,
161
+ * then it will try to fetch the public key using the RPC method,
162
+ * and finally it will try to fetch the public key using the legacy method.
163
+ * If all attempts fail, it will return the error from RPC Public Key fetch.
164
+ * @param kasEndpoint The KAS endpoint URL.
165
+ * @param algorithm Optional algorithm to fetch the public key for.
166
+ * @returns The public key information.
167
+ */
167
168
  export async function fetchKasPubKey(
168
169
  kasEndpoint: string,
169
170
  algorithm?: KasPublicKeyAlgorithm
170
171
  ): Promise<KasPublicKeyInfo> {
171
- if (!kasEndpoint) {
172
- throw new ConfigurationError('KAS definition not found');
173
- }
174
- // Logs insecure KAS. Secure is enforced in constructor
175
- validateSecureUrl(kasEndpoint);
176
-
177
- // Parse kasEndpoint to URL, then append to its path and update its query parameters
178
- let pkUrlV2: URL;
179
172
  try {
180
- pkUrlV2 = new URL(kasEndpoint);
173
+ return await fetchKasBasePubKey(kasEndpoint);
181
174
  } catch (e) {
182
- throw new ConfigurationError(`KAS definition invalid: [${kasEndpoint}]`, e);
183
- }
184
- if (!pkUrlV2.pathname.endsWith('kas_public_key')) {
185
- if (!pkUrlV2.pathname.endsWith('/')) {
186
- pkUrlV2.pathname += '/';
187
- }
188
- pkUrlV2.pathname += 'v2/kas_public_key';
189
- }
190
- pkUrlV2.searchParams.set('algorithm', algorithm || 'rsa:2048');
191
- if (!pkUrlV2.searchParams.get('v')) {
192
- pkUrlV2.searchParams.set('v', '2');
175
+ console.log(e);
193
176
  }
194
177
 
195
- let kasPubKeyResponseV2: Response;
196
- try {
197
- kasPubKeyResponseV2 = await fetch(pkUrlV2);
198
- } catch (e) {
199
- throw new NetworkError(`unable to fetch public key from [${pkUrlV2}]`, e);
200
- }
201
- if (!kasPubKeyResponseV2.ok) {
202
- switch (kasPubKeyResponseV2.status) {
203
- case 404:
204
- throw new ConfigurationError(`404 for [${pkUrlV2}]`);
205
- case 401:
206
- throw new UnauthenticatedError(`401 for [${pkUrlV2}]`);
207
- case 403:
208
- throw new PermissionDeniedError(`403 for [${pkUrlV2}]`);
209
- default:
210
- throw new NetworkError(
211
- `${pkUrlV2} => ${kasPubKeyResponseV2.status} ${kasPubKeyResponseV2.statusText}`
212
- );
213
- }
214
- }
215
- const jsonContent = await kasPubKeyResponseV2.json();
216
- const { publicKey, kid }: KasPublicKeyInfo = jsonContent;
217
- if (!publicKey) {
218
- throw new NetworkError(
219
- `invalid response from public key endpoint [${JSON.stringify(jsonContent)}]`
220
- );
221
- }
222
- return {
223
- key: noteInvalidPublicKey(pkUrlV2, pemToCryptoPublicKey(publicKey)),
224
- publicKey,
225
- url: kasEndpoint,
226
- algorithm: algorithm || 'rsa:2048',
227
- ...(kid && { kid }),
228
- };
178
+ return await tryPromisesUntilFirstSuccess(
179
+ () => fetchKasPubKeyRpc(kasEndpoint, algorithm),
180
+ () => fetchKasPubKeyLegacy(kasEndpoint, algorithm)
181
+ );
229
182
  }
230
183
 
231
184
  const origin = (u: string): string => {
@@ -252,3 +205,25 @@ export class OriginAllowList {
252
205
  return this.origins.includes(origin(url));
253
206
  }
254
207
  }
208
+
209
+ /**
210
+ * Tries two promise-returning functions in order and returns the first successful result.
211
+ * If both fail, throws the error from the second.
212
+ * @param first First function returning a promise to try.
213
+ * @param second Second function returning a promise to try if the first fails.
214
+ */
215
+ async function tryPromisesUntilFirstSuccess<T>(
216
+ first: () => Promise<T>,
217
+ second: () => Promise<T>
218
+ ): Promise<T> {
219
+ try {
220
+ return await first();
221
+ } catch (e1) {
222
+ console.info('v2 request error', e1);
223
+ try {
224
+ return await second();
225
+ } catch (err) {
226
+ throw err;
227
+ }
228
+ }
229
+ }
package/src/auth/oidc.ts CHANGED
@@ -222,7 +222,7 @@ export class AccessToken {
222
222
  return this.data.access_token;
223
223
  } catch (e) {
224
224
  console.log('access_token fails on user_info endpoint; attempting to renew', e);
225
- if (this.data.refresh_token) {
225
+ if (this.data?.refresh_token) {
226
226
  // Prefer the latest refresh_token if present over creds passed in
227
227
  // to constructor
228
228
  this.config = {
@@ -2,7 +2,12 @@ import * as base64 from '../encodings/base64.js';
2
2
  import { generateKeyPair, keyAgreement } from '../nanotdf-crypto/index.js';
3
3
  import getHkdfSalt from './helpers/getHkdfSalt.js';
4
4
  import DefaultParams from './models/DefaultParams.js';
5
- import { fetchWrappedKey, KasPublicKeyInfo, OriginAllowList } from '../access.js';
5
+ import {
6
+ fetchKeyAccessServers,
7
+ fetchWrappedKey,
8
+ KasPublicKeyInfo,
9
+ OriginAllowList,
10
+ } from '../access.js';
6
11
  import { AuthProvider, isAuthProvider, reqSignature } from '../auth/providers.js';
7
12
  import { ConfigurationError, DecryptError, TdfError, UnsafeUrlError } from '../errors.js';
8
13
  import { cryptoPublicToPem, pemToCryptoPublicKey, validateSecureUrl } from '../utils.js';
@@ -15,6 +20,7 @@ export interface ClientConfig {
15
20
  dpopKeys?: Promise<CryptoKeyPair>;
16
21
  ephemeralKeyPair?: Promise<CryptoKeyPair>;
17
22
  kasEndpoint: string;
23
+ platformUrl: string;
18
24
  }
19
25
 
20
26
  function toJWSAlg(c: CryptoKey): string {
@@ -99,12 +105,13 @@ export default class Client {
99
105
  static readonly INITIAL_RELEASE_IV_SIZE = 3;
100
106
  static readonly IV_SIZE = 12;
101
107
 
102
- allowedKases: OriginAllowList;
108
+ allowedKases?: OriginAllowList;
103
109
  /*
104
110
  These variables are expected to be either assigned during initialization or within the methods.
105
111
  This is needed as the flow is very specific. Errors should be thrown if the necessary step is not completed.
106
112
  */
107
113
  protected kasUrl: string;
114
+ readonly platformUrl: string;
108
115
  kasPubKey?: KasPublicKeyInfo;
109
116
  readonly authProvider: AuthProvider;
110
117
  readonly dpopEnabled: boolean;
@@ -150,7 +157,6 @@ export default class Client {
150
157
  // TODO Disallow http KAS. For now just log as error
151
158
  validateSecureUrl(kasUrl);
152
159
  this.kasUrl = kasUrl;
153
- this.allowedKases = new OriginAllowList([kasUrl]);
154
160
  this.dpopEnabled = dpopEnabled;
155
161
 
156
162
  if (ephemeralKeyPair) {
@@ -168,12 +174,16 @@ export default class Client {
168
174
  dpopKeys,
169
175
  ephemeralKeyPair,
170
176
  kasEndpoint,
177
+ platformUrl,
171
178
  } = optsOrOldAuthProvider;
172
179
  this.authProvider = enwrapAuthProvider(authProvider);
173
180
  // TODO Disallow http KAS. For now just log as error
174
181
  validateSecureUrl(kasEndpoint);
175
182
  this.kasUrl = kasEndpoint;
176
- this.allowedKases = new OriginAllowList(allowedKases || [kasEndpoint], !!ignoreAllowList);
183
+ this.platformUrl = platformUrl;
184
+ if (allowedKases?.length || ignoreAllowList) {
185
+ this.allowedKases = new OriginAllowList(allowedKases || [], ignoreAllowList);
186
+ }
177
187
  this.dpopEnabled = !!dpopEnabled;
178
188
  if (dpopKeys) {
179
189
  this.requestSignerKeyPair = dpopKeys;
@@ -214,8 +224,14 @@ export default class Client {
214
224
  magicNumberVersion: ArrayBufferLike,
215
225
  clientVersion: string
216
226
  ): Promise<CryptoKey> {
217
- if (!this.allowedKases.allows(kasRewrapUrl)) {
218
- throw new UnsafeUrlError(`request URL ∉ ${this.allowedKases.origins};`, kasRewrapUrl);
227
+ let allowedKases = this.allowedKases;
228
+
229
+ if (!allowedKases) {
230
+ allowedKases = await fetchKeyAccessServers(this.platformUrl, this.authProvider);
231
+ }
232
+
233
+ if (!allowedKases.allows(kasRewrapUrl)) {
234
+ throw new UnsafeUrlError(`request URL ∉ ${allowedKases.origins};`, kasRewrapUrl);
219
235
  }
220
236
 
221
237
  const ephemeralKeyPair = await this.ephemeralKeyPair;
@@ -243,22 +259,16 @@ export default class Client {
243
259
  });
244
260
 
245
261
  const jwtPayload = { requestBody: requestBodyStr };
246
- const requestBody = {
247
- signedRequestToken: await reqSignature(jwtPayload, requestSignerKeyPair.privateKey, {
248
- alg: toJWSAlg(requestSignerKeyPair.publicKey),
249
- }),
250
- };
262
+
263
+ const signedRequestToken = await reqSignature(jwtPayload, requestSignerKeyPair.privateKey, {
264
+ alg: toJWSAlg(requestSignerKeyPair.publicKey),
265
+ });
251
266
 
252
267
  // Wrapped
253
- const wrappedKey = await fetchWrappedKey(
254
- kasRewrapUrl,
255
- requestBody,
256
- this.authProvider,
257
- clientVersion
258
- );
268
+ const wrappedKey = await fetchWrappedKey(kasRewrapUrl, signedRequestToken, this.authProvider);
259
269
 
260
270
  // Extract the iv and ciphertext
261
- const entityWrappedKey = new Uint8Array(base64.decodeArrayBuffer(wrappedKey.entityWrappedKey));
271
+ const entityWrappedKey = wrappedKey.entityWrappedKey;
262
272
  const ivLength =
263
273
  clientVersion == Client.SDK_INITIAL_RELEASE ? Client.INITIAL_RELEASE_IV_SIZE : Client.IV_SIZE;
264
274
  const iv = entityWrappedKey.subarray(0, ivLength);
@@ -314,7 +314,7 @@ export default class Header {
314
314
  */
315
315
  getKasRewrapUrl(): string {
316
316
  try {
317
- return `${rstrip(this.kas.url, '/')}/v2/rewrap`;
317
+ return `${rstrip(this.kas.url, '/')}`;
318
318
  } catch (e) {
319
319
  throw new ConfigurationError(`cannot construct KAS Rewrap URL: ${e.message}`);
320
320
  }
@@ -71,7 +71,7 @@ export async function keyAgreement(
71
71
  }
72
72
  ): Promise<CryptoKey> {
73
73
  for (const k of [privateKey, publicKey]) {
74
- const mechanism = keyAlgorithmToPublicKeyAlgorithm(k.algorithm);
74
+ const mechanism = keyAlgorithmToPublicKeyAlgorithm(k);
75
75
  if (mechanism !== 'ec:secp256r1') {
76
76
  throw new ConfigurationError(
77
77
  `${k.type} CryptoKey is expected to be of type ECDSA or ECDH, not [${k.algorithm?.name}]`
package/src/opentdf.ts CHANGED
@@ -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,17 +317,25 @@ 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({
316
336
  authProvider,
317
337
  dpopKeys,
318
- kasEndpoint: 'https://disallow.all.invalid',
338
+ kasEndpoint: this.platformUrl || 'https://disallow.all.invalid',
319
339
  policyEndpoint,
320
340
  });
321
341
  this.dpopKeys =
@@ -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 {
@@ -369,7 +395,7 @@ export class OpenTDF {
369
395
  splitPlan: opts.splitPlan,
370
396
  windowSize: opts.windowSize,
371
397
  wrappingKeyAlgorithm: opts.wrappingKeyAlgorithm,
372
- tdfSpecVersion: opts.tdfSpecVersion ?? '4.3.0',
398
+ tdfSpecVersion: opts.tdfSpecVersion,
373
399
  });
374
400
  const stream: DecoratedStream = oldStream.stream;
375
401
  stream.manifest = Promise.resolve(oldStream.manifest);
@@ -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.opts.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 {
@@ -486,13 +522,17 @@ class NanoTDFReader {
486
522
  r.header = nanotdf.header;
487
523
  return r;
488
524
  }
525
+ const platformUrl = this.opts.platformUrl || this.outer.platformUrl;
526
+ const kasEndpoint =
527
+ this.opts.allowedKASEndpoints?.[0] || platformUrl || 'https://disallow.all.invalid';
489
528
  const nc = new Client({
490
529
  allowedKases: this.opts.allowedKASEndpoints,
491
530
  authProvider: this.outer.authProvider,
492
531
  ignoreAllowList: this.opts.ignoreAllowlist,
493
532
  dpopEnabled: this.outer.dpopEnabled,
494
533
  dpopKeys: this.outer.dpopKeys,
495
- kasEndpoint: this.opts.allowedKASEndpoints?.[0] || 'https://disallow.all.invalid',
534
+ kasEndpoint,
535
+ platformUrl,
496
536
  });
497
537
  // TODO: The version number should be fetched from the API
498
538
  const version = '0.0.1';
@@ -550,10 +590,11 @@ class ZTDFReader {
550
590
  noVerify: noVerifyAssertions,
551
591
  wrappingKeyAlgorithm,
552
592
  } = this.opts;
553
- const allowList = new OriginAllowList(
554
- this.opts.allowedKASEndpoints ?? [],
555
- this.opts.ignoreAllowlist
556
- );
593
+
594
+ if (!this.opts.ignoreAllowlist && !this.opts.allowedKASEndpoints && !this.opts.platformUrl) {
595
+ throw new ConfigurationError('platformUrl is required when allowedKasEndpoints is empty');
596
+ }
597
+
557
598
  const dpopKeys = await this.client.dpopKeys;
558
599
 
559
600
  const { authProvider, cryptoService } = this.client;
@@ -561,6 +602,17 @@ class ZTDFReader {
561
602
  throw new ConfigurationError('authProvider is required');
562
603
  }
563
604
 
605
+ let allowList: OriginAllowList | undefined;
606
+
607
+ if (this.opts.allowedKASEndpoints?.length || this.opts.ignoreAllowlist) {
608
+ allowList = new OriginAllowList(
609
+ this.opts.allowedKASEndpoints || [],
610
+ this.opts.ignoreAllowlist
611
+ );
612
+ } else if (this.opts.platformUrl) {
613
+ allowList = await fetchKeyAccessServers(this.opts.platformUrl, authProvider);
614
+ }
615
+
564
616
  const overview = await this.overview;
565
617
  const oldStream = await decryptStreamFrom(
566
618
  {
@@ -642,10 +694,14 @@ class Collection {
642
694
  break;
643
695
  }
644
696
 
697
+ const kasEndpoint =
698
+ opts.defaultKASEndpoint || opts.platformUrl || 'https://disallow.all.invalid';
699
+
645
700
  this.client = new NanoTDFDatasetClient({
646
701
  authProvider,
647
- kasEndpoint: opts.defaultKASEndpoint ?? 'https://disallow.all.invalid',
702
+ kasEndpoint: kasEndpoint,
648
703
  maxKeyIterations: opts.maxKeyIterations,
704
+ platformUrl: opts.platformUrl,
649
705
  });
650
706
  }
651
707