appcenter-cli
Version:
Command line tool for Visual Studio App Center
124 lines (123 loc) • 5.12 kB
JavaScript
;
// Token store implementation over OSX keychain
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOsxTokenStore = exports.OsxTokenStore = void 0;
//
// Access to the OSX keychain - list, add, get password, remove
//
const _ = require("lodash");
const rx = require("rxjs");
const childProcess = require("child_process");
const from = require("from2");
const split = require("split2");
const through = require("through2");
const osx_keychain_parser_1 = require("./osx-keychain-parser");
const debug = require("debug")("appcenter-cli:util:token-store:osx:osx-token-store");
const util_1 = require("util");
const securityPath = "/usr/bin/security";
const serviceName = "appcenter-cli";
const oldServiceName = "mobile-center-cli";
class OsxTokenStore {
list() {
return rx.Observable.create((observer) => {
const securityProcess = childProcess.spawn(securityPath, ["dump-keychain"]);
const securityStream = securityProcess.stdout
.pipe(split())
.pipe(through(function (line, enc, done) {
done(null, line.toString().replace(/\\134/g, "\\"));
}))
.pipe(new osx_keychain_parser_1.OsxSecurityParsingStream());
securityStream.on("data", (data) => {
debug(`listing, got data ${util_1.inspect(data)}`);
if (data.svce !== serviceName) {
debug(`service does not match, skipping`);
return;
}
const key = data.acct;
// Have to get specific token to get tokens, but we have ids
const accessToken = {
id: data.gena,
token: null,
};
debug(`Outputting ${util_1.inspect({ key, accessToken })}`);
observer.next({ key, accessToken });
});
securityStream.on("end", (err) => {
debug(`output from security program complete`);
if (err) {
observer.error(err);
}
else {
observer.complete();
}
});
});
}
get(key, useOldName = false) {
const args = ["find-generic-password", "-a", key, "-s", useOldName ? oldServiceName : serviceName, "-g"];
return new Promise((resolve, reject) => {
resolve = _.once(resolve);
reject = _.once(reject);
childProcess.execFile(securityPath, args, (err, stdout, stderr) => {
if (err) {
return reject(err);
}
const match = /^password: (?:0x[0-9A-F]+. )?"(.*)"$/m.exec(stderr);
if (match) {
const accessToken = match[1].replace(/\\134/g, "\\");
debug(`stdout for security program = "${stdout}"`);
debug(`parsing stdout`);
// Parse the rest of the information from stdout to get user & token ID
const parsed = from([stdout]).pipe(osx_keychain_parser_1.createOsxSecurityParsingStream());
parsed.on("data", (data) => {
debug(`got data on key lookup: ${util_1.inspect(data)}`);
resolve({
key: data.acct,
accessToken: {
id: data.gena,
token: accessToken,
},
});
});
parsed.on("error", (err) => {
debug(`parsed string failed`);
reject(err);
});
}
else {
reject(new Error("Password in incorrect format"));
}
});
});
}
set(key, value) {
const args = ["add-generic-password", "-a", key, "-D", "appcenter cli password", "-s", serviceName, "-w", value.token, "-U"];
if (value.id) {
args.push("-G", value.id);
}
return new Promise((resolve, reject) => {
childProcess.execFile(securityPath, args, function (err, stdout, stderr) {
if (err) {
return reject(new Error("Could not add password to keychain: " + stderr));
}
return resolve();
});
});
}
remove(key) {
const args = ["delete-generic-password", "-a", key, "-s", serviceName];
return new Promise((resolve, reject) => {
childProcess.execFile(securityPath, args, function (err, stdout, stderr) {
if (err) {
return reject(new Error("Could not remove account from keychain, " + stderr));
}
return resolve();
});
});
}
}
exports.OsxTokenStore = OsxTokenStore;
function createOsxTokenStore() {
return new OsxTokenStore();
}
exports.createOsxTokenStore = createOsxTokenStore;