Skip to content

Commit

Permalink
Integration the QR code, revoction list 2020 and encrypted storage pl…
Browse files Browse the repository at this point in the history
…ugins (#138)

<!--
  For Work In Progress Pull Requests, please use the Draft PR feature,
see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for
further details.
  
  For a timely review/response, please avoid force-pushing additional
  commits if your PR already received reviews or comments.
  
Before submitting a Pull Request, please ensure you've done the
following:
- 📖 Read the [Contributing
Guide](https://github.com/uncefact/project-vckit/blob/main/CONTRIBUTING.md).
- 📖 Read the [Code of
Conduct](https://github.com/uncefact/project-vckit/blob/main/CODE_OF_CONDUCT.md).
  - 👷‍♀️ Create small PRs. In most cases, this will be possible.
  - ✅ Provide tests for your changes.
- 📝 Use descriptive commit messages following [conventional
commits](https://www.conventionalcommits.org/en/v1.0.0/).
- 📗 Update any related documentation and include any relevant
screenshots.
-->

## What type of PR is this? (check all applicable)

- [ ] 🍕 Feature
- [ ] 🐛 Bug Fix
- [ ] 📝 Documentation Update
- [ ] 🎨 Style
- [ ] 🧑‍💻 Code Refactor
- [ ] 🔥 Performance Improvements
- [ ] ✅ Test
- [ ] 🤖 Build
- [ ] 🔁 CI
- [ ] 📦 Chore (Release)
- [ ] ⏩ Revert

## Description

<!-- 
Please do not leave this blank 
This PR [adds/removes/fixes/replaces] the [feature/bug/etc]. 
-->

## Related Tickets & Documents
<!-- 
Please use this format link issue numbers: Fixes #123

https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword
-->

## Mobile & Desktop Screenshots/Recordings

<!-- Visual changes require screenshots -->


## Added tests?

- [ ] 👍 yes
- [ ] 🙅 no, because they aren't needed
- [ ] 🙋 no, because I need help

## Added to documentation?

- [ ] 📜 README.md
- [ ] 📓 [vc-kit doc site](https://uncefact.github.io/vckit/)
- [ ] 📕 storybook
- [ ] 🙅 no documentation needed

## [optional] Are there any post-deployment tasks we need to perform?


<!-- note: PRs with deleted sections will be marked invalid -->

---------

Signed-off-by: Nam Hoang <[email protected]>
Co-authored-by: Hoa Ngo <[email protected]>
  • Loading branch information
namhoang1604 and hoa-ngo-gs committed Aug 7, 2023
1 parent 094cd19 commit 59fb8a5
Show file tree
Hide file tree
Showing 30 changed files with 1,490 additions and 632 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ website/node_modules
**/build/
**/*.log
/packages/*/build/
/packages/*/lib/
/packages/*/api/*.api.json
/packages/*/api/*.api.md
/packages/*/coverage/
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@vckit/revocationlist": "workspace:*",
"@vckit/encrypted-storage": "workspace:*",
"@veramo/core": "5.2.0",
"@veramo/credential-status": "5.2.0",
"@veramo/credential-eip712": "5.2.0",
"@veramo/credential-ld": "5.2.0",
"@veramo/credential-w3c": "5.2.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/core-types/src/types/IRevocationList2020.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { IPluginMethodMap, IAgent } from './IAgent.js';
import { Request } from 'express';
import { CredentialStatus, VerifiableCredential } from './vc-data-model.js';

/**
* @public
*/
export interface RequestWithAgent extends Request {
agent?: IAgent;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core-types/src/types/vc-data-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export enum RenderingType {
* @beta This API may change without prior notice.
*/
export interface RenderMethodPayload {
'@id': string;
'@id'?: string;
'@type': RenderingType;

[x: string]: any; // Additional properties can be added dynamically
Expand Down
10 changes: 7 additions & 3 deletions packages/demo-explorer/craco.config.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
const webpack = require('webpack')
const path = require('path');
const path = require('path')

const ouputDir = process.env.REACT_APP_MODE === 'verifier' ? 'build/verifier' : 'build/explorer';
const ouputDir =
process.env.REACT_APP_MODE === 'verifier'
? 'build/verifier'
: 'build/explorer'

module.exports = {
babel: {
plugins: ['@babel/plugin-syntax-import-assertions'],
},
webpack: {
configure: (webpackConfig, { env, paths }) => {
paths.appBuild = webpackConfig.output.path = path.resolve(ouputDir);
paths.appBuild = webpackConfig.output.path = path.resolve(ouputDir)
webpackConfig.resolve.fallback = {
...webpackConfig.resolve.fallback,
http: require.resolve('stream-http'),
url: require.resolve('url/'),
zlib: require.resolve('browserify-zlib'),
https: require.resolve('https-browserify'),
fs: false,
}
/* ... */
return webpackConfig
Expand Down
6 changes: 5 additions & 1 deletion packages/demo-explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@
]
},
"dependencies": {
"@govtechsg/oa-encryption": "^1.3.5",
"@jsonforms/material-renderers": "^3.1.0",
"@jsonforms/react": "^3.1.0",
"@vckit/example-documents": "workspace:^1.0.0-beta.4",
"@veramo/remote-client": "5.2.1-next.5",
"@vckit/react-components": "workspace:^*",
"@vckit/renderer": "workspace:^*",
"commander": "^10.0.1",
"express": "^4.18.2",
"express-favicon": "^2.0.4"
"express-favicon": "^2.0.4",
"html2canvas": "^1.4.1"
},
"release": {
"branches": [
Expand Down
58 changes: 55 additions & 3 deletions packages/demo-explorer/src/components/AgentDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,65 @@
import { Dropdown } from 'antd'
import React from 'react'
import React, { useEffect, useState } from 'react'
import { useVeramo } from '@veramo-community/veramo-react'
import { useNavigate } from 'react-router-dom'
import { CheckCircleOutlined } from '@ant-design/icons'
import { useQuery } from 'react-query'

const AgentDropdown: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const { agents, setActiveAgentId, activeAgentId } = useVeramo()
const { agents, setActiveAgentId, activeAgentId, addAgentConfig } =
useVeramo()
const navigate = useNavigate()

const schemaUrl = process.env.REACT_APP_SCHEMA_URL
const apiKey = process.env.REACT_APP_REMOTE_AGENT_API_KEY
const defaultAgentId = process.env.REACT_APP_DEFAULT_AGENT_ID || ''
const [agentUrl, setAgentUrl] = useState<string>('')

const { data: schema } = useQuery(
['schema', { endpoint: schemaUrl }],
async () => {
if (schemaUrl) {
const response = await fetch(schemaUrl)
return await response.json()
}
},
{
enabled: !!schemaUrl,
},
)

useEffect(() => {
if (schema) {
setAgentUrl(schema.servers[0].url)
}
}, [schema])

useEffect(() => {
if (agents) {
const existingAgent = agents.find(
(_agent: any) => _agent.context?.id === defaultAgentId,
)
if (!existingAgent) {
if (schema && agentUrl && schemaUrl) {
addAgentConfig({
context: { id: defaultAgentId, name: 'Agent', schema: schemaUrl },
remoteAgents: [
{
url: agentUrl,
enabledMethods: Object.keys(schema['x-methods']),
token: apiKey,
},
],
})
setActiveAgentId(defaultAgentId)
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [agents, schema, agentUrl, apiKey, schemaUrl])

return (
<Dropdown
menu={{
Expand All @@ -23,7 +73,9 @@ const AgentDropdown: React.FC<{ children: React.ReactNode }> = ({
style={{
fontSize: '17px',
opacity: _agent.context?.id === activeAgentId ? 1 : 0.1,
}} rev={undefined} />
}}
rev={undefined}
/>
),
label: _agent.context?.name,
}
Expand Down
172 changes: 130 additions & 42 deletions packages/demo-explorer/src/components/CredentialInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,153 @@
import React from 'react'
import { Descriptions } from 'antd'
import React, { useCallback, useEffect, useState } from 'react'
import { Alert, Button, Descriptions, Spin } from 'antd'
import { VerifiableCredential } from '@veramo/core'
import { format } from 'date-fns'
import { useVeramo } from '@veramo-community/veramo-react'

interface CredentialInfoProps {
credential: VerifiableCredential
hash: string
}

interface TableRow {
key: string
value: string
}

const CredentialInfo: React.FC<CredentialInfoProps> = ({ credential }) => {
if (!credential) return null
const CredentialInfo: React.FC<CredentialInfoProps> = ({
credential,
hash,
}) => {
const { agent } = useVeramo()
const [credentialData] = useState<any>(credential)
const [data, setData] = useState<Array<TableRow>>([])
const [loading, setLoading] = useState(false)
const [revoked, setRevoked] = useState(false)
const [errorMessage, setErrorMessage] = useState<null | string>()

const data: Array<TableRow> = []
const fetchVCStatus = useCallback(async () => {
setLoading(true)
await checkVCStatus({ hash })
setLoading(false)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hash])

for (const key in credential.credentialSubject) {
let value = credential.credentialSubject[key]
value = typeof value === 'string' ? value : JSON.stringify(value)
data.push({ key, value })
useEffect(() => {
setData([])
for (const key in credentialData.credentialSubject) {
let value = credentialData.credentialSubject[key]
value = typeof value === 'string' ? value : JSON.stringify(value)
setData((d) => [...d, { key, value }])
}
fetchVCStatus()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [credentialData])

if (!credential || !hash) return null

const revoke = async () => {
setLoading(true)
try {
const { revoked: vcRevoked } = await agent?.revokeCredential({ hash })
setRevoked(vcRevoked || false)
} catch (e: any) {
console.log(e)
setErrorMessage(e.message + ' Please refresh the page and try again.')
}
setLoading(false)
}

const activate = async () => {
setLoading(true)
try {
const { revoked: vcRevoked } = await agent?.activateCredential({ hash })
setRevoked(vcRevoked || false)
} catch (e: any) {
console.log(e)
setErrorMessage(e.message + ' Please refresh the page and try again.')
}
setLoading(false)
}

const checkVCStatus = async (args: { hash: string }) => {
const { revoked: vcRevoked } = await agent?.checkStatus(args)

setRevoked(vcRevoked || false)
}

return (
<>
<Descriptions
bordered
column={{ xxl: 2, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }}
>
<Descriptions.Item label="Type">
{(credential.type as string[]).join(',')}
</Descriptions.Item>
<Descriptions.Item label="Context">
{(credential['@context'] as string[]).join(',')}
</Descriptions.Item>
<Descriptions.Item label="Issuer">
{(credential.issuer as { id: string }).id as string}
</Descriptions.Item>
<Descriptions.Item label="Issuance date">
{format(new Date(credential.issuanceDate), 'PPP')}
</Descriptions.Item>
<Descriptions.Item label="Proof type">
{credential.proof.type}
</Descriptions.Item>
<Descriptions.Item label="Id">{credential.id}</Descriptions.Item>
</Descriptions>
<Spin spinning={loading} tip="Loading...">
<>
<Descriptions
bordered
column={{ xxl: 2, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }}
>
<Descriptions.Item label="Type">
{(credentialData.type as string[]).join(',')}
</Descriptions.Item>
<Descriptions.Item label="Context">
{(credentialData['@context'] as string[]).join(',')}
</Descriptions.Item>
<Descriptions.Item label="Issuer">
{(credentialData.issuer as { id: string }).id as string}
</Descriptions.Item>
<Descriptions.Item label="Issuance date">
{format(new Date(credentialData.issuanceDate), 'PPP')}
</Descriptions.Item>
<Descriptions.Item label="Proof type">
{credentialData.proof.type}
</Descriptions.Item>
<Descriptions.Item label="Id">{credentialData.id}</Descriptions.Item>
</Descriptions>

<br />
<br />

<Descriptions
bordered
column={{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }}
>
{data.map((i) => (
<Descriptions.Item label={i.key} key={i.key}>
{i.value}
<Descriptions
bordered
column={{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }}
>
{data.map((i) => (
<Descriptions.Item label={i.key} key={i.key}>
{i.value}
</Descriptions.Item>
))}
<Descriptions.Item label="Status">
{revoked ? 'Revoked' : 'Active'}
</Descriptions.Item>
))}
</Descriptions>
</>
</Descriptions>
<br />

{revoked ? (
<Button
type="primary"
onClick={() => {
activate()
}}
disabled={loading}
>
Active
</Button>
) : (
<Button
danger
type="primary"
onClick={() => {
revoke()
}}
disabled={loading}
>
Revoke
</Button>
)}
{errorMessage && (
<>
<br />
<br />
<Alert message={errorMessage} type="error" />
</>
)}
</>
</Spin>
)
}

Expand Down
Loading

0 comments on commit 59fb8a5

Please sign in to comment.