UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

105 lines (104 loc) 4.07 kB
"use strict"; /** * Copyright (c) Microsoft. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createOsxSecurityParsingStream = exports.OsxSecurityParsingStream = void 0; const Pumpify = require("pumpify"); const split = require("split2"); const stream = require("stream"); const debug = require("debug")("appcenter-cli:util:token-store:osx:osx-keychain-parser"); // // Regular expressions that match the various fields in the input // // Fields at the root - not attributes const rootFieldRe = /^([^: \t]+):(?: (?:"([^"]+)")|(.*))?$/; // Attribute values, this gets a little more complicated const attrRe = /^ (?:(0x[0-9a-fA-F]+) |"([a-z]{4})")<[^>]+>=(?:(<NULL>)|"([^"]+)"|(0x[0-9a-fA-F]+)(?: "([^"]+)")|(.*)?)/; // // Stream based parser for the OSX security(1) program output. // Implements a simple state machine. States are: // // 0 - Waiting for the initial "keychain" string. // 1 - Waiting for the "attributes" string. adds any properties to the // current entry object being parsed while waiting. // 2 - reading attributes. Continues adding the attributes to the // current entry object until we hit either a non-indented line // or end. At which point we emit. // class OsxSecurityParsingStream extends stream.Transform { constructor() { super({ objectMode: true }); this.currentEntry = null; this.inAttributes = false; } _transform(chunk, encoding, callback) { const line = chunk.toString(); debug(`Parsing line [${line}]`); const rootMatch = line.match(rootFieldRe); if (rootMatch) { this.processRootLine(rootMatch[1], rootMatch[2] || rootMatch[3]); } else { const attrMatch = line.match(attrRe); if (attrMatch) { // Did we match a four-char named field? We don't care about hex fields if (attrMatch[2]) { // We skip nulls, and grab text rather than hex encoded versions of value const value = attrMatch[6] || attrMatch[4]; if (value) { this.processAttributeLine(attrMatch[2], value); } } } } callback(); } _flush(callback) { this.emitCurrentEntry(); callback(); } emitCurrentEntry() { if (this.currentEntry) { this.push(this.currentEntry); this.currentEntry = null; } } processRootLine(key, value) { debug(`matched root line`); if (this.inAttributes) { debug(`was in attributes, emitting`); this.emitCurrentEntry(); this.inAttributes = false; } if (key === "attributes") { debug(`now in attributes`); this.inAttributes = true; } else { debug(`adding root attribute ${key} with value ${value} to object`); this.currentEntry = this.currentEntry || {}; this.currentEntry[key] = value; } } processAttributeLine(key, value) { debug(`adding attribute ${key} with value ${value} to object`); this.currentEntry[key] = value; } } exports.OsxSecurityParsingStream = OsxSecurityParsingStream; function createOsxSecurityParsingStream() { return new Pumpify.obj(split(), new OsxSecurityParsingStream()); } exports.createOsxSecurityParsingStream = createOsxSecurityParsingStream;