import {execFile} from 'child_process';

import keytar from 'keytar';

import {Emitter} from 'atom';

export const UNAUTHENTICATED = Symbol('UNAUTHENTICATED');

export class KeytarStrategy {
  static isValid() {
    const rand = Math.floor(Math.random() * 10e20).toString(16);
    keytar.replacePassword('atom-test-service', rand, rand);
    const pass = keytar.getPassword('atom-test-service', rand);
    return pass === rand;
  }

  getPassword(service, account) {
    return keytar.getPassword(service, account);
  }

  replacePassword(service, account, password) {
    return keytar.replacePassword(service, account, password);
  }

  deletePassword(service, account) {
    return keytar.deletePassword(service, account);
  }
}

export class SecurityBinaryStrategy {
  static isValid() {
    return process.platform === 'darwin';
  }

  async getPassword(service, account) {
    try {
      const password = await this.exec(['find-generic-password', '-s', service, '-a', account, '-w']);
      return password.trim() || UNAUTHENTICATED;
    } catch (err) {
      return UNAUTHENTICATED;
    }
  }

  replacePassword(service, account, newPassword) {
    return this.exec(['add-generic-password', '-s', service, '-a', account, '-w', newPassword, '-U']);
  }

  deletePassword(service, account) {
    return this.exec(['delete-generic-password', '-s', service, '-a', account]);
  }

  exec(securityArgs, {binary} = {binary: 'security'}) {
    return new Promise((resolve, reject) => {
      execFile(binary, securityArgs, (error, stdout) => {
        if (error) { return reject(error); }
        return resolve(stdout);
      });
    });
  }
}

let instance = null;
const strategies = [KeytarStrategy, SecurityBinaryStrategy];
export default class GithubLoginModel {
  static get() {
    if (!instance) {
      instance = new GithubLoginModel();
    }
    return instance;
  }

  constructor(Strategy = strategies.find(strat => strat.isValid())) {
    this.emitter = new Emitter();
    if (!Strategy) {
      throw new Error('None of the listed GithubLoginModel strategies returned true for `isValid`');
    }
    this.strategy = new Strategy();
  }

  async getToken(account) {
    let password = await this.strategy.getPassword('atom-github', account);
    if (!password) {
      // User is not logged in
      password = UNAUTHENTICATED;
    }
    return password;
  }

  async setToken(account, token) {
    await this.strategy.replacePassword('atom-github', account, token);
    this.didUpdate();
  }

  async removeToken(account) {
    await this.strategy.deletePassword('atom-github', account);
    this.didUpdate();
  }

  didUpdate() {
    this.emitter.emit('did-update');
  }

  onDidUpdate(cb) {
    return this.emitter.on('did-update', cb);
  }

  destroy() {
    this.emitter.dispose();
  }
}

@@ -403,28 +403,111 @@
     
-return pass === rand
+const success = pass === rand;%0A    keytar.deletePassword('atom-test-service', rand);%0A    return success
 ;%0A  

Delete test password from Keychain when verifying Keytar strategy