functional shc (including photo)

This commit is contained in:
Billy Lo 2021-09-30 00:26:15 -04:00
parent 0fe177dffa
commit 0e53240dd0
5 changed files with 153 additions and 173 deletions

View File

@ -70,6 +70,14 @@ function Page(props: PageProps): JSX.Element {
<td id='organization' style={{width: 220}}></td>
<td id='vaccinationDate' style={{width:120}}></td>
</tr>
<tr id='extraRow2' hidden>
<td id='organization2' style={{width: 220}}></td>
<td id='vaccinationDate2' style={{width:120}}></td>
</tr>
<tr id='extraRow1' hidden>
<td id='organization1' style={{width: 220}}></td>
<td id='vaccinationDate1' style={{width:120}}></td>
</tr>
<tr style={{height: 20}}></tr>
<tr>
<td><b>NAME</b></td>

View File

@ -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;
@ -86,73 +70,11 @@ 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 }[];

102
src/passphoto-common.ts Normal file
View File

@ -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<PackageResult> {
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}
}
}

View File

@ -37,7 +37,7 @@ export interface PayloadBody {
export class Payload {
receipts: Receipt[];
receipts: HashTable<Receipt>;
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;

View File

@ -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<QrCode>;
barcode: QrCode;
static async generatePass(payloadBody: PayloadBody, numDose: number): Promise<Blob> {
// Create Payload
try {
const payload: Payload = new Payload(payloadBody, numDose);
payload.serialNumber = uuid4();
console.log('generatePass');
// register record
const results = await PassPhotoCommon.preparePayload(payloadBody, numDose);
const clonedReceipt = Object.assign({}, payload.receipt);
delete clonedReceipt.name;
delete clonedReceipt.dateOfBirth;
clonedReceipt["serialNumber"] = payload.serialNumber;
clonedReceipt["type"] = 'photo';
const payload = results.payload;
const qrCode = results.qrCode;
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
let receipt;
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);
}