Last active
December 12, 2024 12:21
-
-
Save ezzabuzaid/069d29b16ff46e5adc89eb5d5ba0452a to your computer and use it in GitHub Desktop.
Secrets Managment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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