mirror of
https://github.com/covidpass-org/covidpass.git
synced 2025-02-18 04:30:53 +01:00
Changes regarding C# backend
- Working with C# backend, signing just the pass.json hash - Bugfixes error handling
This commit is contained in:
parent
c38718cb50
commit
bb23afc000
@ -9,9 +9,9 @@ export function Alert() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div id="alert" style={{"display": "none"}} className="bg-red-100 border border-red-400 text-red-700 px-4 mx-4 py-3 rounded relative" role="alert">
|
<div id="alert" style={{"display": "none"}} className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 mt-5 rounded relative" role="alert">
|
||||||
<strong className="font-bold pr-2" id="heading"></strong>
|
<strong className="font-bold pr-2" id="heading"/>
|
||||||
<span className="block sm:inline" id="message"></span>
|
<span className="block sm:inline" id="message"/>
|
||||||
<span className="absolute top-0 bottom-0 right-0 px-4 py-3" onClick={close}>
|
<span className="absolute top-0 bottom-0 right-0 px-4 py-3" onClick={close}>
|
||||||
<svg className="fill-current h-6 w-6 text-red-500" role="button" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><title>Close</title><path d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"/></svg>
|
<svg className="fill-current h-6 w-6 text-red-500" role="button" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><title>Close</title><path d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"/></svg>
|
||||||
</span>
|
</span>
|
||||||
|
@ -2,10 +2,10 @@ const PDFJS = require('pdfjs-dist')
|
|||||||
PDFJS.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDFJS.version}/pdf.worker.js`
|
PDFJS.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDFJS.version}/pdf.worker.js`
|
||||||
|
|
||||||
import jsQR from "jsqr"
|
import jsQR from "jsqr"
|
||||||
import { saveAs } from 'file-saver'
|
import {saveAs} from 'file-saver'
|
||||||
|
|
||||||
import { decodeData } from "../src/decode"
|
import {decodeData} from "../src/decode"
|
||||||
import { createPass } from "../src/pass"
|
import {createPass} from "../src/pass"
|
||||||
import Card from "../components/Card"
|
import Card from "../components/Card"
|
||||||
import Alert from "../components/Alert"
|
import Alert from "../components/Alert"
|
||||||
|
|
||||||
@ -43,12 +43,12 @@ function Form() {
|
|||||||
const file = document.getElementById('pdf').files[0]
|
const file = document.getElementById('pdf').files[0]
|
||||||
|
|
||||||
const result = await readFileAsync(file)
|
const result = await readFileAsync(file)
|
||||||
var typedarray = new Uint8Array(result)
|
let typedArray = new Uint8Array(result)
|
||||||
|
|
||||||
const canvas = document.getElementById('canvas')
|
const canvas = document.getElementById('canvas')
|
||||||
const ctx = canvas.getContext('2d')
|
const ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
var loadingTask = PDFJS.getDocument(typedarray)
|
let loadingTask = PDFJS.getDocument(typedArray)
|
||||||
await loadingTask.promise.then(async function (pdfDocument) {
|
await loadingTask.promise.then(async function (pdfDocument) {
|
||||||
const pdfPage = await pdfDocument.getPage(1)
|
const pdfPage = await pdfDocument.getPage(1)
|
||||||
const viewport = pdfPage.getViewport({ scale: 1 })
|
const viewport = pdfPage.getViewport({ scale: 1 })
|
||||||
@ -63,8 +63,8 @@ function Form() {
|
|||||||
return await renderTask.promise
|
return await renderTask.promise
|
||||||
})
|
})
|
||||||
|
|
||||||
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
||||||
var code = jsQR(imageData.data, imageData.width, imageData.height, {
|
let code = jsQR(imageData.data, imageData.width, imageData.height, {
|
||||||
inversionAttempts: 'dontInvert',
|
inversionAttempts: 'dontInvert',
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -78,9 +78,7 @@ function Form() {
|
|||||||
error('Invalid QR code found', 'Make sure that you picked the correct PDF')
|
error('Invalid QR code found', 'Make sure that you picked the correct PDF')
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = { decoded: decoded, raw: rawData }
|
return {decoded: decoded, raw: rawData}
|
||||||
|
|
||||||
return result
|
|
||||||
} else {
|
} else {
|
||||||
error('No QR code found', 'Try scanning the PDF again')
|
error('No QR code found', 'Try scanning the PDF again')
|
||||||
}
|
}
|
||||||
@ -119,7 +117,7 @@ function Form() {
|
|||||||
saveAs(passBlob, 'covid.pkpass')
|
saveAs(passBlob, 'covid.pkpass')
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error('Error:', error.message)
|
error('Error:', e.message)
|
||||||
} finally {
|
} finally {
|
||||||
document.getElementById('spin').style.display = 'none'
|
document.getElementById('spin').style.display = 'none'
|
||||||
}
|
}
|
||||||
@ -155,7 +153,7 @@ function Form() {
|
|||||||
<option value="teal">teal</option>
|
<option value="teal">teal</option>
|
||||||
</select>
|
</select>
|
||||||
<div className="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none">
|
<div className="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none">
|
||||||
<svg className="w-5 h-5 fill-current" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" fillRule="evenodd"></path></svg>
|
<svg className="w-5 h-5 fill-current" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" fillRule="evenodd"/></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
} />
|
} />
|
||||||
@ -177,8 +175,8 @@ function Form() {
|
|||||||
</button>
|
</button>
|
||||||
<div id="spin" style={{ "display": "none" }}>
|
<div id="spin" style={{ "display": "none" }}>
|
||||||
<svg className="animate-spin h-5 w-5 ml-2" viewBox="0 0 24 24">
|
<svg className="animate-spin h-5 w-5 ml-2" viewBox="0 0 24 24">
|
||||||
<circle className="opacity-0" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
<circle className="opacity-0" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"/>
|
||||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { NextSeo } from 'next-seo';
|
import { NextSeo } from 'next-seo';
|
||||||
|
|
||||||
import Form from '../components/Form'
|
import Form from '../components/Form'
|
||||||
import Logo from '../components/Logo'
|
|
||||||
import Card from '../components/Card'
|
import Card from '../components/Card'
|
||||||
import Page from '../components/Page'
|
import Page from '../components/Page'
|
||||||
|
|
||||||
|
@ -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.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 = {
|
exports.VALUE_TYPES = {
|
||||||
medicalProducts: 'vaccine-medicinal-product.json',
|
medicalProducts: 'vaccine-medicinal-product.json',
|
||||||
countryCodes: 'country-2-codes.json',
|
countryCodes: 'country-2-codes.json',
|
||||||
manufacturers: 'vaccine-mah-manf.json',
|
manufacturers: 'vaccine-mah-manf.json',
|
||||||
}
|
}
|
||||||
exports.COLORS = {
|
exports.COLORS = {
|
||||||
white: 'rgb(255, 255, 255)',
|
white: 'rgb(255, 255, 255)',
|
||||||
black: 'rgb(0, 0, 0)',
|
black: 'rgb(0, 0, 0)',
|
||||||
grey: 'rgb(33, 33, 33)',
|
grey: 'rgb(33, 33, 33)',
|
||||||
green: 'rgb(27, 94, 32)',
|
green: 'rgb(27, 94, 32)',
|
||||||
indigo: 'rgb(26, 35, 126)',
|
indigo: 'rgb(26, 35, 126)',
|
||||||
blue: 'rgb(1, 87, 155)',
|
blue: 'rgb(1, 87, 155)',
|
||||||
purple: 'rgb(74, 20, 140)',
|
purple: 'rgb(74, 20, 140)',
|
||||||
teal: 'rgb(0, 77, 64)',
|
teal: 'rgb(0, 77, 64)',
|
||||||
}
|
}
|
||||||
exports.NAME = 'CovidPass'
|
exports.NAME = 'CovidPass'
|
||||||
|
exports.PASS_IDENTIFIER = 'pass.de.marvinsextro.covidpass' // WELL KNOWN
|
||||||
|
exports.TEAM_IDENTIFIER = 'X8Q7Q2RLTD' // WELL KNOWN
|
||||||
|
29
src/pass.js
29
src/pass.js
@ -1,18 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const consts = require('./constants')
|
const constants = require('./constants')
|
||||||
const utils = require('./utils')
|
const utils = require('./utils')
|
||||||
const img = require('./img')
|
|
||||||
|
|
||||||
const { Payload } = require('./payload')
|
const { Payload } = require('./payload')
|
||||||
const { toBuffer } = require('do-not-zip')
|
const { toBuffer } = require('do-not-zip')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
|
|
||||||
exports.createPass = async function(data) {
|
exports.createPass = async function(data) {
|
||||||
async function getJSONfromURL(url) {
|
|
||||||
return await (await fetch(url)).json()
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBufferHash(buffer) {
|
function getBufferHash(buffer) {
|
||||||
// creating hash
|
// creating hash
|
||||||
const sha = crypto.createHash('sha1');
|
const sha = crypto.createHash('sha1');
|
||||||
@ -30,6 +25,7 @@ exports.createPass = async function(data) {
|
|||||||
// Adding required files
|
// Adding required files
|
||||||
// Create pass.json
|
// Create pass.json
|
||||||
zip.push({ path: 'pass.json', data: Buffer.from(JSON.stringify(pass)) })
|
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.png', data: payload.img1x })
|
||||||
zip.push({ path: 'icon@2x.png', data: payload.img2x })
|
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 });
|
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',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/octet-stream',
|
'Accept': 'application/octet-stream',
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
manifest: manifestJson
|
PassJsonHash: passHash,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.status != 200) {
|
if (response.status !== 200) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,8 +83,6 @@ exports.createPass = async function(data) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
let signingIdentity = await getJSONfromURL(consts.API_BASE_URL + 'signing_identity')
|
|
||||||
|
|
||||||
const qrCode = {
|
const qrCode = {
|
||||||
message: payload.raw,
|
message: payload.raw,
|
||||||
@ -97,14 +91,14 @@ exports.createPass = async function(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pass = {
|
const pass = {
|
||||||
passTypeIdentifier: signingIdentity['pass_identifier'],
|
passTypeIdentifier: constants.PASS_IDENTIFIER,
|
||||||
teamIdentifier: signingIdentity['pass_team_id'],
|
teamIdentifier: constants.TEAM_IDENTIFIER,
|
||||||
sharingProhibited: true,
|
sharingProhibited: true,
|
||||||
voided: false,
|
voided: false,
|
||||||
formatVersion: 1,
|
formatVersion: 1,
|
||||||
logoText: consts.NAME,
|
logoText: constants.NAME,
|
||||||
organizationName: consts.NAME,
|
organizationName: constants.NAME,
|
||||||
description: consts.NAME,
|
description: constants.NAME,
|
||||||
labelColor: payload.labelColor,
|
labelColor: payload.labelColor,
|
||||||
foregroundColor: payload.foregroundColor,
|
foregroundColor: payload.foregroundColor,
|
||||||
backgroundColor: payload.backgroundColor,
|
backgroundColor: payload.backgroundColor,
|
||||||
@ -182,6 +176,5 @@ exports.createPass = async function(data) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let buf = await signPassWithRemote(pass, payload)
|
return await signPassWithRemote(pass, payload)
|
||||||
return buf
|
|
||||||
}
|
}
|
||||||
|
@ -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")
|
const fetch = require("node-fetch")
|
||||||
|
|
||||||
exports.getValueSets = async function() {
|
exports.getValueSets = async function() {
|
||||||
async function getJSONfromURL(url) {
|
async function getJSONFromURL(url) {
|
||||||
return await (await fetch(url)).json()
|
return await (await fetch(url)).json()
|
||||||
}
|
}
|
||||||
|
|
||||||
var valueSets = {}
|
let valueSets = {}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(VALUE_TYPES)) {
|
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
|
return valueSets
|
||||||
|
Loading…
x
Reference in New Issue
Block a user