Skip to content

Commit

Permalink
Add SD-JWT and ZKP formats
Browse files Browse the repository at this point in the history
  • Loading branch information
Jdu278 authored Aug 9, 2024
1 parent 62b7271 commit d691cf3
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 64 deletions.
94 changes: 74 additions & 20 deletions components/PresentationForm.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
<template>
<div class="text-xl lg:text-3xl font-bold text-accent m-6 text-center">
<h1>Ihre Daten</h1>
<h1>Ausweisen</h1>
</div>
<div class="text-center border border-gray-400 rounded m-6 p-2">
<p class="m-2">Wählen Sie zuerst die Art der Übertragung:</p>
<div class="flex flex-row w-full text-sm items-center justify-center">
<div class="form-control flex-1 mx-1 lg:px-8">
<label class="label cursor-pointer">
<span class="label-text mr-1">mDoc</span>
<input v-model="formType" type="radio" name="formType" value="mDoc" class="radio checked:bg-blue-500">
</label>
</div>
<div class="form-control flex-1 mx-1">
<label class="label cursor-pointer">
<span class="label-text mr-1">SDJWT</span>
<input v-model="formType" type="radio" name="formType" value="SDJWT" class="radio checked:bg-blue-500">
</label>
</div>
<label class="flex items-center flex-1 mx-2">
<input v-model="isZkpSelected" type="checkbox" class="mr-2">
<span class="cursor-pointer">ZKP</span>
</label>
</div>
</div>
<div class="text-xl lg:text-xl font-bold text-accent m-6 text-center">
<h2>Ihre Daten</h2>
</div>
<div class="text-base text-black m-6 text-center">
<p>Wählen Sie hier die Daten, welche Sie übermitteln möchten.</p>
Expand Down Expand Up @@ -31,12 +55,14 @@

<script setup lang="ts">
import axios from 'axios';
import type {TransactionRequest} from "~/models/TransactionRequest.ts";
import {presentationInfo} from '~/models/PresentationInfo';
import type {Format, TransactionRequest, ZkpFormat} from "~/models/TransactionRequest.ts";
import {MDocClaims} from '~/models/MDocClaims';
import type {TransactionResponse} from "~/models/TransactionResponse";
import {ref} from "vue";
import {SdJwtClaims} from "~/models/SdJwtClaims";
const errorMessage = ref<string | null>(null);
const formType = ref<string>('mDoc');
const isZkpSelected = ref<boolean>(false);
const emit = defineEmits(['data-posted']);
const sessionStore = useSessionStore();
Expand All @@ -45,13 +71,50 @@ const runtimeConfig = useRuntimeConfig()
const baseUrl = runtimeConfig.public.apiUrl
const nonce = crypto.randomUUID()
const dataList = ref<{ kind: string, selected: boolean }[]>(Object.keys(presentationInfo).map(kind => ({
kind,
selected: false
})));
const dataList = computed(() => {
const claims = formType.value === 'mDoc' ? MDocClaims : SdJwtClaims;
return Object.keys(claims).map(kind => ({
kind,
selected: false
}));
});
const postData = async () => {
const selectedItems = dataList.value.filter(item => item.selected);
const alg: string[] = [
"ES256", "ES384", "ES512", "EdDSA",
"ESB256", "ESB320", "ESB384", "ESB512"
]
const format: Format = formType.value === 'mDoc' ? {
mso_mdoc: {
alg
}
} : {
vc_sd_jwt: {
alg
}
};
const zkpformat: ZkpFormat = formType.value === 'mDoc' ? {
"mso_mdoc+zkp": {
"proof_type": ["secp256r1-sha256"]
}
} : {
"vc+sd-jwt+zkp": {
"proof_type": ["secp256r1-sha256"]
}
}
function pathLayout(kind: string) {
if (formType.value === 'mDoc') {
return [`$['eu.europa.ec.eudi.pid.1']['${MDocClaims[kind]}']`]
} else {
return [`$.${SdJwtClaims[kind]}`]
}
}
const presentationRequest: TransactionRequest = {
nonce: nonce,
response_mode: 'direct_post',
Expand All @@ -63,33 +126,24 @@ const postData = async () => {
id: "eu.europa.ec.eudi.pid.1",
name: "EUDI PID",
purpose: "We need to verify your identity",
format: {
mso_mdoc: {
alg: [
"ES256", "ES384", "ES512", "EdDSA",
"ESB256", "ESB320", "ESB384", "ESB512"
]
}
},
format: isZkpSelected.value ? zkpformat : format,
constraints: {
fields: selectedItems.map(item => ({
path: [`$['eu.europa.ec.eudi.pid.1']['${presentationInfo[item.kind]}']`],
path: pathLayout(item.kind),
intent_to_retain: false
}))
}
}
],
},
};
try {
const response = await axios.post(`${baseUrl}/ui/presentations`, presentationRequest);
const {client_id, presentation_id, request_uri}: TransactionResponse = response.data;
sessionStore.setPresentationStore({client_id, presentation_id, request_uri, nonce});
emit('data-posted', {client_id, request_uri});
console.log('client_id: ', client_id);
emit('data-posted', { client_id, request_uri });
} catch (error) {
console.error('Error posting data:', error);
Expand Down
7 changes: 3 additions & 4 deletions components/QrCode.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-if="props.data" class="flex flex-col justify-center items-center gap-6">
<div v-if="props.qrCodeData" class="flex flex-col justify-center items-center gap-6">
<qrcode-vue :value="link" :level="level" :render-as="renderAs" :size="200" class="my-10"/>
<NuxtLink :to="link">
<button class="btn btn-primary">
Expand All @@ -17,10 +17,9 @@ const runtimeConfig = useRuntimeConfig()
const baseUrl = runtimeConfig.public.apiUrl
const props = defineProps<{
data: { client_id: string, request_uri: string }
qrCodeData: { client_id: string, request_uri: string }
}>();
const {client_id, request_uri} = props.data;
const {client_id, request_uri} = props.qrCodeData;
const authenticationUrl = `eudi-openid4vp://${baseUrl}?client_id=${client_id}&request_uri=${request_uri}`
const link = ref(authenticationUrl)
Expand Down
26 changes: 26 additions & 0 deletions models/MDocClaims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export type ClaimSignature = {
[key: string]: string;
}
export const MDocClaims: ClaimSignature = {
'Familienname': 'family_name',
'Geburtsname': 'family_name_birth',
'Geburtsdatum': 'birthdate',
'Alter in Geburtsjahren': 'age_birth_year',
'Alter in Jahren': 'age_in_years',
'Über 12': 'age_equal_or_over.12',
'Über 14': 'age_equal_or_over.14',
'Über 16': 'age_equal_or_over.16',
'Über 18': 'age_equal_or_over.18',
'Über 21': 'age_equal_or_over.21',
'Über 65': 'age_equal_or_over.65',
'Geburtsort': 'birth_place',
'Wohnland': 'resident_country',
'Wohnstadt': 'resident_city',
'Postleitzahl': 'resident_postal_code',
'Wohnstraße': 'resident_street',
'Nationalität': 'nationality',
'Ausstellungsdatum': 'issuance_date',
'Ablaufdatum': 'expiry_date',
'Ausstellungsland': 'issuing_country',
'Ausstellende Behörde': 'issuing_authority',
};
33 changes: 0 additions & 33 deletions models/PresentationInfo.ts

This file was deleted.

25 changes: 25 additions & 0 deletions models/SdJwtClaims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type {ClaimSignature} from "~/models/MDocClaims";

export const SdJwtClaims: ClaimSignature = {
'VCT': 'vct',
'Aussteller': 'iss',
'Name': 'given_name',
'Familienname': 'family_name',
'Geburtsname': 'birth_family_name',
'Geburtsdatum': 'birthdate',
'Alter in Geburtsjahren': 'age_birth_year',
'Alter in Jahren': 'age_in_years',
'Über 12': 'age_equal_or_over.12',
'Über 14': 'age_equal_or_over.14',
'Über 16': 'age_equal_or_over.16',
'Über 18': 'age_equal_or_over.18',
'Über 21': 'age_equal_or_over.21',
'Über 65': 'age_equal_or_over.65',
'Geburtsort': 'place_of_birth.locality',
'Wohnstadt': 'address.locality',
'Postleitzahl': 'address.postal_code',
'Wohnadresse': 'address.street_address',
'Nationalität': 'nationalities',
'Ausstellungsland': 'issuing_country',
'Ausstellende Behörde': 'issuing_authority',
};
19 changes: 16 additions & 3 deletions models/TransactionRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,29 @@ type InputDescriptor = {
id: string;
name: string;
purpose: string;
format: Format;
format: Format | ZkpFormat;
constraints: Constraint;
}

type Format = {
export type Format = {
mso_mdoc: {
alg: string[];
};
}
} | {
vc_sd_jwt: {
alg: string[];
}
}

export type ZkpFormat = {
"vc+sd-jwt+zkp": {
proof_type: string[];
}
} | {
"mso_mdoc+zkp": {
proof_type: string[];
}
}
type Constraint = {
fields: Field[];
}
Expand Down
8 changes: 4 additions & 4 deletions pages/provider.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<template>
<div>
<PresentationForm v-if="!qrCodeData" @data-posted="handleDataPosted"/>
<QrCode v-if="qrCodeData" :data="qrCodeData"/>
<PresentationForm v-if="!qrCodeData" @data-posted="handleDataPosted"/>
<QrCode v-if="qrCodeData" :qr-code-data="qrCodeData"/>
</div>
</template>

<script setup lang="ts">
import QrCode from "~/components/QrCode.vue";
import PresentationForm from "~/components/PresentationForm.vue";
const qrCodeData = ref<{client_id: string, request_uri: string} | null>(null);
const qrCodeData = ref<{ client_id: string, request_uri: string } | null>(null);
const handleDataPosted = (client_id: string, request_uri: string) => {
const handleDataPosted = ({client_id, request_uri}: {client_id: string, request_uri: string}) => {
qrCodeData.value = {client_id, request_uri};
};
</script>

0 comments on commit d691cf3

Please sign in to comment.