186 lines
4.7 KiB
JavaScript
186 lines
4.7 KiB
JavaScript
'use strict';
|
|
|
|
const constants = require('./constants')
|
|
const utils = require('./utils')
|
|
|
|
const { Payload } = require('./payload')
|
|
const { toBuffer } = require('do-not-zip')
|
|
const crypto = require('crypto')
|
|
|
|
exports.createPass = async function(data) {
|
|
function getBufferHash(buffer) {
|
|
// creating hash
|
|
const sha = crypto.createHash('sha1');
|
|
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(
|
|
zip.reduce(
|
|
(res, { path, data }) => {
|
|
res[path] = getBufferHash(data);
|
|
return res;
|
|
},
|
|
{},
|
|
),
|
|
);
|
|
zip.push({ path: 'manifest.json', data: manifestJson });
|
|
|
|
// 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',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
PassJsonHash: passHash,
|
|
useBlackVersion: !payload.dark
|
|
})
|
|
})
|
|
|
|
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 {
|
|
valueSets = await utils.getValueSets()
|
|
} catch {
|
|
return undefined
|
|
}
|
|
|
|
let payload
|
|
|
|
try {
|
|
payload = new Payload(data, valueSets)
|
|
} catch (e) {
|
|
return undefined
|
|
}
|
|
|
|
const qrCode = {
|
|
message: payload.raw,
|
|
format: "PKBarcodeFormatQR",
|
|
messageEncoding: "utf-8"
|
|
}
|
|
|
|
const pass = {
|
|
passTypeIdentifier: constants.PASS_IDENTIFIER,
|
|
teamIdentifier: constants.TEAM_IDENTIFIER,
|
|
sharingProhibited: false,
|
|
voided: false,
|
|
formatVersion: 1,
|
|
logoText: constants.NAME,
|
|
organizationName: constants.NAME,
|
|
description: constants.NAME,
|
|
labelColor: payload.labelColor,
|
|
foregroundColor: payload.foregroundColor,
|
|
backgroundColor: payload.backgroundColor,
|
|
serialNumber: payload.uvci,
|
|
barcodes: [qrCode],
|
|
barcode: qrCode,
|
|
generic: {
|
|
headerFields: [
|
|
{
|
|
key: "type",
|
|
label: "Certificate Type",
|
|
value: payload.certificateType
|
|
}
|
|
],
|
|
primaryFields: [
|
|
{
|
|
key: "name",
|
|
label: "Name",
|
|
value: payload.name
|
|
}
|
|
],
|
|
secondaryFields: [
|
|
{
|
|
key: "dose",
|
|
label: "Dose",
|
|
value: payload.dose
|
|
},
|
|
{
|
|
key: "dov",
|
|
label: "Date of Vaccination",
|
|
value: payload.dateOfVaccination,
|
|
textAlignment: "PKTextAlignmentRight"
|
|
}
|
|
],
|
|
auxiliaryFields: [
|
|
{
|
|
key: "vaccine",
|
|
label: "Vaccine",
|
|
value: payload.vaccineName
|
|
},
|
|
{
|
|
key: "dob",
|
|
label: "Date of Birth", value:
|
|
payload.dateOfBirth,
|
|
textAlignment: "PKTextAlignmentRight"
|
|
}
|
|
],
|
|
backFields: [
|
|
{
|
|
key: "uvci",
|
|
label: "Unique Certificate Identifier (UVCI)",
|
|
value: payload.uvci
|
|
},
|
|
{
|
|
key: "issuer",
|
|
label: "Certificate Issuer",
|
|
value: payload.certificateIssuer
|
|
},
|
|
{
|
|
key: "country",
|
|
label: "Country of Vaccination",
|
|
value: payload.countryOfVaccination
|
|
},
|
|
{
|
|
key: "manufacturer",
|
|
label: "Manufacturer",
|
|
value: payload.manufacturer
|
|
},
|
|
{
|
|
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."
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
return await signPassWithRemote(pass, payload)
|
|
}
|