Files
PicList/src/renderer/manage/utils/digestAuth.ts
2025-08-15 13:29:09 +08:00

79 lines
2.0 KiB
TypeScript

import type { IStringKeyMap } from '#/types/types'
const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/
let NC = 0
const NC_PAD = '00000000'
function md5(text: any) {
return window.node.crypto.createHash('md5').update(text).digest('hex')
}
export function digestAuthHeader(
method: string,
uri: string,
wwwAuthenticate: string,
username: string,
password: string
) {
const parts = wwwAuthenticate.split(',')
const opts = {} as IStringKeyMap
for (const i of parts) {
const m = AUTH_KEY_VALUE_RE.exec(i)
if (m) {
opts[m[1]] = m[2].replace(/["']/g, '')
}
}
if (!opts.realm || !opts.nonce) {
return ''
}
let qop = opts.qop || ''
const userpassArray = [username, password]
let nc = String(++NC)
nc = NC_PAD.substring(nc.length) + nc
const cnonce = window.node.crypto.randomBytes(8).toString('hex')
const ha1 = md5(userpassArray[0] + ':' + opts.realm + ':' + userpassArray[1])
const ha2 = md5(method.toUpperCase() + ':' + uri)
let s = ha1 + ':' + opts.nonce
if (qop) {
qop = qop.split(',')[0]
s += ':' + nc + ':' + cnonce + ':' + qop
}
s += ':' + ha2
const response = md5(s)
let authstring =
'Digest username="' +
userpassArray[0] +
'", realm="' +
opts.realm +
'", nonce="' +
opts.nonce +
'", uri="' +
uri +
'", response="' +
response +
'"'
if (opts.opaque) {
authstring += ', opaque="' + opts.opaque + '"'
}
if (qop) {
authstring += ', qop=' + qop + ', nc=' + nc + ', cnonce="' + cnonce + '"'
}
return authstring
}
export async function getAuthHeader(method: string, host: string, uri: string, username: string, password: string) {
try {
const response = await fetch(`${host}${uri}`)
if (response.status === 401 && response.headers.get('www-authenticate')) {
return digestAuthHeader(method, uri, response.headers.get('www-authenticate')!, username, password)
}
} catch (error: any) {
console.error('Network error:', error)
}
}