Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project: "Invite only" #20

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions inviteonly/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Invite only

This project is for proving you have received an invitation by email to an event.

Your identity is kept private by utilizing the ZK capabilities of zkEmail and Aztec.

This can be used for either personal invitations, or even for larger organized events. Larger events could be from services like Luma. Proving an invitation for an event might be useful for requesting a POAP, airdrop or for getting an invite to another event.

## Unfinished

**NOTE**: this project is far from ready. Unfortunately, this project did not get much further than the drawing board - the idea was formed but not much was done about it.

## Challenge Selection
The selected challenge is "zkEmail Guardian".

## Team information

Lauri Peltonen, ZK developer.

## Technical Approach

Utilize zkEmail to prove that the user has received an email from a certain email address and that the email includes a certain keyword.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool idea, have you looked into particular event platforms and what comes in their confirmation emails? Eg Meetup, Luma, ...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was more thinking of aiming this to more personal invitations. But those event platforms would probably make sense as well...


## Expected Outcomes

A way for anyone to prove that they are invited to an event, without exposing their email address. If time permits, a crude website to demonstrate - otherwise interaction through CLI.

## Lessons Learned (For Submission)

- Time should be reserved for this kind of projects, properly
- This project's best takeaway (for me, at least) was getting to know the Aztec community a bit, learn how the system works and seeing what others are building.
- A lot of various incompatibility issues were faced, and those were documented in the parent project. Luckily, getting over those did not require much time.

## Project Links (For Submission)

This project utilizes heavily code from https://github.com/saleel/gitclaim .

## Video Demo (For Submission)

Not available.
4 changes: 4 additions & 0 deletions inviteonly/app/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
NEXT_PUBLIC_GOOGLE_CLIENT_ID=
# TEMP_DIR=/tmp
2 changes: 2 additions & 0 deletions inviteonly/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.next
node_modules
1 change: 1 addition & 0 deletions inviteonly/app/assets/circuit-vkey.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,51,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,47,240,230,242,231,107,40,32,83,148,206,64,135,127,91,243,155,28,19,179,103,102,182,153,218,193,142,86,212,208,110,6,43,119,255,206,171,204,206,119,6,100,87,230,110,133,11,152,218,246,201,44,20,14,2,98,140,238,31,98,62,62,46,20,171,230,231,128,69,171,179,98,125,163,4,13,74,114,13,206,85,113,67,141,197,214,59,129,54,118,47,159,204,247,140,10,129,217,70,107,127,201,253,197,13,12,94,132,169,255,0,52,107,30,69,84,20,32,5,81,37,141,185,236,160,31,184,17,156,179,222,33,130,20,0,179,168,218,187,32,220,232,162,5,236,99,20,106,195,153,45,150,236,46,160,240,120,205,250,11,162,103,235,75,178,148,55,229,74,154,161,102,49,234,110,202,19,142,253,191,181,70,193,48,81,238,239,18,198,166,128,5,105,105,149,239,221,95,248,222,115,193,149,51,21,140,19,102,181,247,205,89,189,229,253,130,225,31,255,73,190,155,138,29,240,244,168,130,254,229,239,153,176,21,65,209,172,201,236,14,197,167,68,16,21,185,226,200,139,141,220,200,54,241,190,4,229,32,143,168,182,116,43,7,206,104,24,231,93,167,151,79,168,194,255,219,31,51,148,9,72,11,153,12,34,244,125,18,53,82,98,93,158,220,25,212,27,4,153,157,195,195,55,33,124,144,92,111,232,48,185,237,220,217,239,69,114,220,137,34,40,229,250,65,26,205,176,46,68,102,102,176,210,75,203,123,219,118,44,231,177,144,78,201,225,170,1,218,44,73,151,34,78,40,64,16,199,110,52,140,169,249,118,189,81,195,172,100,247,242,175,241,145,85,164,175,163,128,7,35,70,15,128,4,41,154,217,220,252,222,79,126,108,171,45,84,241,88,145,0,26,151,132,71,139,15,160,196,236,114,181,140,150,111,6,31,88,206,232,225,48,35,240,26,9,178,239,102,135,94,240,69,171,90,61,9,164,166,27,193,255,158,150,230,166,127,168,37,113,65,154,153,89,95,229,29,110,46,83,130,40,25,171,189,255,113,101,71,173,27,247,44,128,190,227,91,110,172,78,19,174,10,193,52,211,129,202,77,63,156,190,214,194,106,185,58,128,46,10,203,135,62,169,150,177,242,254,60,14,21,85,15,93,81,166,195,100,131,200,10,94,195,62,151,173,165,223,56,131,23,42,119,69,167,79,35,38,20,114,222,199,181,105,24,95,102,69,56,117,44,61,84,228,145,129,134,201,56,45,108,111,16,228,55,161,192,25,93,153,204,216,226,75,44,99,7,205,234,92,110,55,40,105,135,166,71,146,236,237,198,151,200,235,241,182,240,50,65,104,164,182,123,7,23,199,114,227,1,210,41,159,57,74,204,166,7,111,155,16,64,236,44,169,24,154,253,222,114,67,84,227,138,78,71,96,133,44,135,141,7,29,169,203,229,3,102,153,229,146,71,214,89,154,137,16,25,88,15,42,111,247,117,155,66,54,64,129,208,129,123,30,28,0,198,141,169,34,76,173,140,136,184,85,71,145,74,147,45,5,70,61,197,120,38,19,219,45,20,156,200,103,38,183,20,26,220,167,159,158,96,39,126,7,216,241,105,108,46,98,15,128,90,156,93,161,212,211,107,130,225,111,185,215,221,218,20,0,103,201,156,84,10,143,171,86,219,197,126,93,27,98,234,166,225,148,123,217,190,151,219,95,49,135,209,150,72,116,18,72,77,5,36,203,227,84,128,183,83,64,91,192,225,25,27,42,156,82,199,179,245,103,199,143,22,24,130,236,19,150,23,52,5,63,93,14,183,185,232,140,119,240,39,50,178,168,133,69,246,65,103,116,98,17,38,36,207,56,82,106,37,202,16,45,103,124,147,51,86,162,41,12,33,190,217,46,232,120,183,4,125,11,57,128,205,89,204,151,240,181,66,45,107,15,35,32,105,157,87,188,231,72,239,0,223,5,176,16,72,60,114,195,199,255,112,167,47,8,66,185,99,15,230,44,31,175,1,142,210,201,179,190,235,129,18,3,59,222,194,21,7,116,138,112,215,109,14,52,200,74,1,251,24,185,239,138,208,71,28,39,248,188,139,107,19,72,35,233,134,125,191,181,236,199,204,88,208,181,92,224,198,45,22,163,172,18,240,90,123,12,26,225,246,200,34,248,86,54,242,73,29,177,4,154,145,2,227,183,200,149,65,218,232,145,21,71,47,194,212,247,28,59,27,158,146,5,9,49,254,12,8,167,137,19,167,22,164,92,105,23,222,212,21,156,91,246,191,17,161,52,21,107,177,156,8,145,47,141,29,174,92,118,95,145,15,61,84,183,52,152,103,131,34,186,250,141,160,57,152,73,68,121,84,230,151,188,23,96,99,77,78,39,240,228,12,86,245,41,133,127,137,87,90,18,24,211,10,232,121,230,127,197,67,123,16,233,78,249,5,123,140,212,103,176,245,247,81,49,150,106,4,181,76,61,43,233,12,86,14,212,109,118,223,227,120,15,208,2,35,246,27,77,123,18,254,141,26,126,189,49,2,31,60,74,83,195,106,12,98,97,73,243,120,60,227,27,240,43,129,69,147,93,11,157,71,27,173,195,27,77,187,88,56,0,5,91,195,111,26,10,6,58,62,12,19,114,51,163,131,35,183,139,128,67,4,214,163,60,27,91,101,204,195,42,8,91,7,134,163,98,158,135,138,91,87,13,254,219,161,99,117,239,79,13,121,146,13,46,111,192,46,148,51,59,32,19,78,134,246,22,11,25,173,210,142,22,15,186,171,91,16,185,181,138,214,4,121,49,2,180,132,144,66,152,149,9,246,213,240,216,108,149,138,148,207,158,34,53,220,222,122,92,160,53,67,18,178,32,84,96,13,126,207,74,41,62,93,170,108,151,61,86,242,226,204,223,22,77,3,103,209,123,139,53,110,140,186,182,178,30,63,215,29,30,52,209,117,188,71,157,19,41,143,160,214,55,56,148,82,104,186,92,223,173,161,247,217,88,152,22,175,104,109,33,9,80,30,195,94,195,123,117,17,109,84,169,252,22,158,232,253,128,207,167,88,78,15,200,70,19,230,207,62,69,60,245,41,27,163,143,206,35,88,139,157,60,79,154,229,63,126,107,188,172,209,101,22,213,124,18,22,184,203,46,204,182,152,255,48,79,134,138,155,226,30,167,102,243,254,149,191,174,12,216,239,235,243,81,159,91,187,191,23,45,147,164,222,143,239,83,42,173,250,36,28,127,202,212,192,82,155,155,174,135,204,202,196,84,165,178,108,50,44,160,23,150,189,145,13,159,193,166,27,51,248,89,125,108,8,154,56,130,250,101,104,218,217,175,153,222,66,214,147,20,238,164,175,62,251,220,137,83,243,250,43,31,243,169,246,9,27,82,156,84,191,62,36,93,100,72,53,245,235,112,27,43,178,20,74,24,155,245,210,83,12,255,21,224,56,143,52,25,128,160,214,33,5,64,41,44,235,98,70,100,35,90,210,202,154,216,197,30,83,120,244,208,235,218,16,150,6,158,29,153,50,182,9,249,111,21,38,51,0,133,202,229,225,72,204,224,81,9,25,113,218,132,166,191,230,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,42,224,45,28,60,16,32,97,149,48,220,105,120,221,95,56,124,227,73,182,212,62,181,56,172,40,55,239,200,37,149,21,38,38,255,229,51,47,108,149,236,211,109,4,218,255,49,169,161,35,164,183,176,12,120,62,175,225,244,57,137,120,147,96]
1 change: 1 addition & 0 deletions inviteonly/app/assets/circuit.json

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions inviteonly/app/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

function Header() {
return (
<header className="navbar">
<div className="logo">
GitClaim
</div>
</header>
);
}

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<Header />
<div className="container">{children}</div>
</>
)
}
5 changes: 5 additions & 0 deletions inviteonly/app/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
69 changes: 69 additions & 0 deletions inviteonly/app/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import dotenv from 'dotenv';
import webpack from "webpack";

dotenv.config();

/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
outputFileTracingIncludes: {
'/api/claim-airdrop': [
'./node_modules/@aztec/bb.js/dest/node/barretenberg_wasm/**/*',
'./node_modules/@aztec/bb.js/dest/node/barretenberg_wasm/barretenberg_wasm_thread/factory/node/thread.worker.js'
],
'/api/claim-airdrop/': [
'./node_modules/@aztec/bb.js/dest/node/barretenberg_wasm/**/*',
'./node_modules/@aztec/bb.js/dest/node/barretenberg_wasm/barretenberg_wasm_thread/factory/node/thread.worker.js'
],
},
},
reactStrictMode: true,
sassOptions: {
includePaths: ['./'],
},
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'developers.google.com',
},
],
},
env: {
NEXT_PUBLIC_GOOGLE_CLIENT_ID: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
},
webpack: (config) => {
config.experiments = {
asyncWebAssembly: true,
syncWebAssembly: true,
layers: true,
}
config.plugins.push(
new webpack.NormalModuleReplacementPlugin(/^node:/, (resource) => {
resource.request = resource.request.replace(/^node:/, "");
})
);
return config
},
async headers() {
// These headers are necessary to enabled SharedArrayBuffer
// which is needed for multi-threaded proof generation
return [
{
source: '/:path*',
headers: [
{
key: 'Cross-Origin-Embedder-Policy',
value: 'require-corp',
},
{
key: 'Cross-Origin-Opener-Policy',
value: 'same-origin',
},
],
},
];
},
};

export default nextConfig;
54 changes: 54 additions & 0 deletions inviteonly/app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "ui",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@mach-34/zkemail-nr": "^1.1.0",
"@noir-lang/backend_barretenberg": "0.35.0-999071b.nightly",
"@noir-lang/noir_js": "0.35.0-999071b.nightly",
"@supabase/supabase-js": "^2.45.4",
"bulma": "^1.0.2",
"cal-sans": "^1.0.1",
"dotenv": "^16.4.5",
"idb-keyval": "^6.2.1",
"next": "14.2.11",
"react": "^18",
"react-dom": "^18",
"react-dropzone": "^14.2.9",
"sass": "^1.78.0"
},
"resolutions": {
"@zk-email/helpers": "6.1.6",
"@aztec/bb.js": "https://gitpkg.vercel.app/saleel/aztec-packages/barretenberg/ts?master"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.11",
"typescript": "^5",
"webpack": "^5.95.0"
},
"eslintConfig": {
"extends": [
"next/core-web-vitals",
"next/typescript"
],
"rules": {
"max-len": [
"error",
{
"code": 120
}
]
}
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
11 changes: 11 additions & 0 deletions inviteonly/app/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { AppProps } from "next/app";
import Layout from "../components/layout";
import "../styles/main.scss";

export default function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
13 changes: 13 additions & 0 deletions inviteonly/app/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
62 changes: 62 additions & 0 deletions inviteonly/app/pages/api/claim-airdrop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { verifyProof } from '../../utils';

type ResponseData = {
success: boolean;
message: string;
};

// WARNING!
// In-memory storage for nullifiers
// This will be reset during every server restart
// Replace with a database for actual use
const usedNullifiers = new Set<string>();

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
if (req.method !== 'POST') {
return res.status(405).json({ success: false, message: 'Method Not Allowed' });
}

const { proof, publicInputs } = req.body;

if (!proof || !publicInputs) {
return res.status(400).json({ success: false, message: 'Missing proof or public inputs' });
}

try {
// Verify the proof
const isValid = await verifyProof(proof, publicInputs);
if (!isValid) {
return res.status(400).json({ success: false, message: 'Invalid proof' });
}

// Construct the repo URL string from the first 50 bytes of publicInputs
/* const repoUrlBytes = publicInputs.slice(0, 50);
const repoUrl = repoUrlBytes.map((byte: number) => String.fromCharCode(byte)).join('').trim();
*/
// Check if the repo is eligible
/* if (!isEligibleRepo(repoUrl)) {
return res.status(403).json({ success: false, message: 'Repository is not eligible for the airdrop' });
} */

// Extract nullifier from public inputs
const nullifier = publicInputs[50];

// Check if nullifier has been used before
if (usedNullifiers.has(nullifier)) {
return res.status(400).json({ success: false, message: 'User already claimed the airdrop (nullifier found)' });
}

// Store the nullifier
usedNullifiers.add(nullifier);

// Airdrop claimed successfully
return res.status(200).json({ success: true, message: 'Airdrop claimed successfully' });
} catch (error) {
console.error('Error claiming airdrop:', error);
return res.status(500).json({ success: false, message: 'Internal server error' });
}
}
Loading