@authup/server-kit 1.0.0-beta.3 → 1.0.0-beta.32

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 (189) hide show
  1. package/LICENSE +201 -21
  2. package/README.md +2 -2
  3. package/dist/crypto/hash/hash.d.ts +1 -1
  4. package/dist/crypto/hash/hash.d.ts.map +1 -1
  5. package/dist/crypto/index.d.ts +1 -1
  6. package/dist/crypto/index.d.ts.map +1 -1
  7. package/dist/crypto/json-web-token/extract.d.ts +16 -0
  8. package/dist/crypto/json-web-token/extract.d.ts.map +1 -0
  9. package/dist/crypto/json-web-token/index.d.ts +1 -1
  10. package/dist/crypto/json-web-token/index.d.ts.map +1 -1
  11. package/dist/crypto/json-web-token/sign/index.d.ts +3 -0
  12. package/dist/crypto/json-web-token/sign/index.d.ts.map +1 -0
  13. package/dist/crypto/json-web-token/sign/module.d.ts +4 -0
  14. package/dist/crypto/json-web-token/sign/module.d.ts.map +1 -0
  15. package/dist/crypto/json-web-token/sign/types.d.ts +28 -0
  16. package/dist/crypto/json-web-token/sign/types.d.ts.map +1 -0
  17. package/dist/crypto/json-web-token/type.d.ts +4 -33
  18. package/dist/crypto/json-web-token/type.d.ts.map +1 -1
  19. package/dist/crypto/json-web-token/utils.d.ts +5 -2
  20. package/dist/crypto/json-web-token/utils.d.ts.map +1 -1
  21. package/dist/crypto/json-web-token/verify/index.d.ts +3 -0
  22. package/dist/crypto/json-web-token/verify/index.d.ts.map +1 -0
  23. package/dist/crypto/json-web-token/verify/module.d.ts +12 -0
  24. package/dist/crypto/json-web-token/verify/module.d.ts.map +1 -0
  25. package/dist/crypto/json-web-token/verify/types.d.ts +25 -0
  26. package/dist/crypto/json-web-token/verify/types.d.ts.map +1 -0
  27. package/dist/crypto/key/asymmetric/check.d.ts +3 -0
  28. package/dist/crypto/key/asymmetric/check.d.ts.map +1 -0
  29. package/dist/crypto/key/asymmetric/constants.d.ts +8 -0
  30. package/dist/crypto/key/asymmetric/constants.d.ts.map +1 -0
  31. package/dist/crypto/key/asymmetric/create.d.ts +3 -0
  32. package/dist/crypto/key/asymmetric/create.d.ts.map +1 -0
  33. package/dist/crypto/key/asymmetric/helpers/index.d.ts +2 -0
  34. package/dist/crypto/key/asymmetric/helpers/index.d.ts.map +1 -0
  35. package/dist/crypto/key/asymmetric/helpers/wrap.d.ts +5 -0
  36. package/dist/crypto/key/asymmetric/helpers/wrap.d.ts.map +1 -0
  37. package/dist/crypto/key/asymmetric/index.d.ts +9 -0
  38. package/dist/crypto/key/asymmetric/index.d.ts.map +1 -0
  39. package/dist/crypto/key/asymmetric/key-usages.d.ts +5 -0
  40. package/dist/crypto/key/asymmetric/key-usages.d.ts.map +1 -0
  41. package/dist/crypto/key/asymmetric/module.d.ts +20 -0
  42. package/dist/crypto/key/asymmetric/module.d.ts.map +1 -0
  43. package/dist/crypto/key/asymmetric/normalize.d.ts +4 -0
  44. package/dist/crypto/key/asymmetric/normalize.d.ts.map +1 -0
  45. package/dist/crypto/key/asymmetric/types.d.ts +35 -0
  46. package/dist/crypto/key/asymmetric/types.d.ts.map +1 -0
  47. package/dist/crypto/key/base.d.ts +9 -0
  48. package/dist/crypto/key/base.d.ts.map +1 -0
  49. package/dist/crypto/key/index.d.ts +4 -0
  50. package/dist/crypto/key/index.d.ts.map +1 -0
  51. package/dist/crypto/key/symmetric/check.d.ts +3 -0
  52. package/dist/crypto/key/symmetric/check.d.ts.map +1 -0
  53. package/dist/crypto/key/symmetric/constants.d.ts +7 -0
  54. package/dist/crypto/key/symmetric/constants.d.ts.map +1 -0
  55. package/dist/crypto/key/symmetric/create.d.ts +3 -0
  56. package/dist/crypto/key/symmetric/create.d.ts.map +1 -0
  57. package/dist/crypto/key/symmetric/index.d.ts +7 -0
  58. package/dist/crypto/key/symmetric/index.d.ts.map +1 -0
  59. package/dist/crypto/key/symmetric/key-usages.d.ts +2 -0
  60. package/dist/crypto/key/symmetric/key-usages.d.ts.map +1 -0
  61. package/dist/crypto/key/symmetric/module.d.ts +13 -0
  62. package/dist/crypto/key/symmetric/module.d.ts.map +1 -0
  63. package/dist/crypto/key/symmetric/normalize.d.ts +4 -0
  64. package/dist/crypto/key/symmetric/normalize.d.ts.map +1 -0
  65. package/dist/crypto/key/symmetric/types.d.ts +32 -0
  66. package/dist/crypto/key/symmetric/types.d.ts.map +1 -0
  67. package/dist/domain-event/index.d.ts +1 -1
  68. package/dist/domain-event/index.d.ts.map +1 -1
  69. package/dist/domain-event/module.d.ts +9 -0
  70. package/dist/domain-event/module.d.ts.map +1 -0
  71. package/dist/domain-event/redis/index.d.ts +1 -1
  72. package/dist/domain-event/redis/index.d.ts.map +1 -1
  73. package/dist/domain-event/redis/module.d.ts +9 -0
  74. package/dist/domain-event/redis/module.d.ts.map +1 -0
  75. package/dist/domain-event/socket/index.d.ts +1 -2
  76. package/dist/domain-event/socket/index.d.ts.map +1 -1
  77. package/dist/domain-event/socket/module.d.ts +9 -0
  78. package/dist/domain-event/socket/module.d.ts.map +1 -0
  79. package/dist/domain-event/type.d.ts +8 -0
  80. package/dist/domain-event/type.d.ts.map +1 -1
  81. package/dist/domain-event/utils.d.ts +2 -1
  82. package/dist/domain-event/utils.d.ts.map +1 -1
  83. package/dist/index.d.ts +1 -2
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.mjs +841 -466
  86. package/dist/index.mjs.map +1 -1
  87. package/dist/services/cache/adapters/index.d.ts +3 -0
  88. package/dist/services/cache/adapters/index.d.ts.map +1 -0
  89. package/dist/services/cache/adapters/memory.d.ts +15 -0
  90. package/dist/services/cache/adapters/memory.d.ts.map +1 -0
  91. package/dist/services/cache/adapters/redis.d.ts +17 -0
  92. package/dist/services/cache/adapters/redis.d.ts.map +1 -0
  93. package/dist/services/cache/helper.d.ts +3 -0
  94. package/dist/services/cache/helper.d.ts.map +1 -0
  95. package/dist/services/cache/index.d.ts +4 -0
  96. package/dist/services/cache/index.d.ts.map +1 -0
  97. package/dist/services/cache/types.d.ts +25 -0
  98. package/dist/services/cache/types.d.ts.map +1 -0
  99. package/dist/services/index.d.ts +5 -0
  100. package/dist/services/index.d.ts.map +1 -0
  101. package/dist/services/logger/index.d.ts +4 -0
  102. package/dist/services/logger/index.d.ts.map +1 -0
  103. package/dist/services/logger/module.d.ts +4 -0
  104. package/dist/services/logger/module.d.ts.map +1 -0
  105. package/dist/services/logger/singleton.d.ts +7 -0
  106. package/dist/services/logger/singleton.d.ts.map +1 -0
  107. package/dist/services/logger/types.d.ts +7 -0
  108. package/dist/services/logger/types.d.ts.map +1 -0
  109. package/dist/services/redis/check.d.ts +3 -0
  110. package/dist/services/redis/check.d.ts.map +1 -0
  111. package/dist/services/redis/factory.d.ts +4 -0
  112. package/dist/services/redis/factory.d.ts.map +1 -0
  113. package/dist/services/redis/index.d.ts +4 -0
  114. package/dist/services/redis/index.d.ts.map +1 -0
  115. package/dist/services/redis/module.d.ts +5 -0
  116. package/dist/services/redis/module.d.ts.map +1 -0
  117. package/dist/services/vault/index.d.ts +3 -0
  118. package/dist/services/vault/index.d.ts.map +1 -0
  119. package/dist/services/vault/module.d.ts +3 -0
  120. package/dist/services/vault/module.d.ts.map +1 -0
  121. package/dist/services/vault/singleton.d.ts +6 -0
  122. package/dist/services/vault/singleton.d.ts.map +1 -0
  123. package/package.json +43 -32
  124. package/dist/crypto/json-web-token/decode.d.ts +0 -15
  125. package/dist/crypto/json-web-token/decode.d.ts.map +0 -1
  126. package/dist/crypto/json-web-token/sign.d.ts +0 -4
  127. package/dist/crypto/json-web-token/sign.d.ts.map +0 -1
  128. package/dist/crypto/json-web-token/verify.d.ts +0 -15
  129. package/dist/crypto/json-web-token/verify.d.ts.map +0 -1
  130. package/dist/crypto/key-pair/constants.d.ts +0 -5
  131. package/dist/crypto/key-pair/constants.d.ts.map +0 -1
  132. package/dist/crypto/key-pair/create.d.ts +0 -3
  133. package/dist/crypto/key-pair/create.d.ts.map +0 -1
  134. package/dist/crypto/key-pair/delete.d.ts +0 -3
  135. package/dist/crypto/key-pair/delete.d.ts.map +0 -1
  136. package/dist/crypto/key-pair/index.d.ts +0 -9
  137. package/dist/crypto/key-pair/index.d.ts.map +0 -1
  138. package/dist/crypto/key-pair/load.d.ts +0 -3
  139. package/dist/crypto/key-pair/load.d.ts.map +0 -1
  140. package/dist/crypto/key-pair/module.d.ts +0 -3
  141. package/dist/crypto/key-pair/module.d.ts.map +0 -1
  142. package/dist/crypto/key-pair/save.d.ts +0 -3
  143. package/dist/crypto/key-pair/save.d.ts.map +0 -1
  144. package/dist/crypto/key-pair/type.d.ts +0 -65
  145. package/dist/crypto/key-pair/type.d.ts.map +0 -1
  146. package/dist/crypto/key-pair/utils/check.d.ts +0 -4
  147. package/dist/crypto/key-pair/utils/check.d.ts.map +0 -1
  148. package/dist/crypto/key-pair/utils/file-name.d.ts +0 -4
  149. package/dist/crypto/key-pair/utils/file-name.d.ts.map +0 -1
  150. package/dist/crypto/key-pair/utils/index.d.ts +0 -5
  151. package/dist/crypto/key-pair/utils/index.d.ts.map +0 -1
  152. package/dist/crypto/key-pair/utils/options.d.ts +0 -3
  153. package/dist/crypto/key-pair/utils/options.d.ts.map +0 -1
  154. package/dist/crypto/key-pair/utils/private-key.d.ts +0 -4
  155. package/dist/crypto/key-pair/utils/private-key.d.ts.map +0 -1
  156. package/dist/domain-event/publish.d.ts +0 -4
  157. package/dist/domain-event/publish.d.ts.map +0 -1
  158. package/dist/domain-event/redis/publish.d.ts +0 -4
  159. package/dist/domain-event/redis/publish.d.ts.map +0 -1
  160. package/dist/domain-event/socket/publish.d.ts +0 -4
  161. package/dist/domain-event/socket/publish.d.ts.map +0 -1
  162. package/dist/domain-event/socket/singleton.d.ts +0 -4
  163. package/dist/domain-event/socket/singleton.d.ts.map +0 -1
  164. package/dist/domain-event/socket/type.d.ts +0 -5
  165. package/dist/domain-event/socket/type.d.ts.map +0 -1
  166. package/dist/index.cjs +0 -642
  167. package/dist/index.cjs.map +0 -1
  168. package/dist/logger/index.d.ts +0 -4
  169. package/dist/logger/index.d.ts.map +0 -1
  170. package/dist/logger/module.d.ts +0 -4
  171. package/dist/logger/module.d.ts.map +0 -1
  172. package/dist/logger/presets/index.d.ts +0 -2
  173. package/dist/logger/presets/index.d.ts.map +0 -1
  174. package/dist/logger/presets/void.d.ts +0 -16
  175. package/dist/logger/presets/void.d.ts.map +0 -1
  176. package/dist/logger/type.d.ts +0 -14
  177. package/dist/logger/type.d.ts.map +0 -1
  178. package/dist/smtp/config/index.d.ts +0 -2
  179. package/dist/smtp/config/index.d.ts.map +0 -1
  180. package/dist/smtp/config/singleton.d.ts +0 -5
  181. package/dist/smtp/config/singleton.d.ts.map +0 -1
  182. package/dist/smtp/index.d.ts +0 -5
  183. package/dist/smtp/index.d.ts.map +0 -1
  184. package/dist/smtp/module.d.ts +0 -4
  185. package/dist/smtp/module.d.ts.map +0 -1
  186. package/dist/smtp/singleton.d.ts +0 -3
  187. package/dist/smtp/singleton.d.ts.map +0 -1
  188. package/dist/smtp/type.d.ts +0 -14
  189. package/dist/smtp/type.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,607 +1,982 @@
1
- import { compare as compare$1, hash as hash$1 } from 'bcrypt';
2
- import { createPrivateKey, generateKeyPair, createPublicKey } from 'node:crypto';
3
- import { isObject, TokenError, KeyType, DomainEventName, buildDomainEventFullName } from '@authup/core';
1
+ import { compare as compare$1, hash as hash$1 } from '@node-rs/bcrypt';
2
+ import { arrayBufferToBase64, base64ToArrayBuffer, isObject as isObject$1 } from '@authup/kit';
3
+ import { JWTAlgorithm, JWTError, JWKType } from '@authup/specs';
4
+ import { subtle } from 'uncrypto';
5
+ import { Algorithm, sign, verify } from '@node-rs/jsonwebtoken';
6
+ import { isObject } from 'smob';
7
+ import { TTLCache } from '@isaacs/ttlcache';
8
+ import { createClient, JsonAdapter, buildKeyPath } from 'redis-extension';
9
+ export { Client as RedisClient, JsonAdapter as RedisJsonAdapter, Watcher as RedisWatcher, buildKeyPath as buildRedisKeyPath, escapeKey as escapeRedisKey, parseKeyPath as parseRedisKeyPath } from 'redis-extension';
4
10
  import path from 'node:path';
5
- import fs from 'node:fs';
6
- import { decode, sign, verify } from 'jsonwebtoken';
7
- import { isObject as isObject$1 } from 'smob';
8
- import { hasClient, hasConfig, useClient } from 'redis-extension';
11
+ import process from 'node:process';
12
+ import { transports, createLogger as createLogger$1, format } from 'winston';
13
+ export { Logger } from 'winston';
14
+ import { singa } from 'singa';
15
+ export { VaultClient, createClient as createVaultClient } from '@hapic/vault';
16
+ import { buildEventFullName } from '@authup/core-realtime-kit';
9
17
  import { Emitter } from '@socket.io/redis-emitter';
10
- import { createTransport, createTestAccount } from 'nodemailer';
11
18
 
12
19
  async function compare(value, hashedValue) {
13
20
  return compare$1(value, hashedValue);
14
21
  }
15
22
 
16
- async function hash(str, saltOrRounds = 10) {
17
- return hash$1(str, saltOrRounds);
23
+ async function hash(str, rounds = 10) {
24
+ return hash$1(str, rounds);
18
25
  }
19
26
 
20
27
  /*
21
- * Copyright (c) 2022.
28
+ * Copyright (c) 2022-2024.
22
29
  * Author Peter Placzek (tada5hi)
23
30
  * For the full copyright and license information,
24
31
  * view the LICENSE file that was distributed with this source code.
25
- */ var KeyPairKind;
26
- (function(KeyPairKind) {
27
- KeyPairKind["PRIVATE"] = "private";
28
- KeyPairKind["PUBLIC"] = "public";
29
- })(KeyPairKind || (KeyPairKind = {}));
30
-
31
- function isKeyPair(data) {
32
- return isObject(data) && typeof data.privateKey !== 'undefined' && typeof data.publicKey !== 'undefined';
33
- }
34
- function isKeyPairWithPublicKey(data) {
35
- return isObject(data) && typeof data.publicKey !== 'undefined';
36
- }
37
-
38
- function extendKeyPairOptions(options) {
39
- var _options;
40
- options = options ?? {};
41
- options.directory = options.directory || process.cwd();
42
- options.directory = path.isAbsolute(options.directory) ? options.directory : path.resolve(process.cwd(), options.directory);
43
- (_options = options).type ?? (_options.type = 'rsa');
44
- if (options.type === 'rsa' || options.type === 'rsa-pss' || options.type === 'dsa') {
45
- options.modulusLength = 2048;
46
- }
47
- if (!options.privateKeyEncoding) {
48
- options.privateKeyEncoding = {
49
- type: 'pkcs8',
50
- format: 'pem'
51
- };
32
+ */ var CryptoAsymmetricAlgorithm = /*#__PURE__*/ function(CryptoAsymmetricAlgorithm) {
33
+ CryptoAsymmetricAlgorithm["RSA_PSS"] = "RSA-PSS";
34
+ CryptoAsymmetricAlgorithm["RSASSA_PKCS1_V1_5"] = "RSASSA-PKCS1-v1_5";
35
+ CryptoAsymmetricAlgorithm["RSA_OAEP"] = "RSA-OAEP";
36
+ CryptoAsymmetricAlgorithm["ECDSA"] = "ECDSA";
37
+ CryptoAsymmetricAlgorithm["ECDH"] = "ECDH";
38
+ return CryptoAsymmetricAlgorithm;
39
+ }({});
40
+
41
+ class BaseKey {
42
+ key;
43
+ // ----------------------------------------------
44
+ constructor(cryptoKey){
45
+ this.key = cryptoKey;
46
+ }
47
+ // ----------------------------------------------
48
+ async toArrayBuffer() {
49
+ if (this.key.type === 'private') {
50
+ return subtle.exportKey('pkcs8', this.key);
51
+ }
52
+ if (this.key.type === 'public') {
53
+ return subtle.exportKey('spki', this.key);
54
+ }
55
+ return subtle.exportKey('raw', this.key);
52
56
  }
53
- if (!options.publicKeyEncoding) {
54
- options.publicKeyEncoding = {
55
- type: 'spki',
56
- format: 'pem'
57
- };
57
+ async toUint8Array() {
58
+ const arrayBuffer = await this.toArrayBuffer();
59
+ return new Uint8Array(arrayBuffer);
58
60
  }
59
- if (options.privateKeyEncoding.passphrase && !options.privateKeyEncoding.cipher) {
60
- options.privateKeyEncoding.cipher = 'aes-256-cbc';
61
+ async toBase64() {
62
+ const arrayBuffer = await this.toArrayBuffer();
63
+ return arrayBufferToBase64(arrayBuffer);
64
+ }
65
+ async toJWK() {
66
+ return subtle.exportKey('jwk', this.key);
61
67
  }
62
- return options;
63
68
  }
64
69
 
65
- function buildKeyFileName(type, context) {
66
- const options = extendKeyPairOptions(context);
67
- const parts = [];
68
- switch(type){
69
- case KeyPairKind.PRIVATE:
70
+ /*
71
+ * Copyright (c) 2024-2024.
72
+ * Author Peter Placzek (tada5hi)
73
+ * For the full copyright and license information,
74
+ * view the LICENSE file that was distributed with this source code.
75
+ */ function enc(type, input) {
76
+ return `-----BEGIN ${type}-----\n${input}\n-----END ${type}-----`;
77
+ }
78
+ function encodePKCS8ToPEM(base64) {
79
+ return enc('PRIVATE KEY', base64);
80
+ }
81
+ function encodeSPKIToPem(input) {
82
+ return enc('PUBLIC KEY', input);
83
+ }
84
+ // ------------------------------------------------------------
85
+ function dec(type, input) {
86
+ input = input.replace(`-----BEGIN ${type}-----\n`, '');
87
+ input = input.replace(`\n-----END ${type}-----\n`, '');
88
+ input = input.replace(`-----END ${type}-----\n`, '');
89
+ input = input.replace(`\n-----END ${type}-----`, '');
90
+ return input;
91
+ }
92
+ function decodePemToPKCS8(input) {
93
+ return dec('PRIVATE KEY', input);
94
+ }
95
+ function decodePemToSpki(input) {
96
+ return dec('PUBLIC KEY', input);
97
+ }
98
+
99
+ /**
100
+ * @see https://nodejs.org/api/webcrypto.html#cryptokeyusages
101
+ */ function getKeyUsagesForAsymmetricAlgorithm(name, format) {
102
+ if (name === CryptoAsymmetricAlgorithm.RSA_PSS || name === CryptoAsymmetricAlgorithm.ECDSA || name === CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5) {
103
+ if (format === 'spki') {
104
+ return [
105
+ 'verify'
106
+ ];
107
+ }
108
+ if (format === 'pkcs8') {
109
+ return [
110
+ 'sign'
111
+ ];
112
+ }
113
+ return [
114
+ 'sign',
115
+ 'verify'
116
+ ];
117
+ }
118
+ if (name === CryptoAsymmetricAlgorithm.ECDH) {
119
+ if (format === 'spki') {
120
+ return [];
121
+ }
122
+ return [
123
+ 'deriveKey',
124
+ 'deriveBits'
125
+ ];
126
+ }
127
+ if (name === CryptoAsymmetricAlgorithm.RSA_OAEP) {
128
+ if (format === 'spki') {
129
+ return [
130
+ 'encrypt'
131
+ ];
132
+ }
133
+ if (format === 'pkcs8') {
134
+ return [
135
+ 'decrypt'
136
+ ];
137
+ }
138
+ return [
139
+ 'encrypt',
140
+ 'decrypt'
141
+ ];
142
+ }
143
+ throw new SyntaxError(`Key usages can not be determined for asymmetric algorithm: ${name}`);
144
+ }
145
+
146
+ function normalizeAsymmetricKeyPairCreateOptions(options) {
147
+ let optionsNormalized;
148
+ switch(options.name){
149
+ case CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5:
150
+ case CryptoAsymmetricAlgorithm.RSA_PSS:
151
+ case CryptoAsymmetricAlgorithm.RSA_OAEP:
70
152
  {
71
- if (options.privateName) {
72
- parts.push(options.privateName);
73
- } else {
74
- parts.push(type);
75
- }
76
- if (options.privateExtension) {
77
- if (options.privateExtension.startsWith('.')) {
78
- options.privateExtension = options.privateExtension.slice(1);
79
- }
80
- parts.push(options.privateExtension);
81
- } else {
82
- parts.push('pem');
83
- }
153
+ optionsNormalized = {
154
+ modulusLength: 2048,
155
+ publicExponent: new Uint8Array([
156
+ 0x01,
157
+ 0x00,
158
+ 0x01
159
+ ]),
160
+ hash: 'SHA-256',
161
+ ...options
162
+ };
84
163
  break;
85
164
  }
86
- case KeyPairKind.PUBLIC:
165
+ case CryptoAsymmetricAlgorithm.ECDSA:
166
+ case CryptoAsymmetricAlgorithm.ECDH:
87
167
  {
88
- if (options.publicName) {
89
- parts.push(options.publicName);
90
- } else {
91
- parts.push(type);
92
- }
93
- if (options.publicExtension) {
94
- if (options.publicExtension.startsWith('.')) {
95
- options.publicExtension = options.publicExtension.slice(1);
96
- }
97
- parts.push(options.publicExtension);
98
- } else {
99
- parts.push('pem');
100
- }
101
- break;
168
+ optionsNormalized = {
169
+ namedCurve: 'P-256',
170
+ ...options
171
+ };
102
172
  }
103
173
  }
104
- return parts.join('.');
174
+ return optionsNormalized;
105
175
  }
106
-
107
- function decryptRSAPrivateKey(context, key) {
108
- const privateKey = createPrivateKey({
109
- type: context.privateKeyEncoding.type,
110
- format: context.privateKeyEncoding.format,
111
- key,
112
- passphrase: context.privateKeyEncoding.passphrase || context.passphrase
113
- });
114
- let content = privateKey.export({
115
- type: context.privateKeyEncoding.type,
116
- format: context.privateKeyEncoding.format
117
- });
118
- if (typeof content !== 'string') {
119
- content = Buffer.from(content).toString('utf-8');
176
+ function normalizeAsymmetricKeyImportOptions(options) {
177
+ let optionsNormalized;
178
+ switch(options.name){
179
+ case CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5:
180
+ case CryptoAsymmetricAlgorithm.RSA_PSS:
181
+ case CryptoAsymmetricAlgorithm.RSA_OAEP:
182
+ {
183
+ optionsNormalized = {
184
+ hash: 'SHA-256',
185
+ ...options
186
+ };
187
+ break;
188
+ }
189
+ case CryptoAsymmetricAlgorithm.ECDSA:
190
+ case CryptoAsymmetricAlgorithm.ECDH:
191
+ {
192
+ optionsNormalized = {
193
+ namedCurve: 'P-256',
194
+ ...options
195
+ };
196
+ }
120
197
  }
121
- return content;
198
+ return optionsNormalized;
122
199
  }
123
200
 
124
- async function saveKeyPair(keyPair, context) {
125
- context = extendKeyPairOptions(context);
126
- await fs.promises.mkdir(context.directory, {
127
- recursive: true
128
- });
129
- await Promise.all([
130
- {
131
- path: path.resolve(context.directory, buildKeyFileName(KeyPairKind.PRIVATE, context)),
132
- content: keyPair.privateKey
133
- },
134
- {
135
- path: path.resolve(context.directory, buildKeyFileName(KeyPairKind.PUBLIC, context)),
136
- content: keyPair.publicKey
137
- }
138
- ].map((file)=>fs.promises.writeFile(file.path, file.content)));
139
- return keyPair;
140
- }
141
-
142
- async function createKeyPair(context) {
143
- const options = extendKeyPairOptions(context);
144
- const keyPair = await new Promise((resolve, reject)=>{
145
- const callback = (err, publicKey, privateKey)=>{
146
- if (err) reject(err);
147
- resolve({
148
- privateKey,
149
- publicKey
201
+ class AsymmetricKey extends BaseKey {
202
+ async toPem() {
203
+ const base64 = await this.toBase64();
204
+ if (this.key.type === 'public') {
205
+ return encodeSPKIToPem(base64);
206
+ }
207
+ if (this.key.type === 'private') {
208
+ return encodePKCS8ToPEM(base64);
209
+ }
210
+ throw new Error(`${this.key.type} can not be converted to pem.`);
211
+ }
212
+ // ----------------------------------------------------------------
213
+ static async fromPem(ctx) {
214
+ if (ctx.format === 'pkcs8') {
215
+ return AsymmetricKey.fromBase64({
216
+ ...ctx,
217
+ key: decodePemToPKCS8(ctx.key)
150
218
  });
151
- };
152
- switch(options.type){
153
- case 'dsa':
154
- generateKeyPair(options.type, options, callback);
155
- break;
156
- case 'ec':
157
- generateKeyPair(options.type, options, callback);
158
- break;
159
- case 'rsa':
160
- generateKeyPair(options.type, options, callback);
161
- break;
162
- case 'rsa-pss':
163
- generateKeyPair(options.type, options, callback);
164
- break;
165
219
  }
166
- });
167
- if (options.save) {
168
- await saveKeyPair(keyPair, options);
220
+ return AsymmetricKey.fromBase64({
221
+ ...ctx,
222
+ key: decodePemToSpki(ctx.key)
223
+ });
224
+ }
225
+ static async fromBase64(ctx) {
226
+ const arrayBuffer = base64ToArrayBuffer(ctx.key);
227
+ return AsymmetricKey.fromArrayBuffer({
228
+ ...ctx,
229
+ key: arrayBuffer
230
+ });
169
231
  }
170
- if (options.passphrase || options.privateKeyEncoding.passphrase) {
171
- keyPair.privateKey = decryptRSAPrivateKey(options, keyPair.privateKey);
232
+ static async fromArrayBuffer(ctx) {
233
+ const normalizedOptions = normalizeAsymmetricKeyImportOptions(ctx.options);
234
+ const cryptoKey = await subtle.importKey(ctx.format, ctx.key, normalizedOptions, true, getKeyUsagesForAsymmetricAlgorithm(normalizedOptions.name, ctx.format));
235
+ return new AsymmetricKey(cryptoKey);
236
+ }
237
+ // ----------------------------------------------------------------
238
+ static buildImportOptionsForJWTAlgorithm(alg) {
239
+ if (alg === JWTAlgorithm.RS256) {
240
+ return {
241
+ name: CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5,
242
+ hash: 'SHA-256'
243
+ };
244
+ }
245
+ if (alg === JWTAlgorithm.RS384) {
246
+ return {
247
+ name: CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5,
248
+ hash: 'SHA-384'
249
+ };
250
+ }
251
+ if (alg === JWTAlgorithm.RS512) {
252
+ return {
253
+ name: CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5,
254
+ hash: 'SHA-512'
255
+ };
256
+ }
257
+ if (alg === JWTAlgorithm.ES256) {
258
+ return {
259
+ name: CryptoAsymmetricAlgorithm.ECDSA,
260
+ namedCurve: 'P-256'
261
+ };
262
+ }
263
+ if (alg === JWTAlgorithm.ES384) {
264
+ return {
265
+ name: CryptoAsymmetricAlgorithm.ECDSA,
266
+ namedCurve: 'P-384'
267
+ };
268
+ }
269
+ if (alg === JWTAlgorithm.ES512) {
270
+ return {
271
+ name: CryptoAsymmetricAlgorithm.ECDSA,
272
+ namedCurve: 'P-521'
273
+ };
274
+ }
275
+ throw new Error(`Signature algorithm ${alg} is not supported.`);
172
276
  }
173
- return keyPair;
174
277
  }
175
278
 
176
- async function deleteKeyPair(context) {
177
- const options = extendKeyPairOptions(context);
178
- const privateKeyPath = path.resolve(options.directory, buildKeyFileName(KeyPairKind.PRIVATE, options));
179
- const publicKeyPath = path.resolve(options.directory, buildKeyFileName(KeyPairKind.PUBLIC, options));
180
- try {
181
- await Promise.all([
182
- privateKeyPath,
183
- publicKeyPath
184
- ].map((filePath)=>fs.promises.stat(filePath)));
185
- } catch (e) {
186
- return;
187
- }
188
- await Promise.all([
189
- privateKeyPath,
190
- publicKeyPath
191
- ].map((filePath)=>fs.promises.rm(filePath)));
279
+ function isAsymmetricAlgorithm(input) {
280
+ return Object.values(CryptoAsymmetricAlgorithm).includes(input);
192
281
  }
193
282
 
194
- async function loadKeyPair(context) {
195
- const options = extendKeyPairOptions(context);
196
- const privateKeyPath = path.resolve(options.directory, buildKeyFileName(KeyPairKind.PRIVATE, options));
197
- try {
198
- await fs.promises.stat(privateKeyPath);
199
- } catch (e) {
200
- return undefined;
283
+ async function createAsymmetricKeyPair(options) {
284
+ const optionsNormalized = normalizeAsymmetricKeyPairCreateOptions(options);
285
+ return subtle.generateKey(optionsNormalized, true, getKeyUsagesForAsymmetricAlgorithm(optionsNormalized.name));
286
+ }
287
+
288
+ /*
289
+ * Copyright (c) 2024.
290
+ * Author Peter Placzek (tada5hi)
291
+ * For the full copyright and license information,
292
+ * view the LICENSE file that was distributed with this source code.
293
+ */ var SymmetricAlgorithm = /*#__PURE__*/ function(SymmetricAlgorithm) {
294
+ SymmetricAlgorithm["HMAC"] = "HMAC";
295
+ SymmetricAlgorithm["AES_CTR"] = "AES-CTR";
296
+ SymmetricAlgorithm["AES_CBC"] = "AES-CBC";
297
+ SymmetricAlgorithm["AES_GCM"] = "AES-GCM";
298
+ return SymmetricAlgorithm;
299
+ }({});
300
+
301
+ function isSymmetricAlgorithm(input) {
302
+ return Object.values(SymmetricAlgorithm).includes(input);
303
+ }
304
+
305
+ function getKeyUsagesForSymmetricAlgorithm(name) {
306
+ /**
307
+ * @see https://nodejs.org/api/webcrypto.html#cryptokeyusages
308
+ */ if (name === SymmetricAlgorithm.HMAC) {
309
+ return [
310
+ 'sign',
311
+ 'verify'
312
+ ];
313
+ }
314
+ if (name === SymmetricAlgorithm.AES_CBC || name === SymmetricAlgorithm.AES_GCM || name === SymmetricAlgorithm.AES_CTR) {
315
+ return [
316
+ 'encrypt',
317
+ 'decrypt'
318
+ ];
319
+ }
320
+ throw new SyntaxError(`Key usages can not be determined for symmetric algorithm: ${name}`);
321
+ }
322
+
323
+ function normalizeSymmetricKeyCreateOptions(input) {
324
+ if (input.name === SymmetricAlgorithm.HMAC) {
325
+ return {
326
+ hash: 'SHA-256',
327
+ ...input
328
+ };
201
329
  }
202
- const privateKeyBuffer = await fs.promises.readFile(privateKeyPath);
203
- let privateKey = privateKeyBuffer.toString();
204
- if (options.passphrase || options.privateKeyEncoding.passphrase) {
205
- privateKey = decryptRSAPrivateKey(options, privateKey);
330
+ return {
331
+ length: 256,
332
+ name: input.name
333
+ };
334
+ }
335
+ function normalizeSymmetricKeyImportOptions(input) {
336
+ if (input.name === SymmetricAlgorithm.HMAC) {
337
+ return {
338
+ hash: 'SHA-256',
339
+ ...input
340
+ };
206
341
  }
207
- const publicKeyPath = path.resolve(options.directory, buildKeyFileName(KeyPairKind.PUBLIC, options));
208
- let publicKey;
209
- try {
210
- await fs.promises.stat(publicKeyPath);
211
- const publicKeyBuffer = await fs.promises.readFile(publicKeyPath);
212
- publicKey = publicKeyBuffer.toString();
213
- } catch (e) {
214
- const publicKeyObject = createPublicKey({
215
- key: privateKey,
216
- format: options.privateKeyEncoding.format,
217
- type: options.publicKeyEncoding.type
218
- });
219
- const stringOrBuffer = publicKeyObject.export({
220
- format: options.publicKeyEncoding.format,
221
- type: options.publicKeyEncoding.type
342
+ return input;
343
+ }
344
+
345
+ class SymmetricKey extends BaseKey {
346
+ static async fromBase64(ctx) {
347
+ const arrayBuffer = base64ToArrayBuffer(ctx.key);
348
+ return SymmetricKey.fromArrayBuffer({
349
+ ...ctx,
350
+ key: arrayBuffer
222
351
  });
223
- if (typeof stringOrBuffer !== 'string') {
224
- publicKey = stringOrBuffer.toString();
225
- } else {
226
- publicKey = stringOrBuffer;
352
+ }
353
+ static async fromArrayBuffer(ctx) {
354
+ const normalizedOptions = normalizeSymmetricKeyImportOptions(ctx.options);
355
+ const cryptoKey = await subtle.importKey(ctx.format, ctx.key, normalizedOptions, true, getKeyUsagesForSymmetricAlgorithm(normalizedOptions.name));
356
+ return new SymmetricKey(cryptoKey);
357
+ }
358
+ static buildImportOptionsForJWTAlgorithm(alg) {
359
+ if (alg === JWTAlgorithm.HS256) {
360
+ return {
361
+ name: SymmetricAlgorithm.HMAC,
362
+ hash: 'SHA-256'
363
+ };
364
+ }
365
+ if (alg === JWTAlgorithm.HS384) {
366
+ return {
367
+ name: SymmetricAlgorithm.HMAC,
368
+ hash: 'SHA-384'
369
+ };
227
370
  }
228
- if (options.save) {
229
- await saveKeyPair({
230
- privateKey,
231
- publicKey
232
- }, options);
371
+ if (alg === JWTAlgorithm.HS512) {
372
+ return {
373
+ name: SymmetricAlgorithm.HMAC,
374
+ hash: 'SHA-512'
375
+ };
233
376
  }
377
+ throw new Error(`Signature algorithm ${alg} is not supported.`);
234
378
  }
235
- return {
236
- privateKey,
237
- publicKey
238
- };
239
379
  }
240
380
 
241
- const keyPairCache = {};
242
- async function useKeyPair(value) {
243
- let options;
244
- if (typeof value === 'string') {
245
- options = extendKeyPairOptions({
246
- privateName: value
247
- });
248
- } else {
249
- options = extendKeyPairOptions(value || {});
250
- }
251
- if (Object.prototype.hasOwnProperty.call(keyPairCache, options.privateName)) {
252
- return keyPairCache[options.privateName];
381
+ async function createSymmetricKey(input) {
382
+ const optionsNormalized = normalizeSymmetricKeyCreateOptions(input);
383
+ return subtle.generateKey(optionsNormalized, true, getKeyUsagesForSymmetricAlgorithm(optionsNormalized.name));
384
+ }
385
+
386
+ /**
387
+ * Decode a JWT token with no verification.
388
+ *
389
+ * @param token
390
+ *
391
+ * @throws JWTError
392
+ */ function extractTokenHeader(token) {
393
+ const parts = token.split('.');
394
+ if (parts.length !== 3) {
395
+ throw JWTError.invalid();
396
+ }
397
+ const [headerBase64] = parts;
398
+ try {
399
+ const payload = atob(headerBase64);
400
+ return JSON.parse(payload);
401
+ /*
402
+ return {
403
+ typ: 'JWT',
404
+ alg: transformInternalToJWTAlgorithm(header.algorithm),
405
+ cty: header.contentType,
406
+ jku: header.jsonKeyUrl,
407
+ kid: header.keyId,
408
+ x5u: header.x5Url,
409
+ x5c: header.x5CertChain,
410
+ x5t: header.x5CertThumbprint,
411
+ 'x5t#S256': header.x5TS256CertThumbprint,
412
+ };
413
+ */ } catch {
414
+ throw JWTError.headerInvalid('The token header could not be extracted.');
253
415
  }
254
- let keyPair = await loadKeyPair(options);
255
- if (typeof keyPair === 'undefined') {
256
- keyPair = await createKeyPair(options);
416
+ }
417
+ /**
418
+ * @param token
419
+ *
420
+ * @throws JWTError
421
+ */ function extractTokenPayload(token) {
422
+ const parts = token.split('.');
423
+ if (parts.length !== 3) {
424
+ throw JWTError.invalid();
425
+ }
426
+ const [, payloadBase64] = parts;
427
+ try {
428
+ const payload = atob(payloadBase64);
429
+ return JSON.parse(payload);
430
+ } catch {
431
+ throw JWTError.payloadInvalid('The token payload could not be extracted.');
257
432
  }
258
- keyPairCache[options.privateName] = keyPair;
259
- return keyPair;
260
433
  }
261
434
 
262
435
  function createErrorForJWTError(e) {
263
- if (isObject$1(e) && typeof e.name === 'string') {
264
- switch(e.name){
265
- case 'TokenExpiredError':
436
+ if (isObject(e)) {
437
+ if (typeof e.name === 'string') {
438
+ switch(e.name){
439
+ case 'TokenExpiredError':
440
+ {
441
+ return JWTError.expired();
442
+ }
443
+ case 'NotBeforeError':
444
+ {
445
+ if (typeof e.date === 'string' || e.date instanceof Date) {
446
+ return JWTError.notActiveBefore(e.date);
447
+ }
448
+ break;
449
+ }
450
+ case 'JsonWebTokenError':
451
+ {
452
+ if (typeof e.message === 'string') {
453
+ return JWTError.payloadInvalid(e.message);
454
+ }
455
+ break;
456
+ }
457
+ }
458
+ }
459
+ // @see https://github.com/Keats/jsonwebtoken/blob/master/src/errors.rs
460
+ switch(e.message){
461
+ case 'ExpiredSignature':
266
462
  {
267
- return TokenError.expired();
463
+ return JWTError.expired();
268
464
  }
269
- case 'NotBeforeError':
465
+ case 'ImmatureSignature':
270
466
  {
271
- if (typeof e.date === 'string' || e.date instanceof Date) {
272
- return TokenError.notActiveBefore(e.date);
273
- }
274
- break;
467
+ return JWTError.notActiveBefore();
275
468
  }
276
- case 'JsonWebTokenError':
469
+ case 'InvalidToken':
470
+ case 'InvalidSignature':
277
471
  {
278
- if (typeof e.message === 'string') {
279
- return TokenError.payloadInvalid(e.message);
280
- }
281
- break;
472
+ return JWTError.payloadInvalid();
282
473
  }
283
474
  }
284
475
  }
285
- return new TokenError({
476
+ return new JWTError({
286
477
  cause: e,
287
478
  logMessage: true,
288
479
  message: 'The JWT error could not be determined.'
289
480
  });
290
481
  }
291
-
292
- function decodeToken(token, options) {
293
- options ?? (options = {});
294
- let output;
295
- try {
296
- output = decode(token, {
297
- ...options
298
- });
299
- } catch (e) {
300
- throw createErrorForJWTError(e);
301
- }
302
- if (output === null) {
303
- throw TokenError.payloadInvalid('The token could not be decoded.');
482
+ function transformJWTAlgorithmToInternal(algorithm) {
483
+ switch(algorithm){
484
+ case JWTAlgorithm.HS256:
485
+ {
486
+ return Algorithm.HS256;
487
+ }
488
+ case JWTAlgorithm.HS384:
489
+ {
490
+ return Algorithm.HS384;
491
+ }
492
+ case JWTAlgorithm.HS512:
493
+ {
494
+ return Algorithm.HS512;
495
+ }
496
+ case JWTAlgorithm.RS256:
497
+ {
498
+ return Algorithm.RS256;
499
+ }
500
+ case JWTAlgorithm.RS384:
501
+ {
502
+ return Algorithm.RS384;
503
+ }
504
+ case JWTAlgorithm.RS512:
505
+ {
506
+ return Algorithm.RS512;
507
+ }
508
+ case JWTAlgorithm.ES256:
509
+ {
510
+ return Algorithm.ES256;
511
+ }
512
+ case JWTAlgorithm.ES384:
513
+ {
514
+ return Algorithm.ES384;
515
+ }
516
+ case JWTAlgorithm.PS256:
517
+ {
518
+ return Algorithm.PS256;
519
+ }
520
+ case JWTAlgorithm.PS384:
521
+ {
522
+ return Algorithm.PS384;
523
+ }
524
+ case JWTAlgorithm.PS512:
525
+ {
526
+ return Algorithm.PS512;
527
+ }
304
528
  }
305
- return output;
529
+ throw new Error(`The algorithm ${algorithm} is not supported.`);
306
530
  }
307
531
 
308
- async function signToken(payload, context) {
309
- context.expiresIn = context.expiresIn || 3600;
532
+ const getUtcTimestamp = ()=>Math.floor(new Date().getTime() / 1000);
533
+ async function signToken(claims, context) {
534
+ if (typeof claims.exp !== 'number') {
535
+ claims.exp = getUtcTimestamp() + 3600;
536
+ }
537
+ if (typeof claims.iat !== 'number') {
538
+ claims.iat = getUtcTimestamp();
539
+ }
310
540
  switch(context.type){
311
- case KeyType.RSA:
312
- case KeyType.EC:
541
+ case JWKType.RSA:
542
+ case JWKType.EC:
313
543
  {
314
- const { type, keyPair, ...options } = context;
315
- const { privateKey } = isKeyPair(keyPair) ? keyPair : await useKeyPair(keyPair);
316
- if (type === KeyType.RSA) {
317
- options.algorithm = options.algorithm || 'RS256';
544
+ let algorithm;
545
+ let key;
546
+ if (typeof context.key === 'string') {
547
+ key = encodePKCS8ToPEM(context.key);
548
+ } else {
549
+ const keyContainer = new AsymmetricKey(context.key);
550
+ key = await keyContainer.toPem();
551
+ }
552
+ if (context.type === JWKType.RSA) {
553
+ algorithm = context.algorithm ? transformJWTAlgorithmToInternal(context.algorithm) : Algorithm.RS256;
318
554
  } else {
319
- options.algorithm = options.algorithm || 'ES256';
555
+ algorithm = context.algorithm ? transformJWTAlgorithmToInternal(context.algorithm) : Algorithm.ES256;
320
556
  }
321
- return sign(payload, privateKey, options);
557
+ return sign(claims, key, {
558
+ algorithm,
559
+ keyId: context.keyId
560
+ });
322
561
  }
323
- case KeyType.OCT:
562
+ case JWKType.OCT:
324
563
  {
325
- const { type, secret, ...options } = context;
326
- options.algorithm = options.algorithm || 'HS256';
327
- return sign(payload, secret, options);
564
+ const algorithm = context.algorithm ? transformJWTAlgorithmToInternal(context.algorithm) : Algorithm.HS256;
565
+ let key;
566
+ if (typeof context.key === 'string') {
567
+ key = context.key;
568
+ } else {
569
+ const keyContainer = new SymmetricKey(context.key);
570
+ key = await keyContainer.toUint8Array();
571
+ }
572
+ return sign(claims, key, {
573
+ algorithm,
574
+ keyId: context.keyId
575
+ });
328
576
  }
329
577
  }
330
- throw new TokenError();
578
+ throw new JWTError();
331
579
  }
332
580
 
333
- async function verifyToken(token, context) {
581
+ /**
582
+ * Verify JWT.
583
+ *
584
+ * @param token
585
+ * @param context
586
+ *
587
+ * @throws OAuth2Error
588
+ */ async function verifyToken(token, context) {
334
589
  let promise;
335
590
  let output;
336
591
  try {
337
592
  switch(context.type){
338
- case KeyType.RSA:
339
- case KeyType.EC:
593
+ case JWKType.RSA:
594
+ case JWKType.EC:
340
595
  {
341
- const { type, keyPair, ...options } = context;
342
- const { publicKey } = isKeyPairWithPublicKey(keyPair) ? keyPair : await useKeyPair(keyPair);
343
- if (type === KeyType.RSA) {
344
- options.algorithms = options.algorithms || [
345
- 'RS256',
346
- 'RS384',
347
- 'RS512',
348
- 'PS256',
349
- 'PS384',
350
- 'PS512'
596
+ let algorithms;
597
+ if (context.type === JWKType.RSA) {
598
+ algorithms = context.algorithms ? context.algorithms.map((algorithm)=>transformJWTAlgorithmToInternal(algorithm)) : [
599
+ Algorithm.RS256,
600
+ Algorithm.RS384,
601
+ Algorithm.RS512,
602
+ Algorithm.PS256,
603
+ Algorithm.PS384,
604
+ Algorithm.PS512
351
605
  ];
352
606
  } else {
353
- options.algorithms = options.algorithms || [
354
- 'ES256',
355
- 'ES384',
356
- 'ES512'
607
+ algorithms = context.algorithms ? context.algorithms.map((algorithm)=>transformJWTAlgorithmToInternal(algorithm)) : [
608
+ Algorithm.ES256,
609
+ Algorithm.ES384
357
610
  ];
358
611
  }
359
- promise = new Promise((resolve, reject)=>{
360
- verify(token, publicKey, options, (err, decoded)=>{
361
- if (err) {
362
- reject(err);
363
- return;
364
- }
365
- resolve(decoded);
366
- });
612
+ let key;
613
+ if (typeof context.key === 'string') {
614
+ key = encodeSPKIToPem(context.key);
615
+ } else {
616
+ const keyContainer = new AsymmetricKey(context.key);
617
+ key = await keyContainer.toPem();
618
+ }
619
+ promise = verify(token, key, {
620
+ algorithms,
621
+ validateNbf: true
367
622
  });
368
623
  break;
369
624
  }
370
- case KeyType.OCT:
625
+ case JWKType.OCT:
371
626
  {
372
- const { type, secret, ...options } = context;
373
- options.algorithms = options.algorithms || [
374
- 'HS256',
375
- 'HS384',
376
- 'HS512'
627
+ const algorithms = context.algorithms ? context.algorithms.map((algorithm)=>transformJWTAlgorithmToInternal(algorithm)) : [
628
+ Algorithm.HS256,
629
+ Algorithm.HS384,
630
+ Algorithm.HS512
377
631
  ];
378
- promise = new Promise((resolve, reject)=>{
379
- verify(token, secret, options, (err, decoded)=>{
380
- if (err) {
381
- reject(err);
382
- return;
383
- }
384
- resolve(decoded);
385
- });
632
+ let key;
633
+ if (typeof context.key === 'string') {
634
+ key = context.key;
635
+ } else {
636
+ const keyContainer = new SymmetricKey(context.key);
637
+ key = await keyContainer.toUint8Array();
638
+ }
639
+ promise = verify(token, key, {
640
+ algorithms,
641
+ validateNbf: true
386
642
  });
387
643
  }
388
644
  }
389
- output = await promise;
645
+ if (promise) {
646
+ output = await promise;
647
+ }
390
648
  } catch (e) {
391
649
  throw createErrorForJWTError(e);
392
650
  }
393
- if (typeof output === 'undefined') {
394
- throw new TokenError({
395
- message: 'Invalid type.'
396
- });
651
+ if (!output) {
652
+ throw new JWTError();
397
653
  }
398
654
  return output;
399
655
  }
400
656
 
401
- function transformDomainEventData(input) {
402
- if (isObject(input)) {
403
- const keys = Object.keys(input);
404
- for(let i = 0; i < keys.length; i++){
405
- const value = input[keys[i]];
406
- if (value instanceof Date) {
407
- input[keys[i]] = value.toISOString();
657
+ /*
658
+ * Copyright (c) 2024-2024.
659
+ * Author Peter Placzek (tada5hi)
660
+ * For the full copyright and license information,
661
+ * view the LICENSE file that was distributed with this source code.
662
+ */ class DomainEventPublisher {
663
+ publishers;
664
+ constructor(){
665
+ this.publishers = new Set();
666
+ }
667
+ mount(publisher) {
668
+ this.publishers.add(publisher);
669
+ }
670
+ async publish(ctx) {
671
+ const publishers = this.publishers.values();
672
+ while(true){
673
+ const it = publishers.next();
674
+ if (it.done) {
675
+ return;
408
676
  }
677
+ await it.value.publish(ctx);
409
678
  }
410
679
  }
411
- return input;
412
- }
413
- function buildDomainEventChannelName(input, id) {
414
- if (typeof input === 'string') {
415
- return input;
416
- }
417
- return input(id);
418
680
  }
419
681
 
420
- async function publishDomainRedisEvent(context, destinations) {
421
- if (!hasClient() && !hasConfig()) {
422
- return Promise.resolve();
682
+ class MemoryCache {
683
+ instance;
684
+ constructor(options = {}){
685
+ this.instance = new TTLCache({
686
+ checkAgeOnGet: true,
687
+ ttl: Infinity,
688
+ ...options || {}
689
+ });
423
690
  }
424
- context = transformDomainEventData(context);
425
- const json = JSON.stringify(context);
426
- const client = useClient();
427
- const pipeline = client.pipeline();
428
- for(let i = 0; i < destinations.length; i++){
429
- const { namespace } = destinations[i];
430
- const keyPrefix = namespace ? `${namespace}:` : '';
431
- let key = keyPrefix + buildDomainEventChannelName(destinations[i].channel);
432
- pipeline.publish(key, json);
433
- if (context.event !== DomainEventName.CREATED && typeof destinations[i].channel === 'function') {
434
- key = keyPrefix + buildDomainEventChannelName(destinations[i].channel, context.data.id);
435
- pipeline.publish(key, json);
691
+ async pop(key) {
692
+ if (this.instance.has(key)) {
693
+ const output = this.instance.get(key);
694
+ this.instance.delete(key);
695
+ return output;
436
696
  }
697
+ return null;
437
698
  }
438
- return pipeline.exec();
439
- }
440
-
441
- let instance$3;
442
- function useSocketEmitter() {
443
- if (typeof instance$3 !== 'undefined') {
444
- return instance$3;
445
- }
446
- instance$3 = new Emitter(useClient());
447
- return instance$3;
448
- }
449
-
450
- function publishDomainSocketEvent(context, destinations) {
451
- if (!hasClient() && !hasConfig()) {
452
- return;
699
+ async has(key) {
700
+ return this.instance.has(key);
453
701
  }
454
- context = transformDomainEventData(context);
455
- for(let i = 0; i < destinations.length; i++){
456
- let emitter = useSocketEmitter();
457
- if (destinations[i].namespace) {
458
- emitter = emitter.of(destinations[i].namespace);
702
+ async get(key) {
703
+ const output = await this.instance.get(key);
704
+ if (output) {
705
+ return output;
459
706
  }
460
- let roomName = buildDomainEventChannelName(destinations[i].channel);
461
- const fullEventName = buildDomainEventFullName(context.type, context.event);
462
- emitter.in(roomName)// eslint-disable-next-line @typescript-eslint/ban-ts-comment
463
- // @ts-ignore
464
- .emit(fullEventName, {
465
- ...context,
466
- meta: {
467
- roomName
468
- }
707
+ return null;
708
+ }
709
+ async set(key, value, options) {
710
+ this.instance.set(key, value, {
711
+ ttl: options.ttl
469
712
  });
470
- if (context.event !== DomainEventName.CREATED && typeof destinations[i].channel === 'function') {
471
- roomName = buildDomainEventChannelName(destinations[i].channel, context.data.id);
472
- emitter.in(roomName)// eslint-disable-next-line @typescript-eslint/ban-ts-comment
473
- // @ts-ignore
474
- .emit(fullEventName, {
475
- ...context,
476
- meta: {
477
- roomName,
478
- roomId: context.data.id
713
+ }
714
+ async drop(key) {
715
+ this.instance.delete(key);
716
+ }
717
+ async dropMany(keys) {
718
+ for (const key of keys){
719
+ this.instance.delete(key);
720
+ }
721
+ }
722
+ async clear(options = {}) {
723
+ if (options.prefix) {
724
+ const keys = this.instance.keys();
725
+ let iterator = keys.next();
726
+ while(!iterator.done){
727
+ if (typeof iterator.value !== 'string') {
728
+ continue;
479
729
  }
480
- });
730
+ if (iterator.value.startsWith(options.prefix)) {
731
+ this.instance.delete(iterator.value);
732
+ }
733
+ iterator = keys.next();
734
+ }
735
+ return;
481
736
  }
737
+ this.instance.clear();
482
738
  }
483
739
  }
484
740
 
485
- async function publishDomainEvent(context, destinations) {
486
- await publishDomainRedisEvent(context, destinations);
487
- publishDomainSocketEvent(context, destinations);
741
+ function isRedisClient(data) {
742
+ return isObject(data) && typeof data.connect === 'function' && typeof data.disconnect === 'function';
488
743
  }
489
744
 
490
- /*
491
- * Copyright (c) 2022.
492
- * Author Peter Placzek (tada5hi)
493
- * For the full copyright and license information,
494
- * view the LICENSE file that was distributed with this source code.
495
- */ class VoidLogger {
496
- error() {
497
- return this;
745
+ function createRedisClient(input) {
746
+ if (typeof input === 'boolean') {
747
+ return createClient({
748
+ connectionString: 'redis://127.0.0.1'
749
+ });
750
+ }
751
+ if (typeof input === 'string') {
752
+ return createClient({
753
+ connectionString: input
754
+ });
755
+ }
756
+ if (!isRedisClient(input)) {
757
+ return createClient({
758
+ options: input
759
+ });
760
+ }
761
+ return input;
762
+ }
763
+
764
+ class RedisCache {
765
+ client;
766
+ jsonAdapter;
767
+ constructor(input){
768
+ this.client = createRedisClient(input);
769
+ this.jsonAdapter = new JsonAdapter(this.client);
770
+ }
771
+ async get(key) {
772
+ const output = await this.jsonAdapter.get(key);
773
+ if (output) {
774
+ return output;
775
+ }
776
+ return null;
498
777
  }
499
- warn() {
500
- return this;
778
+ async pop(key) {
779
+ const raw = await this.client.getdel(key);
780
+ if (!raw) {
781
+ return null;
782
+ }
783
+ try {
784
+ return JSON.parse(raw);
785
+ } catch {
786
+ return null;
787
+ }
501
788
  }
502
- info() {
503
- return this;
789
+ async has(key) {
790
+ const output = await this.get(key);
791
+ return !!output;
504
792
  }
505
- http() {
506
- return this;
793
+ async set(key, value, options) {
794
+ await this.jsonAdapter.set(key, value, {
795
+ milliseconds: options.ttl
796
+ });
507
797
  }
508
- verbose() {
509
- return this;
798
+ async drop(key) {
799
+ await this.jsonAdapter.drop(key);
510
800
  }
511
- debug() {
512
- return this;
801
+ async dropMany(keys) {
802
+ const pipeline = this.client.pipeline();
803
+ for (const key of keys){
804
+ pipeline.del(key);
805
+ }
806
+ await pipeline.exec();
807
+ }
808
+ async clear(options = {}) {
809
+ if (options.prefix) {
810
+ const pipeline = this.client.pipeline();
811
+ const keys = await this.client.keys(`${options.prefix}*`);
812
+ for (const key of keys){
813
+ pipeline.del(key);
814
+ }
815
+ await pipeline.exec();
816
+ return;
817
+ }
818
+ await this.client.flushdb();
513
819
  }
514
820
  }
515
821
 
516
- let instance$2;
517
- function useLogger() {
518
- if (typeof instance$2 !== 'undefined') {
519
- return instance$2;
520
- }
521
- instance$2 = new VoidLogger();
522
- return instance$2;
822
+ function buildCacheKey(options) {
823
+ return buildKeyPath(options);
523
824
  }
524
- function setLogger(logger) {
525
- instance$2 = logger;
825
+
826
+ function createNoopLogger() {
827
+ return createLogger$1({
828
+ silent: true
829
+ });
830
+ }
831
+ function createLogger(context) {
832
+ let items;
833
+ const cwd = context.directory || process.cwd();
834
+ if (context.env === 'production') {
835
+ items = [
836
+ new transports.Console({
837
+ level: 'info'
838
+ }),
839
+ new transports.File({
840
+ filename: path.join(cwd, 'http.log'),
841
+ level: 'http',
842
+ maxsize: 10 * 1024 * 1024,
843
+ maxFiles: 5
844
+ }),
845
+ new transports.File({
846
+ filename: path.join(cwd, 'error.log'),
847
+ level: 'warn',
848
+ maxsize: 10 * 1024 * 1024,
849
+ maxFiles: 5
850
+ })
851
+ ];
852
+ } else {
853
+ items = [
854
+ new transports.Console({
855
+ level: 'debug'
856
+ })
857
+ ];
858
+ }
859
+ // @see https://github.com/winstonjs/triple-beam/blob/master/config/npm.js
860
+ return createLogger$1({
861
+ format: format.combine(format.errors({
862
+ stack: true
863
+ }), format.timestamp(), format.colorize(), format.simple()),
864
+ transports: items
865
+ });
526
866
  }
527
867
 
528
- /*
529
- * Copyright (c) 2022.
530
- * Author Peter Placzek (tada5hi)
531
- * For the full copyright and license information,
532
- * view the LICENSE file that was distributed with this source code.
533
- */ let instance$1;
534
- function hasSmtpConfig() {
535
- return !!instance$1;
868
+ const instance$1 = singa({
869
+ name: 'logger'
870
+ });
871
+ function setLoggerFactory(factory) {
872
+ instance$1.setFactory(factory);
536
873
  }
537
- function setSmtpConfig(value) {
538
- instance$1 = value;
874
+ function isLoggerUsable() {
875
+ return instance$1.has() || instance$1.hasFactory();
539
876
  }
540
- function useSmtpConfig() {
541
- if (typeof instance$1 !== 'undefined') {
542
- return instance$1;
543
- }
544
- instance$1 = {};
545
- return instance$1;
877
+ function setLogger(input) {
878
+ instance$1.set(input);
879
+ }
880
+ function useLogger() {
881
+ return instance$1.use();
546
882
  }
547
883
 
548
- function createSmtpClient(options) {
549
- let transport;
550
- options = options || {};
551
- if (typeof options === 'string') {
552
- transport = createTransport(options);
553
- } else if (options.connectionString) {
554
- transport = createTransport(options.connectionString);
555
- } else {
556
- let auth;
557
- if (options.user && options.password) {
558
- auth = {
559
- type: 'login',
560
- user: options.user,
561
- pass: options.password
562
- };
884
+ const instance = singa({
885
+ name: 'vault'
886
+ });
887
+ function setVaultFactory(factory) {
888
+ instance.setFactory(factory);
889
+ }
890
+ function isVaultClientUsable() {
891
+ return instance.has() || instance.hasFactory();
892
+ }
893
+ function useVaultClient() {
894
+ return instance.use();
895
+ }
896
+
897
+ function transformDomainEventData(input) {
898
+ const keys = Object.keys(input);
899
+ for (const key_ of keys){
900
+ const key = key_;
901
+ const value = input[key];
902
+ if (!isObject$1(value)) {
903
+ continue;
904
+ }
905
+ if (value instanceof Date) {
906
+ input[key] = value.toISOString();
563
907
  }
564
- transport = createTransport({
565
- host: options.host,
566
- port: options.port,
567
- auth,
568
- secure: options.ssl,
569
- opportunisticTLS: options.starttls,
570
- tls: {
571
- rejectUnauthorized: false
908
+ }
909
+ return input;
910
+ }
911
+ function buildDomainEventChannelName(input, id) {
912
+ if (typeof input === 'string') {
913
+ return input;
914
+ }
915
+ return input(id);
916
+ }
917
+
918
+ class DomainEventRedisPublisher {
919
+ driver;
920
+ constructor(input){
921
+ this.driver = createRedisClient(input);
922
+ }
923
+ async publish(ctx) {
924
+ const data = JSON.stringify(transformDomainEventData(ctx.content));
925
+ const pipeline = this.driver.pipeline();
926
+ for(let i = 0; i < ctx.destinations.length; i++){
927
+ const { namespace } = ctx.destinations[i];
928
+ const keyPrefix = namespace ? `${namespace}:` : '';
929
+ let key = keyPrefix + buildDomainEventChannelName(ctx.destinations[i].channel);
930
+ pipeline.publish(key, data);
931
+ if (typeof ctx.destinations[i].channel === 'function') {
932
+ key = keyPrefix + buildDomainEventChannelName(ctx.destinations[i].channel, ctx.content.data.id);
933
+ pipeline.publish(key, data);
572
934
  }
573
- });
935
+ }
936
+ await pipeline.exec();
574
937
  }
575
- transport.on('error', (e)=>{
576
- useLogger().error(e.message);
577
- });
578
- return transport;
579
- }
580
-
581
- let instance;
582
- async function useSMTPClient() {
583
- if (typeof instance !== 'undefined') {
584
- return instance;
585
- }
586
- let options;
587
- if (process.env.NODE_ENV === 'test') {
588
- const testAccount = await createTestAccount();
589
- options = {
590
- host: 'smtp.ethereal.email',
591
- port: 587,
592
- ssl: false,
593
- user: testAccount.user,
594
- password: testAccount.pass
595
- };
596
- } else {
597
- options = useSmtpConfig();
938
+ }
939
+
940
+ class DomainEventSocketPublisher {
941
+ driver;
942
+ constructor(input){
943
+ const client = createRedisClient(input);
944
+ this.driver = new Emitter(client);
945
+ }
946
+ async publish(ctx) {
947
+ ctx.content = transformDomainEventData(ctx.content);
948
+ for(let i = 0; i < ctx.destinations.length; i++){
949
+ const destination = ctx.destinations[i];
950
+ let emitter;
951
+ if (destination.namespace) {
952
+ emitter = this.driver.of(destination.namespace);
953
+ } else {
954
+ emitter = this.driver;
955
+ }
956
+ let roomName = buildDomainEventChannelName(destination.channel);
957
+ const fullEventName = buildEventFullName(ctx.content.type, ctx.content.event);
958
+ emitter.in(roomName).emit(fullEventName, {
959
+ ...ctx.content,
960
+ meta: {
961
+ roomName
962
+ }
963
+ });
964
+ if (typeof destination.channel === 'function') {
965
+ roomName = buildDomainEventChannelName(destination.channel, ctx.content.data.id);
966
+ emitter.in(roomName).emit(fullEventName, {
967
+ ...ctx.content,
968
+ meta: {
969
+ roomName,
970
+ roomId: ctx.content.data.id
971
+ }
972
+ });
973
+ }
974
+ }
598
975
  }
599
- instance = createSmtpClient(options);
600
- return instance;
601
976
  }
602
977
 
603
978
  /*
604
- * Copyright (c) 2022.
979
+ * Copyright (c) 2022-2024.
605
980
  * Author Peter Placzek (tada5hi)
606
981
  * For the full copyright and license information,
607
982
  * view the LICENSE file that was distributed with this source code.
@@ -609,5 +984,5 @@ async function useSMTPClient() {
609
984
  return Object.prototype.hasOwnProperty.call(obj, prop);
610
985
  }
611
986
 
612
- export { KeyPairKind, VoidLogger, buildKeyFileName, compare, createKeyPair, createSmtpClient, decodeToken, decryptRSAPrivateKey, deleteKeyPair, extendKeyPairOptions, hasOwnProperty, hasSmtpConfig, hash, isKeyPair, isKeyPairWithPublicKey, loadKeyPair, publishDomainEvent, publishDomainRedisEvent, publishDomainSocketEvent, saveKeyPair, setLogger, setSmtpConfig, signToken, useKeyPair, useLogger, useSMTPClient, useSmtpConfig, useSocketEmitter, verifyToken };
987
+ export { AsymmetricKey, BaseKey, CryptoAsymmetricAlgorithm, DomainEventPublisher, DomainEventRedisPublisher, DomainEventSocketPublisher, MemoryCache, RedisCache, SymmetricAlgorithm, SymmetricKey, buildCacheKey, compare, createAsymmetricKeyPair, createLogger, createNoopLogger, createRedisClient, createSymmetricKey, decodePemToPKCS8, decodePemToSpki, encodePKCS8ToPEM, encodeSPKIToPem, extractTokenHeader, extractTokenPayload, getKeyUsagesForAsymmetricAlgorithm, getKeyUsagesForSymmetricAlgorithm, hasOwnProperty, hash, isAsymmetricAlgorithm, isLoggerUsable, isRedisClient, isSymmetricAlgorithm, isVaultClientUsable, normalizeAsymmetricKeyImportOptions, normalizeAsymmetricKeyPairCreateOptions, setLogger, setLoggerFactory, setVaultFactory, signToken, useLogger, useVaultClient, verifyToken };
613
988
  //# sourceMappingURL=index.mjs.map