Skip to content

Commit 24ea70a

Browse files
feat: use --app-name in error page title (#7693)
1 parent a6d80dc commit 24ea70a

File tree

7 files changed

+49
-10
lines changed

7 files changed

+49
-10
lines changed

src/browser/pages/error.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
1212
/>
1313
<meta name="color-scheme" content="light dark" />
14-
<title>{{ERROR_TITLE}} - code-server</title>
14+
<title>{{ERROR_TITLE}} - {{APP_NAME}}</title>
1515
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon-dark-support.svg" />
1616
<link rel="alternate icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" />
1717
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />

src/node/cli.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ export interface DefaultedArgs extends ConfigArgs {
519519
"extensions-dir": string
520520
"user-data-dir": string
521521
"session-socket": string
522+
"app-name": string
522523
/* Positional arguments. */
523524
_: string[]
524525
}
@@ -665,6 +666,10 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
665666
}
666667
args["proxy-domain"] = finalProxies
667668

669+
if (!args["app-name"]) {
670+
args["app-name"] = "code-server"
671+
}
672+
668673
args._ = getResolvedPathsFromArgs(args)
669674

670675
return {

src/node/routes/errors.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export const errorHandler: express.ErrorRequestHandler = async (err, req, res, n
5757
replaceTemplates(req, content)
5858
.replace(/{{ERROR_TITLE}}/g, statusCode.toString())
5959
.replace(/{{ERROR_HEADER}}/g, statusCode.toString())
60-
.replace(/{{ERROR_BODY}}/g, escapeHtml(err.message)),
60+
.replace(/{{ERROR_BODY}}/g, escapeHtml(err.message))
61+
.replace(/{{APP_NAME}}/g, req.args["app-name"]),
6162
)
6263
} else {
6364
res.json({

src/node/routes/login.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ const getRoot = async (req: Request, error?: Error): Promise<string> => {
2929
const content = await fs.readFile(path.join(rootPath, "src/browser/pages/login.html"), "utf8")
3030
const locale = req.args["locale"] || "en"
3131
i18n.changeLanguage(locale)
32-
const appName = req.args["app-name"] || "code-server"
33-
const welcomeText = req.args["welcome-text"] || (i18n.t("WELCOME", { app: appName }) as string)
32+
const welcomeText = req.args["welcome-text"] || (i18n.t("WELCOME", { app: req.args["app-name"] }) as string)
3433

3534
// Determine password message using i18n
3635
let passwordMsg = i18n.t("LOGIN_PASSWORD", { configFile: req.args.config })
@@ -43,7 +42,7 @@ const getRoot = async (req: Request, error?: Error): Promise<string> => {
4342
return replaceTemplates(
4443
req,
4544
content
46-
.replace(/{{I18N_LOGIN_TITLE}}/g, i18n.t("LOGIN_TITLE", { app: appName }))
45+
.replace(/{{I18N_LOGIN_TITLE}}/g, i18n.t("LOGIN_TITLE", { app: req.args["app-name"] }))
4746
.replace(/{{WELCOME_TEXT}}/g, welcomeText)
4847
.replace(/{{PASSWORD_MSG}}/g, passwordMsg)
4948
.replace(/{{I18N_LOGIN_BELOW}}/g, i18n.t("LOGIN_BELOW"))

src/node/routes/vscode.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,16 +172,15 @@ router.get("/", ensureVSCodeLoaded, async (req, res, next) => {
172172
})
173173

174174
router.get("/manifest.json", async (req, res) => {
175-
const appName = req.args["app-name"] || "code-server"
176175
res.writeHead(200, { "Content-Type": "application/manifest+json" })
177176

178177
res.end(
179178
replaceTemplates(
180179
req,
181180
JSON.stringify(
182181
{
183-
name: appName,
184-
short_name: appName,
182+
name: req.args["app-name"],
183+
short_name: req.args["app-name"],
185184
start_url: ".",
186185
display: "fullscreen",
187186
display_override: ["window-controls-overlay"],

test/unit/node/cli.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const defaults = {
3838
"extensions-dir": path.join(paths.data, "extensions"),
3939
"user-data-dir": paths.data,
4040
"session-socket": path.join(paths.data, "code-server-ipc.sock"),
41+
"app-name": "code-server",
4142
_: [],
4243
}
4344

test/unit/node/routes/errors.test.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import express from "express"
2+
import { UserProvidedArgs, setDefaults } from "../../../../src/node/cli"
23
import { errorHandler } from "../../../../src/node/routes/errors"
34

45
describe("error page is rendered for text/html requests", () => {
@@ -9,7 +10,7 @@ describe("error page is rendered for text/html requests", () => {
910
statusCode: 404,
1011
message: ";>hello<script>alert(1)</script>",
1112
}
12-
const req = createRequest()
13+
const req = await createRequest()
1314
const res = {
1415
status: jest.fn().mockReturnValue(this),
1516
send: jest.fn().mockReturnValue(this),
@@ -20,9 +21,41 @@ describe("error page is rendered for text/html requests", () => {
2021
expect(res.status).toHaveBeenCalledWith(404)
2122
expect(res.send).toHaveBeenCalledWith(expect.not.stringContaining("<script>"))
2223
})
24+
25+
it("should use custom app-name in error page title", async () => {
26+
const err = {
27+
statusCode: 404,
28+
message: "Not found",
29+
}
30+
const req = await createRequest({ "app-name": "MyCodeServer" })
31+
const res = {
32+
status: jest.fn().mockReturnValue(this),
33+
send: jest.fn().mockReturnValue(this),
34+
set: jest.fn().mockReturnValue(this),
35+
} as unknown as express.Response
36+
37+
await errorHandler(err, req, res, jest.fn())
38+
expect(res.send).toHaveBeenCalledWith(expect.stringContaining("<title>404 - MyCodeServer</title>"))
39+
})
40+
41+
it("should use default 'code-server' when app-name is not set", async () => {
42+
const err = {
43+
statusCode: 500,
44+
message: "Internal error",
45+
}
46+
const req = await createRequest()
47+
const res = {
48+
status: jest.fn().mockReturnValue(this),
49+
send: jest.fn().mockReturnValue(this),
50+
set: jest.fn().mockReturnValue(this),
51+
} as unknown as express.Response
52+
53+
await errorHandler(err, req, res, jest.fn())
54+
expect(res.send).toHaveBeenCalledWith(expect.stringContaining("<title>500 - code-server</title>"))
55+
})
2356
})
2457

25-
function createRequest(): express.Request {
58+
async function createRequest(args: UserProvidedArgs = {}): Promise<express.Request> {
2659
return {
2760
headers: {
2861
accept: ["text/html"],
@@ -31,5 +64,6 @@ function createRequest(): express.Request {
3164
query: {
3265
to: "test",
3366
},
67+
args: await setDefaults(args),
3468
} as unknown as express.Request
3569
}

0 commit comments

Comments
 (0)