AirGappedSubmission: Include working Submission link

This commit is contained in:
David Ernst
2024-07-05 00:05:43 +03:00
parent e8143179c3
commit e2ae76de47
2 changed files with 58 additions and 6 deletions

View File

@@ -9,7 +9,10 @@ import { validateAuthToken } from './check-auth-token'
import { pusher } from './pusher'
export default async (req: NextApiRequest, res: NextApiResponse) => {
const { auth, election_id, encrypted_vote } = req.body
const payload = req.method === 'POST' ? req.body : req.query
const { auth, election_id, encrypted_vote } = payload
// return res.status(200).json({ auth, election_id, encrypted_vote })
const electionDoc = firebase.firestore().collection('elections').doc(election_id)

View File

@@ -1,3 +1,4 @@
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { DetailedEncryptionReceipt } from './submitted/DetailedEncryptionReceipt'
@@ -13,7 +14,9 @@ export const AirGappedSubmission = ({
state: State
}) => {
const [isOffline, setIsOffline] = useState(false)
const path = useRouter().asPath
// Show when going offline
useEffect(() => {
const setOnline = () => setIsOffline(false)
const setOffline = () => setIsOffline(true)
@@ -27,7 +30,12 @@ export const AirGappedSubmission = ({
}
}, [])
if (!isOffline) return null
// Or include "offline" in path (e.g /vote?auth=foo&offline) to show even if online
if (!(isOffline || path.includes('offline'))) return null
const submission_url = `/api/submit-vote?auth=${auth}&election_id=${election_id}&encrypted_vote=${JSON.stringify(
sortedKeys(state.encrypted),
)}`
return (
<div className="px-3 py-2 mt-3 rounded-lg shadow-lg bg-yellow-200/50">
@@ -37,18 +45,18 @@ export const AirGappedSubmission = ({
You can submit your vote via an air-gapped submission. If you do this from a Private Incognito window, it
ensures even this webapp cannot possibly extract your private vote selections.
</div>
<h4>When you{"'"}re done making your vote selections...</h4>
<h4>1. When you{"'"}re done making your vote selections...</h4>
<div>
1. Copy and Paste the following <i>Detailed Encryption Receipt</i> somewhere safe for your own private records:
Copy and Paste the following <i>Detailed Encryption Receipt</i> somewhere safe for your own private records:
<div className="mt-2 bg-gray-100">
<DetailedEncryptionReceipt {...{ auth, election_id, state }} />
</div>
</div>
<div>
<h4 className="mt-6 mb-3">Verifying your Vote</h4>
2. The easiest way to quickly verify your vote was counted correctly is your <i>Verification #</i>.
<h4 className="mt-16 mb-3">2. Verifying your Vote</h4>
The easiest way to quickly verify your vote was counted correctly is your <i>Verification #</i>.
<div className="mb-3 opacity-60">
This unique secret number is generated randomly on your own device. No one else can know it.
</div>
@@ -64,6 +72,47 @@ export const AirGappedSubmission = ({
for quicker access.
</div>
</div>
<div>
<h4 className="mt-16 mb-3">3. Submitting your Vote</h4>
Lastly, now that your private verification information is backed up, you are ready to submit your encrypted
vote.
<div className="mt-2 opacity-50">Your full encrypted vote is:</div>
<div className="px-2 py-1 mb-3 overflow-x-scroll text-xs whitespace-pre bg-gray-100 rounded shadow-lg">
{JSON.stringify(sortedKeys(state.encrypted), null, 2)}
</div>
<div>
You can submit this encrypted payload by visiting this <i className="font-semibold">Submission URL</i>, once
you turn your internet back on:
</div>
<div>
<a className="text-xs break-all" href={submission_url} rel="noreferrer" target="_blank">
{window.location.origin}
{submission_url}
</a>
</div>
<hr className="my-5 opacity-30" />
<div className="my-2">
Once you{"'"}ve copied down your private data and Submission URL, you can close this window, turn your
internet back on, and visit your submission URL.
</div>
</div>
</div>
)
}
function sortedKeys(obj: unknown): string {
const sortedObj = JSON.parse(
JSON.stringify(obj, (key, value) =>
value instanceof Object && !(value instanceof Array)
? Object.keys(value)
.sort()
.reduce((sorted, key) => {
sorted[key] = value[key]
return sorted
}, {} as Record<string, unknown>)
: value,
),
)
return sortedObj
}