diff --git a/src/App.tsx b/src/App.tsx
index ddae05d..f2578fd 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -86,6 +86,7 @@ const router = createBrowserRouter([
},
{
path: "/reports",
+ loader: getServerSettings,
element: ,
},
{
diff --git a/src/apis/helpers/decrypt-report.ts b/src/apis/helpers/decrypt-report.ts
index e77eee9..dfcc0bb 100644
--- a/src/apis/helpers/decrypt-report.ts
+++ b/src/apis/helpers/decrypt-report.ts
@@ -3,13 +3,17 @@ import update from "immutability-helper"
import {DecryptedReportContent} from "~/server-types"
import {AuthContextType} from "~/components"
+import {extractCleartextFromSignedMessage} from "~/utils"
export default async function decryptReport(
- encryptedContent: string,
+ signedMessage: string,
decryptContent: AuthContextType["_decryptUsingPrivateKey"],
+ publicKeyInPEM: string,
): Promise {
+ const encryptedMessage = await extractCleartextFromSignedMessage(signedMessage, publicKeyInPEM)
+
return update(
- camelcaseKeys(JSON.parse(await decryptContent(encryptedContent)), {
+ camelcaseKeys(JSON.parse(await decryptContent(encryptedMessage)), {
deep: true,
}),
{
diff --git a/src/components/widgets/DecryptReport.tsx b/src/components/widgets/DecryptReport.tsx
index 8ccb400..4f58625 100644
--- a/src/components/widgets/DecryptReport.tsx
+++ b/src/components/widgets/DecryptReport.tsx
@@ -1,10 +1,11 @@
import {ReactElement, useContext} from "react"
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 {AuthContext} from "../AuthContext"
+import {useLoaderData} from "react-router-dom"
interface DecryptReportPropsBase {
encryptedContent?: string
@@ -30,11 +31,12 @@ export default function DecryptReport({
reports,
children: render,
}: DecryptReportProps): ReactElement {
+ const serverSettings = useLoaderData() as ServerSettings
const {_decryptUsingPrivateKey} = useContext(AuthContext)
const {value} = useAsync(async () => {
const decrypt = async (content: string): Promise =>
- decryptReport(content, _decryptUsingPrivateKey)
+ decryptReport(content, _decryptUsingPrivateKey, serverSettings.publicKey)
if (encryptedContent) {
return decrypt(encryptedContent)
diff --git a/src/server-types.ts b/src/server-types.ts
index ef3ee5e..2d522e1 100644
--- a/src/server-types.ts
+++ b/src/server-types.ts
@@ -81,6 +81,7 @@ export interface ServerSettings {
emailLoginExpirationInSeconds: number
customAliasSuffixLength: number
instanceSalt: string
+ publicKey: string
}
export interface Alias {
diff --git a/src/utils/crypto/extract-cleartext-from-signed-message.ts b/src/utils/crypto/extract-cleartext-from-signed-message.ts
new file mode 100644
index 0000000..6ecf725
--- /dev/null
+++ b/src/utils/crypto/extract-cleartext-from-signed-message.ts
@@ -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 {
+ 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()
+}
diff --git a/src/utils/crypto/index.ts b/src/utils/crypto/index.ts
index b945c22..066a3dd 100644
--- a/src/utils/crypto/index.ts
+++ b/src/utils/crypto/index.ts
@@ -10,3 +10,5 @@ export * from "./get-master-password"
export {default as getMasterPassword} from "./get-master-password"
export * 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"