astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
78 lines (77 loc) • 2.06 kB
JavaScript
import { decodeBase64, decodeHex, encodeBase64, encodeHexUpperCase } from "@oslojs/encoding";
const ALGORITHM = "AES-GCM";
async function createKey() {
const key = await crypto.subtle.generateKey(
{
name: ALGORITHM,
length: 256
},
true,
["encrypt", "decrypt"]
);
return key;
}
const ENVIRONMENT_KEY_NAME = "ASTRO_KEY";
function getEncodedEnvironmentKey() {
return process.env[ENVIRONMENT_KEY_NAME] || "";
}
function hasEnvironmentKey() {
return getEncodedEnvironmentKey() !== "";
}
async function getEnvironmentKey() {
if (!hasEnvironmentKey()) {
throw new Error(
`There is no environment key defined. If you see this error there is a bug in Astro.`
);
}
const encodedKey = getEncodedEnvironmentKey();
return decodeKey(encodedKey);
}
async function encodeKey(key) {
const exported = await crypto.subtle.exportKey("raw", key);
const encodedKey = encodeBase64(new Uint8Array(exported));
return encodedKey;
}
async function decodeKey(encoded) {
const bytes = decodeBase64(encoded);
return crypto.subtle.importKey("raw", bytes, ALGORITHM, true, ["encrypt", "decrypt"]);
}
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const IV_LENGTH = 24;
async function encryptString(key, raw) {
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH / 2));
const data = encoder.encode(raw);
const buffer = await crypto.subtle.encrypt(
{
name: ALGORITHM,
iv
},
key,
data
);
return encodeHexUpperCase(iv) + encodeBase64(new Uint8Array(buffer));
}
async function decryptString(key, encoded) {
const iv = decodeHex(encoded.slice(0, IV_LENGTH));
const dataArray = decodeBase64(encoded.slice(IV_LENGTH));
const decryptedBuffer = await crypto.subtle.decrypt(
{
name: ALGORITHM,
iv
},
key,
dataArray
);
const decryptedString = decoder.decode(decryptedBuffer);
return decryptedString;
}
export {
createKey,
decodeKey,
decryptString,
encodeKey,
encryptString,
getEnvironmentKey,
hasEnvironmentKey
};