@lightharu/krouter 1.8.0

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 (61) hide show
  1. package/LICENSE +679 -0
  2. package/README.md +238 -0
  3. package/dist-web/assets/index-CM4-0adf.css +1 -0
  4. package/dist-web/assets/index-DCslvfUR.js +139 -0
  5. package/dist-web/favicon.svg +9 -0
  6. package/dist-web/icon.svg +9 -0
  7. package/dist-web/index.html +19 -0
  8. package/out-server/main/kiroAuthSync.js +249 -0
  9. package/out-server/main/kproxy/certManager.js +262 -0
  10. package/out-server/main/kproxy/index.js +254 -0
  11. package/out-server/main/kproxy/mitmProxy.js +475 -0
  12. package/out-server/main/kproxy/types.js +23 -0
  13. package/out-server/main/proxy/accountPool.js +543 -0
  14. package/out-server/main/proxy/clientConfig.js +596 -0
  15. package/out-server/main/proxy/index.js +25 -0
  16. package/out-server/main/proxy/kiroApi.js +1996 -0
  17. package/out-server/main/proxy/logger.js +407 -0
  18. package/out-server/main/proxy/modelCatalog.js +75 -0
  19. package/out-server/main/proxy/promptCacheTracker.js +301 -0
  20. package/out-server/main/proxy/proxyServer.js +3543 -0
  21. package/out-server/main/proxy/selfSignedCert.js +179 -0
  22. package/out-server/main/proxy/systemProxy.js +250 -0
  23. package/out-server/main/proxy/tokenCounter.js +164 -0
  24. package/out-server/main/proxy/toolNameRegistry.js +57 -0
  25. package/out-server/main/proxy/translator.js +1084 -0
  26. package/out-server/main/proxy/types.js +3 -0
  27. package/out-server/main/registration/browser-identity.js +184 -0
  28. package/out-server/main/registration/chainProxy.js +349 -0
  29. package/out-server/main/registration/config.js +58 -0
  30. package/out-server/main/registration/email-service.js +801 -0
  31. package/out-server/main/registration/fingerprint.js +352 -0
  32. package/out-server/main/registration/http-utils.js +148 -0
  33. package/out-server/main/registration/jwe.js +74 -0
  34. package/out-server/main/registration/names.js +142 -0
  35. package/out-server/main/registration/proton-mail-window.js +339 -0
  36. package/out-server/main/registration/registrar.js +1715 -0
  37. package/out-server/main/registration/tlsClientPool.js +70 -0
  38. package/out-server/main/registration/xxtea.js +161 -0
  39. package/out-server/main/runtimePaths.js +19 -0
  40. package/out-server/main/utils/redact.js +95 -0
  41. package/out-server/server/index.js +1272 -0
  42. package/out-server/server/services/accountExtras.js +105 -0
  43. package/out-server/server/services/accountProfileHydration.js +95 -0
  44. package/out-server/server/services/authFlows.js +509 -0
  45. package/out-server/server/services/dashboardTunnel.js +315 -0
  46. package/out-server/server/services/diagnostics.js +326 -0
  47. package/out-server/server/services/kiroAccounts.js +431 -0
  48. package/out-server/server/services/kiroSettings.js +260 -0
  49. package/out-server/server/services/kproxyRuntime.js +264 -0
  50. package/out-server/server/services/localKiroCredentials.js +320 -0
  51. package/out-server/server/services/machineIdRuntime.js +327 -0
  52. package/out-server/server/services/protonBrowserRuntime.js +724 -0
  53. package/out-server/server/services/proxyRuntime.js +523 -0
  54. package/out-server/server/services/registrationRuntime.js +106 -0
  55. package/out-server/server/store.js +266 -0
  56. package/package.json +113 -0
  57. package/resources/tls-client-xgo-1.14.0-windows-amd64.dll +0 -0
  58. package/scripts/kiro-manager-cli.cjs +3 -0
  59. package/scripts/krouter-cli.cjs +509 -0
  60. package/src/renderer/src/assets/krouter-logo.svg +11 -0
  61. package/src/renderer/src/assets/krouter-mark.svg +9 -0
@@ -0,0 +1,352 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrderedMap = void 0;
4
+ exports.newFPContext = newFPContext;
5
+ exports.resetPerfTiming = resetPerfTiming;
6
+ exports.buildFingerprintData = buildFingerprintData;
7
+ exports.generateFingerprint = generateFingerprint;
8
+ const xxtea_1 = require("./xxtea");
9
+ function randInt(max) {
10
+ return Math.floor(Math.random() * max);
11
+ }
12
+ function crc32Str(str) {
13
+ let crc = 0xffffffff >>> 0;
14
+ const table = getCrc32Table();
15
+ for (let i = 0; i < str.length; i++) {
16
+ crc = ((crc >>> 8) ^ table[(crc ^ str.charCodeAt(i)) & 0xff]) >>> 0;
17
+ }
18
+ return (crc ^ 0xffffffff) >>> 0;
19
+ }
20
+ let _t = null;
21
+ function getCrc32Table() {
22
+ if (_t)
23
+ return _t;
24
+ _t = new Uint32Array(256);
25
+ for (let i = 0; i < 256; i++) {
26
+ let c = i >>> 0;
27
+ for (let j = 0; j < 8; j++)
28
+ c = c & 1 ? (0xedb88320 ^ (c >>> 1)) >>> 0 : c >>> 1;
29
+ _t[i] = c;
30
+ }
31
+ return _t;
32
+ }
33
+ // ============ OrderedMap ============
34
+ class OrderedMap {
35
+ keys = [];
36
+ values = new Map();
37
+ set(key, value) {
38
+ if (!this.values.has(key))
39
+ this.keys.push(key);
40
+ this.values.set(key, value);
41
+ }
42
+ toJSON() {
43
+ const parts = [];
44
+ for (const k of this.keys) {
45
+ parts.push(`${JSON.stringify(k)}:${JSON.stringify(this.values.get(k))}`);
46
+ }
47
+ return `{${parts.join(',')}}`;
48
+ }
49
+ }
50
+ exports.OrderedMap = OrderedMap;
51
+ function newFPContext(identity) {
52
+ const ts = Math.floor(Date.now() / 1000);
53
+ return {
54
+ identity,
55
+ canvasHash: identity.canvasHash,
56
+ histogramBins: [...identity.histogramBase],
57
+ lsUbidSignin: `${identity.lsubidPrefixSignin}-${String(randInt(10000000)).padStart(7, '0')}-${String(randInt(10000000)).padStart(7, '0')}:${ts}`,
58
+ lsUbidProfile: '',
59
+ perfTiming: null,
60
+ startTime: null
61
+ };
62
+ }
63
+ function resetPerfTiming(ctx) {
64
+ ctx.perfTiming = null;
65
+ }
66
+ function genPerfTiming(nowMs) {
67
+ const loadEventEnd = nowMs - (500 + randInt(1001));
68
+ const loadDuration = 2000 + randInt(2001);
69
+ const base = loadEventEnd - loadDuration;
70
+ const dnsOffset = 2 + randInt(8);
71
+ const connectEndOffset = 300 + randInt(300);
72
+ const responseOffset = connectEndOffset + 200 + randInt(400);
73
+ const domInteractiveOffset = loadDuration - (5 + randInt(11));
74
+ const domContentLoadedStart = domInteractiveOffset + randInt(3);
75
+ return {
76
+ connectStart: base + dnsOffset + 1 + randInt(3),
77
+ secureConnectionStart: base + dnsOffset + 3 + randInt(5),
78
+ unloadEventEnd: 0,
79
+ domainLookupStart: base + dnsOffset,
80
+ domainLookupEnd: base + dnsOffset + randInt(2),
81
+ responseStart: base + responseOffset,
82
+ connectEnd: base + connectEndOffset,
83
+ responseEnd: base + responseOffset + randInt(5),
84
+ requestStart: base + connectEndOffset,
85
+ domLoading: base + responseOffset + 2 + randInt(5),
86
+ redirectStart: 0,
87
+ loadEventEnd,
88
+ domComplete: loadEventEnd,
89
+ navigationStart: base,
90
+ loadEventStart: loadEventEnd,
91
+ domContentLoadedEventEnd: loadEventEnd,
92
+ unloadEventStart: 0,
93
+ redirectEnd: 0,
94
+ domInteractive: base + domInteractiveOffset,
95
+ fetchStart: base + dnsOffset,
96
+ domContentLoadedEventStart: base + domContentLoadedStart
97
+ };
98
+ }
99
+ function getPerfTiming(ctx, nowMs) {
100
+ if (!ctx.perfTiming)
101
+ ctx.perfTiming = genPerfTiming(nowMs);
102
+ return ctx.perfTiming;
103
+ }
104
+ function getLsUbid(ctx, pageType) {
105
+ if (pageType === 'profile') {
106
+ if (!ctx.lsUbidProfile) {
107
+ const ts = ctx.perfTiming
108
+ ? Math.floor(ctx.perfTiming.loadEventEnd / 1000)
109
+ : Math.floor(Date.now() / 1000);
110
+ ctx.lsUbidProfile = `${ctx.identity.lsubidPrefixProfile}-${String(randInt(10000000)).padStart(7, '0')}-${String(randInt(10000000)).padStart(7, '0')}:${ts}`;
111
+ }
112
+ return ctx.lsUbidProfile;
113
+ }
114
+ return ctx.lsUbidSignin;
115
+ }
116
+ function getStartTime(ctx, nowMs) {
117
+ if (ctx.startTime === null)
118
+ ctx.startTime = nowMs;
119
+ return ctx.startTime;
120
+ }
121
+ // ============ Metrics & Interaction ============
122
+ function genMetricsFirstLoad(pageType) {
123
+ const m = {
124
+ el: 0, script: 0, h: 0, batt: 0, perf: 0, auto: 0,
125
+ tz: 0, fp2: 0, lsubid: 0, browser: 0, capabilities: 0,
126
+ gpu: 0, dnt: 0, math: 0, tts: 0, input: 0, canvas: 0,
127
+ captchainput: 0, pow: 0
128
+ };
129
+ switch (pageType) {
130
+ case 'profile':
131
+ m.batt = 5 + randInt(21);
132
+ m.fp2 = 1 + randInt(8);
133
+ m.browser = randInt(4);
134
+ m.capabilities = 1 + randInt(8);
135
+ m.dnt = randInt(4);
136
+ m.input = 8 + randInt(23);
137
+ m.canvas = 5 + randInt(16);
138
+ break;
139
+ case 'signup':
140
+ m.script = randInt(3);
141
+ m.batt = randInt(6);
142
+ m.fp2 = randInt(4);
143
+ m.gpu = 3 + randInt(6);
144
+ break;
145
+ default:
146
+ m.script = randInt(3);
147
+ m.auto = randInt(3);
148
+ m.browser = randInt(3);
149
+ m.gpu = 3 + randInt(6);
150
+ }
151
+ return m;
152
+ }
153
+ function genMetricsPageSubmit() {
154
+ return {
155
+ el: 0, script: 0, h: 0, batt: 0, perf: randInt(3),
156
+ auto: 0, tz: 0, fp2: 0, lsubid: 0, browser: 0,
157
+ capabilities: 0, gpu: 0, dnt: 0, math: 0, tts: 0,
158
+ input: 0, canvas: 0, captchainput: 0, pow: 0
159
+ };
160
+ }
161
+ function genInteraction(eventType) {
162
+ if (eventType === 'PageLoad' || eventType === 'first_load') {
163
+ return {
164
+ clicks: 0, touches: 0, keyPresses: 0,
165
+ cuts: 0, copies: 0, pastes: 0,
166
+ keyPressTimeIntervals: [], mouseClickPositions: [],
167
+ keyCycles: [], mouseCycles: [], touchCycles: []
168
+ };
169
+ }
170
+ const nClicks = 1 + randInt(3);
171
+ const nKeys = 3 + randInt(8);
172
+ const nIntervals = Math.max(1, Math.floor(nKeys / 3)) + randInt(Math.max(1, Math.floor(nKeys / 2) - Math.floor(nKeys / 3) + 1));
173
+ const nCycles = Math.max(2, Math.floor(nKeys / 2)) + randInt(Math.max(1, Math.floor(nKeys * 2 / 3) - Math.floor(nKeys / 2) + 1));
174
+ return {
175
+ clicks: nClicks, touches: 0, keyPresses: nKeys,
176
+ cuts: 0, copies: 0, pastes: 0,
177
+ keyPressTimeIntervals: Array.from({ length: nIntervals }, () => 80 + randInt(621)),
178
+ mouseClickPositions: Array.from({ length: nClicks }, () => `${400 + randInt(401)},${300 + randInt(201)}`),
179
+ keyCycles: Array.from({ length: nCycles }, () => 20 + randInt(281)),
180
+ mouseCycles: Array.from({ length: nClicks }, () => 50 + randInt(101)),
181
+ touchCycles: []
182
+ };
183
+ }
184
+ function genFormField(startMs, emailLen, email, interaction) {
185
+ const fieldTs = startMs - (10 + randInt(41));
186
+ const fieldRand = 1000 + randInt(9000);
187
+ const fieldName = `formField29-${fieldTs}-${fieldRand}`;
188
+ let nKeys = Math.max(3, Math.floor(emailLen / 3) + randInt(5) - 2);
189
+ const intervals = Array.from({ length: Math.min(nKeys - 1, 5) }, () => 80 + randInt(621));
190
+ const keyCycles = Array.from({ length: Math.min(nKeys, 6) }, () => 20 + randInt(231));
191
+ if (typeof interaction.keyPresses === 'number' && interaction.keyPresses > 0) {
192
+ nKeys = interaction.keyPresses;
193
+ }
194
+ const checksumStr = email || `user${1000 + randInt(9000)}@example.com`;
195
+ const cksum = crc32Str(checksumStr).toString(16).toUpperCase().padStart(8, '0');
196
+ return {
197
+ [fieldName]: {
198
+ clicks: 1, touches: 0, keyPresses: nKeys,
199
+ cuts: 0, copies: 0, pastes: 0,
200
+ keyPressTimeIntervals: intervals,
201
+ mouseClickPositions: [`${100 + randInt(151)}.5,${10 + randInt(11)}.5`],
202
+ keyCycles, mouseCycles: [80 + randInt(71)], touchCycles: [],
203
+ width: 180, height: 32, totalFocusTime: 0,
204
+ checksum: cksum, autocomplete: false, prefilled: false
205
+ }
206
+ };
207
+ }
208
+ // ============ Build Fingerprint ============
209
+ function formatScreen(s) {
210
+ return `${s.width}-${s.height}-${s.availHeight}-${s.colorDepth}-*-*-*`;
211
+ }
212
+ function formatPlugins(plugins) {
213
+ return plugins.map((p) => p.name).join(' ');
214
+ }
215
+ function buildFingerprintData(identity, locationURL, referrer, nowMs, ctx, pageType, eventType, timeOnPage, emailLen, email) {
216
+ const canvasHash = ctx ? ctx.canvasHash : identity.canvasHash;
217
+ const histogram = ctx ? ctx.histogramBins : identity.histogramBase;
218
+ const perfTiming = ctx ? getPerfTiming(ctx, nowMs) : genPerfTiming(nowMs);
219
+ let lsUbid;
220
+ if (ctx) {
221
+ lsUbid = getLsUbid(ctx, pageType);
222
+ }
223
+ else {
224
+ lsUbid = `${identity.lsubidPrefixSignin}-${String(randInt(10000000)).padStart(7, '0')}-${String(randInt(10000000)).padStart(7, '0')}:${Math.floor(perfTiming.loadEventEnd / 1000)}`;
225
+ }
226
+ let dynamicURLs;
227
+ let scriptsElapsed;
228
+ let historyLength;
229
+ let isCompatible;
230
+ switch (pageType) {
231
+ case 'profile':
232
+ dynamicURLs = [`/dist/main/app_${identity.webpackHash}.min.js`];
233
+ scriptsElapsed = 0;
234
+ historyLength = (eventType === 'PageLoad' || eventType === 'first_load') ? 2 : 3;
235
+ isCompatible = true;
236
+ break;
237
+ case 'signup':
238
+ dynamicURLs = ['/assets/js/app.js'];
239
+ scriptsElapsed = 1;
240
+ historyLength = 5;
241
+ isCompatible = true;
242
+ break;
243
+ default:
244
+ dynamicURLs = ['/assets/js/app.js'];
245
+ scriptsElapsed = 1;
246
+ historyLength = 1;
247
+ isCompatible = false;
248
+ }
249
+ let metrics;
250
+ if (eventType === 'first_load' || (eventType === 'PageLoad' && pageType === 'profile')) {
251
+ metrics = genMetricsFirstLoad(pageType);
252
+ }
253
+ else {
254
+ metrics = genMetricsPageSubmit();
255
+ }
256
+ const interaction = genInteraction(eventType);
257
+ const endMs = nowMs + randInt(51);
258
+ let startTime;
259
+ if (eventType !== 'PageLoad' && eventType !== 'first_load' && timeOnPage > 0) {
260
+ startTime = endMs - timeOnPage;
261
+ }
262
+ else if (ctx) {
263
+ if (eventType === 'first_load') {
264
+ startTime = getStartTime(ctx, nowMs - (500 + randInt(501)));
265
+ }
266
+ else if (eventType === 'PageLoad' && pageType === 'profile') {
267
+ startTime = getStartTime(ctx, nowMs - (30 + randInt(51)));
268
+ }
269
+ else {
270
+ startTime = getStartTime(ctx, nowMs);
271
+ }
272
+ }
273
+ else {
274
+ startTime = nowMs;
275
+ }
276
+ const pluginsStr = formatPlugins(identity.plugins);
277
+ const screenStr = formatScreen(identity.screen);
278
+ const result = new OrderedMap();
279
+ result.set('metrics', metrics);
280
+ result.set('start', startTime);
281
+ result.set('interaction', interaction);
282
+ result.set('scripts', {
283
+ dynamicUrls: dynamicURLs, inlineHashes: [],
284
+ elapsed: scriptsElapsed, dynamicUrlCount: dynamicURLs.length, inlineHashesCount: 0
285
+ });
286
+ result.set('history', { length: historyLength });
287
+ result.set('battery', {});
288
+ result.set('performance', { timing: perfTiming });
289
+ result.set('automation', {
290
+ wd: { properties: { document: [], window: [], navigator: [] } },
291
+ phantom: { properties: { window: [] } }
292
+ });
293
+ result.set('end', endMs);
294
+ result.set('timeZone', 8);
295
+ result.set('flashVersion', null);
296
+ result.set('plugins', pluginsStr + ' ||' + screenStr);
297
+ result.set('dupedPlugins', pluginsStr + ' ||' + screenStr);
298
+ result.set('screenInfo', screenStr);
299
+ result.set('lsUbid', lsUbid);
300
+ result.set('referrer', referrer);
301
+ result.set('userAgent', identity.ua);
302
+ result.set('location', locationURL);
303
+ result.set('webDriver', false);
304
+ result.set('capabilities', {
305
+ css: {
306
+ textShadow: 1, WebkitTextStroke: 1, boxShadow: 1,
307
+ borderRadius: 1, borderImage: 1, opacity: 1,
308
+ transform: 1, transition: 1
309
+ },
310
+ js: {
311
+ audio: true, geolocation: true, localStorage: 'supported',
312
+ touch: false, video: true, webWorker: true
313
+ },
314
+ elapsed: 0
315
+ });
316
+ result.set('gpu', {
317
+ vendor: identity.gpuVendor, model: identity.gpuModel,
318
+ extensions: identity.webGLExts
319
+ });
320
+ result.set('dnt', null);
321
+ result.set('math', { tan: identity.mathTan, sin: identity.mathSin, cos: identity.mathCos });
322
+ if (pageType === 'profile') {
323
+ if (eventType === 'PageLoad' || eventType === 'first_load') {
324
+ result.set('timeToSubmit', 1 + randInt(5));
325
+ }
326
+ else if (timeOnPage > 0) {
327
+ result.set('timeToSubmit', timeOnPage);
328
+ }
329
+ else {
330
+ result.set('timeToSubmit', 2000 + randInt(4001));
331
+ }
332
+ }
333
+ if (pageType === 'profile' && eventType !== 'PageLoad' && eventType !== 'first_load' && emailLen > 0) {
334
+ result.set('form', genFormField(nowMs, emailLen, email, interaction));
335
+ }
336
+ else {
337
+ result.set('form', {});
338
+ }
339
+ result.set('canvas', { hash: canvasHash, emailHash: null, histogramBins: [...histogram] });
340
+ result.set('token', { isCompatible, pageHasCaptcha: 0 });
341
+ result.set('auth', { form: { method: 'get' } });
342
+ result.set('errors', []);
343
+ result.set('version', (0, xxtea_1.getTESVersion)());
344
+ return result;
345
+ }
346
+ /** 生成加密后的浏览器指纹字符串 */
347
+ function generateFingerprint(identity, locationURL, referrer, ctx, pageType, eventType, timeOnPage, emailLen, email) {
348
+ const nowMs = Date.now();
349
+ const fpData = buildFingerprintData(identity, locationURL, referrer, nowMs, ctx, pageType, eventType, timeOnPage, emailLen, email);
350
+ const jsonStr = fpData.toJSON();
351
+ return (0, xxtea_1.encryptFingerprint)(jsonStr);
352
+ }
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_SEC_UA = exports.DEFAULT_UA = void 0;
7
+ exports.visitorId = visitorId;
8
+ exports.awsccc = awsccc;
9
+ exports.ubidGen = ubidGen;
10
+ exports.kiroVisitorId = kiroVisitorId;
11
+ exports.pkce = pkce;
12
+ exports.newUUID = newUUID;
13
+ exports.gmtDate = gmtDate;
14
+ exports.extractParam = extractParam;
15
+ exports.splitAfter = splitAfter;
16
+ exports.getNestedMap = getNestedMap;
17
+ exports.getNestedStringMap = getNestedStringMap;
18
+ exports.saveCookies = saveCookies;
19
+ const crypto_1 = __importDefault(require("crypto"));
20
+ exports.DEFAULT_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36';
21
+ exports.DEFAULT_SEC_UA = '"Chromium";v="146", "Not/A)Brand";v="24", "Google Chrome";v="146"';
22
+ /** 生成 4 位随机十六进制 */
23
+ function hex4() {
24
+ const chars = '0123456789abcdef';
25
+ let s = '';
26
+ for (let i = 0; i < 4; i++)
27
+ s += chars[Math.floor(Math.random() * 16)];
28
+ return s;
29
+ }
30
+ /** 生成随机 visitor ID (UUID v4-like) */
31
+ function visitorId() {
32
+ return `${hex4()}${hex4()}-${hex4()}-7${hex4().slice(1)}-${hex4()}-${hex4()}${hex4()}${hex4()}`;
33
+ }
34
+ /** 生成 awsccc cookie 值 */
35
+ function awsccc() {
36
+ const d = {
37
+ e: 1,
38
+ p: 1,
39
+ f: 1,
40
+ a: 1,
41
+ i: `${hex4()}${hex4()}-${hex4()}-4${hex4().slice(1)}-${hex4()}-${hex4()}${hex4()}${hex4()}`,
42
+ v: '1'
43
+ };
44
+ return Buffer.from(JSON.stringify(d)).toString('base64');
45
+ }
46
+ /** 生成 ubid cookie 值 */
47
+ function ubidGen() {
48
+ const d7 = Array.from({ length: 7 }, () => Math.floor(Math.random() * 10)).join('');
49
+ const d6 = Array.from({ length: 6 }, () => Math.floor(Math.random() * 10)).join('');
50
+ return `186-${d7}-${d6}`;
51
+ }
52
+ /** 生成 Kiro visitor ID */
53
+ function kiroVisitorId() {
54
+ const chars = '0123456789abcdefghijklmnopqrstuvwxyz';
55
+ let s = '';
56
+ for (let i = 0; i < 11; i++)
57
+ s += chars[Math.floor(Math.random() * chars.length)];
58
+ return `${Date.now()}-${s}`;
59
+ }
60
+ /** 生成 PKCE code_verifier 和 code_challenge */
61
+ function pkce() {
62
+ const raw = crypto_1.default.randomBytes(32);
63
+ const verifier = raw.toString('base64url');
64
+ const hash = crypto_1.default.createHash('sha256').update(verifier).digest();
65
+ const challenge = hash.toString('base64url');
66
+ return { verifier, challenge };
67
+ }
68
+ /** 生成 UUID */
69
+ function newUUID() {
70
+ const b = crypto_1.default.randomBytes(16);
71
+ return [
72
+ b.subarray(0, 4).toString('hex'),
73
+ b.subarray(4, 6).toString('hex'),
74
+ b.subarray(6, 8).toString('hex'),
75
+ b.subarray(8, 10).toString('hex'),
76
+ b.subarray(10, 16).toString('hex')
77
+ ].join('-');
78
+ }
79
+ /** 生成 GMT 日期字符串 */
80
+ function gmtDate() {
81
+ return new Date().toUTCString();
82
+ }
83
+ /** 从 URL 中提取查询参数 */
84
+ function extractParam(rawURL, key) {
85
+ try {
86
+ const u = new URL(rawURL);
87
+ return u.searchParams.get(key) || '';
88
+ }
89
+ catch {
90
+ return '';
91
+ }
92
+ }
93
+ /** 从字符串中提取分隔符后的内容 */
94
+ function splitAfter(s, sep) {
95
+ const idx = s.indexOf(sep);
96
+ if (idx < 0)
97
+ return '';
98
+ const rest = s.slice(idx + sep.length);
99
+ const ampIdx = rest.indexOf('&');
100
+ return ampIdx >= 0 ? rest.slice(0, ampIdx) : rest;
101
+ }
102
+ /** 获取嵌套 map 值 */
103
+ function getNestedMap(data, ...keys) {
104
+ let current = data;
105
+ for (const k of keys) {
106
+ if (typeof current !== 'object' || current === null)
107
+ return null;
108
+ current = current[k];
109
+ }
110
+ return typeof current === 'object' && current !== null
111
+ ? current
112
+ : null;
113
+ }
114
+ /** 获取嵌套的 string map */
115
+ function getNestedStringMap(data, key) {
116
+ if (!data)
117
+ return null;
118
+ const nested = data[key];
119
+ if (typeof nested !== 'object' || nested === null)
120
+ return null;
121
+ const result = {};
122
+ for (const [k, v] of Object.entries(nested)) {
123
+ if (typeof v === 'string')
124
+ result[k] = v;
125
+ }
126
+ return Object.keys(result).length > 0 ? result : null;
127
+ }
128
+ /** 从 Set-Cookie 头中提取并保存 cookies */
129
+ function saveCookies(cookies, headers) {
130
+ const skip = new Set(['path', 'domain', 'expires', 'max-age', 'secure', 'httponly', 'samesite']);
131
+ const setCookieHeader = headers['set-cookie'];
132
+ if (!setCookieHeader)
133
+ return;
134
+ const values = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader];
135
+ for (const raw of values) {
136
+ if (!raw.includes('='))
137
+ continue;
138
+ const mainPart = raw.split(';')[0];
139
+ const eqIdx = mainPart.indexOf('=');
140
+ if (eqIdx < 0)
141
+ continue;
142
+ const k = mainPart.slice(0, eqIdx).trim();
143
+ const v = mainPart.slice(eqIdx + 1).trim();
144
+ if (!skip.has(k.toLowerCase()) && k) {
145
+ cookies.set(k, v);
146
+ }
147
+ }
148
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.encryptPassword = encryptPassword;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ function b64url(data) {
9
+ return data.toString('base64url');
10
+ }
11
+ function jwkToPublicKey(jwk) {
12
+ const n = Buffer.from(jwk.n, 'base64url');
13
+ const e = Buffer.from(jwk.e, 'base64url');
14
+ return crypto_1.default.createPublicKey({
15
+ key: {
16
+ kty: 'RSA',
17
+ n: n.toString('base64url'),
18
+ e: e.toString('base64url')
19
+ },
20
+ format: 'jwk'
21
+ });
22
+ }
23
+ function genUUID() {
24
+ const b = crypto_1.default.randomBytes(16);
25
+ return [
26
+ b.subarray(0, 4).toString('hex'),
27
+ b.subarray(4, 6).toString('hex'),
28
+ b.subarray(6, 8).toString('hex'),
29
+ b.subarray(8, 10).toString('hex'),
30
+ b.subarray(10, 16).toString('hex')
31
+ ].join('-');
32
+ }
33
+ /** JWE 加密密码 (RSA-OAEP-256 + A256GCM) */
34
+ function encryptPassword(password, publicKey, issuer, audience, region) {
35
+ // Header
36
+ const header = {
37
+ alg: 'RSA-OAEP-256',
38
+ kid: publicKey.kid,
39
+ enc: 'A256GCM',
40
+ cty: 'enc',
41
+ typ: 'application/aws+signin+jwe'
42
+ };
43
+ const headerJSON = Buffer.from(JSON.stringify(header));
44
+ const headerB64 = b64url(headerJSON);
45
+ // CEK (内容加密密钥)
46
+ const cek = crypto_1.default.randomBytes(32);
47
+ // RSA-OAEP-256 加密 CEK
48
+ const pubKey = jwkToPublicKey(publicKey);
49
+ const encryptedCEK = crypto_1.default.publicEncrypt({
50
+ key: pubKey,
51
+ padding: crypto_1.default.constants.RSA_PKCS1_OAEP_PADDING,
52
+ oaepHash: 'sha256'
53
+ }, cek);
54
+ // Claims
55
+ const now = Math.floor(Date.now() / 1000);
56
+ const claims = {
57
+ iss: `${region}.${issuer}`,
58
+ iat: now,
59
+ nbf: now,
60
+ jti: genUUID(),
61
+ exp: now + 300,
62
+ aud: `${region}.${audience}`,
63
+ password
64
+ };
65
+ const plaintext = Buffer.from(JSON.stringify(claims));
66
+ // AES-256-GCM 加密
67
+ const iv = crypto_1.default.randomBytes(12);
68
+ const cipher = crypto_1.default.createCipheriv('aes-256-gcm', cek, iv, { authTagLength: 16 });
69
+ cipher.setAAD(Buffer.from(headerB64, 'ascii'));
70
+ const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
71
+ const tag = cipher.getAuthTag();
72
+ // JWE Compact: header.encKey.iv.ciphertext.tag
73
+ return `${headerB64}.${b64url(encryptedCEK)}.${b64url(iv)}.${b64url(ct)}.${b64url(tag)}`;
74
+ }