@piarre/ts-freebox
Version:
420 lines (408 loc) • 14.5 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Freebox: () => Freebox,
request: () => request
});
module.exports = __toCommonJS(src_exports);
// src/utils/fetch.ts
var formatUrl = (url) => !url.toString().endsWith("/") ? `${url}/` : url;
var fetchFBX = (url, token, method, options) => {
return fetch(formatUrl(url), {
...options,
method,
body: JSON.stringify(options?.body),
headers: {
...options?.headers,
"Content-Type": "application/json",
"X-Fbx-App-Auth": token || "",
Host: "mafreebox.freebox.fr"
}
}).then((res) => res.json()).catch((error) => {
throw new Error(`\u274C ~ error on call ${url}`, {
cause: error
});
});
};
var request = (url, token, options, method = "GET") => fetchFBX(url, token, method, options);
var fetch_default = request;
// src/lib/freebox.ts
var import_crypto_js = require("crypto-js");
// src/utils/sleep.ts
var sleep = async (ms = 1e3) => await new Promise((resolve) => setTimeout(resolve, ms));
var sleep_default = sleep;
// src/lib/submodule.ts
var Submodule = class {
_freebox;
baseUrl;
token;
constructor(freebox) {
this._freebox = freebox;
this.baseUrl = this._freebox._configuration.baseUrl;
this.token = this._freebox.token;
}
};
var submodule_default = Submodule;
// src/lib/wifi.ts
var Wifi = class extends submodule_default {
constructor(freebox) {
super(freebox);
}
async config() {
return await fetch_default(`${this.baseUrl}/wifi/config/`, this.token);
}
async state() {
return await fetch_default(`${this.baseUrl}/wifi/state/`, this.token);
}
async AP(id) {
return await fetch_default(id == void 0 ? `${this.baseUrl}/wifi/ap/` : `${this.baseUrl}/wifi/ap/${id}`, this.token);
}
async BSS() {
return await fetch_default(`${this.baseUrl}/wifi/bss/`, this.token);
}
};
// src/lib/freebox.ts
var import_log4js = __toESM(require("log4js"));
// src/lib/lan.ts
var LAN = class extends submodule_default {
constructor(freebox) {
super(freebox);
}
/**
* Returns the current LanConfig
* @link https://mafreebox.freebox.fr/doc/index.html#get-the-current-lan-configuration
* @returns {Promise<Response<LanConfig>>}
*/
async config() {
return await fetch_default(`${this.baseUrl}/lan/config/`, this.token);
}
/**
* Update the current LanConfig
* @link https://mafreebox.freebox.fr/doc/index.html#update-the-current-lan-configuration
* @param config The new partial LanConfig
* @returns {Promise<Response<Partial<LanConfig>>>}
*/
async update(config) {
if (!config || Object.keys(config).length === 0)
throw new Error("config is required");
return await fetch_default(
`${this.baseUrl}/lan/config/`,
this.token,
{
body: config
},
"PUT"
);
}
/**
* Getting the list of browsable LAN interfaces
* @link https://mafreebox.freebox.fr/doc/index.html#getting-the-list-of-browsable-lan-interfaces
* @returns {Promise<Response<LanInterface[]>>}
*/
async interfaces() {
return await fetch_default(`${this.baseUrl}/lan/browser/interfaces/`, this.token);
}
/**
* Getting the list of hosts on a given interface
* @link https://mafreebox.freebox.fr/doc/index.html#getting-the-list-of-hosts-on-a-given-interface
* @param _interface Returns the list of LanHost on this interface
* @returns {Promise<Response<LanHost[]>>}
*/
async hosts(_interface = "pub") {
if (!_interface)
throw new Error("interface is required");
return await fetch_default(`${this.baseUrl}/lan/browser/${_interface}/`, this.token);
}
/**
* Getting an host information
* @link https://mafreebox.freebox.fr/doc/index.html#getting-an-host-information
* @param _interface - The interface to which the host is connected
* @param id - The id of the host
* @returns {Promise<Response<LanHost>>}
*/
async host(_interface = "pub", id) {
if (!_interface)
throw new Error("interface is required");
if (!id)
throw new Error("id is required");
return await fetch_default(`${this.baseUrl}/lan/browser/${_interface}/${id}/`, this.token);
}
/**
* Updating an host information
* @link https://mafreebox.freebox.fr/doc/index.html#updating-an-host-information
* @param _interface The interface to which the host is connected
* @param id The id of the host
* @param data The data to update
* @returns {Promise<Response<Partial<LanHost>>>}
*/
async updateHost(_interface = "pub", id, data) {
if (!_interface)
throw new Error("interface is required");
if (!id)
throw new Error("id is required");
if (!data || Object.keys(data).length === 0)
throw new Error("data is required");
return await fetch_default(
`${this.baseUrl}/lan/browser/${_interface}/${id}/`,
this.token,
{
body: data
},
"PUT"
);
}
/**
* Send a wake on LAN packet to the specified host with an optional password
* @link https://mafreebox.freebox.fr/doc/index.html#send-wake-ok-lan-packet-to-an-host
* @param _interface The interface to which the host is connected
* @param mac The MAC address of the host
* @param password - [OPTIONAL] The password to use to send the WOL packet
* @returns
*/
async WOL(_interface = "pub", mac, password = "") {
if (!_interface)
throw new Error("interface is required");
if (!mac)
throw new Error("mac is required");
return await fetch_default(
`${this.baseUrl}/lan/wol/${_interface}/`,
this.token,
{
body: {
mac,
password
}
},
"POST"
);
}
};
// src/lib/connection.ts
var Connection = class extends submodule_default {
constructor(freebox) {
super(freebox);
}
/**
* Get the current Connection status
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#connection-status-object
* @returns {Promise<Response<ConnectionStatus>>}
*/
async status() {
return await fetch_default(`${this.baseUrl}/connection/`, this.token);
}
/**
* Get the current Connection configuration
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#get-the-current-connection-configuration
* @returns {Promise<Response<ConnectionConfig>>}
*/
async config() {
return await fetch_default(`${this.baseUrl}/connection/config/`, this.token);
}
/**
* Update the Connection configuration
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#update-the-connection-configuration
* @param body The new configuration
* @returns {Promise<Response<ConnectionConfig>>}
*/
async updateConfig(body) {
return await fetch_default(`${this.baseUrl}/connection/config/`, this.token, {
body
});
}
/**
* Get the current IPv6 Connection configuration
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#get-the-current-ipv6-connection-configuration
* @returns {Promise<Response<IPv6ConnectionConfiguration>>}
*/
async IPv6config() {
return await fetch_default(`${this.baseUrl}/connection/ipv6/config/`, this.token);
}
/**
* Update the IPv6 Connection configuration
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#update-the-ipv6-connection-configuration
* @param body The new configuration
* @returns {Promise<Response<IPv6ConnectionConfiguration>>}
*/
async updateIPv6Config(body) {
return await fetch_default(
`${this.baseUrl}/connection/ipv6/config/`,
this.token,
{
body
},
"PUT"
);
}
};
// src/lib/port.ts
var PortForwarding = class extends submodule_default {
constructor(freebox) {
super(freebox);
}
/**
* Retrieves the status of a port or all ports.
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#getting-the-list-of-port-forwarding
* @param id - The ID of the port to retrieve the status for. If not provided, retrieves the status of all ports.
* @returns {Promise<Response<T>>}
*/
async status(id) {
return await fetch_default(id == void 0 ? `${this.baseUrl}/fw/redir/` : `${this.baseUrl}/fw/redir/${id}`, this.token);
}
/**
* Updating a port forwarding
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#updating-a-port-forwarding
* @param id The id of the port to update
* @param data The data to update
* @returns {Promise<Response<T>>}
*/
async update(id, data) {
return await fetch_default(`${this.baseUrl}/fw/redir/${id}`, this.token, {
body: data
}, "PUT");
}
/**
* Add a port forwarding
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#add-a-port-forwarding
* @param data Add a port forwarding
* @returns {Promise<Response<T>>}
*/
async add(data) {
return await fetch_default(`${this.baseUrl}/fw/redir/`, this.token, {
body: data
}, "POST");
}
/**
* Delete a port forwarding
* @link https://mafreebox.freebox.fr/doc/index.html?v=b828168f17942dd3e241fff4f01ccdd14bcc89aa#delete-a-port-forwarding
* @param id The id of the port to delete
* @returns {Promise<VoidResponse>}
*/
async delete(id) {
return await fetch_default(`${this.baseUrl}/fw/redir/${id}`, this.token, {}, "DELETE");
}
};
// src/lib/freebox.ts
var Freebox = class {
wifi;
LAN;
connection;
port;
logger = import_log4js.default.getLogger("Freebox");
_configuration = {
baseUrl: "http://mafreebox.freebox.fr/api/v11"
};
_app;
token = "";
constructor(app) {
this._app = app;
this.logger.level = "info";
if (!this._app.app_id) {
throw new Error("app_id must be defined in the app object");
} else if (!this._app.app_name) {
throw new Error("app_name must be defined in the app object");
} else if (!this._app.app_version) {
throw new Error("app_version must be defined in the app object");
} else if (!this._app.device_name) {
throw new Error("device_name must be defined in the app object");
}
}
async login() {
if (this._app.app_token) {
this.logger.info("app_token already defined using it to open a session");
this._app.app_token = this._app.app_token;
} else {
const reqAuthorization = await fetch_default(
`${this._configuration?.baseUrl}/login/authorize/`,
null,
{
body: {
app_id: this._app.app_id,
app_name: this._app.app_name,
app_version: this._app.app_version,
device_name: this._app.device_name
}
},
"POST"
);
this._app.app_token = reqAuthorization.result.app_token;
reqAuthorization.success = false;
while (!reqAuthorization.success) {
this.logger.info(
`Please accept the authorization request on your Freebox Server with token : ${reqAuthorization.result.app_token}`
);
const checkAuthorization = await fetch_default(`${this._configuration?.baseUrl}/login/authorize/${reqAuthorization.result.track_id}`, null);
switch (checkAuthorization.result.status) {
case "unknown":
throw new Error("the app_token is invalid or has been revoked");
case "pending":
this.logger.info("the user has not confirmed the authorization request yet");
break;
case "timeout":
throw new Error("the user did not confirmed the authorization within the given time");
case "granted":
this.logger.info("the app_token is valid and can be used to open a session");
reqAuthorization.success = true;
this._app.app_token = reqAuthorization.result.app_token;
break;
case "denied":
throw new Error("the user denied the authorization request");
default:
throw new Error("Unknown error");
}
await sleep_default();
}
}
const challenge = await fetch_default(`${this._configuration.baseUrl}/login/`, null);
const password = (0, import_crypto_js.HmacSHA1)(challenge.result.challenge, this._app.app_token).toString();
const reqSession = await fetch_default(
`${this._configuration.baseUrl}/login/session/`,
null,
{
body: {
app_id: this._app.app_id,
password
}
},
"POST"
);
this._app.session_token = reqSession.result.session_token;
this.token = this._app.session_token;
this.logger.info("Logged in with sesion_token: ", this._app.session_token);
this.wifi = new Wifi(this);
this.LAN = new LAN(this);
this.connection = new Connection(this);
this.port = new PortForwarding(this);
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Freebox,
request
});