Created
May 17, 2020 12:22
-
-
Save Garfonso/9b5bbc0ade86ad82185edf3208c72017 to your computer and use it in GitHub Desktop.
Manipulate FritzBox 6490 (and maybe other) hosts lists.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//manipulate FritzBox Hosts list using data.lua! | |
'use strict'; | |
const axios = require('axios').default; | |
const crypto = require('crypto'); | |
function buildUrl(host, path) { | |
return 'http://' + host + path; | |
} | |
class FirtzBoxLibDataLua { | |
/** | |
* Constructor | |
* @param {Object} options | |
* @param {string} options.username | |
* @param {string} options.password | |
* @param {string} [options.host] defaults to 'fritz.box' | |
* @param {boolean} [options.debug] | |
*/ | |
constructor(options) { | |
this.username = options.username; | |
this.password = options.password; | |
this.host = options.host || 'fritz.box'; | |
this.debug = options.debug || false; | |
this.sessionId = ''; | |
} | |
log(...parameters) { | |
console.log.apply(console, parameters); | |
} | |
logDebug(...parameters) { | |
if(this.debug) { | |
console.log.apply(console, parameters); | |
} | |
} | |
/** | |
* Login to fritzbox. | |
* @returns {Promise<boolean>} | |
*/ | |
async login() { | |
let result = await axios.get(buildUrl(this.host, '/login_sid.lua')); | |
//this.logDebug('Login first result: ', result); | |
const challenge = result.data.match('<Challenge>(.*?)</Challenge>')[1]; | |
this.logDebug('challenge:', challenge); | |
const hash = crypto.createHash('md5'); | |
hash.update(Buffer.from(challenge + '-' + this.password, 'utf16le')); | |
const challengeResponse = challenge + '-' + hash.digest('hex'); | |
const path = '/login_sid.lua?username=' + this.username + '&response=' + challengeResponse; | |
this.logDebug('Calling:', path); | |
result = await axios.get(buildUrl(this.host, path)); | |
//this.logDebug('Login second result: ', result); | |
this.sessionId = result.data.match('<SID>(.*?)</SID>')[1]; | |
if (this.sessionId === '0000000000000000') { | |
this.logDebug('Could not login:', result.data); | |
throw new Error('could not login: ' + result.data); | |
} else { | |
this.logDebug('Login success, sid:', this.sessionId); | |
return true; | |
} | |
} | |
/** | |
* Get all network devices from fritzBox | |
* @returns {Promise<Buffer|any[]|string>} | |
*/ | |
async getNetworkDevices() { | |
let data = 'xhr=1&sid=' + this.sessionId + '&lang=de&page=netDev&xhrId=all&no_sidrenew='; | |
let result = await axios.post(buildUrl(this.host, '/data.lua'), data); | |
return result.data.data.active.concat(result.data.data.passive); | |
} | |
/** | |
* update Device data | |
* @param {object} oldData device from FritzBox | |
* @param {{name: string, ip: string}} newData | |
* @returns {Promise<boolean|any|{errorText: any, status: number}>} | |
*/ | |
async updateDevice(oldData, newData) { | |
/*let data = 'dev_name=' + newData.name || oldData.name + | |
'&btn_reset_name=&dev_ip=' + newData.ip || oldData.ipv4 + '&static_dhcp=on&kisi_profile=filtprof1' + | |
'&back_to_page=%2Fnet%2Fnet_overview.lua&dev=' + oldData.UID + '&last_action=&validate=btn_save&xhr=1&useajax=1';*/ | |
//return axios.post(buildUrl(this.host, '/net/edit_device.lua?sid=' + this.sessionId), data); | |
let data = 'xhr=1&sid=' + this.sessionId + '&lang=de&no_sidrenew=&'; | |
if (newData.name) { | |
data += 'plc_desc=' + oldData.name + '&dev_name=' + newData.name; | |
} else { | |
data += 'dev_name=' + oldData.name; | |
} | |
if (newData.ip) { | |
data += '&dev_ip=' + newData.ip; | |
} else { | |
data += '&dev_ip=' + oldData.ipv4; | |
} | |
data += '&static_dhcp=on&kisi_profile='; | |
data += 'filtprof1&back_to_page=%2Fnet%2Fnet_overview.lua'; | |
data += '&dev=' + oldData.UID + '&last_action=&btn_save=&oldpage=%2Fnet%2Fedit_device.lua'; | |
let result = await axios.post(buildUrl(this.host, '/data.lua'), data); | |
if (typeof result.data === 'string') { | |
return {status: result.status, errorText: result.data.substring(0, result.data.indexOf('<script>')) || result.data}; | |
} else if (result.data.pid !== 'netDev') { | |
return result.data; | |
} else { | |
return true; | |
} | |
} | |
/** | |
* Delete device from FritzBox. This sometimes does not work or needs to repeated. Not sure why | |
* (But it does not always work in FB UI either... hm) | |
* @param oldData | |
* @returns {Promise<boolean|any|{errorText: any, status: number}>} | |
*/ | |
async deleteDevice(oldData) { | |
let data = 'xhr=1&Verbindung=on&IP-Adresse=on&MAC-Adresse=on&Eigenschaften=on&delete=' + oldData.UID + | |
'&deleteable=true&devname=' + oldData.name + | |
'&devtype=unknown&sid=' + this.sessionId + '&lang=de&page=netDev'; | |
await axios.post(buildUrl(this.host, '/data.lua'), data); | |
data += '&confirmed='; | |
let result = await axios.post(buildUrl(this.host, '/data.lua'), data); | |
//this.logDebug('Result:', result.status, 'msg:', result.data); | |
if (typeof result.data === 'string') { | |
return {status: result.status, errorText: result.data.substring(0, result.data.indexOf('<script>')) || result.data}; | |
} else if (result.data.pid !== 'netDev') { | |
return result.data; | |
} else { | |
return true; | |
} | |
} | |
/** | |
* | |
* @param {{name: string, ip: string, mac: string}} newData | |
* @returns {Promise<boolean|any|{errorText: any, status: number}>} | |
*/ | |
async createDevice(newData) { | |
const macParts = newData.mac.split(':'); | |
const ipParts = newData.ip.split('.'); | |
let data = 'xhr=1&sid=' + this.sessionId; | |
data += '&lang=de&no_sidrenew=&name=' + newData.name; | |
for (let i = 0; i < 6; i += 1) { | |
data += '&mac' + i + '=' + macParts[i]; | |
} | |
for (let i = 0; i < 4; i += 1) { | |
data += '&ip' + i + '=' + ipParts[i]; | |
} | |
data += '&back_to_page=%2Fnet%2Fnet_overview.lua&apply=&oldpage=%2Fnet%2Fnewdevice.lua'; | |
const result = await axios.post(buildUrl(this.host, '/data.lua'), data); | |
if (typeof result.data === 'string') { | |
return {status: result.status, errorText: result.data.substring(0, result.data.indexOf('<script>')) || result.data}; | |
} else if (result.data.pid !== 'netDev') { | |
return result.data; | |
} else { | |
return true; | |
} | |
} | |
} | |
module.exports = FirtzBoxLibDataLua; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Use like this: