From bb23afc0000cbd77866d8e48386fe75974d6cfa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hauke=20T=C3=B6njes?= Date: Mon, 28 Jun 2021 20:33:58 +0200 Subject: [PATCH 1/6] Changes regarding C# backend - Working with C# backend, signing just the pass.json hash - Bugfixes error handling --- components/Alert.js | 6 +++--- components/Form.js | 26 ++++++++++++-------------- pages/index.js | 1 - src/constants.js | 27 +++++++++++++++------------ src/pass.js | 29 +++++++++++------------------ src/utils.js | 8 ++++---- 6 files changed, 45 insertions(+), 52 deletions(-) diff --git a/components/Alert.js b/components/Alert.js index 439e2bb..a7bfad3 100644 --- a/components/Alert.js +++ b/components/Alert.js @@ -9,9 +9,9 @@ export function Alert() { } return( - diff --git a/pages/index.js b/pages/index.js index 5c37529..f5e7db5 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,7 +1,6 @@ import { NextSeo } from 'next-seo'; import Form from '../components/Form' -import Logo from '../components/Logo' import Card from '../components/Card' import Page from '../components/Page' diff --git a/src/constants.js b/src/constants.js index 1974d65..b68f548 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,18 +1,21 @@ -exports.BASE_URL = 'https://raw.githubusercontent.com/ehn-dcc-development/ehn-dcc-valuesets/main/' exports.API_BASE_URL = 'https://api.covidpass.marvinsextro.de/' + +exports.VALUE_SET_BASE_URL = 'https://raw.githubusercontent.com/ehn-dcc-development/ehn-dcc-valuesets/main/' exports.VALUE_TYPES = { - medicalProducts: 'vaccine-medicinal-product.json', - countryCodes: 'country-2-codes.json', - manufacturers: 'vaccine-mah-manf.json', + medicalProducts: 'vaccine-medicinal-product.json', + countryCodes: 'country-2-codes.json', + manufacturers: 'vaccine-mah-manf.json', } exports.COLORS = { - white: 'rgb(255, 255, 255)', - black: 'rgb(0, 0, 0)', - grey: 'rgb(33, 33, 33)', - green: 'rgb(27, 94, 32)', - indigo: 'rgb(26, 35, 126)', - blue: 'rgb(1, 87, 155)', - purple: 'rgb(74, 20, 140)', - teal: 'rgb(0, 77, 64)', + white: 'rgb(255, 255, 255)', + black: 'rgb(0, 0, 0)', + grey: 'rgb(33, 33, 33)', + green: 'rgb(27, 94, 32)', + indigo: 'rgb(26, 35, 126)', + blue: 'rgb(1, 87, 155)', + purple: 'rgb(74, 20, 140)', + teal: 'rgb(0, 77, 64)', } exports.NAME = 'CovidPass' +exports.PASS_IDENTIFIER = 'pass.de.marvinsextro.covidpass' // WELL KNOWN +exports.TEAM_IDENTIFIER = 'X8Q7Q2RLTD' // WELL KNOWN diff --git a/src/pass.js b/src/pass.js index 65860c4..c040c21 100644 --- a/src/pass.js +++ b/src/pass.js @@ -1,18 +1,13 @@ 'use strict'; -const consts = require('./constants') +const constants = require('./constants') const utils = require('./utils') -const img = require('./img') const { Payload } = require('./payload') const { toBuffer } = require('do-not-zip') const crypto = require('crypto') exports.createPass = async function(data) { - async function getJSONfromURL(url) { - return await (await fetch(url)).json() - } - function getBufferHash(buffer) { // creating hash const sha = crypto.createHash('sha1'); @@ -30,6 +25,7 @@ exports.createPass = async function(data) { // Adding required files // Create pass.json zip.push({ path: 'pass.json', data: Buffer.from(JSON.stringify(pass)) }) + const passHash = getBufferHash(Buffer.from(JSON.stringify(pass))) zip.push({ path: 'icon.png', data: payload.img1x }) zip.push({ path: 'icon@2x.png', data: payload.img2x }) @@ -49,18 +45,18 @@ exports.createPass = async function(data) { ); zip.push({ path: 'manifest.json', data: manifestJson }); - const response = await fetch(consts.API_BASE_URL + 'sign_manifest', { + const response = await fetch(`${constants.API_BASE_URL}/sign`, { method: 'POST', headers: { 'Accept': 'application/octet-stream', 'Content-Type': 'application/json' }, body: JSON.stringify({ - manifest: manifestJson + PassJsonHash: passHash, }) }) - if (response.status != 200) { + if (response.status !== 200) { return undefined } @@ -87,8 +83,6 @@ exports.createPass = async function(data) { } catch (e) { return undefined } - - let signingIdentity = await getJSONfromURL(consts.API_BASE_URL + 'signing_identity') const qrCode = { message: payload.raw, @@ -97,14 +91,14 @@ exports.createPass = async function(data) { } const pass = { - passTypeIdentifier: signingIdentity['pass_identifier'], - teamIdentifier: signingIdentity['pass_team_id'], + passTypeIdentifier: constants.PASS_IDENTIFIER, + teamIdentifier: constants.TEAM_IDENTIFIER, sharingProhibited: true, voided: false, formatVersion: 1, - logoText: consts.NAME, - organizationName: consts.NAME, - description: consts.NAME, + logoText: constants.NAME, + organizationName: constants.NAME, + description: constants.NAME, labelColor: payload.labelColor, foregroundColor: payload.foregroundColor, backgroundColor: payload.backgroundColor, @@ -182,6 +176,5 @@ exports.createPass = async function(data) { } }; - let buf = await signPassWithRemote(pass, payload) - return buf + return await signPassWithRemote(pass, payload) } diff --git a/src/utils.js b/src/utils.js index 827ed20..a08e30f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,15 +1,15 @@ -const { VALUE_TYPES, BASE_URL } = require("./constants") +const { VALUE_TYPES, VALUE_SET_BASE_URL } = require("./constants") const fetch = require("node-fetch") exports.getValueSets = async function() { - async function getJSONfromURL(url) { + async function getJSONFromURL(url) { return await (await fetch(url)).json() } - var valueSets = {} + let valueSets = {} for (const [key, value] of Object.entries(VALUE_TYPES)) { - valueSets[key] = await getJSONfromURL(BASE_URL + value) + valueSets[key] = await getJSONFromURL(VALUE_SET_BASE_URL + value) } return valueSets From e4537e250dc1d6620a21e46138289ca30f0cd2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hauke=20T=C3=B6njes?= Date: Mon, 28 Jun 2021 21:58:07 +0200 Subject: [PATCH 2/6] Load API_BASE_URL from backend - Remove api_base_url constant --- pages/api/config.js | 4 ++ src/constants.js | 2 - src/pass.js | 110 +++++++++++++++++++++++--------------------- 3 files changed, 61 insertions(+), 55 deletions(-) create mode 100644 pages/api/config.js diff --git a/pages/api/config.js b/pages/api/config.js new file mode 100644 index 0000000..4892943 --- /dev/null +++ b/pages/api/config.js @@ -0,0 +1,4 @@ +export default function handler(req, res) { + // Return the API_BASE_URL. This Endpoint allows us to access the env Variable in client javascript + res.status(200).json({ apiBaseUrl: process.env.API_BASE_URL }) +} \ No newline at end of file diff --git a/src/constants.js b/src/constants.js index b68f548..af4c362 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,5 +1,3 @@ -exports.API_BASE_URL = 'https://api.covidpass.marvinsextro.de/' - exports.VALUE_SET_BASE_URL = 'https://raw.githubusercontent.com/ehn-dcc-development/ehn-dcc-valuesets/main/' exports.VALUE_TYPES = { medicalProducts: 'vaccine-medicinal-product.json', diff --git a/src/pass.js b/src/pass.js index c040c21..dc971d7 100644 --- a/src/pass.js +++ b/src/pass.js @@ -14,24 +14,24 @@ exports.createPass = async function(data) { sha.update(buffer); return sha.digest('hex'); } - + async function signPassWithRemote(pass, payload) { // From pass-js // https://github.com/walletpass/pass-js/blob/2b6475749582ca3ea742a91466303cb0eb01a13a/src/pass.ts - + // Creating new Zip file const zip = [] - + // Adding required files // Create pass.json zip.push({ path: 'pass.json', data: Buffer.from(JSON.stringify(pass)) }) const passHash = getBufferHash(Buffer.from(JSON.stringify(pass))) - + zip.push({ path: 'icon.png', data: payload.img1x }) zip.push({ path: 'icon@2x.png', data: payload.img2x }) zip.push({ path: 'logo.png', data: payload.img1x }) zip.push({ path: 'logo@2x.png', data: payload.img2x }) - + // adding manifest // Construct manifest here const manifestJson = JSON.stringify( @@ -44,8 +44,12 @@ exports.createPass = async function(data) { ), ); zip.push({ path: 'manifest.json', data: manifestJson }); - - const response = await fetch(`${constants.API_BASE_URL}/sign`, { + + // Load API_BASE_URL form nextjs backend + const configResponse = await fetch('/api/config') + const apiBaseUrl = (await configResponse.json()).apiBaseUrl + + const response = await fetch(`${apiBaseUrl}/sign`, { method: 'POST', headers: { 'Accept': 'application/octet-stream', @@ -55,19 +59,19 @@ exports.createPass = async function(data) { PassJsonHash: passHash, }) }) - + if (response.status !== 200) { return undefined } - + const manifestSignature = await response.arrayBuffer() - + zip.push({ path: 'signature', data: Buffer.from(manifestSignature) }); - + // finished! return toBuffer(zip); } - + let valueSets try { @@ -107,69 +111,69 @@ exports.createPass = async function(data) { barcode: qrCode, generic: { headerFields: [ - { - key: "type", - label: "Certificate Type", - value: payload.certificateType + { + key: "type", + label: "Certificate Type", + value: payload.certificateType } ], primaryFields: [ - { - key: "name", - label: "Name", - value: payload.name + { + key: "name", + label: "Name", + value: payload.name } ], secondaryFields: [ - { - key: "dose", - label: "Dose", - value: payload.dose + { + key: "dose", + label: "Dose", + value: payload.dose }, - { - key: "dov", - label: "Date of Vaccination", - value: payload.dateOfVaccination, + { + key: "dov", + label: "Date of Vaccination", + value: payload.dateOfVaccination, textAlignment: "PKTextAlignmentRight" } ], auxiliaryFields: [ - { - key: "vaccine", - label: "Vaccine", - value: payload.vaccineName + { + key: "vaccine", + label: "Vaccine", + value: payload.vaccineName }, - { - key: "dob", - label: "Date of Birth", value: - payload.dateOfBirth, + { + key: "dob", + label: "Date of Birth", value: + payload.dateOfBirth, textAlignment: "PKTextAlignmentRight" } ], backFields: [ - { - key: "uvci", - label: "Unique Certificate Identifier (UVCI)", + { + key: "uvci", + label: "Unique Certificate Identifier (UVCI)", value: payload.uvci }, - { - key: "issuer", - label: "Certificate Issuer", - value: payload.certificateIssuer + { + key: "issuer", + label: "Certificate Issuer", + value: payload.certificateIssuer }, - { - key: "country", - label: "Country of Vaccination", + { + key: "country", + label: "Country of Vaccination", value: payload.countryOfVaccination }, - { - key: "manufacturer", - label: "Manufacturer", - value: payload.manufacturer + { + key: "manufacturer", + label: "Manufacturer", + value: payload.manufacturer }, - { - key: "disclaimer", - label: "Disclaimer", + { + key: "disclaimer", + label: "Disclaimer", value: "This certificate is only valid in combination with the ID card of the certificate holder and expires one year + 14 days after the last dose. The validity of this certificate was not checked by CovidPass." } ] From 54da9784264e5e1dd4ed83ad22aeb95b2c72c08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hauke=20T=C3=B6njes?= Date: Mon, 28 Jun 2021 22:29:37 +0200 Subject: [PATCH 3/6] ghrc.io publish ci --- publish.yml | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 publish.yml diff --git a/publish.yml b/publish.yml new file mode 100644 index 0000000..fefce96 --- /dev/null +++ b/publish.yml @@ -0,0 +1,49 @@ +# This is a basic workflow to help you get started with Actions + +name: Publish +on: + push: + branches: + - '**' + tags: + - 'v*.*.*' + pull_request: + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Docker meta + id: meta + uses: docker/metadata-action@v3 + with: + # list of Docker images to use as base name for tags + images: ghcr.io/covidpass-org/covidpass + # generate Docker tags based on the following events/attributes + tags: | + type=schedule + type=edge,branch=dev + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 977c0d4f063508e8a775959648df0d407a9265ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hauke=20T=C3=B6njes?= Date: Mon, 28 Jun 2021 22:30:39 +0200 Subject: [PATCH 4/6] Wrong folder for action --- publish.yml => .github/workflows/publish.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename publish.yml => .github/workflows/publish.yml (100%) diff --git a/publish.yml b/.github/workflows/publish.yml similarity index 100% rename from publish.yml rename to .github/workflows/publish.yml From 2519ea8981ddbb66fa02aca00ea40e58a0b1cb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hauke=20T=C3=B6njes?= Date: Mon, 28 Jun 2021 23:37:01 +0200 Subject: [PATCH 5/6] Send Server info about wallet card color --- src/pass.js | 1 + src/payload.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pass.js b/src/pass.js index dc971d7..6e64ee8 100644 --- a/src/pass.js +++ b/src/pass.js @@ -57,6 +57,7 @@ exports.createPass = async function(data) { }, body: JSON.stringify({ PassJsonHash: passHash, + useBlackVersion: payload.dark }) }) diff --git a/src/payload.js b/src/payload.js index dfb78c3..6b1921d 100644 --- a/src/payload.js +++ b/src/payload.js @@ -83,6 +83,7 @@ exports.Payload = class { this.img2x = img2x this.raw = rawData + this.dark = dark this.name = name this.dose = dose From 288bde031aa7d8d9846b65398a6391ba2172f7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hauke=20T=C3=B6njes?= Date: Mon, 28 Jun 2021 23:45:00 +0200 Subject: [PATCH 6/6] Wrong boolean value --- src/pass.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pass.js b/src/pass.js index 6e64ee8..eb18c0c 100644 --- a/src/pass.js +++ b/src/pass.js @@ -57,7 +57,7 @@ exports.createPass = async function(data) { }, body: JSON.stringify({ PassJsonHash: passHash, - useBlackVersion: payload.dark + useBlackVersion: !payload.dark }) })