Add QR scanner to Unseal page. Closes #22.
This commit is contained in:
parent
228901a68c
commit
18f034acd3
|
@ -13,6 +13,8 @@
|
|||
"mini-css-extract-plugin": "^1.4.1",
|
||||
"node-sass": "^5.0.0",
|
||||
"prismjs": "^1.23.0",
|
||||
"qr-scanner": "^1.2.0",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass-loader": "^11.0.1",
|
||||
"uikit": "^3.6.19",
|
||||
"webpack": "^5.32.0",
|
||||
|
|
|
@ -2,14 +2,103 @@ import { Page } from "../types/Page.js";
|
|||
import { submitUnsealKey, getSealStatus } from "../api.js";
|
||||
import { setPageContent, setErrorText, changePage } from "../pageUtils.js";
|
||||
import { makeElement } from "../htmlUtils.js";
|
||||
import { Margin } from "../elements/Margin.js";
|
||||
import { MarginInline } from "../elements/MarginInline.js";
|
||||
import i18next from 'i18next';
|
||||
import QrScanner from 'qr-scanner';
|
||||
|
||||
import qrScannerWorkerSource from '!!raw-loader!qr-scanner/qr-scanner-worker.min.js';
|
||||
QrScanner.WORKER_PATH = URL.createObjectURL(new Blob([qrScannerWorkerSource]));
|
||||
|
||||
const UnsealInputModes = {
|
||||
FORM_INPUT: "FORM_INPUT",
|
||||
QR_INPUT: "QR_INPUT"
|
||||
}
|
||||
|
||||
export class UnsealPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
//this.mode = UnsealInputModes.QR_INPUT;
|
||||
this.mode = UnsealInputModes.FORM_INPUT;
|
||||
}
|
||||
cleanup() {
|
||||
this.deinitWebcam()
|
||||
clearInterval(this.refresher);
|
||||
}
|
||||
|
||||
deinitWebcam() {
|
||||
try {
|
||||
this.stream.getTracks().forEach(function (track) {
|
||||
track.stop();
|
||||
});
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
makeRefresher() {
|
||||
this.refresher = setInterval(async function () {
|
||||
this.updateSealProgress(await getSealStatus());
|
||||
}.bind(this), 1000);
|
||||
}
|
||||
|
||||
async render() {
|
||||
this.unsealProgress = makeElement({
|
||||
tag: "progress",
|
||||
class: "uk-progress",
|
||||
attributes: { value: "0", max: "0" }
|
||||
});
|
||||
this.unsealProgressText = makeElement({
|
||||
tag: "p",
|
||||
text: i18next.t("unseal_keys_progress", { progress: "0", keys_needed: "0" }),
|
||||
});
|
||||
this.unsealInputContent = makeElement({
|
||||
tag: "div"
|
||||
})
|
||||
setPageContent(makeElement({
|
||||
tag: "div",
|
||||
children: [
|
||||
this.unsealProgress,
|
||||
makeElement({
|
||||
tag: "p",
|
||||
id: "errorText",
|
||||
class: ["uk-text-danger", "uk-margin-top"]
|
||||
}),
|
||||
this.unsealProgressText,
|
||||
this.unsealInputContent
|
||||
]
|
||||
}));
|
||||
this.switchInputMode(this.mode);
|
||||
this.updateSealProgress(await getSealStatus());
|
||||
this.makeRefresher();
|
||||
}
|
||||
|
||||
setButtons(method) {
|
||||
let newMethod;
|
||||
let buttonText;
|
||||
newMethod = method == UnsealInputModes.FORM_INPUT ? UnsealInputModes.QR_INPUT : UnsealInputModes.FORM_INPUT;
|
||||
buttonText = newMethod == UnsealInputModes.FORM_INPUT ? i18next.t("unseal_input_btn") : i18next.t("unseal_qr_btn");
|
||||
this.unsealInputContent.appendChild(makeElement({
|
||||
tag: "button",
|
||||
class: ["uk-button", "uk-button-primary"],
|
||||
text: buttonText,
|
||||
onclick: () => {
|
||||
this.switchInputMode(newMethod);
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
switchInputMode(method) {
|
||||
this.deinitWebcam();
|
||||
this.unsealInputContent.querySelectorAll('*').forEach(n => n.remove())
|
||||
if (method == UnsealInputModes.FORM_INPUT) this.makeUnsealForm();
|
||||
if (method == UnsealInputModes.QR_INPUT) this.makeQRInput();
|
||||
this.setButtons(method);
|
||||
}
|
||||
|
||||
makeUnsealForm() {
|
||||
this.unsealKeyForm = makeElement({
|
||||
tag: "form",
|
||||
children: [
|
||||
|
@ -30,36 +119,44 @@ export class UnsealPage extends Page {
|
|||
})),
|
||||
]
|
||||
});
|
||||
|
||||
this.unsealProgress = makeElement({
|
||||
tag: "progress",
|
||||
class: "uk-progress",
|
||||
attributes: { value: "0", max: "0" }
|
||||
});
|
||||
this.unsealProgressText = makeElement({
|
||||
tag: "p",
|
||||
text: i18next.t("unseal_keys_progress", { progress: "0", keys_needed: "0" }),
|
||||
});
|
||||
|
||||
setPageContent(makeElement({
|
||||
tag: "div",
|
||||
children: [
|
||||
this.unsealProgress,
|
||||
makeElement({
|
||||
tag: "p",
|
||||
id: "errorText",
|
||||
class: ["uk-text-danger", "uk-margin-top"]
|
||||
}),
|
||||
this.unsealProgressText,
|
||||
this.unsealKeyForm
|
||||
]
|
||||
}));
|
||||
this.unsealInputContent.appendChild(this.unsealKeyForm);
|
||||
this.unsealKeyForm.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
pageState.currentPage.handleKeySubmit();
|
||||
});
|
||||
this.updateSealProgress(await getSealStatus());
|
||||
this.handleKeySubmit();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
async makeQRInput() {
|
||||
let webcamVideo = makeElement({
|
||||
tag: "video"
|
||||
})
|
||||
|
||||
let QRInput = makeElement({
|
||||
tag: "div",
|
||||
children: [
|
||||
Margin(webcamVideo),
|
||||
]
|
||||
})
|
||||
this.unsealInputContent.appendChild(QRInput);
|
||||
|
||||
|
||||
this.stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: {
|
||||
facingMode: 'environment',
|
||||
},
|
||||
audio: false,
|
||||
});
|
||||
webcamVideo.srcObject = this.stream;
|
||||
let lastSeenCode = "";
|
||||
const qrScanner = new QrScanner(webcamVideo, function (code) {
|
||||
if (lastSeenCode == code) return;
|
||||
lastSeenCode = code;
|
||||
this.submitKey(code);
|
||||
console.log('decoded qr code:', code)
|
||||
}.bind(this));
|
||||
qrScanner.start();
|
||||
}
|
||||
|
||||
updateSealProgress(data) {
|
||||
let progress = data.progress;
|
||||
let keysNeeded = data.t;
|
||||
|
@ -77,10 +174,8 @@ export class UnsealPage extends Page {
|
|||
}
|
||||
}
|
||||
|
||||
async handleKeySubmit() {
|
||||
let formData = new FormData(this.unsealKeyForm);
|
||||
|
||||
submitUnsealKey(formData.get("key")).then(_ => {
|
||||
submitKey(key) {
|
||||
submitUnsealKey(key).then(_ => {
|
||||
getSealStatus().then(data => {
|
||||
this.updateSealProgress(data);
|
||||
});
|
||||
|
@ -88,6 +183,12 @@ export class UnsealPage extends Page {
|
|||
setErrorText(e.message);
|
||||
});
|
||||
}
|
||||
|
||||
async handleKeySubmit() {
|
||||
let formData = new FormData(this.unsealKeyForm);
|
||||
|
||||
this.submitKey(formData.get("key"))
|
||||
}
|
||||
get name() {
|
||||
return i18next.t("unseal_vault_text");
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ $global-warning-background: #d08770;
|
|||
$global-danger-background: #bf616a;
|
||||
|
||||
$button-primary-background: #5e81ac;
|
||||
$progress-bar-background: #5e81ac;
|
||||
|
||||
// Keep these in same order as https://github.com/uikit/uikit/blob/develop/src/less/components/_import.less
|
||||
@import "uikit/src/scss/variables.scss";
|
||||
|
|
|
@ -26,6 +26,9 @@ module.exports = {
|
|||
// Unseal Page
|
||||
"unseal_vault_text": "Unseal the Vault",
|
||||
"submit_key_btn": "Submit Key",
|
||||
"unseal_input_btn": "Switch to Manual Key Input",
|
||||
"unseal_qr_btn": "Switch to QR Key Input",
|
||||
|
||||
"key_input_placeholder": "Key",
|
||||
"unseal_keys_progress": "Keys: {{progress}}/{{keys_needed}}",
|
||||
|
||||
|
|
Loading…
Reference in a new issue