Feature: webdav picbed now support digest auth

This commit is contained in:
萌萌哒赫萝
2023-09-12 19:27:59 -07:00
parent 09a636f414
commit 2e655a4ebd
15 changed files with 408 additions and 94 deletions

View File

@@ -779,10 +779,20 @@ export const supportedPicBedList: IStringKeyMap = {
default: true,
type: 'boolean',
tooltip: $T('MANAGE_CONSTANT_WEBDAV_SSL_TOOLTIP')
},
authType: {
required: true,
description: $T('MANAGE_CONSTANT_WEBDAV_AUTH_TYPE_DESC'),
default: 'basic',
type: 'select',
selectOptions: {
basic: 'Basic',
digest: 'Digest'
}
}
},
explain: $T('MANAGE_CONSTANT_WEBDAV_EXPLAIN'),
options: ['alias', 'endpoint', 'username', 'password', 'bucketName', 'baseDir', 'customUrl', 'webPath', 'proxy', 'sslEnabled'],
options: ['alias', 'endpoint', 'username', 'password', 'bucketName', 'baseDir', 'customUrl', 'webPath', 'proxy', 'sslEnabled', 'authType'],
refLink: 'https://piclist.cn/manage.html#webdav',
referenceText: $T('MANAGE_CONSTANT_WEBDAV_REFER_TEXT')
},

View File

@@ -0,0 +1,74 @@
import crypto from 'crypto'
import axios from 'axios'
const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/
let NC = 0
const NC_PAD = '00000000'
function md5 (text: crypto.BinaryLike) {
return 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 (let i = 0; i < parts.length; i++) {
const m = AUTH_KEY_VALUE_RE.exec(parts[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 = 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 {
await axios.get(
`${host}${uri}`
)
} catch (error: any) {
if (error.response.status === 401 && error.response.headers['www-authenticate']) {
return digestAuthHeader(method, uri, error.response.headers['www-authenticate'], username, password)
}
}
}