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

Upgrade to use ticket PCDs instead of semaphore signature + API #5

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions apps/web-app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ NEXTAUTH_URL=
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SINGLE_KEY_LOGIN=
PASSPORT_URL=
73 changes: 44 additions & 29 deletions apps/web-app/context/UserPassportContext.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useRouter } from "next/router"
import { createContext, ReactNode, useState, useContext, useEffect } from "react"
import {
openSignedZuzaluUUIDPopup,
useFetchParticipant,
usePassportPopupMessages,
useSemaphoreSignatureProof
getWithoutProvingUrl,
User
} from "@pcd/passport-interface"
import axios from "axios"
import { EdDSATicketPCDPackage } from "@pcd/eddsa-ticket-pcd"
import { EdDSAPCDPackage } from "@pcd/eddsa-pcd"

type UserPassportContextData = {
requestSignedZuID: () => void
Expand All @@ -24,7 +24,6 @@ type UserPassportProviderProps = {
export const UserPassportContext = createContext({} as UserPassportContextData)

export function UserPassportContextProvider({ children }: UserPassportProviderProps) {
const [uuid, setUuid] = useState<string | undefined>()
const [pcdStr, setPcdStr] = useState("")
const router = useRouter()
const [loadingPassport, setLoadingPassport] = useState({
Expand All @@ -33,15 +32,13 @@ export function UserPassportContextProvider({ children }: UserPassportProviderPr
})
const [errorPassport, setErrorPassport] = useState(false)

const PASSPORT_URL = "https://zupass.org/"
const PASSPORT_SERVER_URL = "https://api.pcd-passport.com/"

const [pcdStr2, _passportPendingPCDStr] = usePassportPopupMessages()
const PASSPORT_URL: string = process.env.NEXT_PUBLIC_PASSPORT_URL as string;

function requestSignedZuID() {
setLoadingPassport({ step: 1, text: "Waiting to prove passport..." })
const proofUrl = openSignedZuzaluUUIDPopup(PASSPORT_URL, `${window.location.origin}/popup`, "consumer-client")
// requestProofFromPassport(proofUrl)
const proofUrl = getWithoutProvingUrl(PASSPORT_URL, `${window.location.origin}/popup`, EdDSATicketPCDPackage.name);
const popupUrl = `/popup?proofUrl=${encodeURIComponent(proofUrl)}`;
window.open(popupUrl, "_blank", "width=360,height=480,top=100,popup");
}

useEffect(() => {
Expand All @@ -53,34 +50,43 @@ export function UserPassportContextProvider({ children }: UserPassportProviderPr
window.addEventListener("message", receiveMessage, false)
}, [])

const [signatureProofValid, setSignatureProofValid] = useState<boolean | undefined>()
const onProofVerified = (valid: boolean) => {
setSignatureProofValid(valid)
}

const { signatureProof } = useSemaphoreSignatureProof(pcdStr, onProofVerified)
const [participant, setParticipant] = useState<User | null>(null);

useEffect(() => {
if (signatureProofValid && signatureProof) {
const userUuid = signatureProof.claim.signedMessage
setUuid(userUuid)
}
}, [signatureProofValid, signatureProof])

const { participant } = useFetchParticipant(PASSPORT_SERVER_URL, uuid)

const loginProof = async (participant1: any, signatureProofProps: any) => {
if (pcdStr.length > 0) {
(async () => {
// @todo exception?
await EdDSAPCDPackage.init?.({});
await EdDSATicketPCDPackage.init?.({});
console.log(pcdStr);
const serializedPCD = JSON.parse(pcdStr);
const pcd = await EdDSATicketPCDPackage.deserialize(serializedPCD.pcd);
console.log(pcd);
const verified = await EdDSATicketPCDPackage.verify(pcd);
console.log(verified);
if (verified) {
const { ticketId, attendeeEmail, attendeeSemaphoreId, attendeeName } = pcd.claim.ticket;
const user: User = { email: attendeeEmail, uuid: ticketId, commitment: attendeeSemaphoreId, name: attendeeName };
setParticipant(user);
}
})();
}
}, [pcdStr, setParticipant])

const loginProof = async () => {
try {
console.log("sending data to api");
await axios({
method: "post",
url: "https://zuzalu.city/api/passport-user-login/",
data: { participant1, pcdStr },
url: "/api/passport-user-login/",
data: { pcdStr },
headers: {
"Content-Type": "application/json",
htmlcode: process.env.KEY_TO_API as string
}
})
.then((response) => {
console.log(response);
if (response.status === 200) {
setLoadingPassport({
step: 4,
Expand All @@ -100,6 +106,7 @@ export function UserPassportContextProvider({ children }: UserPassportProviderPr
}
})
.catch((error) => {
console.log(error);
setErrorPassport(true)
})
} catch (error1) {
Expand All @@ -111,7 +118,7 @@ export function UserPassportContextProvider({ children }: UserPassportProviderPr
useEffect(() => {
if (participant) {
setLoadingPassport({ step: 3, text: "Logging you in..." })
loginProof(participant, signatureProof)
loginProof();
}
}, [participant])

Expand All @@ -122,4 +129,12 @@ export function UserPassportContextProvider({ children }: UserPassportProviderPr
)
}

export function getServerSideProps() {
return {
props: {
PASSPORT_URL: process.env.PASSPORT_URL as string
}
}
}

export const useUserPassportContext = () => useContext(UserPassportContext)
6 changes: 4 additions & 2 deletions apps/web-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
"name": "web-app",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "next dev --port 3300",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@headlessui/react": "^1.7.2",
"@material-tailwind/react": "^1.4.2",
"@pcd/passport-interface": "latest",
"@pcd/eddsa-pcd": "^0.1.1",
"@pcd/eddsa-ticket-pcd": "^0.1.1",
"@pcd/passport-interface": "0.6.2",
"@pcd/pcd-collection": "latest",
"@pcd/pcd-types": "latest",
"@react-google-maps/api": "^2.18.1",
Expand Down
2 changes: 1 addition & 1 deletion apps/web-app/pages/api/fetchParticipants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const supabaseUrl = "https://polcxtixgqxfuvrqgthn.supabase.co"
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_KEY
const supabase = createClient(supabaseUrl, supabaseKey as string)

const allowedOrigins = ["https://zuzalu.city"]
const allowedOrigins = ["https://zuzalu.city", "http://localhost:3300"]

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
// Check for the 'Origin' header in the request
Expand Down
79 changes: 28 additions & 51 deletions apps/web-app/pages/api/passport-user-login.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,44 @@
import { NextApiRequest, NextApiResponse } from "next"
import { createServerSupabaseClient } from "@supabase/auth-helpers-nextjs"
import { SerializedPCD } from "@pcd/pcd-types"
import { fetchParticipant } from "@pcd/passport-interface"
import { SemaphoreSignaturePCDPackage } from "@pcd/semaphore-signature-pcd"

import { EdDSATicketPCDPackage } from "@pcd/eddsa-ticket-pcd"
import { EdDSAPCDPackage } from "@pcd/eddsa-pcd"
import authMiddleware from "../../hooks/auth"

interface Identity {
participant1: {
uuid: string
commitment: string
email: string
name: string
role: string
residence: string
order_id: string
}

pcdStr: string
}

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const supabase = createServerSupabaseClient({ req, res })
const signInWithSemaphoreProof = async (identity: Identity) => {
const signInWithTicketPCD = async ({ pcdStr }: { pcdStr: string }) => {
// Validate Proof of user before interacting with DB
const {
participant1: { uuid, commitment, email, name, role, residence, order_id },
pcdStr
} = identity

// pcdStr comes in a request parameter
const serPcd = JSON.parse(pcdStr) as SerializedPCD
const serializedPcd = JSON.parse(pcdStr) as SerializedPCD

if (serPcd.type !== SemaphoreSignaturePCDPackage.name) {
if (serializedPcd.type !== EdDSATicketPCDPackage.name) {
throw new Error("Invalid PCD type")
}
const pcd = await SemaphoreSignaturePCDPackage.deserialize(serPcd.pcd)
if (!(await SemaphoreSignaturePCDPackage.verify(pcd))) {
throw new Error("Invalid proof")
}

// Valid proof, check the signed message
await EdDSAPCDPackage.init?.({});
await EdDSATicketPCDPackage.init?.({});

const participant = await fetchParticipant("https://api.pcd-passport.com/", uuid)

if (participant == null || participant.commitment !== pcd.claim.identityCommitment) {
throw new Error("Wrong UUID")
const pcd = await EdDSATicketPCDPackage.deserialize(serializedPcd.pcd)
if (!(await EdDSATicketPCDPackage.verify(pcd))) {
throw new Error("Invalid proof")
}

const { ticketId, attendeeEmail, attendeeSemaphoreId, attendeeName } = pcd.claim.ticket;
const password: string = (process.env.SINGLE_KEY_LOGIN as string).trim()

try {
// Try to log the user in
const { data, error } = await supabase.auth.signInWithPassword({
email,
email: attendeeEmail,
password
})
// If sign in was successful, we're done
if (data && data.user) {
const { error: updatePubUserError } = await supabase
.from("users")
.update({ uui_auth: data.user.id, role })
.eq("email", email)
.update({ uui_auth: data.user.id, role: "" })
.eq("email", attendeeEmail)

if (updatePubUserError) {
res.status(400).json("Error with updating public user")
Expand All @@ -72,17 +49,17 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
// If use sign in was not successful, we need to create the user and then sign them in
if (error) {
const { data: signupData, error: signupError } = await supabase.auth.signUp({
email,
email: attendeeEmail,
password,
options: {
data: {
uuid,
commitment,
email,
name,
role,
residence,
order_id
uuid: ticketId,
commitment: attendeeSemaphoreId,
email: attendeeEmail,
name: attendeeEmail,
role: "", // These are not actually used anywhere
residence: "", // ^^
order_id: ticketId
}
}
})
Expand All @@ -99,7 +76,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const { data: publicUserData, error: publicUserError } = await supabase
.from("users")
.select("id")
.eq("email", email)
.eq("email", attendeeEmail)

if (publicUserError) {
res.status(400).json(`Error fetching public user: ${JSON.stringify(publicUserError)}`)
Expand All @@ -108,15 +85,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {

// If user profile exists, do an update of the uui_auth field
if (publicUserData.length > 0) {
await supabase.from("users").update({ uui_auth: signupData.user.id, role }).eq("email", email)
await supabase.from("users").update({ uui_auth: signupData.user.id, role: "" }).eq("email", attendeeEmail)
}
// Otherwise, add the user profile
else {
const { error: addUserError } = await supabase.from("users").insert({
userName: name,
email,
userName: attendeeName,
email: attendeeEmail,
uui_auth: signupData.user.id,
role
role: ""
})

if (addUserError) {
Expand All @@ -133,7 +110,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}

if (req.body) {
signInWithSemaphoreProof(req.body)
signInWithTicketPCD(req.body);
} else {
res.status(400).json("Request body is empty.")
}
Expand Down
Loading