@seele00/seele 0.1.63 → 0.1.64

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 (105) hide show
  1. package/README.md +5 -3
  2. package/bin/seele-codex +1 -1
  3. package/libexec/seele-server +0 -0
  4. package/libexec/seele-worker +0 -0
  5. package/package.json +1 -4
  6. package/scripts/deploy/bootstrap.sh +14 -3
  7. package/scripts/deploy/start.sh +14 -9
  8. package/web/dist/assets/{abnfDiagram-VRR7QNED-DXJQwnn-.js → abnfDiagram-VRR7QNED-BB7DT0BN.js} +1 -1
  9. package/web/dist/assets/{arc-D_47-IET.js → arc-BlEU_mit.js} +1 -1
  10. package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-CKUldIzR.js → architectureDiagram-ZJ3FMSHR-Dy9cu2Mg.js} +1 -1
  11. package/web/dist/assets/{blockDiagram-677ZJIJ3-BD4Ym8Xi.js → blockDiagram-677ZJIJ3-DP4jMSfo.js} +1 -1
  12. package/web/dist/assets/{c4Diagram-LMCZKHZV-Cn268vLB.js → c4Diagram-LMCZKHZV-BtqFzX1w.js} +1 -1
  13. package/web/dist/assets/channel-mhSuRKJT.js +1 -0
  14. package/web/dist/assets/{chunk-2Q5K7J3B-D00lQ7mJ.js → chunk-2Q5K7J3B-BK9F5a0L.js} +1 -1
  15. package/web/dist/assets/{chunk-32BRIVSS-z7gv8Mry.js → chunk-32BRIVSS-nuQI6gtU.js} +1 -1
  16. package/web/dist/assets/{chunk-5VM5RSS4-BZJeO_rz.js → chunk-5VM5RSS4-D4IT05bt.js} +1 -1
  17. package/web/dist/assets/{chunk-EX3LRPZG-DoIg9UGx.js → chunk-EX3LRPZG-CrOtgxcr.js} +1 -1
  18. package/web/dist/assets/{chunk-JWPE2WC7-C1LcQus2.js → chunk-JWPE2WC7-Dn9JHm4W.js} +1 -1
  19. package/web/dist/assets/{chunk-MOJQB5TN--JPbFu4n.js → chunk-MOJQB5TN-VtD0_fGF.js} +1 -1
  20. package/web/dist/assets/{chunk-RYQCIY6F-BVv30W60.js → chunk-RYQCIY6F-TqRYsCot.js} +1 -1
  21. package/web/dist/assets/{chunk-V7JOEXUC-DYoSFgRT.js → chunk-V7JOEXUC-U9b5a7vL.js} +1 -1
  22. package/web/dist/assets/{chunk-VR4S4FIN-C8BRkTOa.js → chunk-VR4S4FIN-B3qLfeNJ.js} +1 -1
  23. package/web/dist/assets/{chunk-XXDRQBXY-CDfofIob.js → chunk-XXDRQBXY-DazVAZe-.js} +1 -1
  24. package/web/dist/assets/classDiagram-OUVF2IWQ-DYQSxD4g.js +1 -0
  25. package/web/dist/assets/classDiagram-v2-EOCWNBFH-DYQSxD4g.js +1 -0
  26. package/web/dist/assets/{core-C10OFTno.js → core-2RdBW0rZ.js} +1 -1
  27. package/web/dist/assets/{cose-bilkent-JH36ORCC-g9E8J4Fz.js → cose-bilkent-JH36ORCC-vvKttQXU.js} +1 -1
  28. package/web/dist/assets/{cynefin-VYW2F7L2-Dc689veM.js → cynefin-VYW2F7L2-BKMZmA-n.js} +1 -1
  29. package/web/dist/assets/{cynefinDiagram-TSTJHNR4-BAAq_jvr.js → cynefinDiagram-TSTJHNR4-ckdzxzlr.js} +1 -1
  30. package/web/dist/assets/{dagre-VKFMJZFB-CPtiniZQ.js → dagre-VKFMJZFB-CZw8DTb1.js} +1 -1
  31. package/web/dist/assets/{diagram-FQU43EPY-CvbIL3lu.js → diagram-FQU43EPY-C06X0Kru.js} +1 -1
  32. package/web/dist/assets/{diagram-G47NLZAW-u5m78Utg.js → diagram-G47NLZAW-HX9CdauD.js} +1 -1
  33. package/web/dist/assets/{diagram-NH7WQ7WH-4f-Ipubv.js → diagram-NH7WQ7WH-Dlo1tIod.js} +1 -1
  34. package/web/dist/assets/{diagram-OA4YK3LP-SUl1EQ56.js → diagram-OA4YK3LP-C9GXFhgw.js} +1 -1
  35. package/web/dist/assets/{diagram-WEI45ONY-C_Upd46l.js → diagram-WEI45ONY-Ch1Xx234.js} +1 -1
  36. package/web/dist/assets/{ebnfDiagram-CCIWWBDH-CHp2D7Q9.js → ebnfDiagram-CCIWWBDH-Q0_rEUgk.js} +1 -1
  37. package/web/dist/assets/{erDiagram-Q63AITRT-DQliHxOw.js → erDiagram-Q63AITRT-BsDRdpx6.js} +1 -1
  38. package/web/dist/assets/{flowDiagram-23GEKE2U-BcOYSJFM.js → flowDiagram-23GEKE2U-DDFuMRJN.js} +1 -1
  39. package/web/dist/assets/{ganttDiagram-NO4QXBWP-CDLHtJq0.js → ganttDiagram-NO4QXBWP-Cjpm08-d.js} +1 -1
  40. package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-2j8C3mlk.js → gitGraphDiagram-IHSO6WYX-CnIosh2K.js} +1 -1
  41. package/web/dist/assets/index-eN6ddNRA.js +111 -0
  42. package/web/dist/assets/{infoDiagram-FWYZ7A6U-ClxdyQnM.js → infoDiagram-FWYZ7A6U-CH163HyC.js} +1 -1
  43. package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-Bc2nIRgb.js → ishikawaDiagram-FXEZZL3T-DkT-3n3D.js} +1 -1
  44. package/web/dist/assets/{journeyDiagram-5HDEW3XC-R-vJ00LW.js → journeyDiagram-5HDEW3XC-34TnH3wG.js} +1 -1
  45. package/web/dist/assets/{kanban-definition-HUTT4EX6-CR0s_Mo8.js → kanban-definition-HUTT4EX6-CJbOm0lN.js} +1 -1
  46. package/web/dist/assets/{linear-BQgrawZS.js → linear-CTKXTLwe.js} +1 -1
  47. package/web/dist/assets/{mermaid.core-faLMbjSU.js → mermaid.core-CAVP16_-.js} +4 -4
  48. package/web/dist/assets/{mindmap-definition-LN4V7U3C-BZULnQui.js → mindmap-definition-LN4V7U3C-rlppHZj_.js} +1 -1
  49. package/web/dist/assets/{pegDiagram-2B236MQR-DUm1p_1o.js → pegDiagram-2B236MQR-MbcWBNJi.js} +1 -1
  50. package/web/dist/assets/{pieDiagram-ENE6RG2P-r3LCASRK.js → pieDiagram-ENE6RG2P-DKU7a4tv.js} +1 -1
  51. package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-CGaCp0Px.js → quadrantDiagram-ABIIQ3AL-DpDsJVLi.js} +1 -1
  52. package/web/dist/assets/{railroadDiagram-RFXS5EU6-DmEKGO1A.js → railroadDiagram-RFXS5EU6-DrPM3aKC.js} +1 -1
  53. package/web/dist/assets/{requirementDiagram-TGXJPOKE-Byc4ivmp.js → requirementDiagram-TGXJPOKE-ZzS_iVag.js} +1 -1
  54. package/web/dist/assets/{sankeyDiagram-HTMAVEWB-BtJiL4zX.js → sankeyDiagram-HTMAVEWB-DrRrN0Lc.js} +1 -1
  55. package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-Bg3vdDGW.js → sequenceDiagram-DBY2YBRQ-CP8GBGZM.js} +1 -1
  56. package/web/dist/assets/{sizeCapture-X5ZJPWSS-CCRwjaWU.js → sizeCapture-X5ZJPWSS-BYVg_dQd.js} +1 -1
  57. package/web/dist/assets/{stateDiagram-2N3HPSRC-CQU-udox.js → stateDiagram-2N3HPSRC-CsJ3M80-.js} +1 -1
  58. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-CaFOY1Xb.js +1 -0
  59. package/web/dist/assets/{swimlanes-5IMT3BWC-r3tJnQLJ.js → swimlanes-5IMT3BWC-XgRKQ20Q.js} +2 -2
  60. package/web/dist/assets/swimlanesDiagram-G3AALYLV-DaKP_iDy.js +8 -0
  61. package/web/dist/assets/{timeline-definition-FHXFAJF6-DryYrdts.js → timeline-definition-FHXFAJF6-CU_Cq10d.js} +1 -1
  62. package/web/dist/assets/{vennDiagram-L72KCM5P-ZLPc0qvQ.js → vennDiagram-L72KCM5P-CLSDbg6o.js} +1 -1
  63. package/web/dist/assets/{wardleyDiagram-EHGQE667-RmgA6vQ9.js → wardleyDiagram-EHGQE667-DnAOuvzv.js} +1 -1
  64. package/web/dist/assets/{xychartDiagram-FW5EYKEG-BGIzispI.js → xychartDiagram-FW5EYKEG-CyC6V11l.js} +1 -1
  65. package/web/dist/index.html +1 -1
  66. package/codex/dist/app-server.js +0 -63
  67. package/codex/dist/errors.js +0 -16
  68. package/codex/dist/index.js +0 -4
  69. package/codex/dist/rpc-client.js +0 -96
  70. package/codex/dist/transports/stdio.js +0 -81
  71. package/codex/dist/types.js +0 -1
  72. package/codex/package.json +0 -12
  73. package/scripts/deploy/npm/postinstall.mjs +0 -10
  74. package/server/dist/auth/session.js +0 -71
  75. package/server/dist/auth/users.js +0 -276
  76. package/server/dist/codex-runtime/run-streamed-turn.js +0 -587
  77. package/server/dist/config/config.js +0 -71
  78. package/server/dist/contracts/artifact-rendering.js +0 -14
  79. package/server/dist/contracts/global-environment.js +0 -23
  80. package/server/dist/contracts/index.js +0 -114
  81. package/server/dist/contracts/managed-assets.js +0 -13
  82. package/server/dist/contracts/response-style.js +0 -23
  83. package/server/dist/contracts/task-clarification.js +0 -13
  84. package/server/dist/contracts/types.js +0 -1
  85. package/server/dist/contracts/wakeup.js +0 -13
  86. package/server/dist/contracts/workspace-boundary.js +0 -20
  87. package/server/dist/contracts/workspace-knowledge.js +0 -48
  88. package/server/dist/contracts/workspace-memory.js +0 -32
  89. package/server/dist/contracts/workspace-responsibility.js +0 -23
  90. package/server/dist/contracts/workspace-transcript.js +0 -26
  91. package/server/dist/conversations/knowledge.js +0 -380
  92. package/server/dist/conversations/store.js +0 -2466
  93. package/server/dist/doctor.js +0 -105
  94. package/server/dist/realtime/sse.js +0 -12
  95. package/server/dist/runtime-worker/client.js +0 -405
  96. package/server/dist/runtime-worker/process.js +0 -216
  97. package/server/dist/runtime-worker/protocol.js +0 -1
  98. package/server/dist/server.js +0 -4605
  99. package/server/dist/storage/sqlite.js +0 -39
  100. package/web/dist/assets/channel-Uz6zF6Xw.js +0 -1
  101. package/web/dist/assets/classDiagram-OUVF2IWQ-D6mpE1t2.js +0 -1
  102. package/web/dist/assets/classDiagram-v2-EOCWNBFH-D6mpE1t2.js +0 -1
  103. package/web/dist/assets/index-BqSosI7W.js +0 -111
  104. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-YNSWW4ip.js +0 -1
  105. package/web/dist/assets/swimlanesDiagram-G3AALYLV-BGZAc11_.js +0 -8
@@ -1,71 +0,0 @@
1
- import { createHmac, timingSafeEqual } from "node:crypto";
2
- const COOKIE_NAME = "seele_session";
3
- export function readSessionPayload(request, secret) {
4
- const token = parseCookies(request.headers.cookie)[COOKIE_NAME];
5
- if (!token) {
6
- return null;
7
- }
8
- const [encodedPayload, signature] = token.split(".");
9
- if (!encodedPayload || !signature) {
10
- return null;
11
- }
12
- if (!safeEqual(signature, sign(encodedPayload, secret))) {
13
- return null;
14
- }
15
- try {
16
- const payload = JSON.parse(Buffer.from(encodedPayload, "base64url").toString("utf8"));
17
- if (typeof payload.userId !== "string" ||
18
- !Number.isInteger(payload.sessionVersion) ||
19
- !Number.isFinite(payload.expiresAt) ||
20
- payload.expiresAt <= Date.now()) {
21
- return null;
22
- }
23
- return payload;
24
- }
25
- catch {
26
- return null;
27
- }
28
- }
29
- export function setSessionCookie(response, request, input) {
30
- const payload = Buffer.from(JSON.stringify({
31
- userId: input.userId,
32
- sessionVersion: input.sessionVersion,
33
- expiresAt: Date.now() + input.ttlSeconds * 1000,
34
- })).toString("base64url");
35
- const token = `${payload}.${sign(payload, input.secret)}`;
36
- const secure = isSecureRequest(request) ? "; Secure" : "";
37
- response.setHeader("Set-Cookie", `${COOKIE_NAME}=${token}; Path=${input.path}; HttpOnly; SameSite=Strict; Max-Age=${input.ttlSeconds}${secure}`);
38
- }
39
- export function clearSessionCookie(response, request, path) {
40
- const secure = isSecureRequest(request) ? "; Secure" : "";
41
- response.setHeader("Set-Cookie", `${COOKIE_NAME}=; Path=${path}; HttpOnly; SameSite=Strict; Max-Age=0${secure}`);
42
- }
43
- function sign(value, secret) {
44
- return createHmac("sha256", secret).update(value).digest("base64url");
45
- }
46
- function safeEqual(left, right) {
47
- const leftBuffer = Buffer.from(left);
48
- const rightBuffer = Buffer.from(right);
49
- return (leftBuffer.length === rightBuffer.length &&
50
- timingSafeEqual(leftBuffer, rightBuffer));
51
- }
52
- function parseCookies(header) {
53
- if (!header) {
54
- return {};
55
- }
56
- return Object.fromEntries(header.split(";").flatMap((part) => {
57
- const separator = part.indexOf("=");
58
- if (separator < 0) {
59
- return [];
60
- }
61
- const key = part.slice(0, separator).trim();
62
- const value = part.slice(separator + 1).trim();
63
- return key ? [[key, value]] : [];
64
- }));
65
- }
66
- function isSecureRequest(request) {
67
- const forwardedProto = request.headers["x-forwarded-proto"];
68
- const protocol = Array.isArray(forwardedProto) ? forwardedProto[0] : forwardedProto;
69
- return (protocol?.split(",")[0]?.trim() === "https" ||
70
- Boolean(request.socket.encrypted));
71
- }
@@ -1,276 +0,0 @@
1
- import { randomBytes, randomUUID, scrypt, scryptSync, timingSafeEqual, } from "node:crypto";
2
- import path from "node:path";
3
- import { mkdirSync } from "node:fs";
4
- import { openSqliteDatabase, runInTransaction, } from "../storage/sqlite.js";
5
- export class UserStore {
6
- sessionSecret;
7
- db;
8
- dummyPasswordHash;
9
- constructor(databasePath, bootstrap) {
10
- mkdirSync(path.dirname(databasePath), { recursive: true });
11
- this.db = openSqliteDatabase(databasePath);
12
- this.db.exec("pragma journal_mode = WAL");
13
- this.initializeSchema();
14
- this.sessionSecret = this.ensureSessionSecret();
15
- this.dummyPasswordHash = this.ensureDummyPasswordHash();
16
- if (this.countUsers() === 0 && bootstrap?.password) {
17
- this.createUser({
18
- username: bootstrap.username,
19
- password: bootstrap.password,
20
- role: "admin",
21
- });
22
- }
23
- }
24
- get enabled() {
25
- return this.countUsers() > 0;
26
- }
27
- listUsers() {
28
- const rows = this.db
29
- .prepare("select * from auth_users order by created_at asc")
30
- .all();
31
- return rows.map(userFromRow);
32
- }
33
- getUser(id) {
34
- const row = this.db
35
- .prepare("select * from auth_users where id = ?")
36
- .get(id);
37
- return row ? userFromRow(row) : null;
38
- }
39
- getUserByUsername(username) {
40
- const row = this.db
41
- .prepare("select * from auth_users where username = ? collate nocase")
42
- .get(username.trim());
43
- return row ? userFromRow(row) : null;
44
- }
45
- async authenticate(username, password) {
46
- const row = this.db
47
- .prepare("select * from auth_users where username = ? collate nocase")
48
- .get(username.trim());
49
- const passwordMatches = await verifyPassword(password, row?.password_hash ?? this.dummyPasswordHash);
50
- if (!row || !row.active || !passwordMatches) {
51
- return null;
52
- }
53
- return userFromRow(row);
54
- }
55
- loginBlockedUntil(keys, now = Date.now()) {
56
- let blockedUntil = 0;
57
- const statement = this.db.prepare("select locked_until from auth_login_attempts where key = ?");
58
- for (const key of keys) {
59
- const row = statement.get(key);
60
- blockedUntil = Math.max(blockedUntil, row?.locked_until ?? 0);
61
- }
62
- return blockedUntil > now ? blockedUntil : 0;
63
- }
64
- recordLoginFailure(buckets, windowMs, lockoutMs, now = Date.now()) {
65
- runInTransaction(this.db, () => {
66
- const read = this.db.prepare(`
67
- select failure_count, window_started_at, locked_until
68
- from auth_login_attempts where key = ?
69
- `);
70
- const write = this.db.prepare(`
71
- insert into auth_login_attempts (
72
- key, failure_count, window_started_at, locked_until, updated_at
73
- ) values (?, ?, ?, ?, ?)
74
- on conflict(key) do update set
75
- failure_count = excluded.failure_count,
76
- window_started_at = excluded.window_started_at,
77
- locked_until = excluded.locked_until,
78
- updated_at = excluded.updated_at
79
- `);
80
- for (const bucket of buckets) {
81
- const current = read.get(bucket.key);
82
- const expired = !current ||
83
- (current.locked_until <= now &&
84
- now - current.window_started_at >= windowMs);
85
- const failureCount = expired ? 1 : current.failure_count + 1;
86
- const windowStartedAt = expired ? now : current.window_started_at;
87
- const lockedUntil = failureCount >= bucket.maxFailures ? now + lockoutMs : 0;
88
- write.run(bucket.key, failureCount, windowStartedAt, lockedUntil, now);
89
- }
90
- this.db
91
- .prepare("delete from auth_login_attempts where updated_at < ?")
92
- .run(now - Math.max(windowMs, lockoutMs) * 4);
93
- });
94
- }
95
- clearLoginFailures(keys) {
96
- const statement = this.db.prepare("delete from auth_login_attempts where key = ?");
97
- runInTransaction(this.db, () => {
98
- for (const key of keys) {
99
- statement.run(key);
100
- }
101
- });
102
- }
103
- createUser(input) {
104
- const username = normalizeUsername(input.username);
105
- validatePassword(input.password);
106
- const now = new Date().toISOString();
107
- const row = {
108
- id: randomUUID(),
109
- username,
110
- password_hash: hashPassword(input.password),
111
- role: input.role,
112
- active: 1,
113
- session_version: 1,
114
- created_at: now,
115
- updated_at: now,
116
- };
117
- this.db.prepare(`
118
- insert into auth_users (
119
- id, username, password_hash, role, active, session_version, created_at, updated_at
120
- ) values (
121
- @id, @username, @password_hash, @role, @active, @session_version, @created_at, @updated_at
122
- )
123
- `).run(row);
124
- return userFromRow(row);
125
- }
126
- updateUser(id, input) {
127
- const current = this.db
128
- .prepare("select * from auth_users where id = ?")
129
- .get(id);
130
- if (!current) {
131
- return null;
132
- }
133
- const username = input.username === undefined
134
- ? current.username
135
- : normalizeUsername(input.username);
136
- const passwordChanged = input.password !== undefined && input.password.length > 0;
137
- if (passwordChanged) {
138
- validatePassword(input.password);
139
- }
140
- const next = {
141
- ...current,
142
- username,
143
- password_hash: passwordChanged ? hashPassword(input.password) : current.password_hash,
144
- role: input.role ?? current.role,
145
- active: input.active === undefined ? current.active : input.active ? 1 : 0,
146
- session_version: passwordChanged || input.active === false
147
- ? current.session_version + 1
148
- : current.session_version,
149
- updated_at: new Date().toISOString(),
150
- };
151
- this.db.prepare(`
152
- update auth_users set
153
- username = @username,
154
- password_hash = @password_hash,
155
- role = @role,
156
- active = @active,
157
- session_version = @session_version,
158
- updated_at = @updated_at
159
- where id = @id
160
- `).run(next);
161
- return userFromRow(next);
162
- }
163
- deleteUser(id) {
164
- return this.db.prepare("delete from auth_users where id = ?").run(id).changes > 0;
165
- }
166
- countUsers() {
167
- const row = this.db.prepare("select count(*) as count from auth_users").get();
168
- return row.count;
169
- }
170
- initializeSchema() {
171
- this.db.exec(`
172
- create table if not exists auth_users (
173
- id text primary key,
174
- username text not null unique collate nocase,
175
- password_hash text not null,
176
- role text not null check (role in ('admin', 'user')),
177
- active integer not null default 1,
178
- session_version integer not null default 1,
179
- created_at text not null,
180
- updated_at text not null
181
- );
182
- create table if not exists auth_metadata (
183
- key text primary key,
184
- value text not null
185
- );
186
- create table if not exists auth_login_attempts (
187
- key text primary key,
188
- failure_count integer not null,
189
- window_started_at integer not null,
190
- locked_until integer not null,
191
- updated_at integer not null
192
- );
193
- create index if not exists auth_login_attempts_updated_at
194
- on auth_login_attempts(updated_at);
195
- `);
196
- }
197
- ensureSessionSecret() {
198
- const existing = this.db
199
- .prepare("select value from auth_metadata where key = 'session_secret'")
200
- .get();
201
- if (existing) {
202
- return existing.value;
203
- }
204
- const value = randomBytes(32).toString("base64url");
205
- this.db
206
- .prepare("insert into auth_metadata (key, value) values ('session_secret', ?)")
207
- .run(value);
208
- return value;
209
- }
210
- ensureDummyPasswordHash() {
211
- const existing = this.db
212
- .prepare("select value from auth_metadata where key = 'dummy_password_hash'")
213
- .get();
214
- if (existing) {
215
- return existing.value;
216
- }
217
- const value = hashPassword(randomBytes(32).toString("base64url"));
218
- this.db
219
- .prepare("insert into auth_metadata (key, value) values ('dummy_password_hash', ?)")
220
- .run(value);
221
- return value;
222
- }
223
- }
224
- function userFromRow(row) {
225
- return {
226
- id: row.id,
227
- username: row.username,
228
- role: row.role,
229
- active: row.active === 1,
230
- sessionVersion: row.session_version,
231
- createdAt: row.created_at,
232
- updatedAt: row.updated_at,
233
- };
234
- }
235
- function normalizeUsername(value) {
236
- const username = value.trim();
237
- if (!/^[A-Za-z0-9_.-]{2,64}$/.test(username)) {
238
- throw new Error("invalid_username");
239
- }
240
- return username;
241
- }
242
- function validatePassword(value) {
243
- if (value.length < 8 || value.length > 512) {
244
- throw new Error("invalid_password");
245
- }
246
- }
247
- function hashPassword(password) {
248
- const salt = randomBytes(16);
249
- const digest = scryptSync(password, salt, 64);
250
- return `scrypt:${salt.toString("base64url")}:${digest.toString("base64url")}`;
251
- }
252
- async function verifyPassword(password, stored) {
253
- const [algorithm, encodedSalt, encodedDigest] = stored.split(":");
254
- if (algorithm !== "scrypt" || !encodedSalt || !encodedDigest) {
255
- return false;
256
- }
257
- try {
258
- const expected = Buffer.from(encodedDigest, "base64url");
259
- const actual = await derivePassword(password, Buffer.from(encodedSalt, "base64url"), expected.length);
260
- return expected.length === actual.length && timingSafeEqual(expected, actual);
261
- }
262
- catch {
263
- return false;
264
- }
265
- }
266
- function derivePassword(password, salt, length) {
267
- return new Promise((resolve, reject) => {
268
- scrypt(password, salt, length, (error, derivedKey) => {
269
- if (error) {
270
- reject(error);
271
- return;
272
- }
273
- resolve(derivedKey);
274
- });
275
- });
276
- }