asusroutermonitor
Version:
A library to interact with your ASUS router.
406 lines (405 loc) • 14.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RouterInfo = void 0;
const node_fetch_1 = require("node-fetch");
var ClientType;
(function (ClientType) {
ClientType[ClientType["DEVICE"] = 0] = "DEVICE";
ClientType[ClientType["UNK_1"] = 1] = "UNK_1";
ClientType[ClientType["UNK_7"] = 7] = "UNK_7";
ClientType[ClientType["UNK_18"] = 18] = "UNK_18";
ClientType[ClientType["LINUX"] = 22] = "LINUX";
ClientType[ClientType["ROUTER"] = 24] = "ROUTER";
ClientType[ClientType["UNK_34"] = 34] = "UNK_34"; // Unsure, ASUS_Phone
})(ClientType || (ClientType = {}));
;
var IPMethod;
(function (IPMethod) {
IPMethod["STATIC"] = "Manual";
IPMethod["DHCP"] = "Dhcp";
IPMethod["MANUAL"] = "Manual";
IPMethod["OFFLINE"] = "Offline";
})(IPMethod || (IPMethod = {}));
;
var OPMode;
(function (OPMode) {
OPMode[OPMode["NONE"] = 0] = "NONE";
OPMode[OPMode["WIRELESS_ROUTER"] = 1] = "WIRELESS_ROUTER";
OPMode[OPMode["OP_RE_ITEM"] = 2] = "OP_RE_ITEM";
OPMode[OPMode["OP_AP_ITEM"] = 3] = "OP_AP_ITEM";
OPMode[OPMode["OP_MB_ITME"] = 4] = "OP_MB_ITME";
})(OPMode || (OPMode = {}));
;
// TODO: This pains me greatly but I don't know what to do. I can't start with a number.
var WirelessBand;
(function (WirelessBand) {
WirelessBand[WirelessBand["None"] = 0] = "None";
WirelessBand[WirelessBand["2_4GHZ"] = 1] = "2_4GHZ";
WirelessBand[WirelessBand["5GHZ"] = 2] = "5GHZ";
})(WirelessBand || (WirelessBand = {}));
;
var InternetMode;
(function (InternetMode) {
InternetMode["ALLOW"] = "allow";
InternetMode["BLOCK"] = "block";
InternetMode["TIME"] = "time";
})(InternetMode || (InternetMode = {}));
;
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
class RouterInfo {
/**
* Create the object and connect with the router
* @param {string} ip Router IP Address
*/
constructor(ip) {
this.ip = ip;
this.url = `http://${ip}/appGet.cgi`;
this.headers = null;
}
/**
* Authenticate with the router
* @param {string} ip Router IP Address
* @param {string} username Root username
* @param {string} password Root password
* @returns {boolean} Whether authentication was successful.
*/
async authenticate(username, password) {
const loginToken = Buffer.from(`${username}:${password}`).toString('base64');
this.headers = {
'user-agent': 'asusrouter-Android-DUTUtil-1.0.0.245',
'content-type': 'application/x-www-form-urlencoded'
};
const req = await (0, node_fetch_1.default)(`http://${this.ip}/login.cgi`, {
method: 'POST',
headers: this.headers,
body: `login_authorization=${loginToken}`
});
if (req.status !== 200) {
return false;
}
const res = await req.json();
if (!res.asus_token) {
return false;
}
this.headers.cookie = `asus_token=${res.asus_token}`;
return true;
}
/**
* Private get method to execute a hook on the router and return the result
* @param {string} command Command to send to the router
* @returns {string|null} String result from the router or null
*/
async get(command) {
if (this.headers === null) {
return null;
}
const req = await (0, node_fetch_1.default)(this.url, {
method: 'POST',
headers: this.headers,
body: `hook=${command}`
});
if (req.status !== 200) {
return null;
}
return await req.text();
}
/**
* Gets uptime of the router
* @returns {UptimeResponse|null} an object with since and uptime, or null.
*/
async getUptime() {
const r = await this.get('uptime()');
if (r === null) {
return null;
}
const since = r.split(':')[1].split('(')[0];
const uptime = r.split('(')[1].split(' ')[0];
return {
since: new Date(since),
uptime: Number(uptime)
};
}
/**
* Get the uptime of the router in seconds
* @returns {number} Uptime in seconds
*/
async getUptimeSecs() {
const r = await this.get('uptime()');
if (r === null) {
return null;
}
const uptime = r.split('(')[1].split(' ')[0];
return Number(uptime);
}
/**
* Gets the memory usage of the router
* @returns {MemoryUsage|null} Memory usage in bytes or null
*/
async getMemoryUsage() {
const r = await this.get('memory_usage()');
if (r === null) {
return null;
}
// TODO: This will throw an error if the json is invalid.
const usage = JSON.parse(`{${r.slice(17)}`);
return {
mem_total: Number(usage.mem_total),
mem_free: Number(usage.mem_free),
mem_used: Number(usage.mem_used)
};
}
/**
* Gets the CPU usage of the router
* @returns {CPUUsage|null} CPU usage or null
*/
async getCPUUsage() {
const r = await this.get('cpu_usage()');
if (r === null) {
return null;
}
// TODO: This will throw an error if the json is invalid.
const usage = JSON.parse(`{${r.slice(14)}`);
return {
cpu1_total: Number(usage.cpu1_total),
cpu1_usage: Number(usage.cpu1_usage),
cpu2_total: Number(usage.cpu2_total),
cpu2_usage: Number(usage.cpu2_total)
};
}
/**
* Gets a full list of client information as well as the connected mac addresses and client api level.
* @returns {ClientFullInfo|null} List of client information or null
*/
async getClientsFullInfo() {
const r = await this.get('get_clientlist()');
if (r === null) {
return null;
}
const clients = JSON.parse(r);
const clientFullInfo = {
clientList: [],
macList: clients.maclist,
clientAPILevel: clients.ClientAPILevel
};
for (const mac in clients.get_clientlist) {
if (mac === 'macList' || mac === 'ClientAPILevel') {
continue;
}
const oldClient = clients.get_clientlist[mac];
const client = {
type: Number(oldClient.type),
defaultType: Number(oldClient.defaultType),
name: oldClient.name,
nickName: oldClient.nickName,
ip: oldClient.ip,
mac: oldClient.mac,
from: oldClient.from,
macRepeat: !!Number(oldClient.macRepeat),
isGateway: !!Number(oldClient.isGateway),
isWebServer: !!Number(oldClient.isWebServer),
isPrinter: !!Number(oldClient.isPrinter),
isITunes: !!Number(oldClient.isITunes),
dpiType: oldClient.dpiType,
dpiDevice: oldClient.dpiDevice,
vendor: oldClient.vendor,
isWL: Number(oldClient.isWL),
isGN: oldClient.isGN,
isOnline: !!Number(oldClient.isOnline),
ssid: oldClient.ssid,
isLogin: !!Number(oldClient.isLogin),
opMode: Number(oldClient.opMode),
rssi: Number(oldClient.rssi),
curTx: Number(oldClient.curTx),
curRx: Number(oldClient.curRx),
totalTx: Number(oldClient.totalTx),
totalRx: Number(oldClient.totalRx),
wlConnectTime: oldClient.wlConnectTime,
ipMethod: oldClient.ipMethod,
ROG: !!Number(oldClient.ROG),
group: oldClient.group,
callback: oldClient.callback,
keeparp: oldClient.keeparp,
qosLevel: oldClient.qosLevel,
wtFast: oldClient.wtfast,
internetMode: oldClient.internetMode,
internetState: oldClient.internetState,
amesh_isReClient: !!Number(oldClient.amesh_isReClient),
amesh_papMac: oldClient.amesh_papMac,
amesh_bind_mac: oldClient.amesh_bind_mac,
amesh_bind_band: oldClient.amesh_bind_band
};
clientFullInfo.clientList.push(client);
}
return clientFullInfo;
}
/**
* Gets the total traffic since last restart in Megabits
* @returns {Traffic|null} Sent and received Megabits since last boot or null
*/
async getTotalTraffic() {
const r = await this.get('netdev(appobj)');
if (r === null) {
return null;
}
const traffic = JSON.parse(r);
const tx = parseInt(traffic.netdev.INTERNET_tx, 16) * 8 / 1024 / 1024 / 2;
const rx = parseInt(traffic.netdev.INTERNET_rx, 16) * 8 / 1024 / 1024 / 2;
return {
sent: tx,
recv: rx
};
}
/**
* Averages the network traffic over 2 seconds in Megabits
* @returns {Traffic|null} Current network traffic in Mbit/s
*/
async getTraffic() {
const start = await this.get('netdev(appobj)');
await sleep(2000);
const end = await this.get('netdev(appobj)');
if (start === null || end === null) {
return null;
}
const startTraffic = JSON.parse(start);
const endTraffic = JSON.parse(end);
let tx = parseInt(endTraffic.netdev.INTERNET_tx, 16) * 8 / 1024 / 1024 / 2;
tx -= parseInt(startTraffic.netdev.INTERNET_tx, 16) * 8 / 1024 / 1024 / 2;
let rx = parseInt(endTraffic.netdev.INTERNET_rx, 16) * 8 / 1024 / 1024 / 2;
rx -= parseInt(startTraffic.netdev.INTERNET_rx, 16) * 8 / 1024 / 1024 / 2;
return {
sent: tx,
recv: rx
};
}
/**
* Gets the status of the current WAN link
* @returns {WanStatus|null} Status information about the currnet WAN link or null
*/
async getWanStatus() {
const r = await this.get('wanlink()');
if (r === null) {
return null;
}
const status = {};
for (const line of r.split('\n')) {
if (!line.includes('return ') || !line.includes('wanlink_')) {
continue;
}
const key = line.split('(')[0].split('_')[1];
const value = line.split(' ')[4].split(';')[0].replaceAll('\'', '');
status[key] = Number(value) ? Number(value) : value;
}
return status;
}
/**
* Checks if the WAN link is connected
* @returns {boolean|null} Whether the WAN link is connected or null
*/
async isWanOnline() {
const r = await this.get('wanlink()');
if (r === null) {
return null;
}
return r.includes('wanlink_status() { return 1;}');
}
// TODO: Add a custom type for this, I haven't yet because I'm lazy and it's large
/**
* Gets the routers current settings
* @returns {Settings} The router settings
*/
async getSettings() {
const rawSettings = ['time_zone', 'time_zone_dst', 'time_zone_x', 'time_zone_dstoff', 'time_zone', 'ntp_server0', 'acs_dfs', 'productid', 'apps_sq', 'lan_hwaddr', 'lan_ipaddr', 'lan_proto', 'x_Setting', 'label_mac', 'lan_netmask', 'lan_gateway', 'http_enable', 'https_lanport', 'wl0_country_code', 'wl1_country_code'];
const settings = {};
for (const setting of rawSettings) {
const r = await this.get(`nvram_get(${setting})`);
if (r === null) {
continue;
}
settings[setting] = JSON.parse(r)[setting];
}
return settings;
}
/**
* Gets the IP address of the router
* @returns The IP address of the router
*/
async getLanIPAddress() {
const r = await this.get('nvram(lan_ipaddr)');
if (r === null) {
return null;
}
return JSON.parse(r).lan_ipaddr;
}
/**
* Gets the netmask of the router
* @returns {string|null} Router netmask or null
*/
async getLanNetmask() {
const r = await this.get('nvram(lan_netmask)');
if (r === null) {
return null;
}
return JSON.parse(r).lan_netmask;
}
/**
* Gets the ip address of the gateway for the LAN network
* @returns {string|null} IP address of the gateway
*/
async getLanGateway() {
const r = await this.get('nvram(lan_gateway)');
if (r === null) {
return null;
}
return JSON.parse(r).lan_gateway;
}
/**
* Gets a list of DHCP leases
* @returns {DHCPEntry[]|null} List of DHCP entries or null
*/
async getDHCPList() {
const r = await this.get('dhcpLeaseMacList()');
if (r === null) {
return null;
}
const list = [];
for (const entry of JSON.parse(r).dhcpLeaseMacList) {
list.push({
mac: entry[0],
name: decodeURIComponent(entry[1])
});
}
return list;
}
/**
* Gets info on all currently online clients
* @returns {ClientInfo[]|null} Client info on all online clients or null
*/
async getOnlineClients() {
const clients = await this.getClientsFullInfo();
if (clients === null) {
return null;
}
const list = [];
for (const client of clients.clientList) {
if (!client.isOnline) {
continue;
}
list.push(client);
}
return list;
}
/**
* Gets info on a single client
* @param clientMac MAC address of the requested client
* @returns {ClientInfo|null} The client info or null
*/
async getClientInfo(clientMac) {
const clients = await this.getClientsFullInfo();
if (clients === null) {
return null;
}
return clients.clientList.filter((x => x.mac === clientMac))[0] || null;
}
}
exports.RouterInfo = RouterInfo;
;