Files
2026-07-17 12:35:34 +01:00

545 lines
16 KiB
TypeScript

import { filterEmptyValues, getFormValue } from "@/lib";
import { ProviderType } from "@/types";
import {
isConfigurableProvider,
type KnownProviderType,
} from "@/types/providers";
import { ProviderCredentialFields } from "./provider-credential-fields";
// Helper functions for each provider type
export const buildAWSSecret = (formData: FormData, isRole: boolean) => {
if (isRole) {
const secret = {
[ProviderCredentialFields.ROLE_ARN]: getFormValue(
formData,
ProviderCredentialFields.ROLE_ARN,
),
[ProviderCredentialFields.EXTERNAL_ID]: getFormValue(
formData,
ProviderCredentialFields.EXTERNAL_ID,
),
[ProviderCredentialFields.AWS_ACCESS_KEY_ID]: getFormValue(
formData,
ProviderCredentialFields.AWS_ACCESS_KEY_ID,
),
[ProviderCredentialFields.AWS_SECRET_ACCESS_KEY]: getFormValue(
formData,
ProviderCredentialFields.AWS_SECRET_ACCESS_KEY,
),
[ProviderCredentialFields.AWS_SESSION_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.AWS_SESSION_TOKEN,
),
session_duration:
parseInt(
getFormValue(
formData,
ProviderCredentialFields.SESSION_DURATION,
) as string,
10,
) || 3600,
[ProviderCredentialFields.ROLE_SESSION_NAME]: getFormValue(
formData,
ProviderCredentialFields.ROLE_SESSION_NAME,
),
};
return filterEmptyValues(secret);
}
const secret = {
[ProviderCredentialFields.AWS_ACCESS_KEY_ID]: getFormValue(
formData,
ProviderCredentialFields.AWS_ACCESS_KEY_ID,
),
[ProviderCredentialFields.AWS_SECRET_ACCESS_KEY]: getFormValue(
formData,
ProviderCredentialFields.AWS_SECRET_ACCESS_KEY,
),
[ProviderCredentialFields.AWS_SESSION_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.AWS_SESSION_TOKEN,
),
};
return filterEmptyValues(secret);
};
export const buildAzureSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.CLIENT_ID]: getFormValue(
formData,
ProviderCredentialFields.CLIENT_ID,
),
[ProviderCredentialFields.CLIENT_SECRET]: getFormValue(
formData,
ProviderCredentialFields.CLIENT_SECRET,
),
[ProviderCredentialFields.TENANT_ID]: getFormValue(
formData,
ProviderCredentialFields.TENANT_ID,
),
};
return filterEmptyValues(secret);
};
export const buildM365Secret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.CLIENT_ID]: getFormValue(
formData,
ProviderCredentialFields.CLIENT_ID,
),
[ProviderCredentialFields.TENANT_ID]: getFormValue(
formData,
ProviderCredentialFields.TENANT_ID,
),
[ProviderCredentialFields.CLIENT_SECRET]: getFormValue(
formData,
ProviderCredentialFields.CLIENT_SECRET,
),
[ProviderCredentialFields.CERTIFICATE_CONTENT]: getFormValue(
formData,
ProviderCredentialFields.CERTIFICATE_CONTENT,
),
};
return filterEmptyValues(secret);
};
export const buildGCPSecret = (
formData: FormData,
isServiceAccount: boolean,
) => {
if (isServiceAccount) {
const serviceAccountKeyRaw = getFormValue(
formData,
ProviderCredentialFields.SERVICE_ACCOUNT_KEY,
) as string;
try {
return {
service_account_key: JSON.parse(serviceAccountKeyRaw),
};
} catch (error) {
console.error("Invalid service account key JSON:", error);
throw new Error("Invalid service account key format");
}
}
const secret = {
[ProviderCredentialFields.CLIENT_ID]: getFormValue(
formData,
ProviderCredentialFields.CLIENT_ID,
),
[ProviderCredentialFields.CLIENT_SECRET]: getFormValue(
formData,
ProviderCredentialFields.CLIENT_SECRET,
),
[ProviderCredentialFields.REFRESH_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.REFRESH_TOKEN,
),
};
return filterEmptyValues(secret);
};
export const buildKubernetesSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.KUBECONFIG_CONTENT]: getFormValue(
formData,
ProviderCredentialFields.KUBECONFIG_CONTENT,
),
};
return filterEmptyValues(secret);
};
export const buildGitHubSecret = (formData: FormData) => {
// Check which authentication method is being used
const hasPersonalToken =
formData.get(ProviderCredentialFields.PERSONAL_ACCESS_TOKEN) !== null &&
formData.get(ProviderCredentialFields.PERSONAL_ACCESS_TOKEN) !== "";
const hasOAuthToken =
formData.get(ProviderCredentialFields.OAUTH_APP_TOKEN) !== null &&
formData.get(ProviderCredentialFields.OAUTH_APP_TOKEN) !== "";
const hasGitHubApp =
formData.get(ProviderCredentialFields.GITHUB_APP_ID) !== null &&
formData.get(ProviderCredentialFields.GITHUB_APP_ID) !== "";
if (hasPersonalToken) {
const secret = {
[ProviderCredentialFields.PERSONAL_ACCESS_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.PERSONAL_ACCESS_TOKEN,
),
};
return filterEmptyValues(secret);
}
if (hasOAuthToken) {
const secret = {
[ProviderCredentialFields.OAUTH_APP_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.OAUTH_APP_TOKEN,
),
};
return filterEmptyValues(secret);
}
if (hasGitHubApp) {
const secret = {
[ProviderCredentialFields.GITHUB_APP_ID]: getFormValue(
formData,
ProviderCredentialFields.GITHUB_APP_ID,
),
[ProviderCredentialFields.GITHUB_APP_KEY]: getFormValue(
formData,
ProviderCredentialFields.GITHUB_APP_KEY,
),
};
return filterEmptyValues(secret);
}
// If no credentials are provided, return empty object
return {};
};
export const buildMongoDBAtlasSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.ATLAS_PUBLIC_KEY]: getFormValue(
formData,
ProviderCredentialFields.ATLAS_PUBLIC_KEY,
),
[ProviderCredentialFields.ATLAS_PRIVATE_KEY]: getFormValue(
formData,
ProviderCredentialFields.ATLAS_PRIVATE_KEY,
),
};
return filterEmptyValues(secret);
};
export const buildAlibabaCloudSecret = (
formData: FormData,
isRole: boolean,
) => {
if (isRole) {
const secret = {
[ProviderCredentialFields.ALIBABACLOUD_ROLE_ARN]: getFormValue(
formData,
ProviderCredentialFields.ALIBABACLOUD_ROLE_ARN,
),
[ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_ID]: getFormValue(
formData,
ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_ID,
),
[ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_SECRET]: getFormValue(
formData,
ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_SECRET,
),
[ProviderCredentialFields.ALIBABACLOUD_ROLE_SESSION_NAME]: getFormValue(
formData,
ProviderCredentialFields.ALIBABACLOUD_ROLE_SESSION_NAME,
),
};
return filterEmptyValues(secret);
}
const secret = {
[ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_ID]: getFormValue(
formData,
ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_ID,
),
[ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_SECRET]: getFormValue(
formData,
ProviderCredentialFields.ALIBABACLOUD_ACCESS_KEY_SECRET,
),
};
return filterEmptyValues(secret);
};
export const buildVercelSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.VERCEL_API_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.VERCEL_API_TOKEN,
),
};
return filterEmptyValues(secret);
};
export const buildOktaSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.OKTA_CLIENT_ID]: getFormValue(
formData,
ProviderCredentialFields.OKTA_CLIENT_ID,
),
[ProviderCredentialFields.OKTA_PRIVATE_KEY]: getFormValue(
formData,
ProviderCredentialFields.OKTA_PRIVATE_KEY,
),
};
return filterEmptyValues(secret);
};
export const buildOpenStackSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.OPENSTACK_CLOUDS_YAML_CONTENT]: getFormValue(
formData,
ProviderCredentialFields.OPENSTACK_CLOUDS_YAML_CONTENT,
),
[ProviderCredentialFields.OPENSTACK_CLOUDS_YAML_CLOUD]: getFormValue(
formData,
ProviderCredentialFields.OPENSTACK_CLOUDS_YAML_CLOUD,
),
};
return filterEmptyValues(secret);
};
export const buildGoogleWorkspaceSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.GOOGLEWORKSPACE_CREDENTIALS_CONTENT]:
getFormValue(
formData,
ProviderCredentialFields.GOOGLEWORKSPACE_CREDENTIALS_CONTENT,
),
[ProviderCredentialFields.GOOGLEWORKSPACE_DELEGATED_USER]: getFormValue(
formData,
ProviderCredentialFields.GOOGLEWORKSPACE_DELEGATED_USER,
),
};
return filterEmptyValues(secret);
};
export const buildIacSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.REPOSITORY_URL]: getFormValue(
formData,
ProviderCredentialFields.REPOSITORY_URL,
),
[ProviderCredentialFields.ACCESS_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.ACCESS_TOKEN,
),
};
return filterEmptyValues(secret);
};
export const buildImageSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.REGISTRY_USERNAME]: getFormValue(
formData,
ProviderCredentialFields.REGISTRY_USERNAME,
),
[ProviderCredentialFields.REGISTRY_PASSWORD]: getFormValue(
formData,
ProviderCredentialFields.REGISTRY_PASSWORD,
),
[ProviderCredentialFields.REGISTRY_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.REGISTRY_TOKEN,
),
[ProviderCredentialFields.IMAGE_FILTER]: getFormValue(
formData,
ProviderCredentialFields.IMAGE_FILTER,
),
[ProviderCredentialFields.TAG_FILTER]: getFormValue(
formData,
ProviderCredentialFields.TAG_FILTER,
),
};
return filterEmptyValues(secret);
};
/**
* Utility function to safely encode a string to base64
* Handles UTF-8 characters properly without using deprecated APIs
*/
const base64Encode = (str: string): string => {
if (!str) return "";
// Convert string to UTF-8 bytes, then to base64
const utf8Bytes = new TextEncoder().encode(str);
// Convert Uint8Array to binary string without spread operator
let binaryString = "";
for (let i = 0; i < utf8Bytes.length; i++) {
binaryString += String.fromCharCode(utf8Bytes[i]);
}
return btoa(binaryString);
};
export const buildOracleCloudSecret = (
formData: FormData,
providerUid?: string,
) => {
const keyContent = getFormValue(
formData,
ProviderCredentialFields.OCI_KEY_CONTENT,
) as string;
// Base64 encode the key content for the backend
// Uses modern TextEncoder API to properly handle UTF-8 characters
const encodedKeyContent = base64Encode(keyContent);
const secret = {
[ProviderCredentialFields.OCI_USER]: getFormValue(
formData,
ProviderCredentialFields.OCI_USER,
),
[ProviderCredentialFields.OCI_FINGERPRINT]: getFormValue(
formData,
ProviderCredentialFields.OCI_FINGERPRINT,
),
[ProviderCredentialFields.OCI_KEY_CONTENT]: encodedKeyContent,
[ProviderCredentialFields.OCI_TENANCY]:
providerUid ||
getFormValue(formData, ProviderCredentialFields.OCI_TENANCY),
[ProviderCredentialFields.OCI_PASS_PHRASE]: getFormValue(
formData,
ProviderCredentialFields.OCI_PASS_PHRASE,
),
};
return filterEmptyValues(secret);
};
/**
* Clean a Cloudflare API token by removing common copy-paste issues:
* - Leading/trailing whitespace
* - "Bearer " prefix (if user copied the full header)
* - Tabs and other whitespace characters
*/
const cleanCloudflareToken = (token: string | null | undefined): string => {
if (!token) return "";
// Remove leading/trailing whitespace and tabs
let cleaned = token.trim().replace(/\t/g, "");
// Remove "Bearer " prefix if present (case-insensitive)
if (cleaned.toLowerCase().startsWith("bearer ")) {
cleaned = cleaned.slice(7).trim();
}
return cleaned;
};
export const buildCloudflareSecret = (formData: FormData) => {
// Check which authentication method is being used
const hasApiToken =
formData.get(ProviderCredentialFields.CLOUDFLARE_API_TOKEN) !== null &&
formData.get(ProviderCredentialFields.CLOUDFLARE_API_TOKEN) !== "";
const hasApiKey =
formData.get(ProviderCredentialFields.CLOUDFLARE_API_KEY) !== null &&
formData.get(ProviderCredentialFields.CLOUDFLARE_API_KEY) !== "";
if (hasApiToken) {
const apiToken = getFormValue(
formData,
ProviderCredentialFields.CLOUDFLARE_API_TOKEN,
) as string;
return {
[ProviderCredentialFields.CLOUDFLARE_API_TOKEN]:
cleanCloudflareToken(apiToken),
};
}
if (hasApiKey) {
const apiKey = getFormValue(
formData,
ProviderCredentialFields.CLOUDFLARE_API_KEY,
) as string;
const apiEmail = getFormValue(
formData,
ProviderCredentialFields.CLOUDFLARE_API_EMAIL,
) as string;
return filterEmptyValues({
[ProviderCredentialFields.CLOUDFLARE_API_KEY]: apiKey?.trim(),
[ProviderCredentialFields.CLOUDFLARE_API_EMAIL]: apiEmail?.trim(),
});
}
return {};
};
// Main function to build secret configuration
export const buildSecretConfig = (
formData: FormData,
providerType: ProviderType,
providerUid?: string,
) => {
const isRole = formData.get(ProviderCredentialFields.ROLE_ARN) !== null;
const isServiceAccount =
formData.get(ProviderCredentialFields.SERVICE_ACCOUNT_KEY) !== null;
const secretBuilders: Record<
KnownProviderType,
() => { secretType: string; secret: unknown }
> = {
aws: () => ({
secretType: isRole ? "role" : "static",
secret: buildAWSSecret(formData, isRole),
}),
azure: () => ({
secretType: "static",
secret: buildAzureSecret(formData),
}),
m365: () => ({
secretType: "static",
secret: buildM365Secret(formData),
}),
gcp: () => ({
secretType: isServiceAccount ? "service_account" : "static",
secret: buildGCPSecret(formData, isServiceAccount),
}),
kubernetes: () => ({
secretType: "static",
secret: buildKubernetesSecret(formData),
}),
github: () => ({
secretType: "static",
secret: buildGitHubSecret(formData),
}),
iac: () => ({
secretType: "static",
secret: buildIacSecret(formData),
}),
image: () => ({
secretType: "static",
secret: buildImageSecret(formData),
}),
oraclecloud: () => ({
secretType: "static",
secret: buildOracleCloudSecret(formData, providerUid),
}),
mongodbatlas: () => ({
secretType: "static",
secret: buildMongoDBAtlasSecret(formData),
}),
alibabacloud: () => {
const isRole =
formData.get(ProviderCredentialFields.ALIBABACLOUD_ROLE_ARN) !== null;
return {
secretType: isRole ? "role" : "static",
secret: buildAlibabaCloudSecret(formData, isRole),
};
},
cloudflare: () => ({
secretType: "static",
secret: buildCloudflareSecret(formData),
}),
openstack: () => ({
secretType: "static",
secret: buildOpenStackSecret(formData),
}),
googleworkspace: () => ({
secretType: "static",
secret: buildGoogleWorkspaceSecret(formData),
}),
vercel: () => ({
secretType: "static",
secret: buildVercelSecret(formData),
}),
okta: () => ({
secretType: "static",
secret: buildOktaSecret(formData),
}),
};
if (!isConfigurableProvider(providerType)) {
throw new Error(`Unsupported provider type: ${providerType}`);
}
return secretBuilders[providerType]();
};