Skip to content
Merged
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
6 changes: 5 additions & 1 deletion src/app/core/constants/general.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Profile, RequestUriMethod } from "../models/TransactionInitializationRequest";

export const ACTIVE_TRANSACTION = 'ACTIVE_TRANSACTION';
export const SCHEME = 'scheme';
export const DEFAULT_SCHEME = 'haip-vp://';
export const ISSUER_CHAIN = 'ISSUER_CHAIN';

export const DefaultRequestUriMethod: RequestUriMethod = 'get';
export const DefaultProfile: Profile = 'haip';
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
<a id="inspectLogs" mat-menu-item (click)="inspectLogs()"
>Inspect transaction logs</a
>
<a id="customScheme" mat-menu-item (click)="changeCustomScheme()"
>Change default scheme</a
>
<a id="issuerChain" mat-menu-item (click)="changeIssuerChain()"
>Configure issuer chain</a
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { MatMenuModule } from "@angular/material/menu";
import { MatToolbarModule } from '@angular/material/toolbar';
import { OpenLogsComponent } from "@shared/elements/open-logs/open-logs.component";
import { MatDialog, MatDialogModule } from "@angular/material/dialog";
import {InputSchemeComponent} from "@shared/elements/input-scheme/input-scheme.component";
import { IssuerChainComponent } from '@app/shared/elements/trusted-issuer/issuer-chain.component';

@Component({
Expand Down Expand Up @@ -40,16 +39,6 @@ export class WalletLayoutHeaderComponent {
});
}

changeCustomScheme () {
this.dialog.open(InputSchemeComponent, {
data: {
transactionId: '',
label: 'Inspect transaction logs',
isInspectLogs: true
},
});
}

changeIssuerChain () {
this.dialog.open(IssuerChainComponent, {
data: {
Expand Down
7 changes: 5 additions & 2 deletions src/app/core/models/InitializedTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { RequestUriMethod } from "./TransactionInitializationRequest"

export type InitializedTransaction = {
client_id: string,
request_uri: string,
request_uri_method: 'get' | 'post',
transaction_id: string
request_uri_method: RequestUriMethod,
transaction_id: string,
authorization_request_uri: string
}
18 changes: 17 additions & 1 deletion src/app/core/models/TransactionInitializationRequest.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import { DCQL } from './dcql/DCQL';

export type RequestUriMethod = 'get' | 'post';
export type Profile = 'haip' | 'openid4vp';
export type ProfileOptions = {
endpoint: string;
}
export const profileOptions: Record<Profile, ProfileOptions> = {
haip: {
endpoint: 'haip-vp://',
},
openid4vp: {
endpoint: 'openid4vp://',
},
};

export type TransactionInitializationRequest = {
nonce: string;
request_uri_method: 'get' | 'post';
request_uri_method: RequestUriMethod;
dcql_query: DCQL;
issuer_chain?: string;
profile: Profile;
authorization_request_uri: string;
};

export type PresentationQuery = DCQL;
8 changes: 6 additions & 2 deletions src/app/core/services/dcql-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
AttributeSelectionMethod,
} from '@app/features/presentation-request-preparation/models/AttestationSelection';
import { v4 as uuidv4 } from 'uuid';
import { TransactionInitializationRequest } from '../models/TransactionInitializationRequest';
import { Profile, RequestUriMethod, TransactionInitializationRequest } from '../models/TransactionInitializationRequest';
import {
MsoMdocAttestation,
SdJwtVcAttestation,
Expand All @@ -21,7 +21,9 @@ export class DCQLService {
dcqlPresentationRequest(
selectedAttestations: AttestationSelection[],
selectedAttributes: { [id: string]: string[] },
selectedRequestUriMethod: 'get' | 'post',
selectedRequestUriMethod: RequestUriMethod,
selectedProfile: Profile,
authorizationRequestUri: string,
issuerChain?: string
): TransactionInitializationRequest {
let dcqlQueries: CredentialQuery[] = selectedAttestations.map(
Expand All @@ -44,6 +46,8 @@ export class DCQLService {
nonce: uuidv4(),
request_uri_method: selectedRequestUriMethod,
issuer_chain: issuerChain,
profile: selectedProfile,
authorization_request_uri: authorizationRequestUri
};
}

Expand Down
14 changes: 8 additions & 6 deletions src/app/core/services/verifier-endpoint.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import {ActiveTransaction} from "@core/models/ActiveTransaction";
import { SessionStorageService } from './session-storage.service';

const SAME_DEVICE_UI_RE_ENTRY_URL = '/get-wallet-code?response_code={RESPONSE_CODE}';
const PRESENTATIONS_ENDPOINT = 'ui/presentations';
const VALIDATE_SD_JWT_VC_PRESENTATION_ENDPOINT = 'utilities/process/sdJwtVc';
const INIT_TRANSACTION_ENDPOINT = 'ui/presentations/v2';
const WALLET_RESPONSE_ENDPOINT = 'ui/presentations/${transactionId}';
const EVENTS_ENDPOINT = 'ui/presentations/${transactionId}/events';
const VALIDATE_SD_JWT_VC_PRESENTATION_ENDPOINT = 'utilities/validations/sdJwtVc';

@Injectable()
export class VerifierEndpointService {
Expand All @@ -34,7 +36,7 @@ export class VerifierEndpointService {
if (!this.deviceDetectorService.isDesktop()) {
payload['wallet_response_redirect_uri_template'] = location.origin + SAME_DEVICE_UI_RE_ENTRY_URL;
}
this.httpService.post<InitializedTransaction, string>(PRESENTATIONS_ENDPOINT, payload)
this.httpService.post<InitializedTransaction, string>(INIT_TRANSACTION_ENDPOINT, payload)
.pipe(
tap((res) => {
let activeTransaction : ActiveTransaction = {
Expand All @@ -49,14 +51,14 @@ export class VerifierEndpointService {

getWalletResponse(transaction_id: string, code?: string): Observable<WalletResponse> {
if (typeof code == 'undefined') {
return this.httpService.get(PRESENTATIONS_ENDPOINT+`/${transaction_id}`);
return this.httpService.get(WALLET_RESPONSE_ENDPOINT.replace('${transactionId}', transaction_id));
} else {
return this.httpService.get(PRESENTATIONS_ENDPOINT+`/${transaction_id}?response_code=${code}`);
return this.httpService.get(WALLET_RESPONSE_ENDPOINT.replace('${transactionId}', transaction_id) + `?response_code=${code}`);
}
}

getsTransactionEventsLogs(transactionId: string): Observable<EventLog[]> {
return this.httpService.get(PRESENTATIONS_ENDPOINT+`/${transactionId}/events`)
return this.httpService.get(EVENTS_ENDPOINT.replace('${transactionId}', transactionId))
.pipe(
map((data: any) => {
return data.events.map((event: EventLog) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class QrCodeComponent implements OnInit, OnDestroy {
transaction!: ActiveTransaction;

deepLinkTxt!: string;
scheme!: string;

qrCodeDownloadLink!: SafeUrl;
readonly dialog!: MatDialog;

Expand All @@ -69,12 +69,6 @@ export class QrCodeComponent implements OnInit, OnDestroy {
this.localStorageService = this.injector.get(LocalStorageService);
this.dialog = this.injector.get(MatDialog);
this.isCrossDevice = this.deviceDetectorService.isDesktop();

if (this.localStorageService.get(constants.SCHEME)) {
this.scheme = this.localStorageService.get(constants.SCHEME) ?? constants.DEFAULT_SCHEME;
} else {
this.scheme = constants.DEFAULT_SCHEME;
}
}

ngOnInit(): void {
Expand All @@ -84,7 +78,7 @@ export class QrCodeComponent implements OnInit, OnDestroy {
if (!this.transaction) {
this.navigateService.goHome();
} else {
this.deepLinkTxt = this.buildQrCode(this.transaction.initialized_transaction);
this.deepLinkTxt = this.transaction.initialized_transaction.authorization_request_uri;
if (this.isCrossDevice) {
this.pollingRequest(this.transaction.initialized_transaction.transaction_id);
}
Expand Down Expand Up @@ -131,10 +125,6 @@ export class QrCodeComponent implements OnInit, OnDestroy {
return concludedTransaction;
}

private buildQrCode(data: { client_id: string, request_uri: string, request_uri_method: 'get' | 'post', transaction_id: string }): string {
return `${this.scheme}?client_id=${encodeURIComponent(data.client_id)}&request_uri=${encodeURIComponent(data.request_uri)}&request_uri_method=${encodeURIComponent(data.request_uri_method)}`;
}

openLogs() {
this.dialog.open(OpenLogsComponent, {
data: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="component-root">
<ng-container *ngFor="let selection of attestationsSelection">
<mat-card appearance="outlined">
<mat-card >
<mat-card-header>
<mat-card-title>{{ nameOf(selection.type) }}</mat-card-title>
<mat-card-subtitle>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<mat-card>
<mat-card-header>
<mat-card-title>Presentation Options</mat-card-title>
<mat-card-subtitle>
Configure the options for your presentation request.
</mat-card-subtitle>
</mat-card-header>

<mat-card-content>
<div class="request-options-grid">
<div class="request-options-row">
<div class="request-options-label">
<span>Presentation Profile</span>
<p class="request-options-helper">
Defines the rules and constraints of the presentation
</p>
</div>
<div class="request-options-control">
<mat-button-toggle-group
[formControl]="presentationProfileControl"
(valueChange)="profileChange.emit($event)"
aria-label="Presentation Profile"
>
<mat-button-toggle value="haip">HAIP</mat-button-toggle>
<mat-button-toggle value="openid4vp">OpenID4VP</mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>

<div class="request-options-row">
<div class="request-options-label">
<span>Request URI Method</span>
<p class="request-options-helper">
Choose how the wallet fetches the authorization request
</p>
</div>
<div class="request-options-control">
<mat-button-toggle-group
[formControl]="requestUriMethodControl"
(valueChange)="requestUriMethodChange.emit($event)"
aria-label="Request URI Method"
>
<mat-button-toggle value="get">GET</mat-button-toggle>
<mat-button-toggle value="post">POST</mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>

<div class="request-options-row">
<div class="request-options-label">
<span>Authorization Endpoint</span>
<p class="request-options-helper">
Specify an endpoint URI for the authorization request
</p>
</div>
<div class="request-options-control">
<mat-form-field appearance="outline" class="config-option-field">
<mat-label>Authorization Endpoint</mat-label>
<input
matInput
placeholder="scheme://"
[formControl]="authorizationSchemeControl"
autocomplete="off"
(input)="
authorizationSchemeChange.emit(authorizationSchemeControl.value)
"
/>
</mat-form-field>
</div>
</div>
</div>
</mat-card-content>
</mat-card>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
:host {
display: block;
}

.request-options-grid {
display: flex;
flex-direction: column;
gap: 24px;
padding-top: 16px;
}

.request-options-row {
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
gap: 16px;
}

.request-options-label {
text-align: right;

span {
display: block;
font-weight: 500;
}
}

.request-options-helper {
margin: 4px 0 0;
font-size: 0.85rem;
color: rgba(0, 0, 0, 0.6);
}

.request-options-control {
flex-direction: column;
gap: 8px;
}

@media (max-width: 576px) {
.request-options-row {
grid-template-columns: 1fr;
}

.request-options-label {
text-align: left;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { PresentationOptionsComponent } from './presentation-options.component';

describe('PresentationOptionsComponent', () => {
let component: PresentationOptionsComponent;
let fixture: ComponentFixture<PresentationOptionsComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PresentationOptionsComponent]
})
.compileComponents();

fixture = TestBed.createComponent(PresentationOptionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatCardModule, MatCardHeader, MatCardSubtitle, MatCard, MatCardTitle, MatCardContent } from '@angular/material/card';

import {
Profile,
RequestUriMethod,
} from '@app/core/models/TransactionInitializationRequest';

@Component({
selector: 'vc-presentation-options',
imports: [
CommonModule,
ReactiveFormsModule,
MatButtonToggleModule,
MatFormFieldModule,
MatInputModule,
MatCardHeader,
MatCard,
MatCardTitle,
MatCardSubtitle,
MatCardContent
],
templateUrl: './presentation-options.component.html',
styleUrl: './presentation-options.component.scss',
})
export class PresentationOptionsComponent {
@Input() presentationProfileControl!: FormControl<Profile>;
@Input() requestUriMethodControl!: FormControl<RequestUriMethod>;
@Input() authorizationSchemeControl!: FormControl<string>;

@Output() profileChange = new EventEmitter<Profile>();
@Output() requestUriMethodChange = new EventEmitter<RequestUriMethod>();
@Output() authorizationSchemeChange = new EventEmitter<string>();
}
Loading