UNPKG

@fdm-monster/server

Version:

FDM Monster is a bulk OctoPrint manager to set up, configure and monitor 3D printers. Our aim is to provide extremely optimized websocket performance and reliability.

131 lines (130 loc) 5.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "PrusaLinkHttpClientBuilder", { enumerable: true, get: function() { return PrusaLinkHttpClientBuilder; } }); const _defaulthttpclientbuilder = require("../../../shared/default-http-client.builder"); const _octoprintserviceconstants = require("../../octoprint/constants/octoprint-service.constants"); const _digestauthutil = require("./digest-auth.util"); const _nodecrypto = require("node:crypto"); class PrusaLinkHttpClientBuilder extends _defaulthttpclientbuilder.DefaultHttpClientBuilder { maxRetries = 1; username; password; authHeaderContext; onAuthError; onAuthSuccess; onRequestRetry; build() { if (!this.axiosOptions.baseURL) { throw new Error("Base URL is required"); } const axiosInstance = super.build(); if (this.username && this.password) { axiosInstance.interceptors.request.use(async (config)=>{ if (this.authHeaderContext) { const computedDigestHeader = this.generateDigestHeader(config.method?.toUpperCase() ?? "GET", config.url ?? "/"); config.headers[_octoprintserviceconstants.authorizationHeaderKey] = computedDigestHeader; } return config; }); axiosInstance.interceptors.response.use((response)=>response, async (error)=>{ const originalRequest = error.config; if (error.response?.status === 401 && this.username?.length && this.password?.length && (!originalRequest._retryCount || originalRequest._retryCount < this.maxRetries)) { const wwwAuthHeader = error.response.headers[_octoprintserviceconstants.wwwAuthenticationHeaderKey]; if (wwwAuthHeader) { if (typeof this.onAuthSuccess === "function") { this.onAuthSuccess(wwwAuthHeader); } this.saveParsedAuthHeaderContext(wwwAuthHeader); originalRequest._retryCount = (originalRequest._retryCount ?? 0) + 1; if (typeof this.onRequestRetry === "function") { this.onRequestRetry(error, originalRequest._retryCount); } return axiosInstance(originalRequest); } } if (error.response?.status === 401 && this.onAuthError && typeof this.onAuthError === "function") { this.onAuthError(error); } return Promise.reject(error); }); } return axiosInstance; } withDigestAuth(username, password, onAuthError, onRequestRetry, onAuthSuccess) { if (!username?.length) { throw new Error("username may not be an empty string"); } if (!password?.length) { throw new Error("password may not be an empty string"); } if (onAuthError && typeof onAuthError !== "function") { throw new Error("onAuthError must be a function"); } if (onAuthSuccess && typeof onAuthSuccess !== "function") { throw new Error("onAuthSuccess must be a function"); } if (onRequestRetry && typeof onRequestRetry !== "function") { throw new Error("onRequestRetry must be a function"); } this.username = username; this.password = password; this.onAuthError = onAuthError; this.onRequestRetry = onRequestRetry; this.onAuthSuccess = onAuthSuccess; return this; } withAuthHeader(authHeader) { if (!authHeader?.length) { throw new Error("Digest header may not be an empty string"); } this.saveParsedAuthHeaderContext(authHeader); return this; } saveParsedAuthHeaderContext(authHeader) { const headerValue = authHeader.startsWith("Digest ") ? authHeader.substring(7) : authHeader; const authParams = Object.fromEntries(headerValue.split(", ").map((param)=>{ const parts = param.split("="); if (parts.length === 2) { return [ parts[0], parts[1].replace(/"/g, "") ]; } return [ parts[0], "" ]; })); this.authHeaderContext = { realm: authParams.realm, nonce: authParams.nonce, qop: authParams.qop, hasQop: "qop" in authParams }; } generateDigestHeader(method, uri) { if (!this.authHeaderContext || !this.username || !this.password) { throw new Error("Digest auth not properly configured"); } const { realm, nonce, qop, hasQop } = this.authHeaderContext; return (0, _digestauthutil.generateDigestAuthHeader)({ username: this.username, password: this.password, method, uri, realm, nonce, qop: hasQop ? qop : undefined, nc: hasQop ? "00000001" : undefined, cnonce: hasQop ? (0, _nodecrypto.randomBytes)(8).toString("hex") : undefined }); } } //# sourceMappingURL=prusa-link-http-client.builder.js.map