New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

fritzdect-aha-nodejs

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fritzdect-aha-nodejs - npm Package Compare versions

Comparing version

to
1.0.0

example.js

5

index.js

@@ -1,4 +0,1 @@

import Fritz from './lib/fritz_ahaapi.js';
import FritzEmu from './lib/fritz_mockserver.js';
export { Fritz, FritzEmu };
module.exports = { Fritz: require('./lib/fritz_ahaapi.js'), FritzEmu: require('./lib/fritz_mockserver.js') };

123

lib/fritz_ahaapi.js

@@ -17,9 +17,9 @@ /**

* first version 19.12.2020
* part of fritzdect-aha-nodejs 16.11.2022 as ES module
*
*/
import { pbkdf2Sync, createHash } from 'crypto';
import http from 'http';
import https from 'http';
//import crypto from 'crypto';
const crypto = require('crypto');
const LOGIN_SID_ROUTE = '/login_sid.lua?version=2';

@@ -314,2 +314,11 @@ const SMARTHOME_ROUTE = '/webservices/homeautoswitch.lua?0=0';

}
// getswitchpower
async getSwitchPower(ain) {
try {
const body = this.executeCommand2('getswitchpower', ain, 1);
return Promise.resolve(body);
} catch (error) {
return Promise.reject(error);
}
}
// getswitchenergy

@@ -466,3 +475,3 @@ async getSwitchEnergy(ain) {

if (box_url) {
let httpprot = null;
let http = null;
let defaultport = null;

@@ -475,7 +484,7 @@ const req_url = new URL(box_url);

if (protocol == 'http:') {
httpprot = http; // vom import
http = require('http');
defaultport = 80;
if (this.debug) console.log('using http');
} else if (protocol == 'https:') {
httpprot = https; // vom import
http = require('https');
defaultport = 443;

@@ -500,3 +509,3 @@ //http.globalAgent.options.secureProtocol = 'SSLv3_method';

let p = new Promise((resolve, reject) => {
const req = httpprot.request(options, (res) => {
const req = http.request(options, (res) => {
res.setEncoding('utf8');

@@ -570,5 +579,5 @@ if (res.statusCode !== 200) {

// py hash1 = hashlib.pbkdf2_hmac("sha256", password.encode(), salt1, iter1)
const hash1 = pbkdf2Sync(password, salt1, iter1, 32, 'sha256');
const hash1 = crypto.pbkdf2Sync(password, salt1, iter1, 32, 'sha256');
// py hash2 = hashlib.pbkdf2_hmac("sha256", hash1, salt2, iter2)
const hash2 = pbkdf2Sync(hash1, salt2, iter2, 32, 'sha256');
const hash2 = crypto.pbkdf2Sync(hash1, salt2, iter2, 32, 'sha256');
// response salt2 + hash2

@@ -587,3 +596,6 @@ return challenge_parts[4] + '$' + hash2.toString('hex');

// the legacy response needs utf_16_le encoding
const md5_sum = createHash('md5').update(Buffer.from(challenge + '-' + password, 'utf16le')).digest('hex');
const md5_sum = crypto
.createHash('md5')
.update(Buffer.from(challenge + '-' + password, 'utf16le'))
.digest('hex');
const response = challenge + '-' + md5_sum;

@@ -602,3 +614,3 @@ return response;

if (box_url && username && challenge_response) {
let httpprot = null;
let http = null;
let defaultport = null;

@@ -611,7 +623,7 @@ const req_url = new URL(box_url);

if (protocol == 'http:') {
httpprot = http; //vom import
http = require('http');
defaultport = 80;
if (this.debug) console.log('using http');
} else if (protocol == 'https:') {
httpprot = https; // vom import
http = require('https');
defaultport = 443;

@@ -640,3 +652,3 @@ //http.globalAgent.options.secureProtocol = 'SSLv3_method';

let p = new Promise((resolve, reject) => {
const req = httpprot.request(options, (res) => {
const req = http.request(options, (res) => {
res.setEncoding('utf8');

@@ -715,3 +727,3 @@ if (res.statusCode !== 200) {

if (sid) path += 'sid=' + sid;
if (sid) path += '&sid=' + sid;
if (command) path += '&logout=' + command;

@@ -781,3 +793,3 @@ // console.log('valid SID ' + path);

if (box_url && path) {
let httpprot = null;
let http = null;
let defaultport = null;

@@ -790,7 +802,7 @@ const req_url = new URL(box_url);

if (protocol == 'http:') {
httpprot = http; //vom import
http = require('http');
defaultport = 80;
if (this.debug) console.log('using http');
} else if (protocol == 'https:') {
httpprot = https; // vom import
http = require('https');
defaultport = 443;

@@ -815,3 +827,3 @@ //http.globalAgent.options.secureProtocol = 'SSLv3_method';

let p = new Promise((resolve, reject) => {
const req = httpprot.request(options, (res) => {
const req = http.request(options, (res) => {
res.setEncoding('utf8');

@@ -888,3 +900,3 @@ if (res.statusCode !== 200) {

return Promise.reject({
msg: 'error calling executeCommand',
msg: 'error calling executeCommand, could not check SID',
function: 'check_SID',

@@ -1029,69 +1041,2 @@ error: sessionID

export default Fritz;
//--------------- sample code ----------------
/*
const Fritz = require('../fritzhttp.js');
var fritz = new Fritz('admin', 'password', 'http://localhost.3333');
async function test() {
const login = await fritz.login_SID().catch((e) => {
console.log('fault calling login() ', e);
});
console.log('login', login);
if (login) {
await fritz
.getDeviceListInfos()
.then(function(response) {
console.log('Devices' + response);
})
.catch((e) => {
console.log('Fehler Devicelist ', e);
});
await fritz
.getUserPermissions()
.then(function(response) {
console.log('Rights : ' + response);
})
.catch((e) => {
console.log('Fehler getUserPermissions', e);
});
await fritz
.check_SID()
.then(function(response) {
console.log('Checkresponse : ' + response);
})
.catch((e) => {
console.log('Fehler checkSID', e);
});
await fritz
.logout_SID()
.then(function(response) {
console.log('logout : ' + response);
})
.catch((e) => {
console.log('Fehler logout_SID', e);
});
}
//with relogin
await fritz
.getDeviceListInfos()
.then(function(response) {
console.log('Devices' + response);
})
.catch((e) => {
console.log('Fehler Devicelist ', e);
});
await fritz
.logout_SID()
.then(function(response) {
console.log('logout : ' + response);
})
.catch((e) => {
console.log('Fehler logout_SID', e);
});
}
test();
*/
module.exports = Fritz;
// @ts-nocheck
//server to emulate the fritzbox responses
import { createServer } from 'http';
import { readFileSync } from 'fs';
import { parse } from 'querystring';
import { xml2json } from 'xml2json-light';
import figlet from 'figlet';
import chalk from 'chalk';
const http = require('http');
const fs = require('fs');
const { parse } = require('querystring');
const parser = require('xml2json-light');
const figlet = require('figlet');
const chalk = require('chalk');
const crypto = require('crypto');
import { pbkdf2Sync, createHash } from 'crypto';
const path = require('path');
console.log('PATH ist ' + path.join(__dirname, './data/'));
import { join } from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log('PATH ist ' + join(__dirname, './data/'));
const xmlDevicesGroups = readFileSync(join(__dirname, './data/') + 'test_api_response.xml');
const xmlDevicesGroups = fs.readFileSync(path.join(__dirname, './data/') + 'test_api_response.xml');
//var xmlDevicesGroups = fs.readFileSync('./test.xml');
const xmlTemplate = fs.readFileSync(path.join(__dirname, './data/') + 'template_answer.xml');
const xmlTempStat = fs.readFileSync(path.join(__dirname, './data/') + 'devicestat_temp_answer.xml');
const xmlPowerStats = fs.readFileSync(path.join(__dirname, './data/') + 'devicestat_power_answer.xml');
const xmlColorDefaults = fs.readFileSync(path.join(__dirname, './data/') + 'color_defaults.xml');
const hkr_batt = fs.readFileSync(path.join(__dirname, './data/') + 'hkr_response.xml');
const guestWlan = fs.readFileSync(path.join(__dirname, './data/') + 'guest_wlan_form.xml');
const xmlTemplate = readFileSync(join(__dirname, './data/') + 'template_answer.xml');
const xmlTempStat = readFileSync(join(__dirname, './data/') + 'devicestat_temp_answer.xml');
const xmlPowerStats = readFileSync(join(__dirname, './data/') + 'devicestat_power_answer.xml');
const xmlColorDefaults = readFileSync(join(__dirname, './data/') + 'color_defaults.xml');
const hkr_batt = readFileSync(join(__dirname, './data/') + 'hkr_response.xml');
const guestWlan = readFileSync(join(__dirname, './data/') + 'guest_wlan_form.xml');
let server;
//hashing stuff
const challenge = (4294967295 + Math.floor(Math.random() * 4294967295)).toString(16).slice(-8);

@@ -42,3 +28,3 @@ const challenge2 = (4294967295 + Math.floor(Math.random() * 4294967295)).toString(16).slice(-8);

const challengeResponse =
challenge + '-' + createHash('md5').update(Buffer.from(challenge + '-' + password, 'utf16le')).digest('hex');
challenge + '-' + crypto.createHash('md5').update(Buffer.from(challenge + '-' + password, 'utf16le')).digest('hex');
const mocksid =

@@ -48,3 +34,4 @@ (4294967295 + Math.floor(Math.random() * 4294967295)).toString(16).slice(-8) +

const devices2json = xml2json(String(xmlDevicesGroups));
//Devices and Groups derved from xmlDevicesGroups
const devices2json = parser.xml2json(String(xmlDevicesGroups));
let devices = [].concat((devices2json.devicelist || {}).device || []).map((device) => {

@@ -60,3 +47,4 @@ // remove spaces in AINs

});
const templates2json = xml2json(String(xmlTemplate));
//Templates derived from xmlTemplate
const templates2json = parser.xml2json(String(xmlTemplate));
let templates = [].concat((templates2json.templatelist || {}).template || []).map(function(template) {

@@ -67,9 +55,12 @@ // remove spaces in AINs

});
let result = templates;
//apiresponse is the xml file with AINs not having the spaces inside
//used in the response
var apiresponse = {};
apiresponse['devicelist'] = { version: '1', device: devices, group: groups };
apiresponse['templatelist'] = { version: '1', template: templates };
console.log(apiresponse);
//console.log(apiresponse);
// Functions for reply on the requests
function loginoutAnswerV2(response, sid, method, username, userresponse, request) {

@@ -187,24 +178,4 @@ if (!sid && method == 'GET') {

function findAin(type, ain) {
let position = null;
if (type === 'device') {
for (let i = 0; i < apiresponse['devicelist']['device'].length; i++) {
if (apiresponse['devicelist']['device'][i].identifier === ain) {
position = i;
break;
}
}
} else if (type === 'group') {
for (let i = 0; i < apiresponse['devicelist']['device'].length; i++) {
if (apiresponse['devicelist']['device'][i].identifier === ain) {
position = i;
break;
}
}
}
return position;
}
function errorAnswer(response) {
response.statusCode = 403;
function errorAnswer(response, code) {
response.statusCode = code;
response.end();

@@ -245,3 +216,3 @@ return response;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -269,3 +240,3 @@ return response;

console.log(' did not find the ain in templates ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -286,3 +257,3 @@ return response;

response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify(switchlist));
response.write(String(switchlist));
response.end();

@@ -301,3 +272,3 @@ return response;

if (setswitchstate) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
if ((switchcmd = 'setswitchon')) {

@@ -320,3 +291,3 @@ apiresponse.devicelist.device[pos].switch.state = 1;

} else if (setgroupstate) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
if ((switchcmd = 'setswitchon')) {

@@ -340,3 +311,3 @@ apiresponse.devicelist.group[pos].switch.state = 0;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -354,11 +325,11 @@ return response;

response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + gettemp + "'" ]));
response.write(String(gettemp));
response.end();
} else if (getgrouptemp) {
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + getgrouptemp + "'" ]));
response.write(String(getgrouptemp));
response.end();
} else {
console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -386,3 +357,3 @@ return response;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -408,3 +379,3 @@ return response;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -422,13 +393,16 @@ return response;

.map((group) => group.powermeter[item2]);
if (getswitchmeter) {
if (getswitchmeter.length > 0) {
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + getswitchmeter + "'" ]));
//response.write(JSON.stringify([ "'" + getswitchmeter + "'" ]));
response.write(String(getswitchmeter));
response.end();
} else if (getgroupmeter) {
} else if (getgroupmeter.length > 0) {
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + getgroupmeter + "'" ]));
//response.write(JSON.stringify([ "'" + getgroupmeter + "'" ]));
response.write(String(getgroupmeter));
response.end();
} else {
console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
//verursacht StatusCode400
response = errorAnswer(response, 400);
}

@@ -450,11 +424,11 @@ return response;

response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + gethkrtemp + "'" ]));
response.write(String(gethkrtemp));
response.end();
} else if (getgrouphkrtemp) {
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + getgrouphkrtemp + "'" ]));
response.write(String(getgrouphkrtemp));
response.end();
} else {
console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -472,3 +446,3 @@ return response;

if (sethkrtemp) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].hkr.tsoll = param;

@@ -478,3 +452,3 @@ response.statusCode = 200;

} else if (setgrouphkrtemp) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].hkr.tsoll = param;

@@ -485,3 +459,3 @@ response.statusCode = 200;

console.log('-> did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -513,3 +487,2 @@ return response;

response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(String(xmlTempStat));
response.write(String(xmlPowerStats));

@@ -519,3 +492,3 @@ response.end();

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -541,3 +514,3 @@ return response;

}
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].simpleonoff.state = newstate;

@@ -553,3 +526,3 @@ response.statusCode = 200;

}
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].simpleonoff.state = newstate;

@@ -573,3 +546,3 @@ response.statusCode = 200;

if (levelvalue) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].levelcontrol.level = level;

@@ -580,3 +553,3 @@ apiresponse.devicelist.device[pos].levelcontrol.levelpercentage = Math.floor(Number(level) / 255 * 100);

} else if (grouplevel) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].levelcontrol.level = level;

@@ -601,3 +574,3 @@ apiresponse.devicelist.device[pos].levelcontrol.levelpercentage = Math.floor(Number(level) / 255 * 100);

if (levelvalueperc) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].levelcontrol.level = Math.floor(Number(level) / 100 * 255);

@@ -608,3 +581,3 @@ apiresponse.devicelist.device[pos].levelcontrol.levelpercentage = level;

} else if (grouplevelperc) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].levelcontrol.level = Math.floor(Number(level) / 100 * 255);

@@ -616,3 +589,3 @@ apiresponse.devicelist.device[pos].levelcontrol.levelpercentage = level;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -634,3 +607,3 @@ return response;

if (colorvalue) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].colorcontrol[cmd] = newvalue;

@@ -640,3 +613,3 @@ response.statusCode = 200;

} else if (groupcolor) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].colorcontrol[cmd] = newvalue;

@@ -647,3 +620,3 @@ response.statusCode = 200;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -661,3 +634,3 @@ return response;

if (settempvalue) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].colorcontrol.temperature = temperature;

@@ -667,3 +640,3 @@ response.statusCode = 200;

} else if (setgrouptemp) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].colorcontrol.temperature = temperature;

@@ -674,3 +647,3 @@ response.statusCode = 200;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -698,16 +671,16 @@ return response;

if (hkrboost) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].hkr.boostactiveendtime = endtimestamp;
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + endtimestamp + "'" ]));
response.write(String(endtimestamp));
response.end();
} else if (groupboost) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].hkr.boostactiveendtime = endtimestamp;
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + endtimestamp + "'" ]));
response.write(String(endtimestamp));
response.end();
} else {
console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -728,16 +701,16 @@ return response;

if (hkrwindow) {
const pos = this.findAin('device', ain);
const pos = findAin('device', ain);
apiresponse.devicelist.device[pos].hkr.windowopenactiveendtime = endtimestamp;
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + endtimestamp + "'" ]));
response.write(String(endtimestamp));
response.end();
} else if (groupwindow) {
const pos = this.findAin('group', ain);
const pos = findAin('group', ain);
apiresponse.devicelist.group[pos].hkr.windowopenactiveendtime = endtimestamp;
response.writeHead(200, { 'xmlDevicesGroups-Type': 'application/json' });
response.write(JSON.stringify([ "'" + endtimestamp + "'" ]));
response.write(String(endtimestamp));
response.end();
} else {
console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -762,3 +735,3 @@ return response;

console.log(' did not find the ain in devices/groups ' + ain);
response = errorAnswer(response);
response = errorAnswer(response, 400);
}

@@ -778,3 +751,3 @@ return response;

console.log('switchcmd no case found ' + switchcmd);
response = errorAnswer(response);
response = errorAnswer(response, 400);
return response;

@@ -784,2 +757,25 @@ break;

}
// helper function
function findAin(type, ain) {
let position = null;
if (type === 'device') {
for (let i = 0; i < apiresponse['devicelist']['device'].length; i++) {
if (apiresponse['devicelist']['device'][i].identifier === ain) {
position = i;
break;
}
}
} else if (type === 'group') {
for (let i = 0; i < apiresponse['devicelist']['device'].length; i++) {
if (apiresponse['devicelist']['device'][i].identifier === ain) {
position = i;
break;
}
}
}
return position;
}
// the emulation class
let server;
class FritzEmu {

@@ -807,3 +803,3 @@ constructor(testfile, port, debugmode) {

//Create a server
server = createServer(this.handleHttpRequest);
server = http.createServer(this.handleHttpRequest);
//Lets start our server

@@ -857,3 +853,3 @@ server.listen(3333, function() {

ain = commandsplit[1];
console.log('ain : ', commandsplit[1]);
console.log('-> ain : ', commandsplit[1]);
break;

@@ -996,5 +992,4 @@ case 'ain':

}
//setupHttpServer(function() {});
export default FritzEmu;
module.exports = FritzEmu;

@@ -1001,0 +996,0 @@ // ausprobieren bei echter FB ob getswitchname, getswitchpresent, gettemperature auch auf thermostat geht

{
"name": "fritzdect-aha-nodejs",
"version": "0.9.1",
"version": "1.0.0",
"description": "NodeJS library using the AHA api of Fritzbox to control DECT smarthome devices.",
"main": "index.js",
"type": "module",
"dependencies": {
"chalk": "^4.1.2",
"figlet": "^1.5.2",
"xml2json-light": "^1.0.6",
"command-line-args": "^5.2.0",
"command-line-usage": "^6.1.1"
},
"devDependencies": {
"chai": "^4.3.5",
"chalk": "^4.1.2",
"eslint": "^8.26.0",
"figlet": "^1.5.2",
"mocha": "^10.1.0",
"xml2json-light": "^1.0.6"
"mocha": "^10.1.0"
},

@@ -15,0 +18,0 @@ "scripts": {

@@ -14,7 +14,8 @@ # fritzdect-aha-nodejs

* control configured templates
* uses new session ID method (FW >7.25), as well as the fallback to md5 method as a fallback
* no production dependencies
* uses new session ID method (FW >7.25), as well as the fallback to md5 method
* no production dependencies for the API itself (the dependencies are only related to the testscript and emulation)
## Getting Started
it is an ES module with named exports
it is an common js module with named exports.
it exposes 2 classes, the API (Fritz) and an emulation (FritzEmu)

@@ -31,7 +32,26 @@ ### Prerequisites

### Usage
```javascript
const Fritz = require('fritzdect-aha-nodejs').Fritz;
fritz = new Fritz(yourUsername, yourPassword, your.Url || '', your.options || {});
//your async function
...
const login = await fritz.login_SID();
const devicelistinfos = await fritz.getDeviceListInfos();
const logout = await fritz.logout_SID();
...
```
see the example.js.
## API Calls
* todo for 1.0.1
## Changelog
### **WORK IN PROGRESS**
* 0.9.1 (foxthefox) first release on npm
* 0.0.1 (foxthefox) initial release
### 1.0.0
* (foxthefox) common js module with 2 named exports Fritz and FritzEmu
### 0.9.1
* (foxthefox) first release on npm as ESM
## License

@@ -38,0 +58,0 @@ Copyright (c) 2022 foxthefox <foxthefox@wysiwis.net>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet