Skip to content

Commit 4a08292

Browse files
committed
feat: add escapeHTML function
This can be used to escape any special characters in a string with HTML before sending from the server back to the client. This is important to prevent a cross-site scripting attack.
1 parent d2f0e17 commit 4a08292

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

src/node/routes/login.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ const getRoot = async (req: Request, error?: Error): Promise<string> => {
3636
} else if (req.args.usingEnvHashedPassword) {
3737
passwordMsg = "Password was set from $HASHED_PASSWORD."
3838
}
39+
40+
if (error) {
41+
console.log("there is an error", error.message)
42+
}
3943
return replaceTemplates(
4044
req,
4145
content

src/node/util.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,3 +509,17 @@ export const isFile = async (path: string): Promise<boolean> => {
509509
return false
510510
}
511511
}
512+
513+
/**
514+
* Escapes any HTML string special characters, like &, <, >, ", and '.
515+
*
516+
* Source: https://stackoverflow.com/a/6234804/3015595
517+
**/
518+
export function escapeHTML(unsafe: string): string {
519+
return unsafe
520+
.replace(/&/g, "&amp;")
521+
.replace(/</g, "&lt;")
522+
.replace(/>/g, "&gt;")
523+
.replace(/"/g, "&quot;")
524+
.replace(/'/g, "&#039;")
525+
}

test/unit/node/util.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,3 +434,11 @@ describe("onLine", () => {
434434
expect(await received).toEqual(expected)
435435
})
436436
})
437+
438+
describe("escapeHTML", () => {
439+
it("should escape HTML", () => {
440+
expect(util.escapeHTML(`<div class="error">"Hello & world"</div>`)).toBe(
441+
"&lt;div class=&quot;error&quot;&gt;&quot;Hello &amp; world&quot;&lt;/div&gt;",
442+
)
443+
})
444+
})

test/unit/routes/login.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import * as httpserver from "../../utils/httpserver"
2+
import * as integration from "../../utils/integration"
3+
14
import { RateLimiter } from "../../../src/node/routes/login"
25

36
describe("login", () => {
@@ -34,4 +37,43 @@ describe("login", () => {
3437
expect(limiter.removeToken()).toBe(false)
3538
})
3639
})
40+
describe.only("/", () => {
41+
let _codeServer: httpserver.HttpServer | undefined
42+
function codeServer(): httpserver.HttpServer {
43+
if (!_codeServer) {
44+
throw new Error("tried to use code-server before setting it up")
45+
}
46+
return _codeServer
47+
}
48+
49+
// Store whatever might be in here so we can restore it afterward.
50+
// TODO: We should probably pass this as an argument somehow instead of
51+
// manipulating the environment.
52+
const previousEnvPassword = process.env.PASSWORD
53+
54+
beforeEach(async () => {
55+
process.env.PASSWORD = "test"
56+
_codeServer = await integration.setup(["--auth=password"], "")
57+
})
58+
59+
afterEach(() => {
60+
process.env.PASSWORD = previousEnvPassword
61+
})
62+
63+
// TODO@jsjoeio fix this name of test
64+
it("should return an error", async () => {
65+
const resp = await codeServer().fetch("/", { method: "POST" })
66+
// TODO@jsjoeio um not sure why we are getting a 404
67+
expect(resp.status).toBe(404)
68+
69+
try {
70+
const content = JSON.parse(await resp.text())
71+
72+
expect(content.error).toMatch("ENOENT")
73+
} catch (error) {
74+
console.log("heree")
75+
console.error(error)
76+
}
77+
})
78+
})
3779
})

0 commit comments

Comments
 (0)