Set up "email verification" workflow (minus the email itself)
We'll start sending out the email in the next step, when the setup of nodemailer is complete. Right now, everything else works: creating a verification link, processing it when clicked on, and even updating (instead of appending) a pledge when the same email submits multiple times. No pretty error messages though; that's another thing to be worked on :P WARNING: Don't deploy this commit live; people will be told about a verification email but they won't actually get it yet!
This commit is contained in:
parent
a33ba1dc9c
commit
a381077b83
3 changed files with 126 additions and 0 deletions
|
@ -25,6 +25,7 @@
|
|||
"tailwindcss": "^3.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@constemi/itsdangerjs": "^0.0.2",
|
||||
"bookshelf": "^1.2.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"express": "^4.17.2",
|
||||
|
|
120
server/index.js
120
server/index.js
|
@ -1,6 +1,7 @@
|
|||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const path = require('path')
|
||||
const { URLSafeTimedSerializer } = require("@constemi/itsdangerjs")
|
||||
|
||||
require('dotenv').config()
|
||||
|
||||
|
@ -15,6 +16,20 @@ if (process.env.DEBUG || process.env.CROWDFUNDING_SITE_DEBUG) {
|
|||
|
||||
if (DEBUG) console.log('Starting website in debug mode')
|
||||
|
||||
// set up secret key
|
||||
let secretKey
|
||||
if (process.env.CROWDFUNDING_SITE_SECRET_KEY) {
|
||||
secretKey = process.env.CROWDFUNDING_SITE_SECRET_KEY
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
secretKey = 'NotReallyASecret'
|
||||
console.warn("Secret key is not set! We're falling back to the default one which is INSECURE and NOT TO BE USED IN PRODUCTION")
|
||||
} else {
|
||||
console.error('No secret key is set. You cannot run this in production without setting a secret key because that would be very insecure. Sorry.')
|
||||
process.exit()
|
||||
}
|
||||
}
|
||||
|
||||
// get goal details
|
||||
const goalPeople = Number(process.env.CROWDFUNDING_SITE_GOAL_PEOPLE) || 750
|
||||
const goalRupees = Number(process.env.CROWDFUNDING_SITE_GOAL_RUPEES) || 500000
|
||||
|
@ -213,9 +228,113 @@ router.post('/pledge', async (req, res) => {
|
|||
return
|
||||
}
|
||||
|
||||
// check for existing pledge
|
||||
let existingPledge
|
||||
try {
|
||||
existingPledge = await (Pledge
|
||||
.query({
|
||||
where: {
|
||||
'email': req.query.email,
|
||||
'amount': amount,
|
||||
},
|
||||
})
|
||||
.orderBy('created_at', 'DESC')
|
||||
.fetch())
|
||||
} catch(e) {
|
||||
if (e.name == 'EmptyResponse' && DEBUG) {
|
||||
console.debug('No existing pledge')
|
||||
} else {
|
||||
console.warn(`Weird error happened: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
// generate verification link
|
||||
let serialiser = URLSafeTimedSerializer(secretKey, pledge.get('email'))
|
||||
let verificationLink = `${req.protocol}://${req.hostname}/verify?email=${encodeURIComponent(pledge.get('email'))}&key=${encodeURIComponent(serialiser.dumps(pledge.get('amount')))}`
|
||||
|
||||
// TODO: send out the email, along with existing pledge deets
|
||||
console.debug(`Verification link generated: ${verificationLink}`)
|
||||
|
||||
res.send("Thank you! We're still working on setting up this website, so as you can see this page doesn't look great at the moment, but we will be sending you a confirmation email in a few days. Watch out for an email from editors@snipettemag.com, and if it doesn't reach, check your spam box :P")
|
||||
})
|
||||
|
||||
// save pledge after verification complete
|
||||
router.get('/verify', async (req, res) => {
|
||||
if (DEBUG) console.debug('Validating pledge:', req.query)
|
||||
|
||||
// unpack verification link (unless it's expired)
|
||||
let serialiser = URLSafeTimedSerializer(secretKey, req.query.email)
|
||||
let amount
|
||||
|
||||
try {
|
||||
amount = serialiser.loads(req.query.key, 300) // number in seconds
|
||||
} catch(e) {
|
||||
if (e.name == 'SignatureExpired') {
|
||||
res.send("Oops, looks like your link has expired. Please go back and try pledging again. Sorry :(")
|
||||
return
|
||||
} else {
|
||||
res.send("An unknown error occurred. Please generate a new link and try again. Sorry for the inconvenience :(")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// check against database
|
||||
let pledge
|
||||
try {
|
||||
pledge = await (UnverifiedPledge
|
||||
.query({
|
||||
where: {
|
||||
'email': req.query.email,
|
||||
'amount': amount,
|
||||
},
|
||||
})
|
||||
.orderBy('created_at', 'DESC')
|
||||
.fetch())
|
||||
} catch(e) {
|
||||
if (e.name == 'EmptyResponse') {
|
||||
res.send('That pledge was not found in our records. Are you sure you made it? Please go back and try again :(')
|
||||
return
|
||||
} else {
|
||||
throw e
|
||||
res.send("An unknown error occurred. Please generate a new link and try again. Sorry for the inconvenience :(")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// prepare our new pledge
|
||||
let newPledge = new Pledge()
|
||||
|
||||
newPledge.set('was_robot', pledge.get('was_robot'))
|
||||
newPledge.set('amount', pledge.get('amount'))
|
||||
newPledge.set('overseas', pledge.get('overseas'))
|
||||
newPledge.set('name', pledge.get('name'))
|
||||
newPledge.set('anonymous', pledge.get('anonymous'))
|
||||
newPledge.set('email', pledge.get('email'))
|
||||
newPledge.set('phone', pledge.get('phone'))
|
||||
newPledge.set('retry_times', pledge.get('retry_times'))
|
||||
newPledge.set('get_newsletter', pledge.get('get_newsletter'))
|
||||
newPledge.set('other_message', pledge.get('other_message'))
|
||||
|
||||
// destroy previous pledges by that user
|
||||
try {
|
||||
await (Pledge
|
||||
.query({
|
||||
where: {
|
||||
email: req.query.email,
|
||||
}
|
||||
})
|
||||
.destroy())
|
||||
} catch(e) {
|
||||
if (e.message != 'No Rows Deleted') throw e
|
||||
}
|
||||
|
||||
// save the new pledge
|
||||
await newPledge.save()
|
||||
|
||||
// dummy message
|
||||
res.send('all done (not)')
|
||||
})
|
||||
|
||||
router.use(express.static('dist'))
|
||||
|
||||
// start the listener!
|
||||
|
@ -228,5 +347,6 @@ module.exports = {
|
|||
knex,
|
||||
bookshelf,
|
||||
Pledge,
|
||||
UnverifiedPledge,
|
||||
router,
|
||||
}
|
||||
|
|
|
@ -205,6 +205,11 @@
|
|||
"@babel/helper-validator-identifier" "^7.15.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@constemi/itsdangerjs@^0.0.2":
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@constemi/itsdangerjs/-/itsdangerjs-0.0.2.tgz#1cb5803b26fb1262150d64c90f5451511f431340"
|
||||
integrity sha512-/TKmvxodKwhI42BIKt7YJQR1xD2bWeUFtxjs4RFbRMHjtWgYn5WocyclbkM0WEDY0xoS16eQQxykwdtzYhoCfw==
|
||||
|
||||
"@iarna/toml@^2.2.0":
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c"
|
||||
|
|
Loading…
Reference in a new issue