Add a QR code reader

This commit is contained in:
Rodolphe Bréard 2023-07-30 20:37:07 +02:00
parent 22b5527fde
commit 34620f1747
3 changed files with 134 additions and 3 deletions

113
package-lock.json generated
View file

@ -14,6 +14,7 @@
"base32-encode": "^2.0.0",
"bulma": "^0.9.4",
"vue": "^3.3.4",
"vue-qrcode-reader": "^5.1.0",
"vue-router": "^4.2.4"
},
"devDependencies": {
@ -401,6 +402,28 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@sec-ant/barcode-detector": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@sec-ant/barcode-detector/-/barcode-detector-0.1.5.tgz",
"integrity": "sha512-l6ULVNfp4T1U2JjFTwW26ZZoWRTxCNsXfE1Bk74/1JB1eK6hHPBxVugs3pBUqV75A0inou5S9S+ay4sRBrjieQ==",
"dependencies": {
"@sec-ant/zxing-wasm": "^1.2.4"
}
},
"node_modules/@sec-ant/zxing-wasm": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@sec-ant/zxing-wasm/-/zxing-wasm-1.2.4.tgz",
"integrity": "sha512-8avz7BHc8aa+k0Jym/1dJEOlqsYEZkoqiFtSVXbmxMwWXG7+OJCJBEWRR8VJPOlVmQj4pSVWtJr/dMuIf1TM/A==",
"dependencies": {
"@types/emscripten": "^1.39.6",
"zustand": "^4.3.8"
}
},
"node_modules/@types/emscripten": {
"version": "1.39.7",
"resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.7.tgz",
"integrity": "sha512-tLqYV94vuqDrXh515F/FOGtBcRMTPGvVV1LzLbtYDcQmmhtpf/gLYf+hikBbQk8MzOHNz37wpFfJbYAuSn8HqA=="
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.17",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz",
@ -819,6 +842,24 @@
"node": ">=0.12.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"peer": true
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/magic-string": {
"version": "0.30.1",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
@ -900,6 +941,18 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -945,6 +998,11 @@
"node": ">=14.0.0"
}
},
"node_modules/sdp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@ -973,6 +1031,14 @@
"node": ">=8.0"
}
},
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/vite": {
"version": "4.4.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz",
@ -1040,6 +1106,18 @@
"@vue/shared": "3.3.4"
}
},
"node_modules/vue-qrcode-reader": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.1.0.tgz",
"integrity": "sha512-jOlvpTSMQ0ttYl582VwvCOcO4qNJId0lRN3Cl+Czgwoml6pOVAnwBQb5VMPxxJiwI/nIuKzXxcPoAixf/VMrJw==",
"dependencies": {
"@sec-ant/barcode-detector": "^0.1.5",
"webrtc-adapter": "^8.2.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/vue-router": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz",
@ -1053,6 +1131,41 @@
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/webrtc-adapter": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz",
"integrity": "sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==",
"dependencies": {
"sdp": "^3.2.0"
},
"engines": {
"node": ">=6.0.0",
"npm": ">=3.10.0"
}
},
"node_modules/zustand": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.9.tgz",
"integrity": "sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw==",
"dependencies": {
"use-sync-external-store": "1.2.0"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"immer": ">=9.0",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"immer": {
"optional": true
},
"react": {
"optional": true
}
}
}
}
}

View file

@ -19,6 +19,7 @@
"base32-encode": "^2.0.0",
"bulma": "^0.9.4",
"vue": "^3.3.4",
"vue-qrcode-reader": "^5.1.0",
"vue-router": "^4.2.4"
},
"devDependencies": {

View file

@ -2,6 +2,7 @@
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import { useStorage } from '@vueuse/core'
import { QrcodeStream } from 'vue-qrcode-reader'
import { sha256 } from '@noble/hashes/sha256';
import base32Encode from 'base32-encode';
@ -60,6 +61,18 @@ const addAccount = () => {
}
};
// QR code reader
const scanQrCode = ref(false);
const showQrCodeScanner = (data) => {
scanQrCode.value = true;
};
const onQrCodeDetected = (result_list) => {
if (result_list.length >= 1) {
privateKey.value = result_list[0].rawValue;
scanQrCode.value = false;
}
};
// Cancel button
const cancellDisabled = computed(() => {
return !accounts.value.length;
@ -99,12 +112,16 @@ const resetErrorMessage = () => {
<input class="input" type="text" id="new-addr-domain" placeholder="example.org" v-model="domainName">
</div>
</div>
<div class="field">
<label class="label" for="new-addr-key">Private key</label>
<div class="control">
<label class="label" for="new-addr-key">Private key</label>
<div class="field has-addons">
<div class="control is-expanded">
<input class="input" type="text" id="new-addr-key" v-model="privateKey">
</div>
<p class="control">
<a class="button is-primary" @click="showQrCodeScanner">Scan</a>
</p>
</div>
<qrcode-stream v-if="scanQrCode" @detect="onQrCodeDetected"></qrcode-stream>
<div class="buttons is-centered">
<button class="button is-success" :disabled="addDisabled" @click="addAccount">Add account</button>
<button class="button is-light" v-if="!cancellDisabled" @click="toMainView">Cancel</button>