NeahNew/node_modules/webdav/dist/node/auth/digest.js
2025-05-03 14:17:46 +02:00

73 lines
2.6 KiB
JavaScript

import md5 from "md5";
import { ha1Compute } from "../tools/crypto.js";
const NONCE_CHARS = "abcdef0123456789";
const NONCE_SIZE = 32;
export function createDigestContext(username, password, ha1) {
return { username, password, ha1, nc: 0, algorithm: "md5", hasDigestAuth: false };
}
export function generateDigestAuthHeader(options, digest) {
const url = options.url.replace("//", "");
const uri = url.indexOf("/") == -1 ? "/" : url.slice(url.indexOf("/"));
const method = options.method ? options.method.toUpperCase() : "GET";
const qop = /(^|,)\s*auth\s*($|,)/.test(digest.qop) ? "auth" : false;
const ncString = `00000000${digest.nc}`.slice(-8);
const ha1 = ha1Compute(digest.algorithm, digest.username, digest.realm, digest.password, digest.nonce, digest.cnonce, digest.ha1);
const ha2 = md5(`${method}:${uri}`);
const digestResponse = qop
? md5(`${ha1}:${digest.nonce}:${ncString}:${digest.cnonce}:${qop}:${ha2}`)
: md5(`${ha1}:${digest.nonce}:${ha2}`);
const authValues = {
username: digest.username,
realm: digest.realm,
nonce: digest.nonce,
uri,
qop,
response: digestResponse,
nc: ncString,
cnonce: digest.cnonce,
algorithm: digest.algorithm,
opaque: digest.opaque
};
const authHeader = [];
for (const k in authValues) {
if (authValues[k]) {
if (k === "qop" || k === "nc" || k === "algorithm") {
authHeader.push(`${k}=${authValues[k]}`);
}
else {
authHeader.push(`${k}="${authValues[k]}"`);
}
}
}
return `Digest ${authHeader.join(", ")}`;
}
function makeNonce() {
let uid = "";
for (let i = 0; i < NONCE_SIZE; ++i) {
uid = `${uid}${NONCE_CHARS[Math.floor(Math.random() * NONCE_CHARS.length)]}`;
}
return uid;
}
export function parseDigestAuth(response, _digest) {
const isDigest = responseIndicatesDigestAuth(response);
if (!isDigest) {
return false;
}
const re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi;
for (;;) {
const authHeader = (response.headers && response.headers.get("www-authenticate")) || "";
const match = re.exec(authHeader);
if (!match) {
break;
}
_digest[match[1]] = match[2] || match[3];
}
_digest.nc += 1;
_digest.cnonce = makeNonce();
return true;
}
export function responseIndicatesDigestAuth(response) {
const authHeader = (response.headers && response.headers.get("www-authenticate")) || "";
return authHeader.split(/\s/)[0].toLowerCase() === "digest";
}