cursedbelt-core 2.6.0 → 2.7.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.
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one place a satellite's owner-password floor is decided.
|
|
3
3
|
*
|
|
4
|
-
* ── Why this is shared, and why the default is
|
|
4
|
+
* ── Why this is shared, and why the default is 6 ────────────────────────────
|
|
5
5
|
* Three apps had independently written a `MIN_PASSWORD_BYTES` constant into
|
|
6
6
|
* their own `scripts/owner.ts`, and they had already drifted (9, 14, 14) with
|
|
7
7
|
* a paragraph in each explaining itself against the others. A floor is a
|
|
8
8
|
* POLICY, and a policy copied three times is three policies.
|
|
9
9
|
*
|
|
10
|
-
* The default is {@link DEFAULT_MIN_PASSWORD_BYTES} =
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The default is {@link DEFAULT_MIN_PASSWORD_BYTES} = 6 — the owner, 2026-09-24:
|
|
11
|
+
* *"make the minimum password length 6 characters"* (it was 9). It is a SIGN-IN
|
|
12
|
+
* floor: every door that uses it rate-limits guesses, so a short password costs
|
|
13
|
+
* an attacker attempts, not seconds. A secret that can be guessed OFFLINE (vault's
|
|
14
|
+
* passphrase, which derives its encryption key) raises it at its own call site.
|
|
13
15
|
* Argon2id — what every caller hashes with — is what actually carries the cost
|
|
14
16
|
* of a guess here; these apps have exactly ONE principal and no enumerable user
|
|
15
17
|
* list, so the marginal value of characters 10–14 is small and the friction is
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
* {@link resolveMinPasswordBytes} takes an optional override and **refuses to
|
|
26
28
|
* go below the default**. An app that genuinely runs at higher stakes says so
|
|
27
29
|
* at its own call site, in one visible argument, with a comment saying why.
|
|
28
|
-
*
|
|
30
|
+
* `vault` does (9, since 2026-09-24 — its passphrase is an encryption key). The retired orch companion app did (14, as the single
|
|
29
31
|
* internet-facing door into the host that runs `claude` in every repo) until
|
|
30
32
|
* the owner dropped it to the shared floor on 2026-07-26.
|
|
31
33
|
*
|
|
@@ -38,12 +40,12 @@
|
|
|
38
40
|
* they read, so a multi-byte character counts as more than one, which is the
|
|
39
41
|
* conservative direction).
|
|
40
42
|
*/
|
|
41
|
-
export declare const DEFAULT_MIN_PASSWORD_BYTES =
|
|
43
|
+
export declare const DEFAULT_MIN_PASSWORD_BYTES = 6;
|
|
42
44
|
/**
|
|
43
45
|
* The floor this app enforces: the default, or a higher one it asks for.
|
|
44
46
|
*
|
|
45
47
|
* Throws on an override below the default rather than silently clamping. A
|
|
46
|
-
* caller passing
|
|
48
|
+
* caller passing 4 believes it is enforcing 4; being handed 6 without a word is
|
|
47
49
|
* how a security floor becomes folklore.
|
|
48
50
|
*/
|
|
49
51
|
export declare function resolveMinPasswordBytes(override?: number): number;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one place a satellite's owner-password floor is decided.
|
|
3
3
|
*
|
|
4
|
-
* ── Why this is shared, and why the default is
|
|
4
|
+
* ── Why this is shared, and why the default is 6 ────────────────────────────
|
|
5
5
|
* Three apps had independently written a `MIN_PASSWORD_BYTES` constant into
|
|
6
6
|
* their own `scripts/owner.ts`, and they had already drifted (9, 14, 14) with
|
|
7
7
|
* a paragraph in each explaining itself against the others. A floor is a
|
|
8
8
|
* POLICY, and a policy copied three times is three policies.
|
|
9
9
|
*
|
|
10
|
-
* The default is {@link DEFAULT_MIN_PASSWORD_BYTES} =
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The default is {@link DEFAULT_MIN_PASSWORD_BYTES} = 6 — the owner, 2026-09-24:
|
|
11
|
+
* *"make the minimum password length 6 characters"* (it was 9). It is a SIGN-IN
|
|
12
|
+
* floor: every door that uses it rate-limits guesses, so a short password costs
|
|
13
|
+
* an attacker attempts, not seconds. A secret that can be guessed OFFLINE (vault's
|
|
14
|
+
* passphrase, which derives its encryption key) raises it at its own call site.
|
|
13
15
|
* Argon2id — what every caller hashes with — is what actually carries the cost
|
|
14
16
|
* of a guess here; these apps have exactly ONE principal and no enumerable user
|
|
15
17
|
* list, so the marginal value of characters 10–14 is small and the friction is
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
* {@link resolveMinPasswordBytes} takes an optional override and **refuses to
|
|
26
28
|
* go below the default**. An app that genuinely runs at higher stakes says so
|
|
27
29
|
* at its own call site, in one visible argument, with a comment saying why.
|
|
28
|
-
*
|
|
30
|
+
* `vault` does (9, since 2026-09-24 — its passphrase is an encryption key). The retired orch companion app did (14, as the single
|
|
29
31
|
* internet-facing door into the host that runs `claude` in every repo) until
|
|
30
32
|
* the owner dropped it to the shared floor on 2026-07-26.
|
|
31
33
|
*
|
|
@@ -38,12 +40,12 @@
|
|
|
38
40
|
* they read, so a multi-byte character counts as more than one, which is the
|
|
39
41
|
* conservative direction).
|
|
40
42
|
*/
|
|
41
|
-
export const DEFAULT_MIN_PASSWORD_BYTES =
|
|
43
|
+
export const DEFAULT_MIN_PASSWORD_BYTES = 6;
|
|
42
44
|
/**
|
|
43
45
|
* The floor this app enforces: the default, or a higher one it asks for.
|
|
44
46
|
*
|
|
45
47
|
* Throws on an override below the default rather than silently clamping. A
|
|
46
|
-
* caller passing
|
|
48
|
+
* caller passing 4 believes it is enforcing 4; being handed 6 without a word is
|
|
47
49
|
* how a security floor becomes folklore.
|
|
48
50
|
*/
|
|
49
51
|
export function resolveMinPasswordBytes(override) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursedbelt-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Framework-agnostic core of the cursedbelt split — isomorphic domain logic. cwip below it, cursedbelt-server and cursedbelt (react) above it.",
|
|
@@ -7,13 +7,13 @@ import { DEFAULT_MIN_PASSWORD_BYTES, resolveMinPasswordBytes } from './passwordP
|
|
|
7
7
|
describe('resolveMinPasswordBytes', () => {
|
|
8
8
|
it('is the shared default when an app asks for nothing', () => {
|
|
9
9
|
expect(resolveMinPasswordBytes()).toBe(DEFAULT_MIN_PASSWORD_BYTES);
|
|
10
|
-
expect(DEFAULT_MIN_PASSWORD_BYTES).toBe(
|
|
10
|
+
expect(DEFAULT_MIN_PASSWORD_BYTES).toBe(6);
|
|
11
11
|
});
|
|
12
12
|
it('lets an app raise it, visibly, at its own call site', () => {
|
|
13
13
|
expect(resolveMinPasswordBytes(14)).toBe(14);
|
|
14
14
|
});
|
|
15
15
|
it('🔴 refuses to go BELOW the default, and refuses a non-integer', () => {
|
|
16
|
-
expect(() => resolveMinPasswordBytes(
|
|
17
|
-
expect(() => resolveMinPasswordBytes(
|
|
16
|
+
expect(() => resolveMinPasswordBytes(5)).toThrow(/may only be RAISED/);
|
|
17
|
+
expect(() => resolveMinPasswordBytes(6.5)).toThrow(/must be an integer/);
|
|
18
18
|
});
|
|
19
19
|
});
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one place a satellite's owner-password floor is decided.
|
|
3
3
|
*
|
|
4
|
-
* ── Why this is shared, and why the default is
|
|
4
|
+
* ── Why this is shared, and why the default is 6 ────────────────────────────
|
|
5
5
|
* Three apps had independently written a `MIN_PASSWORD_BYTES` constant into
|
|
6
6
|
* their own `scripts/owner.ts`, and they had already drifted (9, 14, 14) with
|
|
7
7
|
* a paragraph in each explaining itself against the others. A floor is a
|
|
8
8
|
* POLICY, and a policy copied three times is three policies.
|
|
9
9
|
*
|
|
10
|
-
* The default is {@link DEFAULT_MIN_PASSWORD_BYTES} =
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The default is {@link DEFAULT_MIN_PASSWORD_BYTES} = 6 — the owner, 2026-09-24:
|
|
11
|
+
* *"make the minimum password length 6 characters"* (it was 9). It is a SIGN-IN
|
|
12
|
+
* floor: every door that uses it rate-limits guesses, so a short password costs
|
|
13
|
+
* an attacker attempts, not seconds. A secret that can be guessed OFFLINE (vault's
|
|
14
|
+
* passphrase, which derives its encryption key) raises it at its own call site.
|
|
13
15
|
* Argon2id — what every caller hashes with — is what actually carries the cost
|
|
14
16
|
* of a guess here; these apps have exactly ONE principal and no enumerable user
|
|
15
17
|
* list, so the marginal value of characters 10–14 is small and the friction is
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
* {@link resolveMinPasswordBytes} takes an optional override and **refuses to
|
|
26
28
|
* go below the default**. An app that genuinely runs at higher stakes says so
|
|
27
29
|
* at its own call site, in one visible argument, with a comment saying why.
|
|
28
|
-
*
|
|
30
|
+
* `vault` does (9, since 2026-09-24 — its passphrase is an encryption key). The retired orch companion app did (14, as the single
|
|
29
31
|
* internet-facing door into the host that runs `claude` in every repo) until
|
|
30
32
|
* the owner dropped it to the shared floor on 2026-07-26.
|
|
31
33
|
*
|
|
@@ -39,13 +41,13 @@
|
|
|
39
41
|
* they read, so a multi-byte character counts as more than one, which is the
|
|
40
42
|
* conservative direction).
|
|
41
43
|
*/
|
|
42
|
-
export const DEFAULT_MIN_PASSWORD_BYTES =
|
|
44
|
+
export const DEFAULT_MIN_PASSWORD_BYTES = 6;
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* The floor this app enforces: the default, or a higher one it asks for.
|
|
46
48
|
*
|
|
47
49
|
* Throws on an override below the default rather than silently clamping. A
|
|
48
|
-
* caller passing
|
|
50
|
+
* caller passing 4 believes it is enforcing 4; being handed 6 without a word is
|
|
49
51
|
* how a security floor becomes folklore.
|
|
50
52
|
*/
|
|
51
53
|
export function resolveMinPasswordBytes(override?: number): number {
|