diff --git a/components/Page.tsx b/components/Page.tsx index 97fe0dd..ecf98e2 100644 --- a/components/Page.tsx +++ b/components/Page.tsx @@ -70,6 +70,14 @@ function Page(props: PageProps): JSX.Element { + + + + + + + + NAME diff --git a/src/pass.ts b/src/pass.ts index 4c66899..4b48e46 100644 --- a/src/pass.ts +++ b/src/pass.ts @@ -5,26 +5,10 @@ import {Constants} from "./constants"; import {Payload, PayloadBody, PassDictionary} from "./payload"; import * as Sentry from '@sentry/react'; import { QRCodeMatrixUtil } from '@zxing/library'; +import {QrCode,Encoding,PackageResult,QrFormat,PassPhotoCommon} from './passphoto-common'; const crypto = require('crypto') -enum QrFormat { - PKBarcodeFormatQR = 'PKBarcodeFormatQR', - PKBarcodeFormatPDF417 = 'PKBarcodeFormatPDF417' -} - -enum Encoding { - utf8 = "utf-8", - iso88591 = "iso-8859-1" -} - -interface QrCode { - message: string; - format: QrFormat; - messageEncoding: Encoding; - // altText: string; -} - interface SignData { PassJsonHash: string; useBlackVersion: boolean; @@ -85,74 +69,12 @@ export class PassData { // Create Payload try { - - console.log(JSON.stringify(payloadBody, null, 2), numDose); - - const payload: Payload = new Payload(payloadBody, numDose); - - payload.serialNumber = uuid4(); - - // register record - - const clonedReceipt = Object.assign({}, payloadBody.receipts[numDose]); - delete clonedReceipt.name; - delete clonedReceipt.dateOfBirth; - clonedReceipt["serialNumber"] = payload.serialNumber; - clonedReceipt["type"] = 'applewallet'; - - let requestOptions = { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(clonedReceipt) // body data type must match "Content-Type" header - } - - console.log('registering ' + JSON.stringify(clonedReceipt, null, 2)); - const configResponse = await fetch('/api/config'); - - const configResponseJson = await configResponse.json(); - - const verifierHost = configResponseJson.verifierHost; - const registrationHost = configResponseJson.registrationHost; - let functionSuffix = configResponseJson.functionSuffix; - - if (functionSuffix == undefined) - functionSuffix = ''; - - const registerUrl = `${registrationHost}/register${functionSuffix}`; - // console.log(registerUrl); - - const response = await fetch(registerUrl, requestOptions); - const responseJson = await response.json(); - - console.log(JSON.stringify(responseJson,null,2)); - - if (responseJson["result"] != 'OK') { - console.error(responseJson); - return Promise.reject(); - } - - const encodedUri = `serialNumber=${encodeURIComponent(payload.serialNumber)}&vaccineName=${encodeURIComponent(payloadBody.receipts[numDose].vaccineName)}&vaccinationDate=${encodeURIComponent(payloadBody.receipts[numDose].vaccinationDate)}&organization=${encodeURIComponent(payloadBody.receipts[numDose].organization)}&dose=${encodeURIComponent(payloadBody.receipts[numDose].numDoses)}`; - const qrCodeUrl = `${verifierHost}/verify?${encodedUri}`; - - // console.log(qrCodeUrl); - - let qrCodeMessage = payloadBody.rawData.startsWith('shc:/') - ? payloadBody.rawData - : qrCodeUrl; - - // Create QR Code Object - const qrCode: QrCode = { - message: qrCodeMessage, - format: QrFormat.PKBarcodeFormatQR, - messageEncoding: Encoding.iso88591, - // altText : payload.rawData - - } + + const results = await PassPhotoCommon.preparePayload(payloadBody, numDose); + const payload = results.payload; // Create pass data - const pass: PassData = new PassData(payload, qrCode); + const pass: PassData = new PassData(results.payload, results.qrCode); // Create new zip const zip = [] as { path: string; data: Buffer | string }[]; diff --git a/src/passphoto-common.ts b/src/passphoto-common.ts new file mode 100644 index 0000000..b2fce1b --- /dev/null +++ b/src/passphoto-common.ts @@ -0,0 +1,102 @@ +import {toBuffer as createZip} from 'do-not-zip'; +import {v4 as uuid4} from 'uuid'; + +import {Constants} from "./constants"; +import {Payload, PayloadBody, PassDictionary} from "./payload"; +import * as Sentry from '@sentry/react'; +import { QRCodeMatrixUtil } from '@zxing/library'; + +export enum QrFormat { + PKBarcodeFormatQR = 'PKBarcodeFormatQR', + PKBarcodeFormatPDF417 = 'PKBarcodeFormatPDF417' +} + +export enum Encoding { + utf8 = "utf-8", + iso88591 = "iso-8859-1" +} + +export interface QrCode { + message: string; + format: QrFormat; + messageEncoding: Encoding; + // altText: string; +} + +export interface PackageResult { + payload: Payload; + qrCode: QrCode; +} + +export class PassPhotoCommon { + + static async preparePayload(payloadBody: PayloadBody, numDose: number) : Promise { + console.log(JSON.stringify(payloadBody, null, 2), numDose); + + const payload: Payload = new Payload(payloadBody, numDose); + + payload.serialNumber = uuid4(); + + // register record + + const clonedReceipt = Object.assign({}, payloadBody.receipts[numDose]); + delete clonedReceipt.name; + delete clonedReceipt.dateOfBirth; + clonedReceipt["serialNumber"] = payload.serialNumber; + clonedReceipt["type"] = 'applewallet'; + + let requestOptions = { + method: 'POST', // *GET, POST, PUT, DELETE, etc. + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(clonedReceipt) // body data type must match "Content-Type" header + } + + console.log('registering ' + JSON.stringify(clonedReceipt, null, 2)); + const configResponse = await fetch('/api/config'); + + const configResponseJson = await configResponse.json(); + + const verifierHost = configResponseJson.verifierHost; + const registrationHost = configResponseJson.registrationHost; + let functionSuffix = configResponseJson.functionSuffix; + + if (functionSuffix == undefined) + functionSuffix = ''; + + const registerUrl = `${registrationHost}/register${functionSuffix}`; + // console.log(registerUrl); + + const response = await fetch(registerUrl, requestOptions); + const responseJson = await response.json(); + + console.log(JSON.stringify(responseJson,null,2)); + + if (responseJson["result"] != 'OK') { + console.error(responseJson); + return Promise.reject(); + } + + const encodedUri = `serialNumber=${encodeURIComponent(payload.serialNumber)}&vaccineName=${encodeURIComponent(payloadBody.receipts[numDose].vaccineName)}&vaccinationDate=${encodeURIComponent(payloadBody.receipts[numDose].vaccinationDate)}&organization=${encodeURIComponent(payloadBody.receipts[numDose].organization)}&dose=${encodeURIComponent(payloadBody.receipts[numDose].numDoses)}`; + const qrCodeUrl = `${verifierHost}/verify?${encodedUri}`; + + // console.log(qrCodeUrl); + + let qrCodeMessage = payloadBody.rawData.startsWith('shc:/') + ? payloadBody.rawData + : qrCodeUrl; + + // Create QR Code Object + const qrCode: QrCode = { + message: qrCodeMessage, + format: QrFormat.PKBarcodeFormatQR, + messageEncoding: Encoding.iso88591, + // altText : payload.rawData + + } + + return {payload: payload, qrCode: qrCode} + + } +} \ No newline at end of file diff --git a/src/payload.ts b/src/payload.ts index bc61897..dd3a9c0 100644 --- a/src/payload.ts +++ b/src/payload.ts @@ -37,7 +37,7 @@ export interface PayloadBody { export class Payload { - receipts: Receipt[]; + receipts: HashTable; rawData: string; backgroundColor: string; labelColor: string; @@ -50,14 +50,11 @@ export class Payload { constructor(body: PayloadBody, numDose: number) { let generic: PassDictionary = { - headerFields: [ - ], + headerFields: [], primaryFields: [], secondaryFields: [], auxiliaryFields: [], - backFields: [ - //TODO: add url link back to grassroots site - ] + backFields: [] } this.backgroundColor = COLORS.YELLOW; this.labelColor = COLORS.WHITE @@ -82,7 +79,7 @@ export class Payload { } } - + this.receipts = body.receipts; this.rawData = body.rawData; this.generic = generic; diff --git a/src/photo.ts b/src/photo.ts index c58d36b..97a3e5b 100644 --- a/src/photo.ts +++ b/src/photo.ts @@ -4,25 +4,10 @@ import {v4 as uuid4} from 'uuid'; import {BrowserQRCodeSvgWriter} from "@zxing/browser"; import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image'; import * as Sentry from '@sentry/react'; - -enum QrFormat { - PKBarcodeFormatQR = 'PKBarcodeFormatQR', - PKBarcodeFormatPDF417 = 'PKBarcodeFormatPDF417' -} - -enum Encoding { - utf8 = "utf-8", - iso88591 = "iso-8859-1" -} - -interface QrCode { - message: string; - format: QrFormat; - messageEncoding: Encoding; - // altText: string; -} +import {QrCode,Encoding,PackageResult,QrFormat,PassPhotoCommon} from './passphoto-common'; export class Photo { + logoText: string = Constants.NAME; organizationName: string = Constants.NAME; description: string = Constants.NAME; @@ -33,88 +18,53 @@ export class Photo { barcodes: Array; barcode: QrCode; - - static async generatePass(payloadBody: PayloadBody, numDose: number): Promise { // Create Payload try { - const payload: Payload = new Payload(payloadBody, numDose); - payload.serialNumber = uuid4(); + console.log('generatePass'); + + const results = await PassPhotoCommon.preparePayload(payloadBody, numDose); + + const payload = results.payload; + const qrCode = results.qrCode; - // register record + let receipt; - const clonedReceipt = Object.assign({}, payload.receipt); - delete clonedReceipt.name; - delete clonedReceipt.dateOfBirth; - clonedReceipt["serialNumber"] = payload.serialNumber; - clonedReceipt["type"] = 'photo'; - - let requestOptions = { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(clonedReceipt) // body data type must match "Content-Type" header + if (results.payload.rawData.length == 0) { + receipt = results.payload.receipts[numDose]; + } else { + receipt = results.payload.receipts[numDose]; } - console.log('registering ' + JSON.stringify(clonedReceipt, null, 2)); - const configResponse = await fetch('/api/config') - const verifierHost = (await configResponse.json()).verifierHost - - // const verifierHost = 'https://verifier.vaccine-ontario.ca'; - - const response = await fetch('https://us-central1-grassroot-verifier.cloudfunctions.net/register', requestOptions); - const responseJson = await response.json(); - - console.log(JSON.stringify(responseJson,null,2)); - - if (responseJson["result"] != 'OK') - return Promise.reject(); - - const encodedUri = `serialNumber=${encodeURIComponent(payload.serialNumber)}&vaccineName=${encodeURIComponent(payload.receipt.vaccineName)}&vaccinationDate=${encodeURIComponent(payload.receipt.vaccinationDate)}&organization=${encodeURIComponent(payload.receipt.organization)}&dose=${encodeURIComponent(payload.receipt.numDoses)}`; - const qrCodeUrl = `${verifierHost}/verify?${encodedUri}`; - - // Create QR Code Object - const qrCode: QrCode = { - message: qrCodeUrl, - format: QrFormat.PKBarcodeFormatQR, - messageEncoding: Encoding.iso88591, - // altText : payload.rawData - - } - - // Create photo - // const photo: Photo = new Photo(payload, qrCode); - - // const body = domTree.getElementById('main'); const body = document.getElementById('pass-image'); body.hidden = false; body.style.backgroundColor = payload.backgroundColor - const name = payload.receipt.name; - const dateOfBirth = payload.receipt.dateOfBirth; - const vaccineName = payload.receipt.vaccineName; - let vaccineNameProper = vaccineName.charAt(0) + vaccineName.substr(1).toLowerCase(); - - if (vaccineName.includes('PFIZER')) - vaccineNameProper = 'Pfizer (Comirnaty)' - - if (vaccineName.includes('MODERNA')) - vaccineNameProper = 'Moderna (SpikeVax)' - - if (vaccineName.includes('ASTRAZENECA')) - vaccineNameProper = 'AstraZeneca (Vaxzevria)' - - let doseVaccine = "#" + String(payload.receipt.numDoses) + ": " + vaccineNameProper; + const vaccineName = receipt.vaccineName; + let doseVaccine = "#" + String(receipt.numDoses) + ": " + vaccineName; document.getElementById('vaccineName').innerText = doseVaccine; - document.getElementById('vaccinationDate').innerText = payload.receipt.vaccinationDate; - document.getElementById('organization').innerText = payload.receipt.organization; - document.getElementById('name').innerText = payload.receipt.name; - document.getElementById('dob').innerText = payload.receipt.dateOfBirth; + + document.getElementById('vaccinationDate').innerText = receipt.vaccinationDate; + document.getElementById('organization').innerText = receipt.organization; + document.getElementById('name').innerText = receipt.name; + document.getElementById('dob').innerText = receipt.dateOfBirth; + + if ((results.payload.rawData.length != 0) && (numDose > 1)) { + for (let i = 1; i < numDose; i++) { + + console.log(i); + + receipt = results.payload.receipts[i]; + + document.getElementById('extraRow' + i ).hidden = false; + document.getElementById('vaccinationDate' + i).innerText = receipt.vaccinationDate; + document.getElementById('organization' + i).innerText = receipt.organization; + } + } const codeWriter = new BrowserQRCodeSvgWriter(); const svg = codeWriter.write(qrCode.message,200,200); @@ -123,6 +73,7 @@ export class Photo { const blobPromise = toBlob(body); return blobPromise; + } catch (e) { return Promise.reject(e); }