Capture.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <template>
  2. <div class="modal is-active">
  3. <div class="modal-background"></div>
  4. <div class="modal-content">
  5. <section class="section">
  6. <div class="columns is-centered">
  7. <div class="column is-three-quarters">
  8. <div class="box has-text-centered has-background-black-ter is-shadowless">
  9. <div v-if="errorText">
  10. <p class="block is-size-5">{{ $t('twofaccounts.stream.live_scan_cant_start') }}</p>
  11. <p class="has-text-light block">{{ $t('twofaccounts.stream.' + errorText + '.reason') }}</p>
  12. <p class="is-size-7">{{ $t('twofaccounts.stream.' + errorText + '.solution') }}</p>
  13. </div>
  14. <span v-else class="is-size-4 has-text-light">
  15. <font-awesome-icon :icon="['fas', 'spinner']" size="2x" spin />
  16. </span>
  17. </div>
  18. </div>
  19. </div>
  20. </section>
  21. </div>
  22. <div class="fullscreen-streamer">
  23. <qrcode-stream @decode="submitUri" @init="onStreamerInit" camera="auto" />
  24. </div>
  25. <div class="fullscreen-footer">
  26. <!-- Cancel button -->
  27. <label class="button is-large is-warning is-rounded" @click="exitStream()">
  28. {{ $t('commons.cancel') }}
  29. </label>
  30. </div>
  31. </div>
  32. </template>
  33. <script>
  34. import { QrcodeStream } from 'vue-qrcode-reader'
  35. import Form from './../components/Form'
  36. export default {
  37. data(){
  38. return {
  39. showStream: true,
  40. errorText: '',
  41. form: new Form({
  42. qrcode: null,
  43. uri: '',
  44. }),
  45. }
  46. },
  47. components: {
  48. QrcodeStream,
  49. },
  50. methods: {
  51. exitStream() {
  52. this.camera = 'off'
  53. this.$router.go(-1)
  54. },
  55. async onStreamerInit (promise) {
  56. try {
  57. await promise
  58. }
  59. catch (error) {
  60. if (error.name === 'NotAllowedError') {
  61. this.errorText = 'need_grant_permission'
  62. } else if (error.name === 'NotReadableError') {
  63. this.errorText = 'not_readable'
  64. } else if (error.name === 'NotFoundError') {
  65. this.errorText = 'no_cam_on_device'
  66. } else if (error.name === 'NotSupportedError' || error.name === 'InsecureContextError') {
  67. this.errorText = 'secured_context_required'
  68. } else if (error.name === 'OverconstrainedError') {
  69. this.errorText = 'camera_not_suitable'
  70. } else if (error.name === 'StreamApiNotSupportedError') {
  71. this.errorText = 'stream_api_not_supported'
  72. }
  73. }
  74. },
  75. /**
  76. * Push a decoded URI to the Create or Import form
  77. *
  78. * The basicQRcodeReader option is Off, so qrcode decoding has already be done by vue-qrcode-reader, whether
  79. * from livescan or file input.
  80. * We simply check the uri validity to prevent useless push to the form, but the form will check uri validity too.
  81. */
  82. async submitUri(event) {
  83. this.form.uri = event
  84. if( !this.form.uri ) {
  85. this.$notify({type: 'is-warning', text: this.$t('errors.qrcode_cannot_be_read') })
  86. }
  87. else if( this.form.uri.slice(0, 33).toLowerCase() == "otpauth-migration://offline?data=" ) {
  88. this.pushUriToImportForm(this.form.uri)
  89. }
  90. else if( this.form.uri.slice(0, 15).toLowerCase() !== "otpauth://totp/" && this.form.uri.slice(0, 15).toLowerCase() !== "otpauth://hotp/" ) {
  91. this.$notify({type: 'is-warning', text: this.$t('errors.no_valid_otp') })
  92. }
  93. else {
  94. this.pushUriToCreateForm(this.form.uri)
  95. }
  96. },
  97. pushUriToCreateForm(data) {
  98. this.$router.push({ name: 'createAccount', params: { decodedUri: data } });
  99. },
  100. pushUriToImportForm(data) {
  101. this.$router.push({ name: 'importAccounts', params: { migrationUri: data } });
  102. }
  103. }
  104. }
  105. </script>