keeweb/app/scripts/comp/otp-qr-reader.js

169 lines
5.8 KiB
JavaScript
Raw Normal View History

2016-03-31 22:52:04 +02:00
'use strict';
var Backbone = require('backbone'),
Alerts = require('./alerts'),
Locale = require('../util/locale'),
Logger = require('../util/logger'),
FeatureDetector = require('../util/feature-detector'),
2016-04-01 23:09:16 +02:00
Otp = require('../util/otp'),
2016-03-31 22:52:04 +02:00
QrCode = require('qrcode');
var logger = new Logger('otp-qr-reader');
var OtpQrReader = {
alert: null,
2016-04-02 16:34:30 +02:00
fileInput: null,
2016-03-31 22:52:04 +02:00
read: function() {
var screenshotKey = FeatureDetector.screenshotToClipboardShortcut();
if (screenshotKey) {
screenshotKey = Locale.detSetupOtpAlertBodyWith.replace('{}', '<code>' + screenshotKey + '</code>');
}
2016-07-17 21:08:23 +02:00
var pasteKey = FeatureDetector.isMobile ? ''
2016-07-17 13:30:38 +02:00
: Locale.detSetupOtpAlertBodyWith.replace('{}',
2016-03-31 22:52:04 +02:00
'<code>' + FeatureDetector.actionShortcutSymbol() + 'V</code>');
OtpQrReader.startListenClipoard();
2016-04-04 20:45:17 +02:00
var buttons = [{result: 'manually', title: Locale.detSetupOtpManualButton, silent: true},
Alerts.buttons.cancel];
2016-07-17 21:08:23 +02:00
if (FeatureDetector.isMobile) {
2016-04-04 20:45:17 +02:00
buttons.unshift({result: 'select', title: Locale.detSetupOtpScanButton});
2016-04-02 16:34:30 +02:00
}
2016-07-17 21:08:23 +02:00
var line3 = FeatureDetector.isMobile ? Locale.detSetupOtpAlertBody3Mobile
2016-07-17 13:30:38 +02:00
: Locale.detSetupOtpAlertBody3.replace('{}', pasteKey || '');
2016-03-31 22:52:04 +02:00
OtpQrReader.alert = Alerts.alert({
icon: 'qrcode',
header: Locale.detSetupOtpAlert,
body: [Locale.detSetupOtpAlertBody,
Locale.detSetupOtpAlertBody1,
Locale.detSetupOtpAlertBody2.replace('{}', screenshotKey || ''),
2016-04-04 20:45:17 +02:00
line3,
Locale.detSetupOtpAlertBody4
2016-03-31 22:52:04 +02:00
].join('<br/>'),
esc: '',
click: '',
enter: '',
2016-04-02 16:34:30 +02:00
buttons: buttons,
complete: function(res) {
2016-03-31 22:52:04 +02:00
OtpQrReader.alert = null;
OtpQrReader.stopListenClipboard();
2016-04-02 16:34:30 +02:00
if (res === 'select') {
OtpQrReader.selectFile();
2016-04-04 20:45:17 +02:00
} else if (res === 'manually') {
OtpQrReader.enterManually();
2016-04-02 16:34:30 +02:00
}
2016-03-31 22:52:04 +02:00
}
});
2016-04-02 18:43:13 +02:00
// transparent window with QR scanner - is it better? check usability of this
2016-03-31 22:52:04 +02:00
// var BrowserWindow = require('../../comp/launcher').remReq('browser-window');
2016-04-02 18:43:13 +02:00
// new BrowserWindow({ width: 800, height: 600, show: false, alwaysOnTop: true, backgroundColor: '#80FFFFFF',
// transparent: true }).show();
2016-03-31 22:52:04 +02:00
},
2016-04-02 16:34:30 +02:00
selectFile: function() {
if (!OtpQrReader.fileInput) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('capture', 'camera');
input.setAttribute('accept', 'image/*');
input.setAttribute('class', 'hide-by-pos');
OtpQrReader.fileInput = input;
OtpQrReader.fileInput.onchange = OtpQrReader.fileSelected;
}
OtpQrReader.fileInput.click();
},
fileSelected: function() {
var file = OtpQrReader.fileInput.files[0];
if (!file || file.type.indexOf('image') < 0) {
return;
}
OtpQrReader.readFile(file);
},
2016-03-31 22:52:04 +02:00
startListenClipoard: function() {
document.addEventListener('paste', OtpQrReader.pasteEvent);
},
stopListenClipboard: function() {
document.removeEventListener('paste', OtpQrReader.pasteEvent);
},
pasteEvent: function(e) {
2016-07-17 13:30:38 +02:00
var item = _.find(e.clipboardData.items, item => item.kind === 'file' && item.type.indexOf('image') !== -1);
2016-03-31 22:52:04 +02:00
if (!item) {
2016-04-02 16:34:30 +02:00
logger.debug('Paste without file');
2016-03-31 22:52:04 +02:00
return;
}
2016-04-02 16:34:30 +02:00
logger.info('Reading pasted image', item.type);
2016-03-31 22:52:04 +02:00
if (OtpQrReader.alert) {
OtpQrReader.alert.change({
header: Locale.detOtpImageReading
});
}
2016-04-02 16:34:30 +02:00
OtpQrReader.readFile(item.getAsFile());
},
readFile: function(file) {
2016-03-31 22:52:04 +02:00
var reader = new FileReader();
reader.onload = function() {
logger.debug('Image data loaded');
OtpQrReader.readQr(reader.result);
};
2016-04-02 16:34:30 +02:00
reader.readAsDataURL(file);
2016-03-31 22:52:04 +02:00
},
readQr: function(imageData) {
var image = new Image();
image.onload = function() {
logger.debug('Image format loaded');
try {
var ts = logger.ts();
var url = new QrCode(image).decode();
2016-04-01 21:19:27 +02:00
logger.info('QR code read', logger.ts(ts));
2016-04-02 16:34:30 +02:00
OtpQrReader.removeAlert();
2016-03-31 22:52:04 +02:00
try {
var otp = Otp.parseUrl(url);
OtpQrReader.trigger('qr-read', otp);
} catch (err) {
2016-04-01 21:19:27 +02:00
logger.error('Error parsing QR code', err);
2016-03-31 22:52:04 +02:00
Alerts.error({
header: Locale.detOtpQrWrong,
2016-07-17 13:30:38 +02:00
body: Locale.detOtpQrWrongBody + '<pre class="modal__pre">' + _.escape(err.toString()) + '</pre>'
2016-03-31 22:52:04 +02:00
});
}
} catch (e) {
logger.error('Error reading QR code', e);
2016-04-02 16:34:30 +02:00
OtpQrReader.removeAlert();
2016-03-31 22:52:04 +02:00
Alerts.error({
header: Locale.detOtpQrError,
body: Locale.detOtpQrErrorBody
});
}
};
image.onerror = function() {
logger.debug('Image load error');
2016-04-02 16:34:30 +02:00
OtpQrReader.removeAlert();
2016-03-31 22:52:04 +02:00
Alerts.error({
header: Locale.detOtpImageError,
body: Locale.detOtpImageErrorBody
});
};
image.src = imageData;
2016-04-02 16:34:30 +02:00
},
2016-04-04 20:45:17 +02:00
enterManually: function() {
OtpQrReader.trigger('enter-manually');
},
2016-04-02 16:34:30 +02:00
removeAlert: function() {
if (OtpQrReader.alert) {
2016-04-03 21:16:05 +02:00
OtpQrReader.alert.closeImmediate();
2016-04-02 16:34:30 +02:00
}
2016-03-31 22:52:04 +02:00
}
};
_.extend(OtpQrReader, Backbone.Events);
module.exports = OtpQrReader;