From 04a1f697cec17699eff044b26bb3b032739ef8ee Mon Sep 17 00:00:00 2001 From: Billy Lo Date: Sun, 17 Oct 2021 11:56:54 -0400 Subject: [PATCH 1/5] enhancing ios15 check with user agent --- components/Form.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/Form.tsx b/components/Form.tsx index d39a9c0..a00571b 100644 --- a/components/Form.tsx +++ b/components/Form.tsx @@ -14,7 +14,7 @@ import {PassData} from "../src/pass"; import {Photo} from "../src/photo"; import {COLORS} from "../src/colors"; import Colors from './Colors'; -import {isChrome, isIOS, isIPad13, isMacOs, isSafari, deviceDetect, osName, osVersion} from 'react-device-detect'; +import {isChrome, isIOS, isIPad13, isMacOs, isSafari, deviceDetect, osName, osVersion, getUA} from 'react-device-detect'; import * as Sentry from '@sentry/react'; import { counterReset } from 'html2canvas/dist/types/css/property-descriptors/counter-reset'; import { color } from 'html2canvas/dist/types/css/types/color'; @@ -382,7 +382,10 @@ function Form(): JSX.Element { // setAddErrorMessage('Sorry. Apple Wallet pass can be added using Safari or Chrome only.'); // setIsDisabledAppleWallet(true); // } - if (isIOS && (!osVersion.startsWith('15'))) { + + const uaIsiOS15 = getUA.includes('iPhone OS 15'); + if (isIOS && ((!osVersion.startsWith('15')) && !uaIsiOS15)) { + console.warn(`Not iOS15 error: isIOS=${isIOS} osVersion=${osVersion} UA=${getUA}` ); setAddErrorMessage('Sorry, iOS 15+ is needed for the Apple Wallet functionality to work with Smart Health Card') setIsDisabledAppleWallet(true); return; From 24ec6b062b4d28157cb1122f0ddf8eec84a51a01 Mon Sep 17 00:00:00 2001 From: Billy Lo Date: Sun, 17 Oct 2021 11:58:10 -0400 Subject: [PATCH 2/5] add sentry logging for ios15 log errors --- components/Form.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/Form.tsx b/components/Form.tsx index a00571b..f6562cd 100644 --- a/components/Form.tsx +++ b/components/Form.tsx @@ -385,7 +385,9 @@ function Form(): JSX.Element { const uaIsiOS15 = getUA.includes('iPhone OS 15'); if (isIOS && ((!osVersion.startsWith('15')) && !uaIsiOS15)) { - console.warn(`Not iOS15 error: isIOS=${isIOS} osVersion=${osVersion} UA=${getUA}` ); + const message = `Not iOS15 error: isIOS=${isIOS} osVersion=${osVersion} UA=${getUA}` + console.warn(message); + Sentry.captureMessage(message); setAddErrorMessage('Sorry, iOS 15+ is needed for the Apple Wallet functionality to work with Smart Health Card') setIsDisabledAppleWallet(true); return; From 8e83c65f6c649b5bca2aee501e07a93074e89c5e Mon Sep 17 00:00:00 2001 From: Ryan Slobojan Date: Sun, 17 Oct 2021 13:30:18 -0400 Subject: [PATCH 3/5] Added direct camera-scan support for creating QR codes * SHC QR codes can now be scanned directly from the camera, eliminating the need for error-prone screenshotting or photos - the scanner will auto-detect an SHC QR code and proceed to the next step --- components/Form.tsx | 80 +++++++++++++++++++++++++------------ public/locales/en/index.yml | 12 +++--- src/process.ts | 43 ++++++++++++-------- 3 files changed, 86 insertions(+), 49 deletions(-) diff --git a/components/Form.tsx b/components/Form.tsx index d39a9c0..e0816f0 100644 --- a/components/Form.tsx +++ b/components/Form.tsx @@ -9,15 +9,11 @@ import Card from "./Card"; import Alert from "./Alert"; import Check from './Check'; import {PayloadBody} from "../src/payload"; -import {getPayloadBodyFromFile} from "../src/process"; +import {getPayloadBodyFromFile, processSHCCode} from "../src/process"; import {PassData} from "../src/pass"; import {Photo} from "../src/photo"; -import {COLORS} from "../src/colors"; -import Colors from './Colors'; -import {isChrome, isIOS, isIPad13, isMacOs, isSafari, deviceDetect, osName, osVersion} from 'react-device-detect'; +import {isIOS, isMacOs, isSafari, osVersion} from 'react-device-detect'; import * as Sentry from '@sentry/react'; -import { counterReset } from 'html2canvas/dist/types/css/property-descriptors/counter-reset'; -import { color } from 'html2canvas/dist/types/css/types/color'; import Bullet from './Bullet'; @@ -27,9 +23,6 @@ function Form(): JSX.Element { // Whether camera is open or not const [isCameraOpen, setIsCameraOpen] = useState(false); - // Currently selected color - const [selectedColor, setSelectedColor] = useState(COLORS.WHITE); - // Currently selected dose const [selectedDose, setSelectedDose] = useState(2); @@ -98,7 +91,7 @@ function Form(): JSX.Element { if (inputFile && inputFile.current) { inputFile.current.addEventListener('change', () => { let selectedFile = inputFile.current.files[0]; - if (selectedFile !== undefined) { + if (selectedFile) { setFileLoading(true); setQrCode(undefined); setPayloadBody(undefined); @@ -132,7 +125,7 @@ function Form(): JSX.Element { } catch (e) { setFile(file); setFileLoading(false); - if (e != undefined) { + if (e) { console.error(e); // Don't report known errors to Sentry @@ -151,11 +144,15 @@ function Form(): JSX.Element { setFileErrorMessage("Unexpected error. Sorry."); } } - } // Show file Dialog async function showFileDialog() { + hideCameraView(); + + // Clear out any currently-selected files + inputFile.current.value = ''; + inputFile.current.click(); } @@ -172,10 +169,11 @@ function Form(): JSX.Element { // Hide camera view async function hideCameraView() { - if (globalControls !== undefined) { + if (globalControls) { globalControls.stop(); } setIsCameraOpen(false); + _setFileErrorMessages([]); } // Show camera view @@ -189,13 +187,13 @@ function Form(): JSX.Element { try { deviceList = await BrowserQRCodeReader.listVideoInputDevices(); } catch (e) { - setAddErrorMessage('noCameraAccess'); + setFileErrorMessage('noCameraAccess'); return; } // Check if camera device is present if (deviceList.length == 0) { - setAddErrorMessage("noCameraFound"); + setFileErrorMessage("noCameraFound"); return; } @@ -207,24 +205,46 @@ function Form(): JSX.Element { // Start decoding from video device await codeReader.decodeFromVideoDevice(undefined, previewElem, - (result, error, controls) => { - if (result !== undefined) { - setQrCode(result); - setFile(undefined); + async (result, error, controls) => { + if (result) { + const qrCode = result.getText(); + // Check if this was a valid SHC QR code - if it was not, display an error + if (!qrCode.startsWith('shc:/')) { + setFileErrorMessage('The scanned QR code was not a valid Smart Health Card QR code!'); + } else { + _setFileErrorMessages([]); + setQrCode(result); + setFile(undefined); + setPayloadBody(undefined); + setShowDoseOption(false); + setGenerated(false); + checkBrowserType(); + + const payloadBody = await processSHCCode(qrCode); + + setPayloadBody(payloadBody); - controls.stop(); - - // Reset - setGlobalControls(undefined); - setIsCameraOpen(false); + controls.stop(); + + // Reset + setGlobalControls(undefined); + setIsCameraOpen(false); + } } - if (error !== undefined) { - setAddErrorMessage(error.message); + if (error) { + setFileErrorMessage(error.message); } } ) ); + setQrCode(undefined); + setPayloadBody(undefined); + setFile(undefined); + setShowDoseOption(false); + setGenerated(false); + _setFileErrorMessages([]); + setIsCameraOpen(true); } @@ -442,6 +462,12 @@ function Form(): JSX.Element { className="focus:outline-none h-20 bg-green-600 hover:bg-gray-700 text-white font-semibold rounded-md"> {t('index:openFile')} +
+