2020-06-03 18:07:50 +02:00
|
|
|
import KeychainServiceDriverBase from './KeychainServiceDriverBase';
|
2020-11-05 18:58:23 +02:00
|
|
|
const Setting = require('../../models/Setting').default;
|
|
|
|
const BaseService = require('../BaseService').default;
|
2020-06-03 18:07:50 +02:00
|
|
|
|
|
|
|
export default class KeychainService extends BaseService {
|
|
|
|
|
|
|
|
private driver:KeychainServiceDriverBase;
|
|
|
|
private static instance_:KeychainService;
|
2020-10-20 17:16:18 +02:00
|
|
|
private enabled_:boolean = true;
|
2020-06-03 18:07:50 +02:00
|
|
|
|
|
|
|
static instance():KeychainService {
|
|
|
|
if (!this.instance_) this.instance_ = new KeychainService();
|
|
|
|
return this.instance_;
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:16:18 +02:00
|
|
|
public initialize(driver:KeychainServiceDriverBase) {
|
2020-06-03 18:07:50 +02:00
|
|
|
if (!driver.appId || !driver.clientId) throw new Error('appId and clientId must be set on the KeychainServiceDriver');
|
|
|
|
this.driver = driver;
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:16:18 +02:00
|
|
|
// This is to programatically disable the keychain service, regardless whether keychain
|
|
|
|
// is supported or not in the system (In other word, this might "enabled" but nothing
|
|
|
|
// will be saved to the keychain if there isn't one).
|
|
|
|
public get enabled():boolean {
|
|
|
|
return this.enabled_;
|
|
|
|
}
|
|
|
|
|
|
|
|
public set enabled(v:boolean) {
|
|
|
|
this.enabled_ = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
public async setPassword(name:string, password:string):Promise<boolean> {
|
|
|
|
if (!this.enabled) return false;
|
|
|
|
|
2020-06-03 18:07:50 +02:00
|
|
|
// Due to a bug in macOS, this may throw an exception "The user name or passphrase you entered is not correct."
|
|
|
|
// The fix is to open Keychain Access.app. Right-click on the login keychain and try locking it and then unlocking it again.
|
|
|
|
// https://github.com/atom/node-keytar/issues/76
|
|
|
|
return this.driver.setPassword(name, password);
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:16:18 +02:00
|
|
|
public async password(name:string):Promise<string> {
|
|
|
|
if (!this.enabled) return null;
|
|
|
|
|
2020-06-03 18:07:50 +02:00
|
|
|
return this.driver.password(name);
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:16:18 +02:00
|
|
|
public async deletePassword(name:string):Promise<void> {
|
|
|
|
if (!this.enabled) return;
|
|
|
|
|
2020-06-03 18:07:50 +02:00
|
|
|
await this.driver.deletePassword(name);
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:16:18 +02:00
|
|
|
public async detectIfKeychainSupported() {
|
2020-06-03 18:07:50 +02:00
|
|
|
this.logger().info('KeychainService: checking if keychain supported');
|
|
|
|
|
|
|
|
if (Setting.value('keychain.supported') >= 0) {
|
|
|
|
this.logger().info('KeychainService: check was already done - skipping. Supported:', Setting.value('keychain.supported'));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const passwordIsSet = await this.setPassword('zz_testingkeychain', 'mytest');
|
|
|
|
|
|
|
|
if (!passwordIsSet) {
|
|
|
|
this.logger().info('KeychainService: could not set test password - keychain support will be disabled');
|
|
|
|
Setting.setValue('keychain.supported', 0);
|
|
|
|
} else {
|
|
|
|
const result = await this.password('zz_testingkeychain');
|
|
|
|
await this.deletePassword('zz_testingkeychain');
|
|
|
|
this.logger().info('KeychainService: tried to set and get password. Result was:', result);
|
|
|
|
Setting.setValue('keychain.supported', result === 'mytest' ? 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|