Skip to content

Commit dcffc78

Browse files
committed
Updated ehic and pda1 definitions
1 parent d683f9d commit dcffc78

7 files changed

Lines changed: 92 additions & 197 deletions

File tree

src/app/core/constants/attestation-definitions.ts

Lines changed: 14 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -131,149 +131,29 @@ export const EHIC_ATTESTATION: AttestationDefinition = {
131131
name: "European Health Insurance Card (EHIC)",
132132
type: AttestationType.EHIC,
133133
dataSet: [
134-
{
135-
identifier: "credential_holder",
136-
attribute: "Credential holder",
137-
nested: [
138-
{ identifier: "credential_holder.given_name", attribute: "Given name" },
139-
{ identifier: "credential_holder.family_name", attribute: "Family name" },
140-
{ identifier: "credential_holder.birth_date", attribute: "Birth date" },
141-
{ identifier: "credential_holder.other_elements", attribute: "Other elements" },
142-
],
143-
},
144-
{
145-
identifier: "subject",
146-
attribute: "Subject",
147-
nested: [
148-
{ identifier: "subject.given_name", attribute: "Given name" },
149-
{ identifier: "subject.family_name", attribute: "Family name" },
150-
{ identifier: "subject.birth_date", attribute: "Birth date" },
151-
],
152-
},
153-
{ identifier: 'social_security_pin', attribute: 'Social Security Identification/PIN'},
154-
{
155-
identifier: "validity_period",
156-
attribute: "Validity period",
157-
nested: [
158-
{ identifier: "validity_period.starting_date", attribute: "Starting date" },
159-
{ identifier: "validity_period.ending_date", attribute: "Ending date" },
160-
],
161-
},
162-
{ identifier: 'document_id', attribute: 'Document Identifier'},
163-
{
164-
identifier: "competentInstitution",
165-
attribute: "Competent institution",
166-
nested: [
167-
{ identifier: "competentInstitution.institution_id", attribute: "Institution ID" },
168-
{ identifier: "competentInstitution.institution_name", attribute: "Institution name" },
169-
{ identifier: "competentInstitution.country_code", attribute: "Country code" },
170-
],
171-
},
134+
{ identifier: "credential_holder", attribute: "Credential holder" },
135+
{ identifier: "subject", attribute: "Subject" },
136+
{ identifier: 'social_security_pin', attribute: 'Social Security PIN'},
137+
{ identifier: "starting_date", attribute: "Starting Date" },
138+
{ identifier: "ending_date", attribute: "Ending Date" },
139+
{ identifier: 'document_id', attribute: 'Document Identifier' },
140+
{ identifier: "competent_institution", attribute: 'Competent Institution' }
172141
],
173142
}
174143

175144
export const PDA1_ATTESTATION: AttestationDefinition = {
176145
name: "Portable Document A1 (PDA1)",
177146
type: AttestationType.PDA1,
178147
dataSet: [
179-
{
180-
identifier: "credential_holder",
181-
attribute: "Credential holder",
182-
nested: [
183-
{ identifier: "credential_holder.given_name", attribute: "Given name" },
184-
{ identifier: "credential_holder.family_name", attribute: "Family name" },
185-
{ identifier: "credential_holder.birth_date", attribute: "Birth date" },
186-
{ identifier: "credential_holder.other_elements", attribute: "Other elements" },
187-
],
188-
},
189-
{ identifier: 'social_security_pin', attribute: 'Social Security Identification/PIN'},
190-
{
191-
identifier: "nationality",
192-
attribute: "Nationality",
193-
nested: [
194-
{ identifier: "nationality.country_code", attribute: "Country code" },
195-
],
196-
},
197-
{
198-
identifier: "employment_details",
199-
attribute: "Employment details",
200-
nested: [
201-
{ identifier: "employment_details.type", attribute: "Type of employment" },
202-
{ identifier: "employment_details.name", attribute: "Name" },
203-
{ identifier: "employment_details.employer_id", attribute: "Employer ID" },
204-
{ identifier: "employment_details.type_id", attribute: "Type of ID" },
205-
{
206-
identifier: "address",
207-
attribute: "Address",
208-
nested: [
209-
{ identifier: "address.street", attribute: "Street" },
210-
{ identifier: "address.town", attribute: "Town" },
211-
{ identifier: "address.postal_code", attribute: "Postal code" },
212-
{ identifier: "address.country_code", attribute: "Country code" },
213-
],
214-
},
215-
],
216-
},
217-
{
218-
identifier: 'places_of_work',
219-
attribute: 'Places of work',
220-
nested: [
221-
{
222-
identifier: "no_fixed_place",
223-
attribute: "No fixed place of work",
224-
nested: [
225-
{ identifier: "no_fixed_place.country_code", attribute: "Country code" },
226-
],
227-
},
228-
{
229-
identifier: "place_of_work",
230-
attribute: "Place of work",
231-
nested: [
232-
{ identifier: "place_of_work.company", attribute: "Company" },
233-
{ identifier: "place_of_work.flag_base_home_state", attribute: "Flag base home state" },
234-
{ identifier: "place_of_work.company_id", attribute: "Company ID" },
235-
{ identifier: "place_of_work.id_type", attribute: "Type of ID" },
236-
{ identifier: "place_of_work.street", attribute: "Street" },
237-
{ identifier: "place_of_work.town", attribute: "Town" },
238-
{ identifier: "place_of_work.postal_code", attribute: "Postal code" },
239-
{ identifier: "place_of_work.country_code", attribute: "Country code" },
240-
],
241-
},
242-
]
243-
},
244-
{
245-
identifier: 'legislation',
246-
attribute: 'Legislation',
247-
nested: [
248-
{
249-
identifier: "decision",
250-
attribute: "Decision",
251-
nested: [
252-
{ identifier: "decision.member_state", attribute: "Member state" },
253-
{ identifier: "decision.transitional_rules", attribute: "Transitional rules" },
254-
],
255-
},
256-
{
257-
identifier: "validity_period",
258-
attribute: "Validity period",
259-
nested: [
260-
{ identifier: "validity_period.starting_date", attribute: "Staring date" },
261-
{ identifier: "validity_period.ending_date", attribute: "Ending date" },
262-
],
263-
},
264-
]
265-
},
148+
{ identifier: "credential_holder", attribute: "Credential holder" },
149+
{ identifier: 'social_security_pin', attribute: 'Social Security Identification/PIN' },
150+
{ identifier: "nationality", attribute: "Nationality" },
151+
{ identifier: "employment_details", attribute: "Employment details" },
152+
{ identifier: 'places_of_work', attribute: 'Places of work' },
153+
{ identifier: 'legislation', attribute: 'Legislation' },
266154
{ identifier: 'status_confirmation', attribute: 'Status confirmation'},
267155
{ identifier: 'document_id', attribute: 'Document Identifier'},
268-
{
269-
identifier: "competentInstitution",
270-
attribute: "Competent institution",
271-
nested: [
272-
{ identifier: "competentInstitution.institution_id", attribute: "Institution ID" },
273-
{ identifier: "competentInstitution.institution_name", attribute: "Institution name" },
274-
{ identifier: "competentInstitution.country_code", attribute: "Country code" },
275-
],
276-
},
156+
{ identifier: "competent_institution", attribute: "Competent institution"},
277157
]
278158
}
279159

src/app/core/constants/attestations-per-format.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const EHIC_MSO_MDOC: MsoMdocAttestation = {
6868
export const EHIC_SD_JWT_VC: SdJwtVcAttestation = {
6969
format: AttestationFormat.SD_JWT_VC,
7070
attestationDef: EHIC_ATTESTATION,
71-
vct: 'eu.europa.ec.eudi.ehic.1',
71+
vct: 'urn:eu.europa.ec.eudi:ehic:1',
7272
attributePath: (attribute: DataElement) => { return `$.${sdJwtVcAttributePath(attribute, AttestationType.EHIC)}` },
7373
claimPath: (attribute: DataElement) => { return { path: sdJwtVcAttributePath(attribute, AttestationType.EHIC).split('.') } }
7474
}
@@ -85,7 +85,7 @@ export const PDA1_MSO_MDOC: MsoMdocAttestation = {
8585
export const PDA1_SD_JWT_VC: SdJwtVcAttestation = {
8686
format: AttestationFormat.SD_JWT_VC,
8787
attestationDef: PDA1_ATTESTATION,
88-
vct: 'eu.europa.ec.eudi.pda1.1',
88+
vct: 'urn:eu.europa.ec.eudi:pda1:1',
8989
attributePath: (attribute: DataElement) => { return `$.${sdJwtVcAttributePath(attribute, AttestationType.PDA1)}` },
9090
claimPath: (attribute: DataElement) => { return { path: sdJwtVcAttributePath(attribute, AttestationType.PDA1).split('.') } }
9191
}

src/app/core/services/decoders/DecodingUtils.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,6 @@
1-
21
export function elementAsString(element: any, prepend?: string): string {
3-
if ((typeof element) === "object") {
4-
5-
if (Array.isArray(element)) {
6-
return (element as string[]).map((it) => {
7-
return JSON.stringify(it);
8-
}).join(', ')
9-
10-
} else {
11-
let str = ""
12-
if (typeof prepend !== 'undefined') {
13-
str += "<br/>"
14-
} else {
15-
prepend = ""
16-
}
17-
return str + Object.keys(element).map((it) => {
18-
return prepend + "&nbsp;&nbsp;" + it + ": " + elementAsString(element[it], "&nbsp;&nbsp;").toString()
19-
}).join("<br/>");
20-
}
21-
2+
if (typeof element === 'object') {
3+
return JSON.stringify(element);
224
} else {
235
return element.toString();
246
}

src/app/core/services/decoders/JwtVcJsonAttestationDecoder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@ export class JwtVcJsonAttestationDecoder implements AttestationDecoder {
2929
let sharedCredentials = this.unWrapCredentials(vp)
3030

3131
if (sharedCredentials.length == 1) {
32-
return of(this.toSinge(sharedCredentials[0]))
32+
return of(this.toSingle(sharedCredentials[0]))
3333

3434
} else {
35-
let singles = sharedCredentials.map(it => this.toSinge(it));
35+
let singles = sharedCredentials.map(it => this.toSingle(it));
3636
return of({
3737
kind: "enveloped",
3838
attestations: singles
3939
})
4040
}
4141
}
4242

43-
toSinge(vcJwt: string): Single {
43+
toSingle(vcJwt: string): Single {
4444
let vc = this.jWTService.decodeToObject(vcJwt) as any;
4545
return {
4646
kind: "single",

src/app/features/invoke-wallet/components/view-attestation/view-attestation.component.html

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,60 @@ <h2 mat-dialog-title>{{attestation.name}}</h2>
33
<mat-dialog-content class="mat-typography">
44
<mat-tab-group>
55
<mat-tab label="Attributes">
6+
<!-- Main attribute list -->
67
<mat-list>
7-
<mat-list-item *ngFor="let option of attestation.attributes; trackBy: trackByFn">
8-
<span matListItemTitle>
9-
<strong>{{option.key}}</strong>
10-
</span>
11-
<span matListItemLine>
12-
<ng-container *ngIf="isJson(option.value); else plainText">
13-
<!-- Recursive template for nested JSON -->
14-
<ng-container *ngTemplateOutlet="recursiveJson; context:{ $implicit: parseJson(option.value), level: 0 }"></ng-container>
15-
</ng-container>
16-
<ng-template #plainText>
17-
<span>{{option.value}}</span>
18-
</ng-template>
19-
</span>
20-
</mat-list-item>
8+
<ng-container *ngFor="let option of attestation.attributes; trackBy: trackByFn">
9+
<mat-list-item>
10+
<span matListItemTitle>
11+
<strong>{{option.key}}</strong>
12+
</span>
13+
<span matListItemLine style="display: flex">
14+
<ng-container *ngIf="isJson(option.value); else plainText">
15+
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: parseJson(option.value) }"></ng-container>
16+
</ng-container>
17+
<ng-template #plainText>
18+
<span [innerHTML]="option.value" style="display: flex; padding-top: 1em"></span>
19+
</ng-template>
20+
</span>
21+
</mat-list-item>
22+
<mat-divider></mat-divider>
23+
</ng-container>
2124
</mat-list>
2225

23-
<!-- Recursive template definition -->
24-
<ng-template #recursiveJson let-value let-level="level">
25-
<ng-container *ngIf="isObject(value)">
26-
<div *ngFor="let item of objectToKeyValue(value); trackBy: trackByFn" class="nested-attributes">
27-
<span><strong>{{item.key}}</strong>:</span>
28-
<ng-container *ngIf="isObject(item.value) || isArray(item.value)">
29-
<ng-container *ngTemplateOutlet="recursiveJson; context:{ $implicit: item.value, level: level + 1 }"></ng-container>
30-
</ng-container>
31-
<ng-container *ngIf="!isObject(item.value) && !isArray(item.value)">
32-
{{item.value}}
26+
<!-- Recursive template for nested lists -->
27+
<ng-template #recursiveList let-value>
28+
<mat-list class="nested-list">
29+
<ng-container *ngIf="isObject(value)">
30+
<ng-container *ngFor="let item of objectToKeyValue(value); trackBy: trackByFn">
31+
<div class="nested-item">
32+
<div class="nested-key"><strong>{{item.key}}</strong></div>
33+
<div class="nested-value">
34+
<ng-container *ngIf="isObject(item.value) || isArray(item.value)">
35+
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: item.value }"></ng-container>
36+
</ng-container>
37+
<ng-container *ngIf="!isObject(item.value) && !isArray(item.value)">
38+
{{item.value}}
39+
</ng-container>
40+
</div>
41+
</div>
3342
</ng-container>
34-
</div>
35-
</ng-container>
36-
<ng-container *ngIf="isArray(value)">
37-
<div *ngFor="let item of value; let i = index; trackBy: trackByFn" class="nested-attributes">
38-
<strong>[{{i}}]</strong>:
39-
<ng-container *ngIf="isObject(item) || isArray(item)">
40-
<ng-container *ngTemplateOutlet="recursiveJson; context:{ $implicit: item, level: level + 1 }"></ng-container>
41-
</ng-container>
42-
<ng-container *ngIf="!isObject(item) && !isArray(item)">
43-
{{item}}
43+
</ng-container>
44+
<ng-container *ngIf="isArray(value)">
45+
<ng-container *ngFor="let item of value; let i = index; trackBy: trackByFn">
46+
<div class="nested-item">
47+
<div class="nested-key"><strong>[{{i}}]</strong>:</div>
48+
<div class="nested-value">
49+
<ng-container *ngIf="isObject(item) || isArray(item)">
50+
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: item }"></ng-container>
51+
</ng-container>
52+
<ng-container *ngIf="!isObject(item) && !isArray(item)">
53+
{{item}}
54+
</ng-container>
55+
</div>
56+
</div>
4457
</ng-container>
45-
</div>
46-
</ng-container>
58+
</ng-container>
59+
</mat-list>
4760
</ng-template>
4861
</mat-tab>
4962

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
@use '/src/template' as temp;
22

33
:host {
4-
.nested-attributes {
5-
padding-left: 1em;
4+
.nested-list {
5+
margin-left: 1em;
6+
}
7+
8+
.nested-item {
9+
align-items: flex-start;
10+
}
11+
12+
.nested-key {
13+
margin-right: 4px;
14+
min-width: 3em;
15+
}
16+
17+
.nested-value {
18+
flex: 1;
19+
}
20+
21+
mat-list-item {
22+
height: auto !important;
23+
min-height: 48px;
624
}
725
}

src/app/features/invoke-wallet/components/view-attestation/view-attestation.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
1414
import { DialogData } from '@features/invoke-wallet/components/view-attestation/model/DialogData';
1515
import { MatButtonModule } from '@angular/material/button';
1616
import { MatTabsModule } from '@angular/material/tabs';
17+
import { MatDividerModule } from '@angular/material/divider';
1718

1819
@Component({
1920
selector: 'vc-view-attestation',
@@ -25,6 +26,7 @@ import { MatTabsModule } from '@angular/material/tabs';
2526
MatDialogModule,
2627
MatButtonModule,
2728
MatTabsModule,
29+
MatDividerModule,
2830
],
2931
templateUrl: './view-attestation.component.html',
3032
styleUrls: ['./view-attestation.component.scss'],

0 commit comments

Comments
 (0)