2020-02-08 19:47:21 +01:00
|
|
|
/* eslint-disable no-console */
|
2020-01-29 12:30:50 +01:00
|
|
|
const fs = require('fs').promises
|
|
|
|
const path = require('path')
|
|
|
|
const util = require('util')
|
|
|
|
const exec = util.promisify(require('child_process').exec)
|
2020-02-07 10:21:53 +01:00
|
|
|
const crypto = require('crypto')
|
2020-01-30 15:00:34 +01:00
|
|
|
const aws = require('aws-sdk')
|
2020-01-29 12:30:50 +01:00
|
|
|
const express = require('express')
|
|
|
|
const { Mutex } = require('async-mutex')
|
2020-01-29 17:59:37 +01:00
|
|
|
const multer = require('multer')
|
2020-02-29 12:22:45 +01:00
|
|
|
const blake2 = require('blake2')
|
2020-01-30 15:00:34 +01:00
|
|
|
|
|
|
|
const mutex = new Mutex()
|
|
|
|
const s3 = new aws.S3()
|
|
|
|
const router = express.Router()
|
2020-02-06 15:24:04 +01:00
|
|
|
const { Contribution } = require('../models')
|
2020-01-29 17:59:37 +01:00
|
|
|
const upload = multer({ dest: '/tmp/tornado' })
|
2020-01-29 12:30:50 +01:00
|
|
|
|
2020-02-06 15:24:04 +01:00
|
|
|
async function uploadToS3({ filename, contributionIndex }) {
|
2020-01-30 15:00:34 +01:00
|
|
|
const fileContent = await fs.readFile(`/tmp/tornado/${filename}`)
|
|
|
|
return s3
|
|
|
|
.upload({
|
|
|
|
Bucket: process.env.AWS_S3_BUCKET,
|
2020-02-06 15:24:04 +01:00
|
|
|
Key: `response_${contributionIndex}`,
|
2020-01-30 15:00:34 +01:00
|
|
|
ACL: 'public-read',
|
|
|
|
Body: fileContent
|
|
|
|
})
|
|
|
|
.promise()
|
|
|
|
}
|
2020-01-29 12:30:50 +01:00
|
|
|
|
2020-01-29 17:59:37 +01:00
|
|
|
async function verifyResponse({ filename }) {
|
2020-01-29 12:30:50 +01:00
|
|
|
console.log('Running verifier')
|
|
|
|
const { stdout, stderr } = await exec(
|
2020-01-31 18:03:09 +01:00
|
|
|
`../bin/phase2_verify_contribution circuit.json current.params /tmp/tornado/${filename}`,
|
2020-01-29 17:59:37 +01:00
|
|
|
{
|
|
|
|
cwd: './server/snark_files/',
|
|
|
|
env: { RUST_BACKTRACE: 1 }
|
2020-01-29 12:30:50 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
console.log(stdout)
|
|
|
|
console.error(stderr)
|
|
|
|
}
|
|
|
|
|
|
|
|
router.get('/challenge', (req, res) => {
|
|
|
|
res.sendFile('./snark_files/current.params', { root: path.join(__dirname, '../') })
|
|
|
|
})
|
|
|
|
|
|
|
|
router.get('/contributions', async (req, res) => {
|
2020-02-06 15:24:04 +01:00
|
|
|
const contributions = await Contribution.findAll({
|
2020-02-25 15:13:09 +01:00
|
|
|
attributes: ['id', 'name', 'company', 'handle', 'socialType', 'attestation']
|
2020-02-06 15:24:04 +01:00
|
|
|
})
|
2020-02-25 15:13:09 +01:00
|
|
|
res.json(contributions)
|
2020-01-29 12:30:50 +01:00
|
|
|
})
|
|
|
|
|
2020-01-29 17:59:37 +01:00
|
|
|
router.post('/response', upload.single('response'), async (req, res) => {
|
|
|
|
if (!req.file) {
|
2020-01-29 12:30:50 +01:00
|
|
|
res.status(400).send('Missing response file')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
await mutex.runExclusive(async () => {
|
2020-02-06 15:24:04 +01:00
|
|
|
const contributionIndex = await Contribution.nextContributionIndex()
|
2020-01-29 12:30:50 +01:00
|
|
|
try {
|
2020-02-06 15:24:04 +01:00
|
|
|
console.log(`Started processing contribution ${contributionIndex}`)
|
2020-01-29 17:59:37 +01:00
|
|
|
await verifyResponse({ filename: req.file.filename })
|
2020-01-29 12:30:50 +01:00
|
|
|
} catch (e) {
|
2020-02-06 15:24:04 +01:00
|
|
|
console.error('Got error during verifying', e)
|
|
|
|
await fs.unlink(`/tmp/tornado/${req.file.filename}`)
|
2020-01-29 12:30:50 +01:00
|
|
|
res.status(422).send(e.toString())
|
2020-01-29 17:59:37 +01:00
|
|
|
return
|
2020-01-29 12:30:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2020-02-05 16:02:34 +01:00
|
|
|
const socialType = req.session.socialType || 'anonymous'
|
|
|
|
let name = null
|
|
|
|
let company = null
|
|
|
|
let handle = null
|
2020-02-07 10:21:53 +01:00
|
|
|
let token = null
|
2020-02-05 16:02:34 +01:00
|
|
|
if (socialType !== 'anonymous' && req.body) {
|
|
|
|
name = req.body.name || null
|
|
|
|
company = req.body.company || null
|
|
|
|
handle = req.session.handle || null
|
2020-02-07 10:21:53 +01:00
|
|
|
} else {
|
|
|
|
token = crypto.randomBytes(32).toString('hex')
|
2020-02-05 16:02:34 +01:00
|
|
|
}
|
|
|
|
|
2020-02-29 12:22:45 +01:00
|
|
|
const contribution = await fs.readFile(`/tmp/tornado/${req.file.filename}`)
|
|
|
|
const blake2Instance = blake2.createHash('blake2b')
|
|
|
|
blake2Instance.update(contribution)
|
|
|
|
const hash = '0x' + blake2Instance.digest('hex')
|
|
|
|
|
|
|
|
await Contribution.create({ name, company, handle, socialType, token, hash })
|
2020-02-06 15:24:04 +01:00
|
|
|
|
|
|
|
console.log('Contribution is correct, uploading to storage')
|
|
|
|
if (process.env.DISABLE_S3 !== 'true') {
|
|
|
|
await uploadToS3({ filename: req.file.filename, contributionIndex })
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('Committing changes')
|
|
|
|
await fs.rename(`/tmp/tornado/${req.file.filename}`, './server/snark_files/current.params')
|
2020-02-08 16:57:49 +01:00
|
|
|
await fs.copyFile(
|
|
|
|
'./server/snark_files/current.params',
|
|
|
|
`./server/snark_files/response_${contributionIndex}`
|
|
|
|
)
|
2020-02-06 15:24:04 +01:00
|
|
|
|
2020-02-29 12:22:45 +01:00
|
|
|
console.log('Finished. The hash of the contribution is', hash)
|
|
|
|
res.json({ contributionIndex, token, hash })
|
2020-01-29 12:30:50 +01:00
|
|
|
} catch (e) {
|
2020-02-06 15:24:04 +01:00
|
|
|
console.error('Got error during save', e)
|
|
|
|
await fs.unlink(`/tmp/tornado/${req.file.filename}`)
|
2020-01-29 12:30:50 +01:00
|
|
|
res.status(503).send(e.toString())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2020-02-08 19:47:21 +01:00
|
|
|
router.post('/authorize_contribution', async (req, res) => {
|
|
|
|
if (!req.body || !req.body.name || !req.body.token) {
|
|
|
|
res.status(404).send('Wrong request params')
|
|
|
|
}
|
|
|
|
|
|
|
|
const contribution = await Contribution.findOne({ where: { token: req.body.token } })
|
2020-02-29 12:22:45 +01:00
|
|
|
console.log('contribution', contribution.dataValues.id)
|
2020-02-08 19:47:21 +01:00
|
|
|
if (!contribution) {
|
|
|
|
res.status(404).send('There is no such contribution')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contribution.dataValues.socialType !== 'anonymous') {
|
|
|
|
res.status(404).send('The contribution is already authorized')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!req.session.socialType || req.session.socialType === 'anonymous') {
|
|
|
|
res.status(403).send('Access forbidden')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
await Contribution.update(
|
|
|
|
{
|
|
|
|
name: req.body.name,
|
|
|
|
company: req.body.company,
|
|
|
|
handle: req.session.handle,
|
|
|
|
socialType: req.session.socialType
|
|
|
|
},
|
2020-02-29 12:22:45 +01:00
|
|
|
{ where: { id: contribution.dataValues.id }, individualHooks: true }
|
2020-02-08 19:47:21 +01:00
|
|
|
)
|
2020-02-29 12:22:45 +01:00
|
|
|
res.send('OK')
|
2020-02-08 19:47:21 +01:00
|
|
|
} catch (e) {
|
|
|
|
console.error('updateError', e)
|
|
|
|
res.status(404).send('Update error')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-02-14 15:13:11 +01:00
|
|
|
router.post('/get_contribution_index', async (req, res) => {
|
2020-02-11 10:53:41 +01:00
|
|
|
if (!req.body || !req.body.token) {
|
|
|
|
res.status(404).send('Wrong request params')
|
|
|
|
}
|
|
|
|
|
|
|
|
const contribution = await Contribution.findOne({ where: { token: req.body.token } })
|
|
|
|
if (!contribution) {
|
|
|
|
res.status(404).send('There is no such contribution')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contribution.dataValues.socialType !== 'anonymous') {
|
|
|
|
res.status(404).send('The contribution is already authorized')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return res.json({ id: contribution.dataValues.id }).send()
|
|
|
|
})
|
|
|
|
|
2020-01-29 17:59:37 +01:00
|
|
|
module.exports = router
|