diff --git a/README.md b/README.md
index e18491e0..98a40fe1 100644
--- a/README.md
+++ b/README.md
@@ -46,10 +46,10 @@ GOOGLE_API_KEY=""
# Daytona API key for accessing and modifying the code in the cloud sandbox.
DAYTONA_API_KEY=""
-# Encryption key for GitHub tokens (32-byte hex string for AES-256)
+# Encryption key for secrets (32-byte hex string for AES-256)
# Should be the same value as the one used in the web app.
# Can be generated via: `openssl rand -hex 32`
-GITHUB_TOKEN_ENCRYPTION_KEY=""
+SECRETS_ENCRYPTION_KEY=""
# Used for setting the git user name & email for commits.
GITHUB_APP_NAME="open-swe-dev"
@@ -75,13 +75,13 @@ GITHUB_APP_NAME="open-swe-dev"
GITHUB_APP_ID=""
GITHUB_APP_PRIVATE_KEY=""
-# Encryption key for GitHub tokens (32-byte hex string for AES-256)
+# Encryption key for secrets (32-byte hex string for AES-256)
# Should be the same value as the one used in the open-swe app.
# Can be generated via: `openssl rand -hex 32`
-GITHUB_TOKEN_ENCRYPTION_KEY=""
+SECRETS_ENCRYPTION_KEY=""
```
-**REMINDER**: The `GITHUB_TOKEN_ENCRYPTION_KEY` environment variable must be the same in both the web and open-swe apps.
+**REMINDER**: The `SECRETS_ENCRYPTION_KEY` environment variable must be the same in both the web and open-swe apps.
To get the GitHub App secrets, first create a new GitHub app (note: this is not the same as the OAuth app) in [the developer settings](https://github.com/settings/apps/new).
diff --git a/apps/docs/setup/authentication.mdx b/apps/docs/setup/authentication.mdx
index 01af3267..cf42d947 100644
--- a/apps/docs/setup/authentication.mdx
+++ b/apps/docs/setup/authentication.mdx
@@ -47,12 +47,12 @@ All headers are prefixed with `x-` to ensure they're included in LangGraph run c
### Token Encryption
-Open SWE implements AES-256-GCM encryption for all GitHub tokens to prevent exposure in:
+Open SWE implements AES-256-GCM encryption for all secrets passed to the LangGraph server to prevent exposure in:
- LangSmith trace metadata
- Run configurations
- Potential unauthorized access scenarios
-The encryption process uses the `GITHUB_TOKEN_ENCRYPTION_KEY` environment variable and includes:
+The encryption process uses the `SECRETS_ENCRYPTION_KEY` environment variable and includes:
- **Initialization Vector (IV)** for unique encryption per token
- **Authentication Tag** for data integrity verification
- **Base64 encoding** for safe transport
@@ -135,5 +135,5 @@ This design ensures tokens remain encrypted in storage and traces while being av
-Always ensure the `GITHUB_TOKEN_ENCRYPTION_KEY` environment variable is identical between your web application and LangGraph agent deployments.
+Always ensure the `SECRETS_ENCRYPTION_KEY` environment variable is identical between your web application and LangGraph agent deployments.
diff --git a/apps/docs/setup/development.mdx b/apps/docs/setup/development.mdx
index 96de70f3..772014ab 100644
--- a/apps/docs/setup/development.mdx
+++ b/apps/docs/setup/development.mdx
@@ -62,8 +62,8 @@ Before starting, ensure you have the following installed:
GITHUB_APP_CLIENT_SECRET=""
GITHUB_APP_REDIRECT_URI="http://localhost:3000/api/auth/github/callback"
- # Token encryption key (generate with: openssl rand -hex 32)
- GITHUB_TOKEN_ENCRYPTION_KEY=""
+ # Encryption key for secrets (generate with: openssl rand -hex 32)
+ SECRETS_ENCRYPTION_KEY=""
# GitHub App details (will be filled after creating GitHub App)
GITHUB_APP_NAME="open-swe-dev"
@@ -101,7 +101,6 @@ Before starting, ensure you have the following installed:
FIRECRAWL_API_KEY="" # For URL content extraction
# GitHub App settings (same as web app)
- GITHUB_TOKEN_ENCRYPTION_KEY="" # Must match web app value
GITHUB_APP_NAME="open-swe-dev"
GITHUB_APP_ID=""
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
@@ -113,10 +112,11 @@ Before starting, ensure you have the following installed:
# Server configuration
PORT="2024"
OPEN_SWE_APP_URL="http://localhost:3000"
+ SECRETS_ENCRYPTION_KEY="" # Must match web app value
```
- Generate the `GITHUB_TOKEN_ENCRYPTION_KEY` using: `openssl rand -hex 32`. This key must be identical in both environment files.
+ Generate the `SECRETS_ENCRYPTION_KEY` using: `openssl rand -hex 32`. This key must be identical in both environment files.
diff --git a/apps/open-swe/.env.example b/apps/open-swe/.env.example
index 17eeb803..c3d38e46 100644
--- a/apps/open-swe/.env.example
+++ b/apps/open-swe/.env.example
@@ -25,10 +25,6 @@ FIRECRAWL_API_KEY=""
# ------------------Github App Secrets-----------------
-# Encryption key for GitHub tokens (32-byte hex string for AES-256)
-# Should be the same value as the one used in the web app, so that tokens
-# encrypted in the web app can be decrypted in the agent.
-GITHUB_TOKEN_ENCRYPTION_KEY=""
# Used for setting the git user name & email for commits.
# Can modify to whatever string you want.
GITHUB_APP_NAME="open-swe-dev"
@@ -50,3 +46,7 @@ PORT="2024"
# Should be the URL of the web app. Localhost in dev, production URL
# in production.
OPEN_SWE_APP_URL="http://localhost:3000"
+# Encryption key for secrets (32-byte hex string for AES-256)
+# Should be the same value as the one used in the web app, so that secrets
+# encrypted in the web app can be decrypted in the agent.
+SECRETS_ENCRYPTION_KEY=""
diff --git a/apps/open-swe/src/routes/github/issue-webhook.ts b/apps/open-swe/src/routes/github/issue-webhook.ts
index 0ba94aa5..ea6bf95c 100644
--- a/apps/open-swe/src/routes/github/issue-webhook.ts
+++ b/apps/open-swe/src/routes/github/issue-webhook.ts
@@ -12,7 +12,7 @@ import {
GITHUB_USER_LOGIN_HEADER,
MANAGER_GRAPH_ID,
} from "@open-swe/shared/constants";
-import { encryptGitHubToken } from "@open-swe/shared/crypto";
+import { encryptSecret } from "@open-swe/shared/crypto";
import { HumanMessage } from "@langchain/core/messages";
import {
getOpenSWEAutoAcceptLabel,
@@ -86,10 +86,8 @@ const getHeaders = (
};
webhooks.on("issues.labeled", async ({ payload }) => {
- if (!process.env.GITHUB_TOKEN_ENCRYPTION_KEY) {
- throw new Error(
- "GITHUB_TOKEN_ENCRYPTION_KEY environment variable is required",
- );
+ if (!process.env.SECRETS_ENCRYPTION_KEY) {
+ throw new Error("SECRETS_ENCRYPTION_KEY environment variable is required");
}
const validOpenSWELabels = [getOpenSWELabel(), getOpenSWEAutoAcceptLabel()];
if (
@@ -132,9 +130,9 @@ webhooks.on("issues.labeled", async ({ payload }) => {
const langGraphClient = createLangGraphClient({
defaultHeaders: {
- [GITHUB_INSTALLATION_TOKEN_COOKIE]: encryptGitHubToken(
+ [GITHUB_INSTALLATION_TOKEN_COOKIE]: encryptSecret(
token,
- process.env.GITHUB_TOKEN_ENCRYPTION_KEY,
+ process.env.SECRETS_ENCRYPTION_KEY,
),
[GITHUB_INSTALLATION_NAME]: issueData.owner,
[GITHUB_USER_ID_HEADER]: issueData.userId.toString(),
diff --git a/apps/open-swe/src/security/auth.ts b/apps/open-swe/src/security/auth.ts
index 0c0cf075..8da8782c 100644
--- a/apps/open-swe/src/security/auth.ts
+++ b/apps/open-swe/src/security/auth.ts
@@ -11,7 +11,7 @@ import {
GITHUB_USER_ID_HEADER,
GITHUB_USER_LOGIN_HEADER,
} from "@open-swe/shared/constants";
-import { decryptGitHubToken } from "@open-swe/shared/crypto";
+import { decryptSecret } from "@open-swe/shared/crypto";
import { verifyGitHubWebhookOrThrow } from "./github.js";
import { createWithOwnerMetadata, createOwnerFilter } from "./utils.js";
@@ -49,11 +49,9 @@ export const auth = new Auth()
return await verifyGitHubWebhookOrThrow(request);
}
- const encryptionKey = process.env.GITHUB_TOKEN_ENCRYPTION_KEY;
+ const encryptionKey = process.env.SECRETS_ENCRYPTION_KEY;
if (!encryptionKey) {
- throw new Error(
- "Missing GITHUB_TOKEN_ENCRYPTION_KEY environment variable.",
- );
+ throw new Error("Missing SECRETS_ENCRYPTION_KEY environment variable.");
}
const installationNameHeader = request.headers.get(
@@ -90,14 +88,14 @@ export const auth = new Auth()
});
}
user = await verifyGithubUserId(
- decryptGitHubToken(encryptedInstallationToken, encryptionKey),
+ decryptSecret(encryptedInstallationToken, encryptionKey),
Number(userIdHeader),
userLoginHeader,
);
} else {
// Ensure we decrypt the token before passing to the verification function.
user = await verifyGithubUser(
- decryptGitHubToken(encryptedAccessToken, encryptionKey),
+ decryptSecret(encryptedAccessToken, encryptionKey),
);
}
diff --git a/apps/open-swe/src/utils/github-tokens.ts b/apps/open-swe/src/utils/github-tokens.ts
index 15a2d8f7..df141ce6 100644
--- a/apps/open-swe/src/utils/github-tokens.ts
+++ b/apps/open-swe/src/utils/github-tokens.ts
@@ -3,7 +3,7 @@ import {
GITHUB_INSTALLATION_TOKEN_COOKIE,
} from "@open-swe/shared/constants";
import { GraphConfig } from "@open-swe/shared/open-swe/types";
-import { decryptGitHubToken } from "@open-swe/shared/crypto";
+import { decryptSecret } from "@open-swe/shared/crypto";
export function getGitHubTokensFromConfig(config: GraphConfig): {
githubAccessToken: string;
@@ -22,18 +22,16 @@ export function getGitHubTokensFromConfig(config: GraphConfig): {
}
// Get the encryption key from environment variables
- const encryptionKey = process.env.GITHUB_TOKEN_ENCRYPTION_KEY;
+ const encryptionKey = process.env.SECRETS_ENCRYPTION_KEY;
if (!encryptionKey) {
- throw new Error(
- "Missing GITHUB_TOKEN_ENCRYPTION_KEY environment variable.",
- );
+ throw new Error("Missing SECRETS_ENCRYPTION_KEY environment variable.");
}
// Decrypt the GitHub token
const githubAccessToken = encryptedGitHubToken
- ? decryptGitHubToken(encryptedGitHubToken, encryptionKey)
+ ? decryptSecret(encryptedGitHubToken, encryptionKey)
: "";
- const githubInstallationToken = decryptGitHubToken(
+ const githubInstallationToken = decryptSecret(
encryptedInstallationToken,
encryptionKey,
);
diff --git a/apps/web/.env.example b/apps/web/.env.example
index f5f0f091..4628f665 100644
--- a/apps/web/.env.example
+++ b/apps/web/.env.example
@@ -7,10 +7,6 @@ GITHUB_APP_CLIENT_SECRET=""
# your GitHub app settings.
GITHUB_APP_REDIRECT_URI="http://localhost:3000/api/auth/github/callback"
-# Encryption key for GitHub tokens (32-byte hex string for AES-256)
-# Should be the same value as the one used in the web app, so that tokens
-# encrypted in the web app can be decrypted in the agent.
-GITHUB_TOKEN_ENCRYPTION_KEY=""
# Used for setting the git user name & email for commits.
# Can modify to whatever string you want.
GITHUB_APP_NAME="open-swe-dev"
@@ -29,3 +25,7 @@ NEXT_PUBLIC_API_URL="http://localhost:3000/api"
# The API URL of the LangGraph server. Used in the proxy route to forward
# requests to the LangGraph server.
LANGGRAPH_API_URL="http://localhost:2024"
+# Encryption key for secrets (32-byte hex string for AES-256)
+# Should be the same value as the one used in the web app, so that secrets
+# encrypted in the web app can be decrypted in the agent.
+SECRETS_ENCRYPTION_KEY=""
diff --git a/apps/web/src/app/api/[..._path]/route.ts b/apps/web/src/app/api/[..._path]/route.ts
index fb1d7fb1..d22e3bee 100644
--- a/apps/web/src/app/api/[..._path]/route.ts
+++ b/apps/web/src/app/api/[..._path]/route.ts
@@ -5,150 +5,11 @@ import {
GITHUB_INSTALLATION_TOKEN_COOKIE,
GITHUB_INSTALLATION_NAME,
} from "@open-swe/shared/constants";
-import { encryptGitHubToken } from "@open-swe/shared/crypto";
-import { NextRequest } from "next/server";
-import { getInstallationToken } from "@/utils/github";
-import { App } from "@octokit/app";
-import { validate } from "uuid";
-
-function getGitHubAccessTokenOrThrow(
- req: NextRequest,
- encryptionKey: string,
-): string {
- const token = req.cookies.get(GITHUB_TOKEN_COOKIE)?.value ?? "";
-
- if (!token) {
- throw new Error(
- "No GitHub access token found. User must authenticate first.",
- );
- }
-
- return encryptGitHubToken(token, encryptionKey);
-}
-
-async function getGitHubInstallationTokenOrThrow(
- installationIdCookie: string,
- encryptionKey: string,
-): Promise {
- const appId = process.env.GITHUB_APP_ID;
- const privateAppKey = process.env.GITHUB_APP_PRIVATE_KEY;
-
- if (!appId || !privateAppKey) {
- throw new Error("GitHub App ID or Private App Key is not configured.");
- }
-
- const token = await getInstallationToken(
- installationIdCookie,
- appId,
- privateAppKey,
- );
- return encryptGitHubToken(token, encryptionKey);
-}
-
-async function getInstallationName(installationId: string) {
- if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_APP_PRIVATE_KEY) {
- throw new Error("GitHub App ID or Private App Key is not configured.");
- }
- const app = new App({
- appId: process.env.GITHUB_APP_ID,
- privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
- });
-
- // Get installation details
- const { data } = await app.octokit.request(
- "GET /app/installations/{installation_id}",
- {
- installation_id: Number(installationId),
- },
- );
-
- const installationName =
- data.account && "name" in data.account
- ? data.account.name
- : data.account?.login;
-
- return installationName ?? "";
-}
-
-const isNewRunRequest = (reqUrlStr: string, reqMethod: string) => {
- try {
- const reqPathnameParts = new URL(reqUrlStr).pathname.split("/");
- const isCreateNewRunReq =
- reqPathnameParts?.[1] === "api" &&
- reqPathnameParts?.[2] === "threads" &&
- validate(reqPathnameParts?.[3]) &&
- reqPathnameParts?.[4] === "runs" &&
- reqMethod.toLowerCase() === "post";
- const isStreamRunReq =
- reqPathnameParts?.[1] === "api" &&
- reqPathnameParts?.[2] === "threads" &&
- validate(reqPathnameParts?.[3]) &&
- reqPathnameParts?.[4] === "runs" &&
- validate(reqPathnameParts?.[5]) &&
- reqPathnameParts?.[6]?.startsWith("stream") &&
- reqMethod.toLowerCase() === "get";
- return isCreateNewRunReq || isStreamRunReq;
- } catch {
- return false;
- }
-};
-
-const isGetStateRequest = (reqUrlStr: string, reqMethod: string) => {
- try {
- const reqPathnameParts = new URL(reqUrlStr).pathname.split("/");
- const isGetStateReq =
- reqPathnameParts?.[1] === "api" &&
- reqPathnameParts?.[2] === "threads" &&
- validate(reqPathnameParts?.[3]) &&
- reqPathnameParts?.[4] === "state" &&
- reqMethod.toLowerCase() === "get";
- return isGetStateReq;
- } catch {
- return false;
- }
-};
-
-const isSearchThreadsRequest = (reqUrlStr: string, reqMethod: string) => {
- try {
- const reqPathnameParts = new URL(reqUrlStr).pathname.split("/");
- const isGetStateReq =
- reqPathnameParts?.[1] === "api" &&
- reqPathnameParts?.[2] === "threads" &&
- reqPathnameParts?.[3] === "search" &&
- reqMethod.toLowerCase() === "post";
- return isGetStateReq;
- } catch {
- return false;
- }
-};
-
-async function getInstallationNameFromReq(
- req: Request,
- installationId: string,
-): Promise {
- try {
- const requestJson = await req.json();
- const installationName = requestJson?.input?.targetRepository?.owner;
- if (installationName) {
- return installationName;
- }
- } catch {
- // no-op
- }
-
- try {
- if (
- isNewRunRequest(req.url, req.method) ||
- isGetStateRequest(req.url, req.method) ||
- isSearchThreadsRequest(req.url, req.method)
- ) {
- return await getInstallationName(installationId);
- }
- return "";
- } catch {
- return "";
- }
-}
+import {
+ getGitHubInstallationTokenOrThrow,
+ getInstallationNameFromReq,
+ getGitHubAccessTokenOrThrow,
+} from "./utils";
// This file acts as a proxy for requests to your LangGraph server.
// Read the [Going to Production](https://github.com/langchain-ai/agent-chat-ui?tab=readme-ov-file#going-to-production) section for more information.
@@ -159,10 +20,10 @@ export const { GET, POST, PUT, PATCH, DELETE, OPTIONS, runtime } =
runtime: "edge", // default
disableWarningLog: true,
headers: async (req) => {
- const encryptionKey = process.env.GITHUB_TOKEN_ENCRYPTION_KEY;
+ const encryptionKey = process.env.SECRETS_ENCRYPTION_KEY;
if (!encryptionKey) {
throw new Error(
- "GITHUB_TOKEN_ENCRYPTION_KEY environment variable is required",
+ "SECRETS_ENCRYPTION_KEY environment variable is required",
);
}
const installationIdCookie = req.cookies.get(
diff --git a/apps/web/src/app/api/[..._path]/utils.ts b/apps/web/src/app/api/[..._path]/utils.ts
new file mode 100644
index 00000000..c14d2ce1
--- /dev/null
+++ b/apps/web/src/app/api/[..._path]/utils.ts
@@ -0,0 +1,145 @@
+import { getInstallationToken } from "@/utils/github";
+import { App } from "@octokit/app";
+import { GITHUB_TOKEN_COOKIE } from "@open-swe/shared/constants";
+import { encryptSecret } from "@open-swe/shared/crypto";
+import { NextRequest } from "next/server";
+import { validate } from "uuid";
+
+export function getGitHubAccessTokenOrThrow(
+ req: NextRequest,
+ encryptionKey: string,
+): string {
+ const token = req.cookies.get(GITHUB_TOKEN_COOKIE)?.value ?? "";
+
+ if (!token) {
+ throw new Error(
+ "No GitHub access token found. User must authenticate first.",
+ );
+ }
+
+ return encryptSecret(token, encryptionKey);
+}
+
+export async function getGitHubInstallationTokenOrThrow(
+ installationIdCookie: string,
+ encryptionKey: string,
+): Promise {
+ const appId = process.env.GITHUB_APP_ID;
+ const privateAppKey = process.env.GITHUB_APP_PRIVATE_KEY;
+
+ if (!appId || !privateAppKey) {
+ throw new Error("GitHub App ID or Private App Key is not configured.");
+ }
+
+ const token = await getInstallationToken(
+ installationIdCookie,
+ appId,
+ privateAppKey,
+ );
+ return encryptSecret(token, encryptionKey);
+}
+
+async function getInstallationName(installationId: string) {
+ if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_APP_PRIVATE_KEY) {
+ throw new Error("GitHub App ID or Private App Key is not configured.");
+ }
+ const app = new App({
+ appId: process.env.GITHUB_APP_ID,
+ privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
+ });
+
+ // Get installation details
+ const { data } = await app.octokit.request(
+ "GET /app/installations/{installation_id}",
+ {
+ installation_id: Number(installationId),
+ },
+ );
+
+ const installationName =
+ data.account && "name" in data.account
+ ? data.account.name
+ : data.account?.login;
+
+ return installationName ?? "";
+}
+
+function isNewRunRequest(reqUrlStr: string, reqMethod: string) {
+ try {
+ const reqPathnameParts = new URL(reqUrlStr).pathname.split("/");
+ const isCreateNewRunReq =
+ reqPathnameParts?.[1] === "api" &&
+ reqPathnameParts?.[2] === "threads" &&
+ validate(reqPathnameParts?.[3]) &&
+ reqPathnameParts?.[4] === "runs" &&
+ reqMethod.toLowerCase() === "post";
+ const isStreamRunReq =
+ reqPathnameParts?.[1] === "api" &&
+ reqPathnameParts?.[2] === "threads" &&
+ validate(reqPathnameParts?.[3]) &&
+ reqPathnameParts?.[4] === "runs" &&
+ validate(reqPathnameParts?.[5]) &&
+ reqPathnameParts?.[6]?.startsWith("stream") &&
+ reqMethod.toLowerCase() === "get";
+ return isCreateNewRunReq || isStreamRunReq;
+ } catch {
+ return false;
+ }
+}
+
+function isGetStateRequest(reqUrlStr: string, reqMethod: string) {
+ try {
+ const reqPathnameParts = new URL(reqUrlStr).pathname.split("/");
+ const isGetStateReq =
+ reqPathnameParts?.[1] === "api" &&
+ reqPathnameParts?.[2] === "threads" &&
+ validate(reqPathnameParts?.[3]) &&
+ reqPathnameParts?.[4] === "state" &&
+ reqMethod.toLowerCase() === "get";
+ return isGetStateReq;
+ } catch {
+ return false;
+ }
+}
+
+function isSearchThreadsRequest(reqUrlStr: string, reqMethod: string) {
+ try {
+ const reqPathnameParts = new URL(reqUrlStr).pathname.split("/");
+ const isGetStateReq =
+ reqPathnameParts?.[1] === "api" &&
+ reqPathnameParts?.[2] === "threads" &&
+ reqPathnameParts?.[3] === "search" &&
+ reqMethod.toLowerCase() === "post";
+ return isGetStateReq;
+ } catch {
+ return false;
+ }
+}
+
+export async function getInstallationNameFromReq(
+ req: Request,
+ installationId: string,
+): Promise {
+ try {
+ const requestJson = await req.json();
+ const installationName = requestJson?.input?.targetRepository?.owner;
+ if (installationName) {
+ return installationName;
+ }
+ } catch {
+ // no-op
+ }
+
+ try {
+ if (
+ isNewRunRequest(req.url, req.method) ||
+ isGetStateRequest(req.url, req.method) ||
+ isSearchThreadsRequest(req.url, req.method)
+ ) {
+ return await getInstallationName(installationId);
+ }
+ return "";
+ } catch {
+ return "";
+ }
+}
diff --git a/packages/shared/src/crypto.ts b/packages/shared/src/crypto.ts
index e3cc44af..b28f2718 100644
--- a/packages/shared/src/crypto.ts
+++ b/packages/shared/src/crypto.ts
@@ -20,19 +20,16 @@ function deriveKey(encryptionKey: string): Buffer {
}
/**
- * Encrypts a GitHub token using AES-256-GCM
+ * Encrypts a secret using AES-256-GCM
*
- * @param token - The GitHub access token to encrypt
+ * @param secret - The secret to encrypt
* @param encryptionKey - The encryption key (will be hashed to 256 bits)
* @returns Base64 encoded encrypted data containing IV, encrypted token, and auth tag
* @throws Error if encryption fails or inputs are invalid
*/
-export function encryptGitHubToken(
- token: string,
- encryptionKey: string,
-): string {
- if (!token || typeof token !== "string") {
- throw new Error("Token must be a non-empty string");
+export function encryptSecret(secret: string, encryptionKey: string): string {
+ if (!secret || typeof secret !== "string") {
+ throw new Error("Secret must be a non-empty string");
}
if (!encryptionKey || typeof encryptionKey !== "string") {
@@ -49,9 +46,9 @@ export function encryptGitHubToken(
// Create cipher
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
- // Encrypt the token
+ // Encrypt the secret
const encryptedBuffer = Buffer.concat([
- cipher.update(token, "utf8"),
+ cipher.update(secret, "utf8"),
cipher.final(),
]);
@@ -64,25 +61,25 @@ export function encryptGitHubToken(
return combined.toString("base64");
} catch (error) {
throw new Error(
- `Failed to encrypt token: ${error instanceof Error ? error.message : "Unknown error"}`,
+ `Failed to encrypt secret: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
}
/**
- * Decrypts a GitHub token using AES-256-GCM
+ * Decrypts a secret using AES-256-GCM
*
- * @param encryptedToken - Base64 encoded encrypted data from encryptGitHubToken
+ * @param encryptedSecret - Base64 encoded encrypted data from encryptSecret
* @param encryptionKey - The encryption key used for encryption
- * @returns The decrypted GitHub access token
+ * @returns The decrypted secret
* @throws Error if decryption fails or inputs are invalid
*/
-export function decryptGitHubToken(
- encryptedToken: string,
+export function decryptSecret(
+ encryptedSecret: string,
encryptionKey: string,
): string {
- if (!encryptedToken || typeof encryptedToken !== "string") {
- throw new Error("Encrypted token must be a non-empty string");
+ if (!encryptedSecret || typeof encryptedSecret !== "string") {
+ throw new Error("Encrypted secret must be a non-empty string");
}
if (!encryptionKey || typeof encryptionKey !== "string") {
@@ -91,11 +88,13 @@ export function decryptGitHubToken(
try {
// Decode the combined data
- const combined = Buffer.from(encryptedToken, "base64");
+ const combined = Buffer.from(encryptedSecret, "base64");
// Minimum length: IV_LENGTH + TAG_LENGTH + 1 byte for data
if (combined.length < IV_LENGTH + TAG_LENGTH + 1) {
- throw new Error("Invalid encrypted token format: too short or malformed");
+ throw new Error(
+ "Invalid encrypted secret format: too short or malformed",
+ );
}
// Extract IV, encrypted data, and tag
@@ -126,7 +125,7 @@ export function decryptGitHubToken(
return decryptedBuffer.toString("utf8");
} catch (error) {
throw new Error(
- `Failed to decrypt token: ${error instanceof Error ? error.message : "Unknown error"}`,
+ `Failed to decrypt secret: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
}