Fixes browser app, adds no-auth (#38)

* Add no-auth flag

* Install packages for app dir
This commit is contained in:
Kyle Carberry 2019-02-26 16:03:42 -06:00 committed by GitHub
parent a07d0c9c3d
commit be3f0c437f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 40 deletions

View File

@ -24,6 +24,7 @@ export class Entry extends Command {
open: flags.boolean({ char: "o", description: "Open in browser on startup" }), open: flags.boolean({ char: "o", description: "Open in browser on startup" }),
port: flags.integer({ char: "p", default: 8080, description: "Port to bind on" }), port: flags.integer({ char: "p", default: 8080, description: "Port to bind on" }),
version: flags.version({ char: "v" }), version: flags.version({ char: "v" }),
"no-auth": flags.boolean({ default: false }),
// Dev flags // Dev flags
"bootstrap-fork": flags.string({ hidden: true }), "bootstrap-fork": flags.string({ hidden: true }),
@ -132,41 +133,47 @@ export class Entry extends Command {
const password = "023450wf0951"; const password = "023450wf0951";
const hasCustomHttps = certData && certKeyData; const hasCustomHttps = certData && certKeyData;
const app = await createApp((app) => { const app = await createApp({
app.use((req, res, next) => { bypassAuth: flags["no-auth"],
res.on("finish", () => { registerMiddleware: (app): void => {
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip)); 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));
});
next();
}); });
// If we're not running from the binary and we aren't serving the static
next(); // pre-built version, use webpack to serve the web files.
}); if (!isCli && !serveStatic) {
// If we're not running from the binary and we aren't serving the static const webpackConfig = require(path.join(__dirname, "..", "..", "web", "webpack.config.js"));
// pre-built version, use webpack to serve the web files. const compiler = require("webpack")(webpackConfig);
if (!isCli && !serveStatic) { app.use(require("webpack-dev-middleware")(compiler, {
const webpackConfig = require(path.join(__dirname, "..", "..", "web", "webpack.config.js")); logger,
const compiler = require("webpack")(webpackConfig); publicPath: webpackConfig.output.publicPath,
app.use(require("webpack-dev-middleware")(compiler, { stats: webpackConfig.stats,
logger, }));
publicPath: webpackConfig.output.publicPath, app.use(require("webpack-hot-middleware")(compiler));
stats: webpackConfig.stats,
}));
app.use(require("webpack-hot-middleware")(compiler));
}
}, {
builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir,
workingDirectory: workingDir,
fork: (modulePath: string, args: string[], options: ForkOptions): ChildProcess => {
if (options && options.env && options.env.AMD_ENTRYPOINT) {
return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir);
} }
return fork(modulePath, args, options);
}, },
}, password, hasCustomHttps ? { serverOptions: {
key: certKeyData, builtInExtensionsDirectory: builtInExtensionsDir,
cert: certData, dataDirectory: dataDir,
} : undefined); workingDirectory: workingDir,
fork: (modulePath: string, args: string[], options: ForkOptions): ChildProcess => {
if (options && options.env && options.env.AMD_ENTRYPOINT) {
return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir);
}
return fork(modulePath, args, options);
},
},
password,
httpsOptions: hasCustomHttps ? {
key: certKeyData,
cert: certData,
} : undefined,
});
logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port)); logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port));
app.server.listen(flags.port, flags.host); app.server.listen(flags.port, flags.host);
@ -191,8 +198,12 @@ export class Entry extends Command {
logger.warn("Documentation on securing your setup: https://coder.com/docs"); logger.warn("Documentation on securing your setup: https://coder.com/docs");
} }
logger.info(" "); if (!flags["no-auth"]) {
logger.info(`Password:\u001B[1m ${password}`); logger.info(" ");
logger.info(`Password:\u001B[1m ${password}`);
} else {
logger.warn("Launched without authentication.");
}
logger.info(" "); logger.info(" ");
logger.info("Started (click the link below to open):"); logger.info("Started (click the link below to open):");
logger.info(`http://localhost:${flags.port}/`); logger.info(`http://localhost:${flags.port}/`);

View File

@ -20,7 +20,15 @@ import { handle as handleTunnel } from "@coder/tunnel/src/server";
import { createPortScanner } from "./portScanner"; import { createPortScanner } from "./portScanner";
import { buildDir, isCli } from "./constants"; import { buildDir, isCli } from "./constants";
export const createApp = async (registerMiddleware?: (app: express.Application) => void, options?: ServerOptions, password?: string, httpsOptions?: https.ServerOptions): Promise<{ interface CreateAppOptions {
registerMiddleware?: (app: express.Application) => void;
serverOptions?: ServerOptions;
password?: string;
httpsOptions?: https.ServerOptions;
bypassAuth?: boolean;
}
export const createApp = async (options: CreateAppOptions): Promise<{
readonly express: express.Application; readonly express: express.Application;
readonly server: http.Server; readonly server: http.Server;
readonly wss: ws.Server; readonly wss: ws.Server;
@ -38,15 +46,26 @@ export const createApp = async (registerMiddleware?: (app: express.Application)
return cookies; return cookies;
}; };
const ensureAuthed = (req: http.IncomingMessage, res: express.Response): boolean => {
if (!isAuthed(req)) {
res.status(401);
res.end();
return false;
}
return true;
};
const isAuthed = (req: http.IncomingMessage): boolean => { const isAuthed = (req: http.IncomingMessage): boolean => {
try { try {
if (!password || !isCli) { if (!options.password || options.bypassAuth) {
return true; return true;
} }
// Try/catch placed here just in case // Try/catch placed here just in case
const cookies = parseCookies(req); const cookies = parseCookies(req);
if (cookies.password && cookies.password === password) { if (cookies.password && cookies.password === options.password) {
return true; return true;
} }
} catch (ex) { } catch (ex) {
@ -62,8 +81,8 @@ export const createApp = async (registerMiddleware?: (app: express.Application)
}; };
const app = express(); const app = express();
if (registerMiddleware) { if (options.registerMiddleware) {
registerMiddleware(app); options.registerMiddleware(app);
} }
const certs = await new Promise<pem.CertificateCreationResult>((res, rej): void => { const certs = await new Promise<pem.CertificateCreationResult>((res, rej): void => {
@ -134,7 +153,7 @@ export const createApp = async (registerMiddleware?: (app: express.Application)
onClose: (cb): void => ws.addEventListener("close", () => cb()), onClose: (cb): void => ws.addEventListener("close", () => cb()),
}; };
const server = new Server(connection, options); const server = new Server(connection, options.serverOptions);
}); });
const baseDir = buildDir || path.join(__dirname, ".."); const baseDir = buildDir || path.join(__dirname, "..");
@ -150,6 +169,10 @@ export const createApp = async (registerMiddleware?: (app: express.Application)
} }
}); });
app.get("/resource/:url(*)", async (req, res) => { app.get("/resource/:url(*)", async (req, res) => {
if (!ensureAuthed(req, res)) {
return;
}
try { try {
const fullPath = `/${req.params.url}`; const fullPath = `/${req.params.url}`;
// const relative = path.relative(options!.dataDirectory, fullPath); // const relative = path.relative(options!.dataDirectory, fullPath);
@ -184,6 +207,10 @@ export const createApp = async (registerMiddleware?: (app: express.Application)
} }
}); });
app.post("/resource/:url(*)", async (req, res) => { app.post("/resource/:url(*)", async (req, res) => {
if (!ensureAuthed(req, res)) {
return;
}
try { try {
const fullPath = `/${req.params.url}`; const fullPath = `/${req.params.url}`;

View File

@ -40,3 +40,4 @@ const handlePackages = (dir: string): void => {
}; };
handlePackages(resolve(__dirname, "..", "packages")); handlePackages(resolve(__dirname, "..", "packages"));
handlePackages(resolve(__dirname, "..", "packages", "app"));