Skip to content

Commit

Permalink
New RPC method for signing with prefixed keys (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
robknight authored Oct 22, 2024
1 parent 15f5ed6 commit 73b6fbd
Show file tree
Hide file tree
Showing 22 changed files with 217 additions and 17 deletions.
8 changes: 8 additions & 0 deletions apps/client-web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# client-web

## 0.0.11

### Patch Changes

- Updated dependencies
- @parcnet-js/client-rpc@1.1.1
- @parcnet-js/client-helpers@1.0.2

## 0.0.10

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion apps/client-web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "client-web",
"private": true,
"version": "0.0.10",
"version": "0.0.11",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
9 changes: 6 additions & 3 deletions apps/client-web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ function App() {
if (
state.advice &&
state.connectionState === ConnectionState.AUTHORIZED &&
state.zapp
state.zapp &&
state.zappOrigin
) {
state.advice.hideClient();
state.advice.ready(
Expand All @@ -43,7 +44,8 @@ function App() {
state.pods,
dispatch,
state.identity,
state.zapp
state.zapp,
state.zappOrigin
)
);
}
Expand All @@ -53,7 +55,8 @@ function App() {
state.pods,
state.identity,
dispatch,
state.zapp
state.zapp,
state.zappOrigin
]);

return (
Expand Down
6 changes: 4 additions & 2 deletions apps/client-web/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export class ParcnetClientProcessor implements ParcnetRPC {
private readonly pods: PODCollectionManager,
dispatch: Dispatch<ClientAction>,
userIdentity: Identity,
zapp: Zapp
zapp: Zapp,
zappOrigin: string
) {
this.subscriptions = new QuerySubscriptions(this.pods);
this.subscriptions.onSubscriptionUpdated((update, serial) => {
Expand All @@ -37,7 +38,8 @@ export class ParcnetClientProcessor implements ParcnetRPC {
this.pods,
this.subscriptions,
userIdentity,
zapp
zapp,
zappOrigin
);
this.identity = new ParcnetIdentityProcessor(userIdentity, zapp);
this.gpc = new ParcnetGPCProcessor(
Expand Down
29 changes: 28 additions & 1 deletion apps/client-web/src/client/pod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export class ParcnetPODProcessor implements ParcnetPODRPC {
private readonly pods: PODCollectionManager,
private readonly subscriptions: QuerySubscriptions,
private readonly identity: Identity,
private readonly zapp: Zapp
private readonly zapp: Zapp,
private readonly zappOrigin: string
) {}

public async query(
Expand Down Expand Up @@ -94,4 +95,30 @@ export class ParcnetPODProcessor implements ParcnetPODRPC {
);
return podToPODData(pod);
}

public async signPrefixed(entries: PODEntries): Promise<PODData> {
const permission = this.zapp.permissions.SIGN_POD;
if (!permission) {
throw new MissingPermissionError("SIGN_POD", "pod.signPrefixed");
}

for (const name of Object.keys(entries)) {
if (!name.startsWith("_UNSAFE_")) {
throw new Error(
"PODs signed with signPrefixed must have a prefix of _UNSAFE_"
);
}
}

entries.UNSAFE_META_ORIGIN = {
type: "string",
value: this.zappOrigin
};

const pod = POD.sign(
entries,
encodePrivateKey(Buffer.from(this.identity.export(), "base64"))
);
return podToPODData(pod);
}
}
14 changes: 11 additions & 3 deletions apps/client-web/src/pages/HostedZapp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,27 @@ export function HostedZapp(): ReactNode {
}, [dispatch]);

useEffect(() => {
if (state.advice && state.zapp) {
if (state.advice && state.zapp && state.zappOrigin) {
state.advice.hideClient();
state.advice.ready(
new ParcnetClientProcessor(
state.advice,
state.pods,
dispatch,
state.identity,
state.zapp
state.zapp,
state.zappOrigin
)
);
}
}, [state.advice, state.pods, state.identity, dispatch, state.zapp]);
}, [
state.advice,
state.pods,
state.identity,
dispatch,
state.zapp,
state.zappOrigin
]);

const modalVisible = useMemo(() => {
return state.proofInProgress !== undefined;
Expand Down
9 changes: 9 additions & 0 deletions examples/test-app/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# test-app

## 1.0.13

### Patch Changes

- Updated dependencies
- @parcnet-js/app-connector@1.1.1
- @parcnet-js/client-rpc@1.1.1
- @parcnet-js/ticket-spec@1.1.1

## 1.0.12

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/test-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "test-app",
"version": "1.0.12",
"version": "1.0.13",
"private": true,
"type": "module",
"scripts": {
Expand Down
100 changes: 99 additions & 1 deletion examples/test-app/src/apis/PODSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export function PODSection(): ReactNode {
<QueryPODs 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>
<SignPODWithPrefix z={z} setSignedPOD={setPOD} />
<h2 className="text-lg font-bold mt-4">Insert POD</h2>
<InsertPOD z={z} pod={pod} />
<h2 className="text-lg font-bold mt-4">Delete POD</h2>
Expand Down Expand Up @@ -134,6 +136,7 @@ type Action =
| {
type: "ADD_ENTRY";
value: PODValue;
prefix?: string;
}
| {
type: "REMOVE_ENTRY";
Expand All @@ -150,7 +153,7 @@ const editPODReducer = function (
switch (action.type) {
case "ADD_ENTRY": {
const newState = { ...state };
let key = "entry";
let key = `${action.prefix ?? ""}entry`;
let n = 1;
while (key in newState) {
key = `entry${n}`;
Expand Down Expand Up @@ -308,6 +311,101 @@ ${Object.entries(entries)
);
}

function SignPODWithPrefix({
z,
setSignedPOD
}: {
z: ParcnetAPI;
setSignedPOD: Dispatch<SetStateAction<PODData | null>>;
}): ReactNode {
const [creationState, setCreationState] = useState<PODCreationState>(
PODCreationState.None
);
const [pod, setPOD] = useState<PODData | null>(null);
const [entries, dispatch] = useReducer(editPODReducer, {
_UNSAFE_test: { type: "string", value: "Testing" }
} satisfies PODEntries);
return (
<div>
<p>
To sign a POD, first we have to create the entries. Note that the
entries must have a prefix of <code>_UNSAFE_</code>. Select the entries
for the POD below:
</p>
<div className="flex flex-col gap-2 mb-4">
{Object.entries(entries).map(([name, value], index) => (
<EditPODEntry
key={index}
showLabels={index === 0}
name={name}
value={value.value}
type={value.type}
dispatch={dispatch}
/>
))}
<Button
onClick={() =>
dispatch({
type: "ADD_ENTRY",
value: { type: "string", value: "" },
prefix: "_UNSAFE_"
})
}
>
Add Another Entry
</Button>
</div>
<p>
Then we can sign the POD:
<code className="block text-xs font-base rounded-md p-2 whitespace-pre">
{`const pod = await z.pod.sign({
${Object.entries(entries)
.map(([key, value]) => {
return ` ${key}: { type: "${value.type}", value: ${
bigintish.includes(value.type)
? `${value.value.toString()}n`
: `"${value.value.toString()}"`
} }`;
})
.join(",\n")}
});
`}
</code>
</p>
<TryIt
onClick={async () => {
try {
const pod = await z.pod.signPrefixed(entries);
setPOD(pod);
setSignedPOD(pod);
setCreationState(PODCreationState.Success);
} catch (e) {
console.error(e);
setCreationState(PODCreationState.Failure);
}
}}
label="Sign POD with Prefix"
/>
{creationState !== PODCreationState.None && (
<div className="my-2">
{creationState === PODCreationState.Success && (
<div>
POD signed successfully! The signature is{" "}
<code className="block text-xs font-base rounded-md p-2 whitespace-pre">
{pod?.signature}
</code>
</div>
)}
{creationState === PODCreationState.Failure && (
<div>An error occurred while signing your POD.</div>
)}
</div>
)}
</div>
);
}

function EditPODEntry({
name,
value,
Expand Down
8 changes: 8 additions & 0 deletions packages/app-connector/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @parcnet-js/app-connector

## 1.1.1

### Patch Changes

- Support 'signPrefixed' for unsafely-signed PODs
- Updated dependencies
- @parcnet-js/client-rpc@1.1.1

## 1.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/app-connector/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parcnet-js/app-connector",
"version": "1.1.0",
"version": "1.1.1",
"license": "GPL-3.0-or-later",
"type": "module",
"main": "dist/index.cjs",
Expand Down
4 changes: 4 additions & 0 deletions packages/app-connector/src/api_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ export class ParcnetPODWrapper {
this.#api.pod.sign(entries).then(resolve).catch(reject);
});
}

async signPrefixed(entries: PODEntries): Promise<PODData> {
return this.#api.pod.signPrefixed(entries);
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/app-connector/src/rpc_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ export class ParcnetRPCConnector implements ParcnetRPC, ParcnetEvents {
[entries],
ParcnetRPCSchema.pod.sign
);
},
signPrefixed: async (entries: PODEntries): Promise<PODData> => {
return this.#typedInvoke(
"pod.signPrefixed",
[entries],
ParcnetRPCSchema.pod.signPrefixed
);
}
};
this.gpc = {
Expand Down
7 changes: 7 additions & 0 deletions packages/client-helpers/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @parcnet-js/client-helpers

## 1.0.2

### Patch Changes

- Updated dependencies
- @parcnet-js/client-rpc@1.1.1

## 1.0.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/client-helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parcnet-js/client-helpers",
"version": "1.0.1",
"version": "1.0.2",
"license": "GPL-3.0-or-later",
"type": "module",
"main": "dist/index.js",
Expand Down
6 changes: 6 additions & 0 deletions packages/client-rpc/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @parcnet-js/client-rpc

## 1.1.1

### Patch Changes

- Support 'signPrefixed' for unsafely-signed PODs

## 1.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/client-rpc/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@parcnet-js/client-rpc",
"type": "module",
"version": "1.1.0",
"version": "1.1.1",
"license": "GPL-3.0-or-later",
"main": "dist/index.js",
"module": "dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions packages/client-rpc/src/rpc_interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface ParcnetPODRPC {
unsubscribe: (subscriptionId: string) => Promise<void>;
// Returns serialized POD
sign: (entries: PODEntries) => Promise<PODData>;
signPrefixed: (entries: PODEntries) => Promise<PODData>;
}

export interface ParcnetRPC {
Expand Down
Loading

0 comments on commit 73b6fbd

Please sign in to comment.