Improve password handling

- Error out if auth is enabled but no password is passed in
- Indicate password location on login page
This commit is contained in:
Anmol Sethi 2020-05-12 19:19:37 -04:00
parent 524b0205e9
commit c0d6eb4664
No known key found for this signature in database
GPG Key ID: 8CEF1878FF10ADEB
5 changed files with 33 additions and 15 deletions

View File

@ -22,6 +22,7 @@ rules:
# For overloads.
no-dupe-class-members: off
"@typescript-eslint/no-use-before-define": off
"@typescript-eslint/no-non-null-assertion": off
settings:
# Does not work with CommonJS unfortunately.

View File

@ -56,8 +56,7 @@
"stylelint": "^13.0.0",
"stylelint-config-recommended": "^3.0.0",
"ts-node": "^8.4.1",
"typescript": "3.7.2",
"yarn": "^1.22.4"
"typescript": "3.7.2"
},
"resolutions": {
"@types/node": "^12.12.7",
@ -79,7 +78,8 @@
"tar": "^6.0.1",
"tar-fs": "^2.0.0",
"ws": "^7.2.0",
"xdg-basedir": "^4.0.0"
"xdg-basedir": "^4.0.0",
"yarn": "^1.22.4"
},
"bin": {
"code-server": "out/node/entry.js"

View File

@ -26,7 +26,7 @@
<div class="card-box">
<div class="header">
<h1 class="main">Welcome to code-server</h1>
<div class="sub">Please log in below. Check code-server's logs for the generated password.</div>
<div class="sub">Please log in below. {{PASSWORD_MSG}}</div>
</div>
<div class="content">
<form class="login-form" method="post">

View File

@ -2,8 +2,8 @@ import * as http from "http"
import * as limiter from "limiter"
import * as querystring from "querystring"
import { HttpCode, HttpError } from "../../common/http"
import { AuthType, HttpProvider, HttpResponse, Route } from "../http"
import { hash } from "../util"
import { AuthType, HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
import { hash, humanPath } from "../util"
interface LoginPayload {
password?: string
@ -18,6 +18,14 @@ interface LoginPayload {
* Login HTTP provider.
*/
export class LoginHttpProvider extends HttpProvider {
public constructor(
options: HttpProviderOptions,
private readonly configFile: string,
private readonly envPassword: boolean,
) {
super(options)
}
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
if (this.options.auth !== AuthType.Password || !this.isRoot(route)) {
throw new HttpError("Not found", HttpCode.NotFound)
@ -46,6 +54,11 @@ export class LoginHttpProvider extends HttpProvider {
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/login.html")
response.content = response.content.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
let passwordMsg = `Check the config file at ${humanPath(this.configFile)} for the password.`
if (this.envPassword) {
passwordMsg = "Password was set from $PASSWORD."
}
response.content = response.content.replace(/{{PASSWORD_MSG}}/g, passwordMsg)
return this.replaceTemplates(route, response)
}

View File

@ -36,10 +36,21 @@ const main = async (cliArgs: Args): Promise<void> => {
// This prioritizes the flags set in args over the ones in the config file.
let args = Object.assign(configArgs, cliArgs)
if (!args.auth) {
args = {
...args,
auth: AuthType.Password,
}
}
logger.trace(`Using extensions-dir at ${humanPath(args["extensions-dir"])}`)
logger.trace(`Using user-data-dir at ${humanPath(args["user-data-dir"])}`)
const envPassword = !!process.env.PASSWORD
const password = args.auth === AuthType.Password && (process.env.PASSWORD || args.password)
if (args.auth === AuthType.Password && !password) {
throw new Error("Please pass in a password via the config file or $PASSWORD")
}
const [host, port] = bindAddrFromAllSources(cliArgs, configArgs)
// Spawn the main HTTP server.
@ -69,7 +80,7 @@ const main = async (cliArgs: Args): Promise<void> => {
const api = httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer, vscode, args["user-data-dir"])
const update = httpServer.registerHttpProvider("/update", UpdateHttpProvider, false)
httpServer.registerHttpProvider("/proxy", ProxyHttpProvider)
httpServer.registerHttpProvider("/login", LoginHttpProvider)
httpServer.registerHttpProvider("/login", LoginHttpProvider, args.config!, envPassword)
httpServer.registerHttpProvider("/static", StaticHttpProvider)
httpServer.registerHttpProvider("/dashboard", DashboardHttpProvider, api, update)
@ -79,15 +90,8 @@ const main = async (cliArgs: Args): Promise<void> => {
const serverAddress = await httpServer.listen()
logger.info(`HTTP server listening on ${serverAddress}`)
if (!args.auth) {
args = {
...args,
auth: AuthType.Password,
}
}
if (args.auth === AuthType.Password) {
if (process.env.PASSWORD) {
if (envPassword) {
logger.info(" - Using password from $PASSWORD")
} else {
logger.info(` - Using password from ${humanPath(args.config)}`)