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](); };