Skip to content

Instantly share code, notes, and snippets.

@ezzabuzaid
Last active December 12, 2024 12:21
Show Gist options
  • Save ezzabuzaid/069d29b16ff46e5adc89eb5d5ba0452a to your computer and use it in GitHub Desktop.
Save ezzabuzaid/069d29b16ff46e5adc89eb5d5ba0452a to your computer and use it in GitHub Desktop.
Secrets Managment
export async function generateKey() {
const sodium = await import('libsodium-wrappers').then(
({ default: sodium }) => sodium.ready.then(() => sodium)
);
return sodium.crypto_secretbox_keygen();
}
export async function encrypt(key: ArrayBuffer, plain: string) {
const sodium = await import('libsodium-wrappers').then(
({ default: sodium }) => sodium.ready.then(() => sodium)
);
const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
const secret = sodium.crypto_secretbox_easy(
plain,
nonce,
new Uint8Array(key)
);
return {
secret,
nonce,
};
}
export async function decrypt(
secret: Uint8Array,
nonce: Uint8Array,
key: Uint8Array
) {
const sodium = await import('libsodium-wrappers').then(
({ default: sodium }) => sodium.ready.then(() => sodium)
);
return sodium.to_string(
sodium.crypto_secretbox_open_easy(secret, nonce, key)
);
}
import { decrypt, encrypt, generateKey } from '@january/modern';
import { turso } from './turso';
export async function getProjectKey(projectId: string) {
const { rows } = await turso.execute({
sql: 'select key from serverize_keys where projectId = ?',
args: [projectId],
});
if (rows.length === 0) {
await turso.execute({
sql: 'insert into serverize_keys (projectId, key) values (?, ?)',
args: [projectId, await generateKey()],
});
return getProjectKey(projectId);
}
return rows[0].key as ArrayBuffer;
}
export async function saveSecret(
projectId: string,
secretLabel: string,
secretValue: string
) {
const key = await getProjectKey(projectId);
const { nonce, secret } = await encrypt(key as ArrayBuffer, secretValue);
await turso.execute({
sql: 'insert into serverize_secrets (projectId, label, nonce, secret) values (?, ?, ?, ?) on conflict (projectId, label) do update set nonce = excluded.nonce, secret = excluded.secret',
args: [projectId, secretLabel, nonce, secret],
});
}
export async function getSecrets(projectId: string) {
return await turso
.execute({
sql: 'select label from serverize_secrets where projectId = ?',
args: [projectId],
})
.then(({ rows }) => rows);
}
export async function getSecretsValues(projectId: string) {
const projectKey = await getProjectKey(projectId);
const secrets = await turso.execute({
sql: 'SELECT * FROM serverize_secrets WHERE projectId = ?',
args: [projectId],
});
const env: Record<string, string> = {};
for (const secret of secrets.rows) {
const decrypted = await decrypt(
new Uint8Array(secret.secret as ArrayBuffer),
new Uint8Array(secret.nonce as ArrayBuffer),
new Uint8Array(projectKey as ArrayBuffer)
);
env[secret.label as string] = decrypted;
}
return env;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment