Archived
1
0

Featureful (#31)

* Fix loading within the CLI

* Remove app

* Remove promise handle

* Add initial travis file

* Add libxkbfile dependency

* Add libxkbfile-dev

* Add build script

* Fix malformed bash statement

* Remove yarn from script

* Improve build script

* Extract upx before usage

* Only run upx if on linux

* Ensure resource directory exists

* Pack runnable binary

* Export binary with platform

* Improve build process

* Install upx before running install script

* Update typescript version before running nexe

* Add os.release() function for multi-platform support

* Update travis.yml to improve deployment

* Add on CI

* Update to v1.31.0

* Add libsecret

* Update build target

* Skip cleanup

* Fix built-in extensions

* Add basics for apps

* Create custom DNS server

* Fix forking within CLI. Fixes TS language features

* Fix filename resolve

* Fix default extensions path

* Add custom dialog

* Store workspace path

* Remove outfiles

* Cleanup

* Always authed outside of CLI

* Use location.host for client

* Remove useless app interface

* Remove debug file for building wordlist

* Use chromes tcp host

* Update patch

* Build browser app before packaging

* Replace all css containing file:// URLs, fix webviews

* Fix save

* Fix mkdir
This commit is contained in:
Kyle Carberry
2019-02-21 11:55:42 -06:00
committed by Asher
parent bdd24081ab
commit 85d2225e0c
84 changed files with 5204 additions and 264 deletions

16
packages/server/README.md Normal file
View File

@ -0,0 +1,16 @@
# server
## Endpoints
### `/tunnel/<port>`
Tunnels a TCP connection over WebSockets. Implemented for proxying connections from a remote machine locally.
### `/ports`
Watches for open ports. Implemented for tunneling ports on the remote server.
### `/resource/<url>`
Reads files on GET.
Writes files on POST.

View File

@ -18,9 +18,12 @@
"@oclif/plugin-help": "^2.1.4",
"express": "^4.16.4",
"express-static-gzip": "^1.1.3",
"httpolyglot": "^0.1.2",
"mime-types": "^2.1.21",
"nexe": "^2.0.0-rc.34",
"segfault-handler": "^1.0.1",
"node-netstat": "^1.6.0",
"pem": "^1.14.1",
"promise.prototype.finally": "^3.1.0",
"spdlog": "^0.7.2",
"ws": "^6.1.2",
"xhr2": "^0.1.4"
@ -29,6 +32,7 @@
"@types/express": "^4.16.0",
"@types/fs-extra": "^5.0.4",
"@types/mime-types": "^2.1.0",
"@types/pem": "^1.9.4",
"@types/ws": "^6.0.1",
"fs-extra": "^7.0.1",
"string-replace-webpack-plugin": "^0.1.3",

View File

@ -3,57 +3,12 @@ const fse = require("fs-extra");
const os = require("os");
const path = require("path");
const nexe = require("nexe");
const zlib = require("zlib");
const nexeRoot = path.join(os.homedir(), ".nexe");
if (!fs.existsSync(nexeRoot)) {
throw new Error("run nexe manually on a binary to initialize it");
}
const listed = fs.readdirSync(nexeRoot);
listed.forEach((list) => {
if (list.startsWith("linux")) {
const stat = fs.statSync(path.join(nexeRoot, list));
if (stat.isFile()) {
if (stat.size > 20000000) {
throw new Error("must use upx to shrink node binary in ~/.nexe/" + list);
}
}
}
});
const tmpDir = path.join(__dirname, "../build");
if (fs.existsSync(tmpDir)) {
console.log("Removing old build dir...");
fse.removeSync(tmpDir);
}
console.log("Copying build files...");
fse.copySync(path.join(__dirname, "../resources"), tmpDir, {
recursive: true,
});
const modDir = path.join(tmpDir, "modules");
fs.mkdirSync(modDir);
fse.copySync(path.join(__dirname, "../../protocol/node_modules/node-pty/build/Release/pty.node"), path.join(modDir, "pty.node"));
const zipper = (p) => {
const stat = fs.statSync(p);
if (!stat.isDirectory()) {
fs.writeFileSync(p + ".gz", zlib.gzipSync(fs.readFileSync(p)));
fse.removeSync(p);
return;
}
const files = fs.readdirSync(p);
files.forEach((f) => zipper(path.join(p, f)));
};
zipper(path.join(tmpDir, "web"));
zipper(path.join(tmpDir, "bootstrap-fork.js"));
nexe.compile({
debugBundle: true,
input: path.join(__dirname, "../out/cli.js"),
output: 'cli',
targets: ["linux"],
output: `cli-${process.env.TRAVIS_OS_NAME || os.platform()}`,
targets: [os.platform()],
native: {
spdlog: {
additionalFiles: [

View File

@ -6,7 +6,7 @@ import * as os from "os";
import * as path from "path";
import * as WebSocket from "ws";
import { createApp } from "./server";
import { requireModule } from "./vscode/bootstrapFork";
import { requireModule, requireFork } from "./vscode/bootstrapFork";
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
import { setup as setupNativeModules } from "./modules";
import { fillFs } from "./fill";
@ -26,6 +26,8 @@ export class Entry extends Command {
// Dev flags
"bootstrap-fork": flags.string({ hidden: true }),
"fork": flags.string({ hidden: true }),
env: flags.string({ hidden: true }),
args: flags.string({ hidden: true }),
};
@ -76,6 +78,12 @@ export class Entry extends Command {
return requireModule(modulePath, builtInExtensionsDir);
}
if (flags["fork"]) {
const modulePath = flags["fork"];
return requireFork(modulePath, JSON.parse(flags.args!), builtInExtensionsDir);
}
const dataDir = flags["data-dir"] || path.join(os.homedir(), ".vscode-remote");
const workingDir = args["workdir"];
@ -92,6 +100,38 @@ export class Entry extends Command {
const logDir = path.join(dataDir, "logs", new Date().toISOString().replace(/[-:.TZ]/g, ""));
process.env.VSCODE_LOGS = logDir;
const certPath = flags.cert;
const certKeyPath = flags["cert-key"];
if (certPath && !certKeyPath) {
logger.error("'--cert-key' flag is required when specifying a certificate!");
process.exit(1);
}
if (!certPath && certKeyPath) {
logger.error("'--cert' flag is required when specifying certificate key!");
process.exit(1);
}
let certData: Buffer | undefined;
let certKeyData: Buffer | undefined;
if (typeof certPath !== "undefined" && typeof certKeyPath !== "undefined") {
try {
certData = fs.readFileSync(certPath);
} catch (ex) {
logger.error(`Failed to read certificate: ${ex.message}`);
process.exit(1);
}
try {
certKeyData = fs.readFileSync(certKeyPath);
} catch (ex) {
logger.error(`Failed to read certificate key: ${ex.message}`);
process.exit(1);
}
}
logger.info("\u001B[1mvscode-remote v1.0.0");
// TODO: fill in appropriate doc url
logger.info("Additional documentation: https://coder.com/docs");
@ -111,7 +151,9 @@ export class Entry extends Command {
}
});
const app = createApp((app) => {
const password = "023450wf0951";
const hasCustomHttps = certData && certKeyData;
const app = await createApp((app) => {
app.use((req, res, next) => {
res.on("finish", () => {
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip));
@ -132,10 +174,13 @@ export class Entry extends Command {
app.use(require("webpack-hot-middleware")(compiler));
}
}, {
builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir,
workingDirectory: workingDir,
});
builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir,
workingDirectory: workingDir,
}, password, hasCustomHttps ? {
key: certKeyData,
cert: certData,
} : undefined);
logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port));
app.server.listen(flags.port, flags.host);
@ -161,7 +206,7 @@ export class Entry extends Command {
}
logger.info(" ");
logger.info("Password:\u001B[1m 023450wf09");
logger.info(`Password:\u001B[1m ${password}`);
logger.info(" ");
logger.info("Started (click the link below to open):");
logger.info(`http://localhost:${flags.port}/`);

View File

@ -49,7 +49,11 @@ export const fillFs = (): void => {
}
};
if (customPromisify) {
(<any>fs[propertyName])[util.promisify.custom] = customPromisify;
(<any>fs[propertyName])[util.promisify.custom] = (...args: any[]) => {
return customPromisify(...args).catch((ex) => {
throw ex;
});
};
}
};
@ -113,13 +117,6 @@ export const fillFs = (): void => {
const fileDesc = fds.get(fd)!;
/**
* `readFile` is filled within nexe, but `read` is not
* https://github.com/nexe/nexe/blob/master/src/fs/patch.ts#L199
* We can simulate a real _read_ by reading the entire file.
* Efficiency can be improved here by storing the entire file in memory
* until it has been closed.
*/
return fs.readFile(fileDesc.path, (err, rb) => {
if (err) {
return callOld();

View File

@ -35,8 +35,10 @@ export const setup = (dataDirectory: string): void => {
*/
unpackModule("pty");
const nodePtyUtils = require("../../protocol/node_modules/node-pty/lib/utils") as typeof import("../../protocol/node_modules/node-pty/src/utils");
nodePtyUtils.loadNative = (modName: string) => {
// tslint:disable-next-line:no-any
nodePtyUtils.loadNative = (modName: string): any => {
return __non_webpack_require__(path.join(dataDirectory, "modules", modName + ".node"));
};
// tslint:disable-next-line:no-unused-expression
require("../../protocol/node_modules/node-pty/lib/index") as typeof import("../../protocol/node_modules/node-pty/src/index");
};

View File

@ -0,0 +1,105 @@
//@ts-ignore
import * as netstat from "node-netstat";
import { Event, Emitter } from "@coder/events";
export interface PortScanner {
readonly ports: ReadonlyArray<number>;
readonly onAdded: Event<ReadonlyArray<number>>;
readonly onRemoved: Event<ReadonlyArray<number>>;
dispose(): void;
}
/**
* Creates a disposable port scanner.
* Will scan local ports and emit events when ports are added or removed.
* Currently only scans TCP ports.
*/
export const createPortScanner = (scanInterval: number = 250): PortScanner => {
const ports = new Map<number, number>();
const addEmitter = new Emitter<number[]>();
const removeEmitter = new Emitter<number[]>();
const scan = (onCompleted: (err?: Error) => void): void => {
const scanTime = Date.now();
const added: number[] = [];
netstat({
done: (err: Error): void => {
const removed: number[] = [];
ports.forEach((value, key) => {
if (value !== scanTime) {
// Remove port
removed.push(key);
ports.delete(key);
}
});
if (removed.length > 0) {
removeEmitter.emit(removed);
}
if (added.length > 0) {
addEmitter.emit(added);
}
onCompleted(err);
},
filter: {
state: "LISTEN",
},
}, (data: {
readonly protocol: string;
readonly local: {
readonly port: number;
readonly address: string;
};
}) => {
// https://en.wikipedia.org/wiki/Registered_port
if (data.local.port <= 1023 || data.local.port >= 49151) {
return;
}
// Only forward TCP ports
if (!data.protocol.startsWith("tcp")) {
return;
}
if (!ports.has(data.local.port)) {
added.push(data.local.port);
}
ports.set(data.local.port, scanTime);
});
};
let lastTimeout: NodeJS.Timer | undefined;
let disposed: boolean = false;
const doInterval = (): void => {
scan(() => {
if (disposed) {
return;
}
lastTimeout = setTimeout(doInterval, scanInterval);
});
};
doInterval();
return {
get ports(): number[] {
return Array.from(ports.keys());
},
get onAdded(): Event<number[]> {
return addEmitter.event;
},
get onRemoved(): Event<number[]> {
return removeEmitter.event;
},
dispose(): void {
if (typeof lastTimeout !== "undefined") {
clearTimeout(lastTimeout);
}
disposed = true;
},
};
};

View File

@ -1,4 +1,4 @@
import { logger } from "@coder/logger";
import { logger, field } from "@coder/logger";
import { ReadWriteConnection } from "@coder/protocol";
import { Server, ServerOptions } from "@coder/protocol/src/node/server";
import * as express from "express";
@ -6,30 +6,116 @@ import * as express from "express";
import * as expressStaticGzip from "express-static-gzip";
import * as fs from "fs";
import * as http from "http";
//@ts-ignore
import * as httpolyglot from "httpolyglot";
import * as https from "https";
import * as mime from "mime-types";
import * as net from "net";
import * as path from "path";
import * as pem from "pem";
import * as util from "util";
import * as ws from "ws";
import { isCli, buildDir } from "./constants";
import { TunnelCloseCode } from "@coder/tunnel/src/common";
import { handle as handleTunnel } from "@coder/tunnel/src/server";
import { createPortScanner } from "./portScanner";
import { buildDir, isCli } from "./constants";
export const createApp = (registerMiddleware?: (app: express.Application) => void, options?: ServerOptions): {
export const createApp = async (registerMiddleware?: (app: express.Application) => void, options?: ServerOptions, password?: string, httpsOptions?: https.ServerOptions): Promise<{
readonly express: express.Application;
readonly server: http.Server;
readonly wss: ws.Server;
} => {
}> => {
const parseCookies = (req: http.IncomingMessage): { [key: string]: string } => {
const cookies: { [key: string]: string } = {};
const rc = req.headers.cookie;
if (rc) {
rc.split(";").forEach((cook) => {
const parts = cook.split("=");
cookies[parts.shift()!.trim()] = decodeURI(parts.join("="));
});
}
return cookies;
};
const isAuthed = (req: http.IncomingMessage): boolean => {
try {
if (!password || !isCli) {
return true;
}
// Try/catch placed here just in case
const cookies = parseCookies(req);
if (cookies.password && cookies.password === password) {
return true;
}
} catch (ex) {
logger.error("Failed to parse cookies", field("error", ex));
}
return false;
};
const isEncrypted = (socket: net.Socket): boolean => {
// tslint:disable-next-line:no-any
return (socket as any).encrypted;
};
const app = express();
if (registerMiddleware) {
registerMiddleware(app);
}
const server = http.createServer(app);
const certs = await new Promise<pem.CertificateCreationResult>((res, rej): void => {
pem.createCertificate({
selfSigned: true,
}, (err, result) => {
if (err) {
rej(err);
return;
}
res(result);
});
});
const server = httpolyglot.createServer({
key: certs.serviceKey,
cert: certs.certificate,
}, app) as http.Server;
const wss = new ws.Server({ server });
wss.shouldHandle = (req): boolean => {
// Should handle auth here
return true;
return isAuthed(req);
};
wss.on("connection", (ws) => {
const portScanner = createPortScanner();
wss.on("connection", (ws, req) => {
if (req.url && req.url.startsWith("/tunnel")) {
try {
const rawPort = req.url.split("/").pop();
const port = Number.parseInt(rawPort!, 10);
handleTunnel(ws, port);
} catch (ex) {
ws.close(TunnelCloseCode.Error, ex.toString());
}
return;
}
if (req.url && req.url.startsWith("/ports")) {
const onAdded = portScanner.onAdded((added) => ws.send(JSON.stringify({ added })));
const onRemoved = portScanner.onRemoved((removed) => ws.send(JSON.stringify({ removed })));
ws.on("close", () => {
onAdded.dispose();
onRemoved.dispose();
});
return ws.send(JSON.stringify({ ports: portScanner.ports }));
}
const connection: ReadWriteConnection = {
onMessage: (cb): void => {
ws.addEventListener("message", (event) => cb(event.data));
@ -52,11 +138,17 @@ export const createApp = (registerMiddleware?: (app: express.Application) => voi
});
const baseDir = buildDir || path.join(__dirname, "..");
if (isCli) {
app.use(expressStaticGzip(path.join(baseDir, "build/web")));
} else {
app.use(express.static(path.join(baseDir, "resources/web")));
}
const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth"));
const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth"));
app.use((req, res, next) => {
if (isAuthed(req)) {
// We can serve the actual VSCode bin
authStaticFunc(req, res, next);
} else {
// Serve only the unauthed version
unauthStaticFunc(req, res, next);
}
});
app.get("/resource/:url(*)", async (req, res) => {
try {
const fullPath = `/${req.params.url}`;
@ -91,6 +183,28 @@ export const createApp = (registerMiddleware?: (app: express.Application) => voi
res.end();
}
});
app.post("/resource/:url(*)", async (req, res) => {
try {
const fullPath = `/${req.params.url}`;
const data: string[] = [];
req.setEncoding("utf8");
req.on("data", (chunk) => {
data.push(chunk);
});
req.on("end", () => {
const body = data.join("");
fs.writeFileSync(fullPath, body);
logger.debug("Wrote resource", field("path", fullPath), field("content-length", body.length));
res.status(200);
res.end();
});
} catch (ex) {
res.write(ex.toString());
res.status(500);
res.end();
}
});
return {
express: app,

View File

@ -5,37 +5,104 @@ import * as zlib from "zlib";
import * as vm from "vm";
import { isCli } from "../constants";
let ipcMsgBuffer: Buffer[] | undefined = [];
let ipcMsgListener = process.send ? (d: Buffer): number => ipcMsgBuffer!.push(d) : undefined;
if (ipcMsgListener) {
process.on("message", ipcMsgListener);
}
/**
* Requires a module from the filesystem.
*
* Will load from the CLI if file is included inside of the default extensions dir
*/
// tslint:disable-next-line:no-any
const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any => {
const mod = require("module") as typeof import("module");
const customMod = new mod.Module(id);
customMod.filename = id;
// tslint:disable-next-line:no-any
customMod.paths = [(<any>mod)._nodeModulePaths(path.dirname(id)), path.join(__dirname, "../../../../lib/vscode/node_modules")];
if (id.startsWith(builtInExtensionsDir)) {
customMod.loaded = true;
const fileName = id.endsWith(".js") ? id : `${id}.js`;
const req = vm.runInThisContext(mod.wrap(fs.readFileSync(fileName).toString()), {
displayErrors: true,
filename: id + fileName,
});
req(customMod.exports, customMod.require.bind(customMod), customMod, fileName, path.dirname(id));
return customMod.exports;
}
return customMod.require(id);
};
/**
* Called from forking a module
*/
export const requireFork = (modulePath: string, args: string[], builtInExtensionsDir: string): void => {
const Module = require("module") as typeof import("module");
const oldRequire = Module.prototype.require;
// tslint:disable-next-line:no-any
Module.prototype.require = (id: string): any => {
if (id === "typescript") {
return require("typescript");
}
return oldRequire(id);
};
if (!process.send) {
throw new Error("No IPC messaging initialized");
}
process.argv = ["", "", ...args];
requireFilesystemModule(modulePath, builtInExtensionsDir);
if (ipcMsgBuffer && ipcMsgListener) {
process.removeListener("message", ipcMsgListener);
// tslint:disable-next-line:no-any
ipcMsgBuffer.forEach((i) => process.emit("message" as any, i as any));
ipcMsgBuffer = undefined;
ipcMsgListener = undefined;
}
};
export const requireModule = (modulePath: string, builtInExtensionsDir: string): void => {
process.env.AMD_ENTRYPOINT = modulePath;
const xml = require("xhr2");
xml.XMLHttpRequest.prototype._restrictedHeaders["user-agent"] = false;
// tslint:disable-next-line no-any this makes installing extensions work.
(global as any).XMLHttpRequest = xml.XMLHttpRequest;
const mod = require("module") as typeof import("module");
const promiseFinally = require("promise.prototype.finally") as { shim: () => void };
promiseFinally.shim();
/**
* Used for loading extensions. Using __non_webpack_require__ didn't work
* as it was not resolving to the FS.
*/
(global as any).nativeNodeRequire = (id: string): any => {// tslint:disable-line no-any
const customMod = new mod.Module(id);
customMod.filename = id;
// tslint:disable-next-line no-any
customMod.paths = (mod as any)._nodeModulePaths(path.dirname(id));
if (id.startsWith(builtInExtensionsDir)) {
customMod.loaded = true;
const req = vm.runInThisContext(mod.wrap(fs.readFileSync(id + ".js").toString()), {
displayErrors: true,
filename: id + ".js",
});
req(customMod.exports, customMod.require.bind(customMod), customMod, __filename, path.dirname(id));
return customMod.exports;
}
return customMod.require(id);
// tslint:disable-next-line:no-any
(global as any).nativeNodeRequire = (id: string): any => {
return requireFilesystemModule(id, builtInExtensionsDir);
};
if (isCli) {
/**
* Needed for properly forking external modules within the CLI
*/
// tslint:disable-next-line:no-any
(<any>cp).fork = (modulePath: string, args: ReadonlyArray<string> = [], options?: cp.ForkOptions): cp.ChildProcess => {
return cp.spawn(process.execPath, ["--fork", modulePath, "--args", JSON.stringify(args)], {
...options,
stdio: [null, null, null, "ipc"],
});
};
}
let content: Buffer | undefined;
const readFile = (name: string): Buffer => {
return fs.readFileSync(path.join(process.env.BUILD_DIR as string || path.join(__dirname, "../.."), "./build", name));
@ -43,7 +110,7 @@ export const requireModule = (modulePath: string, builtInExtensionsDir: string):
if (isCli) {
content = zlib.gunzipSync(readFile("bootstrap-fork.js.gz"));
} else {
content = readFile("../resources/bootstrap-fork.js");
content = readFile("../../vscode/bin/bootstrap-fork.js");
}
eval(content.toString());
};
@ -71,7 +138,7 @@ export const forkModule = (modulePath: string, args: string[], options: cp.ForkO
stdio: [null, null, null, "ipc"],
};
if (isCli) {
proc = cp.execFile(process.execPath, forkArgs, forkOptions);
proc = cp.spawn(process.execPath, forkArgs, options);
} else {
proc = cp.spawn(process.execPath, ["--require", "ts-node/register", "--require", "tsconfig-paths/register", process.argv[1], ...forkArgs], forkOptions);
}

View File

@ -129,6 +129,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/pem@^1.9.4":
version "1.9.4"
resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.4.tgz#9ef9302dc5f0352503e193003b208cddef4ffa45"
integrity sha512-cLRUgpedqF4lnQxDsjbRCgHRPHaJvnsHC+LEBTKnChddoPYJYQMq/LjSsEDwvRteeJV8MGt7Ea9jYCBVufrcNg==
dependencies:
"@types/node" "*"
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
@ -430,13 +437,6 @@ binary-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==
bindings@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.4.0.tgz#909efa49f2ebe07ecd3cb136778f665052040127"
integrity sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ==
dependencies:
file-uri-to-path "1.0.0"
bindings@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5"
@ -624,6 +624,11 @@ chardet@^0.4.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=
charenc@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
chokidar@^1.6.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@ -800,6 +805,11 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
crypt@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
css-loader@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.9.1.tgz#2e1aa00ce7e30ef2c6a7a4b300a080a7c979e0dc"
@ -915,6 +925,13 @@ deepmerge@^2.0.1:
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
define-properties@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
dependencies:
object-keys "^1.0.12"
define-property@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
@ -1019,6 +1036,32 @@ end-of-stream@^1.0.0:
dependencies:
once "^1.4.0"
es-abstract@^1.9.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9"
integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==
dependencies:
es-to-primitive "^1.2.0"
function-bind "^1.1.1"
has "^1.0.3"
is-callable "^1.1.4"
is-regex "^1.0.4"
object-keys "^1.0.12"
es-to-primitive@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
dependencies:
is-callable "^1.1.4"
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es6-promisify@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6"
integrity sha512-J3ZkwbEnnO+fGAKrjVpeUAnZshAdfZvbhQpqfIH9kSAspReRC4nJnu8ewm55b4y9ElyeuhCTzJD0XiH8Tsbhlw==
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -1279,11 +1322,6 @@ file-type@^6.1.0:
resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919"
integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@ -1429,6 +1467,11 @@ fsevents@^1.0.0:
nan "^2.9.2"
node-pre-gyp "^0.10.0"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
fuse-box@^3.1.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/fuse-box/-/fuse-box-3.6.0.tgz#a4adf41a60855c7b0a0775b3095b6b0c2d35b011"
@ -1645,6 +1688,11 @@ has-symbol-support-x@^1.4.1:
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
has-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
has-to-string-tag-x@^1.2.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
@ -1688,6 +1736,13 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
has@^1.0.1, has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
http-cache-semantics@3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
@ -1712,6 +1767,11 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
httpolyglot@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/httpolyglot/-/httpolyglot-0.1.2.tgz#e4d347fe8984a62f467d4060df527f1851f6997b"
integrity sha1-5NNH/omEpi9GfUBg31J/GFH2mXs=
iconv-lite@0.4.23:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
@ -1815,11 +1875,16 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.1.5:
is-buffer@^1.1.5, is-buffer@~1.1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@ -1834,6 +1899,11 @@ is-data-descriptor@^1.0.0:
dependencies:
kind-of "^6.0.0"
is-date-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
is-descriptor@^0.1.0:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
@ -1956,6 +2026,13 @@ is-promise@^2.1.0:
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
is-regex@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
dependencies:
has "^1.0.1"
is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
@ -1966,6 +2043,13 @@ is-stream@^1.0.0, is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
is-symbol@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
dependencies:
has-symbols "^1.0.0"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@ -1976,11 +2060,21 @@ is-windows@^1.0.2:
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
is-wsl@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
@ -2192,6 +2286,15 @@ math-random@^1.0.1:
resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
md5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
dependencies:
charenc "~0.0.1"
crypt "~0.0.1"
is-buffer "~1.1.1"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -2344,7 +2447,7 @@ mute-stream@0.0.7:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
nan@^2.0.9, nan@^2.8.0, nan@^2.9.2:
nan@^2.8.0, nan@^2.9.2:
version "2.12.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==
@ -2406,6 +2509,13 @@ nexe@^2.0.0-rc.34:
uglify-es "^3.3.9"
uglify-js "3.0.28"
node-netstat@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/node-netstat/-/node-netstat-1.6.0.tgz#38c36b5f966b00ffaa2ed6f6321e6ad4487d8c89"
integrity sha512-KPDopkvPllhcILoHMWYUxvOO5c+VcPB38LxlOFPiZhZ/hJTMH/GXGCs6nvxu4d6unwsbEfgzJ4pPye3CFv9yTg==
dependencies:
is-wsl "^1.1.0"
node-pre-gyp@^0.10.0:
version "0.10.3"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
@ -2501,6 +2611,11 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-keys@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==
object-visit@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
@ -2576,7 +2691,7 @@ os-homedir@^1.0.0:
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
@ -2660,6 +2775,16 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
pem@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.1.tgz#8ff3c5884bfcba7bbdfea5b67a7fa24b4ca3bb86"
integrity sha512-WY3IzMoh+Gwp4xJTT2MqIOaVzNqU7jHqj7k0pOnLIkNSnOpjhy3PHr9mXGi+C5tRC2z1EX5lvzEbd9BtHumHLQ==
dependencies:
es6-promisify "^6.0.0"
md5 "^2.2.1"
os-tmpdir "^1.0.1"
which "^1.3.1"
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
@ -2744,6 +2869,15 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
promise.prototype.finally@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e"
integrity sha512-7p/K2f6dI+dM8yjRQEGrTQs5hTQixUAdOGpMEA3+pVxpX5oHKRSKAXyLw9Q9HUWDTdwtoo39dSHGQtN90HcEwQ==
dependencies:
define-properties "^1.1.2"
es-abstract "^1.9.0"
function-bind "^1.1.1"
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
@ -3022,14 +3156,6 @@ seek-bzip@^1.0.5:
dependencies:
commander "~2.8.1"
segfault-handler@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/segfault-handler/-/segfault-handler-1.0.1.tgz#9466d8f77d8826cfbdfa811124ece02983fd6ad2"
integrity sha512-3koBV3F0IPxTYacnoL7WoFlaMndXsXj62tiVbbW9Kzp3K+F9Y6GWW5XmKSv7j+7nf2M+qjNzc4W1iZoa8vocjw==
dependencies:
bindings "^1.2.1"
nan "^2.0.9"
semver@^5.3.0, semver@^5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
@ -3668,6 +3794,13 @@ watch@^1.0.1:
exec-sh "^0.2.0"
minimist "^1.2.0"
which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"