diff --git a/.circleci/config.yml b/.circleci/config.yml index 9152cf0..7b403e0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ jobs: name: Download Circuits command: | cd packages/backend - wget https://pub-4c6a367a0d1b43b39b344703b032a675.r2.dev/circuits.tar.gz + wget https://pub-6c705682d0d84704aeda74c87d3880ec.r2.dev/circuits.tar.gz tar -xzf circuits.tar.gz rm circuits.tar.gz - run: diff --git a/.gitignore b/.gitignore index d6fc5a6..09a3d91 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ packages/contracts/contracts/verifiers/ db/ circuits/ dist/ + +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 43f3f96..6ee5b9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-buster +FROM node:18-buster COPY . /src @@ -6,7 +6,7 @@ WORKDIR /src RUN yarn && rm -rf packages/frontend -FROM node:16-buster +FROM node:18-buster COPY --from=0 /src /src WORKDIR /src/packages/backend diff --git a/packages/backend/.env.example b/packages/backend/.env.example new file mode 100644 index 0000000..afb6586 --- /dev/null +++ b/packages/backend/.env.example @@ -0,0 +1,12 @@ +R2_ACCOUNT_ID= +R2_ACCESS_KEY_ID= +R2_SECRET_ACCESS_KEY= +GITHUB_CLIENT_ID= +GITHUB_CLIENT_SECRET= +GITHUB_REDIRECT_URI= +DISCORD_CLIENT_ID= +DISCORD_CLIENT_SECRET= +DISCORD_REDIRECT_URI= +TWITTER_CLIENT_ID= +TWITTER_CLIENT_SECRET= +TWITTER_REDIRECT_URI= \ No newline at end of file diff --git a/packages/backend/package.json b/packages/backend/package.json index d4aa8cb..222c6b1 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -11,12 +11,14 @@ "dependencies": { "@aws-sdk/client-s3": "^3.345.0", "anondb": "^0.0.21", + "crypto": "^1.0.1", "dotenv": "^16.0.3", "especial": "^0.1.0-beta-3", "ethers": "^5.7.2", "express": "^4.18.2", "multer": "^1.4.5-lts.1", "node-fetch": "^3.3.1", + "octokit": "^3.1.1", "snarkjs": "git+https://github.com/vimwitch/snarkjs.git" }, "main": "index.js", diff --git a/packages/backend/src/config.mjs b/packages/backend/src/config.mjs index 5bbfcd3..22270bc 100644 --- a/packages/backend/src/config.mjs +++ b/packages/backend/src/config.mjs @@ -45,6 +45,12 @@ export const DISCORD_REDIRECT_URI = process.env.DISCORD_REDIRECT_URI ?? 'http://localhost:8000/oauth/discord/callback' +export const TWITTER_CLIENT_ID = process.env.TWITTER_CLIENT_ID +export const TWITTER_CLIENT_SECRET = process.env.TWITTER_CLIENT_SECRET +export const TWITTER_REDIRECT_URI = + process.env.TWITTER_REDIRECT_URI ?? + 'http://localhost:8000/oauth/twitter/callback' + export const WS_SERVER = process.env.WS_SERVER ?? `ws://127.0.0.1:8001` export const WELCOME_MESSAGE = @@ -62,7 +68,7 @@ export const ATTESTATION_URL = const ptauPath = path.join( __dirname, - '../circuits/powersOfTau28_hez_final_17.ptau' + '../circuits/powersOfTau28_hez_final_18.ptau' ) export const authOptions = [ @@ -147,13 +153,13 @@ export const circuits = [ ptauPath, }, { - name: 'Prove Reputation', - zkeyPath: path.join(__dirname, '../circuits/proveReputation.zkey'), + name: 'Reputation', + zkeyPath: path.join(__dirname, '../circuits/reputation.zkey'), ptauPath, }, { - name: 'Double Action', - zkeyPath: path.join(__dirname, '../circuits/preventDoubleAction.zkey'), + name: 'Scope Nullifier', + zkeyPath: path.join(__dirname, '../circuits/scopeNullifier.zkey'), ptauPath, }, ] diff --git a/packages/backend/src/http/discord.mjs b/packages/backend/src/http/discord.mjs index 6336668..4450627 100644 --- a/packages/backend/src/http/discord.mjs +++ b/packages/backend/src/http/discord.mjs @@ -136,6 +136,7 @@ export default ({ app, db, ceremony }) => { res.status(204).end() } else { const url = new URL(_state.redirectDestination) + url.searchParams.set('name', `Discord#${user.username}`) res.redirect(url.toString()) } }) diff --git a/packages/backend/src/http/github.mjs b/packages/backend/src/http/github.mjs index 4f03294..fa5bf31 100644 --- a/packages/backend/src/http/github.mjs +++ b/packages/backend/src/http/github.mjs @@ -5,6 +5,7 @@ import { } from '../config.mjs' import fetch from 'node-fetch' import { catchError } from '../catchError.mjs' +import { Octokit } from 'octokit' const GITHUB_URL = process.env.GITHUB_URL ?? 'https://github.com' const GITHUB_API_URL = process.env.GITHUB_URL ?? 'https://api.github.com' @@ -24,10 +25,11 @@ export default ({ app, wsApp, db, ceremony }) => { userId: auth.userId, }) const url = new URL('/login/oauth/authorize', GITHUB_URL) - url.searchParams.append('client_id', GITHUB_CLIENT_ID) - url.searchParams.append('redirect_uri', GITHUB_REDIRECT_URI) - url.searchParams.append('state', state._id) - url.searchParams.append('allow_signup', 'false') + url.searchParams.set('client_id', GITHUB_CLIENT_ID) + url.searchParams.set('redirect_uri', GITHUB_REDIRECT_URI) + url.searchParams.set('scope', 'gist') + url.searchParams.set('state', state._id) + url.searchParams.set('allow_signup', 'false') res.redirect(url.toString()) }) ) @@ -53,17 +55,14 @@ export default ({ app, wsApp, db, ceremony }) => { if (error) { // access was denied const url = new URL(_state.redirectDestination) - url.searchParams.append( - 'error', - 'There was a problem authenticating you' - ) + url.searchParams.set('error', 'There was a problem authenticating you') res.redirect(url.toString()) return } const url = new URL('/login/oauth/access_token', GITHUB_URL) - url.searchParams.append('client_id', GITHUB_CLIENT_ID) - url.searchParams.append('client_secret', GITHUB_CLIENT_SECRET) - url.searchParams.append('code', code) + url.searchParams.set('client_id', GITHUB_CLIENT_ID) + url.searchParams.set('client_secret', GITHUB_CLIENT_SECRET) + url.searchParams.set('code', code) const auth = await fetch(url.toString(), { method: 'POST', headers: { @@ -118,8 +117,38 @@ export default ({ app, wsApp, db, ceremony }) => { res.status(204).end() } else { const _url = new URL(_state.redirectDestination) + _url.searchParams.set('github_access_token', access_token) + _url.searchParams.set('name', `Github#${user.login}`) res.redirect(_url.toString()) } }) ) + + app.get( + '/post/github', + catchError(async (req, res) => { + const { access_token, content } = req.query + const octokit = new Octokit({ + request: { + fetch: fetch, + }, + auth: access_token, + }) + + const filename = `unirep-trusted-setup-${+new Date()}.log.md` + const data = { + description: 'Post of Unirep trusted setup', + files: {}, + headers: { + 'x-github-api-version': '2022-11-28', + }, + } + data.files[filename] = { + content, + } + + const response = await octokit.request('POST /gists', data) + res.json(response) + }) + ) } diff --git a/packages/backend/src/http/twitter.mjs b/packages/backend/src/http/twitter.mjs new file mode 100644 index 0000000..a61b8ac --- /dev/null +++ b/packages/backend/src/http/twitter.mjs @@ -0,0 +1,134 @@ +import { TWITTER_CLIENT_ID, TWITTER_REDIRECT_URI } from '../config.mjs' +import fetch from 'node-fetch' +import crypto from 'crypto' +import { catchError } from '../catchError.mjs' + +const TWITTER_URL = process.env.TWITTER_URL ?? 'https://twitter.com' +const TWITTER_API_URL = process.env.TWITTER_URL ?? 'https://api.twitter.com' + +export default ({ app, wsApp, db, ceremony }) => { + app.get( + '/oauth/twitter', + catchError(async (req, res) => { + const { token, content } = req.query + const auth = await db.findOne('Auth', { + where: { token }, + }) + if (!auth) return res.status(401).json({ error: 'unauthorized' }) + + const challenge = crypto.randomBytes(32).toString('hex') + const state = await db.create('OAuthState', { + type: 'twitter', + data: `${challenge}&${content}`, + redirectDestination: req.query.redirectDestination, + userId: auth.userId, + }) + const url = new URL('/i/oauth2/authorize', TWITTER_URL) + url.searchParams.set('response_type', 'code') + url.searchParams.set('client_id', TWITTER_CLIENT_ID) + url.searchParams.set('redirect_uri', TWITTER_REDIRECT_URI) + url.searchParams.set( + 'scope', + 'users.read tweet.read tweet.write offline.access' + ) + url.searchParams.set('state', state._id) + // PKCE thing + url.searchParams.set('code_challenge', challenge) + url.searchParams.set('code_challenge_method', 'plain') + res.redirect(url.toString()) + }) + ) + + app.get( + '/oauth/twitter/callback', + catchError(async (req, res) => { + const { code, state, error } = req.query + const _state = await db.findOne('OAuthState', { + where: { _id: state }, + }) + if (!_state) { + res.status(401).json({ + error: 'Invalid state', + }) + return + } + await db.delete('OAuthState', { + where: { + _id: state, + }, + }) + if (error) { + // access was denied + const url = new URL(_state.redirectDestination) + url.searchParams.set('error', 'There was a problem authenticating you') + res.redirect(url.toString()) + return + } + const challenge = _state.data.split('&')[0] + const args = { + code, + grant_type: 'authorization_code', + client_id: TWITTER_CLIENT_ID, + code_verifier: challenge, + redirect_uri: TWITTER_REDIRECT_URI, + } + const body = Object.entries(args) + .map(([key, val]) => `${key}=${encodeURIComponent(val)}`) + .join('&') + + const url = new URL('/2/oauth2/token', TWITTER_API_URL) + const auth = await fetch(url.toString(), { + method: 'POST', + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + body, + }) + + const authOutcome = await auth.json() + + const userUrl = new URL('/2/users/me', TWITTER_API_URL) + const userRes = await fetch(userUrl.toString(), { + headers: { + authorization: `Bearer ${authOutcome.access_token}`, + }, + }).then((r) => r.json()) + + const apiurl = new URL('/2/tweets', TWITTER_API_URL) + const text = _state.data.split('&')[1] + const data = { + text, + } + + const response = await fetch(apiurl.toString(), { + method: 'POST', + headers: { + authorization: `Bearer ${authOutcome.access_token}`, + 'user-agent': 'v2CreateTweetJS', + 'content-type': 'application/json', + accept: 'application/json', + }, + body: JSON.stringify(data), + }).then((r) => r.json()) + + if (!_state.redirectDestination) { + res.status(204).end() + } else { + const _url = new URL(_state.redirectDestination) + if (!response.data) { + _url.searchParams.set( + 'error', + 'You are not allowed to post duplicate content on twitter.' + ) + res.redirect(_url.toString()) + return + } + _url.searchParams.set( + 'twitter_post_url', + `https://x.com/${userRes.data.username}/status/${response.data.id}` + ) + res.redirect(_url.toString()) + } + }) + ) +} diff --git a/packages/backend/src/index.mjs b/packages/backend/src/index.mjs index ff03835..e6c09e8 100644 --- a/packages/backend/src/index.mjs +++ b/packages/backend/src/index.mjs @@ -44,7 +44,7 @@ try { const backup = new Backup(db) backup.start() } catch (err) { - console.log('Error starting backup system, aborting') + console.log('Error starting backup system, aborting:', err) } const deviceAuth = new DeviceAuth(db) diff --git a/packages/frontend/.env.example b/packages/frontend/.env.example new file mode 100644 index 0000000..15cbe5d --- /dev/null +++ b/packages/frontend/.env.example @@ -0,0 +1 @@ +HTTP_SERVER='https://dev2.http.ceremony.unirep.io' \ No newline at end of file diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 5ae0a52..2e92c0e 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -12,13 +12,17 @@ }, "dependencies": { "@cloudflare/kv-asset-handler": "^0.2.0", + "as-bind": "^0.8.2", "css-minimizer-webpack-plugin": "^5.0.0", "dayjs": "^1.11.8", + "dotenv-webpack": "^8.0.1", "especial": "^0.1.0-beta-3", "ethers": "^5.7.2", "file-loader": "^6.2.0", "mobx-react-lite": "^3.4.0", - "randomf": "^0.0.3" + "randomf": "^0.0.3", + "react-toastify": "^9.1.3", + "three": "^0.156.1" }, "devDependencies": { "@babel/core": "^7.19.6", diff --git a/packages/frontend/public/UniRep-Ceremony-OG.png b/packages/frontend/public/UniRep-Ceremony-OG.png new file mode 100644 index 0000000..ab9d910 Binary files /dev/null and b/packages/frontend/public/UniRep-Ceremony-OG.png differ diff --git a/packages/frontend/public/arrow.svg b/packages/frontend/public/arrow.svg deleted file mode 100644 index b323d5a..0000000 --- a/packages/frontend/public/arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/frontend/public/arrow_collapse.svg b/packages/frontend/public/arrow_collapse.svg new file mode 100644 index 0000000..1b1be6d --- /dev/null +++ b/packages/frontend/public/arrow_collapse.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/frontend/public/arrow_download.svg b/packages/frontend/public/arrow_download.svg new file mode 100644 index 0000000..a562df7 --- /dev/null +++ b/packages/frontend/public/arrow_download.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/frontend/public/arrow_dropdown.svg b/packages/frontend/public/arrow_dropdown.svg new file mode 100644 index 0000000..91c7c53 --- /dev/null +++ b/packages/frontend/public/arrow_dropdown.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/frontend/public/arrow_next.svg b/packages/frontend/public/arrow_next.svg new file mode 100644 index 0000000..07847bb --- /dev/null +++ b/packages/frontend/public/arrow_next.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/public/arrow_previous.svg b/packages/frontend/public/arrow_previous.svg new file mode 100644 index 0000000..e1e10f3 --- /dev/null +++ b/packages/frontend/public/arrow_previous.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/public/copy.svg b/packages/frontend/public/copy.svg new file mode 100644 index 0000000..ea024be --- /dev/null +++ b/packages/frontend/public/copy.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/frontend/public/cosmos1.svg b/packages/frontend/public/cosmos1.svg new file mode 100644 index 0000000..c02d318 --- /dev/null +++ b/packages/frontend/public/cosmos1.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/public/discord.svg b/packages/frontend/public/discord.svg new file mode 100644 index 0000000..ad9c7e4 --- /dev/null +++ b/packages/frontend/public/discord.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/frontend/public/download-arrow.png b/packages/frontend/public/download-arrow.png deleted file mode 100644 index 80aa5c6..0000000 Binary files a/packages/frontend/public/download-arrow.png and /dev/null differ diff --git a/packages/frontend/public/favicon.ico b/packages/frontend/public/favicon.ico new file mode 100644 index 0000000..c5cd4db Binary files /dev/null and b/packages/frontend/public/favicon.ico differ diff --git a/packages/frontend/public/github.svg b/packages/frontend/public/github.svg new file mode 100644 index 0000000..b10bca5 --- /dev/null +++ b/packages/frontend/public/github.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/frontend/public/hummingbird.svg b/packages/frontend/public/hummingbird.svg deleted file mode 100644 index cda1b82..0000000 --- a/packages/frontend/public/hummingbird.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/frontend/public/index.html b/packages/frontend/public/index.html index d6f962a..9fbedd9 100644 --- a/packages/frontend/public/index.html +++ b/packages/frontend/public/index.html @@ -1,12 +1,16 @@ - + + trusted setup