@aooth/user 0.1.6 → 0.1.7

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,4 +1,4 @@
1
- import { S as UserCredentials, n as WithCasOptions, t as UserStore, w as UserStoreUpdate } from "./user-store-B3EStUfT.cjs";
1
+ import { S as UserCredentials, n as WithCasOptions, t as UserStore, w as UserStoreUpdate } from "./user-store-BZsKtBHy.cjs";
2
2
 
3
3
  //#region src/atscript-db/index.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as UserCredentials, n as WithCasOptions, t as UserStore, w as UserStoreUpdate } from "./user-store-C1lxahSB.mjs";
1
+ import { S as UserCredentials, n as WithCasOptions, t as UserStore, w as UserStoreUpdate } from "./user-store-62LCSa8q.mjs";
2
2
 
3
3
  //#region src/atscript-db/index.d.ts
4
4
  /**
package/dist/index.cjs CHANGED
@@ -338,7 +338,8 @@ function resolveConfig(config) {
338
338
  scryptR: config?.password?.scryptR ?? 8,
339
339
  scryptP: config?.password?.scryptP ?? 1,
340
340
  keyLength: config?.password?.keyLength ?? 64,
341
- policies: normalizePolicies(config?.password?.policies)
341
+ policies: normalizePolicies(config?.password?.policies),
342
+ maxAgeMs: config?.password?.maxAgeMs ?? 0
342
343
  },
343
344
  lockout: {
344
345
  threshold: config?.lockout?.threshold ?? 0,
@@ -506,6 +507,24 @@ var UserService = class {
506
507
  lockEnds: account.lockEnds
507
508
  };
508
509
  }
510
+ /**
511
+ * Returns `true` when the user's password is older than
512
+ * `config.password.maxAgeMs`. Returns `false` when:
513
+ * - `maxAgeMs` is unset or `0` (expiry disabled)
514
+ * - `password.lastChanged` is `0` / falsy (no recorded change — never
515
+ * expire a user whose timestamp wasn't captured, since that would
516
+ * force-loop on every login)
517
+ *
518
+ * Consulted by `@aooth/auth-moost` `LoginWorkflow`'s `credentials`
519
+ * step to set `ctx.isPasswordExpired` when `guards.passwordExpiry`
520
+ * is true (the default).
521
+ */
522
+ isPasswordExpired(user, now = this.config.clock()) {
523
+ const maxAgeMs = this.config.password.maxAgeMs;
524
+ const lastChanged = user.password.lastChanged;
525
+ if (!maxAgeMs || !lastChanged) return false;
526
+ return now - lastChanged > maxAgeMs;
527
+ }
509
528
  async checkPolicies(password, passwordData) {
510
529
  const result = {
511
530
  passed: true,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as UserServiceConfig, S as UserCredentials, _ as PolicyCheckResult, a as LockStatus, b as TrustedDeviceRecord, c as MfaData, d as PasswordConfig, f as PasswordData, g as PasswordPolicyInstance, h as PasswordPolicyEvalFn, i as DeepPartial, l as MfaMethod, m as PasswordPolicyDef, n as WithCasOptions, o as LockoutConfig, p as PasswordPolicyContext, r as AccountData, s as LoginResult, t as UserStore, u as MfaMethodInfo, v as TotpConfig, w as UserStoreUpdate, x as UserAuthErrorType, y as TransferablePolicy } from "./user-store-B3EStUfT.cjs";
1
+ import { C as UserServiceConfig, S as UserCredentials, _ as PolicyCheckResult, a as LockStatus, b as TrustedDeviceRecord, c as MfaData, d as PasswordConfig, f as PasswordData, g as PasswordPolicyInstance, h as PasswordPolicyEvalFn, i as DeepPartial, l as MfaMethod, m as PasswordPolicyDef, n as WithCasOptions, o as LockoutConfig, p as PasswordPolicyContext, r as AccountData, s as LoginResult, t as UserStore, u as MfaMethodInfo, v as TotpConfig, w as UserStoreUpdate, x as UserAuthErrorType, y as TransferablePolicy } from "./user-store-BZsKtBHy.cjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
4
  declare class UserAuthError extends Error {
@@ -117,6 +117,19 @@ declare class UserService<T extends object = object> {
117
117
  lockAccount(username: string, reason: string, duration?: number): Promise<void>;
118
118
  unlockAccount(username: string): Promise<void>;
119
119
  getLockStatus(account: UserCredentials["account"]): LockStatus;
120
+ /**
121
+ * Returns `true` when the user's password is older than
122
+ * `config.password.maxAgeMs`. Returns `false` when:
123
+ * - `maxAgeMs` is unset or `0` (expiry disabled)
124
+ * - `password.lastChanged` is `0` / falsy (no recorded change — never
125
+ * expire a user whose timestamp wasn't captured, since that would
126
+ * force-loop on every login)
127
+ *
128
+ * Consulted by `@aooth/auth-moost` `LoginWorkflow`'s `credentials`
129
+ * step to set `ctx.isPasswordExpired` when `guards.passwordExpiry`
130
+ * is true (the default).
131
+ */
132
+ isPasswordExpired(user: UserCredentials & T, now?: number): boolean;
120
133
  checkPolicies(password: string, passwordData?: PasswordData): Promise<PolicyCheckResult>;
121
134
  getTransferablePolicies(): TransferablePolicy[];
122
135
  addMfaMethod(username: string, method: MfaMethod): Promise<void>;
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as UserServiceConfig, S as UserCredentials, _ as PolicyCheckResult, a as LockStatus, b as TrustedDeviceRecord, c as MfaData, d as PasswordConfig, f as PasswordData, g as PasswordPolicyInstance, h as PasswordPolicyEvalFn, i as DeepPartial, l as MfaMethod, m as PasswordPolicyDef, n as WithCasOptions, o as LockoutConfig, p as PasswordPolicyContext, r as AccountData, s as LoginResult, t as UserStore, u as MfaMethodInfo, v as TotpConfig, w as UserStoreUpdate, x as UserAuthErrorType, y as TransferablePolicy } from "./user-store-C1lxahSB.mjs";
1
+ import { C as UserServiceConfig, S as UserCredentials, _ as PolicyCheckResult, a as LockStatus, b as TrustedDeviceRecord, c as MfaData, d as PasswordConfig, f as PasswordData, g as PasswordPolicyInstance, h as PasswordPolicyEvalFn, i as DeepPartial, l as MfaMethod, m as PasswordPolicyDef, n as WithCasOptions, o as LockoutConfig, p as PasswordPolicyContext, r as AccountData, s as LoginResult, t as UserStore, u as MfaMethodInfo, v as TotpConfig, w as UserStoreUpdate, x as UserAuthErrorType, y as TransferablePolicy } from "./user-store-62LCSa8q.mjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
4
  declare class UserAuthError extends Error {
@@ -117,6 +117,19 @@ declare class UserService<T extends object = object> {
117
117
  lockAccount(username: string, reason: string, duration?: number): Promise<void>;
118
118
  unlockAccount(username: string): Promise<void>;
119
119
  getLockStatus(account: UserCredentials["account"]): LockStatus;
120
+ /**
121
+ * Returns `true` when the user's password is older than
122
+ * `config.password.maxAgeMs`. Returns `false` when:
123
+ * - `maxAgeMs` is unset or `0` (expiry disabled)
124
+ * - `password.lastChanged` is `0` / falsy (no recorded change — never
125
+ * expire a user whose timestamp wasn't captured, since that would
126
+ * force-loop on every login)
127
+ *
128
+ * Consulted by `@aooth/auth-moost` `LoginWorkflow`'s `credentials`
129
+ * step to set `ctx.isPasswordExpired` when `guards.passwordExpiry`
130
+ * is true (the default).
131
+ */
132
+ isPasswordExpired(user: UserCredentials & T, now?: number): boolean;
120
133
  checkPolicies(password: string, passwordData?: PasswordData): Promise<PolicyCheckResult>;
121
134
  getTransferablePolicies(): TransferablePolicy[];
122
135
  addMfaMethod(username: string, method: MfaMethod): Promise<void>;
package/dist/index.mjs CHANGED
@@ -337,7 +337,8 @@ function resolveConfig(config) {
337
337
  scryptR: config?.password?.scryptR ?? 8,
338
338
  scryptP: config?.password?.scryptP ?? 1,
339
339
  keyLength: config?.password?.keyLength ?? 64,
340
- policies: normalizePolicies(config?.password?.policies)
340
+ policies: normalizePolicies(config?.password?.policies),
341
+ maxAgeMs: config?.password?.maxAgeMs ?? 0
341
342
  },
342
343
  lockout: {
343
344
  threshold: config?.lockout?.threshold ?? 0,
@@ -505,6 +506,24 @@ var UserService = class {
505
506
  lockEnds: account.lockEnds
506
507
  };
507
508
  }
509
+ /**
510
+ * Returns `true` when the user's password is older than
511
+ * `config.password.maxAgeMs`. Returns `false` when:
512
+ * - `maxAgeMs` is unset or `0` (expiry disabled)
513
+ * - `password.lastChanged` is `0` / falsy (no recorded change — never
514
+ * expire a user whose timestamp wasn't captured, since that would
515
+ * force-loop on every login)
516
+ *
517
+ * Consulted by `@aooth/auth-moost` `LoginWorkflow`'s `credentials`
518
+ * step to set `ctx.isPasswordExpired` when `guards.passwordExpiry`
519
+ * is true (the default).
520
+ */
521
+ isPasswordExpired(user, now = this.config.clock()) {
522
+ const maxAgeMs = this.config.password.maxAgeMs;
523
+ const lastChanged = user.password.lastChanged;
524
+ if (!maxAgeMs || !lastChanged) return false;
525
+ return now - lastChanged > maxAgeMs;
526
+ }
508
527
  async checkPolicies(password, passwordData) {
509
528
  const result = {
510
529
  passed: true,
@@ -113,6 +113,14 @@ interface PasswordConfig {
113
113
  keyLength?: number;
114
114
  /** Password policy rules */
115
115
  policies?: (PasswordPolicyDef | PasswordPolicyInstance)[];
116
+ /**
117
+ * Force re-set of an existing password after this many ms since
118
+ * `password.lastChanged`. `0` / undefined disables expiry. Read by
119
+ * `UserService.isPasswordExpired()`; consulted by `@aooth/auth-moost`
120
+ * `LoginWorkflow`'s forced-change branch when `guards.passwordExpiry`
121
+ * is true (the default).
122
+ */
123
+ maxAgeMs?: number;
116
124
  }
117
125
  interface LockoutConfig {
118
126
  /** Lock after this many failed attempts (0 = disabled) */
@@ -113,6 +113,14 @@ interface PasswordConfig {
113
113
  keyLength?: number;
114
114
  /** Password policy rules */
115
115
  policies?: (PasswordPolicyDef | PasswordPolicyInstance)[];
116
+ /**
117
+ * Force re-set of an existing password after this many ms since
118
+ * `password.lastChanged`. `0` / undefined disables expiry. Read by
119
+ * `UserService.isPasswordExpired()`; consulted by `@aooth/auth-moost`
120
+ * `LoginWorkflow`'s forced-change branch when `guards.passwordExpiry`
121
+ * is true (the default).
122
+ */
123
+ maxAgeMs?: number;
116
124
  }
117
125
  interface LockoutConfig {
118
126
  /** Lock after this many failed attempts (0 = disabled) */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aooth/user",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "User credential primitives for aoothjs",
5
5
  "keywords": [
6
6
  "aoothjs",
@@ -47,9 +47,9 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@atscript/core": "^0.1.64",
50
- "@atscript/db": "^0.1.90",
51
- "@atscript/db-sql-tools": "^0.1.90",
52
- "@atscript/db-sqlite": "^0.1.90",
50
+ "@atscript/db": "^0.1.91",
51
+ "@atscript/db-sql-tools": "^0.1.91",
52
+ "@atscript/db-sqlite": "^0.1.91",
53
53
  "@atscript/typescript": "^0.1.64",
54
54
  "@types/better-sqlite3": "^7.6.13",
55
55
  "better-sqlite3": "^12.6.2",