@opentdf/sdk 0.9.0-beta.92 → 0.9.0-beta.94

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 (187) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/src/access/access-fetch.js +1 -2
  3. package/dist/cjs/src/access/access-rpc.js +1 -3
  4. package/dist/cjs/src/access.js +1 -14
  5. package/dist/cjs/src/auth/auth.js +13 -10
  6. package/dist/cjs/src/auth/dpop.js +121 -0
  7. package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +37 -3
  8. package/dist/cjs/src/auth/oidc-externaljwt-provider.js +37 -3
  9. package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +37 -3
  10. package/dist/cjs/src/auth/oidc.js +10 -8
  11. package/dist/cjs/src/auth/providers.js +35 -12
  12. package/dist/cjs/src/crypto/index.js +16 -2
  13. package/dist/cjs/src/crypto/pemPublicToCrypto.js +17 -11
  14. package/dist/cjs/src/opentdf.js +50 -13
  15. package/dist/cjs/src/policy/discovery.js +2 -2
  16. package/dist/cjs/tdf3/index.js +4 -2
  17. package/dist/cjs/tdf3/src/assertions.js +71 -31
  18. package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  19. package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
  20. package/dist/cjs/tdf3/src/client/index.js +23 -33
  21. package/dist/cjs/tdf3/src/crypto/crypto-utils.js +12 -5
  22. package/dist/cjs/tdf3/src/crypto/declarations.js +1 -1
  23. package/dist/cjs/tdf3/src/crypto/index.js +849 -88
  24. package/dist/cjs/tdf3/src/crypto/jose/jwt-claims-set.js +11 -0
  25. package/dist/cjs/tdf3/src/crypto/jose/validate-crit.js +8 -0
  26. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +41 -0
  27. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/epoch.js +6 -0
  28. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/is_object.js +21 -0
  29. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +112 -0
  30. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/secs.js +60 -0
  31. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +38 -0
  32. package/dist/cjs/tdf3/src/crypto/jose/vendor/util/errors.js +135 -0
  33. package/dist/cjs/tdf3/src/crypto/jwt.js +183 -0
  34. package/dist/cjs/tdf3/src/crypto/salt.js +14 -8
  35. package/dist/cjs/tdf3/src/models/encryption-information.js +17 -20
  36. package/dist/cjs/tdf3/src/models/key-access.js +43 -63
  37. package/dist/cjs/tdf3/src/tdf.js +75 -75
  38. package/dist/cjs/tdf3/src/utils/index.js +5 -39
  39. package/dist/types/src/access/access-fetch.d.ts.map +1 -1
  40. package/dist/types/src/access/access-rpc.d.ts.map +1 -1
  41. package/dist/types/src/access.d.ts +0 -5
  42. package/dist/types/src/access.d.ts.map +1 -1
  43. package/dist/types/src/auth/auth.d.ts +9 -6
  44. package/dist/types/src/auth/auth.d.ts.map +1 -1
  45. package/dist/types/src/auth/dpop.d.ts +60 -0
  46. package/dist/types/src/auth/dpop.d.ts.map +1 -0
  47. package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +3 -2
  48. package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
  49. package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +3 -2
  50. package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
  51. package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +3 -2
  52. package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
  53. package/dist/types/src/auth/oidc.d.ts +6 -4
  54. package/dist/types/src/auth/oidc.d.ts.map +1 -1
  55. package/dist/types/src/auth/providers.d.ts +5 -4
  56. package/dist/types/src/auth/providers.d.ts.map +1 -1
  57. package/dist/types/src/crypto/index.d.ts +2 -1
  58. package/dist/types/src/crypto/index.d.ts.map +1 -1
  59. package/dist/types/src/crypto/pemPublicToCrypto.d.ts +18 -0
  60. package/dist/types/src/crypto/pemPublicToCrypto.d.ts.map +1 -1
  61. package/dist/types/src/opentdf.d.ts +26 -7
  62. package/dist/types/src/opentdf.d.ts.map +1 -1
  63. package/dist/types/src/policy/discovery.d.ts +2 -2
  64. package/dist/types/tdf3/index.d.ts +3 -3
  65. package/dist/types/tdf3/index.d.ts.map +1 -1
  66. package/dist/types/tdf3/src/assertions.d.ts +23 -8
  67. package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
  68. package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts +3 -3
  69. package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts.map +1 -1
  70. package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts +4 -4
  71. package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts.map +1 -1
  72. package/dist/types/tdf3/src/client/builders.d.ts +2 -2
  73. package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
  74. package/dist/types/tdf3/src/client/index.d.ts +6 -5
  75. package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
  76. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts +14 -4
  77. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -1
  78. package/dist/types/tdf3/src/crypto/declarations.d.ts +283 -18
  79. package/dist/types/tdf3/src/crypto/declarations.d.ts.map +1 -1
  80. package/dist/types/tdf3/src/crypto/index.d.ts +105 -28
  81. package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -1
  82. package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts +3 -0
  83. package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts.map +1 -0
  84. package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts +5 -0
  85. package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts.map +1 -0
  86. package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts +6 -0
  87. package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts.map +1 -0
  88. package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts +3 -0
  89. package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts.map +1 -0
  90. package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts +3 -0
  91. package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts.map +1 -0
  92. package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts +3 -0
  93. package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts.map +1 -0
  94. package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts +3 -0
  95. package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts.map +1 -0
  96. package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts +3 -0
  97. package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts.map +1 -0
  98. package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts +76 -0
  99. package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts.map +1 -0
  100. package/dist/types/tdf3/src/crypto/jwt.d.ts +76 -0
  101. package/dist/types/tdf3/src/crypto/jwt.d.ts.map +1 -0
  102. package/dist/types/tdf3/src/crypto/salt.d.ts +6 -1
  103. package/dist/types/tdf3/src/crypto/salt.d.ts.map +1 -1
  104. package/dist/types/tdf3/src/models/encryption-information.d.ts +4 -4
  105. package/dist/types/tdf3/src/models/encryption-information.d.ts.map +1 -1
  106. package/dist/types/tdf3/src/models/key-access.d.ts +8 -5
  107. package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -1
  108. package/dist/types/tdf3/src/tdf.d.ts +8 -8
  109. package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
  110. package/dist/types/tdf3/src/utils/index.d.ts +4 -3
  111. package/dist/types/tdf3/src/utils/index.d.ts.map +1 -1
  112. package/dist/web/src/access/access-fetch.js +3 -4
  113. package/dist/web/src/access/access-rpc.js +3 -5
  114. package/dist/web/src/access.js +1 -13
  115. package/dist/web/src/auth/auth.js +13 -10
  116. package/dist/web/src/auth/dpop.js +118 -0
  117. package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -3
  118. package/dist/web/src/auth/oidc-externaljwt-provider.js +4 -3
  119. package/dist/web/src/auth/oidc-refreshtoken-provider.js +4 -3
  120. package/dist/web/src/auth/oidc.js +11 -9
  121. package/dist/web/src/auth/providers.js +13 -12
  122. package/dist/web/src/crypto/index.js +4 -2
  123. package/dist/web/src/crypto/pemPublicToCrypto.js +11 -9
  124. package/dist/web/src/opentdf.js +17 -13
  125. package/dist/web/src/policy/discovery.js +2 -2
  126. package/dist/web/tdf3/index.js +3 -2
  127. package/dist/web/tdf3/src/assertions.js +71 -31
  128. package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  129. package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
  130. package/dist/web/tdf3/src/client/index.js +25 -35
  131. package/dist/web/tdf3/src/crypto/crypto-utils.js +12 -5
  132. package/dist/web/tdf3/src/crypto/declarations.js +1 -1
  133. package/dist/web/tdf3/src/crypto/index.js +830 -84
  134. package/dist/web/tdf3/src/crypto/jose/jwt-claims-set.js +5 -0
  135. package/dist/web/tdf3/src/crypto/jose/validate-crit.js +3 -0
  136. package/dist/web/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +35 -0
  137. package/dist/web/tdf3/src/crypto/jose/vendor/lib/epoch.js +4 -0
  138. package/dist/web/tdf3/src/crypto/jose/vendor/lib/is_object.js +19 -0
  139. package/dist/web/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +107 -0
  140. package/dist/web/tdf3/src/crypto/jose/vendor/lib/secs.js +58 -0
  141. package/dist/web/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +36 -0
  142. package/dist/web/tdf3/src/crypto/jose/vendor/util/errors.js +117 -0
  143. package/dist/web/tdf3/src/crypto/jwt.js +174 -0
  144. package/dist/web/tdf3/src/crypto/salt.js +13 -7
  145. package/dist/web/tdf3/src/models/encryption-information.js +11 -14
  146. package/dist/web/tdf3/src/models/key-access.js +44 -31
  147. package/dist/web/tdf3/src/tdf.js +71 -71
  148. package/dist/web/tdf3/src/utils/index.js +5 -6
  149. package/package.json +11 -4
  150. package/src/access/access-fetch.ts +2 -8
  151. package/src/access/access-rpc.ts +0 -7
  152. package/src/access.ts +0 -17
  153. package/src/auth/auth.ts +21 -12
  154. package/src/auth/dpop.ts +222 -0
  155. package/src/auth/oidc-clientcredentials-provider.ts +23 -15
  156. package/src/auth/oidc-externaljwt-provider.ts +23 -15
  157. package/src/auth/oidc-refreshtoken-provider.ts +23 -15
  158. package/src/auth/oidc.ts +21 -10
  159. package/src/auth/providers.ts +46 -29
  160. package/src/crypto/index.ts +21 -1
  161. package/src/crypto/pemPublicToCrypto.ts +11 -9
  162. package/src/opentdf.ts +36 -17
  163. package/src/policy/discovery.ts +2 -2
  164. package/tdf3/index.ts +32 -5
  165. package/tdf3/src/assertions.ts +99 -30
  166. package/tdf3/src/ciphers/aes-gcm-cipher.ts +7 -2
  167. package/tdf3/src/ciphers/symmetric-cipher-base.ts +7 -4
  168. package/tdf3/src/client/builders.ts +2 -2
  169. package/tdf3/src/client/index.ts +60 -59
  170. package/tdf3/src/crypto/crypto-utils.ts +15 -8
  171. package/tdf3/src/crypto/declarations.ts +338 -22
  172. package/tdf3/src/crypto/index.ts +1021 -118
  173. package/tdf3/src/crypto/jose/jwt-claims-set.ts +10 -0
  174. package/tdf3/src/crypto/jose/validate-crit.ts +9 -0
  175. package/tdf3/src/crypto/jose/vendor/lib/buffer_utils.ts +34 -0
  176. package/tdf3/src/crypto/jose/vendor/lib/epoch.ts +3 -0
  177. package/tdf3/src/crypto/jose/vendor/lib/is_object.ts +18 -0
  178. package/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.ts +106 -0
  179. package/tdf3/src/crypto/jose/vendor/lib/secs.ts +57 -0
  180. package/tdf3/src/crypto/jose/vendor/lib/validate_crit.ts +35 -0
  181. package/tdf3/src/crypto/jose/vendor/util/errors.ts +101 -0
  182. package/tdf3/src/crypto/jwt.ts +256 -0
  183. package/tdf3/src/crypto/salt.ts +16 -8
  184. package/tdf3/src/models/encryption-information.ts +14 -21
  185. package/tdf3/src/models/key-access.ts +57 -41
  186. package/tdf3/src/tdf.ts +110 -93
  187. package/tdf3/src/utils/index.ts +5 -6
@@ -0,0 +1,10 @@
1
+ import type { JWTHeaderParameters, JWTPayload, JWTVerifyOptions } from 'jose';
2
+ import jwtClaimsSet from './vendor/lib/jwt_claims_set.js';
3
+
4
+ export default function joseJwtClaimsSet(
5
+ protectedHeader: JWTHeaderParameters,
6
+ encodedPayload: Uint8Array,
7
+ options?: JWTVerifyOptions
8
+ ): JWTPayload {
9
+ return jwtClaimsSet(protectedHeader, encodedPayload, options) as JWTPayload;
10
+ }
@@ -0,0 +1,9 @@
1
+ import validateCrit from './vendor/lib/validate_crit.js';
2
+
3
+ export default validateCrit as (
4
+ Err: new (message?: string, options?: { cause?: unknown }) => Error,
5
+ recognizedDefault: Map<string, boolean>,
6
+ recognizedOption: Record<string, boolean> | undefined,
7
+ protectedHeader: Record<string, unknown> | undefined,
8
+ joseHeader: Record<string, unknown>
9
+ ) => Set<string>;
@@ -0,0 +1,34 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ export const encoder = new TextEncoder();
4
+ export const decoder = new TextDecoder();
5
+ const MAX_INT32 = 2 ** 32;
6
+ export function concat(...buffers) {
7
+ const size = buffers.reduce((acc, { length }) => acc + length, 0);
8
+ const buf = new Uint8Array(size);
9
+ let i = 0;
10
+ for (const buffer of buffers) {
11
+ buf.set(buffer, i);
12
+ i += buffer.length;
13
+ }
14
+ return buf;
15
+ }
16
+ function writeUInt32BE(buf, value, offset) {
17
+ if (value < 0 || value >= MAX_INT32) {
18
+ throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`);
19
+ }
20
+ buf.set([value >>> 24, value >>> 16, value >>> 8, value & 0xff], offset);
21
+ }
22
+ export function uint64be(value) {
23
+ const high = Math.floor(value / MAX_INT32);
24
+ const low = value % MAX_INT32;
25
+ const buf = new Uint8Array(8);
26
+ writeUInt32BE(buf, high, 0);
27
+ writeUInt32BE(buf, low, 4);
28
+ return buf;
29
+ }
30
+ export function uint32be(value) {
31
+ const buf = new Uint8Array(4);
32
+ writeUInt32BE(buf, value);
33
+ return buf;
34
+ }
@@ -0,0 +1,3 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ export default (date) => Math.floor(date.getTime() / 1000);
@@ -0,0 +1,18 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ function isObjectLike(value) {
4
+ return typeof value === 'object' && value !== null;
5
+ }
6
+ export default (input) => {
7
+ if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {
8
+ return false;
9
+ }
10
+ if (Object.getPrototypeOf(input) === null) {
11
+ return true;
12
+ }
13
+ let proto = input;
14
+ while (Object.getPrototypeOf(proto) !== null) {
15
+ proto = Object.getPrototypeOf(proto);
16
+ }
17
+ return Object.getPrototypeOf(input) === proto;
18
+ };
@@ -0,0 +1,106 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js';
4
+ import { decoder } from './buffer_utils.js';
5
+ import epoch from './epoch.js';
6
+ import secs from './secs.js';
7
+ import isObject from './is_object.js';
8
+ const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, '');
9
+ const checkAudiencePresence = (audPayload, audOption) => {
10
+ if (typeof audPayload === 'string') {
11
+ return audOption.includes(audPayload);
12
+ }
13
+ if (Array.isArray(audPayload)) {
14
+ return audOption.some(Set.prototype.has.bind(new Set(audPayload)));
15
+ }
16
+ return false;
17
+ };
18
+ export default (protectedHeader, encodedPayload, options = {}) => {
19
+ let payload;
20
+ try {
21
+ payload = JSON.parse(decoder.decode(encodedPayload));
22
+ }
23
+ catch {
24
+ }
25
+ if (!isObject(payload)) {
26
+ throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
27
+ }
28
+ const { typ } = options;
29
+ if (typ &&
30
+ (typeof protectedHeader.typ !== 'string' ||
31
+ normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
32
+ throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, 'typ', 'check_failed');
33
+ }
34
+ const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
35
+ const presenceCheck = [...requiredClaims];
36
+ if (maxTokenAge !== undefined)
37
+ presenceCheck.push('iat');
38
+ if (audience !== undefined)
39
+ presenceCheck.push('aud');
40
+ if (subject !== undefined)
41
+ presenceCheck.push('sub');
42
+ if (issuer !== undefined)
43
+ presenceCheck.push('iss');
44
+ for (const claim of new Set(presenceCheck.reverse())) {
45
+ if (!(claim in payload)) {
46
+ throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, 'missing');
47
+ }
48
+ }
49
+ if (issuer &&
50
+ !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
51
+ throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, 'iss', 'check_failed');
52
+ }
53
+ if (subject && payload.sub !== subject) {
54
+ throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, 'sub', 'check_failed');
55
+ }
56
+ if (audience &&
57
+ !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
58
+ throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, 'aud', 'check_failed');
59
+ }
60
+ let tolerance;
61
+ switch (typeof options.clockTolerance) {
62
+ case 'string':
63
+ tolerance = secs(options.clockTolerance);
64
+ break;
65
+ case 'number':
66
+ tolerance = options.clockTolerance;
67
+ break;
68
+ case 'undefined':
69
+ tolerance = 0;
70
+ break;
71
+ default:
72
+ throw new TypeError('Invalid clockTolerance option type');
73
+ }
74
+ const { currentDate } = options;
75
+ const now = epoch(currentDate || new Date());
76
+ if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
77
+ throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, 'iat', 'invalid');
78
+ }
79
+ if (payload.nbf !== undefined) {
80
+ if (typeof payload.nbf !== 'number') {
81
+ throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, 'nbf', 'invalid');
82
+ }
83
+ if (payload.nbf > now + tolerance) {
84
+ throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, 'nbf', 'check_failed');
85
+ }
86
+ }
87
+ if (payload.exp !== undefined) {
88
+ if (typeof payload.exp !== 'number') {
89
+ throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, 'exp', 'invalid');
90
+ }
91
+ if (payload.exp <= now - tolerance) {
92
+ throw new JWTExpired('"exp" claim timestamp check failed', payload, 'exp', 'check_failed');
93
+ }
94
+ }
95
+ if (maxTokenAge) {
96
+ const age = now - payload.iat;
97
+ const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
98
+ if (age - tolerance > max) {
99
+ throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, 'iat', 'check_failed');
100
+ }
101
+ if (age < 0 - tolerance) {
102
+ throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, 'iat', 'check_failed');
103
+ }
104
+ }
105
+ return payload;
106
+ };
@@ -0,0 +1,57 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ const minute = 60;
4
+ const hour = minute * 60;
5
+ const day = hour * 24;
6
+ const week = day * 7;
7
+ const year = day * 365.25;
8
+ const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
9
+ export default (str) => {
10
+ const matched = REGEX.exec(str);
11
+ if (!matched || (matched[4] && matched[1])) {
12
+ throw new TypeError('Invalid time period format');
13
+ }
14
+ const value = parseFloat(matched[2]);
15
+ const unit = matched[3].toLowerCase();
16
+ let numericDate;
17
+ switch (unit) {
18
+ case 'sec':
19
+ case 'secs':
20
+ case 'second':
21
+ case 'seconds':
22
+ case 's':
23
+ numericDate = Math.round(value);
24
+ break;
25
+ case 'minute':
26
+ case 'minutes':
27
+ case 'min':
28
+ case 'mins':
29
+ case 'm':
30
+ numericDate = Math.round(value * minute);
31
+ break;
32
+ case 'hour':
33
+ case 'hours':
34
+ case 'hr':
35
+ case 'hrs':
36
+ case 'h':
37
+ numericDate = Math.round(value * hour);
38
+ break;
39
+ case 'day':
40
+ case 'days':
41
+ case 'd':
42
+ numericDate = Math.round(value * day);
43
+ break;
44
+ case 'week':
45
+ case 'weeks':
46
+ case 'w':
47
+ numericDate = Math.round(value * week);
48
+ break;
49
+ default:
50
+ numericDate = Math.round(value * year);
51
+ break;
52
+ }
53
+ if (matched[1] === '-' || matched[4] === 'ago') {
54
+ return -numericDate;
55
+ }
56
+ return numericDate;
57
+ };
@@ -0,0 +1,35 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js';
4
+ export default (Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) => {
5
+ if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {
6
+ throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
7
+ }
8
+ if (!protectedHeader || protectedHeader.crit === undefined) {
9
+ return new Set();
10
+ }
11
+ if (!Array.isArray(protectedHeader.crit) ||
12
+ protectedHeader.crit.length === 0 ||
13
+ protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) {
14
+ throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
15
+ }
16
+ let recognized;
17
+ if (recognizedOption !== undefined) {
18
+ recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
19
+ }
20
+ else {
21
+ recognized = recognizedDefault;
22
+ }
23
+ for (const parameter of protectedHeader.crit) {
24
+ if (!recognized.has(parameter)) {
25
+ throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
26
+ }
27
+ if (joseHeader[parameter] === undefined) {
28
+ throw new Err(`Extension Header Parameter "${parameter}" is missing`);
29
+ }
30
+ if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
31
+ throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
32
+ }
33
+ }
34
+ return new Set(protectedHeader.crit);
35
+ };
@@ -0,0 +1,101 @@
1
+ // @ts-nocheck
2
+ // Generated from jose@6.0.8. Do not edit directly.
3
+ export class JOSEError extends Error {
4
+ static code = 'ERR_JOSE_GENERIC';
5
+ code = 'ERR_JOSE_GENERIC';
6
+ constructor(message, options) {
7
+ super(message, options);
8
+ this.name = this.constructor.name;
9
+ Error.captureStackTrace?.(this, this.constructor);
10
+ }
11
+ }
12
+ export class JWTClaimValidationFailed extends JOSEError {
13
+ static code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
14
+ code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
15
+ claim;
16
+ reason;
17
+ payload;
18
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
19
+ super(message, { cause: { claim, reason, payload } });
20
+ this.claim = claim;
21
+ this.reason = reason;
22
+ this.payload = payload;
23
+ }
24
+ }
25
+ export class JWTExpired extends JOSEError {
26
+ static code = 'ERR_JWT_EXPIRED';
27
+ code = 'ERR_JWT_EXPIRED';
28
+ claim;
29
+ reason;
30
+ payload;
31
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
32
+ super(message, { cause: { claim, reason, payload } });
33
+ this.claim = claim;
34
+ this.reason = reason;
35
+ this.payload = payload;
36
+ }
37
+ }
38
+ export class JOSEAlgNotAllowed extends JOSEError {
39
+ static code = 'ERR_JOSE_ALG_NOT_ALLOWED';
40
+ code = 'ERR_JOSE_ALG_NOT_ALLOWED';
41
+ }
42
+ export class JOSENotSupported extends JOSEError {
43
+ static code = 'ERR_JOSE_NOT_SUPPORTED';
44
+ code = 'ERR_JOSE_NOT_SUPPORTED';
45
+ }
46
+ export class JWEDecryptionFailed extends JOSEError {
47
+ static code = 'ERR_JWE_DECRYPTION_FAILED';
48
+ code = 'ERR_JWE_DECRYPTION_FAILED';
49
+ constructor(message = 'decryption operation failed', options) {
50
+ super(message, options);
51
+ }
52
+ }
53
+ export class JWEInvalid extends JOSEError {
54
+ static code = 'ERR_JWE_INVALID';
55
+ code = 'ERR_JWE_INVALID';
56
+ }
57
+ export class JWSInvalid extends JOSEError {
58
+ static code = 'ERR_JWS_INVALID';
59
+ code = 'ERR_JWS_INVALID';
60
+ }
61
+ export class JWTInvalid extends JOSEError {
62
+ static code = 'ERR_JWT_INVALID';
63
+ code = 'ERR_JWT_INVALID';
64
+ }
65
+ export class JWKInvalid extends JOSEError {
66
+ static code = 'ERR_JWK_INVALID';
67
+ code = 'ERR_JWK_INVALID';
68
+ }
69
+ export class JWKSInvalid extends JOSEError {
70
+ static code = 'ERR_JWKS_INVALID';
71
+ code = 'ERR_JWKS_INVALID';
72
+ }
73
+ export class JWKSNoMatchingKey extends JOSEError {
74
+ static code = 'ERR_JWKS_NO_MATCHING_KEY';
75
+ code = 'ERR_JWKS_NO_MATCHING_KEY';
76
+ constructor(message = 'no applicable key found in the JSON Web Key Set', options) {
77
+ super(message, options);
78
+ }
79
+ }
80
+ export class JWKSMultipleMatchingKeys extends JOSEError {
81
+ [Symbol.asyncIterator];
82
+ static code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';
83
+ code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';
84
+ constructor(message = 'multiple matching keys found in the JSON Web Key Set', options) {
85
+ super(message, options);
86
+ }
87
+ }
88
+ export class JWKSTimeout extends JOSEError {
89
+ static code = 'ERR_JWKS_TIMEOUT';
90
+ code = 'ERR_JWKS_TIMEOUT';
91
+ constructor(message = 'request timed out', options) {
92
+ super(message, options);
93
+ }
94
+ }
95
+ export class JWSSignatureVerificationFailed extends JOSEError {
96
+ static code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
97
+ code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
98
+ constructor(message = 'signature verification failed', options) {
99
+ super(message, options);
100
+ }
101
+ }
@@ -0,0 +1,256 @@
1
+ import {
2
+ type AsymmetricSigningAlgorithm,
3
+ type CryptoService,
4
+ type PrivateKey,
5
+ type PublicKey,
6
+ type SigningAlgorithm,
7
+ type SymmetricKey,
8
+ } from './declarations.js';
9
+ import { base64 } from '../../../src/encodings/index.js';
10
+ import {
11
+ decodeProtectedHeader as joseDecodeProtectedHeader,
12
+ errors as joseErrors,
13
+ type JWTHeaderParameters,
14
+ type JWTPayload,
15
+ type JWTVerifyOptions,
16
+ type SignOptions,
17
+ } from 'jose';
18
+ import jwtClaimsSet from './jose/jwt-claims-set.js';
19
+ import validateCrit from './jose/validate-crit.js';
20
+
21
+ export type JwtHeader = JWTHeaderParameters & { alg: SigningAlgorithm };
22
+ export type JwtPayload = JWTPayload;
23
+
24
+ /**
25
+ * Options for JWT signing. Matches jose SignOptions interface.
26
+ */
27
+ export type SignJwtOptions = SignOptions;
28
+
29
+ /**
30
+ * Options for JWT verification. Matches jose JWTVerifyOptions interface.
31
+ * Combines signature verification options and JWT claim verification options.
32
+ */
33
+ export type VerifyJwtOptions = Omit<JWTVerifyOptions, 'algorithms'> & {
34
+ /**
35
+ * A list of accepted JWS "alg" (Algorithm) Header Parameter values.
36
+ * By default all algorithms supported by the CryptoService are allowed.
37
+ * Unsecured JWTs ({ "alg": "none" }) are never accepted.
38
+ */
39
+ algorithms?: SigningAlgorithm[];
40
+ };
41
+
42
+ /**
43
+ * Base64url encode data per RFC 4648 Section 5.
44
+ * Uses URL-safe alphabet (- and _ instead of + and /) with no padding.
45
+ * Exported for testing purposes.
46
+ */
47
+ export function base64urlEncode(data: string | Uint8Array): string {
48
+ if (typeof data === 'string') {
49
+ // Encode string to base64url
50
+ const bytes = new TextEncoder().encode(data);
51
+ return base64.encodeArrayBuffer(bytes.buffer, true); // urlSafe = true
52
+ } else {
53
+ // Encode Uint8Array to base64url
54
+ const buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
55
+ return base64.encodeArrayBuffer(buffer, true); // urlSafe = true
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Helper to convert base64url to standard base64 with padding.
61
+ */
62
+ function base64urlToBase64(str: string): string {
63
+ // Convert base64url to base64: replace - with +, _ with /
64
+ let b64 = str.replace(/-/g, '+').replace(/_/g, '/');
65
+
66
+ // Add padding if needed
67
+ const padding = (4 - (b64.length % 4)) % 4;
68
+ b64 += '='.repeat(padding);
69
+
70
+ return b64;
71
+ }
72
+
73
+ /**
74
+ * Base64url decode to Uint8Array per RFC 4648 Section 5.
75
+ */
76
+ function base64urlDecodeBytes(str: string): Uint8Array {
77
+ const b64 = base64urlToBase64(str);
78
+ return new Uint8Array(base64.decodeArrayBuffer(b64));
79
+ }
80
+
81
+ /**
82
+ * Decode the protected header from a JWT without verifying the signature.
83
+ * Useful for inspecting the header to determine key type before verification.
84
+ *
85
+ * @param token - The JWT string
86
+ * @returns The decoded header
87
+ * @throws Error if the token is malformed or uses alg "none"
88
+ */
89
+ export function decodeProtectedHeader(token: string): JwtHeader {
90
+ return joseDecodeProtectedHeader(token) as JwtHeader;
91
+ }
92
+
93
+ /**
94
+ * Sign a JWT using CryptoService. Replaces jose SignJWT.
95
+ *
96
+ * Implementation:
97
+ * 1. Base64url encode header and payload as JSON
98
+ * 2. Create signing input: `${headerB64}.${payloadB64}`
99
+ * 3. Sign via cryptoService.sign() (asymmetric) or hmac() (HS256)
100
+ * 4. Return compact JWT: `${headerB64}.${payloadB64}.${signatureB64}`
101
+ *
102
+ * @param cryptoService - Crypto implementation to use
103
+ * @param payload - JWT payload (claims)
104
+ * @param key - PEM-encoded private key for asymmetric algorithms, or raw key bytes for HS256
105
+ * @param header - JWT header (must include alg)
106
+ * @param options - Optional signing options (e.g., crit header handling)
107
+ * @returns Compact JWT string
108
+ */
109
+ export async function signJwt(
110
+ cryptoService: CryptoService,
111
+ payload: JwtPayload,
112
+ key: PrivateKey | SymmetricKey,
113
+ header: JwtHeader,
114
+ options?: SignJwtOptions
115
+ ): Promise<string> {
116
+ validateCrit(joseErrors.JWSInvalid, new Map([['b64', true]]), options?.crit, header, header);
117
+
118
+ // Encode header and payload per RFC 7515
119
+ const headerB64 = base64urlEncode(JSON.stringify(header));
120
+ const payloadB64 = base64urlEncode(JSON.stringify(payload));
121
+
122
+ // Create signing input
123
+ const signingInput = `${headerB64}.${payloadB64}`;
124
+ const signingInputBytes = new TextEncoder().encode(signingInput);
125
+
126
+ // Sign via CryptoService - route based on algorithm
127
+ let signature: Uint8Array;
128
+ if (header.alg === 'HS256') {
129
+ if (key._brand !== 'SymmetricKey') {
130
+ throw new Error('HS256 requires a SymmetricKey');
131
+ }
132
+ signature = await cryptoService.hmac(signingInputBytes, key);
133
+ } else {
134
+ if (key._brand !== 'PrivateKey') {
135
+ throw new Error(`${header.alg} requires a PrivateKey`);
136
+ }
137
+ signature = await cryptoService.sign(
138
+ signingInputBytes,
139
+ key,
140
+ header.alg as AsymmetricSigningAlgorithm
141
+ );
142
+ }
143
+
144
+ // Return compact JWT
145
+ return `${signingInput}.${base64urlEncode(signature)}`;
146
+ }
147
+
148
+ /**
149
+ * Verify a JWT and return its contents. Replaces jose jwtVerify.
150
+ *
151
+ * Implementation:
152
+ * 1. Split token into header.payload.signature
153
+ * 2. Decode header, validate algorithm against allowlist
154
+ * 3. Verify signature via cryptoService.verify() (asymmetric) or verifyHmac() (HS256)
155
+ * 4. Validate JWT claims (aud, iss, exp, nbf, etc.)
156
+ * 5. Return decoded header and payload
157
+ *
158
+ * @param cryptoService - Crypto implementation to use
159
+ * @param token - The JWT string to verify
160
+ * @param key - For asymmetric: PEM string or PublicKey (opaque). For HS256: Uint8Array or SymmetricKey (opaque).
161
+ * @param options - Verification options including algorithm allowlist and claim validations
162
+ * @throws Error if signature invalid, algorithm not in allowlist, claims invalid, or token malformed
163
+ * @returns Decoded header and payload
164
+ */
165
+ export async function verifyJwt(
166
+ cryptoService: CryptoService,
167
+ token: string,
168
+ key: string | Uint8Array | PublicKey | SymmetricKey,
169
+ options?: VerifyJwtOptions
170
+ ): Promise<{ header: JwtHeader; payload: JwtPayload }> {
171
+ const parts = token.split('.');
172
+ if (parts.length !== 3) {
173
+ throw new joseErrors.JWTInvalid('Invalid Token or Protected Header formatting');
174
+ }
175
+ const [headerB64, payloadB64, signatureB64] = parts;
176
+
177
+ // Decode and validate header
178
+ const headerRaw = decodeProtectedHeader(token);
179
+ if (typeof headerRaw.alg !== 'string' || !headerRaw.alg) {
180
+ throw new joseErrors.JWTInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
181
+ }
182
+ if ((headerRaw.alg as string) === 'none') {
183
+ throw new joseErrors.JWTInvalid('Invalid JWT: alg "none" not allowed');
184
+ }
185
+
186
+ // Validate algorithm is in allowlist if provided
187
+ if (options?.algorithms && !options.algorithms.includes(headerRaw.alg as SigningAlgorithm)) {
188
+ throw new joseErrors.JWTInvalid(`Invalid JWT: algorithm "${headerRaw.alg}" not in allowlist`);
189
+ }
190
+
191
+ const extensions = validateCrit(
192
+ joseErrors.JWSInvalid,
193
+ new Map([['b64', true]]),
194
+ options?.crit,
195
+ headerRaw,
196
+ headerRaw
197
+ );
198
+
199
+ // Now we know it's a valid algorithm
200
+ const header = headerRaw as JwtHeader;
201
+
202
+ // Verify signature via CryptoService - route based on algorithm
203
+ const signingInput = `${headerB64}.${payloadB64}`;
204
+ const signingInputBytes = new TextEncoder().encode(signingInput);
205
+ const signature = base64urlDecodeBytes(signatureB64);
206
+
207
+ let valid: boolean;
208
+ if (header.alg === 'HS256') {
209
+ // Symmetric verification - accept Uint8Array or SymmetricKey
210
+ if (typeof key === 'string') {
211
+ throw new Error('HS256 requires a Uint8Array or SymmetricKey, not a PEM string');
212
+ }
213
+ if ('_brand' in key && key._brand === 'PublicKey') {
214
+ throw new Error('HS256 requires a SymmetricKey, not a PublicKey');
215
+ }
216
+ // Convert Uint8Array to SymmetricKey if needed, otherwise assume it's already SymmetricKey
217
+ const symmetricKey =
218
+ key instanceof Uint8Array
219
+ ? await cryptoService.importSymmetricKey(key)
220
+ : (key as SymmetricKey);
221
+ valid = await cryptoService.verifyHmac(signingInputBytes, signature, symmetricKey);
222
+ } else {
223
+ // Asymmetric verification - accept string (PEM) or PublicKey
224
+ if (key instanceof Uint8Array) {
225
+ throw new Error(`${header.alg} requires a PEM string or PublicKey, not Uint8Array`);
226
+ }
227
+ if (typeof key === 'object' && '_brand' in key && key._brand === 'SymmetricKey') {
228
+ throw new Error(`${header.alg} requires a PublicKey, not a SymmetricKey`);
229
+ }
230
+ // Convert PEM string to PublicKey if needed, otherwise assume it's already PublicKey
231
+ const publicKey =
232
+ typeof key === 'string'
233
+ ? await cryptoService.importPublicKey(key, { usage: 'sign' })
234
+ : (key as PublicKey);
235
+ valid = await cryptoService.verify(
236
+ signingInputBytes,
237
+ signature,
238
+ publicKey,
239
+ header.alg as AsymmetricSigningAlgorithm
240
+ );
241
+ }
242
+
243
+ if (!valid) {
244
+ throw new joseErrors.JWTInvalid('Invalid JWT: signature verification failed');
245
+ }
246
+
247
+ if (extensions.has('b64') && (header as { b64?: boolean }).b64 === false) {
248
+ throw new joseErrors.JWTInvalid('JWTs MUST NOT use unencoded payload');
249
+ }
250
+
251
+ // Decode payload and validate JWT claims
252
+ const payloadBytes = base64urlDecodeBytes(payloadB64);
253
+ const payload = jwtClaimsSet(header, payloadBytes, options) as JwtPayload;
254
+
255
+ return { header, payload };
256
+ }
@@ -1,11 +1,19 @@
1
- const generateSalt = async () => {
2
- const encoder = new TextEncoder();
3
- const data = encoder.encode('TDF');
1
+ import type { CryptoService } from './declarations.js';
2
+
3
+ let cachedSalt: Uint8Array | null = null;
4
4
 
5
- // Generate hash
6
- const hashBuffer = await crypto.subtle.digest('SHA-256', data);
5
+ /**
6
+ * Get the ZTDF salt (SHA-256 of "TDF").
7
+ * Lazily computed on first call and cached thereafter.
8
+ */
9
+ export async function getZtdfSalt(cryptoService: CryptoService): Promise<Uint8Array> {
10
+ if (cachedSalt) {
11
+ return cachedSalt;
12
+ }
7
13
 
8
- return new Uint8Array(hashBuffer);
9
- };
14
+ const encoder = new TextEncoder();
15
+ const data = encoder.encode('TDF');
10
16
 
11
- export const ztdfSalt = generateSalt();
17
+ cachedSalt = await cryptoService.digest('SHA-256', data);
18
+ return cachedSalt;
19
+ }