Skip to content

Commit

Permalink
add gs1 to frontend
Browse files Browse the repository at this point in the history
Signed-off-by: F-Node-Karlsruhe <[email protected]>
  • Loading branch information
F-Node-Karlsruhe committed Jul 23, 2024
1 parent 66f1179 commit 1b62f14
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 97 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ WIP
2.0.0 (2024-07-23)

- add gs1 verification endpoint
- use gs1 endpoint on gs1 credential

1.7.8 (2024-06-13)
---
Expand Down
16 changes: 0 additions & 16 deletions api/src/services/verifier/gs1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,7 @@ import {
import { documentLoader } from "../documentLoader/index.js";
import { Verifier } from "./index.js";

export const gs1CredentialTypes = [
"OrganizationDataCredential",
"GS1PrefixLicenseCredential",
"GS1CompanyPrefixLicenseCredential",
"KeyCredential",
"ProductDataCredential",
];

export const gs1CredentialContext =
"https://ref.gs1.org/gs1/vc/license-context";

export function isGs1Credential(credential: VerifiableCredential): boolean {
return (
credential["@context"].includes(gs1CredentialContext) &&
credential.type.some((type: string) => gs1CredentialTypes.includes(type))
);
}
export function getVerifierFunction(challenge?: string, domain?: string) {
return async function (verifiable: any) {
return await Verifier.verify(verifiable, challenge, domain);
Expand Down
5 changes: 0 additions & 5 deletions api/src/services/verifier/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ import { DataIntegrityProof } from "@digitalbazaar/data-integrity";
import jsigs from "jsonld-signatures";

import { documentLoader } from "../documentLoader/index.js";
import {
isGs1Credential,
checkGS1Credential,
verifyGS1Credentials,
} from "./gs1.js";

const { createVerifyCryptosuite } = ecdsaSd2023Cryptosuite;
const {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from 'axios'
const axiosInstance = axios.create({
baseURL: process.env.VERIFIER_API || 'https://ssi.eecc.de/api/verifier',
baseURL: process.env.VERIFIER_API || 'http://localhost:3000/api/verifier',
timeout: 5000,
headers: {
'Accept': 'application/ld+json,application/json,*/*'
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/components/Credential.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
<div class="card-header p-3">
<div class="row justify-content-between align-items-center">
<div class="col-8">
<h5 class="mb-0 text-primary">{{ getCredentialType(credential) }}</h5>
<h5 class="mb-0 text-primary"><img v-if="isGs1Credential(credential)" class="me-1" style="height: 1.5rem;"
src="https://ref.gs1.org/logos/gs1logo.png" /> {{ getCredentialType(credential) }}</h5>
<div class="credentialid mt-1"><a :href="credential.id">{{ credential.id }}</a></div>
</div>
<div class="col-2 text-end">
Expand Down Expand Up @@ -184,7 +185,7 @@ import { Tooltip } from 'bootstrap';
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
import { credentialPDF } from '../pdf.js';
import { getPlainCredential, getCredentialType } from '../utils.js';
import { getPlainCredential, getCredentialType, isGs1Credential } from '../utils.js';
import * as JsHashes from 'jshashes';
pdfMake.vfs = pdfFonts.pdfMake.vfs;
Expand All @@ -207,7 +208,8 @@ export default {
return {
toast: useToast(),
getPlainCredential: getPlainCredential,
getCredentialType: getCredentialType
getCredentialType: getCredentialType,
isGs1Credential: isGs1Credential
}
},
mounted() {
Expand Down
146 changes: 85 additions & 61 deletions frontend/src/utils.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,119 @@
import jsonld from 'jsonld';
import { demoAuthPresentation } from './store/demoAuth';
import jsonld from 'jsonld'
import { demoAuthPresentation } from './store/demoAuth'

export const VerifiableType = {
CREDENTIAL: 'VerifiableCredential',
PRESENTATION: 'VerifiablePresentation'
};
CREDENTIAL: 'VerifiableCredential',
PRESENTATION: 'VerifiablePresentation',
}

const IPFS_GATEWAYS = ['ipfs.io', 'ipfs.ssi.eecc.de']

export function isURL(url) {
if (typeof url != 'string') return false;
return url.startsWith('https://');
if (typeof url != 'string') return false
return url.startsWith('https://')
}

export function getCredentialValue(value) {
return typeof value === 'object' ? value.value || value['@value'] || JSON.stringify(value, null, 2) : value;
return typeof value === 'object'
? value.value || value['@value'] || JSON.stringify(value, null, 2)
: value
}

export function getPlainCredential(credential) {
var clean_credential = { ...credential };
delete clean_credential.verified;
delete clean_credential.revoked;
delete clean_credential.suspended;
delete clean_credential.status;
delete clean_credential.presentation;
delete clean_credential.context;
return clean_credential;
var clean_credential = { ...credential }
delete clean_credential.verified
delete clean_credential.revoked
delete clean_credential.suspended
delete clean_credential.status
delete clean_credential.presentation
delete clean_credential.context
return clean_credential
}

export function getVerifiableType(verifiable) {
if (verifiable.type.includes(VerifiableType.PRESENTATION)) return VerifiableType.PRESENTATION;
return VerifiableType.CREDENTIAL;
if (verifiable.type.includes(VerifiableType.PRESENTATION))
return VerifiableType.PRESENTATION
return VerifiableType.CREDENTIAL
}

export function getCredentialType(credential) {
return credential.type.length > 1 ? credential.type.filter((c) => c != 'VerifiableCredential')[0] : credential.type[0];
return credential.type.length > 1
? credential.type.filter((c) => c != 'VerifiableCredential')[0]
: credential.type[0]
}

export function getHolder(presentation) {
if (presentation.holder) return presentation.holder;
const proof = Array.isArray(presentation.proof) ? presentation.proof[0] : presentation.proof
return proof.verificationMethod.split('#')[0];
if (presentation.holder) return presentation.holder
const proof = Array.isArray(presentation.proof)
? presentation.proof[0]
: presentation.proof
return proof.verificationMethod.split('#')[0]
}

export async function fetchIPFS(IPFSUrl) {

var document;

await Promise.any(IPFS_GATEWAYS.map(async (gateway) => {

return await fetch(`https://${gateway}/ipfs/${IPFSUrl.split('ipfs://')[1]}`);

}))
.then((result) => {

document = result;

})
.catch((error) => {
console.error(error)
})

if (!document) throw Error('Fetching from IPFS failed');

return document;

var document

await Promise.any(
IPFS_GATEWAYS.map(async (gateway) => {
return await fetch(
`https://${gateway}/ipfs/${IPFSUrl.split('ipfs://')[1]}`,
)
}),
)
.then((result) => {
document = result
})
.catch((error) => {
console.error(error)
})

if (!document) throw Error('Fetching from IPFS failed')

return document
}


const documentLoader = async (url) => {
let document;
if (url.startsWith('ipfs://')) {

document = await fetchIPFS(url)

} else document = await fetch(url);

return {
contextUrl: null,
document: await document.json(),
documentUrl: url
};
};

let document
if (url.startsWith('ipfs://')) {
document = await fetchIPFS(url)
} else document = await fetch(url)

return {
contextUrl: null,
document: await document.json(),
documentUrl: url,
}
}

export async function getContext(credential) {
const resolved = await jsonld.processContext(await jsonld.processContext(null, null), credential, { documentLoader });
return resolved.mappings;
const resolved = await jsonld.processContext(
await jsonld.processContext(null, null),
credential,
{ documentLoader },
)
return resolved.mappings
}

export function isDemoAuth(auth) {
return auth != undefined && JSON.stringify(auth) == JSON.stringify(demoAuthPresentation);
return (
auth != undefined &&
JSON.stringify(auth) == JSON.stringify(demoAuthPresentation)
)
}

const gs1CredentialTypes = [
'OrganizationDataCredential',
'GS1PrefixLicenseCredential',
'GS1CompanyPrefixLicenseCredential',
'KeyCredential',
'ProductDataCredential',
]

const gs1CredentialContext = 'https://ref.gs1.org/gs1/vc/license-context'

export function isGs1Credential(credential) {
return (
credential['@context'].includes(gs1CredentialContext) &&
credential.type.some((type) => gs1CredentialTypes.includes(type))
)
}
38 changes: 27 additions & 11 deletions frontend/src/views/Verify.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<script>
import { useToast } from "vue-toastification";
import { Tooltip } from "bootstrap";
import { getVerifiableType, VerifiableType, getContext, getHolder } from "../utils.js";
import { getVerifiableType, VerifiableType, getContext, getHolder, isGs1Credential } from "../utils.js";
import Passport from "@/components/Passport.vue";
Expand Down Expand Up @@ -242,8 +242,12 @@ export default {
},
async verify(verifiable) {
let isGs1 = false;
if (getVerifiableType(verifiable) == VerifiableType.PRESENTATION) {
const presentation = {
presentation:
{
Expand All @@ -253,26 +257,37 @@ export default {
}
}
if (Array.isArray(verifiable.verifiableCredential)) verifiable.verifiableCredential.forEach(
(credential) => this.addCredential({ ...credential, presentation })
);
else this.addCredential({ ...verifiable.verifiableCredential, presentation });
if (Array.isArray(verifiable.verifiableCredential)) {
isGs1 = verifiable.verifiableCredential.some(cred => isGs1Credential(cred))
verifiable.verifiableCredential.forEach(
(credential) => this.addCredential({ ...credential, presentation })
);
}
else {
isGs1 = isGs1Credential(verifiable.verifiableCredential)
this.addCredential({ ...verifiable.verifiableCredential, presentation });
}
} else {
isGs1 = isGs1Credential(verifiable)
this.addCredential({ ...verifiable });
}
const res = await this.$api.post('/', [verifiable], { params: { challenge: this.$route.query.challenge } });
const result = res.data[0];
const res = await this.$api.post(isGs1 ? '/gs1' : '/', isGs1 ? verifiable : [verifiable], { params: { challenge: this.$route.query.challenge } });
const result = isGs1 ? res.data : res.data[0];
console.log(result)
// verifiable is a presentations
if (getVerifiableType(verifiable) == VerifiableType.PRESENTATION) {
// build presentation object with important properties for attaching to the credential
var presentation = {
verified: result.verified,
presentationResult: result.presentationResult.verified,
presentationResult: isGs1 ? result.verified : result.presentationResult.verified,
holder: getHolder(verifiable),
challenge: Array.isArray(verifiable.proof) ? verifiable.proof[0].challenge : verifiable.proof.challenge,
domain: Array.isArray(verifiable.proof) ? verifiable.proof[0].domain : verifiable.proof.domain,
Expand All @@ -299,14 +314,15 @@ export default {
}
// contains array of credentials
if (Array.isArray(verifiable.verifiableCredential))
if (Array.isArray(verifiable.verifiableCredential)) {
const credentialResults = isGs1 ? result.result : result.credentialResults;
verifiable.verifiableCredential.forEach(
credential => this.assignResult(
credential.id,
result.credentialResults.find(credRes => credRes.credentialId == credential.id),
credentialResults.find(credRes => credRes.credentialId == credential.id),
presentation
));
}
// contains single credential object
else this.assignResult(verifiable.verifiableCredential.id, result[0], presentation);
Expand Down

0 comments on commit 1b62f14

Please sign in to comment.