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 PKG = __PKG__
|
||||||
export const DB_PATH = "src/db/db.sqlite"
|
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