mirror of
https://github.com/tornadocash/trusted-setup-server.git
synced 2024-11-21 17:36:54 +01:00
authorize button feature
This commit is contained in:
parent
7fb6395dd7
commit
431b06ca52
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="ceremony">
|
||||
<h1 class="title is-size-1 is-size-2-mobile is-spaced">
|
||||
Hello, <span>@{{ userHandle }}</span>
|
||||
Hello, <span>@{{ handle }}</span>
|
||||
</h1>
|
||||
<h2 class="subtitle">
|
||||
Do you want to authorize your contribution #{{ contributionIndex }}? Please sign in.
|
||||
@ -10,15 +10,34 @@
|
||||
<Form />
|
||||
</fieldset>
|
||||
<div class="buttons is-centered">
|
||||
<b-button v-if="isLoggedIn" :disabled="hasErrorName.invalid" type="is-primary" outlined>
|
||||
<b-button
|
||||
v-if="isLoggedIn && !hideSaveBtn"
|
||||
@click="authorize"
|
||||
:disabled="hasErrorName.invalid"
|
||||
type="is-primary"
|
||||
outlined
|
||||
>
|
||||
Save information
|
||||
</b-button>
|
||||
<b-button
|
||||
v-if="status.type === 'is-success'"
|
||||
@click="makeTweet"
|
||||
type="is-primary"
|
||||
tag="a"
|
||||
target="_blank"
|
||||
outlined
|
||||
>
|
||||
Tweet about your contribution
|
||||
</b-button>
|
||||
</div>
|
||||
<div v-show="status.type === 'is-danger' || status.type === 'is-success'" class="status">
|
||||
<div :class="status.type" class="status-message">{{ status.msg }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex'
|
||||
import { mapGetters, mapActions, mapState } from 'vuex'
|
||||
import Form from '@/components/Form'
|
||||
|
||||
export default {
|
||||
@ -27,24 +46,60 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contributionIndex: 1
|
||||
contributionIndex: 1,
|
||||
token: null,
|
||||
status: {
|
||||
type: '',
|
||||
msg: ''
|
||||
},
|
||||
hideSaveBtn: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('user', ['isLoggedIn', 'hasErrorName']),
|
||||
userHandle: {
|
||||
get() {
|
||||
return this.$store.state.user.handle
|
||||
}
|
||||
}
|
||||
...mapState('user', ['name', 'handle', 'company']),
|
||||
...mapGetters('user', ['isLoggedIn', 'hasErrorName'])
|
||||
},
|
||||
async mounted() {
|
||||
await this.getUserData()
|
||||
// TODO. parse href to take token (it's supposed to be after #)
|
||||
// then you need to store it in localstorage OR pass to server (to `/connect`) so after the authorization redirect server can put it in url
|
||||
this.token = this.$route.query.token
|
||||
if (!this.token) {
|
||||
window.location.replace(window.location.origin)
|
||||
} else {
|
||||
// TODO try to load contribution data. May be it's already authorized
|
||||
// also set `contributionIndex`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('user', ['getUserData'])
|
||||
...mapActions('user', ['getUserData', 'makeTweet']),
|
||||
async authorize() {
|
||||
const body = {
|
||||
token: this.token,
|
||||
name: this.name,
|
||||
company: this.company
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/authorize_contribution', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
if (response.ok) {
|
||||
this.status.msg = `Your contribution is verified and authorized. Thank you.`
|
||||
this.status.type = 'is-success'
|
||||
this.hideSaveBtn = true
|
||||
} else {
|
||||
const error = await response.text()
|
||||
this.status.msg = error
|
||||
this.status.type = 'is-danger'
|
||||
}
|
||||
} catch (e) {
|
||||
this.status.msg = 'Something went wrong. Please contact support'
|
||||
this.status.type = 'is-danger'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -174,6 +174,9 @@ export default {
|
||||
this.status.type = 'is-success'
|
||||
const responseData = await resp.json()
|
||||
this.$store.commit('user/SET_CONTRIBUTION_INDEX', responseData.contributionIndex)
|
||||
console.log(
|
||||
`${window.location.origin}/authorize-contribution?token=${responseData.token}`
|
||||
)
|
||||
} else if (resp.status === 422) {
|
||||
if (retry < 3) {
|
||||
console.log(`Looks like someone else uploaded contribution ahead of us, retrying`)
|
||||
|
@ -13,6 +13,7 @@ const {
|
||||
GITHUB_CALLBACK_URL
|
||||
} = process.env
|
||||
const providers = ['github', 'twitter']
|
||||
const signInPages = ['/make-contribution', '/authorize-contribution']
|
||||
|
||||
// twitter uses OAuth1
|
||||
const twitter = new oauth.OAuth(
|
||||
@ -43,8 +44,31 @@ function validateProvider(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
router.get('/connect/:provider', validateProvider, (req, res) => {
|
||||
function validateRefferer(req, res, next) {
|
||||
let referrer
|
||||
try {
|
||||
referrer = new URL(req.get('Referrer'))
|
||||
} catch (e) {
|
||||
res.status(403).send('Access forbidden')
|
||||
return
|
||||
}
|
||||
|
||||
if (!signInPages.includes(referrer.pathname)) {
|
||||
res.status(403).send('Access forbidden')
|
||||
return
|
||||
}
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
router.get('/connect/:provider', validateProvider, validateRefferer, (req, res) => {
|
||||
const { provider } = req.params
|
||||
const referrer = new URL(req.get('Referrer'))
|
||||
|
||||
req.session.pageToReturn = referrer.pathname // the page a user will be redirected after signIn
|
||||
if (referrer.pathname === '/authorize-contribution') {
|
||||
req.session.pageToReturn += referrer.search // to add `token` parameter for authorize-contribution page
|
||||
}
|
||||
|
||||
if (provider === 'github') {
|
||||
const CSRFToken = crypto.randomBytes(32).toString('hex')
|
||||
@ -86,7 +110,7 @@ router.get('/oauth_callback/:provider', validateProvider, (req, res) => {
|
||||
} else {
|
||||
req.session.refreshToken = refreshToken
|
||||
req.session.accessToken = accessToken
|
||||
res.redirect('/make-contribution')
|
||||
res.redirect(req.session.pageToReturn)
|
||||
}
|
||||
})
|
||||
} else if (provider === 'twitter') {
|
||||
@ -101,7 +125,7 @@ router.get('/oauth_callback/:provider', validateProvider, (req, res) => {
|
||||
} else {
|
||||
req.session.oauthAccessToken = oauthAccessToken
|
||||
req.session.oauthAccessTokenSecret = oauthAccessTokenSecret
|
||||
res.redirect('/make-contribution')
|
||||
res.redirect(req.session.pageToReturn)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
const fs = require('fs').promises
|
||||
const path = require('path')
|
||||
const util = require('util')
|
||||
@ -97,7 +98,7 @@ router.post('/response', upload.single('response'), async (req, res) => {
|
||||
)
|
||||
|
||||
console.log('Finished')
|
||||
res.json({ contributionIndex })
|
||||
res.json({ contributionIndex, token })
|
||||
} catch (e) {
|
||||
console.error('Got error during save', e)
|
||||
await fs.unlink(`/tmp/tornado/${req.file.filename}`)
|
||||
@ -106,4 +107,43 @@ router.post('/response', upload.single('response'), async (req, res) => {
|
||||
})
|
||||
})
|
||||
|
||||
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 } })
|
||||
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
|
||||
},
|
||||
{ where: { token: req.body.token }, returning: true }
|
||||
)
|
||||
} catch (e) {
|
||||
console.error('updateError', e)
|
||||
res.status(404).send('Update error')
|
||||
}
|
||||
|
||||
res.send('OK')
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
@ -38,12 +38,12 @@ async function start() {
|
||||
next()
|
||||
})
|
||||
|
||||
app.use('/api', sessionsController)
|
||||
app.use('/api', contributionController)
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }))
|
||||
app.use(bodyParser.json())
|
||||
|
||||
app.use('/api', sessionsController)
|
||||
app.use('/api', contributionController)
|
||||
|
||||
// Give nuxt middleware to express
|
||||
app.use(nuxt.render)
|
||||
|
||||
|
@ -1,4 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
const validate = (contribution, options) => {
|
||||
const { name, company, socialType } = contribution.dataValues
|
||||
if (socialType !== 'anonymous' && (name.length < 4 || name.length > 35)) {
|
||||
throw new Error('Wrong name')
|
||||
}
|
||||
if (company && company.length > 35) {
|
||||
throw new Error('Wrong company')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const Contribution = sequelize.define(
|
||||
'Contribution',
|
||||
@ -12,15 +23,8 @@ module.exports = (sequelize, DataTypes) => {
|
||||
},
|
||||
{
|
||||
hooks: {
|
||||
beforeCreate: (contribution, options) => {
|
||||
const { name, company, socialType } = contribution.dataValues
|
||||
if (socialType !== 'anonymous' && (name.length < 4 || name.length > 35)) {
|
||||
throw new Error('Wrong name')
|
||||
}
|
||||
if (company && company.length > 35) {
|
||||
throw new Error('Wrong company')
|
||||
}
|
||||
}
|
||||
beforeCreate: validate,
|
||||
beforeUpdate: validate
|
||||
}
|
||||
}
|
||||
)
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user