104 lines
2.3 KiB
TypeScript
104 lines
2.3 KiB
TypeScript
import { generateId } from "@/utils/genUtils.js";
|
|
import { ApiKey, AppEnv } from "@autumn/shared";
|
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
import crypto from "crypto";
|
|
import { ApiKeyService, CachedKeyService } from "../ApiKeyService.js";
|
|
import { CacheType } from "@/external/caching/cacheActions.js";
|
|
import { getAPIKeyCache } from "@/external/caching/cacheUtils.js";
|
|
import { DrizzleCli } from "@/db/initDrizzle.js";
|
|
|
|
function generateApiKey(length = 32, prefix = "") {
|
|
try {
|
|
// Define allowed characters (alphanumeric only)
|
|
const allowedChars =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
const array = new Uint8Array(length);
|
|
crypto.getRandomValues(array);
|
|
|
|
// Convert random bytes to alphanumeric string
|
|
const key = Array.from(array)
|
|
.map((byte) => allowedChars[byte % allowedChars.length])
|
|
.join("");
|
|
|
|
return prefix ? `${prefix}_${key}` : key;
|
|
} catch (error) {
|
|
console.error("Failed to generate API key:", error);
|
|
throw new Error("Failed to generate secure API key");
|
|
}
|
|
}
|
|
|
|
export const hashApiKey = (apiKey: string) => {
|
|
return crypto.createHash("sha256").update(apiKey).digest("hex");
|
|
};
|
|
|
|
export const createKey = async ({
|
|
db,
|
|
env,
|
|
name,
|
|
orgId,
|
|
prefix,
|
|
meta,
|
|
}: {
|
|
db: DrizzleCli;
|
|
env: AppEnv;
|
|
name: string;
|
|
orgId: string;
|
|
prefix: string;
|
|
meta: any;
|
|
}) => {
|
|
const apiKey = generateApiKey(42, prefix);
|
|
const hashedKey = hashApiKey(apiKey);
|
|
|
|
const apiKeyData: ApiKey = {
|
|
id: generateId("key"),
|
|
org_id: orgId,
|
|
user_id: "",
|
|
name,
|
|
prefix: apiKey.substring(0, 14),
|
|
created_at: Date.now(),
|
|
env,
|
|
hashed_key: hashedKey,
|
|
meta,
|
|
};
|
|
|
|
await ApiKeyService.insert({ db, apiKey: apiKeyData });
|
|
|
|
return apiKey;
|
|
};
|
|
|
|
export const verifyKey = async ({
|
|
db,
|
|
key,
|
|
}: {
|
|
db: DrizzleCli;
|
|
key: string;
|
|
}) => {
|
|
const hashedKey = hashApiKey(key);
|
|
|
|
const env = key.startsWith("am_sk_test") ? AppEnv.Sandbox : AppEnv.Live;
|
|
|
|
const data = await getAPIKeyCache({
|
|
action: CacheType.SecretKey,
|
|
key: hashedKey,
|
|
fn: async () =>
|
|
await ApiKeyService.verifyAndFetch({
|
|
db,
|
|
secretKey: key,
|
|
hashedKey,
|
|
env,
|
|
}),
|
|
});
|
|
|
|
if (!data) {
|
|
return {
|
|
valid: false,
|
|
data: null,
|
|
};
|
|
}
|
|
|
|
return {
|
|
valid: true,
|
|
data: data,
|
|
};
|
|
};
|