Skip to content

Commit

Permalink
feat: add certificates
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra committed Nov 24, 2024
1 parent c015e41 commit afd2f2c
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 3 deletions.
27 changes: 27 additions & 0 deletions agent/src/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
RecordNotFoundError,
W3cJsonLdVerifiablePresentation,
W3cJwtVerifiablePresentation,
X509Certificate,
X509ModuleConfig,
getJwkFromKey,
} from '@credo-ts/core'
import { OpenId4VcVerificationSessionState } from '@credo-ts/openid4vc'
Expand All @@ -30,6 +32,10 @@ const zCreateOfferRequest = z.object({
issuerId: z.string(),
})

const zAddX509CertificateRequest = z.object({
certificate: z.string(),
})

export const apiRouter = express.Router()

apiRouter.use(express.json())
Expand Down Expand Up @@ -80,6 +86,27 @@ apiRouter.get('/x509', async (_, response: Response) => {
})
})

apiRouter.post('/x509', async (request: Request, response: Response) => {
const addX509CertificateRequest = zAddX509CertificateRequest.parse(request.body)

const trustedCertificates = agent.dependencyManager.resolve(X509ModuleConfig).trustedCertificates
try {
const instance = X509Certificate.fromEncodedCertificate(addX509CertificateRequest.certificate)
const base64 = instance.toString('base64')

if (!trustedCertificates?.includes(base64)) {
await agent.x509.addTrustedCertificate(base64)
}

return response.send(instance.toString('text'))
} catch (error) {
return response.status(500).json({
errorMessage: 'error adding x509 certificate',
error,
})
}
})

apiRouter.get('/issuer', async (_, response: Response) => {
return response.json({
credentialsSupported: issuers.flatMap((i) =>
Expand Down
91 changes: 91 additions & 0 deletions app/components/X509Tab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Label } from '@/components/ui/label'
import { CheckboxIcon, ExclamationTriangleIcon, InfoCircledIcon } from '@radix-ui/react-icons'
import { type FormEvent, useState } from 'react'
import { addX509Certificate } from '../lib/api'
import { Alert, AlertDescription, AlertTitle } from './ui/alert'
import { HighLight } from './highLight'

export function X509Tab() {
const [x509Certificate, setX509Certificate] = useState<string>()
const [response, setResponse] = useState<{ success: true; body: string } | { success: false; error: any }>()

async function onSubmitX509Certificate(e: FormEvent) {
e.preventDefault()

setResponse(undefined)
if (!x509Certificate) return
try {
const response = await addX509Certificate(x509Certificate)
console.log(response.ok)
if (response.ok) {
setResponse({ success: true, body: await response.text() })
} else {
setResponse({ success: false, error: await response.json().catch(() => 'Unkonwn parsing error') })
}
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
} catch (error: any) {
setResponse({
success: false,
error: error.message,
})
}
}

return (
<Card className="p-6">
<Alert variant="default" className="mb-5">
<InfoCircledIcon className="h-4 w-4" />
<AlertTitle>Info</AlertTitle>
<AlertDescription>
This playground was built in the context for the{' '}
<a className="underline" href="https://www.sprind.org/en/challenges/eudi-wallet-prototypes/">
EUDI Wallet Prototype Funke
</a>
. It is only compatible with the current deployed version of{' '}
<a className="underline" href="https://github.com/animo/paradym-wallet/tree/main/apps/easypid">
Animo&apos;s EUDI Wallet Prototype
</a>
.
</AlertDescription>
</Alert>
<form className="space-y-4" onSubmit={onSubmitX509Certificate}>
<div className="space-y-2">
<Label htmlFor="x509-certificate">X509 Certificate (PEM or Base64)</Label>
<textarea
className="w-full h-40 p-2 rounded-md bg-white border border-gray-300"
id="x509-certificate"
required
onChange={(e) => setX509Certificate(e.currentTarget.value)}
/>
</div>
{/* <div className="flex justify-center items-center bg-gray-200 min-h-64 w-full rounded-md"> */}
{response ? (
<Alert variant={response.success ? 'success' : 'warning'}>
{response.success ? <CheckboxIcon className="h-5 w-5" /> : <ExclamationTriangleIcon className="h-4 w-4" />}
<AlertTitle className={response.success ? 'mt-0.5' : ''}>
{response.success ? 'Succesfully added X509 certificate' : 'Error adding X509 certificate'}
</AlertTitle>
{!response.success && (
<AlertDescription className="mt-2">
{response.error ? JSON.stringify(response.error, null, 2) : 'Unknown error occurred'}
</AlertDescription>
)}
{response.success && (
<AlertDescription className="mt-2">
<HighLight code={response.body} language="text" />
</AlertDescription>
)}
</Alert>
) : (
<p className="text-gray-500">X509 Certificates will be reset on every server restart and deployment.</p>
)}
{/* </div> */}
<Button className="w-full" onClick={onSubmitX509Certificate} onSubmit={onSubmitX509Certificate}>
Add X509 Certificate
</Button>
</form>
</Card>
)
}
11 changes: 8 additions & 3 deletions app/components/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { GitHubLogoIcon } from '@radix-ui/react-icons'
import { IssueTab } from './IssueTab'
import { ReceiveTab } from './ReceiveTab'
import { VerifyTab } from './VerifyTab'
import { X509Tab } from './X509Tab'

export function Main() {
return (
Expand All @@ -31,17 +32,21 @@ export function Main() {
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="verify">Verify</TabsTrigger>
<TabsTrigger value="issue">Issue</TabsTrigger>
<TabsTrigger value="receive">Receive</TabsTrigger>
<TabsTrigger value="x509">Manage Certificates</TabsTrigger>
{/* <TabsTrigger value="receive">Receive</TabsTrigger> */}
</TabsList>
<TabsContent value="verify">
<VerifyTab />
</TabsContent>
<TabsContent value="issue">
<IssueTab />
</TabsContent>
<TabsContent value="receive">
<ReceiveTab disabled />
<TabsContent value="x509">
<X509Tab />
</TabsContent>
{/* <TabsContent value="receive">
<ReceiveTab disabled />
</TabsContent> */}
</Tabs>
</div>
<footer className="flex items-center justify-center w-full p-4 gap-8">
Expand Down
14 changes: 14 additions & 0 deletions app/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ export async function getIssuer() {
return response.json()
}

export async function addX509Certificate(certificate: string) {
const response = await fetch(`${NEXT_PUBLIC_API_URL}/api/x509`, {
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
body: JSON.stringify({
certificate,
}),
})

return response
}

export async function getX509Certificate() {
const response = await fetch(`${NEXT_PUBLIC_API_URL}/api/x509`)

Expand Down

0 comments on commit afd2f2c

Please sign in to comment.