73 lines
2.6 KiB
JavaScript
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";
|
|
}
|