functional shc (including photo)
This commit is contained in:
parent
0fe177dffa
commit
0e53240dd0
|
@ -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>
|
||||
|
|
86
src/pass.ts
86
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;
|
||||
|
@ -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 }[];
|
||||
|
|
|
@ -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}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
115
src/photo.ts
115
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<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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue