Skip to content

Commit

Permalink
Basic implementation of Email PODs in Z API
Browse files Browse the repository at this point in the history
  • Loading branch information
robknight committed Jan 21, 2025
1 parent 79efcda commit 2481830
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 124 deletions.
6 changes: 4 additions & 2 deletions apps/passport-client/src/zapp/ZappServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ class ZupassPODRPC extends BaseZappServer implements ParcnetPODRPC {
public async insert(collectionId: string, podData: PODData): Promise<void> {
if (
!this.getPermissions().INSERT_POD?.collections.includes(collectionId) ||
collectionId === "Devcon SEA"
collectionId === "Devcon SEA" ||
collectionId === "Email"
) {
throw new MissingPermissionError("INSERT_POD", "pod.insert");
}
Expand Down Expand Up @@ -195,7 +196,8 @@ class ZupassPODRPC extends BaseZappServer implements ParcnetPODRPC {
public async delete(collectionId: string, signature: string): Promise<void> {
if (
!this.getPermissions().DELETE_POD?.collections.includes(collectionId) ||
collectionId === "Devcon SEA"
collectionId === "Devcon SEA" ||
collectionId === "Email"
) {
throw new MissingPermissionError("DELETE_POD", "pod.delete");
}
Expand Down
23 changes: 20 additions & 3 deletions apps/passport-client/src/zapp/collections.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PCDCollection } from "@pcd/pcd-collection";
import type { POD } from "@pcd/pod";
import { POD } from "@pcd/pod";
import { PODEmailPCD, isPODEmailPCD } from "@pcd/pod-email-pcd";
import { isPODPCD } from "@pcd/pod-pcd";
import { PODTicketPCD, isPODTicketPCD, ticketToPOD } from "@pcd/pod-ticket-pcd";

Expand All @@ -13,6 +14,14 @@ export function getCollectionNames(pcds: PCDCollection): string[] {
return pcds.getFoldersInFolder(COLLECTIONS_ROOT_FOLDER_NAME);
}

function emailPCDToPOD(pcd: PODEmailPCD): POD {
return POD.load(
pcd.claim.podEntries,
pcd.proof.signature,
pcd.claim.signerPublicKey
);
}

export function getPODsForCollections(
pcds: PCDCollection,
collectionIds: string[]
Expand All @@ -21,8 +30,16 @@ export function getPODsForCollections(
.flatMap((collectionId) =>
collectionId === "Devcon SEA"
? pcds.getAllPCDsInFolder("Devcon SEA")
: collectionId === "Email"
? pcds.getAllPCDsInFolder("Email")
: pcds.getAllPCDsInFolder(collectionIdToFolderName(collectionId))
)
.filter((pcd) => isPODPCD(pcd) || isPODTicketPCD(pcd))
.map((pcd) => (isPODPCD(pcd) ? pcd.pod : ticketToPOD(pcd as PODTicketPCD)));
.filter((pcd) => isPODPCD(pcd) || isPODTicketPCD(pcd) || isPODEmailPCD(pcd))
.map((pcd) =>
isPODPCD(pcd)
? pcd.pod
: isPODTicketPCD(pcd)
? ticketToPOD(pcd as PODTicketPCD)
: emailPCDToPOD(pcd as PODEmailPCD)
);
}
10 changes: 5 additions & 5 deletions examples/test-zapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
},
"dependencies": {
"@pcd/pod": "^0.5.0",
"@parcnet-js/podspec": "^1.1.3",
"@parcnet-js/ticket-spec": "^1.1.8",
"@parcnet-js/client-rpc": "^1.1.6",
"@parcnet-js/app-connector": "^1.1.8",
"@parcnet-js/app-connector-react": "^1.0.3",
"@parcnet-js/podspec": "^1.2.0",
"@parcnet-js/ticket-spec": "^1.1.9",
"@parcnet-js/client-rpc": "^1.2.0",
"@parcnet-js/app-connector": "^1.1.10",
"@parcnet-js/app-connector-react": "^1.0.5",
"json-bigint": "^1.0.0",
"lodash": "^4.17.21",
"react": "^18.2.0",
Expand Down
89 changes: 89 additions & 0 deletions examples/test-zapp/src/apis/GPC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,95 @@ const gpcProof = await z.gpc.prove({ request: request.schema });
</pre>
)}
</div>

<div>
<p>
Generating an email proof is done like this:
<code className="block text-xs font-base rounded-md p-2 whitespace-pre-wrap">
{`
const request: PodspecProofRequest = {
pods: {
pod1: {
pod: {
entries: {
emailAddress: {
type: "string"
},
semaphoreV4PublicKey: {
type: "eddsa_pubkey"
},
pod_type: {
type: "string",
isMemberOf: [
{ type: "string", value: "zupass.email" }
]
}
},
meta: {
labelEntry: "emailAddress"
}
},
revealed: {
emailAddress: true,
semaphoreV4PublicKey: true,
pod_type: false
}
}
}
};
const gpcProof = await z.gpc.prove({ request });
`}
</code>
</p>
<TryIt
onClick={async () => {
try {
const request: PodspecProofRequest = {
pods: {
pod1: {
pod: {
entries: {
emailAddress: {
type: "string"
},
semaphoreV4PublicKey: {
type: "eddsa_pubkey"
},
pod_type: {
type: "string",
isMemberOf: [
{ type: "string", value: "zupass.email" }
]
}
},
meta: {
labelEntry: "emailAddress"
}
},
revealed: {
emailAddress: true,
semaphoreV4PublicKey: true,
pod_type: false
}
}
}
};

const gpcProof = await z.gpc.prove({ request });
setProveResult(gpcProof);
} catch (e) {
console.log(e);
}
}}
label="Get Email Proof"
/>
{proveResult && (
<pre className="whitespace-pre-wrap">
{JSONBig.stringify(proveResult, null, 2)}
</pre>
)}
</div>
</div>
</div>
);
Expand Down
84 changes: 77 additions & 7 deletions examples/test-zapp/src/apis/PODSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export function PODSection(): ReactNode {
<div className="prose">
<h2 className="text-lg font-bold mt-4">Query PODs</h2>
<QueryPODs z={z} />
<h2 className="text-lg font-bold mt-4">Query Email PODs</h2>
<QueryEmailPODs z={z} />
<h2 className="text-lg font-bold mt-4">Sign POD</h2>
<SignPOD z={z} setSignedPOD={setPOD} />
<h2 className="text-lg font-bold mt-4">Sign POD with Prefix</h2>
Expand Down Expand Up @@ -120,6 +122,74 @@ const pods = await z.pod.collection("${selectedCollection}").query(q);
);
}

function QueryEmailPODs({ z }: { z: ParcnetAPI }): ReactNode {
const [pods, setPODs] = useState<p.PODData[] | undefined>(undefined);
return (
<div>
<p>
Querying Email PODs is done like this:
<code className="block text-xs font-base rounded-md p-2 whitespace-pre">
{`const q = p.pod({
entries: {
emailAddress: {
type: "string"
},
semaphoreV4PublicKey: {
type: "eddsa_pubkey"
},
pod_type: {
type: "string",
isMemberOf: [{ type: "string", value: "zupass.email" }]
}
}
});
const pods = await z.pod.collection("Email").query(q);
`}
</code>
</p>
<TryIt
onClick={async () => {
try {
const q = p.pod({
entries: {
emailAddress: {
type: "string"
},
semaphoreV4PublicKey: {
type: "eddsa_pubkey"
},
pod_type: {
type: "string",
isMemberOf: [{ type: "string", value: "zupass.email" }]
}
}
});
const pods = await z.pod.collection("Email").query(q);
console.log(pods);
setPODs(pods);
} catch (e) {
console.log(e);
}
}}
label="Query Email PODs"
/>
{pods !== undefined && (
<pre className="whitespace-pre-wrap">
{JSONBig.stringify(
pods.map((p) => ({
entries: p.entries,
signature: p.signature,
signerPublicKey: p.signerPublicKey
})),
null,
2
)}
</pre>
)}
</div>
);
}

type Action =
| {
type: "SET_KEY";
Expand Down Expand Up @@ -193,7 +263,7 @@ const editPODReducer = function (
) {
newState[action.key] = {
type: action.podValueType as "string" | "eddsa_pubkey",
value: newState[action.key].value.toString()
value: newState[action.key].value?.toString() ?? ""
};
} else {
state[action.key].type = action.podValueType;
Expand All @@ -203,7 +273,7 @@ const editPODReducer = function (
case "SET_VALUE": {
const newState = { ...state };
if (bigintish.includes(newState[action.key].type)) {
const value = BigInt(action.value);
const value = BigInt(action.value as string);
if (value >= POD_INT_MIN && value <= POD_INT_MAX) {
newState[action.key].value = value;
}
Expand Down Expand Up @@ -271,8 +341,8 @@ ${Object.entries(entries)
.map(([key, value]) => {
return ` ${key}: { type: "${value.type}", value: ${
bigintish.includes(value.type)
? `${value.value.toString()}n`
: `"${value.value.toString()}"`
? `${value.value?.toString() ?? ""}n`
: `"${value.value?.toString() ?? ""}"`
} }`;
})
.join(",\n")}
Expand Down Expand Up @@ -366,8 +436,8 @@ ${Object.entries(entries)
.map(([key, value]) => {
return ` ${key}: { type: "${value.type}", value: ${
bigintish.includes(value.type)
? `${value.value.toString()}n`
: `"${value.value.toString()}"`
? `${value.value?.toString() ?? ""}n`
: `"${value.value?.toString() ?? ""}"`
} }`;
})
.join(",\n")}
Expand Down Expand Up @@ -458,7 +528,7 @@ function EditPODEntry({
<label className="block">
{showLabels && <span className="text-gray-700">Value</span>}
<input
value={value.toString()}
value={value?.toString() ?? ""}
type={typeof value === "string" ? "text" : "number"}
className="mt-1 block w-full rounded-md bg-gray-100 border-transparent focus:border-gray-500 focus:bg-white focus:ring-0"
placeholder=""
Expand Down
4 changes: 2 additions & 2 deletions examples/test-zapp/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import "./index.css";
const zapp: Zapp = {
name: "test-client",
permissions: {
REQUEST_PROOF: { collections: ["Apples", "Bananas"] },
REQUEST_PROOF: { collections: ["Apples", "Bananas", "Email"] },
SIGN_POD: {},
READ_POD: { collections: ["Apples", "Bananas"] },
READ_POD: { collections: ["Apples", "Bananas", "Email"] },
INSERT_POD: { collections: ["Apples", "Bananas"] },
DELETE_POD: { collections: ["Bananas"] },
READ_PUBLIC_IDENTIFIERS: {}
Expand Down
Loading

0 comments on commit 2481830

Please sign in to comment.