mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-19 07:55:25 +02:00
added server signing validation
This commit is contained in:
parent
84f6d6479d
commit
2621693f58
@ -86,6 +86,7 @@ const router = createBrowserRouter([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/reports",
|
path: "/reports",
|
||||||
|
loader: getServerSettings,
|
||||||
element: <ReportsRoute />,
|
element: <ReportsRoute />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -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,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
26
src/utils/crypto/extract-cleartext-from-signed-message.ts
Normal file
26
src/utils/crypto/extract-cleartext-from-signed-message.ts
Normal 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()
|
||||||
|
}
|
@ -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"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user