mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-10 07:58:15 -05:00
feat(dynamic-secret): Minor improvements on usernameTemplate
This commit is contained in:
@@ -146,23 +146,23 @@ export const dynamicSecretLeaseServiceFactory = ({
|
||||
|
||||
let result;
|
||||
try {
|
||||
let identityName = "";
|
||||
const identity: { name: string } = { name: "" };
|
||||
if (actor === ActorType.USER) {
|
||||
const user = await userDAL.findById(actorId);
|
||||
if (user) {
|
||||
identityName = extractEmailUsername(user.username);
|
||||
identity.name = extractEmailUsername(user.username);
|
||||
}
|
||||
} else if (actor === ActorType.Machine) {
|
||||
const identity = await identityDAL.findById(actorId);
|
||||
if (identity) {
|
||||
identityName = identity.name;
|
||||
const machineIdentity = await identityDAL.findById(actorId);
|
||||
if (machineIdentity) {
|
||||
identity.name = machineIdentity.name;
|
||||
}
|
||||
}
|
||||
result = await selectedProvider.create({
|
||||
inputs: decryptedStoredInput,
|
||||
expireAt: expireAt.getTime(),
|
||||
usernameTemplate: dynamicSecretCfg.usernameTemplate,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error && typeof error === "object" && error !== null && "sqlMessage" in error) {
|
||||
|
||||
@@ -133,14 +133,14 @@ const generatePassword = () => {
|
||||
return customAlphabet(charset, 64)();
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-";
|
||||
const randomUsername = `inf-${customAlphabet(charset, 32)()}`;
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -179,15 +179,17 @@ export const AwsElastiCacheDatabaseProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: {
|
||||
name: string;
|
||||
};
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
if (!(await validateConnection(providerInputs))) {
|
||||
throw new BadRequestError({ message: "Failed to establish connection" });
|
||||
}
|
||||
|
||||
const leaseUsername = generateUsername(usernameTemplate, identityName);
|
||||
const leaseUsername = generateUsername(usernameTemplate, identity);
|
||||
const leasePassword = generatePassword();
|
||||
const leaseExpiration = new Date(expireAt).toISOString();
|
||||
|
||||
|
||||
@@ -24,14 +24,14 @@ import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { DynamicSecretAwsIamSchema, TDynamicProviderFns } from "./models";
|
||||
import { compileUsernameTemplate } from "./templateUtils";
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32);
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -65,14 +65,16 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: {
|
||||
name: string;
|
||||
};
|
||||
}) => {
|
||||
const { inputs, usernameTemplate, identityName } = data;
|
||||
const { inputs, usernameTemplate, identity } = data;
|
||||
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs;
|
||||
const createUserRes = await client.send(
|
||||
new CreateUserCommand({
|
||||
|
||||
@@ -15,13 +15,13 @@ const generatePassword = (size = 48) => {
|
||||
return customAlphabet(charset, 48)(size);
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32); // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -80,13 +80,13 @@ export const CassandraProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
const { keyspace } = providerInputs;
|
||||
const expiration = new Date(expireAt).toISOString();
|
||||
|
||||
@@ -13,13 +13,13 @@ const generatePassword = () => {
|
||||
return customAlphabet(charset, 64)();
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32); // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -71,12 +71,12 @@ export const ElasticSearchProvider = (): TDynamicProviderFns => {
|
||||
return infoResponse;
|
||||
};
|
||||
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identityName?: string }) => {
|
||||
const { inputs, usernameTemplate, identityName } = data;
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identity?: { name: string } }) => {
|
||||
const { inputs, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const connection = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
|
||||
await connection.security.putUser({
|
||||
|
||||
@@ -23,13 +23,13 @@ const encodePassword = (password?: string) => {
|
||||
return base64Password;
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32); // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -197,8 +197,8 @@ export const LdapProvider = (): TDynamicProviderFns => {
|
||||
return dnArray;
|
||||
};
|
||||
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identityName?: string }) => {
|
||||
const { inputs, usernameTemplate, identityName } = data;
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identity?: { name: string } }) => {
|
||||
const { inputs, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
@@ -225,7 +225,7 @@ export const LdapProvider = (): TDynamicProviderFns => {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
const generatedLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.creationLdif });
|
||||
|
||||
|
||||
@@ -364,7 +364,9 @@ export type TDynamicProviderFns = {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: {
|
||||
name: string;
|
||||
};
|
||||
}) => Promise<{ entityId: string; data: unknown }>;
|
||||
validateConnection: (inputs: unknown) => Promise<boolean>;
|
||||
validateProviderInputs: (inputs: object) => Promise<unknown>;
|
||||
|
||||
@@ -13,13 +13,13 @@ const generatePassword = (size = 48) => {
|
||||
return customAlphabet(charset, 48)(size);
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32);
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -68,13 +68,13 @@ export const MongoAtlasProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
const expiration = new Date(expireAt).toISOString();
|
||||
await client({
|
||||
|
||||
@@ -13,13 +13,13 @@ const generatePassword = (size = 48) => {
|
||||
return customAlphabet(charset, 48)(size);
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32);
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -60,12 +60,12 @@ export const MongoDBProvider = (): TDynamicProviderFns => {
|
||||
return isConnected;
|
||||
};
|
||||
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identityName?: string }) => {
|
||||
const { inputs, usernameTemplate, identityName } = data;
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identity?: { name: string } }) => {
|
||||
const { inputs, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
|
||||
const db = client.db(providerInputs.database);
|
||||
|
||||
@@ -15,13 +15,13 @@ const generatePassword = () => {
|
||||
return customAlphabet(charset, 64)();
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32); // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -117,12 +117,12 @@ export const RabbitMqProvider = (): TDynamicProviderFns => {
|
||||
return infoResponse;
|
||||
};
|
||||
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identityName?: string }) => {
|
||||
const { inputs, usernameTemplate, identityName } = data;
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identity?: { name: string } }) => {
|
||||
const { inputs, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const connection = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
|
||||
await createRabbitMqUser({
|
||||
|
||||
@@ -16,13 +16,13 @@ const generatePassword = () => {
|
||||
return customAlphabet(charset, 64)();
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32); // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -126,13 +126,13 @@ export const RedisDatabaseProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const connection = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
const expiration = new Date(expireAt).toISOString();
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ const generatePassword = (size = 48) => {
|
||||
return customAlphabet(charset, 48)(size);
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = `inf_${alphaNumericNanoId(25)}`; // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -88,11 +88,11 @@ export const SapAseProvider = (): TDynamicProviderFns => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identityName?: string }) => {
|
||||
const { inputs, usernameTemplate, identityName } = data;
|
||||
const create = async (data: { inputs: unknown; usernameTemplate?: string | null; identity?: { name: string } }) => {
|
||||
const { inputs, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
@@ -22,13 +22,13 @@ const generatePassword = (size = 48) => {
|
||||
return customAlphabet(charset, 48)(size);
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = alphaNumericNanoId(32); // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -102,12 +102,12 @@ export const SapHanaProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
const expiration = new Date(expireAt).toISOString();
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ const generatePassword = (size = 48) => {
|
||||
return customAlphabet(charset, 48)(size);
|
||||
};
|
||||
|
||||
const generateUsername = (usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
const randomUsername = `infisical_${alphaNumericNanoId(32)}`; // Username must start with an ascii letter, so we prepend the username with "inf-"
|
||||
if (!usernameTemplate) return randomUsername;
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName
|
||||
identity
|
||||
});
|
||||
};
|
||||
|
||||
@@ -93,14 +93,14 @@ export const SnowflakeProvider = (): TDynamicProviderFns => {
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
|
||||
const client = await $getClient(providerInputs);
|
||||
|
||||
const username = generateUsername(usernameTemplate, identityName);
|
||||
const username = generateUsername(usernameTemplate, identity);
|
||||
const password = generatePassword();
|
||||
|
||||
try {
|
||||
|
||||
@@ -105,7 +105,7 @@ const generatePassword = (provider: SqlProviders, requirements?: PasswordRequire
|
||||
}
|
||||
};
|
||||
|
||||
const generateUsername = (provider: SqlProviders, usernameTemplate?: string | null, identityName?: string) => {
|
||||
const generateUsername = (provider: SqlProviders, usernameTemplate?: string | null, identity?: { name: string }) => {
|
||||
let randomUsername = "";
|
||||
// For oracle, the client assumes everything is upper case when not using quotes around the password
|
||||
if (provider === SqlProviders.Oracle) {
|
||||
@@ -117,7 +117,7 @@ const generateUsername = (provider: SqlProviders, usernameTemplate?: string | nu
|
||||
return compileUsernameTemplate({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName,
|
||||
identity,
|
||||
options: {
|
||||
toUpperCase: provider === SqlProviders.Oracle
|
||||
}
|
||||
@@ -227,12 +227,12 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
inputs: unknown;
|
||||
expireAt: number;
|
||||
usernameTemplate?: string | null;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
}) => {
|
||||
const { inputs, expireAt, usernameTemplate, identityName } = data;
|
||||
const { inputs, expireAt, usernameTemplate, identity } = data;
|
||||
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
const username = generateUsername(providerInputs.client, usernameTemplate, identityName);
|
||||
const username = generateUsername(providerInputs.client, usernameTemplate, identity);
|
||||
|
||||
const password = generatePassword(providerInputs.client, providerInputs.passwordRequirements);
|
||||
const gatewayCallback = async (host = providerInputs.host, port = providerInputs.port) => {
|
||||
|
||||
@@ -2,73 +2,68 @@
|
||||
import handlebars from "handlebars";
|
||||
import RE2 from "re2";
|
||||
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
|
||||
export const compileUsernameTemplate = ({
|
||||
usernameTemplate,
|
||||
randomUsername,
|
||||
identityName,
|
||||
identity,
|
||||
unixTimestamp,
|
||||
options
|
||||
}: {
|
||||
usernameTemplate: string;
|
||||
randomUsername: string;
|
||||
identityName?: string;
|
||||
identity?: { name: string };
|
||||
unixTimestamp?: number;
|
||||
options?: {
|
||||
toUpperCase?: boolean;
|
||||
};
|
||||
}): string => {
|
||||
// Pre-process template to replace {{random-N}} patterns before compiling
|
||||
// Create isolated handlebars instance
|
||||
const hbs = handlebars.create();
|
||||
|
||||
// Pre-process template to replace {{random N}} patterns using RE2
|
||||
let processedTemplate = usernameTemplate;
|
||||
const randomPattern = /\{\{random-(\d+)\}\}/g;
|
||||
let match;
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while ((match = randomPattern.exec(usernameTemplate)) !== null) {
|
||||
const fullMatch = match[0];
|
||||
const length = parseInt(match[1], 10);
|
||||
try {
|
||||
const randomPattern = new RE2("\\{\\{random (\\d+)\\}\\}", "g");
|
||||
|
||||
if (length > 0 && length <= 100) {
|
||||
const randomValue = alphaNumericNanoId(length);
|
||||
processedTemplate = processedTemplate.replace(fullMatch, randomValue);
|
||||
}
|
||||
// Use RE2's replace with callback function
|
||||
processedTemplate = randomPattern.replace(processedTemplate, (fullMatch: string, lengthStr: string) => {
|
||||
const length = parseInt(lengthStr, 10);
|
||||
|
||||
if (length > 0 && length <= 100) {
|
||||
return alphaNumericNanoId(length);
|
||||
}
|
||||
|
||||
// Return original match if invalid length
|
||||
return fullMatch;
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error, "RE2 pattern failed, using original template");
|
||||
}
|
||||
|
||||
// Register replace helper
|
||||
handlebars.registerHelper(
|
||||
"replace",
|
||||
function (text: string, searchValue: string, replaceValue: string, limit?: number) {
|
||||
// Convert to string if it's not already
|
||||
const textStr = String(text || "");
|
||||
if (!textStr) {
|
||||
return textStr;
|
||||
}
|
||||
|
||||
try {
|
||||
const re2Pattern = new RE2(searchValue, "g");
|
||||
|
||||
if (limit && limit > 0) {
|
||||
// Replace only up to the specified limit
|
||||
let count = 0;
|
||||
return textStr.replace(re2Pattern, (textMatch) => {
|
||||
if (count < limit) {
|
||||
count += 1;
|
||||
return replaceValue;
|
||||
}
|
||||
return textMatch;
|
||||
});
|
||||
}
|
||||
// Replace all occurrences
|
||||
return textStr.replace(re2Pattern, replaceValue);
|
||||
} catch (error) {
|
||||
return textStr;
|
||||
}
|
||||
// Register replace helper on local instance
|
||||
hbs.registerHelper("replace", function (text: string, searchValue: string, replaceValue: string) {
|
||||
// Convert to string if it's not already
|
||||
const textStr = String(text || "");
|
||||
if (!textStr) {
|
||||
return textStr;
|
||||
}
|
||||
);
|
||||
|
||||
// Register truncate helper
|
||||
handlebars.registerHelper("truncate", function (text: string, length: number) {
|
||||
try {
|
||||
const re2Pattern = new RE2(searchValue, "g");
|
||||
// Replace all occurrences
|
||||
return textStr.replace(re2Pattern, replaceValue);
|
||||
} catch (error) {
|
||||
logger.error(error, "RE2 pattern failed, using original template");
|
||||
return textStr;
|
||||
}
|
||||
});
|
||||
|
||||
// Register truncate helper on local instance
|
||||
hbs.registerHelper("truncate", function (text: string, length: number) {
|
||||
// Convert to string if it's not already
|
||||
const textStr = String(text || "");
|
||||
if (!textStr) {
|
||||
@@ -79,16 +74,16 @@ export const compileUsernameTemplate = ({
|
||||
return textStr.substring(0, length);
|
||||
});
|
||||
|
||||
// Compile template with context
|
||||
// Compile template with context using local instance
|
||||
const context = {
|
||||
randomUsername,
|
||||
unixTimestamp: unixTimestamp || Math.floor(Date.now() / 100),
|
||||
identity: {
|
||||
name: identityName
|
||||
name: identity?.name
|
||||
}
|
||||
};
|
||||
|
||||
const result = handlebars.compile(processedTemplate)(context);
|
||||
const result = hbs.compile(processedTemplate)(context);
|
||||
|
||||
if (options?.toUpperCase) {
|
||||
return result.toUpperCase();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import handlebars from "handlebars";
|
||||
import RE2 from "re2";
|
||||
|
||||
import { BadRequestError } from "../errors";
|
||||
import { logger } from "../logger";
|
||||
@@ -8,16 +7,9 @@ type SanitizationArg = {
|
||||
allowedExpressions?: (arg: string) => boolean;
|
||||
};
|
||||
|
||||
const randomPattern = new RE2("^random-\\d+$");
|
||||
|
||||
const isValidExpression = (expression: string, dto: SanitizationArg): boolean => {
|
||||
// Check for random-N pattern (e.g., random-16, random-8)
|
||||
if (expression.startsWith("random-") && randomPattern.test(expression)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow helper functions (replace, truncate)
|
||||
const allowedHelpers = ["replace", "truncate"];
|
||||
const allowedHelpers = ["replace", "truncate", "random"];
|
||||
if (allowedHelpers.includes(expression)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ The Infisical AWS ElastiCache dynamic secret allows you to generate AWS ElastiCa
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -112,7 +112,7 @@ Replace **\<account id\>** with your AWS account id and **\<aws-scope-path\>** w
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -86,7 +86,7 @@ The above configuration allows user creation and granting permissions.
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -94,7 +94,7 @@ The port that your Elasticsearch instance is running on. _(Example: 9200)_
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -130,7 +130,7 @@ The Infisical LDAP dynamic secret allows you to generate user credentials on dem
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -70,7 +70,7 @@ Create a project scoped API Key with the required permission in your Mongo Atlas
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -73,7 +73,7 @@ Create a user with the required permission in your MongoDB instance. This user w
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -78,7 +78,7 @@ Create a user with the required permission in your SQL instance. This user will
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -76,7 +76,7 @@ Create a user with the required permission in your SQL instance. This user will
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -78,7 +78,7 @@ Create a user with the required permission in your SQL instance. This user will
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -79,7 +79,7 @@ Create a user with the required permission in your SQL instance. This user will
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -72,7 +72,7 @@ The port that the RabbitMQ management plugin is listening on. This is `15672` by
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -64,7 +64,7 @@ Create a user with the required permission in your Redis instance. This user wil
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -71,7 +71,7 @@ The Infisical SAP ASE dynamic secret allows you to generate SAP ASE database cre
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -71,7 +71,7 @@ The Infisical SAP HANA dynamic secret allows you to generate SAP HANA database c
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
@@ -84,7 +84,7 @@ Infisical's Snowflake dynamic secrets allow you to generate Snowflake user crede
|
||||
- `{{randomUsername}}`: Random username string
|
||||
- `{{unixTimestamp}}`: Current Unix timestamp
|
||||
- `{{identity.name}}`: Name of the identity that is generating the secret
|
||||
- `{{random-N}}`: Random string of N characters
|
||||
- `{{random N}}`: Random string of N characters
|
||||
|
||||
Allowed template functions are
|
||||
- `truncate`: Truncates a string to a specified length
|
||||
|
||||
Reference in New Issue
Block a user