Skip to content

Commit 714afe0

Browse files
niwla23jsjoeio
andauthored
feat: add customization options for the login page (#5633)
* add customization options for the login page * add unit tests * add test for correct welcome text when none is set but app-name is Signed-off-by: niwla23 <[email protected]> * add test for no app-name set and check in title too Signed-off-by: niwla23 <[email protected]> Signed-off-by: niwla23 <[email protected]> Co-authored-by: Joe Previte <[email protected]>
1 parent 71a127a commit 714afe0

File tree

5 files changed

+68
-3
lines changed

5 files changed

+68
-3
lines changed

src/browser/pages/login.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
http-equiv="Content-Security-Policy"
1111
content="style-src 'self'; script-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
1212
/>
13-
<title>code-server login</title>
13+
<title>{{APP_NAME}} login</title>
1414
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon-dark-support.svg" />
1515
<link rel="alternate icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" />
1616
<link rel="manifest" href="{{BASE}}/manifest.json" crossorigin="use-credentials" />
@@ -24,7 +24,7 @@
2424
<div class="center-container">
2525
<div class="card-box">
2626
<div class="header">
27-
<h1 class="main">Welcome to code-server</h1>
27+
<h1 class="main">{{WELCOME_TEXT}}</h1>
2828
<div class="sub">Please log in below. {{PASSWORD_MSG}}</div>
2929
</div>
3030
<div class="content">

src/node/cli.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs {
8585
"ignore-last-opened"?: boolean
8686
link?: OptionalString
8787
verbose?: boolean
88+
"app-name"?: string
89+
"welcome-text"?: string
8890
/* Positional arguments. */
8991
_?: string[]
9092
}
@@ -238,7 +240,16 @@ export const options: Options<Required<UserProvidedArgs>> = {
238240

239241
log: { type: LogLevel },
240242
verbose: { type: "boolean", short: "vvv", description: "Enable verbose logging." },
241-
243+
"app-name": {
244+
type: "string",
245+
short: "an",
246+
description: "The name to use in branding. Will be shown in titlebar and welcome message",
247+
},
248+
"welcome-text": {
249+
type: "string",
250+
short: "w",
251+
description: "Text to show on login page",
252+
},
242253
link: {
243254
type: OptionalString,
244255
description: `

src/node/routes/login.ts

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export class RateLimiter {
2828

2929
const getRoot = async (req: Request, error?: Error): Promise<string> => {
3030
const content = await fs.readFile(path.join(rootPath, "src/browser/pages/login.html"), "utf8")
31+
const appName = req.args["app-name"] || "code-server"
32+
const welcomeText = req.args["welcome-text"] || `Welcome to ${appName}`
3133
let passwordMsg = `Check the config file at ${humanPath(os.homedir(), req.args.config)} for the password.`
3234
if (req.args.usingEnvPassword) {
3335
passwordMsg = "Password was set from $PASSWORD."
@@ -38,6 +40,8 @@ const getRoot = async (req: Request, error?: Error): Promise<string> => {
3840
return replaceTemplates(
3941
req,
4042
content
43+
.replace(/{{APP_NAME}}/g, appName)
44+
.replace(/{{WELCOME_TEXT}}/g, welcomeText)
4145
.replace(/{{PASSWORD_MSG}}/g, passwordMsg)
4246
.replace(/{{ERROR}}/, error ? `<div class="error">${escapeHtml(error.message)}</div>` : ""),
4347
)

test/unit/node/cli.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ describe("parser", () => {
6767

6868
"1",
6969
"--verbose",
70+
["--app-name", "custom instance name"],
71+
["--welcome-text", "welcome to code"],
7072
"2",
7173

7274
["--locale", "ja"],
@@ -123,6 +125,8 @@ describe("parser", () => {
123125
socket: path.resolve("mumble"),
124126
"socket-mode": "777",
125127
verbose: true,
128+
"app-name": "custom instance name",
129+
"welcome-text": "welcome to code",
126130
version: true,
127131
"bind-addr": "192.169.0.1:8080",
128132
})

test/unit/node/routes/login.test.ts

+46
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,51 @@ describe("login", () => {
9292

9393
expect(htmlContent).toContain("Incorrect password")
9494
})
95+
96+
it("should return correct app-name", async () => {
97+
process.env.PASSWORD = previousEnvPassword
98+
const appName = "testnäme"
99+
const codeServer = await integration.setup([`--app-name=${appName}`], "")
100+
const resp = await codeServer.fetch("/login", { method: "GET" })
101+
102+
const htmlContent = await resp.text()
103+
expect(resp.status).toBe(200)
104+
expect(htmlContent).toContain(`${appName}</h1>`)
105+
expect(htmlContent).toContain(`<title>${appName} login</title>`)
106+
})
107+
108+
it("should return correct app-name when unset", async () => {
109+
process.env.PASSWORD = previousEnvPassword
110+
const appName = "code-server"
111+
const codeServer = await integration.setup([], "")
112+
const resp = await codeServer.fetch("/login", { method: "GET" })
113+
114+
const htmlContent = await resp.text()
115+
expect(resp.status).toBe(200)
116+
expect(htmlContent).toContain(`${appName}</h1>`)
117+
expect(htmlContent).toContain(`<title>${appName} login</title>`)
118+
})
119+
120+
it("should return correct welcome text", async () => {
121+
process.env.PASSWORD = previousEnvPassword
122+
const welcomeText = "Welcome to your code workspace! öäü🔐"
123+
const codeServer = await integration.setup([`--welcome-text=${welcomeText}`], "")
124+
const resp = await codeServer.fetch("/login", { method: "GET" })
125+
126+
const htmlContent = await resp.text()
127+
expect(resp.status).toBe(200)
128+
expect(htmlContent).toContain(welcomeText)
129+
})
130+
131+
it("should return correct welcome text when none is set but app-name is", async () => {
132+
process.env.PASSWORD = previousEnvPassword
133+
const appName = "testnäme"
134+
const codeServer = await integration.setup([`--app-name=${appName}`], "")
135+
const resp = await codeServer.fetch("/login", { method: "GET" })
136+
137+
const htmlContent = await resp.text()
138+
expect(resp.status).toBe(200)
139+
expect(htmlContent).toContain(`Welcome to ${appName}`)
140+
})
95141
})
96142
})

0 commit comments

Comments
 (0)