mirror of https://github.com/coder/code-server.git
feat: add handlePasswordValidation + tests
This commit is contained in:
parent
7ff4117531
commit
a14ea39c4a
|
@ -189,6 +189,66 @@ export function getPasswordMethod(hashedPassword: string | undefined): PasswordM
|
||||||
return "SHA256"
|
return "SHA256"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PasswordValidation = {
|
||||||
|
isPasswordValid: boolean
|
||||||
|
hashedPassword: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HandlePasswordValidationArgs = {
|
||||||
|
/** The PasswordMethod */
|
||||||
|
passwordMethod: PasswordMethod
|
||||||
|
/** The password provided by the user */
|
||||||
|
passwordFromRequestBody: string
|
||||||
|
/** The password set in PASSWORD or config */
|
||||||
|
passwordFromArgs: string | undefined
|
||||||
|
/** The hashed-password set in HASHED_PASSWORD or config */
|
||||||
|
hashedPasswordFromArgs: string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a password is valid and also returns the hash
|
||||||
|
* using the PasswordMethod
|
||||||
|
*/
|
||||||
|
export async function handlePasswordValidation(
|
||||||
|
passwordValidationArgs: HandlePasswordValidationArgs,
|
||||||
|
): Promise<PasswordValidation> {
|
||||||
|
const { passwordMethod, passwordFromArgs, passwordFromRequestBody, hashedPasswordFromArgs } = passwordValidationArgs
|
||||||
|
// TODO implement
|
||||||
|
const passwordValidation = <PasswordValidation>{
|
||||||
|
isPasswordValid: false,
|
||||||
|
hashedPassword: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (passwordMethod) {
|
||||||
|
case "PLAIN_TEXT": {
|
||||||
|
const isValid = passwordFromArgs ? safeCompare(passwordFromRequestBody, passwordFromArgs) : false
|
||||||
|
passwordValidation.isPasswordValid = isValid
|
||||||
|
|
||||||
|
const hashedPassword = await hash(passwordFromRequestBody)
|
||||||
|
passwordValidation.hashedPassword = hashedPassword
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "SHA256": {
|
||||||
|
const isValid = isHashLegacyMatch(passwordFromRequestBody, hashedPasswordFromArgs || "")
|
||||||
|
passwordValidation.isPasswordValid = isValid
|
||||||
|
|
||||||
|
passwordValidation.hashedPassword = hashedPasswordFromArgs || (await hashLegacy(passwordFromRequestBody))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "ARGON2": {
|
||||||
|
const isValid = await isHashMatch(passwordFromRequestBody, hashedPasswordFromArgs || "")
|
||||||
|
passwordValidation.isPasswordValid = isValid
|
||||||
|
|
||||||
|
passwordValidation.hashedPassword = hashedPasswordFromArgs || ""
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return passwordValidation
|
||||||
|
}
|
||||||
|
|
||||||
const mimeTypes: { [key: string]: string } = {
|
const mimeTypes: { [key: string]: string } = {
|
||||||
".aac": "audio/x-aac",
|
".aac": "audio/x-aac",
|
||||||
".avi": "video/x-msvideo",
|
".avi": "video/x-msvideo",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
hash,
|
hash,
|
||||||
isHashMatch,
|
isHashMatch,
|
||||||
|
handlePasswordValidation,
|
||||||
PasswordMethod,
|
PasswordMethod,
|
||||||
getPasswordMethod,
|
getPasswordMethod,
|
||||||
hashLegacy,
|
hashLegacy,
|
||||||
|
@ -232,3 +233,92 @@ describe("getPasswordMethod", () => {
|
||||||
expect(passwordMethod).toEqual(expected)
|
expect(passwordMethod).toEqual(expected)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe.only("handlePasswordValidation", () => {
|
||||||
|
it("should return true with a hashedPassword for a PLAIN_TEXT password", async () => {
|
||||||
|
const p = "password"
|
||||||
|
const passwordValidation = await handlePasswordValidation({
|
||||||
|
passwordMethod: "PLAIN_TEXT",
|
||||||
|
passwordFromRequestBody: p,
|
||||||
|
passwordFromArgs: p,
|
||||||
|
hashedPasswordFromArgs: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
const matchesHash = await isHashMatch(p, passwordValidation.hashedPassword)
|
||||||
|
|
||||||
|
expect(passwordValidation.isPasswordValid).toBe(true)
|
||||||
|
expect(matchesHash).toBe(true)
|
||||||
|
})
|
||||||
|
it("should return false when PLAIN_TEXT password doesn't match args", async () => {
|
||||||
|
const p = "password"
|
||||||
|
const passwordValidation = await handlePasswordValidation({
|
||||||
|
passwordMethod: "PLAIN_TEXT",
|
||||||
|
passwordFromRequestBody: "password1",
|
||||||
|
passwordFromArgs: p,
|
||||||
|
hashedPasswordFromArgs: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
const matchesHash = await isHashMatch(p, passwordValidation.hashedPassword)
|
||||||
|
|
||||||
|
expect(passwordValidation.isPasswordValid).toBe(false)
|
||||||
|
expect(matchesHash).toBe(false)
|
||||||
|
})
|
||||||
|
it("should return true with a hashedPassword for a SHA256 password", async () => {
|
||||||
|
const p = "helloworld"
|
||||||
|
const passwordValidation = await handlePasswordValidation({
|
||||||
|
passwordMethod: "SHA256",
|
||||||
|
passwordFromRequestBody: p,
|
||||||
|
passwordFromArgs: undefined,
|
||||||
|
hashedPasswordFromArgs: "936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af",
|
||||||
|
})
|
||||||
|
|
||||||
|
const matchesHash = isHashLegacyMatch(p, passwordValidation.hashedPassword)
|
||||||
|
|
||||||
|
expect(passwordValidation.isPasswordValid).toBe(true)
|
||||||
|
expect(matchesHash).toBe(true)
|
||||||
|
})
|
||||||
|
it("should return false when SHA256 password doesn't match hash", async () => {
|
||||||
|
const p = "helloworld1"
|
||||||
|
const passwordValidation = await handlePasswordValidation({
|
||||||
|
passwordMethod: "SHA256",
|
||||||
|
passwordFromRequestBody: p,
|
||||||
|
passwordFromArgs: undefined,
|
||||||
|
hashedPasswordFromArgs: "936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af",
|
||||||
|
})
|
||||||
|
|
||||||
|
const matchesHash = isHashLegacyMatch(p, passwordValidation.hashedPassword)
|
||||||
|
|
||||||
|
expect(passwordValidation.isPasswordValid).toBe(false)
|
||||||
|
expect(matchesHash).toBe(false)
|
||||||
|
})
|
||||||
|
it("should return true with a hashedPassword for a ARGON2 password", async () => {
|
||||||
|
const p = "password"
|
||||||
|
const passwordValidation = await handlePasswordValidation({
|
||||||
|
passwordMethod: "ARGON2",
|
||||||
|
passwordFromRequestBody: p,
|
||||||
|
passwordFromArgs: undefined,
|
||||||
|
hashedPasswordFromArgs:
|
||||||
|
"$argon2i$v=19$m=4096,t=3,p=1$0qR/o+0t00hsbJFQCKSfdQ$oFcM4rL6o+B7oxpuA4qlXubypbBPsf+8L531U7P9HYY",
|
||||||
|
})
|
||||||
|
|
||||||
|
const matchesHash = await isHashMatch(p, passwordValidation.hashedPassword)
|
||||||
|
|
||||||
|
expect(passwordValidation.isPasswordValid).toBe(true)
|
||||||
|
expect(matchesHash).toBe(true)
|
||||||
|
})
|
||||||
|
it("should return false when ARGON2 password doesn't match hash", async () => {
|
||||||
|
const p = "password1"
|
||||||
|
const passwordValidation = await handlePasswordValidation({
|
||||||
|
passwordMethod: "ARGON2",
|
||||||
|
passwordFromRequestBody: p,
|
||||||
|
passwordFromArgs: undefined,
|
||||||
|
hashedPasswordFromArgs:
|
||||||
|
"$argon2i$v=19$m=4096,t=3,p=1$0qR/o+0t00hsbJFQCKSfdQ$oFcM4rL6o+B7oxpuA4qlXubypbBPsf+8L531U7P9HYY",
|
||||||
|
})
|
||||||
|
|
||||||
|
const matchesHash = await isHashMatch(p, passwordValidation.hashedPassword)
|
||||||
|
|
||||||
|
expect(passwordValidation.isPasswordValid).toBe(false)
|
||||||
|
expect(matchesHash).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue