@spfn/auth 0.2.0-beta.70 → 0.2.0-beta.71

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.js CHANGED
@@ -5658,6 +5658,25 @@ var init_keys_repository = __esm({
5658
5658
  ).returning();
5659
5659
  return result[0] ?? null;
5660
5660
  }
5661
+ /**
5662
+ * 사용자의 모든 활성 공개키 revoke (비활성화)
5663
+ *
5664
+ * 비번 변경 시 전체 세션 로그아웃에 사용. authenticate는 활성 키만 검증하므로,
5665
+ * revoke된 키로 서명한 기존 세션의 요청은 즉시 401이 된다.
5666
+ * Write primary 사용
5667
+ */
5668
+ async revokeAllActiveByUserId(userId, reason) {
5669
+ return await this.db.update(userPublicKeys).set({
5670
+ isActive: false,
5671
+ revokedAt: /* @__PURE__ */ new Date(),
5672
+ revokedReason: reason
5673
+ }).where(
5674
+ and2(
5675
+ eq2(userPublicKeys.userId, userId),
5676
+ eq2(userPublicKeys.isActive, true)
5677
+ )
5678
+ ).returning();
5679
+ }
5661
5680
  /**
5662
5681
  * 공개키 삭제
5663
5682
  * Write primary 사용
@@ -6936,13 +6955,23 @@ function getPublicKeyObject(publicKeyB64) {
6936
6955
  publicKeyCache.set(publicKeyB64, keyObject);
6937
6956
  return keyObject;
6938
6957
  }
6958
+ var INSECURE_JWT_SECRET = "dev-secret-key-change-in-production";
6959
+ function getJwtSecret() {
6960
+ const secret = env2.SPFN_AUTH_JWT_SECRET;
6961
+ if ((!secret || secret === INSECURE_JWT_SECRET) && process.env.NODE_ENV === "production") {
6962
+ throw new Error(
6963
+ "SPFN_AUTH_JWT_SECRET must be set to a strong secret in production (the default is public)."
6964
+ );
6965
+ }
6966
+ return secret;
6967
+ }
6939
6968
  function generateToken(payload) {
6940
- return jwt.sign(payload, env2.SPFN_AUTH_JWT_SECRET, {
6969
+ return jwt.sign(payload, getJwtSecret(), {
6941
6970
  expiresIn: env2.SPFN_AUTH_JWT_EXPIRES_IN
6942
6971
  });
6943
6972
  }
6944
6973
  function verifyToken(token) {
6945
- return jwt.verify(token, env2.SPFN_AUTH_JWT_SECRET, { algorithms: ["HS256"] });
6974
+ return jwt.verify(token, getJwtSecret(), { algorithms: ["HS256"] });
6946
6975
  }
6947
6976
  function verifyClientToken(token, publicKeyB64, algorithm) {
6948
6977
  const publicKeyObject = getPublicKeyObject(publicKeyB64);
@@ -7082,6 +7111,9 @@ async function validateVerificationCode(target, code, purpose) {
7082
7111
  if (!record) {
7083
7112
  return { valid: false, error: "Invalid verification code" };
7084
7113
  }
7114
+ if (record.attempts >= MAX_VERIFICATION_ATTEMPTS) {
7115
+ return { valid: false, error: "Too many attempts, please request a new code" };
7116
+ }
7085
7117
  if (record.code !== code) {
7086
7118
  await verificationCodesRepository.incrementAttempts(record.id);
7087
7119
  return { valid: false, error: "Invalid verification code" };
@@ -7092,9 +7124,6 @@ async function validateVerificationCode(target, code, purpose) {
7092
7124
  if (/* @__PURE__ */ new Date() > new Date(record.expiresAt)) {
7093
7125
  return { valid: false, error: "Verification code expired" };
7094
7126
  }
7095
- if (record.attempts >= MAX_VERIFICATION_ATTEMPTS) {
7096
- return { valid: false, error: "Too many attempts, please request a new code" };
7097
- }
7098
7127
  return { valid: true, codeId: record.id };
7099
7128
  }
7100
7129
  async function markCodeAsUsed(codeId) {
@@ -7549,6 +7578,7 @@ async function changePasswordService(params) {
7549
7578
  }
7550
7579
  const newPasswordHash = await hashPassword(newPassword);
7551
7580
  await usersRepository.updatePassword(userId, newPasswordHash, true);
7581
+ await keysRepository.revokeAllActiveByUserId(userId, "Revoked by password change");
7552
7582
  }
7553
7583
 
7554
7584
  // src/server/services/rbac.service.ts
@@ -9251,7 +9281,8 @@ var acceptInvitation2 = route2.post("/_auth/invitations/accept").input({
9251
9281
  }),
9252
9282
  password: Type.String({
9253
9283
  minLength: 8,
9254
- description: "User password (minimum 8 characters)"
9284
+ maxLength: 72,
9285
+ description: "User password (8\u201372 characters). bcrypt silently ignores bytes past 72, so longer inputs are rejected rather than truncated."
9255
9286
  })
9256
9287
  })
9257
9288
  }).interceptor({