added server signing validation

This commit is contained in:
Myzel394 2023-01-17 18:33:29 +01:00
parent 84f6d6479d
commit 2621693f58
6 changed files with 40 additions and 4 deletions

View File

@ -86,6 +86,7 @@ const router = createBrowserRouter([
}, },
{ {
path: "/reports", path: "/reports",
loader: getServerSettings,
element: <ReportsRoute />, element: <ReportsRoute />,
}, },
{ {

View File

@ -3,13 +3,17 @@ import update from "immutability-helper"
import {DecryptedReportContent} from "~/server-types" import {DecryptedReportContent} from "~/server-types"
import {AuthContextType} from "~/components" import {AuthContextType} from "~/components"
import {extractCleartextFromSignedMessage} from "~/utils"
export default async function decryptReport( export default async function decryptReport(
encryptedContent: string, signedMessage: string,
decryptContent: AuthContextType["_decryptUsingPrivateKey"], decryptContent: AuthContextType["_decryptUsingPrivateKey"],
publicKeyInPEM: string,
): Promise<DecryptedReportContent> { ): Promise<DecryptedReportContent> {
const encryptedMessage = await extractCleartextFromSignedMessage(signedMessage, publicKeyInPEM)
return update<DecryptedReportContent>( return update<DecryptedReportContent>(
camelcaseKeys(JSON.parse(await decryptContent(encryptedContent)), { camelcaseKeys(JSON.parse(await decryptContent(encryptedMessage)), {
deep: true, deep: true,
}), }),
{ {

View File

@ -1,10 +1,11 @@
import {ReactElement, useContext} from "react" import {ReactElement, useContext} from "react"
import {useAsync} from "react-use" import {useAsync} from "react-use"
import {DecryptedReportContent, Report} from "~/server-types" import {DecryptedReportContent, Report, ServerSettings} from "~/server-types"
import decryptReport from "~/apis/helpers/decrypt-report" import decryptReport from "~/apis/helpers/decrypt-report"
import {AuthContext} from "../AuthContext" import {AuthContext} from "../AuthContext"
import {useLoaderData} from "react-router-dom"
interface DecryptReportPropsBase { interface DecryptReportPropsBase {
encryptedContent?: string encryptedContent?: string
@ -30,11 +31,12 @@ export default function DecryptReport({
reports, reports,
children: render, children: render,
}: DecryptReportProps): ReactElement { }: DecryptReportProps): ReactElement {
const serverSettings = useLoaderData() as ServerSettings
const {_decryptUsingPrivateKey} = useContext(AuthContext) const {_decryptUsingPrivateKey} = useContext(AuthContext)
const {value} = useAsync(async () => { const {value} = useAsync(async () => {
const decrypt = async (content: string): Promise<DecryptedReportContent> => const decrypt = async (content: string): Promise<DecryptedReportContent> =>
decryptReport(content, _decryptUsingPrivateKey) decryptReport(content, _decryptUsingPrivateKey, serverSettings.publicKey)
if (encryptedContent) { if (encryptedContent) {
return decrypt(encryptedContent) return decrypt(encryptedContent)

View File

@ -81,6 +81,7 @@ export interface ServerSettings {
emailLoginExpirationInSeconds: number emailLoginExpirationInSeconds: number
customAliasSuffixLength: number customAliasSuffixLength: number
instanceSalt: string instanceSalt: string
publicKey: string
} }
export interface Alias { export interface Alias {

View File

@ -0,0 +1,26 @@
import {readCleartextMessage, readKey, verify} from "openpgp"
// Extracts the message from a signed message
// Automatically verifies the signature, if it fails, an error is thrown
export default async function extractCleartextFromSignedMessage(
signedMessage: string,
publicKeyInPEM: string,
): Promise<string> {
const publicKey = await readKey({
armoredKey: publicKeyInPEM,
})
const message = await readCleartextMessage({
cleartextMessage: signedMessage,
})
const result = await verify({
// @ts-ignore: The example shows this exact usage
message: message,
verificationKeys: publicKey,
})
const {verified} = result.signatures[0]
await verified
return message.getText()
}

View File

@ -10,3 +10,5 @@ export * from "./get-master-password"
export {default as getMasterPassword} from "./get-master-password" export {default as getMasterPassword} from "./get-master-password"
export * from "./generate-keys" export * from "./generate-keys"
export {default as generateKeys} from "./generate-keys" export {default as generateKeys} from "./generate-keys"
export * from "./extract-cleartext-from-signed-message"
export {default as extractCleartextFromSignedMessage} from "./extract-cleartext-from-signed-message"