mirror of https://github.com/keeweb/keeweb.git
124 lines
3.5 KiB
JavaScript
124 lines
3.5 KiB
JavaScript
import { Events } from 'framework/events';
|
|
import { ExternalOtpDeviceModel } from 'models/external/external-otp-device-model';
|
|
import { ExternalOtpEntryModel } from 'models/external/external-otp-entry-model';
|
|
import { Logger } from 'util/logger';
|
|
import { UsbListener } from 'comp/app/usb-listener';
|
|
import { YubiKey } from 'comp/app/yubikey';
|
|
|
|
const logger = new Logger('yubikey');
|
|
|
|
class YubiKeyOtpModel extends ExternalOtpDeviceModel {
|
|
constructor(props) {
|
|
super({
|
|
id: 'yubikey',
|
|
name: 'YubiKey',
|
|
shortName: 'YubiKey',
|
|
deviceClassName: 'YubiKey',
|
|
...props
|
|
});
|
|
}
|
|
|
|
onUsbDevicesChanged = () => {
|
|
if (UsbListener.attachedYubiKeys.length === 0) {
|
|
this.emit('ejected');
|
|
}
|
|
};
|
|
|
|
open(callback) {
|
|
YubiKey.listWithYkman((err, yubiKeys) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
let openSuccess = 0;
|
|
const openErrors = [];
|
|
const openNextYubiKey = () => {
|
|
const yubiKey = yubiKeys.shift();
|
|
this._addYubiKey(yubiKey.serial, (err) => {
|
|
if (YubiKey.aborted) {
|
|
return callback('Aborted');
|
|
}
|
|
if (err) {
|
|
openErrors.push(err);
|
|
} else {
|
|
openSuccess++;
|
|
}
|
|
if (yubiKeys && yubiKeys.length) {
|
|
openNextYubiKey();
|
|
} else {
|
|
if (openSuccess) {
|
|
this._openComplete();
|
|
}
|
|
callback(openSuccess ? null : openErrors[0]);
|
|
}
|
|
});
|
|
};
|
|
openNextYubiKey();
|
|
});
|
|
}
|
|
|
|
_addYubiKey(serial, callback) {
|
|
logger.info('Adding YubiKey', serial);
|
|
|
|
YubiKey.getOtpCodes(serial, (err, codes) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
for (const code of codes) {
|
|
this.entries.push(
|
|
new ExternalOtpEntryModel({
|
|
id: this.entryId(code.title, code.user),
|
|
device: this,
|
|
deviceSubId: serial,
|
|
icon: 'clock-o',
|
|
title: code.title,
|
|
user: code.user,
|
|
needsTouch: code.needsTouch
|
|
})
|
|
);
|
|
}
|
|
|
|
callback();
|
|
});
|
|
}
|
|
|
|
_openComplete() {
|
|
this.active = true;
|
|
this._buildEntryMap();
|
|
Events.on('usb-devices-changed', this.onUsbDevicesChanged);
|
|
}
|
|
|
|
cancelOpen() {
|
|
YubiKey.abort();
|
|
Events.off('usb-devices-changed', this.onUsbDevicesChanged);
|
|
}
|
|
|
|
getOtp(entry, callback) {
|
|
const msPeriod = 30000;
|
|
const timeLeft = msPeriod - (Date.now() % msPeriod) + 500;
|
|
YubiKey.getOtp(entry.deviceSubId, `${entry.title}:${entry.user}`, (err, otp) => {
|
|
callback(err, otp, timeLeft);
|
|
});
|
|
}
|
|
|
|
cancelGetOtp(entry, ps) {
|
|
if (ps) {
|
|
ps.kill();
|
|
}
|
|
}
|
|
|
|
close(callback) {
|
|
Events.off('usb-devices-changed', this.onUsbDevicesChanged);
|
|
this.set({
|
|
active: false
|
|
});
|
|
}
|
|
}
|
|
|
|
YubiKeyOtpModel.defineModelProperties({
|
|
onUsbDevicesChanged: null
|
|
});
|
|
|
|
export { YubiKeyOtpModel };
|