Skip to content

Commit a00dc99

Browse files
committed
Make all assets unique
All CSS and JavaScript files have unique names now. I also moved the login to the /login path in order to ensure the HTML for each page is also unique.
1 parent e907dbe commit a00dc99

12 files changed

+171
-150
lines changed

build/tasks.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,21 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner
6767
}
6868
fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
6969
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath)));
70-
const cpDir = (dir: string, subdir: "auth" | "unauth", rootPath: string): void => {
70+
const cpDir = (dir: string, rootPath: string, subdir?: "login"): void => {
7171
const stat = fs.statSync(dir);
7272
if (stat.isDirectory()) {
7373
const paths = fs.readdirSync(dir);
74-
paths.forEach((p) => cpDir(path.join(dir, p), subdir, rootPath));
74+
paths.forEach((p) => cpDir(path.join(dir, p), rootPath, subdir));
7575
} else if (stat.isFile()) {
76-
const newPath = path.join(cliBuildPath, "web", subdir, path.relative(rootPath, dir));
76+
const newPath = path.join(cliBuildPath, "web", subdir || "", path.relative(rootPath, dir));
7777
fse.mkdirpSync(path.dirname(newPath));
7878
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
7979
} else {
8080
// Nothing
8181
}
8282
};
83-
cpDir(webOutputPath, "auth", webOutputPath);
84-
cpDir(browserAppOutputPath, "unauth", browserAppOutputPath);
83+
cpDir(webOutputPath, webOutputPath);
84+
cpDir(browserAppOutputPath, browserAppOutputPath, "login");
8585
fse.mkdirpSync(path.join(cliBuildPath, "dependencies"));
8686
fse.copySync(ripgrepPath, path.join(cliBuildPath, "dependencies", "rg"));
8787
});

packages/app/browser/src/app.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ if (!form) {
2828

2929
form.addEventListener("submit", (e) => {
3030
e.preventDefault();
31-
document.cookie = `password=${password.value}`;
31+
document.cookie = `password=${password.value}; `
32+
+ `path=${location.pathname.replace(/\/login\/?$/, "/")}; `
33+
+ `domain=${location.hostname}`;
3234
location.reload();
3335
});
3436

packages/app/browser/webpack.config.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ const root = path.resolve(__dirname, "../../..");
77

88
module.exports = merge(
99
require(path.join(root, "scripts/webpack.client.config.js"))({
10-
entry: path.join(root, "packages/app/browser/src/app.ts"),
11-
template: path.join(root, "packages/app/browser/src/app.html"),
10+
dirname: __dirname,
11+
entry: path.join(__dirname, "src/app.ts"),
12+
name: "login",
13+
template: path.join(__dirname, "src/app.html"),
1214
}), {
13-
output: {
14-
path: path.join(__dirname, "out"),
15-
},
1615
},
1716
);

packages/dns/webpack.config.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ const root = path.resolve(__dirname, "../..");
55

66
module.exports = merge(
77
require(path.join(root, "scripts/webpack.node.config.js"))({
8-
// Options.
8+
dirname: __dirname,
9+
name: "dns",
910
}), {
1011
externals: {
1112
"node-named": "commonjs node-named",
1213
},
13-
output: {
14-
path: path.join(__dirname, "out"),
15-
filename: "main.js",
16-
},
1714
entry: [
1815
"./packages/dns/src/dns.ts"
1916
],

packages/server/src/cli.ts

-7
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,6 @@ const bold = (text: string | number): string | number => {
193193
allowHttp: options.allowHttp,
194194
bypassAuth: options.noAuth,
195195
registerMiddleware: (app): void => {
196-
app.use((req, res, next) => {
197-
res.on("finish", () => {
198-
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip));
199-
});
200-
201-
next();
202-
});
203196
// If we're not running from the binary and we aren't serving the static
204197
// pre-built version, use webpack to serve the web files.
205198
if (!isCli && !serveStatic) {

packages/server/src/server.ts

+64-14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import * as os from "os";
1818
import * as path from "path";
1919
import * as pem from "pem";
2020
import * as util from "util";
21+
import * as url from "url";
2122
import * as ws from "ws";
2223
import { buildDir } from "./constants";
2324
import { createPortScanner } from "./portScanner";
@@ -69,13 +70,18 @@ export const createApp = async (options: CreateAppOptions): Promise<{
6970

7071
// Try/catch placed here just in case
7172
const cookies = parseCookies(req);
73+
logger.trace(`Attempting to log in with password ${cookies.password}`);
7274
if (cookies.password && safeCompare(cookies.password, options.password)) {
75+
logger.trace("Succeeded login attempt");
76+
7377
return true;
7478
}
7579
} catch (ex) {
7680
logger.error("Failed to parse cookies", field("error", ex));
7781
}
7882

83+
logger.trace("Failed login attempt");
84+
7985
return false;
8086
};
8187

@@ -140,13 +146,13 @@ export const createApp = async (options: CreateAppOptions): Promise<{
140146
};
141147

142148
const portScanner = createPortScanner();
143-
wss.on("connection", (ws, req) => {
149+
wss.on("connection", async (ws, req) => {
144150
if (req.url && req.url.startsWith("/tunnel")) {
145151
try {
146152
const rawPort = req.url.split("/").pop();
147153
const port = Number.parseInt(rawPort!, 10);
148154

149-
handleTunnel(ws, port);
155+
await handleTunnel(ws, port);
150156
} catch (ex) {
151157
ws.close(TunnelCloseCode.Error, ex.toString());
152158
}
@@ -189,31 +195,70 @@ export const createApp = async (options: CreateAppOptions): Promise<{
189195
new Server(connection, options.serverOptions);
190196
});
191197

198+
const redirect = (
199+
req: express.Request, res: express.Response,
200+
to: string = "", from: string = "",
201+
code: number = 302, protocol: string = req.protocol,
202+
): void => {
203+
const currentUrl = `${protocol}://${req.headers.host}${req.originalUrl}`;
204+
const newUrl = url.parse(currentUrl);
205+
if (from && newUrl.pathname) {
206+
newUrl.pathname = newUrl.pathname.replace(new RegExp(`\/${from}\/?$`), "/");
207+
}
208+
if (to) {
209+
newUrl.pathname = (newUrl.pathname || "").replace(/\/$/, "") + `/${to}`;
210+
}
211+
newUrl.path = undefined; // Path is not necessary and I'm not sure if it causes issues if it doesn't match pathname.
212+
const newUrlString = url.format(newUrl);
213+
logger.trace(`Redirecting from ${currentUrl} to ${newUrlString}`);
214+
215+
return res.redirect(code, newUrlString);
216+
};
217+
192218
const baseDir = buildDir || path.join(__dirname, "..");
193-
const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth"));
194-
const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth"));
219+
const staticGzip = expressStaticGzip(path.join(baseDir, "build/web"));
220+
195221
app.use((req, res, next) => {
222+
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.originalUrl}`, field("host", req.hostname), field("ip", req.ip));
223+
224+
// Force HTTPS unless allowing HTTP.
196225
if (!isEncrypted(req.socket) && !options.allowHttp) {
197-
return res.redirect(301, `https://${req.headers.host!}${req.path}`);
226+
return redirect(req, res, "", "", 301, "https");
198227
}
199228

200-
if (isAuthed(req)) {
201-
// We can serve the actual VSCode bin
202-
authStaticFunc(req, res, next);
203-
} else {
204-
// Serve only the unauthed version
205-
unauthStaticFunc(req, res, next);
206-
}
229+
next();
207230
});
231+
208232
// @ts-ignore
209-
app.use((err, req, res, next) => {
233+
app.use((err, _req, _res, next) => {
234+
logger.error(err.message);
210235
next();
211236
});
212-
app.get("/ping", (req, res) => {
237+
238+
// If not authenticated, redirect to the login page.
239+
app.get("/", (req, res, next) => {
240+
if (!isAuthed(req)) {
241+
return redirect(req, res, "login");
242+
}
243+
next();
244+
});
245+
246+
// If already authenticated, redirect back to the root.
247+
app.get("/login", (req, res, next) => {
248+
if (isAuthed(req)) {
249+
return redirect(req, res, "", "login");
250+
}
251+
next();
252+
});
253+
254+
// For getting general server data.
255+
app.get("/ping", (_req, res) => {
213256
res.json({
214257
hostname: os.hostname(),
215258
});
216259
});
260+
261+
// For getting a resource on disk.
217262
app.get("/resource/:url(*)", async (req, res) => {
218263
if (!ensureAuthed(req, res)) {
219264
return;
@@ -254,6 +299,8 @@ export const createApp = async (options: CreateAppOptions): Promise<{
254299
res.end();
255300
}
256301
});
302+
303+
// For writing a resource to disk.
257304
app.post("/resource/:url(*)", async (req, res) => {
258305
if (!ensureAuthed(req, res)) {
259306
return;
@@ -282,6 +329,9 @@ export const createApp = async (options: CreateAppOptions): Promise<{
282329
}
283330
});
284331

332+
// Everything else just pulls from the static build directory.
333+
app.use(staticGzip);
334+
285335
return {
286336
express: app,
287337
server,

packages/server/webpack.config.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ const root = path.resolve(__dirname, "../..");
66

77
module.exports = merge(
88
require(path.join(root, "scripts/webpack.node.config.js"))({
9-
// Config options.
9+
dirname: __dirname,
1010
}), {
1111
output: {
1212
filename: "cli.js",
13-
path: path.join(__dirname, "out"),
1413
libraryTarget: "commonjs",
1514
},
1615
node: {

packages/vscode/webpack.bootstrap.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
77

88
module.exports = merge(
99
require(path.join(root, "scripts/webpack.node.config.js"))({
10+
dirname: __dirname,
1011
typescriptCompilerOptions: {
1112
target: "es6",
1213
},
@@ -15,7 +16,6 @@ module.exports = merge(
1516
mode: "development",
1617
output: {
1718
chunkFilename: "[name].bundle.js",
18-
path: path.resolve(__dirname, "out"),
1919
publicPath: "/",
2020
filename: "bootstrap-fork.js",
2121
libraryTarget: "commonjs",

packages/web/src/index.html

+10-10
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
return;
2424
}
2525
document.body.style.background = bg;
26-
})();
27-
28-
// Check that service workers are registered
29-
if ("serviceWorker" in navigator) {
30-
// Use the window load event to keep the page load performant
31-
window.addEventListener("load", () => {
32-
navigator.serviceWorker.register("/service-worker.js");
33-
});
34-
}
26+
})();
27+
28+
// Check that service workers are registered
29+
if ("serviceWorker" in navigator) {
30+
// Use the window load event to keep the page load performant
31+
window.addEventListener("load", () => {
32+
navigator.serviceWorker.register("/service-worker.js");
33+
});
34+
}
3535
</script>
3636
</body>
37-
</html>
37+
</html>

packages/web/webpack.config.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,16 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
77

88
module.exports = merge(
99
require(path.join(root, "scripts/webpack.client.config.js"))({
10+
dirname: __dirname,
1011
entry: path.join(root, "packages/web/src/index.ts"),
12+
name: "ide",
1113
template: path.join(root, "packages/web/src/index.html"),
1214
typescriptCompilerOptions: {
1315
"target": "es5",
1416
"lib": ["dom", "esnext"],
1517
},
1618
},
1719
), {
18-
output: {
19-
chunkFilename: "[name]-[hash:6].bundle.js",
20-
path: path.join(__dirname, "out"),
21-
filename: "[hash:6].bundle.js",
22-
},
2320
node: {
2421
module: "empty",
2522
crypto: "empty",

0 commit comments

Comments
 (0)