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

feat(isle): view credential details #594

Merged
merged 8 commits into from
Mar 6, 2025
6 changes: 5 additions & 1 deletion apps/isle/src/features/permissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,11 @@ export function Permissions() {
size="xs"
colorPalette="green"
rounded="full"
onClick={() => {}}
onClick={() => {
node?.post("view-credential-details", {
id: grant.dataId,
});
}}
>
<ViewIcon w="5" h="5" color="neutral.400" />
</IconButton>
Expand Down
25 changes: 25 additions & 0 deletions examples/consumer-and-issuer/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useEffect, useRef, useState } from "react";
import { useAccount, useSignMessage } from "wagmi";

import { createIDOSUserProfile } from "@/app/actions";
import invariant from "tiny-invariant";

export default function Home() {
const isleRef = useRef<ReturnType<typeof createIsleController> | null>(null);
Expand Down Expand Up @@ -87,6 +88,30 @@ export default function Home() {
// @todo: this should redirect the user to the issuer's knownKYC provider
});

isleRef.current.on("view-credential-details", async ({ data }) => {
const credential = await isleRef.current?.viewCredentialDetails(data.id);
const enclave = new IframeEnclave({
container: "#idOS-enclave",
url: "https://localhost:5173/",
});

await enclave.load();
const user = await isleRef.current?.getUserProfile();
invariant(user, "No user profile found");

await enclave.ready(
user?.id,
address,
address, // @todo: remove public key as a parameter
user.recipient_encryption_public_key,
);
// @todo: use the credential content
const credentialContent = await enclave.decrypt(
credential?.content,
user.recipient_encryption_public_key,
);
});

isleRef.current.on("updated", async ({ data }) => {
switch (data.status) {
case "not-verified": {
Expand Down
30 changes: 27 additions & 3 deletions packages/@controllers/src/isle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
createKwilSigner,
createWebKwilClient,
getAllCredentials,
getSharedCredential,
getUserProfile as getUserProfileCore,
hasProfile,
type idOSCredential,
type idOSUser,
requestDWGSignature,
revokeAccessGrant,
} from "@idos-network/core";
Expand Down Expand Up @@ -95,14 +99,18 @@ interface idOSIsleController {
send: (type: IsleControllerMessage["type"], data: IsleControllerMessage["data"]) => void;
/** Subscribes to messages from the Isle iframe */
on: <T extends IsleNodeMessage["type"]>(type: T, handler: IsleMessageHandler<T>) => () => void;
/** Requests a delegated write grant for the given grantee */
/** Requests a `delegated write grant` for the given `grantee` */
requestDelegatedWriteGrant: (
options: RequestPermissionOptions,
) => Promise<{ signature: string; writeGrant: DelegatedWriteGrantSignatureRequest } | undefined>;
/** Requests an access grant for the given grantee */
/** Requests an access grant for the given `grantee` */
requestPermission: (options: RequestPermissionOptions) => Promise<void>;
/** Revokes an access grant for the given id */
/** Revokes an access grant for the given `id` */
revokePermission: (id: string) => Promise<unknown>;
/** View credential details for the given `id` */
viewCredentialDetails: (id: string) => Promise<idOSCredential>;
/** Get the user profile */
getUserProfile: () => Promise<idOSUser>;
}

// Singleton wagmi config instance shared across all Isle instances
Expand Down Expand Up @@ -241,6 +249,11 @@ export const createIsleController = (options: idOSIsleControllerOptions): idOSIs
return { signature, writeGrant: delegatedWriteGrant };
};

const getUserProfile = async (): Promise<idOSUser> => {
invariant(kwilClient, "No `KwilActionClient` found");
return getUserProfileCore(kwilClient);
};

/**
* Requests an access grant for the given grantee
*/
Expand Down Expand Up @@ -285,6 +298,15 @@ export const createIsleController = (options: idOSIsleControllerOptions): idOSIs
return result;
};

/**
* View credential details for the given `id`
*/
const viewCredentialDetails = async (id: string): Promise<idOSCredential> => {
invariant(kwilClient, "No `KwilActionClient` found");
const [credential] = await getSharedCredential(kwilClient, id);
return credential;
};

/**
* Sets up the communication channel with the Isle iframe
* Initializes message handlers and establishes the connection
Expand Down Expand Up @@ -565,5 +587,7 @@ export const createIsleController = (options: idOSIsleControllerOptions): idOSIs
requestDelegatedWriteGrant,
requestPermission,
revokePermission,
viewCredentialDetails,
getUserProfile,
};
};
9 changes: 9 additions & 0 deletions packages/@core/src/kwil-actions/user.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { idOSUser } from "..";
import type { KwilActionClient } from "./create-kwil-client";

/**
Expand All @@ -14,6 +15,14 @@ export async function hasProfile(kwilClient: KwilActionClient, address: string)
return has_profile;
}

export async function getUserProfile(kwilClient: KwilActionClient) {
const [user] = await kwilClient.call<[idOSUser]>({
name: "get_user",
inputs: {},
});
return user;
}

export interface CreateUserReqParams {
id: string;
recipient_encryption_public_key: string;
Expand Down
12 changes: 12 additions & 0 deletions packages/@core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ export type IsleControllerMessage =
};
KYCPermissions: string[];
};
}
| {
type: "credential-details";
data: {
credential: idOSCredential;
};
};

export type IsleNodeMessage =
Expand Down Expand Up @@ -166,6 +172,12 @@ export type IsleNodeMessage =
data: {
id: string;
};
}
| {
type: "view-credential-details";
data: {
id: string;
};
};

export type IsleMessageHandler<T extends IsleNodeMessage["type"]> = (
Expand Down