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

63 lit protocol 1 #68

Open
wants to merge 6 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
2,876 changes: 2,507 additions & 369 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"@iexec/dataprotector": "0.1.2",
"@iexec/web3mail": "0.5.1",
"@leap-ai/sdk": "^0.0.119",
"@lit-protocol/constants": "^4.1.1",
"@lit-protocol/lit-node-client": "^4.1.1",
"@lit-protocol/types": "^3.2.6",
"@talentlayer/client": "^0.1.6",
"@web3modal/ethereum": "^2.7.1",
"@web3modal/react": "^2.7.1",
Expand All @@ -20,6 +23,8 @@
"heroicons-react": "^1.4.1",
"ipfs-http-client": "^59.0.0",
"level-js": "^6.1.0",
"lit-siwe": "^1.1.8",
"moment": "^2.30.1",
"mongoose": "^7.4.2",
"next": "^13.5.5",
"next-pwa": "^5.6.0",
Expand Down Expand Up @@ -90,4 +95,4 @@
"engines": {
"node": ">=18.17"
}
}
}
197 changes: 191 additions & 6 deletions src/pages/dashboard/profile/edit/trust-score.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,90 @@
import { SparklesIcon } from '@heroicons/react/24/outline';
import Layout from '../../../../components/EditProfile/Layout';
import { useContext, useEffect, useState } from 'react';
import TalentLayerContext from '../../../../context/talentLayer';
import lit from '../../../../utils/lit';
import Loading from '../../../../components/Loading';
import { ICredential, ICredentialDetailsEncrypted } from '../../../../types';
import { useWalletClient } from 'wagmi';
import { AccessControlConditions } from '@lit-protocol/types';
import moment from 'moment';

function EditTrustScore() {
return (
<Layout>
<h2 className='text-white text-xl font-bold text-center my-4'>Comming soon</h2>
<div className='bg-gray-200 relative flex flex-1 items-center justify-center bg-gradient-to-br p-5 shadow-xl rounded-xl'>
const { user } = useContext(TalentLayerContext);
const [credential, setCredential] = useState<ICredential | null>(null);
const [loading, setLoading] = useState<Boolean>(true);
const [decryptedDatas, setDecryptedDatas] = useState(null);
const learnMoreLink = 'https://docs.talentlayer.org';
const { data: client } = useWalletClient();

// Use useEffect to set the initial state based on the user context
useEffect(() => {
const credentials = user?.description?.credentials ?? [];
if (credentials.length > 0) {
let firstCredential = credentials[0];
// Parse the AccessControlConditions JSON
const condition = firstCredential.credentialDetail.claimsEncrypted?.condition ?? null;
if (typeof condition === 'string') {
// @ts-ignore
firstCredential.credentialDetail.claimsEncrypted.condition = JSON.parse(condition);
}
// Handle claims and set state directly because we don't need to decrypt
const claims = firstCredential.credentialDetail.claims ?? null;
if (claims && claims.length > 0) {
const formattedClaims = formatClaims(claims);
setDecryptedDatas(formattedClaims);
}
// Set the first credential
setCredential(firstCredential);
}
setLoading(false);
}, [user]);

useEffect(() => {
(async () => {
await lit.connect();
})();
}, []);

async function decrypt(claimsEncrypted: ICredentialDetailsEncrypted): Promise<void> {
if (!client || !claimsEncrypted) return;
setLoading(true);

try {
const data = await lit.decrypt(
client,
claimsEncrypted.ciphertext,
claimsEncrypted.dataToEncryptHash,
claimsEncrypted.condition as AccessControlConditions,
);

const decryptedString = JSON.parse(data.decryptedString);
setDecryptedDatas(decryptedString);
} catch (error) {
console.log(error);
}

setLoading(false);
}

const DefaultDisplay = (): JSX.Element => {
return (
<>
<div className='relative z-20 flex flex-col gap-3'>
<p className=''>
<span className='text-gray-800'>
{' '}
Gain trust in the network
<br />
Certifiy your existing web3 reputation with blockchain
Certify your existing web3 reputation with blockchain
<br />
Preserve your privacy
<br />
</span>
</p>
<a
aria-current='page'
href='#'
href={learnMoreLink}
className='text-sm text-gray-800 underline-offset-4 underline'>
{' '}
Learn More{' '}
Expand All @@ -29,6 +93,127 @@ function EditTrustScore() {
<div className='absolute right-2 bottom-2 z-10 flex h-14 w-14 items-center justify-center text-redpraha'>
<SparklesIcon width={56} height={56} />
</div>
</>
);
};

const DecryptDisplay = (): JSX.Element => {
const claimsEncrypted = credential?.credentialDetail?.claimsEncrypted ?? undefined;
if (!credential) {
return <ErrorDisplay message="No credential found" learnMoreLink={learnMoreLink} />;
}
if (!claimsEncrypted) {
return <ErrorDisplay message="Credential found but without supported claims" learnMoreLink={learnMoreLink} />;
}
return (
<>
<div className='relative z-20 flex flex-col gap-3 w-full text-gray-800'>
<div className='grid grid-cols-3 gap-3 mt-3'>
{[...Array(Number(claimsEncrypted.total)).keys()].map(index => (
<div key={index} className='bg-white shadow-md p-4 rounded-lg'>
<div className='font-bold blur-sm'>Title example</div>
<div className='text-gray-500 text-lg blur-sm'>Text example</div>
</div>
))}
</div>
<p className='text-center'>
We found credentials on your profile
<br />
Do you want to decrypt them?
<br />
</p>
<button
className='text-smunderline-offset-4 underline'
onClick={() => {
decrypt(claimsEncrypted as ICredentialDetailsEncrypted);
}}>
{' '}
Decrypt{' '}
</button>
</div>
<div className='absolute right-2 bottom-2 z-10 flex h-14 w-14 items-center justify-center text-redpraha'>
<SparklesIcon width={56} height={56} />
</div>
</>
);
};

const formatClaims = (claims: any) => {
if (!claims) return;
claims.map((claim: any) => {
// format dates
const isDate = moment(claim.value, moment.ISO_8601, true).isValid();
if (isDate) {
claim.value = moment(claim.value).calendar();
}

// format value
try {
claim.value = JSON.parse(claim.value);
} catch (e) {} // catch silently
if (Array.isArray(claim.value)) {
claim.value = claim.value.join(", ");
}

// format condition
if (typeof claim.condition === "string") {
claim.condition = claim.condition.replace('==', '=');
}
})

return claims;

}

const ClaimsDecrypted = (claims: any): JSX.Element => {
const formattedClaims = formatClaims(claims.claimsDecrypted);
if (!formattedClaims) {
return <div>No claims found</div>;
}

return (
<div className='relative z-20 flex flex-col gap-3 w-full text-gray-800'>
<h2 className='text-xl font-bold text-center my-4'>Decrypted Claims</h2>
<div className='grid grid-cols-3 gap-3 mt-3'>
{formattedClaims.map((claim, index: number) => (
<div key={index} className='bg-white shadow-md p-4 rounded-lg'>
<div className='font-bold'>{claim.criteria}</div>
<div className='text-gray-500 text-lg'>
{claim.condition}{" "}
{claim.value}
</div>
</div>
))}
</div>
</div>
);
};

const ErrorDisplay = ({ message, learnMoreLink }: { message: string, learnMoreLink?: string }): JSX.Element => {
return (
<div className='text-gray-800'>
{message}
<a
aria-current='page'
href={learnMoreLink}
className='text-sm text-gray-800 underline-offset-4 underline'>
{' '}
Learn More{' '}
</a>
</div>
);
};

return (
<Layout>
<h2 className='text-white text-xl font-bold text-center my-4'>Trust score</h2>
<div className='bg-gray-200 relative flex flex-1 items-center justify-center bg-gradient-to-br p-5 shadow-xl rounded-xl'>
{loading && <Loading />}
{!loading && !credential && <DefaultDisplay />}
{!loading && credential && !decryptedDatas && <DecryptDisplay />}
{!loading && credential && decryptedDatas && (
<ClaimsDecrypted claimsDecrypted={decryptedDatas} />
)}
</div>
</Layout>
);
Expand Down
50 changes: 50 additions & 0 deletions src/queries/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,31 @@ export const getUserById = (chainId: number, id: string): Promise<any> => {
activeOnPlatformMarketing
activeOnProtocolMarketing
}
credentials {
issuer
signature1
signature2
credentialDetail {
author
platform
description
issueTime
expiryTime
userAddress
claims {
platform
criteria
condition
value
}
claimsEncrypted{
total
ciphertext
dataToEncryptHash
condition
}
}
}
}
}
}
Expand Down Expand Up @@ -105,6 +130,31 @@ export const getUserByAddress = (chainId: number, address: string): Promise<any>
activeOnPlatformMarketing
activeOnProtocolMarketing
}
credentials {
issuer
signature1
signature2
credentialDetail {
author
platform
description
issueTime
expiryTime
userAddress
claims {
platform
criteria
condition
value
}
claimsEncrypted{
total
ciphertext
dataToEncryptHash
condition
}
}
}
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Connector } from 'wagmi';
import { AccessControlConditions, EvmContractConditions } from "@lit-protocol/types";

export type IHive = {
id: string;
Expand Down Expand Up @@ -40,8 +41,45 @@ export type IUserDetails = {
skills_raw?: string;
user: IUser;
web3mailPreferences?: IWeb3mailPreferences;
credentials?: ICredential[];
};

export type ICredential = {
id: string;
issuer: string;
signature1: string;
signature2: string;
credentialDetail: ICredentialDetails;
}

export type ICredentialDetails = {
id: string;
author: string;
platform: string;
description: string;
issueTime: string;
expiryTime: string;
userAddress: string;
claims?: IClaim[];
claimsEncrypted?: ICredentialDetailsEncrypted;
}

export type IClaim = {
id: string;
platform: string;
criteria: string;
condition: string;
value: any;
}

export type ICredentialDetailsEncrypted = {
id: string;
ciphertext: string;
dataToEncryptHash: string;
total: number;
condition: EvmContractConditions | AccessControlConditions | String; // it's actually a AccessControlConditions encoded as a json string
}

export type IWeb3mailPreferences = {
activeOnNewService: boolean;
activeOnNewProposal: boolean;
Expand Down
Loading