@getstrata/core 2.2.33 → 2.2.35
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/CHANGELOG.md +10 -0
- package/dist/core/auth/accountState.d.ts +9 -0
- package/dist/core/auth/accountStateMigration.d.ts +7 -0
- package/dist/core/auth/authContext.d.ts +3 -0
- package/dist/core/auth/guard.d.ts +1 -0
- package/dist/core/auth/jwt.d.ts +1 -0
- package/dist/core/auth/oneTimeToken.d.ts +2 -0
- package/dist/core/auth/passwordConfirmCookie.d.ts +2 -2
- package/dist/core/auth/passwordLogin.d.ts +2 -2
- package/dist/core/auth/pendingMfaCookie.d.ts +9 -0
- package/dist/core/auth/sessionCookie.d.ts +3 -0
- package/dist/core/contracts/authUserDirectory.d.ts +5 -0
- package/dist/entries/auth/accountState.js +18 -0
- package/dist/entries/auth/accountStateMigration.js +923 -0
- package/dist/entries/auth/basicAuthGuard.js +19 -1
- package/dist/entries/auth/jwtGuard.js +71 -23
- package/dist/entries/auth/oneTimeToken.js +16 -12
- package/dist/entries/auth/passwordConfirmCookie.js +63 -22
- package/dist/entries/auth/passwordLogin.js +15 -0
- package/dist/entries/auth/pendingMfaCookie.js +100 -0
- package/dist/entries/auth/sessionCookie.js +49 -21
- package/dist/entries/auth/sessionGuard.js +66 -22
- package/dist/entries/http/cookies.js +5 -1
- package/dist/entries/http/csrfMiddleware.js +5 -1
- package/dist/entries/http/csrfToken.js +5 -1
- package/dist/entries/http/requirePasswordConfirmMiddleware.js +1 -1
- package/dist/index.js +72 -38
- package/package.json +17 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @getstrata/core changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.35
|
|
4
|
+
|
|
5
|
+
Retire checked-in HiroApp applications after preserving security, CLI/OpenAPI/HTTP, source, migration and Docker acceptance in generated candidate-package fixtures. Keep all 23 security cases, 40 runtime operations, 22 API/protocol operations, three-engine migration cases and 18 compiler combinations. Make the private root CLI fixture-only, isolate post-commit HTTP databases, and validate the generated production image with restricted runtime credentials, Redis recovery and graceful shutdown. Remove obsolete app regeneration/selectors and update contributor, generator and deployment documentation; retain compatible example preset IDs and explicit application-owned deployment boundaries. Regenerate the sample SDK from the API-only snapshot and verify it against the installed candidate package. Core coverage retains 136 enforced files at 100%; remove only the two deleted private-entrypoint exemptions (272 remaining).
|
|
6
|
+
|
|
7
|
+
## 2.2.34
|
|
8
|
+
|
|
9
|
+
Complete opt-in persisted account-state adoption: atomic SCIM suspension/reactivation and credential revocation, serialized generated password/SSO issuance, version-bound session/MFA/confirmation proofs, safe optional credential-table handling and malformed-cookie rejection. Includes explicit schema migration and upgrade instructions; installing packages alone does not rewrite existing apps.
|
|
10
|
+
|
|
11
|
+
The admission and persistence foundations from #219/#221 are included: optional live status/epoch contracts, guarded additive users/session migrations, atomic epoch advancement, optional-table revocation fixes (#220) and malformed-cookie handling (#218). Legacy directories without metadata keep their admission contract. Epoch-aware revocation requires all custom issuers and security writers to participate in the documented protocol.
|
|
12
|
+
|
|
3
13
|
## 2.2.33
|
|
4
14
|
|
|
5
15
|
Fix shared tenant lookups in generated SQLite column-tenancy apps through typed repositories. Generated SCIM rejects unsupported status/profile mutations before writing and runs mutations in explicit transactions, including immediate observer rollback. Add actual SQLite and restricted Postgres HTTP regressions; full account deactivation remains unsupported and explicit.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AuthUserRecord } from "../contracts/authUserDirectory";
|
|
2
|
+
import type { AuthUser } from "./authContext";
|
|
3
|
+
/** Absence preserves legacy directories; an explicit non-true value fails closed. */
|
|
4
|
+
declare function isAccountActive(record: Pick<AuthUserRecord, "is_active">): boolean;
|
|
5
|
+
/** Custom/token directories must project current account state into their principal. */
|
|
6
|
+
declare function isAuthUserActive(user: AuthUser): boolean;
|
|
7
|
+
/** Opt-in epochs fence stateless credentials independently of wall-clock precision. */
|
|
8
|
+
declare function matchesAuthVersion(issued: unknown, current: number | undefined): boolean;
|
|
9
|
+
export { isAccountActive, isAuthUserActive, matchesAuthVersion };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Migration } from "../database/migrations/types";
|
|
2
|
+
import type { DatabaseDriver } from "../database/schema/driver";
|
|
3
|
+
/** Explicit additive adoption for the standard users table; never runs during authentication. */
|
|
4
|
+
declare function createAccountStateMigration(name: string, driver: DatabaseDriver, options?: {
|
|
5
|
+
sessions?: boolean;
|
|
6
|
+
}): Migration;
|
|
7
|
+
export { createAccountStateMigration };
|
|
@@ -2,6 +2,9 @@ type CredentialSource = "session" | "bearer" | "basic" | "guest" | null;
|
|
|
2
2
|
type AuthUser = {
|
|
3
3
|
id: number | string;
|
|
4
4
|
role?: string;
|
|
5
|
+
/** Current state from a trusted directory/guard, never an unverified client claim. */
|
|
6
|
+
isActive?: boolean;
|
|
7
|
+
authVersion?: number;
|
|
5
8
|
abilities?: string[];
|
|
6
9
|
tokenId?: number;
|
|
7
10
|
emailVerifiedAt?: Date | string | null;
|
|
@@ -40,6 +40,7 @@ declare class AuthManager {
|
|
|
40
40
|
user(request?: Request): Promise<AuthUser | null>;
|
|
41
41
|
check(request?: Request): Promise<boolean>;
|
|
42
42
|
requireUser(request?: Request): Promise<AuthUser>;
|
|
43
|
+
private resolveGuard;
|
|
43
44
|
private authenticateRequest;
|
|
44
45
|
private tryNamedGuards;
|
|
45
46
|
}
|
package/dist/core/auth/jwt.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ type SqlClient = {
|
|
|
14
14
|
declare function consumeOneTimeToken(sql: SqlClient, purpose: string, plain: string, now?: Date): Promise<number | null>;
|
|
15
15
|
declare function revokeUserSessions(sql: SqlClient, userId: number, options?: {
|
|
16
16
|
revokeApiTokens?: boolean;
|
|
17
|
+
/** Requires the account-state migration. Call within the account mutation transaction. */
|
|
18
|
+
incrementAuthVersion?: boolean;
|
|
17
19
|
}): Promise<void>;
|
|
18
20
|
export type { AuthOneTimePurpose };
|
|
19
21
|
export { AUTH_ONE_TIME_PURPOSES, consumeOneTimeToken, generateOneTimeToken, hashOneTimeToken, revokeUserSessions, };
|
|
@@ -2,7 +2,7 @@ declare const PASSWORD_CONFIRM_COOKIE: string;
|
|
|
2
2
|
declare const DEFAULT_PASSWORD_CONFIRM_TTL_SECONDS: number;
|
|
3
3
|
declare function passwordConfirmCookieName(): string;
|
|
4
4
|
declare function passwordConfirmTtlSeconds(): number;
|
|
5
|
-
declare function hasFreshPasswordConfirmation(request: Request, userId: number): boolean;
|
|
6
|
-
declare function createPasswordConfirmCookie(userId: number): string;
|
|
5
|
+
declare function hasFreshPasswordConfirmation(request: Request, userId: number, authVersion?: number): boolean;
|
|
6
|
+
declare function createPasswordConfirmCookie(userId: number, authVersion?: number): string;
|
|
7
7
|
declare function clearPasswordConfirmCookie(): string;
|
|
8
8
|
export { clearPasswordConfirmCookie, createPasswordConfirmCookie, DEFAULT_PASSWORD_CONFIRM_TTL_SECONDS, hasFreshPasswordConfirmation, PASSWORD_CONFIRM_COOKIE, passwordConfirmCookieName, passwordConfirmTtlSeconds, };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthUserRecord } from "../contracts/authUserDirectory";
|
|
2
|
-
type PasswordLoginFailure = "mfa_required" | "mfa_invalid";
|
|
2
|
+
type PasswordLoginFailure = "mfa_required" | "mfa_invalid" | "account_inactive";
|
|
3
3
|
type PasswordLoginSuccess = {
|
|
4
4
|
ok: true;
|
|
5
5
|
consumedRecoveryHash?: string;
|
|
@@ -10,7 +10,7 @@ type PasswordLoginDenied = {
|
|
|
10
10
|
};
|
|
11
11
|
type PasswordLoginResult = PasswordLoginSuccess | PasswordLoginDenied;
|
|
12
12
|
declare function parseRecoveryHashes(raw: string | null | undefined): string[];
|
|
13
|
-
declare function completePasswordLogin(user: Pick<AuthUserRecord, "mfa_enabled" | "mfa_secret" | "mfa_recovery_codes">, options?: {
|
|
13
|
+
declare function completePasswordLogin(user: Pick<AuthUserRecord, "is_active" | "mfa_enabled" | "mfa_secret" | "mfa_recovery_codes">, options?: {
|
|
14
14
|
mfaCode?: string | null;
|
|
15
15
|
}): PasswordLoginResult;
|
|
16
16
|
declare function persistConsumedRecoveryHash(sql: {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface PendingMfaChallenge {
|
|
2
|
+
userId: number;
|
|
3
|
+
authVersion: number;
|
|
4
|
+
}
|
|
5
|
+
declare function createPendingMfaCookie(userId: number, authVersion: number, secret: string): string;
|
|
6
|
+
declare function readPendingMfaCookie(request: Request, secret: string): PendingMfaChallenge | null;
|
|
7
|
+
declare function clearPendingMfaCookie(): string;
|
|
8
|
+
export type { PendingMfaChallenge };
|
|
9
|
+
export { clearPendingMfaCookie, createPendingMfaCookie, readPendingMfaCookie };
|
|
@@ -3,10 +3,12 @@ declare const SESSION_TTL_SECONDS: number;
|
|
|
3
3
|
declare const SESSION_REMEMBER_TTL_SECONDS: number;
|
|
4
4
|
interface CreateSessionCookieOptions {
|
|
5
5
|
remember?: boolean;
|
|
6
|
+
authVersion?: number;
|
|
6
7
|
}
|
|
7
8
|
interface SignedSession {
|
|
8
9
|
userId: number;
|
|
9
10
|
issuedAt: number;
|
|
11
|
+
authVersion?: number;
|
|
10
12
|
}
|
|
11
13
|
declare function sessionCookieName(): string;
|
|
12
14
|
declare function sessionTtlSeconds(): number;
|
|
@@ -15,6 +17,7 @@ declare function readSession(request: Request): SignedSession | null;
|
|
|
15
17
|
declare function readSessionUserId(request: Request): number | null;
|
|
16
18
|
declare function isSessionInvalidated(issuedAt: number, validAfter: Date | string | null | undefined): boolean;
|
|
17
19
|
interface SessionCookieDetails {
|
|
20
|
+
authVersion?: number;
|
|
18
21
|
header: string;
|
|
19
22
|
userId: number;
|
|
20
23
|
issuedAt: number;
|
|
@@ -4,6 +4,10 @@ interface AuthUserRecord {
|
|
|
4
4
|
name?: string | null;
|
|
5
5
|
email?: string | null;
|
|
6
6
|
role: string;
|
|
7
|
+
/** Optional account-status contract; missing preserves legacy behavior. */
|
|
8
|
+
is_active?: boolean;
|
|
9
|
+
/** Optional non-negative safe-integer credential epoch; never reset on reactivation. */
|
|
10
|
+
auth_version?: number;
|
|
7
11
|
email_verified_at?: Date | string | null;
|
|
8
12
|
session_valid_after?: Date | string | null;
|
|
9
13
|
password?: string | null;
|
|
@@ -12,6 +16,7 @@ interface AuthUserRecord {
|
|
|
12
16
|
mfa_recovery_codes?: string | null;
|
|
13
17
|
}
|
|
14
18
|
interface AuthUserDirectory {
|
|
19
|
+
/** Participating directories must project fresh account status as AuthUser.isActive. */
|
|
15
20
|
resolveUserFromToken(token: string): Promise<AuthUser | null>;
|
|
16
21
|
findByIdOrThrow(id: number): Promise<AuthUserRecord>;
|
|
17
22
|
hasActiveBrowserSession?(userId: number, issuedAt: number): Promise<boolean>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/core/auth/accountState.ts
|
|
3
|
+
function isAccountActive(record) {
|
|
4
|
+
return record.is_active === undefined || record.is_active === true;
|
|
5
|
+
}
|
|
6
|
+
function isAuthUserActive(user) {
|
|
7
|
+
return user.isActive === undefined || user.isActive === true;
|
|
8
|
+
}
|
|
9
|
+
function matchesAuthVersion(issued, current) {
|
|
10
|
+
if (current === undefined)
|
|
11
|
+
return true;
|
|
12
|
+
return Number.isSafeInteger(current) && current >= 0 && typeof issued === "number" && Number.isSafeInteger(issued) && issued >= 0 && issued === current;
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
isAccountActive,
|
|
16
|
+
isAuthUserActive,
|
|
17
|
+
matchesAuthVersion
|
|
18
|
+
};
|