Skip to content

Commit 97167e7

Browse files
committed
Add authentication
1 parent 2b2aa9a commit 97167e7

8 files changed

Lines changed: 400 additions & 91 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ yarn patch:apply
7373
yarn
7474
yarn watch
7575
# Wait for the initial compilation to complete (it will say "Finished compilation").
76-
yarn start
76+
yarn start --allow-http --no-auth
7777
# Visit http://localhost:8443
7878
```
7979

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"ensure-in-vscode": "bash ./scripts/tasks.bash ensure-in-vscode",
55
"preinstall": "yarn ensure-in-vscode && cd ../../../ && yarn || true",
66
"postinstall": "rm -rf node_modules/@types/node",
7-
"start": "yarn ensure-in-vscode && nodemon ../../../out/vs/server/main.js --watch ../../../out --verbose",
7+
"start": "yarn ensure-in-vscode && nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js",
88
"watch": "yarn ensure-in-vscode && cd ../../../ && yarn watch",
99
"build": "bash ./scripts/tasks.bash build",
1010
"package": "bash ./scripts/tasks.bash package",

src/cli.ts

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as os from "os";
2+
import * as path from "path";
23

34
import { validatePaths } from "vs/code/node/paths";
45
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
@@ -9,16 +10,16 @@ import pkg from "vs/platform/product/node/package";
910

1011
import { MainServer, WebviewServer } from "vs/server/src/server";
1112
import "vs/server/src/tar";
12-
import { generateCertificate } from "vs/server/src/util";
13+
import { generateCertificate, generatePassword } from "vs/server/src/util";
1314

1415
interface Args extends ParsedArgs {
1516
"allow-http"?: boolean;
17+
auth?: boolean;
1618
cert?: string;
1719
"cert-key"?: string;
1820
"extra-builtin-extensions-dir"?: string;
1921
"extra-extensions-dir"?: string;
2022
host?: string;
21-
"no-auth"?: boolean;
2223
open?: string;
2324
port?: string;
2425
socket?: string;
@@ -58,7 +59,7 @@ options.push({ id: "cert-key", type: "string", cat: "o", description: "Path to c
5859
options.push({ id: "extra-builtin-extensions-dir", type: "string", cat: "o", description: "Path to extra builtin extension directory." });
5960
options.push({ id: "extra-extensions-dir", type: "string", cat: "o", description: "Path to extra user extension directory." });
6061
options.push({ id: "host", type: "string", cat: "o", description: "Host for the main and webview servers." });
61-
options.push({ id: "no-auth", type: "string", cat: "o", description: "Disable password authentication." });
62+
options.push({ id: "no-auth", type: "boolean", cat: "o", description: "Disable password authentication." });
6263
options.push({ id: "open", type: "boolean", cat: "o", description: "Open in the browser on startup." });
6364
options.push({ id: "port", type: "string", cat: "o", description: "Port for the main server." });
6465
options.push({ id: "socket", type: "string", cat: "o", description: "Listen on a socket instead of host:port." });
@@ -115,17 +116,32 @@ const main = async (): Promise<void> => {
115116
}
116117

117118
const options = {
118-
host: args["host"]
119-
|| (args["no-auth"] || args["allow-http"] ? "localhost" : "0.0.0.0"),
119+
host: args.host,
120120
allowHttp: args["allow-http"],
121-
cert: args["cert"],
122-
certKey: args["cert"],
121+
cert: args.cert,
122+
certKey: args["cert-key"],
123+
auth: typeof args.auth !== "undefined" ? args.auth : true,
124+
password: process.env.PASSWORD,
123125
};
124126

127+
if (!options.host) {
128+
options.host = !options.auth || options.allowHttp
129+
? "localhost"
130+
: "0.0.0.0";
131+
}
132+
133+
let usingGeneratedCert = false;
125134
if (!options.allowHttp && (!options.cert || !options.certKey)) {
126135
const { cert, certKey } = await generateCertificate();
127136
options.cert = cert;
128137
options.certKey = certKey;
138+
usingGeneratedCert = true;
139+
}
140+
141+
let usingGeneratedPassword = false;
142+
if (options.auth && !options.password) {
143+
options.password = await generatePassword();
144+
usingGeneratedPassword = true;
129145
}
130146

131147
const webviewPort = typeof args["webview-port"] !== "undefined"
@@ -149,6 +165,25 @@ const main = async (): Promise<void> => {
149165
]);
150166
console.log(`Main server listening on ${serverAddress}`);
151167
console.log(`Webview server listening on ${webviewAddress}`);
168+
169+
if (usingGeneratedPassword) {
170+
console.log(" - Password is", options.password);
171+
console.log(" - To use your own password, set the PASSWORD environment variable");
172+
} else if (options.auth) {
173+
console.log(" - Using custom password for authentication");
174+
} else {
175+
console.log(" - No authentication");
176+
}
177+
178+
if (!options.allowHttp && options.cert && options.certKey) {
179+
console.log(
180+
usingGeneratedCert
181+
? ` - Using generated certificate and key in ${path.dirname(options.cert)} for HTTPS`
182+
: " - Using provided certificate and key for HTTPS",
183+
);
184+
} else {
185+
console.log(" - Not serving HTTPS");
186+
}
152187
};
153188

154189
main().catch((error) => {

src/favicon/favicon.ico

2.03 KB
Binary file not shown.

src/login/login.css

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
html {
2+
box-sizing: border-box;
3+
}
4+
5+
*, *:before, *:after {
6+
box-sizing: inherit;
7+
}
8+
9+
html, body {
10+
background-color: #FFFFFF;
11+
height: 100%;
12+
min-height: 100%;
13+
}
14+
15+
body {
16+
align-items: center;
17+
display: flex;
18+
font-family: "monospace";
19+
justify-content: center;
20+
margin: 0;
21+
padding: 10px;
22+
}
23+
24+
.login-form {
25+
border-radius: 5px;
26+
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
27+
color: #575962;
28+
margin-top: -10%;
29+
max-width: 328px;
30+
padding: 40px;
31+
position: relative;
32+
width: 100%;
33+
}
34+
35+
.login-form > .title {
36+
text-align: center;
37+
text-transform: uppercase;
38+
font-size: 12px;
39+
font-weight: 500;
40+
letter-spacing: 1.5px;
41+
line-height: 15px;
42+
margin-bottom: 0px;
43+
margin-bottom: 5px;
44+
margin-top: 0px;
45+
}
46+
47+
.login-form > .subtitle {
48+
font-size: 19px;
49+
font-weight: bold;
50+
line-height: 25px;
51+
margin-bottom: 45px;
52+
margin: 0;
53+
text-align: center;
54+
}
55+
56+
.login-form > .field {
57+
text-align: left;
58+
font-size: 12px;
59+
color: #797E84;
60+
margin: 16px 0;
61+
}
62+
63+
.login-form > .field > .input {
64+
background: none !important;
65+
border: 1px solid #ccc;
66+
border-radius: 2px;
67+
padding: 5px;
68+
width: 100%;
69+
}
70+
71+
.login-form > .button {
72+
border: none;
73+
border-radius: 24px;
74+
box-shadow: 0 12px 17px 2px rgba(171,173,163,0.14), 0 5px 22px 4px rgba(171,173,163,0.12), 0 7px 8px -4px rgba(171,173,163,0.2);
75+
cursor: pointer;
76+
display: block;
77+
padding: 15px 5px;
78+
width: 100%;
79+
}
80+
81+
.login-form > .button:hover {
82+
background-color: rgb(0, 122, 204);
83+
color: #fff;
84+
}
85+
86+
.error-display {
87+
box-sizing: border-box;
88+
color: #bb2d0f;
89+
font-size: 14px;
90+
font-weight: 400;
91+
line-height: 12px;
92+
padding: 20px 8px 0;
93+
text-align: center;
94+
}

src/login/login.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
5+
<title>Authenticate: code-server</title>
6+
<link href="/login/login.css" rel="stylesheet">
7+
</head>
8+
<body>
9+
<form class="login-form" action="/login" method="post">
10+
<h4 class="title">code-server</h4>
11+
<h2 class="subtitle">
12+
Enter server password
13+
</h2>
14+
<div class="field">
15+
<!-- The onfocus code places the cursor at the end of the value. -->
16+
<input name="password" type="password" class="input" value=""
17+
required autofocus
18+
onfocus="const value=this.value;this.value='';this.value=value;">
19+
</div>
20+
<button class="button" type="submit">
21+
<span class="label">Enter IDE</span>
22+
</button>
23+
<div class="error-display" style="display:none">{{ERROR}}</div>
24+
</form>
25+
</body>
26+
</html>

0 commit comments

Comments
 (0)