@vex-chat/spire 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +37 -38
  2. package/dist/ClientManager.d.ts +1 -3
  3. package/dist/ClientManager.js +6 -48
  4. package/dist/ClientManager.js.map +1 -1
  5. package/dist/Database.d.ts +25 -5
  6. package/dist/Database.js +54 -16
  7. package/dist/Database.js.map +1 -1
  8. package/dist/Spire.d.ts +0 -3
  9. package/dist/Spire.js +35 -73
  10. package/dist/Spire.js.map +1 -1
  11. package/dist/__tests__/Database.spec.js +0 -14
  12. package/dist/__tests__/Database.spec.js.map +1 -1
  13. package/dist/db/schema.d.ts +1 -0
  14. package/dist/migrations/2026-04-14_argon2id-password-hashing.d.ts +3 -0
  15. package/dist/migrations/2026-04-14_argon2id-password-hashing.js +12 -0
  16. package/dist/migrations/2026-04-14_argon2id-password-hashing.js.map +1 -0
  17. package/dist/run.js +0 -1
  18. package/dist/run.js.map +1 -1
  19. package/dist/server/avatar.d.ts +1 -3
  20. package/dist/server/avatar.js +7 -11
  21. package/dist/server/avatar.js.map +1 -1
  22. package/dist/server/errors.d.ts +3 -6
  23. package/dist/server/errors.js +2 -28
  24. package/dist/server/errors.js.map +1 -1
  25. package/dist/server/file.d.ts +1 -2
  26. package/dist/server/file.js +5 -7
  27. package/dist/server/file.js.map +1 -1
  28. package/dist/server/index.d.ts +1 -2
  29. package/dist/server/index.js +22 -33
  30. package/dist/server/index.js.map +1 -1
  31. package/dist/server/invite.d.ts +1 -2
  32. package/dist/server/invite.js +1 -1
  33. package/dist/server/invite.js.map +1 -1
  34. package/dist/server/rateLimit.d.ts +3 -3
  35. package/dist/server/rateLimit.js +6 -6
  36. package/dist/server/rateLimit.js.map +1 -1
  37. package/dist/server/user.d.ts +1 -2
  38. package/dist/server/user.js +3 -5
  39. package/dist/server/user.js.map +1 -1
  40. package/dist/utils/jwtSecret.d.ts +3 -3
  41. package/dist/utils/jwtSecret.js +5 -6
  42. package/dist/utils/jwtSecret.js.map +1 -1
  43. package/dist/utils/loadEnv.js +1 -1
  44. package/dist/utils/loadEnv.js.map +1 -1
  45. package/package.json +6 -4
  46. package/src/ClientManager.ts +6 -58
  47. package/src/Database.ts +83 -21
  48. package/src/Spire.ts +37 -108
  49. package/src/__tests__/Database.spec.ts +0 -17
  50. package/src/db/schema.ts +1 -0
  51. package/src/migrations/2026-04-14_argon2id-password-hashing.ts +18 -0
  52. package/src/run.ts +0 -1
  53. package/src/server/avatar.ts +7 -14
  54. package/src/server/errors.ts +3 -32
  55. package/src/server/file.ts +5 -10
  56. package/src/server/index.ts +23 -37
  57. package/src/server/invite.ts +0 -2
  58. package/src/server/rateLimit.ts +6 -6
  59. package/src/server/user.ts +2 -6
  60. package/src/utils/jwtSecret.ts +5 -6
  61. package/src/utils/loadEnv.ts +1 -1
  62. package/dist/utils/createLogger.d.ts +0 -5
  63. package/dist/utils/createLogger.js +0 -35
  64. package/dist/utils/createLogger.js.map +0 -1
  65. package/src/utils/createLogger.ts +0 -47
package/README.md CHANGED
@@ -1,56 +1,52 @@
1
1
  # @vex-chat/spire
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@vex-chat/spire?style=flat-square&color=cb3837&logo=npm)](https://www.npmjs.com/package/@vex-chat/spire)
4
- [![CI](https://img.shields.io/github/actions/workflow/status/vex-protocol/spire/build.yml?branch=master&style=flat-square&logo=github&label=CI)](https://github.com/vex-protocol/spire/actions/workflows/build.yml)
5
- [![Released](https://img.shields.io/github/release-date/vex-protocol/spire?style=flat-square&label=released)](https://github.com/vex-protocol/spire/releases)
4
+ [![CI](https://img.shields.io/github/actions/workflow/status/vex-protocol/spire-js/build.yml?branch=master&style=flat-square&logo=github&label=CI)](https://github.com/vex-protocol/spire-js/actions/workflows/build.yml)
5
+ [![Released](https://img.shields.io/github/release-date/vex-protocol/spire-js?style=flat-square&label=released)](https://github.com/vex-protocol/spire-js/releases)
6
6
  [![License](https://img.shields.io/npm/l/@vex-chat/spire?style=flat-square&color=blue)](./LICENSE)
7
- [![Type Coverage](https://img.shields.io/badge/dynamic/json?style=flat-square&label=type-coverage&prefix=%E2%89%A5&suffix=%25&query=$.typeCoverage.atLeast&url=https://raw.githubusercontent.com/vex-protocol/spire/master/package.json&color=3178c6&logo=typescript)](https://github.com/plantain-00/type-coverage)
7
+ [![Type Coverage](https://img.shields.io/badge/dynamic/json?style=flat-square&label=type-coverage&prefix=%E2%89%A5&suffix=%25&query=$.typeCoverage.atLeast&url=https://raw.githubusercontent.com/vex-protocol/spire-js/master/package.json&color=3178c6&logo=typescript)](https://github.com/plantain-00/type-coverage)
8
8
  [![Node](https://img.shields.io/node/v/@vex-chat/spire?style=flat-square&color=339933&logo=nodedotjs)](./package.json)
9
- [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/vex-protocol/spire?style=flat-square&label=Scorecard)](https://securityscorecards.dev/viewer/?uri=github.com/vex-protocol/spire)
9
+ [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/vex-protocol/spire-js?style=flat-square&label=Scorecard)](https://securityscorecards.dev/viewer/?uri=github.com/vex-protocol/spire-js)
10
10
  [![Socket](https://socket.dev/api/badge/npm/package/@vex-chat/spire)](https://socket.dev/npm/package/@vex-chat/spire)
11
11
 
12
- Reference server implementation for the [Vex](https://vex.wtf) encrypted chat platform. NodeJS + SQLite + TypeScript, running the wire protocol defined in [@vex-chat/types](https://github.com/vex-protocol/types-js).
12
+ Reference server implementation for the [Vex](https://vex.wtf) protocol.
13
13
 
14
14
  ## What's in the box
15
15
 
16
- - **REST API** (Express 5) for auth, registration, users, servers, channels, invites, and file upload.
17
- - **WebSocket server** (native `ws`) for real-time messaging, presence, and push notifications. Frames are msgpack-encoded per the AsyncAPI spec in `@vex-chat/types`.
18
- - **SQLite persistence** via Kysely + better-sqlite3. Single-file DB, zero external services.
19
- - **Runtime validation** on every trust boundary: every request body, query string, and WebSocket payload is parsed through a Zod schema before any logic runs.
20
- - **Interactive docs** — [Scalar](https://scalar.com) at `/docs` for the OpenAPI spec, the [AsyncAPI web component](https://www.asyncapi.com) at `/async-docs` for the WebSocket protocol. Both production-gated for security.
21
- - **Authentication** via `@vex-chat/crypto` signing keys plus JWT session tokens. Password hashing via native `node:crypto` PBKDF2.
16
+ - **REST API** (Express 5) for full e2e messaging including auth, registration, users, servers, channels, invites, and file upload.
22
17
 
23
18
  ## Install
24
19
 
25
- From public npm:
26
-
27
- ```sh
28
- npm install @vex-chat/spire
29
- ```
30
-
31
20
  Or clone the repo:
32
21
 
33
22
  ```sh
34
- git clone git@github.com:vex-protocol/spire
35
- cd spire
23
+ git clone git@github.com:vex-protocol/spire-js
24
+ cd spire-js
36
25
  npm ci
37
26
  ```
38
27
 
39
- ## Running the server
28
+ ## Running the server (Docker)
40
29
 
41
- Spire runs directly from source via `node --experimental-strip-types` — no pre-compile step needed in dev or prod. From a clone:
30
+ From a clone, with Docker and Docker Compose installed:
42
31
 
43
32
  ```sh
44
- npm start
33
+ cp .env.example .env
34
+ # set SPK, JWT_SECRET, DB_TYPE, … (see Configuration)
35
+ docker compose up --build
45
36
  ```
46
37
 
47
- Or equivalently:
38
+ Compose builds the image from this repo’s `Dockerfile`, starts Spire with a persistent **`spire-data`** volume mounted at `/data` (SQLite + `files/`, `avatars/`, `emoji/`), and fronts it with **nginx** on **port 8080**. Use **http://localhost:8080** for HTTP and WebSocket.
39
+
40
+ ## Running without Docker
41
+
42
+ For local development or if you installed from npm, Spire runs with `node --experimental-strip-types` (no separate compile step):
48
43
 
49
44
  ```sh
50
- node --experimental-strip-types src/run.ts
45
+ npm start
46
+ # or: node --experimental-strip-types src/run.ts
51
47
  ```
52
48
 
53
- From an npm install, the source ships in the tarball under `node_modules/@vex-chat/spire/src/`, so you can run it directly:
49
+ From an npm install, sources live under `node_modules/@vex-chat/spire/src/`:
54
50
 
55
51
  ```sh
56
52
  node --experimental-strip-types node_modules/@vex-chat/spire/src/run.ts
@@ -58,30 +54,33 @@ node --experimental-strip-types node_modules/@vex-chat/spire/src/run.ts
58
54
 
59
55
  ## Configuration
60
56
 
61
- Spire reads configuration from environment variables. Use a `.env` file at the repo root (or wherever you run it from) `dotenv` picks it up automatically.
57
+ Spire reads configuration from environment variables. **Docker Compose:** put them in a `.env` file next to `docker-compose.yml` (the `env_file` entry injects them into the container). **Bare Node:** `dotenv` loads `.env` from the process working directory when you run `src/run.ts`.
62
58
 
63
59
  ### Required
64
60
 
65
- | Variable | Description |
66
- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
67
- | `SPK` | Server private key, hex-encoded. Generate one with `npm run gen-spk`. Used for server identity signing and as the default JWT secret if `JWT_SECRET` isn't set. |
68
- | `DB_TYPE` | `sqlite`, `sqlite3`, or `sqlite3mem`. Controls database backend. `sqlite3mem` runs an in-memory database useful for tests. (MySQL support was removed in `1.0.0`; operators on older deploys should migrate out.) |
69
- | `CANARY` | `true` to enable canary mode (runs extra runtime assertions). `false` for standard production. |
61
+ | Variable | Description |
62
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
63
+ | `SPK` | Server private key, hex-encoded. Generate with `npm run gen-spk` (prints `SPK` and `JWT_SECRET` lines). Used for server identity signing (NaCl). |
64
+ | `JWT_SECRET` | Hex or string used as the **HMAC secret for JWTs** **required** and must be **separate from `SPK`**. `npm run gen-spk` emits a dedicated value; do not reuse `SPK` here. |
65
+ | `DB_TYPE` | `sqlite`, `sqlite3`, or `sqlite3mem`. All values use **SQLite** via `better-sqlite3` (file or `:memory:`). `sqlite3mem` is for tests. The string `mysql` is still accepted for compatibility but maps to the same SQLite setup as the default (there is no MySQL driver). |
70
66
 
71
67
  ### Optional
72
68
 
73
- | Variable | Default | Description |
74
- | ------------ | ------------- | -------------------------------------------------------------------------------------------------- |
75
- | `API_PORT` | `16777` | Port for the REST API and WebSocket server. |
76
- | `NODE_ENV` | `development` | `production` enables hardened Helmet CSP and disables interactive `/docs` / `/async-docs` viewers. |
77
- | `JWT_SECRET` | `SPK` | Override the JWT signing secret. Falls back to `SPK` if unset. |
69
+ | Variable | Default | Description |
70
+ | -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
71
+ | `API_PORT` | `16777` | Port for the REST API and WebSocket server (see `Spire` default in code if unset). |
72
+ | `NODE_ENV` | _(unset)_ | Set to `production` to disable interactive `/docs` / `/async-docs`. If unset or any other value, doc viewers are mounted. `helmet()` runs in all modes. |
73
+ | `CORS_ORIGINS` | _(empty)_ | Comma-separated allowed `Origin` values for `cors`. If unset or empty, **no cross-origin browser access** (`origin: false`). |
74
+ | `CANARY` | _(unset)_ | |
78
75
 
79
76
  ### Sample `.env`
80
77
 
81
78
  ```sh
82
- SPK=a1b2c3... # generate with `npm run gen-spk`
79
+ # Run `npm run gen-spk` and paste the two lines it prints (SPK + JWT_SECRET).
80
+ SPK=a1b2c3...
81
+ JWT_SECRET=d4e5f6...
83
82
  DB_TYPE=sqlite
84
- CANARY=false
83
+ # CANARY=true
85
84
  API_PORT=16777
86
85
  NODE_ENV=production
87
86
  ```
@@ -2,7 +2,6 @@ import type { Database } from "./Database.ts";
2
2
  import type { BaseMsg, Device, User, UserRecord } from "@vex-chat/types";
3
3
  import type WebSocket from "ws";
4
4
  import { EventEmitter } from "events";
5
- import { type SpireOptions } from "./Spire.ts";
6
5
  export declare const POWER_LEVELS: {
7
6
  CREATE: number;
8
7
  DELETE: number;
@@ -17,11 +16,10 @@ export declare class ClientManager extends EventEmitter {
17
16
  private db;
18
17
  private device;
19
18
  private failed;
20
- private log;
21
19
  private notify;
22
20
  private user;
23
21
  private userDetails;
24
- constructor(ws: WebSocket, db: Database, notify: (userID: string, event: string, transmissionID: string) => void, userDetails: User, options?: SpireOptions);
22
+ constructor(ws: WebSocket, db: Database, notify: (userID: string, event: string, transmissionID: string) => void, userDetails: User);
25
23
  getDevice(): Device;
26
24
  getUser(): UserRecord;
27
25
  send(msg: BaseMsg, header?: Uint8Array): void;
@@ -3,10 +3,8 @@ import { setTimeout as sleep } from "node:timers/promises";
3
3
  import { xConcat, XUtils } from "@vex-chat/crypto";
4
4
  import { xSignOpen } from "@vex-chat/crypto";
5
5
  import { MailWSSchema, SocketAuthErrors } from "@vex-chat/types";
6
- import pc from "picocolors";
7
6
  import { parse as uuidParse, validate as uuidValidate } from "uuid";
8
7
  import { TOKEN_EXPIRY } from "./Spire.js";
9
- import { createLogger } from "./utils/createLogger.js";
10
8
  import { createUint8UUID } from "./utils/createUint8UUID.js";
11
9
  import { msgpack } from "./utils/msgpack.js";
12
10
  export const POWER_LEVELS = {
@@ -27,11 +25,10 @@ export class ClientManager extends EventEmitter {
27
25
  db;
28
26
  device;
29
27
  failed = false;
30
- log;
31
28
  notify;
32
29
  user;
33
30
  userDetails;
34
- constructor(ws, db, notify, userDetails, options) {
31
+ constructor(ws, db, notify, userDetails) {
35
32
  super();
36
33
  this.conn = ws;
37
34
  this.db = db;
@@ -39,7 +36,6 @@ export class ClientManager extends EventEmitter {
39
36
  this.userDetails = userDetails;
40
37
  this.device = null;
41
38
  this.notify = notify;
42
- this.log = createLogger("client-manager", options?.logLevel || "error");
43
39
  this.initListeners();
44
40
  this.challenge();
45
41
  }
@@ -56,25 +52,12 @@ export class ClientManager extends EventEmitter {
56
52
  return this.user;
57
53
  }
58
54
  send(msg, header) {
59
- if (header) {
60
- this.log.debug(pc.bold(pc.red("OUTH")), header.toString());
61
- }
62
- else {
63
- this.log.debug(pc.bold(pc.red("OUTH")), emptyHeader.toString());
64
- }
65
55
  const packedMessage = packMessage(msg, header);
66
- this.log.info(pc.bold("⟶ ") +
67
- responseColor(msg.type.toUpperCase()) +
68
- " " +
69
- this.toString() +
70
- " " +
71
- pc.yellow(Buffer.byteLength(packedMessage)));
72
- this.log.debug(pc.bold(pc.red("OUT")), msg);
73
56
  try {
74
57
  this.conn.send(packedMessage);
75
58
  }
76
- catch (err) {
77
- this.log.warn(String(err));
59
+ catch (_err) {
60
+ // debugger: WS send failed
78
61
  this.fail();
79
62
  }
80
63
  }
@@ -103,7 +86,6 @@ export class ClientManager extends EventEmitter {
103
86
  if (this.failed) {
104
87
  return;
105
88
  }
106
- this.log.warn("Connection closed.");
107
89
  this.conn.close();
108
90
  this.failed = true;
109
91
  this.emit("fail");
@@ -124,23 +106,15 @@ export class ClientManager extends EventEmitter {
124
106
  this.fail();
125
107
  });
126
108
  this.conn.on("message", (message) => {
127
- const [header, msg] = unpackMessage(message);
128
109
  const size = Buffer.byteLength(message);
129
110
  if (size > MAX_MSG_SIZE) {
130
- this.sendErr(msg.transmissionID, "Message is too big. Received size " +
111
+ this.sendErr("00000000-0000-0000-0000-000000000000", "Message is too big. Received size " +
131
112
  String(size) +
132
113
  " while max size is " +
133
114
  String(MAX_MSG_SIZE));
134
115
  return;
135
116
  }
136
- this.log.info(pc.bold("⟵ ") +
137
- pc.bold(msg.type.toUpperCase()) +
138
- " " +
139
- this.toString() +
140
- " " +
141
- pc.yellow(String(size)));
142
- this.log.debug(pc.bold(pc.red("INH")), header.toString());
143
- this.log.debug(pc.bold(pc.red("IN")), msg);
117
+ const [header, msg] = unpackMessage(message);
144
118
  if (!msg.type) {
145
119
  this.sendErr(msg.transmissionID, "Message type is required.");
146
120
  return;
@@ -173,7 +147,6 @@ export class ClientManager extends EventEmitter {
173
147
  void this.verifyResponse(msg);
174
148
  break;
175
149
  default:
176
- this.log.info("unsupported message %s", msg.type);
177
150
  break;
178
151
  }
179
152
  });
@@ -191,7 +164,6 @@ export class ClientManager extends EventEmitter {
191
164
  const mail = mailResult.data;
192
165
  try {
193
166
  await this.db.saveMail(mail, header, this.getDevice().deviceID, this.getUser().userID);
194
- this.log.info("Received mail for " + mail.recipient);
195
167
  const deviceDetails = await this.db.retrieveDevice(mail.recipient);
196
168
  if (!deviceDetails) {
197
169
  this.sendErr(msg.transmissionID, "No associated user record found for device.");
@@ -201,13 +173,12 @@ export class ClientManager extends EventEmitter {
201
173
  this.notify(deviceDetails.owner, "mail", msg.transmissionID, null, mail.recipient);
202
174
  }
203
175
  catch (err) {
204
- this.log.error(String(err));
205
176
  this.sendErr(msg.transmissionID, String(err));
206
177
  }
207
178
  }
208
179
  break;
209
180
  default:
210
- this.log.info("Unsupported resource type " + msg.resourceType);
181
+ break;
211
182
  }
212
183
  }
213
184
  ping() {
@@ -279,7 +250,6 @@ export class ClientManager extends EventEmitter {
279
250
  }
280
251
  }
281
252
  if (!message) {
282
- this.log.warn("Signature verification failed!");
283
253
  this.sendAuthError(SocketAuthErrors.BadSignature);
284
254
  this.fail();
285
255
  return;
@@ -289,12 +259,10 @@ export class ClientManager extends EventEmitter {
289
259
  this.authorize(msg.transmissionID);
290
260
  }
291
261
  else {
292
- this.log.warn("Token is bad!");
293
262
  this.sendAuthError(SocketAuthErrors.InvalidToken);
294
263
  }
295
264
  }
296
265
  else {
297
- this.log.info("User is not registered.");
298
266
  this.sendAuthError(SocketAuthErrors.UserNotRegistered);
299
267
  this.fail();
300
268
  }
@@ -312,14 +280,4 @@ function unpackMessage(msg) {
312
280
  const msgb = msgpack.decode(msgp.slice(32));
313
281
  return [msgh, msgb];
314
282
  }
315
- const responseColor = (status) => {
316
- switch (status) {
317
- case "ERROR":
318
- return pc.bold(pc.red(status));
319
- case "SUCCESS":
320
- return pc.bold(pc.green(status));
321
- default:
322
- return status;
323
- }
324
- };
325
283
  //# sourceMappingURL=ClientManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClientManager.js","sourceRoot":"","sources":["../src/ClientManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ClientManager.js","sourceRoot":"","sources":["../src/ClientManager.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  import type { SpireOptions } from "./Spire.ts";
2
2
  import type { Channel, Device, DevicePayload, Emoji, FileSQL, Invite, KeyBundle, MailWS, Permission, PreKeysWS, RegistrationPayload, Server, UserRecord } from "@vex-chat/types";
3
3
  import { EventEmitter } from "events";
4
- export declare const ITERATIONS = 1000;
4
+ /** Internal record that includes the hash algorithm discriminator. */
5
+ export interface InternalUserRecord extends UserRecord {
6
+ hashAlgo: string;
7
+ }
5
8
  export declare class Database extends EventEmitter {
6
9
  private db;
7
- private log;
8
10
  constructor(options?: SpireOptions);
9
11
  close(): Promise<void>;
10
12
  createChannel(name: string, serverID: string): Promise<Channel>;
@@ -32,6 +34,7 @@ export declare class Database extends EventEmitter {
32
34
  isHealthy(): Promise<boolean>;
33
35
  markDeviceLogin(device: Device): Promise<void>;
34
36
  markUserSeen(user: UserRecord): Promise<void>;
37
+ rehashPassword(userID: string, newHash: string): Promise<void>;
35
38
  /**
36
39
  * Retrives a list of users that should be notified when a specific resourceID
37
40
  * experiences changes.
@@ -54,11 +57,28 @@ export declare class Database extends EventEmitter {
54
57
  retrieveServer(serverID: string): Promise<null | Server>;
55
58
  retrieveServerInvites(serverID: string): Promise<Invite[]>;
56
59
  retrieveServers(userID: string): Promise<Server[]>;
57
- retrieveUser(userIdentifier: string): Promise<null | UserRecord>;
60
+ retrieveUser(userIdentifier: string): Promise<InternalUserRecord | null>;
58
61
  retrieveUserDeviceList(userIDs: string[]): Promise<Device[]>;
59
- retrieveUsers(): Promise<UserRecord[]>;
62
+ retrieveUsers(): Promise<InternalUserRecord[]>;
60
63
  saveMail(mail: MailWS, header: Uint8Array, deviceID: string, userID: string): Promise<void>;
61
64
  saveOTK(userID: string, deviceID: string, otks: PreKeysWS[]): Promise<void>;
62
65
  private init;
63
66
  }
64
- export declare const hashPassword: (password: string, salt: Uint8Array) => NonSharedBuffer;
67
+ /**
68
+ * Hash a password with Argon2id (new default).
69
+ * Returns the encoded hash string which embeds salt, params, and digest.
70
+ */
71
+ export declare function hashPasswordArgon2(password: string): Promise<string>;
72
+ /**
73
+ * Verify a password against either Argon2id or legacy PBKDF2 storage.
74
+ * Returns `{ valid, needsRehash }` — callers should rehash on success
75
+ * when `needsRehash` is true.
76
+ */
77
+ export declare function verifyPassword(password: string, stored: {
78
+ hashAlgo: string;
79
+ passwordHash: string;
80
+ passwordSalt: string;
81
+ }): Promise<{
82
+ needsRehash: boolean;
83
+ valid: boolean;
84
+ }>;
package/dist/Database.js CHANGED
@@ -11,8 +11,9 @@ import { pbkdf2Sync } from "node:crypto";
11
11
  import * as fs from "node:fs/promises";
12
12
  import path from "node:path";
13
13
  import { fileURLToPath, pathToFileURL } from "node:url";
14
- import { xMakeNonce, XUtils } from "@vex-chat/crypto";
14
+ import { XUtils } from "@vex-chat/crypto";
15
15
  import { MailType } from "@vex-chat/types";
16
+ import argon2 from "argon2";
16
17
  /**
17
18
  * Narrow a plain integer from the `mailType` SQL column to the
18
19
  * `MailType` union (0 = initial, 1 = subsequent). Throws if the
@@ -30,7 +31,6 @@ function parseMailType(n) {
30
31
  import BetterSqlite3 from "better-sqlite3";
31
32
  import { Kysely, Migrator, sql, SqliteDialect } from "kysely";
32
33
  import { stringify as uuidStringify, validate as uuidValidate } from "uuid";
33
- import { createLogger } from "./utils/createLogger.js";
34
34
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
35
35
  const migrationFolder = path.join(__dirname, "migrations");
36
36
  /**
@@ -80,16 +80,12 @@ function isMigration(mod) {
80
80
  typeof mod.up === "function");
81
81
  }
82
82
  const pubkeyRegex = /[0-9a-f]{64}/;
83
- export const ITERATIONS = 1000;
84
- // ── Row-to-interface converters ─────────────────────────────────────────
85
- // SQLite stores booleans as integers and dates as strings, but the
86
- // @vex-chat/types interfaces expect boolean / Date.
83
+ /** Legacy iteration count kept only for verifying old PBKDF2 hashes. */
84
+ const PBKDF2_ITERATIONS = 1000;
87
85
  export class Database extends EventEmitter {
88
86
  db;
89
- log;
90
87
  constructor(options) {
91
88
  super();
92
- this.log = createLogger("spire-db", options?.logLevel || "error");
93
89
  const dbType = options?.dbType || "sqlite3";
94
90
  let filename;
95
91
  switch (dbType) {
@@ -117,7 +113,6 @@ export class Database extends EventEmitter {
117
113
  void this.init();
118
114
  }
119
115
  async close() {
120
- this.log.info("Closing database.");
121
116
  await this.db.destroy();
122
117
  }
123
118
  async createChannel(name, serverID) {
@@ -211,12 +206,11 @@ export class Database extends EventEmitter {
211
206
  }
212
207
  async createUser(regKey, regPayload) {
213
208
  try {
214
- const salt = xMakeNonce();
215
- const passwordHash = hashPassword(regPayload.password, salt);
209
+ const passwordHash = await hashPasswordArgon2(regPayload.password);
216
210
  const user = {
217
211
  lastSeen: new Date().toISOString(),
218
- passwordHash: passwordHash.toString("hex"),
219
- passwordSalt: XUtils.encodeHex(salt),
212
+ passwordHash,
213
+ passwordSalt: "",
220
214
  userID: uuidStringify(regKey),
221
215
  username: regPayload.username,
222
216
  };
@@ -224,6 +218,7 @@ export class Database extends EventEmitter {
224
218
  .insertInto("users")
225
219
  .values({
226
220
  ...user,
221
+ hashAlgo: "argon2id",
227
222
  lastSeen: user.lastSeen,
228
223
  })
229
224
  .execute();
@@ -401,8 +396,8 @@ export class Database extends EventEmitter {
401
396
  await sql `select 1 as ok`.execute(this.db);
402
397
  return true;
403
398
  }
404
- catch (err) {
405
- this.log.warn("Database health check failed: " + String(err));
399
+ catch (_err) {
400
+ // debugger: health check failed
406
401
  return false;
407
402
  }
408
403
  }
@@ -420,6 +415,17 @@ export class Database extends EventEmitter {
420
415
  .where("userID", "=", user.userID)
421
416
  .execute();
422
417
  }
418
+ async rehashPassword(userID, newHash) {
419
+ await this.db
420
+ .updateTable("users")
421
+ .set({
422
+ hashAlgo: "argon2id",
423
+ passwordHash: newHash,
424
+ passwordSalt: "",
425
+ })
426
+ .where("userID", "=", userID)
427
+ .execute();
428
+ }
423
429
  /**
424
430
  * Retrives a list of users that should be notified when a specific resourceID
425
431
  * experiences changes.
@@ -708,6 +714,39 @@ export class Database extends EventEmitter {
708
714
  this.emit("ready");
709
715
  }
710
716
  }
717
+ /**
718
+ * Hash a password with Argon2id (new default).
719
+ * Returns the encoded hash string which embeds salt, params, and digest.
720
+ */
721
+ export async function hashPasswordArgon2(password) {
722
+ return argon2.hash(password, {
723
+ memoryCost: 65536,
724
+ parallelism: 4,
725
+ timeCost: 3,
726
+ type: argon2.argon2id,
727
+ });
728
+ }
729
+ /**
730
+ * Verify a password against either Argon2id or legacy PBKDF2 storage.
731
+ * Returns `{ valid, needsRehash }` — callers should rehash on success
732
+ * when `needsRehash` is true.
733
+ */
734
+ export async function verifyPassword(password, stored) {
735
+ if (stored.hashAlgo === "argon2id") {
736
+ const valid = await argon2.verify(stored.passwordHash, password);
737
+ return { needsRehash: false, valid };
738
+ }
739
+ // Legacy PBKDF2 path
740
+ const salt = XUtils.decodeHex(stored.passwordSalt);
741
+ const computed = pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, 32, "sha512");
742
+ const storedBuf = XUtils.decodeHex(stored.passwordHash);
743
+ if (computed.length !== storedBuf.length) {
744
+ return { needsRehash: false, valid: false };
745
+ }
746
+ const { timingSafeEqual } = await import("node:crypto");
747
+ const valid = timingSafeEqual(computed, storedBuf);
748
+ return { needsRehash: valid, valid };
749
+ }
711
750
  function toDevice(row) {
712
751
  return { ...row, deleted: Boolean(row.deleted) };
713
752
  }
@@ -730,5 +769,4 @@ function toServer(row) {
730
769
  function toUserRecord(row) {
731
770
  return { ...row };
732
771
  }
733
- export const hashPassword = (password, salt) => pbkdf2Sync(password, salt, ITERATIONS, 32, "sha512");
734
772
  //# sourceMappingURL=Database.js.map