This commit is contained in:
Maidul Islam
2025-03-11 13:08:04 -04:00
parent f5749e326a
commit edf6a37fe5
4 changed files with 52 additions and 41 deletions
@@ -114,15 +114,17 @@ export const DynamicSecretSqlDBSchema = z.object({
passwordRequirements: z passwordRequirements: z
.object({ .object({
length: z.number().min(1).max(250), length: z.number().min(1).max(250),
required: z.object({ required: z
lowercase: z.number().min(0), .object({
uppercase: z.number().min(0), lowercase: z.number().min(0),
digits: z.number().min(0), uppercase: z.number().min(0),
symbols: z.number().min(0) digits: z.number().min(0),
}).refine((data) => { symbols: z.number().min(0)
const total = Object.values(data).reduce((sum, count) => sum + count, 0); })
return total <= 250; .refine((data) => {
}, "Sum of required characters cannot exceed 250"), const total = Object.values(data).reduce((sum, count) => sum + count, 0);
return total <= 250;
}, "Sum of required characters cannot exceed 250"),
allowedSymbols: z.string().optional() allowedSymbols: z.string().optional()
}) })
.refine((data) => { .refine((data) => {
@@ -130,7 +132,7 @@ export const DynamicSecretSqlDBSchema = z.object({
return total <= data.length; return total <= data.length;
}, "Sum of required characters cannot exceed the total length") }, "Sum of required characters cannot exceed the total length")
.optional() .optional()
.describe('Password generation requirements'), .describe("Password generation requirements"),
creationStatement: z.string().trim(), creationStatement: z.string().trim(),
revocationStatement: z.string().trim(), revocationStatement: z.string().trim(),
renewStatement: z.string().trim().optional(), renewStatement: z.string().trim().optional(),
@@ -1,8 +1,7 @@
import { randomInt } from "crypto";
import handlebars from "handlebars"; import handlebars from "handlebars";
import knex from "knex"; import knex from "knex";
import { customAlphabet } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { randomInt } from 'crypto';
import { withGatewayProxy } from "@app/lib/gateway"; import { withGatewayProxy } from "@app/lib/gateway";
import { alphaNumericNanoId } from "@app/lib/nanoid"; import { alphaNumericNanoId } from "@app/lib/nanoid";
@@ -21,7 +20,7 @@ const DEFAULT_PASSWORD_REQUIREMENTS = {
digits: 1, digits: 1,
symbols: 0 symbols: 0
}, },
allowedSymbols: '-_.~!*' allowedSymbols: "-_.~!*"
}; };
const ORACLE_PASSWORD_REQUIREMENTS = { const ORACLE_PASSWORD_REQUIREMENTS = {
@@ -37,36 +36,44 @@ const generatePassword = (provider: SqlProviders, requirements?: PasswordRequire
const { length, required, allowedSymbols } = finalReqs; const { length, required, allowedSymbols } = finalReqs;
const chars = { const chars = {
lowercase: 'abcdefghijklmnopqrstuvwxyz', lowercase: "abcdefghijklmnopqrstuvwxyz",
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
digits: '0123456789', digits: "0123456789",
symbols: allowedSymbols || '-_.~!*' symbols: allowedSymbols || "-_.~!*"
}; };
const parts: string[] = []; const parts: string[] = [];
if (required.lowercase > 0) { if (required.lowercase > 0) {
parts.push(...Array(required.lowercase).fill(0).map(() => parts.push(
chars.lowercase[randomInt(chars.lowercase.length)] ...Array(required.lowercase)
)); .fill(0)
.map(() => chars.lowercase[randomInt(chars.lowercase.length)])
);
} }
if (required.uppercase > 0) { if (required.uppercase > 0) {
parts.push(...Array(required.uppercase).fill(0).map(() => parts.push(
chars.uppercase[randomInt(chars.uppercase.length)] ...Array(required.uppercase)
)); .fill(0)
.map(() => chars.uppercase[randomInt(chars.uppercase.length)])
);
} }
if (required.digits > 0) { if (required.digits > 0) {
parts.push(...Array(required.digits).fill(0).map(() => parts.push(
chars.digits[randomInt(chars.digits.length)] ...Array(required.digits)
)); .fill(0)
.map(() => chars.digits[randomInt(chars.digits.length)])
);
} }
if (required.symbols > 0) { if (required.symbols > 0) {
parts.push(...Array(required.symbols).fill(0).map(() => parts.push(
chars.symbols[randomInt(chars.symbols.length)] ...Array(required.symbols)
)); .fill(0)
.map(() => chars.symbols[randomInt(chars.symbols.length)])
);
} }
const requiredTotal = Object.values(required).reduce<number>((a, b) => a + b, 0); const requiredTotal = Object.values(required).reduce<number>((a, b) => a + b, 0);
@@ -75,21 +82,23 @@ const generatePassword = (provider: SqlProviders, requirements?: PasswordRequire
const allowedChars = Object.entries(chars) const allowedChars = Object.entries(chars)
.filter(([key]) => required[key as keyof typeof required] > 0) .filter(([key]) => required[key as keyof typeof required] > 0)
.map(([, value]) => value) .map(([, value]) => value)
.join(''); .join("");
parts.push(...Array(remainingLength).fill(0).map(() => parts.push(
allowedChars[randomInt(allowedChars.length)] ...Array(remainingLength)
)); .fill(0)
.map(() => allowedChars[randomInt(allowedChars.length)])
);
// shuffle the array to mix up the characters // shuffle the array to mix up the characters
for (let i = parts.length - 1; i > 0; i--) { for (let i = parts.length - 1; i > 0; i -= 1) {
const j = randomInt(i + 1); const j = randomInt(i + 1);
[parts[i], parts[j]] = [parts[j], parts[i]]; [parts[i], parts[j]] = [parts[j], parts[i]];
} }
return parts.join(''); return parts.join("");
} catch (error: unknown) { } catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Unknown error'; const message = error instanceof Error ? error.message : "Unknown error";
throw new Error(`Failed to generate password: ${message}`); throw new Error(`Failed to generate password: ${message}`);
} }
}; };
@@ -1,10 +1,10 @@
import { z } from "zod"; import { z } from "zod";
import { authRateLimit } from "@app/server/config/rateLimiter"; import { authRateLimit } from "@app/server/config/rateLimiter";
import { validatePasswordResetAuthorization } from "@app/services/auth/auth-fns";
import { AuthMode } from "@app/services/auth/auth-type";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { validatePasswordResetAuthorization } from "@app/services/auth/auth-fns";
import { ResetPasswordV2Type } from "@app/services/auth/auth-password-type"; import { ResetPasswordV2Type } from "@app/services/auth/auth-password-type";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerPasswordRouter = async (server: FastifyZodProvider) => { export const registerPasswordRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
@@ -7,6 +7,7 @@ import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto";
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { generateUserSrpKeys } from "@app/lib/crypto/srp"; import { generateUserSrpKeys } from "@app/lib/crypto/srp";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { OrgServiceActor } from "@app/lib/types"; import { OrgServiceActor } from "@app/lib/types";
import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service"; import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service";
@@ -25,7 +26,6 @@ import {
TSetupPasswordViaBackupKeyDTO TSetupPasswordViaBackupKeyDTO
} from "./auth-password-type"; } from "./auth-password-type";
import { ActorType, AuthMethod, AuthTokenType } from "./auth-type"; import { ActorType, AuthMethod, AuthTokenType } from "./auth-type";
import { logger } from "@app/lib/logger";
type TAuthPasswordServiceFactoryDep = { type TAuthPasswordServiceFactoryDep = {
authDAL: TAuthDALFactory; authDAL: TAuthDALFactory;