ecoledirecte.js
Version:
Good-looking client for EcoleDirecte's private API.
168 lines (167 loc) • 6.1 kB
JavaScript
;
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;