Skip to content

Commit b65f206

Browse files
committed
refactor: add functions to check hash password
1 parent 014f1c2 commit b65f206

File tree

4 files changed

+74
-8
lines changed

4 files changed

+74
-8
lines changed

src/node/http.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { normalize, Options } from "../common/util"
88
import { AuthType, DefaultedArgs } from "./cli"
99
import { commit, rootPath } from "./constants"
1010
import { Heart } from "./heart"
11-
import { hash } from "./util"
11+
import { isHashMatch } from "./util"
1212

1313
declare global {
1414
// eslint-disable-next-line @typescript-eslint/no-namespace
@@ -67,7 +67,7 @@ export const authenticated = (req: express.Request): boolean => {
6767
req.cookies.key &&
6868
(req.args["hashed-password"]
6969
? safeCompare(req.cookies.key, req.args["hashed-password"])
70-
: req.args.password && safeCompare(req.cookies.key, hash(req.args.password)))
70+
: req.args.password && isHashMatch(req.args.password, req.cookies.key))
7171
)
7272
default:
7373
throw new Error(`Unsupported auth type ${req.args.auth}`)

src/node/routes/login.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as path from "path"
55
import safeCompare from "safe-compare"
66
import { rootPath } from "../constants"
77
import { authenticated, getCookieDomain, redirect, replaceTemplates } from "../http"
8-
import { hash, humanPath } from "../util"
8+
import { hash, hashLegacy, humanPath, isHashLegacyMatch } from "../util"
99

1010
export enum Cookie {
1111
Key = "key",
@@ -74,12 +74,13 @@ router.post("/", async (req, res) => {
7474

7575
if (
7676
req.args["hashed-password"]
77-
? safeCompare(hash(req.body.password), req.args["hashed-password"])
77+
? isHashLegacyMatch(req.body.password, req.args["hashed-password"])
7878
: req.args.password && safeCompare(req.body.password, req.args.password)
7979
) {
80+
const hashedPassword = req.args["hashed-password"] ? hashLegacy(req.body.password) : hash(req.body.password)
8081
// The hash does not add any actual security but we do it for
8182
// obfuscation purposes (and as a side effect it handles escaping).
82-
res.cookie(Cookie.Key, hash(req.body.password), {
83+
res.cookie(Cookie.Key, hashedPassword, {
8384
domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]),
8485
path: req.body.base || "/",
8586
sameSite: "lax",

src/node/util.ts

+33-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as os from "os"
88
import * as path from "path"
99
import * as util from "util"
1010
import xdgBasedir from "xdg-basedir"
11+
import safeCompare from "safe-compare"
1112

1213
export interface Paths {
1314
data: string
@@ -116,8 +117,38 @@ export const generatePassword = async (length = 24): Promise<string> => {
116117
return buffer.toString("hex").substring(0, length)
117118
}
118119

119-
export const hash = (str: string): string => {
120-
return bcrypt.hashSync(str, 10)
120+
/**
121+
* Used to hash the password.
122+
*/
123+
export const hash = (password: string): string => {
124+
return bcrypt.hashSync(password, 10)
125+
}
126+
127+
/**
128+
* Used to verify if the password matches the hash
129+
*/
130+
export const isHashMatch = (password: string, hash: string) => {
131+
return bcrypt.compareSync(password, hash)
132+
}
133+
134+
/**
135+
* Used to hash the password using the sha256
136+
* algorithm. We only use this to for checking
137+
* the hashed-password set in the config.
138+
*
139+
* Kept for legacy reasons.
140+
*/
141+
export const hashLegacy = (str: string): string => {
142+
return crypto.createHash("sha256").update(str).digest("hex")
143+
}
144+
145+
/**
146+
* Used to check if the password matches the hash using
147+
* the hashLegacy function
148+
*/
149+
export const isHashLegacyMatch = (password: string, hashPassword: string) => {
150+
const hashedWithLegacy = hashLegacy(password)
151+
return safeCompare(hashedWithLegacy, hashPassword)
121152
}
122153

123154
const mimeTypes: { [key: string]: string } = {

test/unit/node/util.test.ts

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { hash } from "../../../src/node/util"
1+
import { hash, isHashMatch, hashLegacy, isHashLegacyMatch } from "../../../src/node/util"
22

33
describe("getEnvPaths", () => {
44
describe("on darwin", () => {
@@ -155,3 +155,37 @@ describe("hash", () => {
155155
expect(hashed).not.toBe(plainTextPassword)
156156
})
157157
})
158+
159+
describe("isHashMatch", () => {
160+
it("should return true if the password matches the hash", () => {
161+
const password = "password123"
162+
const _hash = hash(password)
163+
expect(isHashMatch(password, _hash)).toBe(true)
164+
})
165+
it("should return false if the password does not match the hash", () => {
166+
const password = "password123"
167+
const _hash = hash(password)
168+
expect(isHashMatch("otherPassword123", _hash)).toBe(false)
169+
})
170+
})
171+
172+
describe("hashLegacy", () => {
173+
it("should return a hash of the string passed in", () => {
174+
const plainTextPassword = "mySecretPassword123"
175+
const hashed = hashLegacy(plainTextPassword)
176+
expect(hashed).not.toBe(plainTextPassword)
177+
})
178+
})
179+
180+
describe("isHashLegacyMatchh", () => {
181+
it("should return true if is match", () => {
182+
const password = "password123"
183+
const _hash = hashLegacy(password)
184+
expect(isHashLegacyMatch(password, _hash)).toBe(true)
185+
})
186+
it("should return false if is match", () => {
187+
const password = "password123"
188+
const _hash = hashLegacy(password)
189+
expect(isHashLegacyMatch("otherPassword123", _hash)).toBe(false)
190+
})
191+
})

0 commit comments

Comments
 (0)