Merge pull request #3973 from Infisical/daniel/fips-initative

feat(fips): native FIPS support
This commit is contained in:
Daniel Hougaard
2025-07-15 19:03:51 +04:00
committed by GitHub
167 changed files with 3503 additions and 1619 deletions
@@ -1,9 +1,6 @@
import crypto from "node:crypto";
import bcrypt from "bcrypt";
import { TApiKeys } from "@app/db/schemas/api-keys";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { TUserDALFactory } from "../user/user-dal";
@@ -27,7 +24,7 @@ export const apiKeyServiceFactory = ({ apiKeyDAL, userDAL }: TApiKeyServiceFacto
const createApiKey = async (userId: string, name: string, expiresIn: number) => {
const appCfg = getConfig();
const secret = crypto.randomBytes(16).toString("hex");
const secretHash = await bcrypt.hash(secret, appCfg.SALT_ROUNDS);
const secretHash = await crypto.hashing().createHash(secret, appCfg.SALT_ROUNDS);
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
@@ -59,7 +56,7 @@ export const apiKeyServiceFactory = ({ apiKeyDAL, userDAL }: TApiKeyServiceFacto
throw new UnauthorizedError();
}
const isMatch = await bcrypt.compare(TOKEN_SECRET, apiKey.secretHash);
const isMatch = await crypto.hashing().compareHash(TOKEN_SECRET, apiKey.secretHash);
if (!isMatch) throw new UnauthorizedError();
await apiKeyDAL.updateById(apiKey.id, { lastUsed: new Date() });
const user = await userDAL.findById(apiKey.userId);
@@ -6,7 +6,7 @@ import {
} from "@app/ee/services/app-connections/oci";
import { getOracleDBConnectionListItem, OracleDBConnectionMethod } from "@app/ee/services/app-connections/oracledb";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { generateHash } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError } from "@app/lib/errors";
import { APP_CONNECTION_NAME_MAP, APP_CONNECTION_PLAN_MAP } from "@app/services/app-connection/app-connection-maps";
import {
@@ -305,7 +305,7 @@ export const decryptAppConnection = async (
orgId: appConnection.orgId,
kmsService
}),
credentialsHash: generateHash(appConnection.encryptedCredentials)
credentialsHash: crypto.nativeCrypto.createHash("sha256").update(appConnection.encryptedCredentials).digest("hex")
} as TAppConnection;
};
@@ -6,7 +6,7 @@ import { ValidateOracleDBConnectionCredentialsSchema } from "@app/ee/services/ap
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionAppConnectionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { generateHash } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { DatabaseErrorCode } from "@app/lib/error-codes";
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
import { DiscriminativePick, OrgServiceActor } from "@app/lib/types";
@@ -281,7 +281,7 @@ export const appConnectionServiceFactory = ({
return {
...connection,
credentialsHash: generateHash(connection.encryptedCredentials),
credentialsHash: crypto.nativeCrypto.createHash("sha256").update(connection.encryptedCredentials).digest("hex"),
credentials: validatedCredentials
} as TAppConnection;
} catch (err) {
@@ -1,9 +1,10 @@
import { AssumeRoleCommand, STSClient } from "@aws-sdk/client-sts";
import AWS from "aws-sdk";
import { AxiosError } from "axios";
import { randomUUID } from "crypto";
import { CustomAWSHasher } from "@app/lib/aws/hashing";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, InternalServerError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { AppConnection, AWSRegion } from "@app/services/app-connection/app-connection-enums";
@@ -35,6 +36,8 @@ export const getAwsConnectionConfig = async (appConnection: TAwsConnectionConfig
case AwsConnectionMethod.AssumeRole: {
const client = new STSClient({
region,
useFipsEndpoint: crypto.isFipsModeEnabled(),
sha256: CustomAWSHasher,
credentials:
appCfg.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID && appCfg.INF_APP_CONNECTION_AWS_SECRET_ACCESS_KEY
? {
@@ -46,7 +49,7 @@ export const getAwsConnectionConfig = async (appConnection: TAwsConnectionConfig
const command = new AssumeRoleCommand({
RoleArn: credentials.roleArn,
RoleSessionName: `infisical-app-connection-${randomUUID()}`,
RoleSessionName: `infisical-app-connection-${crypto.nativeCrypto.randomUUID()}`,
DurationSeconds: 900, // 15 mins
ExternalId: orgId
});
@@ -1,11 +1,8 @@
import crypto from "node:crypto";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { Knex } from "knex";
import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal";
@@ -81,7 +78,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
const { token, ...tkCfg } = getTokenConfig(type);
const appCfg = getConfig();
const tokenHash = await bcrypt.hash(token, appCfg.SALT_ROUNDS);
const tokenHash = await crypto.hashing().createHash(token, appCfg.SALT_ROUNDS);
await tokenDAL.transaction(async (tx) => {
await tokenDAL.delete({ userId, type, orgId: orgId || null }, tx);
const newToken = await tokenDAL.create(
@@ -115,7 +112,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu
throw new Error("Token expired. Please try again");
}
const isValidToken = await bcrypt.compare(code, token.tokenHash);
const isValidToken = await crypto.hashing().compareHash(code, token.tokenHash);
if (!isValidToken) {
if (token?.triesLeft) {
if (token.triesLeft === 1) {
@@ -162,7 +159,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu
message: "Failed to find refresh token"
});
const decodedToken = jwt.verify(refreshToken, appCfg.AUTH_SECRET) as AuthModeRefreshJwtTokenPayload;
const decodedToken = crypto.jwt().verify(refreshToken, appCfg.AUTH_SECRET) as AuthModeRefreshJwtTokenPayload;
if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN)
throw new UnauthorizedError({
+4 -5
View File
@@ -1,6 +1,5 @@
import jwt from "jsonwebtoken";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors";
import { AuthModeProviderJwtTokenPayload, AuthModeProviderSignUpTokenPayload, AuthTokenType } from "./auth-type";
@@ -8,7 +7,7 @@ import { AuthModeProviderJwtTokenPayload, AuthModeProviderSignUpTokenPayload, Au
export const validateProviderAuthToken = (providerToken: string, username?: string) => {
if (!providerToken) throw new UnauthorizedError();
const appCfg = getConfig();
const decodedToken = jwt.verify(providerToken, appCfg.AUTH_SECRET) as AuthModeProviderJwtTokenPayload;
const decodedToken = crypto.jwt().verify(providerToken, appCfg.AUTH_SECRET) as AuthModeProviderJwtTokenPayload;
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError();
@@ -38,7 +37,7 @@ export const validateSignUpAuthorization = (token: string, userId: string, valid
});
}
const decodedToken = jwt.verify(AUTH_TOKEN_VALUE, appCfg.AUTH_SECRET) as AuthModeProviderSignUpTokenPayload;
const decodedToken = crypto.jwt().verify(AUTH_TOKEN_VALUE, appCfg.AUTH_SECRET) as AuthModeProviderSignUpTokenPayload;
if (!validate) return decodedToken;
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw new UnauthorizedError();
@@ -64,7 +63,7 @@ export const validatePasswordResetAuthorization = (token?: string) => {
});
}
const decodedToken = jwt.verify(AUTH_TOKEN_VALUE, appCfg.AUTH_SECRET) as AuthModeProviderSignUpTokenPayload;
const decodedToken = crypto.jwt().verify(AUTH_TOKEN_VALUE, appCfg.AUTH_SECRET) as AuthModeProviderSignUpTokenPayload;
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) {
throw new UnauthorizedError({
+15 -12
View File
@@ -1,5 +1,3 @@
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { Knex } from "knex";
import { OrgMembershipRole, OrgMembershipStatus, TableName, TUsers, UserDeviceSchema } from "@app/db/schemas";
@@ -7,8 +5,7 @@ import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/a
import { isAuthMethodSaml } from "@app/ee/services/permission/permission-fns";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto, generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto";
import { getUserPrivateKey } from "@app/lib/crypto/srp";
import { BadRequestError, DatabaseError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors";
import { getMinExpiresIn, removeTrailingSlash } from "@app/lib/fn";
@@ -157,7 +154,7 @@ export const authLoginServiceFactory = ({
}
}
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
authMethod,
authTokenType: AuthTokenType.ACCESS_TOKEN,
@@ -172,7 +169,7 @@ export const authLoginServiceFactory = ({
{ expiresIn: tokenSessionExpiresIn }
);
const refreshToken = jwt.sign(
const refreshToken = crypto.jwt().sign(
{
authMethod,
authTokenType: AuthTokenType.REFRESH_TOKEN,
@@ -336,8 +333,14 @@ export const authLoginServiceFactory = ({
);
return "";
});
const hashedPassword = await bcrypt.hash(password, cfg.BCRYPT_SALT_ROUND);
const { iv, tag, ciphertext, encoding } = infisicalSymmetricEncypt(privateKey);
const hashedPassword = await crypto.hashing().createHash(password, cfg.SALT_ROUNDS);
const { iv, tag, ciphertext, encoding } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(privateKey);
await userDAL.updateUserEncryptionByUserId(userEnc.userId, {
serverPrivateKey: null,
clientPublicKey: null,
@@ -388,7 +391,7 @@ export const authLoginServiceFactory = ({
authJwtToken = authJwtToken.replace("Bearer ", ""); // remove bearer from token
// The decoded JWT token, which contains the auth method.
const decodedToken = jwt.verify(authJwtToken, cfg.AUTH_SECRET) as AuthModeJwtTokenPayload;
const decodedToken = crypto.jwt().verify(authJwtToken, cfg.AUTH_SECRET) as AuthModeJwtTokenPayload;
if (!decodedToken.authMethod) throw new UnauthorizedError({ name: "Auth method not found on existing token" });
const user = await userDAL.findUserEncKeyByUserId(decodedToken.userId);
@@ -413,7 +416,7 @@ export const authLoginServiceFactory = ({
if (shouldCheckMfa && (!decodedToken.isMfaVerified || decodedToken.mfaMethod !== mfaMethod)) {
enforceUserLockStatus(Boolean(user.isLocked), user.temporaryLockDateEnd);
const mfaToken = jwt.sign(
const mfaToken = crypto.jwt().sign(
{
authMethod: decodedToken.authMethod,
authTokenType: AuthTokenType.MFA_TOKEN,
@@ -624,7 +627,7 @@ export const authLoginServiceFactory = ({
throw err;
}
const decodedToken = jwt.verify(mfaJwtToken, getConfig().AUTH_SECRET) as AuthModeMfaJwtTokenPayload;
const decodedToken = crypto.jwt().verify(mfaJwtToken, getConfig().AUTH_SECRET) as AuthModeMfaJwtTokenPayload;
const userEnc = await userDAL.findUserEncKeyByUserId(userId);
if (!userEnc) throw new Error("Failed to authenticate user");
@@ -774,7 +777,7 @@ export const authLoginServiceFactory = ({
const userEnc = await userDAL.findUserEncKeyByUserId(user.id);
const isUserCompleted = user.isAccepted;
const providerAuthToken = jwt.sign(
const providerAuthToken = crypto.jwt().sign(
{
authTokenType: AuthTokenType.PROVIDER_TOKEN,
userId: user.id,
@@ -1,10 +1,7 @@
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto";
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { generateUserSrpKeys } from "@app/lib/crypto/srp";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@@ -95,7 +92,7 @@ export const authPaswordServiceFactory = ({
if (!isValidClientProof) throw new Error("Failed to authenticate. Try again?");
const appCfg = getConfig();
const hashedPassword = await bcrypt.hash(password, appCfg.BCRYPT_SALT_ROUND);
const hashedPassword = await crypto.hashing().createHash(password, appCfg.SALT_ROUNDS);
await userDAL.updateUserEncryptionByUserId(userId, {
encryptionVersion: 2,
protectedKey,
@@ -175,7 +172,7 @@ export const authPaswordServiceFactory = ({
code
});
const token = jwt.sign(
const token = crypto.jwt().sign(
{
authTokenType: AuthTokenType.SIGNUP_TOKEN,
userId: user.id
@@ -208,13 +205,13 @@ export const authPaswordServiceFactory = ({
throw new BadRequestError({ message: "Current password is required." });
}
const isValid = await bcrypt.compare(oldPassword, user.hashedPassword);
const isValid = await crypto.hashing().compareHash(oldPassword, user.hashedPassword);
if (!isValid) {
throw new BadRequestError({ message: "Incorrect current password." });
}
}
const newHashedPassword = await bcrypt.hash(newPassword, cfg.BCRYPT_SALT_ROUND);
const newHashedPassword = await crypto.hashing().createHash(newPassword, cfg.SALT_ROUNDS);
// we need to get the original private key first for v2
let privateKey: string;
@@ -225,12 +222,15 @@ export const authPaswordServiceFactory = ({
user.serverEncryptedPrivateKeyEncoding &&
user.encryptionVersion === UserEncryption.V2
) {
privateKey = infisicalSymmetricDecrypt({
iv: user.serverEncryptedPrivateKeyIV,
tag: user.serverEncryptedPrivateKeyTag,
ciphertext: user.serverEncryptedPrivateKey,
keyEncoding: user.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
privateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
iv: user.serverEncryptedPrivateKeyIV,
tag: user.serverEncryptedPrivateKeyTag,
ciphertext: user.serverEncryptedPrivateKey,
keyEncoding: user.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
} else {
throw new BadRequestError({
message: "Cannot reset password without current credentials or recovery method",
@@ -243,7 +243,7 @@ export const authPaswordServiceFactory = ({
privateKey
});
const { tag, iv, ciphertext, encoding } = infisicalSymmetricEncypt(privateKey);
const { tag, iv, ciphertext, encoding } = crypto.encryption().symmetric().encryptWithRootEncryptionKey(privateKey);
await userDAL.updateUserEncryptionByUserId(userId, {
hashedPassword: newHashedPassword,
@@ -285,7 +285,7 @@ export const authPaswordServiceFactory = ({
}: TResetPasswordViaBackupKeyDTO) => {
const cfg = getConfig();
const hashedPassword = await bcrypt.hash(password, cfg.BCRYPT_SALT_ROUND);
const hashedPassword = await crypto.hashing().createHash(password, cfg.SALT_ROUNDS);
await userDAL.updateUserEncryptionByUserId(userId, {
encryptionVersion: 2,
@@ -461,7 +461,7 @@ export const authPaswordServiceFactory = ({
const cfg = getConfig();
const hashedPassword = await bcrypt.hash(password, cfg.BCRYPT_SALT_ROUND);
const hashedPassword = await crypto.hashing().createHash(password, cfg.SALT_ROUNDS);
await userDAL.updateUserEncryptionByUserId(
actor.id,
@@ -1,13 +1,10 @@
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { OrgMembershipStatus, SecretKeyEncoding, TableName } from "@app/db/schemas";
import { convertPendingGroupAdditionsToGroupMemberships } from "@app/ee/services/group/group-fns";
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { isAuthMethodSaml } from "@app/ee/services/permission/permission-fns";
import { getConfig } from "@app/lib/config/env";
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { generateUserSrpKeys, getUserPrivateKey } from "@app/lib/crypto/srp";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { getMinExpiresIn } from "@app/lib/fn";
@@ -132,7 +129,7 @@ export const authSignupServiceFactory = ({
await userDAL.updateById(user.id, { isEmailVerified: true });
// generate jwt token this is a temporary token
const jwtToken = jwt.sign(
const jwtToken = crypto.jwt().sign(
{
authTokenType: AuthTokenType.SIGNUP_TOKEN,
userId: user.id.toString()
@@ -193,7 +190,7 @@ export const authSignupServiceFactory = ({
validateSignUpAuthorization(authorization, user.id);
}
const hashedPassword = await bcrypt.hash(password, appCfg.BCRYPT_SALT_ROUND);
const hashedPassword = await crypto.hashing().createHash(password, appCfg.SALT_ROUNDS);
const privateKey = await getUserPrivateKey(password, {
salt,
protectedKey,
@@ -204,7 +201,7 @@ export const authSignupServiceFactory = ({
tag: encryptedPrivateKeyTag,
encryptionVersion: UserEncryption.V2
});
const { tag, encoding, ciphertext, iv } = infisicalSymmetricEncypt(privateKey);
const { tag, encoding, ciphertext, iv } = crypto.encryption().symmetric().encryptWithRootEncryptionKey(privateKey);
const updateduser = await authDAL.transaction(async (tx) => {
const us = await userDAL.updateById(user.id, { firstName, lastName, isAccepted: true }, tx);
if (!us) throw new Error("User not found");
@@ -225,12 +222,15 @@ export const authSignupServiceFactory = ({
systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyEncoding
) {
// get server generated password
const serverGeneratedPassword = infisicalSymmetricDecrypt({
iv: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyIV,
tag: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyTag,
ciphertext: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKey,
keyEncoding: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
const serverGeneratedPassword = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
iv: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyIV,
tag: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyTag,
ciphertext: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKey,
keyEncoding: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
const serverGeneratedPrivateKey = await getUserPrivateKey(serverGeneratedPassword, {
...systemGeneratedUserEncryptionKey
});
@@ -365,7 +365,7 @@ export const authSignupServiceFactory = ({
});
if (!tokenSession) throw new Error("Failed to create token");
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
authMethod: authMethod || AuthMethod.EMAIL,
authTokenType: AuthTokenType.ACCESS_TOKEN,
@@ -378,7 +378,7 @@ export const authSignupServiceFactory = ({
{ expiresIn: tokenSessionExpiresIn }
);
const refreshToken = jwt.sign(
const refreshToken = crypto.jwt().sign(
{
authMethod: authMethod || AuthMethod.EMAIL,
authTokenType: AuthTokenType.REFRESH_TOKEN,
@@ -436,7 +436,7 @@ export const authSignupServiceFactory = ({
});
const appCfg = getConfig();
const hashedPassword = await bcrypt.hash(password, appCfg.BCRYPT_SALT_ROUND);
const hashedPassword = await crypto.hashing().createHash(password, appCfg.SALT_ROUNDS);
const privateKey = await getUserPrivateKey(password, {
salt,
protectedKey,
@@ -447,7 +447,7 @@ export const authSignupServiceFactory = ({
tag: encryptedPrivateKeyTag,
encryptionVersion: 2
});
const { tag, encoding, ciphertext, iv } = infisicalSymmetricEncypt(privateKey);
const { tag, encoding, ciphertext, iv } = crypto.encryption().symmetric().encryptWithRootEncryptionKey(privateKey);
const updateduser = await authDAL.transaction(async (tx) => {
const us = await userDAL.updateById(user.id, { firstName, lastName, isAccepted: true }, tx);
if (!us) throw new Error("User not found");
@@ -464,12 +464,15 @@ export const authSignupServiceFactory = ({
systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyEncoding
) {
// get server generated password
const serverGeneratedPassword = infisicalSymmetricDecrypt({
iv: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyIV,
tag: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyTag,
ciphertext: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKey,
keyEncoding: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
const serverGeneratedPassword = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
iv: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyIV,
tag: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyTag,
ciphertext: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKey,
keyEncoding: systemGeneratedUserEncryptionKey.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
const serverGeneratedPrivateKey = await getUserPrivateKey(serverGeneratedPassword, {
...systemGeneratedUserEncryptionKey
});
@@ -552,7 +555,7 @@ export const authSignupServiceFactory = ({
});
if (!tokenSession) throw new Error("Failed to create token");
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
authMethod: AuthMethod.EMAIL,
authTokenType: AuthTokenType.ACCESS_TOKEN,
@@ -564,7 +567,7 @@ export const authSignupServiceFactory = ({
{ expiresIn: appCfg.JWT_SIGNUP_LIFETIME }
);
const refreshToken = jwt.sign(
const refreshToken = crypto.jwt().sign(
{
authMethod: AuthMethod.EMAIL,
authTokenType: AuthTokenType.REFRESH_TOKEN,
@@ -1,10 +1,11 @@
import { ChangeResourceRecordSetsCommand, Route53Client } from "@aws-sdk/client-route-53";
import * as x509 from "@peculiar/x509";
import acme from "acme-client";
import { KeyObject } from "crypto";
import { TableName } from "@app/db/schemas";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { CustomAWSHasher } from "@app/lib/aws/hashing";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, CryptographyError, NotFoundError } from "@app/lib/errors";
import { OrgServiceActor } from "@app/lib/types";
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
@@ -102,6 +103,8 @@ export const route53InsertTxtRecord = async (
) => {
const config = await getAwsConnectionConfig(connection, AWSRegion.US_WEST_1); // REGION is irrelevant because Route53 is global
const route53Client = new Route53Client({
sha256: CustomAWSHasher,
useFipsEndpoint: crypto.isFipsModeEnabled(),
credentials: config.credentials!,
region: config.region
});
@@ -187,6 +190,12 @@ export const AcmeCertificateAuthorityFns = ({
enableDirectIssuance: boolean;
actor: OrgServiceActor;
}) => {
if (crypto.isFipsModeEnabled()) {
throw new CryptographyError({
message: "ACME is currently not supported in FIPS mode of operation."
});
}
const { dnsAppConnectionId, directoryUrl, accountEmail, dnsProviderConfig } = configuration;
const appConnection = await appConnectionDAL.findById(dnsAppConnectionId);
@@ -404,8 +413,9 @@ export const AcmeCertificateAuthorityFns = ({
});
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const skLeafObj = KeyObject.from(leafKeys.privateKey);
const leafKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const skLeafObj = crypto.nativeCrypto.KeyObject.from(leafKeys.privateKey);
const skLeaf = skLeafObj.export({ format: "pem", type: "pkcs8" }) as string;
const [, certificateCsr] = await acme.crypto.createCsr(
@@ -1,6 +1,6 @@
import * as x509 from "@peculiar/x509";
import crypto from "crypto";
import { crypto } from "@app/lib/crypto/cryptography";
import { NotFoundError } from "@app/lib/errors";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
@@ -133,8 +133,8 @@ export const getCaCredentials = async ({
});
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const skObj = crypto.createPrivateKey({ key: decryptedPrivateKey, format: "der", type: "pkcs8" });
const caPrivateKey = await crypto.subtle.importKey(
const skObj = crypto.nativeCrypto.createPrivateKey({ key: decryptedPrivateKey, format: "der", type: "pkcs8" });
const caPrivateKey = await crypto.nativeCrypto.subtle.importKey(
"pkcs8",
skObj.export({ format: "der", type: "pkcs8" }),
alg,
@@ -142,10 +142,14 @@ export const getCaCredentials = async ({
["sign"]
);
const pkObj = crypto.createPublicKey(skObj);
const caPublicKey = await crypto.subtle.importKey("spki", pkObj.export({ format: "der", type: "spki" }), alg, true, [
"verify"
]);
const pkObj = crypto.nativeCrypto.createPublicKey(skObj);
const caPublicKey = await crypto.nativeCrypto.subtle.importKey(
"spki",
pkObj.export({ format: "der", type: "spki" }),
alg,
true,
["verify"]
);
return {
caSecret,
@@ -277,10 +281,14 @@ export const rebuildCaCrl = async ({
cipherTextBlob: caSecret.encryptedPrivateKey
});
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
"sign"
]);
const skObj = crypto.nativeCrypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const sk = await crypto.nativeCrypto.subtle.importKey(
"pkcs8",
skObj.export({ format: "der", type: "pkcs8" }),
alg,
true,
["sign"]
);
const revokedCerts = await certificateDAL.find({
caId: ca.id,
@@ -1,8 +1,8 @@
import * as x509 from "@peculiar/x509";
import crypto from "crypto";
import { KeyStorePrefixes, TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@@ -198,10 +198,14 @@ export const certificateAuthorityQueueFactory = ({
cipherTextBlob: caSecret.encryptedPrivateKey
});
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
"sign"
]);
const skObj = crypto.nativeCrypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
const sk = await crypto.nativeCrypto.subtle.importKey(
"pkcs8",
skObj.export({ format: "der", type: "pkcs8" }),
alg,
true,
["sign"]
);
const revokedCerts = await certificateDAL.find({
caId: ca.id,
@@ -1,12 +1,12 @@
/* eslint-disable no-bitwise */
import * as x509 from "@peculiar/x509";
import { KeyObject } from "crypto";
import RE2 from "re2";
import { z } from "zod";
import { TCertificateTemplates, TPkiSubscribers } from "@app/db/schemas";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError } from "@app/lib/errors";
import { ms } from "@app/lib/ms";
import { isFQDN } from "@app/lib/validator/validate-url";
@@ -99,7 +99,7 @@ export const InternalCertificateAuthorityFns = ({
}
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const leafKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
name: `CN=${subscriber.commonName}`,
@@ -184,7 +184,7 @@ export const InternalCertificateAuthorityFns = ({
extensions
});
const skLeafObj = KeyObject.from(leafKeys.privateKey);
const skLeafObj = crypto.nativeCrypto.KeyObject.from(leafKeys.privateKey);
const skLeaf = skLeafObj.export({ format: "pem", type: "pkcs8" }) as string;
const kmsEncryptor = await kmsService.encryptWithKmsKey({
@@ -331,7 +331,7 @@ export const InternalCertificateAuthorityFns = ({
});
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const leafKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
name: `CN=${commonName}`,
@@ -450,7 +450,7 @@ export const InternalCertificateAuthorityFns = ({
extensions
});
const skLeafObj = KeyObject.from(leafKeys.privateKey);
const skLeafObj = crypto.nativeCrypto.KeyObject.from(leafKeys.privateKey);
const skLeaf = skLeafObj.export({ format: "pem", type: "pkcs8" }) as string;
const kmsEncryptor = await kmsService.encryptWithKmsKey({
@@ -2,7 +2,6 @@
import { ForbiddenError, subject } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import slugify from "@sindresorhus/slugify";
import crypto, { KeyObject } from "crypto";
import { z } from "zod";
import { TableName, TCertificateAuthorities, TCertificateTemplates } from "@app/db/schemas";
@@ -15,6 +14,7 @@ import {
} from "@app/ee/services/permission/project-permission";
import { extractX509CertFromChain } from "@app/lib/certificates/extract-certificate";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { ms } from "@app/lib/ms";
import { alphaNumericNanoId } from "@app/lib/nanoid";
@@ -171,7 +171,7 @@ export const internalCertificateAuthorityServiceFactory = ({
});
const alg = keyAlgorithmToAlgCfg(keyAlgorithm);
const keys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const keys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const newCa = await certificateAuthorityDAL.transaction(async (tx) => {
const notBeforeDate = notBefore ? new Date(notBefore) : new Date();
@@ -225,8 +225,8 @@ export const internalCertificateAuthorityServiceFactory = ({
kmsId: certificateManagerKmsId
});
// // https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey
const skObj = KeyObject.from(keys.privateKey);
// https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey
const skObj = crypto.nativeCrypto.KeyObject.from(keys.privateKey);
const { cipherTextBlob: encryptedPrivateKey } = await kmsEncryptor({
plainText: skObj.export({
@@ -1102,9 +1102,9 @@ export const internalCertificateAuthorityServiceFactory = ({
kmsService
});
const isCaAndCertPublicKeySame = Buffer.from(await crypto.subtle.exportKey("spki", caPublicKey)).equals(
Buffer.from(certObj.publicKey.rawData)
);
const isCaAndCertPublicKeySame = Buffer.from(
await crypto.nativeCrypto.subtle.exportKey("spki", caPublicKey)
).equals(Buffer.from(certObj.publicKey.rawData));
if (!isCaAndCertPublicKeySame) {
throw new BadRequestError({ message: "CA and certificate public key do not match" });
@@ -1265,7 +1265,7 @@ export const internalCertificateAuthorityServiceFactory = ({
}
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const leafKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
name: `CN=${commonName}`,
@@ -1412,7 +1412,7 @@ export const internalCertificateAuthorityServiceFactory = ({
extensions
});
const skLeafObj = KeyObject.from(leafKeys.privateKey);
const skLeafObj = crypto.nativeCrypto.KeyObject.from(leafKeys.privateKey);
const skLeaf = skLeafObj.export({ format: "pem", type: "pkcs8" }) as string;
const kmsEncryptor = await kmsService.encryptWithKmsKey({
@@ -1,6 +1,5 @@
import { ForbiddenError, subject } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import bcrypt from "bcrypt";
import { TCertificateTemplateEstConfigsUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -11,6 +10,7 @@ import {
} from "@app/ee/services/permission/project-permission";
import { extractX509CertFromChain } from "@app/lib/certificates/extract-certificate";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { isCertChainValid } from "../certificate/certificate-fns";
@@ -308,7 +308,7 @@ export const certificateTemplateServiceFactory = ({
encryptedCaChain = cipherTextBlob;
}
const hashedPassphrase = await bcrypt.hash(passphrase, appCfg.SALT_ROUNDS);
const hashedPassphrase = await crypto.hashing().createHash(passphrase, appCfg.SALT_ROUNDS);
const estConfig = await certificateTemplateEstConfigDAL.create({
certificateTemplateId,
hashedPassphrase,
@@ -404,7 +404,7 @@ export const certificateTemplateServiceFactory = ({
}
if (passphrase) {
const hashedPassphrase = await bcrypt.hash(passphrase, appCfg.SALT_ROUNDS);
const hashedPassphrase = await crypto.hashing().createHash(passphrase, appCfg.SALT_ROUNDS);
updatedData.hashedPassphrase = hashedPassphrase;
}
@@ -1,8 +1,7 @@
import crypto from "node:crypto";
import * as x509 from "@peculiar/x509";
import RE2 from "re2";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { getProjectKmsCertificateKeyId } from "../project/project-fns";
@@ -87,10 +86,10 @@ export const getCertificateCredentials = async ({
});
try {
const skObj = crypto.createPrivateKey({ key: decryptedPrivateKey, format: "pem", type: "pkcs8" });
const skObj = crypto.nativeCrypto.createPrivateKey({ key: decryptedPrivateKey, format: "pem", type: "pkcs8" });
const certPrivateKey = skObj.export({ format: "pem", type: "pkcs8" }).toString();
const pkObj = crypto.createPublicKey(skObj);
const pkObj = crypto.nativeCrypto.createPublicKey(skObj);
const certPublicKey = pkObj.export({ format: "pem", type: "spki" }).toString();
return {
@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { createPrivateKey, createPublicKey, sign, verify } from "crypto";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
@@ -8,6 +7,7 @@ import {
ProjectPermissionCertificateActions,
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
@@ -373,16 +373,16 @@ export const certificateServiceFactory = ({
// Verify private key matches the certificate
let privateKey;
try {
privateKey = createPrivateKey(privateKeyPem);
privateKey = crypto.nativeCrypto.createPrivateKey(privateKeyPem);
} catch (err) {
throw new BadRequestError({ message: "Invalid private key format" });
}
try {
const message = Buffer.from(Buffer.alloc(32));
const publicKey = createPublicKey(certificatePem);
const signature = sign(null, message, privateKey);
const isValid = verify(null, message, publicKey, signature);
const publicKey = crypto.nativeCrypto.createPublicKey(certificatePem);
const signature = crypto.nativeCrypto.sign(null, message, privateKey);
const isValid = crypto.nativeCrypto.verify(null, message, publicKey, signature);
if (!isValid) {
throw new BadRequestError({ message: "Private key does not match certificate" });
@@ -1,10 +1,10 @@
import slugify from "@sindresorhus/slugify";
import { randomUUID } from "crypto";
import sjcl from "sjcl";
import tweetnacl from "tweetnacl";
import tweetnaclUtil from "tweetnacl-util";
import { SecretType, TSecretFolders } from "@app/db/schemas";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { chunkArray } from "@app/lib/fn";
import { logger } from "@app/lib/logger";
@@ -228,7 +228,7 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<Infisica
}
infisicalImportData.secrets.push({
id: randomUUID(),
id: crypto.nativeCrypto.randomUUID(),
name: secretName,
environmentId: matchingAppEnv.id,
value: resolvedSecret.val || "",
@@ -261,7 +261,7 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<Infisica
}
infisicalImportData.secrets.push({
id: randomUUID(),
id: crypto.nativeCrypto.randomUUID(),
name: secretName,
environmentId: matchingAppEnv.id,
value: secretData.val || "",
@@ -348,7 +348,7 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<Infisica
}
infisicalImportData.secrets.push({
id: randomUUID(),
id: crypto.nativeCrypto.randomUUID(),
name: secret,
environmentId: matchingEnv.id,
value: resolvedSecret.val || "",
@@ -380,7 +380,7 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<Infisica
}
infisicalImportData.secrets.push({
id: randomUUID(),
id: crypto.nativeCrypto.randomUUID(),
name: secret,
environmentId: matchingEnv.id,
value: selectedSecret.val || "",
@@ -461,7 +461,7 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<Infisica
}
infisicalImportData.secrets.push({
id: randomUUID(),
id: crypto.nativeCrypto.randomUUID(),
name: secretName,
environmentId: subEnv ? subEnv.parentEnvironmentId : env,
value: resolvedSecret.val || "",
@@ -487,7 +487,7 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise<Infisica
const folderId = targetIdToFolderIdsMap.get(subEnv?.id || "") || subEnv?.id;
infisicalImportData.secrets.push({
id: randomUUID(),
id: crypto.nativeCrypto.randomUUID(),
name: secretName,
environmentId: subEnv ? subEnv.parentEnvironmentId : env,
value: secretData.val || "",
@@ -1,5 +1,5 @@
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { logger } from "@app/lib/logger";
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
@@ -98,7 +98,7 @@ export const externalMigrationQueueFactory = ({
template: SmtpTemplates.ExternalImportStarted
});
const decrypted = infisicalSymmetricDecrypt({
const decrypted = crypto.encryption().symmetric().decryptWithRootEncryptionKey({
ciphertext: data.ciphertext,
iv: data.iv,
keyEncoding: data.encoding,
@@ -1,7 +1,7 @@
import { OrgMembershipRole } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { ForbiddenRequestError } from "@app/lib/errors";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
import { TUserDALFactory } from "../user/user-dal";
import { decryptEnvKeyDataFn, parseEnvKeyDataFn } from "./external-migration-fns";
@@ -29,6 +29,10 @@ export const externalMigrationServiceFactory = ({
actorOrgId,
actorAuthMethod
}: TImportEnvKeyDataCreate) => {
if (crypto.isFipsModeEnabled()) {
throw new BadRequestError({ message: "EnvKey migration is not supported when running in FIPS mode." });
}
const { membership } = await permissionService.getOrgPermission(
actor,
actorId,
@@ -52,7 +56,7 @@ export const externalMigrationServiceFactory = ({
actorAuthMethod
});
const encrypted = infisicalSymmetricEncypt(stringifiedJson);
const encrypted = crypto.encryption().symmetric().encryptWithRootEncryptionKey(stringifiedJson);
await externalMigrationQueue.startImport({
actorEmail: user.email!,
@@ -8,8 +8,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionGroupActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
import { ms } from "@app/lib/ms";
@@ -213,14 +212,17 @@ export const groupProjectServiceFactory = ({
});
}
const botPrivateKey = infisicalSymmetricDecrypt({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
const botPrivateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
const plaintextProjectKey = decryptAsymmetric({
const plaintextProjectKey = crypto.encryption().asymmetric().decrypt({
ciphertext: ghostUserLatestKey.encryptedKey,
nonce: ghostUserLatestKey.nonce,
publicKey: ghostUserLatestKey.sender.publicKey,
@@ -228,7 +230,10 @@ export const groupProjectServiceFactory = ({
});
const projectKeyData = groupMembers.map(({ user: { publicKey, id } }) => {
const { ciphertext: encryptedKey, nonce } = encryptAsymmetric(plaintextProjectKey, publicKey, botPrivateKey);
const { ciphertext: encryptedKey, nonce } = crypto
.encryption()
.asymmetric()
.encrypt(plaintextProjectKey, publicKey, botPrivateKey);
return {
encryptedKey,
@@ -1,7 +1,6 @@
import jwt, { JwtPayload } from "jsonwebtoken";
import { IdentityAuthMethod, TableName, TIdentityAccessTokens } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
import { checkIPAgainstBlocklist, TIp } from "@app/lib/ip";
@@ -81,7 +80,7 @@ export const identityAccessTokenServiceFactory = ({
const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => {
const appCfg = getConfig();
const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as TIdentityAccessTokenJwtPayload;
const decodedToken = crypto.jwt().verify(accessToken, appCfg.AUTH_SECRET) as TIdentityAccessTokenJwtPayload;
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) {
throw new BadRequestError({ message: "Only identity access tokens can be renewed" });
}
@@ -145,7 +144,7 @@ export const identityAccessTokenServiceFactory = ({
expiresIn = undefined;
}
const renewedToken = jwt.sign(
const renewedToken = crypto.jwt().sign(
{
identityId: decodedToken.identityId,
clientSecretId: decodedToken.clientSecretId,
@@ -162,7 +161,7 @@ export const identityAccessTokenServiceFactory = ({
const revokeAccessToken = async (accessToken: string) => {
const appCfg = getConfig();
const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload & {
const decodedToken = crypto.jwt().verify(accessToken, appCfg.AUTH_SECRET) as TIdentityAccessTokenJwtPayload & {
identityAccessTokenId: string;
};
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) {
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ForbiddenError } from "@casl/ability";
import { AxiosError } from "axios";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -13,6 +12,7 @@ import {
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
import { logger } from "@app/lib/logger";
@@ -103,7 +103,7 @@ export const identityAliCloudAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityAliCloudAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ForbiddenError } from "@casl/ability";
import axios from "axios";
import jwt from "jsonwebtoken";
import RE2 from "re2";
import { IdentityAuthMethod } from "@app/db/schemas";
@@ -13,6 +12,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -168,7 +168,7 @@ export const identityAwsAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityAwsAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,6 +1,6 @@
import axios from "axios";
import jwt from "jsonwebtoken";
import { crypto } from "@app/lib/crypto";
import { UnauthorizedError } from "@app/lib/errors";
import { TAzureAuthJwtPayload, TAzureJwksUriResponse, TDecodedAzureAuthJwt } from "./identity-azure-auth-types";
@@ -16,7 +16,7 @@ export const validateAzureIdentity = async ({
}) => {
const jwksUri = `https://login.microsoftonline.com/${tenantId}/discovery/keys`;
const decodedJwt = jwt.decode(azureJwt, { complete: true }) as TDecodedAzureAuthJwt;
const decodedJwt = crypto.jwt().decode(azureJwt, { complete: true }) as TDecodedAzureAuthJwt;
const { kid } = decodedJwt.header;
@@ -35,7 +35,7 @@ export const validateAzureIdentity = async ({
resource = resource.slice(0, -1);
}
return jwt.verify(azureJwt, publicKey, {
return crypto.jwt().verify(azureJwt, publicKey, {
audience: resource,
issuer: `https://sts.windows.net/${tenantId}/`
}) as TAzureAuthJwtPayload;
@@ -1,5 +1,4 @@
import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -10,6 +9,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -96,7 +96,7 @@ export const identityAzureAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityAzureAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,7 +1,7 @@
import axios from "axios";
import { OAuth2Client } from "google-auth-library";
import jwt from "jsonwebtoken";
import { crypto } from "@app/lib/crypto";
import { UnauthorizedError } from "@app/lib/errors";
import { TDecodedGcpIamAuthJwt, TGcpIdTokenPayload } from "./identity-gcp-auth-types";
@@ -48,7 +48,7 @@ export const validateIamIdentity = async ({
identityId: string;
jwt: string;
}) => {
const decodedJwt = jwt.decode(serviceAccountJwt, { complete: true }) as TDecodedGcpIamAuthJwt;
const decodedJwt = crypto.jwt().decode(serviceAccountJwt, { complete: true }) as TDecodedGcpIamAuthJwt;
const { sub, aud } = decodedJwt.payload;
const {
@@ -61,7 +61,7 @@ export const validateIamIdentity = async ({
const publicKey = data[decodedJwt.header.kid];
jwt.verify(serviceAccountJwt, publicKey, {
crypto.jwt().verify(serviceAccountJwt, publicKey, {
algorithms: ["RS256"]
});
@@ -1,5 +1,4 @@
import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -10,6 +9,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -135,7 +135,7 @@ export const identityGcpAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityGcpAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -12,6 +12,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import {
BadRequestError,
ForbiddenRequestError,
@@ -79,7 +80,7 @@ export const identityJwtAuthServiceFactory = ({
orgId: identityMembershipOrg.orgId
});
const decodedToken = jwt.decode(jwtValue, { complete: true });
const decodedToken = crypto.jwt().decode(jwtValue, { complete: true });
if (!decodedToken) {
throw new UnauthorizedError({
message: "Invalid JWT"
@@ -106,11 +107,11 @@ export const identityJwtAuthServiceFactory = ({
});
}
const { kid } = decodedToken.header;
const { kid } = decodedToken.header as { kid: string };
const jwtSigningKey = await client.getSigningKey(kid);
try {
tokenData = jwt.verify(jwtValue, jwtSigningKey.getPublicKey()) as Record<string, string>;
tokenData = crypto.jwt().verify(jwtValue, jwtSigningKey.getPublicKey()) as Record<string, string>;
} catch (error) {
if (error instanceof jwt.JsonWebTokenError) {
throw new UnauthorizedError({
@@ -129,7 +130,7 @@ export const identityJwtAuthServiceFactory = ({
let isMatchAnyKey = false;
for (const publicKey of decryptedPublicKeys) {
try {
tokenData = jwt.verify(jwtValue, publicKey) as Record<string, string>;
tokenData = crypto.jwt().verify(jwtValue, publicKey) as Record<string, string>;
isMatchAnyKey = true;
} catch (error) {
if (error instanceof jwt.JsonWebTokenError) {
@@ -225,7 +226,7 @@ export const identityJwtAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityJwtAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import axios, { AxiosError } from "axios";
import https from "https";
import jwt from "jsonwebtoken";
import RE2 from "re2";
import { IdentityAuthMethod, TIdentityKubernetesAuthsUpdate } from "@app/db/schemas";
@@ -19,6 +18,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { GatewayHttpProxyActions, GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -396,7 +396,7 @@ export const identityKubernetesAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityKubernetesAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod } from "@app/db/schemas";
import { testLDAPConfig } from "@app/ee/services/ldap-config/ldap-fns";
@@ -12,6 +11,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -153,7 +153,7 @@ export const identityLdapAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityLdapAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ForbiddenError } from "@casl/ability";
import { AxiosError } from "axios";
import jwt from "jsonwebtoken";
import RE2 from "re2";
import { IdentityAuthMethod } from "@app/db/schemas";
@@ -14,6 +13,7 @@ import {
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
import { logger } from "@app/lib/logger";
@@ -107,7 +107,7 @@ export const identityOciAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityOciAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -13,6 +13,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import {
BadRequestError,
ForbiddenRequestError,
@@ -93,7 +94,7 @@ export const identityOidcAuthServiceFactory = ({
);
const jwksUri = discoveryDoc.jwks_uri;
const decodedToken = jwt.decode(oidcJwt, { complete: true });
const decodedToken = crypto.jwt().decode(oidcJwt, { complete: true });
if (!decodedToken) {
throw new UnauthorizedError({
message: "Invalid JWT"
@@ -105,12 +106,12 @@ export const identityOidcAuthServiceFactory = ({
requestAgent: identityOidcAuth.oidcDiscoveryUrl.includes("https") ? requestAgent : undefined
});
const { kid } = decodedToken.header;
const { kid } = decodedToken.header as { kid: string };
const oidcSigningKey = await client.getSigningKey(kid);
let tokenData: Record<string, string>;
try {
tokenData = jwt.verify(oidcJwt, oidcSigningKey.getPublicKey(), {
tokenData = crypto.jwt().verify(oidcJwt, oidcSigningKey.getPublicKey(), {
issuer: identityOidcAuth.boundIssuer
}) as Record<string, string>;
} catch (error) {
@@ -193,7 +194,7 @@ export const identityOidcAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityOidcAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,7 +1,4 @@
import crypto from "node:crypto";
import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -13,6 +10,7 @@ import {
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { extractX509CertFromChain } from "@app/lib/certificates/extract-certificate";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -87,8 +85,8 @@ export const identityTlsCertAuthServiceFactory = ({
throw new BadRequestError({ message: "Missing client certificate" });
}
const clientCertificateX509 = new crypto.X509Certificate(leafCertificate);
const caCertificateX509 = new crypto.X509Certificate(caCertificate);
const clientCertificateX509 = new crypto.nativeCrypto.X509Certificate(leafCertificate);
const caCertificateX509 = new crypto.nativeCrypto.X509Certificate(caCertificate);
const isValidCertificate = clientCertificateX509.verify(caCertificateX509.publicKey);
if (!isValidCertificate)
@@ -136,7 +134,7 @@ export const identityTlsCertAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityTlsCertAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,5 +1,4 @@
import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod, TableName } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -10,6 +9,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -362,7 +362,7 @@ export const identityTokenAuthServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityTokenAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
@@ -1,8 +1,4 @@
import crypto from "node:crypto";
import { ForbiddenError } from "@casl/ability";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -13,6 +9,7 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { checkIPAgainstBlocklist, extractIPDetails, isValidIpOrCidr, TIp } from "@app/lib/ip";
@@ -76,7 +73,8 @@ export const identityUaServiceFactory = ({
let validClientSecretInfo: (typeof clientSecrtInfo)[0] | null = null;
for await (const info of clientSecrtInfo) {
const isMatch = await bcrypt.compare(clientSecret, info.clientSecretHash);
const isMatch = await crypto.hashing().compareHash(clientSecret, info.clientSecretHash);
if (isMatch) {
validClientSecretInfo = info;
break;
@@ -148,7 +146,7 @@ export const identityUaServiceFactory = ({
});
const appCfg = getConfig();
const accessToken = jwt.sign(
const accessToken = crypto.jwt().sign(
{
identityId: identityUa.identityId,
clientSecretId: validClientSecretInfo.id,
@@ -250,7 +248,7 @@ export const identityUaServiceFactory = ({
const doc = await identityUaDAL.create(
{
identityId: identityMembershipOrg.identityId,
clientId: crypto.randomUUID(),
clientId: crypto.nativeCrypto.randomUUID(),
clientSecretTrustedIps: JSON.stringify(reformattedClientSecretTrustedIps),
accessTokenMaxTTL,
accessTokenTTL,
@@ -494,7 +492,7 @@ export const identityUaServiceFactory = ({
const appCfg = getConfig();
const clientSecret = crypto.randomBytes(32).toString("hex");
const clientSecretHash = await bcrypt.hash(clientSecret, appCfg.SALT_ROUNDS);
const clientSecretHash = await crypto.hashing().createHash(clientSecret, appCfg.SALT_ROUNDS);
const identityUaAuth = await identityUaDAL.findOne({ identityId: identityMembershipOrg.identityId });
if (!identityUaAuth) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -9,7 +9,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { decryptSymmetric128BitHexKeyUTF8, encryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
import { logger } from "@app/lib/logger";
@@ -218,13 +218,22 @@ export const integrationAuthServiceFactory = ({
} else {
if (!botKey) throw new NotFoundError({ message: `Project bot key for project with ID '${projectId}' not found` });
if (tokenExchange.refreshToken) {
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenExchange.refreshToken, botKey);
const refreshEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenExchange.refreshToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.refreshIV = refreshEncToken.iv;
updateDoc.refreshTag = refreshEncToken.tag;
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
}
if (tokenExchange.accessToken) {
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenExchange.accessToken, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenExchange.accessToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIV = accessEncToken.iv;
updateDoc.accessTag = accessEncToken.tag;
updateDoc.accessCiphertext = accessEncToken.ciphertext;
@@ -346,11 +355,19 @@ export const integrationAuthServiceFactory = ({
url,
updateDoc.metadata as Record<string, string>
);
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
const refreshEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenDetails.refreshToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.refreshIV = refreshEncToken.iv;
updateDoc.refreshTag = refreshEncToken.tag;
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenDetails.accessToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIV = accessEncToken.iv;
updateDoc.accessTag = accessEncToken.tag;
updateDoc.accessCiphertext = accessEncToken.ciphertext;
@@ -360,19 +377,31 @@ export const integrationAuthServiceFactory = ({
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
if (accessToken) {
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessToken, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: accessToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIV = accessEncToken.iv;
updateDoc.accessTag = accessEncToken.tag;
updateDoc.accessCiphertext = accessEncToken.ciphertext;
}
if (accessId) {
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessId, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: accessId,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIdIV = accessEncToken.iv;
updateDoc.accessIdTag = accessEncToken.tag;
updateDoc.accessIdCiphertext = accessEncToken.ciphertext;
}
if (awsAssumeIamRoleArn) {
const awsAssumeIamRoleArnEnc = encryptSymmetric128BitHexKeyUTF8(awsAssumeIamRoleArn, botKey);
const awsAssumeIamRoleArnEnc = crypto.encryption().symmetric().encrypt({
plaintext: awsAssumeIamRoleArn,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.awsAssumeIamRoleArnCipherText = awsAssumeIamRoleArnEnc.ciphertext;
updateDoc.awsAssumeIamRoleArnIV = awsAssumeIamRoleArnEnc.iv;
updateDoc.awsAssumeIamRoleArnTag = awsAssumeIamRoleArnEnc.tag;
@@ -487,11 +516,21 @@ export const integrationAuthServiceFactory = ({
url,
updateDoc.metadata as Record<string, string>
);
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
const refreshEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenDetails.refreshToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.refreshIV = refreshEncToken.iv;
updateDoc.refreshTag = refreshEncToken.tag;
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenDetails.accessToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIV = accessEncToken.iv;
updateDoc.accessTag = accessEncToken.tag;
updateDoc.accessCiphertext = accessEncToken.ciphertext;
@@ -501,19 +540,32 @@ export const integrationAuthServiceFactory = ({
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
if (accessToken) {
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessToken, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: accessToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIV = accessEncToken.iv;
updateDoc.accessTag = accessEncToken.tag;
updateDoc.accessCiphertext = accessEncToken.ciphertext;
}
if (accessId) {
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessId, botKey);
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: accessId,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.accessIdIV = accessEncToken.iv;
updateDoc.accessIdTag = accessEncToken.tag;
updateDoc.accessIdCiphertext = accessEncToken.ciphertext;
}
if (awsAssumeIamRoleArn) {
const awsAssumeIamRoleArnEnc = encryptSymmetric128BitHexKeyUTF8(awsAssumeIamRoleArn, botKey);
const awsAssumeIamRoleArnEnc = crypto.encryption().symmetric().encrypt({
plaintext: awsAssumeIamRoleArn,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
updateDoc.awsAssumeIamRoleArnCipherText = awsAssumeIamRoleArnEnc.ciphertext;
updateDoc.awsAssumeIamRoleArnIV = awsAssumeIamRoleArnEnc.iv;
updateDoc.awsAssumeIamRoleArnTag = awsAssumeIamRoleArnEnc.tag;
@@ -596,20 +648,22 @@ export const integrationAuthServiceFactory = ({
} else {
if (!botKey) throw new NotFoundError({ message: "Project bot key not found" });
if (integrationAuth.accessTag && integrationAuth.accessIV && integrationAuth.accessCiphertext) {
accessToken = decryptSymmetric128BitHexKeyUTF8({
accessToken = crypto.encryption().symmetric().decrypt({
ciphertext: integrationAuth.accessCiphertext,
iv: integrationAuth.accessIV,
tag: integrationAuth.accessTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
}
if (integrationAuth.refreshCiphertext && integrationAuth.refreshIV && integrationAuth.refreshTag) {
const refreshToken = decryptSymmetric128BitHexKeyUTF8({
const refreshToken = crypto.encryption().symmetric().decrypt({
key: botKey,
ciphertext: integrationAuth.refreshCiphertext,
iv: integrationAuth.refreshIV,
tag: integrationAuth.refreshTag
tag: integrationAuth.refreshTag,
keySize: SymmetricKeySize.Bits128
});
if (integrationAuth.accessExpiresAt && integrationAuth.accessExpiresAt < new Date()) {
@@ -620,8 +674,18 @@ export const integrationAuthServiceFactory = ({
integrationAuth?.url,
integrationAuth.metadata as Record<string, string>
);
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
const refreshEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenDetails.refreshToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const accessEncToken = crypto.encryption().symmetric().encrypt({
plaintext: tokenDetails.accessToken,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
accessToken = tokenDetails.accessToken;
await integrationAuthDAL.updateById(integrationAuth.id, {
refreshIV: refreshEncToken.iv,
@@ -637,11 +701,12 @@ export const integrationAuthServiceFactory = ({
if (!accessToken) throw new BadRequestError({ message: "Missing access token" });
if (integrationAuth.accessIdTag && integrationAuth.accessIdIV && integrationAuth.accessIdCiphertext) {
accessId = decryptSymmetric128BitHexKeyUTF8({
accessId = crypto.encryption().symmetric().decrypt({
key: botKey,
ciphertext: integrationAuth.accessIdCiphertext,
iv: integrationAuth.accessIdIV,
tag: integrationAuth.accessIdTag
tag: integrationAuth.accessIdTag,
keySize: SymmetricKeySize.Bits128
});
}
}
@@ -5,7 +5,7 @@ import { Octokit } from "@octokit/rest";
import { TIntegrationAuths, TIntegrations } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@@ -109,12 +109,14 @@ const getIntegrationSecretsV1 = async (
// process secrets in current folder
const secrets = await secretDAL.findByFolderId(dto.folderId);
secrets.forEach((secret) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
const secretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key: dto.key
key: dto.key,
keySize: SymmetricKeySize.Bits128
});
content[secretKey] = true;
@@ -23,7 +23,6 @@ import { createAppAuth } from "@octokit/auth-app";
import { Octokit } from "@octokit/rest";
import AWS, { AWSError } from "aws-sdk";
import { AxiosError } from "axios";
import { randomUUID } from "crypto";
import https from "https";
import sodium from "libsodium-wrappers";
import isEqual from "lodash.isequal";
@@ -31,8 +30,10 @@ import RE2 from "re2";
import { z } from "zod";
import { SecretType, TIntegrationAuths, TIntegrations } from "@app/db/schemas";
import { CustomAWSHasher } from "@app/lib/aws/hashing";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, InternalServerError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TCreateManySecretsRawFn, TUpdateManySecretsRawFn } from "@app/services/secret/secret-types";
@@ -796,6 +797,8 @@ const syncSecretsAWSParameterStore = async ({
if (awsAssumeRoleArn) {
const client = new STSClient({
region: integration.region as string,
useFipsEndpoint: crypto.isFipsModeEnabled(),
sha256: CustomAWSHasher,
credentials:
appCfg.CLIENT_ID_AWS_INTEGRATION && appCfg.CLIENT_SECRET_AWS_INTEGRATION
? {
@@ -806,7 +809,7 @@ const syncSecretsAWSParameterStore = async ({
});
const command = new AssumeRoleCommand({
RoleArn: awsAssumeRoleArn,
RoleSessionName: `infisical-parameter-store-${randomUUID()}`,
RoleSessionName: `infisical-parameter-store-${crypto.nativeCrypto.randomUUID()}`,
DurationSeconds: 900, // 15mins
ExternalId: projectId
});
@@ -1126,7 +1129,7 @@ const syncSecretsAWSSecretManager = async ({
});
const command = new AssumeRoleCommand({
RoleArn: awsAssumeRoleArn,
RoleSessionName: `infisical-sm-${randomUUID()}`,
RoleSessionName: `infisical-sm-${crypto.nativeCrypto.randomUUID()}`,
DurationSeconds: 900, // 15mins
ExternalId: projectId
});
@@ -1,7 +1,6 @@
import jwt from "jsonwebtoken";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, ForbiddenRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
import { Integrations, IntegrationUrls } from "./integration-list";
@@ -718,7 +717,7 @@ const exchangeRefreshGCPSecretManager = async ({
exp: Math.floor(Date.now() / 1000) + 3600
};
const token = jwt.sign(payload, serviceAccount.private_key, { algorithm: "RS256" });
const token = crypto.jwt().sign(payload, serviceAccount.private_key, { algorithm: "RS256" });
const { data }: { data: ServiceAccountAccessTokenGCPSecretManagerResponse } = await request.post(
IntegrationUrls.GCP_TOKEN_URL,
+13 -8
View File
@@ -14,9 +14,8 @@ import {
import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
import { TEnvConfig } from "@app/lib/config/env";
import { randomSecureBytes } from "@app/lib/crypto";
import { symmetricCipherService, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { generateHash } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { AsymmetricKeyAlgorithm, signingService } from "@app/lib/crypto/sign";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@@ -101,7 +100,7 @@ export const kmsServiceFactory = ({
let kmsKeyMaterial: Buffer | null = null;
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
kmsKeyMaterial = randomSecureBytes(
kmsKeyMaterial = crypto.randomBytes(
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyAlgorithm)
);
} else if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
@@ -618,7 +617,7 @@ export const kmsServiceFactory = ({
return;
}
const dataKey = randomSecureBytes();
const dataKey = crypto.randomBytes(32);
const kmsEncryptor = await encryptWithKmsKey(
{
kmsId: kmsKeyId
@@ -761,7 +760,7 @@ export const kmsServiceFactory = ({
return;
}
const dataKey = randomSecureBytes();
const dataKey = crypto.randomBytes(32);
const kmsEncryptor = await encryptWithKmsKey(
{
kmsId: kmsKeyId
@@ -831,6 +830,7 @@ export const kmsServiceFactory = ({
const $getBasicEncryptionKey = () => {
const encryptionKey = envConfig.ENCRYPTION_KEY || envConfig.ROOT_ENCRYPTION_KEY;
const isBase64 = !envConfig.ENCRYPTION_KEY;
if (!encryptionKey)
throw new Error(
@@ -994,7 +994,7 @@ export const kmsServiceFactory = ({
"base64"
)}`;
const verificationHash = generateHash(secretManagerBackup);
const verificationHash = crypto.nativeCrypto.createHash("sha256").update(secretManagerBackup).digest("hex");
secretManagerBackup = `${secretManagerBackup}.${verificationHash}`;
return {
@@ -1011,7 +1011,12 @@ export const kmsServiceFactory = ({
}
const [, backupProjectId, , backupKmsKeyId, backupBase64EncryptedDataKey, backupHash] = backup.split(".");
const computedHash = generateHash(backup.substring(0, backup.lastIndexOf(".")));
const computedHash = crypto.nativeCrypto
.createHash("sha256")
.update(backup.substring(0, backup.lastIndexOf(".")))
.digest("hex");
if (computedHash !== backupHash) {
throw new BadRequestError({
message: "Invalid backup"
@@ -1075,7 +1080,7 @@ export const kmsServiceFactory = ({
if (existingRootConfig) return existingRootConfig;
logger.info("KMS: Generating new ROOT Key");
const newRootKey = randomSecureBytes(32);
const newRootKey = crypto.randomBytes(32);
const encryptedRootKey = await $encryptRootKey(newRootKey, RootKeyEncryptionStrategy.Software).catch((err) => {
logger.error({ hsmEnabled: hsmService.isActive() }, "KMS: Failed to encrypt ROOT Key");
throw err;
@@ -1,11 +1,11 @@
/* eslint-disable class-methods-use-this */
import axios from "axios";
import { TeamsActivityHandler, TurnContext } from "botbuilder";
import jwt from "jsonwebtoken";
import { Knex } from "knex";
import { z } from "zod";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TNotification, TriggerFeature } from "@app/lib/workflow-integrations/types";
@@ -71,7 +71,7 @@ export const verifyTenantFromCode = async (
);
// Verify application token
const { tid: tenantIdFromApplicationAccessToken } = jwt.decode(applicationAccessToken) as { tid: string };
const { tid: tenantIdFromApplicationAccessToken } = crypto.jwt().decode(applicationAccessToken) as { tid: string };
if (tenantIdFromApplicationAccessToken !== tenantId) {
throw new BadRequestError({
@@ -80,7 +80,9 @@ export const verifyTenantFromCode = async (
}
// Verify user authorization token
const { tid: tenantIdFromAuthorizationAccessToken } = jwt.decode(authorizationAccessToken) as { tid: string };
const { tid: tenantIdFromAuthorizationAccessToken } = crypto.jwt().decode(authorizationAccessToken) as {
tid: string;
};
if (tenantIdFromAuthorizationAccessToken !== tenantId) {
throw new BadRequestError({
@@ -3,7 +3,7 @@ import { ForbiddenError } from "@casl/ability";
import { ProjectMembershipRole, ProjectVersion, SecretKeyEncoding } from "@app/db/schemas";
import { OrgPermissionAdminConsoleAction, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TProjectDALFactory } from "../project/project-dal";
@@ -144,12 +144,15 @@ export const orgAdminServiceFactory = ({
});
}
const botPrivateKey = infisicalSymmetricDecrypt({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
const botPrivateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
const userEncryptionKey = await userDAL.findUserEncKeyByUserId(actorId);
if (!userEncryptionKey)
+26 -20
View File
@@ -1,7 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import slugify from "@sindresorhus/slugify";
import crypto from "crypto";
import jwt from "jsonwebtoken";
import { Knex } from "knex";
import {
@@ -33,8 +31,7 @@ import { ProjectPermissionMemberActions, ProjectPermissionSub } from "@app/ee/se
import { TProjectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
import { TSamlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
import { getConfig } from "@app/lib/config/env";
import { generateAsymmetricKeyPair } from "@app/lib/crypto";
import { generateSymmetricKey, infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { generateUserSrpKeys } from "@app/lib/crypto/srp";
import { applyJitter } from "@app/lib/dates";
import { delay as delayMs } from "@app/lib/delay";
@@ -261,6 +258,7 @@ export const orgServiceFactory = ({
const addGhostUser = async (orgId: string, tx?: Knex) => {
const email = `sudo-${alphaNumericNanoId(16)}-${orgId}@infisical.com`; // We add a nanoid because the email is unique. And we have to create a new ghost user each time, so we can have access to the private key.
const password = crypto.randomBytes(128).toString("hex");
const user = await userDAL.create(
@@ -502,22 +500,22 @@ export const orgServiceFactory = ({
orgName: string;
userEmail?: string | null;
}) => {
const { privateKey, publicKey } = generateAsymmetricKeyPair();
const key = generateSymmetricKey();
const { privateKey, publicKey } = await crypto.encryption().asymmetric().generateKeyPair();
const key = crypto.randomBytes(32).toString("base64");
const {
ciphertext: encryptedPrivateKey,
iv: privateKeyIV,
tag: privateKeyTag,
encoding: privateKeyKeyEncoding,
algorithm: privateKeyAlgorithm
} = infisicalSymmetricEncypt(privateKey);
} = crypto.encryption().symmetric().encryptWithRootEncryptionKey(privateKey);
const {
ciphertext: encryptedSymmetricKey,
iv: symmetricKeyIV,
tag: symmetricKeyTag,
encoding: symmetricKeyKeyEncoding,
algorithm: symmetricKeyAlgorithm
} = infisicalSymmetricEncypt(key);
} = crypto.encryption().symmetric().encryptWithRootEncryptionKey(key);
const customerId = await licenseService.generateOrgCustomerId(orgName, userEmail);
const organization = await orgDAL.transaction(async (tx) => {
@@ -600,7 +598,7 @@ export const orgServiceFactory = ({
const cfg = getConfig();
const authToken = authorizationHeader.replace("Bearer ", "");
const decodedToken = jwt.verify(authToken, cfg.AUTH_SECRET) as AuthModeJwtTokenPayload;
const decodedToken = crypto.jwt().verify(authToken, cfg.AUTH_SECRET) as AuthModeJwtTokenPayload;
if (!decodedToken.authMethod) throw new UnauthorizedError({ name: "Auth method not found on existing token" });
const response = await orgDAL.transaction(async (tx) => {
@@ -839,6 +837,7 @@ export const orgServiceFactory = ({
const mailsForOrgInvitation: { email: string; userId: string; firstName: string; lastName: string }[] = [];
const mailsForProjectInvitation: { email: string[]; projectName: string }[] = [];
const newProjectMemberships: TProjectMemberships[] = [];
await orgDAL.transaction(async (tx) => {
const users: Pick<TUsers, "id" | "firstName" | "lastName" | "email" | "username">[] = [];
@@ -878,7 +877,10 @@ export const orgServiceFactory = ({
// Then when user sign in (as login is not possible as isAccepted is false) we rencrypt the private key with the user password
if (!inviteeUser || (inviteeUser && !inviteeUser?.isAccepted && !existingEncrytionKey)) {
const serverGeneratedPassword = crypto.randomBytes(32).toString("hex");
const { tag, encoding, ciphertext, iv } = infisicalSymmetricEncypt(serverGeneratedPassword);
const { tag, encoding, ciphertext, iv } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(serverGeneratedPassword);
const encKeys = await generateUserSrpKeys(inviteeEmail, serverGeneratedPassword);
await userDAL.createUserEncryption(
{
@@ -1096,9 +1098,10 @@ export const orgServiceFactory = ({
tx
);
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(
newGhostUser.keys.plainPrivateKey
);
const { iv, tag, ciphertext, encoding, algorithm } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(newGhostUser.keys.plainPrivateKey);
if (autoGeneratedBot) {
await projectBotDAL.updateById(
autoGeneratedBot.id,
@@ -1136,12 +1139,15 @@ export const orgServiceFactory = ({
});
}
const botPrivateKey = infisicalSymmetricDecrypt({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
const botPrivateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
const newWsMembers = assignWorkspaceKeysToMembers({
decryptKey: ghostUserLatestKey,
@@ -1306,7 +1312,7 @@ export const orgServiceFactory = ({
}
const appCfg = getConfig();
const token = jwt.sign(
const token = crypto.jwt().sign(
{
authTokenType: AuthTokenType.SIGNUP_TOKEN,
userId: user.id
@@ -1,24 +1,22 @@
import { SecretKeyEncoding } from "@app/db/schemas";
import {
decryptAsymmetric,
encryptAsymmetric,
generateAsymmetricKeyPair,
infisicalSymmetricDecrypt,
infisicalSymmetricEncypt
} from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { NotFoundError } from "@app/lib/errors";
import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
import { TProjectDALFactory } from "../project/project-dal";
import { TGetPrivateKeyDTO } from "./project-bot-types";
export const getBotPrivateKey = ({ bot }: TGetPrivateKeyDTO) =>
infisicalSymmetricDecrypt({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
export const getBotPrivateKey = ({ bot }: TGetPrivateKeyDTO) => {
return crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
iv: bot.iv,
tag: bot.tag,
ciphertext: bot.encryptedPrivateKey
});
};
export const getBotKeyFnFactory = (
projectBotDAL: TProjectBotDALFactory,
@@ -51,22 +49,31 @@ export const getBotKeyFnFactory = (
projectV1Keys.serverEncryptedPrivateKeyTag &&
projectV1Keys.serverEncryptedPrivateKeyEncoding
) {
userPrivateKey = infisicalSymmetricDecrypt({
iv: projectV1Keys.serverEncryptedPrivateKeyIV,
tag: projectV1Keys.serverEncryptedPrivateKeyTag,
ciphertext: projectV1Keys.serverEncryptedPrivateKey,
keyEncoding: projectV1Keys.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
userPrivateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
iv: projectV1Keys.serverEncryptedPrivateKeyIV,
tag: projectV1Keys.serverEncryptedPrivateKeyTag,
ciphertext: projectV1Keys.serverEncryptedPrivateKey,
keyEncoding: projectV1Keys.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
}
const workspaceKey = decryptAsymmetric({
const workspaceKey = crypto.encryption().asymmetric().decrypt({
ciphertext: projectV1Keys.projectEncryptedKey,
nonce: projectV1Keys.projectKeyNonce,
publicKey: projectV1Keys.senderPublicKey,
privateKey: userPrivateKey
});
const botKey = generateAsymmetricKeyPair();
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(botKey.privateKey);
const encryptedWorkspaceKey = encryptAsymmetric(workspaceKey, botKey.publicKey, userPrivateKey);
const botKey = await crypto.encryption().asymmetric().generateKeyPair();
const { iv, tag, ciphertext, encoding, algorithm } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(botKey.privateKey);
const encryptedWorkspaceKey = crypto
.encryption()
.asymmetric()
.encrypt(workspaceKey, botKey.publicKey, userPrivateKey);
let botId;
if (!bot) {
@@ -105,7 +112,7 @@ export const getBotKeyFnFactory = (
}
const botPrivateKey = getBotPrivateKey({ bot });
const botKey = decryptAsymmetric({
const botKey = crypto.encryption().asymmetric().decrypt({
ciphertext: bot.encryptedProjectKey,
privateKey: botPrivateKey,
nonce: bot.encryptedProjectKeyNonce,
@@ -3,8 +3,7 @@ import { ForbiddenError } from "@casl/ability";
import { ProjectVersion } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { generateAsymmetricKeyPair } from "@app/lib/crypto";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TProjectDALFactory } from "../project/project-dal";
@@ -54,9 +53,13 @@ export const projectBotServiceFactory = ({
const doc = await projectBotDAL.findOne({ projectId }, tx);
if (doc) return doc;
const keys = privateKey && publicKey ? { privateKey, publicKey } : generateAsymmetricKeyPair();
const keys =
privateKey && publicKey ? { privateKey, publicKey } : await crypto.encryption().asymmetric().generateKeyPair();
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(keys.privateKey);
const { iv, tag, ciphertext, encoding, algorithm } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(keys.privateKey);
const project = await projectDAL.findById(projectId, tx);
+10 -14
View File
@@ -1,10 +1,8 @@
import crypto from "crypto";
import { ProjectVersion, TProjects } from "@app/db/schemas";
import { createSshCaHelper } from "@app/ee/services/ssh/ssh-certificate-authority-fns";
import { SshCaKeySource } from "@app/ee/services/ssh/ssh-certificate-authority-types";
import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types";
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
import { crypto } from "@app/lib/crypto/cryptography";
import { NotFoundError } from "@app/lib/errors";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal";
@@ -12,7 +10,7 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
import { AddUserToWsDTO, TBootstrapSshProjectDTO } from "./project-types";
export const assignWorkspaceKeysToMembers = ({ members, decryptKey, userPrivateKey }: AddUserToWsDTO) => {
const plaintextProjectKey = decryptAsymmetric({
const plaintextProjectKey = crypto.encryption().asymmetric().decrypt({
ciphertext: decryptKey.encryptedKey,
nonce: decryptKey.nonce,
publicKey: decryptKey.sender.publicKey,
@@ -20,11 +18,10 @@ export const assignWorkspaceKeysToMembers = ({ members, decryptKey, userPrivateK
});
const newWsMembers = members.map(({ orgMembershipId, userPublicKey }) => {
const { ciphertext: inviteeCipherText, nonce: inviteeNonce } = encryptAsymmetric(
plaintextProjectKey,
userPublicKey,
userPrivateKey
);
const { ciphertext: inviteeCipherText, nonce: inviteeNonce } = crypto
.encryption()
.asymmetric()
.encrypt(plaintextProjectKey, userPublicKey, userPrivateKey);
return {
orgMembershipId,
@@ -47,11 +44,10 @@ export const createProjectKey = ({ publicKey, privateKey, plainProjectKey }: TCr
const randomBytes = plainProjectKey || crypto.randomBytes(16).toString("hex");
// 4. Encrypt the project key with the users key pair.
const { ciphertext: encryptedProjectKey, nonce: encryptedProjectKeyIv } = encryptAsymmetric(
randomBytes,
publicKey,
privateKey
);
const { ciphertext: encryptedProjectKey, nonce: encryptedProjectKeyIv } = crypto
.encryption()
.asymmetric()
.encrypt(randomBytes, publicKey, privateKey);
return { key: encryptedProjectKey, iv: encryptedProjectKeyIv };
};
+101 -47
View File
@@ -21,14 +21,10 @@ import {
decryptIntegrationAuths,
decryptSecretApprovals,
decryptSecrets,
decryptSecretVersions
decryptSecretVersions,
SymmetricKeySize
} from "@app/lib/crypto";
import {
decryptAsymmetric,
encryptSymmetric128BitHexKeyUTF8,
infisicalSymmetricDecrypt,
infisicalSymmetricEncypt
} from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { logger } from "@app/lib/logger";
import { QueueJobs, QueueName, TQueueJobTypes, TQueueServiceFactory } from "@app/queue";
@@ -118,17 +114,14 @@ export const projectQueueFactory = ({
await projectDAL.setProjectUpgradeStatus(data.projectId, ProjectUpgradeStatus.InProgress); // Set the status to in progress. This is important to prevent multiple upgrades at the same time.
// eslint-disable-next-line no-promise-executor-return
// await new Promise((resolve) => setTimeout(resolve, 50_000));
const userPrivateKey = infisicalSymmetricDecrypt({
const userPrivateKey = crypto.encryption().symmetric().decryptWithRootEncryptionKey({
keyEncoding: data.encryptedPrivateKey.keyEncoding,
ciphertext: data.encryptedPrivateKey.encryptedKey,
iv: data.encryptedPrivateKey.encryptedKeyIv,
tag: data.encryptedPrivateKey.encryptedKeyTag
});
const decryptedPlainProjectKey = decryptAsymmetric({
const decryptedPlainProjectKey = crypto.encryption().asymmetric().decrypt({
ciphertext: oldProjectKey.encryptedKey,
nonce: oldProjectKey.nonce,
publicKey: oldProjectKey.sender.publicKey,
@@ -321,7 +314,10 @@ export const projectQueueFactory = ({
await projectKeyDAL.insertMany(newProjectMembers, tx);
// Encrypt the bot private key (which is the same as the ghost user)
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(ghostUser.keys.plainPrivateKey);
const { iv, tag, ciphertext, encoding, algorithm } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(ghostUser.keys.plainPrivateKey);
// 5. Create a bot for the project
const newBot = await projectBotDAL.create(
@@ -342,14 +338,17 @@ export const projectQueueFactory = ({
tx
);
const botPrivateKey = infisicalSymmetricDecrypt({
keyEncoding: newBot.keyEncoding as SecretKeyEncoding,
iv: newBot.iv,
tag: newBot.tag,
ciphertext: newBot.encryptedPrivateKey
});
const botPrivateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
keyEncoding: newBot.keyEncoding as SecretKeyEncoding,
iv: newBot.iv,
tag: newBot.tag,
ciphertext: newBot.encryptedPrivateKey
});
const botKey = decryptAsymmetric({
const botKey = crypto.encryption().asymmetric().decrypt({
ciphertext: newBot.encryptedProjectKey!,
privateKey: botPrivateKey,
nonce: newBot.encryptedProjectKeyNonce!,
@@ -361,12 +360,29 @@ export const projectQueueFactory = ({
const updatedSecretApprovals: TSecretApprovalRequestsSecrets[] = [];
const updatedIntegrationAuths: TIntegrationAuths[] = [];
for (const rawSecret of decryptedSecrets) {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(rawSecret.decrypted.secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(rawSecret.decrypted.secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(
rawSecret.decrypted.secretComment || "",
botKey
);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: rawSecret.decrypted.secretKey,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: rawSecret.decrypted.secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: rawSecret.decrypted.secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const payload: TSecrets = {
...rawSecret.original,
@@ -393,15 +409,29 @@ export const projectQueueFactory = ({
}
for (const rawSecretVersion of decryptedSecretVersions) {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(rawSecretVersion.decrypted.secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(
rawSecretVersion.decrypted.secretValue || "",
botKey
);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(
rawSecretVersion.decrypted.secretComment || "",
botKey
);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: rawSecretVersion.decrypted.secretKey,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: rawSecretVersion.decrypted.secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: rawSecretVersion.decrypted.secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const payload: TSecretVersions = {
...rawSecretVersion.original,
@@ -428,15 +458,27 @@ export const projectQueueFactory = ({
}
for (const rawSecretApproval of decryptedApprovalSecrets) {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(rawSecretApproval.decrypted.secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(
rawSecretApproval.decrypted.secretValue || "",
botKey
);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(
rawSecretApproval.decrypted.secretComment || "",
botKey
);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: rawSecretApproval.decrypted.secretKey,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: rawSecretApproval.decrypted.secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: rawSecretApproval.decrypted.secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const payload: TSecretApprovalRequestsSecrets = {
...rawSecretApproval.original,
@@ -463,9 +505,21 @@ export const projectQueueFactory = ({
}
for (const integrationAuth of decryptedIntegrationAuths) {
const access = encryptSymmetric128BitHexKeyUTF8(integrationAuth.decrypted.access, botKey);
const accessId = encryptSymmetric128BitHexKeyUTF8(integrationAuth.decrypted.accessId, botKey);
const refresh = encryptSymmetric128BitHexKeyUTF8(integrationAuth.decrypted.refresh, botKey);
const access = crypto.encryption().symmetric().encrypt({
plaintext: integrationAuth.decrypted.access,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const accessId = crypto.encryption().symmetric().encrypt({
plaintext: integrationAuth.decrypted.accessId,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const refresh = crypto.encryption().symmetric().encrypt({
plaintext: integrationAuth.decrypted.refresh,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const payload: TIntegrationAuths = {
...integrationAuth.original,
@@ -27,7 +27,7 @@ import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal";
import { TSshHostGroupDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-dal";
import { PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
import { alphaNumericNanoId } from "@app/lib/nanoid";
@@ -377,7 +377,10 @@ export const projectServiceFactory = ({
tx
);
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(ghostUser.keys.plainPrivateKey);
const { iv, tag, ciphertext, encoding, algorithm } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(ghostUser.keys.plainPrivateKey);
// 5. Create & a bot for the project
await projectBotDAL.create(
@@ -820,7 +823,7 @@ export const projectServiceFactory = ({
});
}
const encryptedPrivateKey = infisicalSymmetricEncypt(userPrivateKey);
const encryptedPrivateKey = crypto.encryption().symmetric().encryptWithRootEncryptionKey(userPrivateKey);
await projectQueue.upgradeProject({
projectId,
@@ -1,10 +1,7 @@
import crypto from "node:crypto";
import bcrypt from "bcrypt";
import { TSecretSharing } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { SecretSharingAccessType } from "@app/lib/types";
@@ -136,7 +133,7 @@ export const secretSharingServiceFactory = ({
const encryptedSecret = encryptWithRoot(Buffer.from(secretValue));
const id = crypto.randomBytes(32).toString("hex");
const hashedPassword = password ? await bcrypt.hash(password, 10) : null;
const hashedPassword = password ? await crypto.hashing().createHash(password, appCfg.SALT_ROUNDS) : null;
const newSharedSecret = await secretSharingDAL.create({
identifier: id,
@@ -386,8 +383,10 @@ export const secretSharingServiceFactory = ({
const encryptWithRoot = kmsService.encryptWithRootKey();
const encryptedSecret = encryptWithRoot(Buffer.from(secretValue));
const appCfg = getConfig();
const id = crypto.randomBytes(32).toString("hex");
const hashedPassword = password ? await bcrypt.hash(password, 10) : null;
const hashedPassword = password ? await crypto.hashing().createHash(password, appCfg.SALT_ROUNDS) : null;
const newSharedSecret = await secretSharingDAL.create({
identifier: id,
@@ -529,7 +528,7 @@ export const secretSharingServiceFactory = ({
const hasProvidedPassword = Boolean(password);
if (isPasswordProtected) {
if (hasProvidedPassword) {
const isMatch = await bcrypt.compare(password as string, sharedSecret.password as string);
const isMatch = await crypto.hashing().compareHash(password as string, sharedSecret.password as string);
if (!isMatch) throw new UnauthorizedError({ message: "Invalid credentials" });
} else {
return { isPasswordProtected };
@@ -24,6 +24,8 @@ import {
Tag
} from "aws-sdk/clients/secretsmanager";
import { CustomAWSHasher } from "@app/lib/aws/hashing";
import { crypto } from "@app/lib/crypto";
import { getAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-fns";
import { AwsSecretsManagerSyncMappingBehavior } from "@app/services/secret-sync/aws-secrets-manager/aws-secrets-manager-sync-enums";
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
@@ -46,6 +48,8 @@ const getSecretsManagerClient = async (secretSync: TAwsSecretsManagerSyncWithCre
const secretsManagerClient = new SecretsManagerClient({
region: config.region,
useFipsEndpoint: crypto.isFipsModeEnabled(),
sha256: CustomAWSHasher,
credentials: config.credentials!
});
+69 -27
View File
@@ -15,11 +15,8 @@ import { hasSecretReadValueOrDescribePermission } from "@app/ee/services/permiss
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionSecretActions } from "@app/ee/services/permission/project-permission";
import { getConfig } from "@app/lib/config/env";
import {
buildSecretBlindIndexFromName,
decryptSymmetric128BitHexKeyUTF8,
encryptSymmetric128BitHexKeyUTF8
} from "@app/lib/crypto";
import { buildSecretBlindIndexFromName } from "@app/lib/crypto";
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy, unique } from "@app/lib/fn";
@@ -237,17 +234,19 @@ export const interpolateSecrets = ({ projectId, secretEncKey, secretDAL, folderD
const secrets = await secretDAL.findByFolderId(folder.id);
const decryptedSec = secrets.reduce<Record<string, string>>((prev, secret) => {
const decryptedSecretKey = decryptSymmetric128BitHexKeyUTF8({
const decryptedSecretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key: secretEncKey
key: secretEncKey,
keySize: SymmetricKeySize.Bits128
});
const decryptedSecretValue = decryptSymmetric128BitHexKeyUTF8({
const decryptedSecretValue = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key: secretEncKey
key: secretEncKey,
keySize: SymmetricKeySize.Bits128
});
// eslint-disable-next-line
@@ -364,30 +363,33 @@ export const decryptSecretRaw = (
},
key: string
) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
const secretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key
key,
keySize: SymmetricKeySize.Bits128
});
const secretValue = !secret.secretValueHidden
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key
key,
keySize: SymmetricKeySize.Bits128
})
: INFISICAL_SECRET_VALUE_HIDDEN_MASK;
let secretComment = "";
if (secret.secretCommentCiphertext && secret.secretCommentIV && secret.secretCommentTag) {
secretComment = decryptSymmetric128BitHexKeyUTF8({
secretComment = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretCommentCiphertext,
iv: secret.secretCommentIV,
tag: secret.secretCommentTag,
key
key,
keySize: SymmetricKeySize.Bits128
});
}
@@ -875,11 +877,30 @@ export const createManySecretsRawFnFactory = ({
message: `Project bot not found for project with ID '${projectId}'. Please upgrade your project.`,
name: "bot_not_found_error"
});
const inputSecrets = secrets.map((secret) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretName, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretValue || "", botKey);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: secret.secretName,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secret.secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretReferences = getAllNestedSecretReferences(secret.secretValue || "");
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretComment || "", botKey);
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secret.secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
return {
type: secret.type,
@@ -1063,10 +1084,28 @@ export const updateManySecretsRawFnFactory = ({
throw new BadRequestError({ message: "New secret name cannot be empty" });
}
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretName, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretValue || "", botKey);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: secret.secretName,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secret.secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretReferences = getAllNestedSecretReferences(secret.secretValue || "");
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretComment || "", botKey);
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secret.secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
return {
type: secret.type,
@@ -1149,28 +1188,31 @@ export const decryptSecretWithBot = (
>,
key: string
) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
const secretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key
key,
keySize: SymmetricKeySize.Bits128
});
const secretValue = decryptSymmetric128BitHexKeyUTF8({
const secretValue = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key
key,
keySize: SymmetricKeySize.Bits128
});
let secretComment = "";
if (secret.secretCommentCiphertext && secret.secretCommentIV && secret.secretCommentTag) {
secretComment = decryptSymmetric128BitHexKeyUTF8({
secretComment = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretCommentCiphertext,
iv: secret.secretCommentIV,
tag: secret.secretCommentTag,
key
key,
keySize: SymmetricKeySize.Bits128
});
}
+66 -41
View File
@@ -18,8 +18,7 @@ import { TSnapshotDALFactory } from "@app/ee/services/secret-snapshot/snapshot-d
import { TSnapshotSecretV2DALFactory } from "@app/ee/services/secret-snapshot/snapshot-secret-v2-dal";
import { KeyStorePrefixes, KeyStoreTtls, TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { getTimeDifferenceInSeconds, groupBy, isSamePath, unique } from "@app/lib/fn";
@@ -504,18 +503,20 @@ export const secretQueueFactory = ({
const secrets = await secretDAL.findByFolderId(dto.folderId);
await Promise.allSettled(
secrets.map(async (secret) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
const secretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key: dto.key
key: dto.key,
keySize: SymmetricKeySize.Bits128
});
const secretValue = decryptSymmetric128BitHexKeyUTF8({
const secretValue = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key: dto.key
key: dto.key,
keySize: SymmetricKeySize.Bits128
});
const expandedSecretValue = await expandSecretReferences({
environment: dto.environment,
@@ -527,11 +528,12 @@ export const secretQueueFactory = ({
content[secretKey] = { value: expandedSecretValue || "" };
if (secret.secretCommentCiphertext && secret.secretCommentIV && secret.secretCommentTag) {
const commentValue = decryptSymmetric128BitHexKeyUTF8({
const commentValue = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretCommentCiphertext,
iv: secret.secretCommentIV,
tag: secret.secretCommentTag,
key: dto.key
key: dto.key,
keySize: SymmetricKeySize.Bits128
});
content[secretKey].comment = commentValue;
}
@@ -952,12 +954,16 @@ export const secretQueueFactory = ({
integrationAuth.awsAssumeIamRoleArnIV &&
integrationAuth.awsAssumeIamRoleArnCipherText
) {
awsAssumeRoleArn = decryptSymmetric128BitHexKeyUTF8({
ciphertext: integrationAuth.awsAssumeIamRoleArnCipherText,
iv: integrationAuth.awsAssumeIamRoleArnIV,
tag: integrationAuth.awsAssumeIamRoleArnTag,
key: botKey as string
});
awsAssumeRoleArn = crypto
.encryption()
.symmetric()
.decrypt({
ciphertext: integrationAuth.awsAssumeIamRoleArnCipherText,
iv: integrationAuth.awsAssumeIamRoleArnIV,
tag: integrationAuth.awsAssumeIamRoleArnTag,
key: botKey as string,
keySize: SymmetricKeySize.Bits128
});
}
const suffixedSecrets: typeof secrets = {};
@@ -1236,7 +1242,10 @@ export const secretQueueFactory = ({
},
tx
);
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(ghostUser.keys.plainPrivateKey);
const { iv, tag, ciphertext, encoding, algorithm } = crypto
.encryption()
.symmetric()
.encryptWithRootEncryptionKey(ghostUser.keys.plainPrivateKey);
await projectBotDAL.updateById(
bot.id,
{
@@ -1267,27 +1276,31 @@ export const secretQueueFactory = ({
secretId: string;
references: { environment: string; secretPath: string; secretKey: string }[];
}[] = [];
await secretV2BridgeDAL.batchInsert(
projectV1Secrets.map((el) => {
const key = decryptSymmetric128BitHexKeyUTF8({
const key = crypto.encryption().symmetric().decrypt({
ciphertext: el.secretKeyCiphertext,
iv: el.secretKeyIV,
tag: el.secretKeyTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const value = decryptSymmetric128BitHexKeyUTF8({
const value = crypto.encryption().symmetric().decrypt({
ciphertext: el.secretValueCiphertext,
iv: el.secretValueIV,
tag: el.secretValueTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const comment =
el.secretCommentCiphertext && el.secretCommentTag && el.secretCommentIV
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.secretCommentCiphertext,
iv: el.secretCommentIV,
tag: el.secretCommentTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: "";
const encryptedValue = secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob;
@@ -1325,6 +1338,7 @@ export const secretQueueFactory = ({
const projectV3SecretVersionsGroupById: Record<string, TSecretVersionsV2> = {};
const projectV3SecretVersionTags: { secret_versions_v2Id: string; secret_tagsId: string }[] = [];
const projectV3SnapshotSecrets: Omit<TSecretSnapshotSecretsV2, "id">[] = [];
snapshots.forEach(({ secretVersions = [], ...snapshot }) => {
secretVersions.forEach((el) => {
projectV3SnapshotSecrets.push({
@@ -1336,25 +1350,28 @@ export const secretQueueFactory = ({
});
if (projectV3SecretVersionsGroupById[el.id]) return;
const key = decryptSymmetric128BitHexKeyUTF8({
const key = crypto.encryption().symmetric().decrypt({
ciphertext: el.secretKeyCiphertext,
iv: el.secretKeyIV,
tag: el.secretKeyTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const value = decryptSymmetric128BitHexKeyUTF8({
const value = crypto.encryption().symmetric().decrypt({
ciphertext: el.secretValueCiphertext,
iv: el.secretValueIV,
tag: el.secretValueTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const comment =
el.secretCommentCiphertext && el.secretCommentTag && el.secretCommentIV
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.secretCommentCiphertext,
iv: el.secretCommentIV,
tag: el.secretCommentTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: "";
const encryptedValue = secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob;
@@ -1395,25 +1412,28 @@ export const secretQueueFactory = ({
);
Object.values(latestSecretVersionByFolder).forEach((el) => {
if (projectV3SecretVersionsGroupById[el.id]) return;
const key = decryptSymmetric128BitHexKeyUTF8({
const key = crypto.encryption().symmetric().decrypt({
ciphertext: el.secretKeyCiphertext,
iv: el.secretKeyIV,
tag: el.secretKeyTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const value = decryptSymmetric128BitHexKeyUTF8({
const value = crypto.encryption().symmetric().decrypt({
ciphertext: el.secretValueCiphertext,
iv: el.secretValueIV,
tag: el.secretValueTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const comment =
el.secretCommentCiphertext && el.secretCommentTag && el.secretCommentIV
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.secretCommentCiphertext,
iv: el.secretCommentIV,
tag: el.secretCommentTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: "";
const encryptedValue = secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob;
@@ -1475,42 +1495,47 @@ export const secretQueueFactory = ({
* */
// eslint-disable-next-line no-await-in-loop
const projectV1IntegrationAuths = await integrationAuthDAL.find({ projectId }, { tx });
await integrationAuthDAL.upsert(
projectV1IntegrationAuths.map((el) => {
const accessToken =
el.accessIV && el.accessTag && el.accessCiphertext
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.accessCiphertext,
iv: el.accessIV,
tag: el.accessTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: undefined;
const accessId =
el.accessIdIV && el.accessIdTag && el.accessIdCiphertext
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.accessIdCiphertext,
iv: el.accessIdIV,
tag: el.accessIdTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: undefined;
const refreshToken =
el.refreshIV && el.refreshTag && el.refreshCiphertext
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.refreshCiphertext,
iv: el.refreshIV,
tag: el.refreshTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: undefined;
const awsAssumeRoleArn =
el.awsAssumeIamRoleArnCipherText && el.awsAssumeIamRoleArnIV && el.awsAssumeIamRoleArnTag
? decryptSymmetric128BitHexKeyUTF8({
? crypto.encryption().symmetric().decrypt({
ciphertext: el.awsAssumeIamRoleArnCipherText,
iv: el.awsAssumeIamRoleArnIV,
tag: el.awsAssumeIamRoleArnTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
: undefined;
+125 -35
View File
@@ -28,11 +28,8 @@ import { TSecretApprovalRequestSecretDALFactory } from "@app/ee/services/secret-
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
import { getConfig } from "@app/lib/config/env";
import {
buildSecretBlindIndexFromName,
decryptSymmetric128BitHexKeyUTF8,
encryptSymmetric128BitHexKeyUTF8
} from "@app/lib/crypto";
import { buildSecretBlindIndexFromName, SymmetricKeySize } from "@app/lib/crypto";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy, pick } from "@app/lib/fn";
import { logger } from "@app/lib/logger";
@@ -161,12 +158,16 @@ export const secretServiceFactory = ({
return (el: { ciphertext?: string; iv: string; tag: string }) =>
projectBot?.botKey
? getAllNestedSecretReferences(
decryptSymmetric128BitHexKeyUTF8({
ciphertext: el.ciphertext || "",
iv: el.iv,
tag: el.tag,
key: projectBot.botKey
})
crypto
.encryption()
.symmetric()
.decrypt({
ciphertext: el.ciphertext || "",
iv: el.iv,
tag: el.tag,
key: projectBot.botKey,
keySize: SymmetricKeySize.Bits128
})
)
: undefined;
};
@@ -1696,9 +1697,28 @@ export const secretServiceFactory = ({
message: `Project bot for project with ID '${projectId}' not found. Please upgrade your project.`,
name: "bot_not_found_error"
});
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretName, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: secretName,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
if (policy) {
const approval = await secretApprovalRequestService.generateSecretApprovalRequest({
policy,
@@ -1864,9 +1884,31 @@ export const secretServiceFactory = ({
name: "bot_not_found_error"
});
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(newSecretName || secretName, botKey);
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretKeyEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: newSecretName || secretName,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
if (policy) {
const approval = await secretApprovalRequestService.generateSecretApprovalRequest({
@@ -2110,11 +2152,30 @@ export const secretServiceFactory = ({
message: `Project bot for project with ID '${projectId}' not found. Please upgrade your project.`,
name: "bot_not_found_error"
});
const sanitizedSecrets = inputSecrets.map(
({ secretComment, secretKey, metadata, tagIds, secretValue, skipMultilineEncoding }) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
const secretKeyEncrypted = crypto.encryption().symmetric().encrypt({
plaintext: secretKey,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
return {
secretName: secretKey,
skipMultilineEncoding,
@@ -2254,6 +2315,7 @@ export const secretServiceFactory = ({
message: `Project bot for project with ID '${projectId}' not found. Please upgrade your project.`,
name: "bot_not_found_error"
});
const sanitizedSecrets = inputSecrets.map(
({
secretComment,
@@ -2265,9 +2327,30 @@ export const secretServiceFactory = ({
secretReminderNote,
secretReminderRepeatDays
}) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(newSecretName || secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
const secretKeyEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: newSecretName || secretKey,
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretValue || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretCommentEncrypted = crypto
.encryption()
.symmetric()
.encrypt({
plaintext: secretComment || "",
key: botKey,
keySize: SymmetricKeySize.Bits128
});
return {
secretName: secretKey,
newSecretName,
@@ -2476,12 +2559,14 @@ export const secretServiceFactory = ({
limit,
sort: [["createdAt", "desc"]]
});
return secretVersions.map((el) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
const secretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
const secretValueHidden = !hasSecretReadValueOrDescribePermission(
@@ -2798,11 +2883,12 @@ export const secretServiceFactory = ({
secrets.map(({ id, secretValueCiphertext, secretValueIV, secretValueTag }) => ({
secretId: id,
references: getAllNestedSecretReferences(
decryptSymmetric128BitHexKeyUTF8({
crypto.encryption().symmetric().decrypt({
ciphertext: secretValueCiphertext,
iv: secretValueIV,
tag: secretValueTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
)
})),
@@ -2902,11 +2988,12 @@ export const secretServiceFactory = ({
const destinationActions = [ProjectPermissionSecretActions.Create, ProjectPermissionSecretActions.Edit] as const;
const decryptedSourceSecrets = sourceSecrets.map((secret) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
const secretKey = crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
});
for (const destinationAction of destinationActions) {
@@ -2942,11 +3029,12 @@ export const secretServiceFactory = ({
return {
...secret,
secretKey,
secretValue: decryptSymmetric128BitHexKeyUTF8({
secretValue: crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
};
});
@@ -2967,17 +3055,19 @@ export const secretServiceFactory = ({
const decryptedDestinationSecrets = destinationSecretsFromDB.map((secret) => {
return {
...secret,
secretKey: decryptSymmetric128BitHexKeyUTF8({
secretKey: crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
}),
secretValue: decryptSymmetric128BitHexKeyUTF8({
secretValue: crypto.encryption().symmetric().decrypt({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key: botKey
key: botKey,
keySize: SymmetricKeySize.Bits128
})
};
});
@@ -1,7 +1,4 @@
import crypto from "node:crypto";
import { ForbiddenError, subject } from "@casl/ability";
import bcrypt from "bcrypt";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -10,6 +7,7 @@ import {
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@@ -87,7 +85,7 @@ export const serviceTokenServiceFactory = ({
throw new NotFoundError({ message: `One or more selected environments not found` });
const secret = crypto.randomBytes(16).toString("hex");
const secretHash = await bcrypt.hash(secret, appCfg.SALT_ROUNDS);
const secretHash = await crypto.hashing().createHash(secret, appCfg.SALT_ROUNDS);
let expiresAt: Date | null = null;
if (expiresIn) {
expiresAt = new Date();
@@ -178,7 +176,7 @@ export const serviceTokenServiceFactory = ({
throw new ForbiddenRequestError({ message: "Service token has expired" });
}
const isMatch = await bcrypt.compare(tokenSecret, serviceToken.secretHash);
const isMatch = await crypto.hashing().compareHash(tokenSecret, serviceToken.secretHash);
if (!isMatch) throw new UnauthorizedError({ message: "Invalid service token" });
await accessTokenQueue.updateServiceTokenStatus(serviceToken.id);
@@ -1,6 +1,4 @@
import bcrypt from "bcrypt";
import { CronJob } from "cron";
import jwt from "jsonwebtoken";
import { IdentityAuthMethod, OrgMembershipRole, TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -12,7 +10,7 @@ import {
overwriteSchema,
validateOverrides
} from "@app/lib/config/env";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { generateUserSrpKeys, getUserPrivateKey } from "@app/lib/crypto/srp";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@@ -164,6 +162,7 @@ export const superAdminServiceFactory = ({
const newCfg = await serverCfgDAL.create({
// @ts-expect-error id is kept as fixed for idempotence and to avoid race condition
id: ADMIN_CONFIG_DB_UUID,
fipsEnabled: crypto.isFipsModeEnabled(),
initialized: false,
allowSignUp: true,
defaultAuthOrgId: null
@@ -277,6 +276,7 @@ export const superAdminServiceFactory = ({
const $syncEnvConfig = async () => {
const config = await getEnvOverrides();
overrideEnvConfig(config);
};
@@ -483,6 +483,7 @@ export const superAdminServiceFactory = ({
userAgent
}: TAdminSignUpDTO) => {
const appCfg = getConfig();
const sanitizedEmail = email.trim().toLowerCase();
const existingUser = await userDAL.findOne({ username: sanitizedEmail });
if (existingUser) throw new BadRequestError({ name: "Admin sign up", message: "User already exists" });
@@ -497,8 +498,10 @@ export const superAdminServiceFactory = ({
iv: encryptedPrivateKeyIV,
tag: encryptedPrivateKeyTag
});
const hashedPassword = await bcrypt.hash(password, appCfg.BCRYPT_SALT_ROUND);
const { iv, tag, ciphertext, encoding } = infisicalSymmetricEncypt(privateKey);
const hashedPassword = await crypto.hashing().createHash(password, appCfg.SALT_ROUNDS);
const { iv, tag, ciphertext, encoding } = crypto.encryption().symmetric().encryptWithRootEncryptionKey(privateKey);
const userInfo = await userDAL.transaction(async (tx) => {
const newUser = await userDAL.create(
{
@@ -584,7 +587,7 @@ export const superAdminServiceFactory = ({
},
tx
);
const { tag, encoding, ciphertext, iv } = infisicalSymmetricEncypt(password);
const { tag, encoding, ciphertext, iv } = crypto.encryption().symmetric().encryptWithRootEncryptionKey(password);
const encKeys = await generateUserSrpKeys(sanitizedEmail, password);
const userEnc = await userDAL.createUserEncryption(
@@ -666,7 +669,7 @@ export const superAdminServiceFactory = ({
tx
);
const generatedAccessToken = jwt.sign(
const generatedAccessToken = crypto.jwt().sign(
{
identityId: newIdentity.id,
identityAccessTokenId: newToken.id,
@@ -1,4 +1,3 @@
import { createHash, randomUUID } from "crypto";
import { PostHog } from "posthog-node";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -6,6 +5,7 @@ import { InstanceType } from "@app/ee/services/license/license-types";
import { TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto/cryptography";
import { logger } from "@app/lib/logger";
import { PostHogEventTypes, TPostHogEvent, TSecretModifiedEvent } from "./telemetry-types";
@@ -42,7 +42,7 @@ export type TTelemetryServiceFactoryDep = {
const getBucketForDistinctId = (distinctId: string): string => {
// Use SHA-256 hash for consistent distribution
const hash = createHash("sha256").update(distinctId).digest("hex");
const hash = crypto.nativeCrypto.createHash("sha256").update(distinctId).digest("hex");
// Take first 8 characters and convert to number for better distribution
const hashNumber = parseInt(hash.substring(0, 8), 16);
@@ -53,7 +53,7 @@ const getBucketForDistinctId = (distinctId: string): string => {
export const createTelemetryEventKey = (event: string, distinctId: string): string => {
const bucketId = getBucketForDistinctId(distinctId);
return `telemetry-event-${event}-${bucketId}-${distinctId}-${randomUUID()}`;
return `telemetry-event-${event}-${bucketId}-${distinctId}-${crypto.nativeCrypto.randomUUID()}`;
};
export const telemetryServiceFactory = ({ keyStore, licenseService }: TTelemetryServiceFactoryDep) => {
+1 -1
View File
@@ -1,3 +1,3 @@
import crypto from "node:crypto";
import { crypto } from "@app/lib/crypto/cryptography";
export const generateRecoveryCode = () => String(crypto.randomInt(10 ** 7, 10 ** 8 - 1));
+11 -7
View File
@@ -3,7 +3,7 @@ import { ForbiddenError } from "@casl/ability";
import { SecretKeyEncoding } from "@app/db/schemas";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
@@ -217,12 +217,16 @@ export const userServiceFactory = ({
if (!user?.serverEncryptedPrivateKey || !user.serverEncryptedPrivateKeyIV || !user.serverEncryptedPrivateKeyTag) {
throw new NotFoundError({ message: `Private key for user with ID '${userId}' not found` });
}
const privateKey = infisicalSymmetricDecrypt({
ciphertext: user.serverEncryptedPrivateKey,
tag: user.serverEncryptedPrivateKeyTag,
iv: user.serverEncryptedPrivateKeyIV,
keyEncoding: user.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
const privateKey = crypto
.encryption()
.symmetric()
.decryptWithRootEncryptionKey({
ciphertext: user.serverEncryptedPrivateKey,
tag: user.serverEncryptedPrivateKeyTag,
iv: user.serverEncryptedPrivateKeyIV,
keyEncoding: user.serverEncryptedPrivateKeyEncoding as SecretKeyEncoding
});
return privateKey;
};
+5 -4
View File
@@ -1,11 +1,10 @@
import crypto from "node:crypto";
import { AxiosError } from "axios";
import picomatch from "picomatch";
import { TWebhooks } from "@app/db/schemas";
import { EventType, TAuditLogServiceFactory, WebhookTriggeredEvent } from "@app/ee/services/audit-log/audit-log-types";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto/cryptography";
import { NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { ActorType } from "@app/services/auth/auth-type";
@@ -41,9 +40,11 @@ export const triggerWebhookRequest = async (
const headers: Record<string, string> = {};
const payload = { ...data, timestamp: Date.now() };
const { secretKey, url } = decryptWebhookDetails(webhook, decryptor);
if (secretKey) {
const webhookSign = crypto.createHmac("sha256", secretKey).update(JSON.stringify(payload)).digest("hex");
const webhookSign = crypto.nativeCrypto
.createHmac("sha256", secretKey)
.update(JSON.stringify(payload))
.digest("hex");
headers["x-infisical-signature"] = `t=${payload.timestamp};${webhookSign}`;
}