mirror of
https://github.com/siv-org/siv.git
synced 2026-01-09 10:27:57 -05:00
72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
import { NextApiRequest, NextApiResponse } from 'next'
|
|
|
|
import { firebase, pushover } from '../_services'
|
|
|
|
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
|
const { already_seen_device, auth_token, election_id, otp } = req.body
|
|
|
|
if (typeof election_id !== 'string') return res.status(400).json({ error: 'Missing election_id' })
|
|
if (typeof auth_token !== 'string') return res.status(400).json({ error: 'Missing auth_token' })
|
|
if (typeof otp !== 'string') return res.status(400).json({ error: 'Missing otp' })
|
|
|
|
const electionDoc = firebase.firestore().collection('elections').doc(election_id)
|
|
const checkDoc = electionDoc.collection('malware-checks').doc(auth_token)
|
|
|
|
const check = await checkDoc.get()
|
|
|
|
const malwareCheckError = malwareCheckErrorGenerator('download', election_id, auth_token, otp, res)
|
|
if (!check.exists) return malwareCheckError('No malware check found')
|
|
|
|
const data = check.data()
|
|
if (!data || !data.checks || !Array.isArray(data.checks)) return malwareCheckError('Invalid check data')
|
|
|
|
// Find matching check entry by OTP
|
|
const checkEntry = data.checks.find((entry: { otp?: string }) => entry.otp === otp)
|
|
if (!checkEntry) return malwareCheckError('Invalid OTP', 401)
|
|
|
|
// Check if already downloaded
|
|
if (checkEntry.downloaded_at) {
|
|
await pushover('Malware check: Already downloaded', `${election_id}: ${auth_token}\nOTP: ${otp}`)
|
|
return res.status(410).json({ error: 'Already downloaded. Restart from original device' })
|
|
}
|
|
|
|
// Fetch encrypted vote from database
|
|
const votes = await electionDoc.collection('votes').where('auth', '==', auth_token).get()
|
|
if (votes.empty) return res.status(404).json({ error: 'Vote not found' })
|
|
const storedVote = votes.docs[0].data()
|
|
|
|
// Update the specific check entry
|
|
const updatedChecks = data.checks.map((entry: { already_seen_device?: null | string; otp?: string }) => {
|
|
if (entry.otp === otp)
|
|
return {
|
|
...entry,
|
|
already_seen_device: already_seen_device ?? null,
|
|
downloaded_at: new Date(),
|
|
downloaded_by_ip: req.headers['x-real-ip'] || null,
|
|
downloaded_by_user_agent: req.headers['user-agent'] || null,
|
|
}
|
|
|
|
return entry
|
|
})
|
|
|
|
await checkDoc.update({ checks: updatedChecks })
|
|
|
|
return res.status(200).json({
|
|
encrypted_randomizers: checkEntry.encrypted_randomizers,
|
|
encrypted_vote: storedVote.encrypted_vote,
|
|
})
|
|
}
|
|
|
|
export function malwareCheckErrorGenerator(
|
|
type: 'confirm' | 'decrypt-success' | 'download',
|
|
election_id: string,
|
|
auth_token: string,
|
|
otp: string,
|
|
res: NextApiResponse,
|
|
) {
|
|
return async function (error: string, errorCode = 404) {
|
|
await pushover(`Malware check, ${type}: ${error}`, `${election_id}: ${auth_token}\nOTP: ${otp}`)
|
|
return res.status(errorCode).json({ error })
|
|
}
|
|
}
|