cursedbelt-server 4.13.0 → 4.14.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.
- package/dist/server/auth/password.js +4 -6
- package/dist/server/google-oauth/googleOAuth.d.ts +303 -0
- package/dist/server/google-oauth/googleOAuth.js +465 -0
- package/dist/server/guard/passwordVerifier.d.ts +1 -1
- package/dist/server/guard/passwordVerifier.js +3 -3
- package/dist/server/sync/tokens.d.ts +1 -1
- package/dist/server/sync/tokens.js +3 -2
- package/package.json +11 -3
- package/src/leafSubpathsImportNothing.spec.ts +10 -0
- package/src/publicSurface.spec.ts +13 -5
- package/src/server/auth/password.ts +4 -5
- package/src/server/google-oauth/googleOAuth.spec.ts +742 -0
- package/src/server/google-oauth/googleOAuth.ts +750 -0
- package/src/server/guard/passwordVerifier.ts +3 -3
- package/src/server/sync/tokens.ts +4 -3
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* every path including a thrown KDF. Callers hand over ownership and must not
|
|
30
30
|
* touch the buffer afterwards.
|
|
31
31
|
*/
|
|
32
|
-
import {
|
|
32
|
+
import { constantTimeEqualBytes } from 'cwip/constant-time';
|
|
33
33
|
import {
|
|
34
34
|
type Argon2idDeriver,
|
|
35
35
|
createSecretEnvelopeManager,
|
|
@@ -79,7 +79,7 @@ export function sealPasswordVerifier(userId: string, password: Uint8Array, deriv
|
|
|
79
79
|
* stored envelope is corruption, not a wrong password, and re-throws.
|
|
80
80
|
*
|
|
81
81
|
* The comparison is constant-time in the sensitive part: argon2id derivation
|
|
82
|
-
* dominates the timing, and GCM tag verification plus the final `
|
|
82
|
+
* dominates the timing, and GCM tag verification plus the final `constantTimeEqualBytes`
|
|
83
83
|
* are constant-time, so a right and a wrong password of equal length are
|
|
84
84
|
* indistinguishable by timing.
|
|
85
85
|
*/
|
|
@@ -106,7 +106,7 @@ export function verifyPasswordEnvelope(
|
|
|
106
106
|
// openWithPassphrase re-derives a one-shot key from the envelope's own salt +
|
|
107
107
|
// the presented password, opens, and zeroizes `password` on every path.
|
|
108
108
|
opened = manager.openWithPassphrase(envelope, refFor(userId), password);
|
|
109
|
-
return
|
|
109
|
+
return constantTimeEqualBytes(opened, VERIFIER_PLAINTEXT);
|
|
110
110
|
} catch (error) {
|
|
111
111
|
// GCM's rejection is the wrong-password verdict — the ONLY error we swallow.
|
|
112
112
|
if (isAppError(error) && error.code === 'SECRET_ENVELOPE_AUTH_FAILED') return false;
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* per capability, sha256 at rest so a database read never yields a usable credential).
|
|
5
5
|
*
|
|
6
6
|
* The plaintext token is returned exactly once, at mint. Verification compares sha256
|
|
7
|
-
* digests via `
|
|
7
|
+
* digests via cwip's `constantTimeEqualBytes` — no length guard, no early exit.
|
|
8
8
|
*/
|
|
9
9
|
import type { Database } from "bun:sqlite";
|
|
10
|
-
import { createHash, randomBytes
|
|
10
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
11
|
+
import { constantTimeEqualBytes } from "cwip/constant-time";
|
|
11
12
|
|
|
12
13
|
export interface DeviceToken {
|
|
13
14
|
name: string;
|
|
@@ -79,7 +80,7 @@ export function createTokenStore(db: Database): TokenStore {
|
|
|
79
80
|
// the lookup timing depend on the presented value.
|
|
80
81
|
for (const raw of allLive.all() as Row[]) {
|
|
81
82
|
const want = Buffer.from(raw.token_sha256);
|
|
82
|
-
if (
|
|
83
|
+
if (constantTimeEqualBytes(want, got)) {
|
|
83
84
|
if (raw.scope !== scope) return null;
|
|
84
85
|
return toToken(raw);
|
|
85
86
|
}
|