mirror of
https://github.com/honojs/hono.git
synced 2024-11-24 19:26:56 +01:00
refactor(utils/basic-auth): Moved Internal function to utils (#3359)
* refactor(utils/basic-auth): Split the code into utils * remove: dependency on HonoRequest
This commit is contained in:
parent
fa1954001c
commit
1db161e343
@ -5,32 +5,9 @@
|
||||
|
||||
import type { Context } from '../../context'
|
||||
import { HTTPException } from '../../http-exception'
|
||||
import type { HonoRequest } from '../../request'
|
||||
import type { MiddlewareHandler } from '../../types'
|
||||
import { auth } from '../../utils/basic-auth'
|
||||
import { timingSafeEqual } from '../../utils/buffer'
|
||||
import { decodeBase64 } from '../../utils/encode'
|
||||
|
||||
const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/
|
||||
const USER_PASS_REGEXP = /^([^:]*):(.*)$/
|
||||
const utf8Decoder = new TextDecoder()
|
||||
const auth = (req: HonoRequest) => {
|
||||
const match = CREDENTIALS_REGEXP.exec(req.header('Authorization') || '')
|
||||
if (!match) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let userPass = undefined
|
||||
// If an invalid string is passed to atob(), it throws a `DOMException`.
|
||||
try {
|
||||
userPass = USER_PASS_REGEXP.exec(utf8Decoder.decode(decodeBase64(match[1])))
|
||||
} catch {} // Do nothing
|
||||
|
||||
if (!userPass) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return { username: userPass[1], password: userPass[2] }
|
||||
}
|
||||
|
||||
type BasicAuthOptions =
|
||||
| {
|
||||
@ -98,7 +75,7 @@ export const basicAuth = (
|
||||
}
|
||||
|
||||
return async function basicAuth(ctx, next) {
|
||||
const requestUser = auth(ctx.req)
|
||||
const requestUser = auth(ctx.req.raw)
|
||||
if (requestUser) {
|
||||
if (verifyUserInOptions) {
|
||||
if (await options.verifyUser(requestUser.username, requestUser.password, ctx)) {
|
||||
|
57
src/utils/basic-auth.test.ts
Normal file
57
src/utils/basic-auth.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { HonoRequest } from '../request'
|
||||
import { auth } from './basic-auth'
|
||||
|
||||
describe('auth', () => {
|
||||
it('auth() - not include Authorization Header', () => {
|
||||
const res = auth(new Request('http://localhost/auth'))
|
||||
expect(res).toBeUndefined()
|
||||
})
|
||||
|
||||
it('auth() - invalid Authorization Header format', () => {
|
||||
const res = auth(
|
||||
new Request('http://localhost/auth', {
|
||||
headers: { Authorization: 'InvalidAuthHeader' },
|
||||
})
|
||||
)
|
||||
expect(res).toBeUndefined()
|
||||
})
|
||||
|
||||
it('auth() - invalid Base64 string in Authorization Header', () => {
|
||||
const res = auth(
|
||||
new Request('http://localhost/auth', {
|
||||
headers: { Authorization: 'Basic InvalidBase64' },
|
||||
})
|
||||
)
|
||||
expect(res).toBeUndefined()
|
||||
})
|
||||
|
||||
it('auth() - valid Authorization Header', () => {
|
||||
const validBase64 = btoa('username:password')
|
||||
const res = auth(
|
||||
new Request('http://localhost/auth', {
|
||||
headers: { Authorization: `Basic ${validBase64}` },
|
||||
})
|
||||
)
|
||||
expect(res).toEqual({ username: 'username', password: 'password' })
|
||||
})
|
||||
|
||||
it('auth() - empty username', () => {
|
||||
const validBase64 = btoa(':password')
|
||||
const res = auth(
|
||||
new Request('http://localhost/auth', {
|
||||
headers: { Authorization: `Basic ${validBase64}` },
|
||||
})
|
||||
)
|
||||
expect(res).toEqual({ username: '', password: 'password' })
|
||||
})
|
||||
|
||||
it('auth() - empty password', () => {
|
||||
const validBase64 = btoa('username:')
|
||||
const res = auth(
|
||||
new Request('http://localhost/auth', {
|
||||
headers: { Authorization: `Basic ${validBase64}` },
|
||||
})
|
||||
)
|
||||
expect(res).toEqual({ username: 'username', password: '' })
|
||||
})
|
||||
})
|
26
src/utils/basic-auth.ts
Normal file
26
src/utils/basic-auth.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { decodeBase64 } from './encode'
|
||||
|
||||
const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/
|
||||
const USER_PASS_REGEXP = /^([^:]*):(.*)$/
|
||||
const utf8Decoder = new TextDecoder()
|
||||
|
||||
export type Auth = (req: Request) => { username: string; password: string } | undefined
|
||||
|
||||
export const auth: Auth = (req: Request) => {
|
||||
const match = CREDENTIALS_REGEXP.exec(req.headers.get('Authorization') || '')
|
||||
if (!match) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let userPass = undefined
|
||||
// If an invalid string is passed to atob(), it throws a `DOMException`.
|
||||
try {
|
||||
userPass = USER_PASS_REGEXP.exec(utf8Decoder.decode(decodeBase64(match[1])))
|
||||
} catch {} // Do nothing
|
||||
|
||||
if (!userPass) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return { username: userPass[1], password: userPass[2] }
|
||||
}
|
Loading…
Reference in New Issue
Block a user