Added utils for cryptography and filesystem interactions
This commit is contained in:
parent
002fd58585
commit
932b770c8f
@ -1,3 +1,5 @@
|
||||
export const PKG = __PKG__
|
||||
export const DB_PATH = "src/db/db.sqlite"
|
||||
// TODO: Add jose keys
|
||||
export const SERVER_PRIVATE_DIR = "src/private"
|
||||
export const SERVER_PRIVATE_KEY_PATH = `${SERVER_PRIVATE_DIR}/key.pem`
|
||||
export const SERVER_PUBLIC_KEY_PATH = `${SERVER_PRIVATE_DIR}/pub.pem`
|
||||
29
src/lib/utils/filesystem-utils.ts
Normal file
29
src/lib/utils/filesystem-utils.ts
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
export async function doesFileExists(path: string) {
|
||||
|
||||
const file = Bun.file(path)
|
||||
return file.exists()
|
||||
|
||||
}
|
||||
|
||||
export async function loadFile(path: string, create?: boolean): Promise<Bun.BunFile> {
|
||||
|
||||
if (!create) {
|
||||
create = false
|
||||
}
|
||||
|
||||
|
||||
if (await doesFileExists(path)) {
|
||||
return Bun.file(path)
|
||||
}
|
||||
|
||||
if (create) {
|
||||
const file = Bun.file(path)
|
||||
file.write("")
|
||||
return file
|
||||
}
|
||||
|
||||
|
||||
// UGLY: make more specific
|
||||
throw new Error("The required file does not exist")
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
import * as jose from "jose";
|
||||
import { loadFile } from "./filesystem-utils";
|
||||
import { SERVER_PRIVATE_KEY_PATH, SERVER_PUBLIC_KEY_PATH } from "./constants";
|
||||
|
||||
|
||||
export class JoseSingleton {
|
||||
|
||||
private static initialized = false
|
||||
|
||||
private static privateKey: CryptoKey
|
||||
private static publicKey: CryptoKey
|
||||
|
||||
public static async init() {
|
||||
|
||||
JoseSingleton.assureNotInitialized()
|
||||
|
||||
JoseSingleton.privateKey = await JoseSingleton.loadPrivateKey()
|
||||
JoseSingleton.publicKey = await JoseSingleton.loadPublicKey()
|
||||
|
||||
}
|
||||
|
||||
private static async loadPrivateKey() {
|
||||
|
||||
JoseSingleton.assureNotInitialized()
|
||||
|
||||
const privateKeyFile = await loadFile(SERVER_PRIVATE_KEY_PATH)
|
||||
return await jose.importPKCS8(
|
||||
await privateKeyFile.text(),
|
||||
"ES512"
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private static async loadPublicKey() {
|
||||
|
||||
JoseSingleton.assureNotInitialized()
|
||||
|
||||
const publicKeyFile = await loadFile(SERVER_PUBLIC_KEY_PATH)
|
||||
return await jose.importPKCS8(
|
||||
await publicKeyFile.text(),
|
||||
"ES512"
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
public static async signObject(object: any) {
|
||||
|
||||
JoseSingleton.assureInitialized()
|
||||
|
||||
const payload = new TextEncoder().encode(
|
||||
JSON.stringify(object)
|
||||
)
|
||||
|
||||
return await new jose.CompactSign(
|
||||
payload
|
||||
).setProtectedHeader({
|
||||
alg: "ES512"
|
||||
}).sign(JoseSingleton.privateKey)
|
||||
|
||||
}
|
||||
|
||||
public static async verifyObject(jwt: string) {
|
||||
|
||||
JoseSingleton.assureInitialized()
|
||||
|
||||
let _payload: Uint8Array
|
||||
|
||||
try {
|
||||
const { payload, protectedHeader } = await jose.compactVerify(
|
||||
jwt,
|
||||
JoseSingleton.publicKey
|
||||
)
|
||||
_payload = payload
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
|
||||
return JSON.parse(
|
||||
new TextDecoder().decode(_payload)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private static assureInitialized() {
|
||||
|
||||
if (!JoseSingleton.initialized) {
|
||||
// UGLY: Be specific
|
||||
throw new Error("JoseSingleton hasn't been initialized")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static assureNotInitialized() {
|
||||
|
||||
if (JoseSingleton.initialized) {
|
||||
// UGLY: Be specific
|
||||
throw new Error("JoseSingleton has already been initialized")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
49
src/lib/utils/openssl-utils.ts
Normal file
49
src/lib/utils/openssl-utils.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { $ } from "bun";
|
||||
import { doesFileExists, loadFile } from "./filesystem-utils";
|
||||
import { SERVER_PRIVATE_KEY_PATH, SERVER_PUBLIC_KEY_PATH } from "./constants";
|
||||
|
||||
export async function openSSLInit() {
|
||||
|
||||
await openSSLCreatePrivateKey()
|
||||
await openSSLCreatePublicKey()
|
||||
|
||||
}
|
||||
|
||||
export async function openSSLCreatePrivateKey() {
|
||||
|
||||
// UGLY: may be refactored to output only the private key
|
||||
|
||||
const outputPromise = $`openssl ecparam -genkey -name secp521r1 -noout`.text()
|
||||
const filePromise = loadFile(SERVER_PRIVATE_KEY_PATH, true)
|
||||
|
||||
const [output, file] = await Promise.all([
|
||||
outputPromise,
|
||||
filePromise
|
||||
])
|
||||
|
||||
await file.write(output)
|
||||
|
||||
}
|
||||
|
||||
|
||||
export async function openSSLCreatePublicKey() {
|
||||
|
||||
// UGLY: may be refactored to output only the private key
|
||||
if (! await doesFileExists(SERVER_PRIVATE_KEY_PATH)) {
|
||||
// UGLY: make more specific
|
||||
throw new Error("You must generate the private key before attempting to generate the public one")
|
||||
}
|
||||
|
||||
const outputPromise = $`openssl ec -in ${SERVER_PRIVATE_KEY_PATH} -pubout `.text()
|
||||
const filePromise = loadFile(SERVER_PUBLIC_KEY_PATH, true)
|
||||
|
||||
const [output, file] = await Promise.all([
|
||||
outputPromise,
|
||||
filePromise
|
||||
])
|
||||
|
||||
await file.write(output)
|
||||
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user