UNPKG

ecoledirecte.js

Version:

Good-looking client for EcoleDirecte's private API.

168 lines (167 loc) 6.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Config = exports.ConfigConstructor = exports.DefaultConfig = exports.EdHeaders = exports.USER_AGENT = exports.makeRequest = exports.formatBytes = exports.toISODate = void 0; const node_fetch_1 = __importDefault(require("node-fetch")); const mime_types_1 = __importDefault(require("mime-types")); const v3_1 = require("ecoledirecte-api-types/v3"); const events_1 = __importDefault(require("../events")); const errors_1 = require("../errors"); const events_2 = __importDefault(require("events")); function toISODate(date) { const d = new Date(date); if (isNaN(d.getTime())) throw new Error("Invalid date"); return [ d.getFullYear(), (d.getMonth() + 1).toString().padStart(2, "0"), d.getDate().toString().padStart(2, "0"), ].join("-"); } exports.toISODate = toISODate; /** * * @description Makes bytes human-readable */ function formatBytes(bytes) { let formatted; if (bytes >= 1073741824) { formatted = (bytes / 1073741824).toFixed(2) + " GB"; } else if (bytes >= 1048576) { formatted = (bytes / 1048576).toFixed(2) + " MB"; } else if (bytes >= 1024) { formatted = (bytes / 1024).toFixed(2) + " KB"; } else if (bytes > 1) { formatted = bytes + " bytes"; } else if (bytes === 1) { formatted = bytes + " byte"; } else { formatted = "0 bytes"; } return formatted; } exports.formatBytes = formatBytes; function getFileName(contentDisposition) { const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; ?|$)/i; const asciiFilenameRegex = /^filename=(["']?)(.*?[^\\])\1(?:; ?|$)/i; let fileName = ""; if (utf8FilenameRegex.test(contentDisposition)) { const execArray = utf8FilenameRegex.exec(contentDisposition); fileName = decodeURIComponent(execArray ? execArray[1] : ""); } else { // prevent ReDos attacks by anchoring the ascii regex to string start and // slicing off everything before 'filename=' const filenameStart = contentDisposition.toLowerCase().indexOf("filename="); if (filenameStart >= 0) { const partialDisposition = contentDisposition.slice(filenameStart); const matches = asciiFilenameRegex.exec(partialDisposition); if (matches != null && matches[2]) { fileName = matches[2]; } } } return fileName; } async function makeRequest(options, context = {}, account, token // eslint-disable-next-line @typescript-eslint/no-explicit-any ) { var _a; const { method, path, body, guard, teachRoot, expectBuffer } = options; const url = exports.Config.get(teachRoot ? "rootp" : "root") + path; const resListener = new events_2.default(); function onRes(callback) { resListener.on("response", callback); } function offRes(callback) { resListener.off("response", callback); } const params = { method: method, headers: { ...exports.EdHeaders, "x-token": (_a = (token || (account === null || account === void 0 ? void 0 : account.token))) !== null && _a !== void 0 ? _a : "", ...exports.Config.get("addedHeaders"), }, }; events_1.default.emit("request", { method, url, body, headers: params.headers, context, onRes, offRes, }); if (method === "POST") { const urlencoded = new URLSearchParams(); urlencoded.append("data", JSON.stringify(body)); params.body = urlencoded; } const response = await (0, node_fetch_1.default)(url, params); const resBody = expectBuffer ? await response.buffer() : (await response.json()); resListener.emit("response", { response, body: resBody }); const failure = !expectBuffer && (0, v3_1.isFailure)(resBody); if (guard && failure) throw new errors_1.EcoleDirecteAPIError(resBody); const someToken = (!expectBuffer && resBody.token) || response.headers.get("x-token"); if (!failure && account && someToken) account.token = someToken; if (expectBuffer) { const buff = resBody; const contentDisposition = response.headers.get("content-disposition"); if (!contentDisposition) throw new Error("No content-disposition"); // Get file name const fileName = getFileName(contentDisposition); // Get MIME type const mimeType = mime_types_1.default.lookup(fileName); // Create Blob const blob = new Blob([buff], { type: mimeType || undefined }); return blob; } return resBody; } exports.makeRequest = makeRequest; exports.USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"; exports.EdHeaders = { authority: "api.ecoledirecte.com", accept: "application/json, text/plain, */*", "accept-language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7", "content-type": "application/x-www-form-urlencoded", origin: "https://www.ecoledirecte.com", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-site", referer: "https://www.ecoledirecte.com/", "user-agent": exports.USER_AGENT, }; exports.DefaultConfig = { root: v3_1.root, rootp: v3_1.rootp, addedHeaders: {}, }; class ConfigConstructor { constructor(source = {}) { this.source = source; } get(key) { const fromSource = this.source[key]; const fromDefault = exports.DefaultConfig[key]; return fromSource !== null && fromSource !== void 0 ? fromSource : fromDefault; } } exports.ConfigConstructor = ConfigConstructor; ConfigConstructor.instance = new ConfigConstructor(); exports.Config = ConfigConstructor.instance;