Possible way to access router api?

Hi there, hope you guys are doing fine. I am trying to access my LTE modem from node-red, I used the HTTP request node with the basic authentication method but in return, I got an error 125002 which means wrong session


image

image
this image is from the main.js script from my home router I have downloaded it has all the functions and commands I need.
I can access http://192.168.*.*/api/monitoring/traffic-statistics/r/nConnection
image

from my chrome browser, this API provides everything u need. I need a valid session token for accessing this API, as far I understand I need to provide the password in base64 for a successful login, is there any way to achieve this in node-red. I have uploaded the main.js file to GitHub, the login functions start at line 4947. main.js

hello .. if the question is about converting the password to base64 then nodejs provides some methods to achieve this in a Function node.

Example:

let password = "Hello World"

msg.payload = Buffer.from(password).toString('base64')

return msg;

Test Flow:

[{"id":"33eef32a2ab48099","type":"function","z":"54efb553244c241f","name":"base64","func":"\nlet password = \"Hello World\"\n\nmsg.payload = Buffer.from(password).toString('base64')\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":960,"wires":[["f47e1d154a28919b"]]},{"id":"8797293b78340b51","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":960,"wires":[["33eef32a2ab48099"]]},{"id":"f47e1d154a28919b","type":"debug","z":"54efb553244c241f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":610,"y":960,"wires":[]}]

ps. Regarding how you pass that to the http request headers .. you have to provide some more information or documentation of your modems API.

Can you have a look at main.js file i have attack with the post, it contains everything about login functions.

What is the brand and model of your LTE modem .. doesnt it have documentation online of how to access its API ? ... instead of trying to decipher a 6000 line javascript file ? :wink:

yeah, there is some GitHub repo huawei-lte-api that contains complete documentation on Huawei LTE API, mostly written in python. the device I am using is not supported yet. it should be fairly easy to access device API with HTTP post request, including user name and password encoded in base64.

 http://192.168.1.1/api/user/login\
 --data "<?xml version=""1.0"" encoding=""UTF-8""?><request>\
<Username>admin</Username>\
<Password>password in base-64</Password>
<password_type>4</password_type>
</request>" --compressed

<?xml version="1.0" encoding="UTF-8"?><response>OK</response>

this is how I am supposed to make an HTTP post request and I can't figure it out yet. this will authenticate me to the device from then I will be able to make further requests to access API

instead of python .. there is also this Nodejs module by the same developer

Maybe in a Function node, using the functionExternalModules option load the huawei-lte-api library and see how it goes.

You can read more about functionExternalModules here

actually there is node-red Node provides same functionality but unfortunately my router is not supported and it returns the same error that I described above .

is there anyway to send http request in node -red i described above ?

If you run this do you get a reply from the modem ?
(replace the password)

[{"id":"6e215f49.aadfe","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1020,"wires":[["e74c77e60cdab6d1"]]},{"id":"2bd2ae1f.24ec22","type":"http request","z":"54efb553244c241f","name":"","method":"POST","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.1/api/user/login","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":550,"y":1020,"wires":[["41fb1ba0.9393f4"]]},{"id":"41fb1ba0.9393f4","type":"debug","z":"54efb553244c241f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":710,"y":1020,"wires":[]},{"id":"e74c77e60cdab6d1","type":"function","z":"54efb553244c241f","name":"request","func":"let password = \"your password\"  // replace\n\nlet base64pass = Buffer.from(password).toString('base64')\n\nmsg.payload = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<request>\n<Username>admin</Username>\n<Password>${base64pass}</Password>\n<password_type>4</password_type>\n</request>`\n\n\nmsg.headers = { \"Content-Type\": \"text/xml\"}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":1020,"wires":[["2bd2ae1f.24ec22","b2bb1968cea6f9f2"]]},{"id":"b2bb1968cea6f9f2","type":"debug","z":"54efb553244c241f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":430,"y":940,"wires":[]}]

Another thing to try is also open your browsers Developer tools, to the network tab, and follow the authentication requests to see what request headers and body is being sent when you login from the browser in order to try to replicate that.

<?xml version="1.0" encoding="UTF-8"?>
<error>
<code>125002</code>
<message></message>
</error>

this is response I get in debug window.

Could not find in chrom but here is wireshark packet dump of login request:

POST /api/user/login HTTP/1.1
Host: 192.168.1.1
Connection: keep-alive
Content-Length: 224
Accept: */*
DNT: 1
X-Requested-With: XMLHttpRequest
__RequestVerificationToken: uqXDO3yhXUfWACBFj30MY1nbJABZZ9WV
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.1.1
Referer: http://192.168.1.1/html/home.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: SessionID=+S+E2lI3r7jLaiixz5Y9zyZncEpuey9P9U+14rl1zt6KGzu0544QoOO/TxsltiRU5PpUc5YPJrMsKkmO/z09jn0syLZv1VXLRsHulQmCIJbKI48AetePP3f9eTa3v8Mw

<?xml version="1.0" encoding="UTF-8"?><request><Username>admin</Username><Password>ZmUxNzJlY2RiNjU3OWI2ZWE5ODQ5Y2UwN2FmM2NlNzIyNDEyNzhjODQ2Y2ViZWVhMjI1MzFmYzZlNTBiZTgwMw==</Password><password_type>4</password_type></request>HTTP/1.1 200 OK
Date: Thu, 01 Jan 1970 00:00:00 GMT
Server: WebServer
Connection: close
X-Download-Options: noopen
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubdomains
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: text/html
Content-Length: 61
__RequestVerificationTokenone:EIvo+wIeK5BxqMXZ4SB5ORlSfQcsOIiB
__RequestVerificationTokentwo:V6B+RW/lKFzlqcdra75rl8kq9miO4Rri
__RequestVerificationToken:EIvo+wIeK5BxqMXZ4SB5ORlSfQcsOIiB#V6B+RW/lKFzlqcdra75rl8kq9miO4Rri#BgiuY9qIWQdc/2Kd7J6cjbq4Sz8U1w/C#iRFU0TJgPGA4LetXo2XqvP8QjwUuHQp3#DtIm2vuhJtSeGIWiZNo5Y2wYcCVxk2Dh#e6OKio5wKsjMnal+a15l82G0RkYJkRvh#So1rTyT6ReRi/mCph0g1NDv8Ha07YTXf#YnUE5sFBS2h2HHWJrGszXAuB1Q8WkZl8#JH8qO03csRhDqwb6hEzzyF8So/2Bb1eq#o1+1i2sWIpEc1TRkYN7gJF1vIVxCtmpm#hZK2TZuHikvDaOLZmZkWWe/KtuA91meh#j05rfgIX/dO8c38Jpjs6ZcS0gokl8D+d#vVFT8rlaWwWimFnpv62NffpU8Vy5up3y#AXaoGeDYuZKJg5ymMrE946vshhMIy41t#zmoOPny8yHOJWvnZGJNEXjPMCqnokaJ2#iY/SzOm5UK70egNeF7t5AGlKHCVGRpai#C7v0yLvcKUwIiYhk+06ycQ0NqZBkX21+#hIEBjexpgbslZbY1WqXiEaCtVxmCyZeg#dXKR8j4/2n3obarMqypttj5OZSdT31J5#Kd/d2A3pQc6uR4IKpfoJrGIOPIFxf4sx#3ahVvpq4E+FhXre0ROKx6zpeZR20yjFm#SGsei0PZQ7T8+lTvQ4BOe5SBBGbVRp8k#b2cChY7wOV/S2WZ/9Pwmy+Og+2M5BH5g#E+r97Ph/bvRAsUimJNDRU221qQJ22QuQ#kOj2ElRhJLT0V+Z3TowvqQgFUmYdTOZv#qUpq06zigQgehn887zK22AJXMG8WqyLU#+wqBczGUZlbsSe7l1LCLb1iViFD5BkAZ#hzjGrw/nAsKvp++Ct84NjClNYAXIHEl3#POuvZc0y4ubP7S4JyX1oWmBxPuyYCq3d#4dAQdk1CXyQrY57kwsQY8nXvbQOvnEF6#4WB6XMyRsuYUplALMkiW3MNy0x3mR790#CmMhSZZr49qh++BQCPWUPwHpD9ff8KB6#
Set-Cookie:SessionID=LBt42/Xj/vHoYsNyqNJjEe3AaFG2jwTGsVB0KtgjRPqICtIKIH68eOq9oPWc+YWAKwpkUO5po3J65W0t0Z5PcAcUqweRgc6mBGXOy6b9OhBSKQhCmF1Zo9gNQkRxyubI;path=/;HttpOnly;

<?xml version="1.0" encoding="UTF-8"?><response>OK</response>

I think the above is useful information ..
in order to get that __RequestVerificationToken
was there previously another GET request to http://192.168.1.1/api/webserver/SesTokInfo ??

here is a request made by the browser you described above it is not from the same session, I made this request manually by entering the URL in the browser.

GET /api/webserver/SesTokInfo HTTP/1.1
Host: 192.168.1.1
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: SessionID=Y3cNrpT9g0bFMhCGFs1ko+0KUHgDK6qf57AqhgKMciwWlLah4HF9eta5TbQP/yIbVNTrEu4ZrOL2lAZXpSwX2U3Zeh9CErfRx7awyNkrQKWtMrMwAtTj/5vu8WSimQax

HTTP/1.1 200 OK
Date: Thu, 01 Jan 1970 00:00:00 GMT
Server: WebServer
Connection: keep-alive
Keep-Alive: timeout=10, max=100
X-Download-Options: noopen
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubdomains
Cache-Control: no-cache
Content-Type: text/html
Content-Length: 277

<?xml version="1.0" encoding="UTF-8"?>
<response>
<SesInfo>SessionID=Y3cNrpT9g0bFMhCGFs1ko+0KUHgDK6qf57AqhgKMciwWlLah4HF9eta5TbQP/yIbVNTrEu4ZrOL2lAZXpSwX2U3Zeh9CErfRx7awyNkrQKWtMrMwAtTj/5vu8WSimQax</SesInfo>
<TokInfo>oj08Gj3Ch2VsJ74ILyaApyM6c99nezPg</TokInfo>
</response>

and here is the result from the browser.

<?xml version="1.0" encoding="UTF-8"?>
<response>
<SesInfo>SessionID=Y3cNrpT9g0bFMhCGFs1ko+0KUHgDK6qf57AqhgKMciwWlLah4HF9eta5TbQP/yIbVNTrEu4ZrOL2lAZXpSwX2U3Zeh9CErfRx7awyNkrQKWtMrMwAtTj/5vu8WSimQax</SesInfo>
<TokInfo>oj08Gj3Ch2VsJ74ILyaApyM6c99nezPg</TokInfo>
</response>

so possibly you need to chain two requests .. one Get request to get the Token and one POST to get the actual information.

Can you show us the msg that you get in Debug node 1 after you run this ?

[{"id":"6e215f49.aadfe","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1040,"wires":[["a40a61b15d00928d"]]},{"id":"2bd2ae1f.24ec22","type":"http request","z":"54efb553244c241f","name":"","method":"POST","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.1/api/user/login","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":970,"y":1040,"wires":[["41fb1ba0.9393f4"]]},{"id":"41fb1ba0.9393f4","type":"debug","z":"54efb553244c241f","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1110,"y":1040,"wires":[]},{"id":"e74c77e60cdab6d1","type":"function","z":"54efb553244c241f","name":"request","func":"let password = \"your password\"  // replace\n\nlet base64pass = Buffer.from(password).toString('base64')\n\nmsg.payload = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<request>\n<Username>admin</Username>\n<Password>${base64pass}</Password>\n<password_type>4</password_type>\n</request>`\n\n\nmsg.headers = {\n    \"Content-Type\": \"text/xml\",\n    \"X-Requested-With\": \"XMLHttpRequest\",\n    \"__RequestVerificationToken\": \"uqXDO3yhXUfWACBFj30MY1nbJABZZ9WV\"\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":800,"y":1040,"wires":[["2bd2ae1f.24ec22"]]},{"id":"b2bb1968cea6f9f2","type":"debug","z":"54efb553244c241f","name":"1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":960,"wires":[]},{"id":"a40a61b15d00928d","type":"http request","z":"54efb553244c241f","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.1/api/webserver/SesTokInfo","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":310,"y":1040,"wires":[["fd99a01ab6dfe1cf"]]},{"id":"fd99a01ab6dfe1cf","type":"xml","z":"54efb553244c241f","name":"","property":"payload","attr":"","chr":"","x":490,"y":1040,"wires":[["b2bb1968cea6f9f2"]]}]

I access my router - Netgear Nighthawk by running the below in a exec node.
You'll see that in the first part I save the token as id, then use it in the second part of the command to execute buttonType=2 which reboots my router.

id=$(wget -q -O- --http-user 'admin' --http-password 'routerPassword' http://192.168.1.1/ADVANCED_home2.htm | perl -lne '/id=([a-f0-9]+)/ && print $1'); wget -O- --http-user 'admin' --http-password 'routerPassword' http://192.168.1.1/newgui_adv_home.cgi?id=$id --post-data "id=$id&buttonType=2";

I can send 192.168.1.1/api/webserver/SesTokInfo with the HTTP request node and the modem replies with token info and session info.

Here is debug output.

{"_msgid":"8644f7f325613bf0","payload":{"response":{"SesInfo":["SessionID=Baugri5HVuQPwXlvFypdEdxZWIY4GAqvXjzIwMeV4+NNJQiCywAL8JPrJAYwfVPMOzq3Fqoto2WWeaMlBmjRt5Xr5B0v5MwGIRQbc7kAj8+UBb96Gsc6BsjLn88FzVOA"],"TokInfo":["5dN3AQFmhla4tblPoCCAolmhGgWNtwG1"]}},"topic":"","statusCode":200,"headers":{"date":"Thu, 01 Jan 1970 00:00:00 GMT","server":"WebServer","connection":"close","x-download-options":"noopen","x-frame-options":"deny","x-xss-protection":"1; mode=block","strict-transport-security":"max-age=31536000; includeSubdomains","cache-control":"no-cache","content-type":"text/html","content-length":"277","x-node-red-request-node":"40e13dfc"},"responseUrl":"http://192.168.1.1/api/webserver/SesTokInfo","redirectList":[],"retry":0}

With this do you get a reply on Debug 2 ?

We are wiring the Token and SessionID from the GET request and use it for the Login request

[{"id":"6e215f49.aadfe","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1040,"wires":[["a40a61b15d00928d"]]},{"id":"2bd2ae1f.24ec22","type":"http request","z":"54efb553244c241f","name":"","method":"POST","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.1/api/user/login","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":850,"y":1040,"wires":[["41fb1ba0.9393f4"]]},{"id":"41fb1ba0.9393f4","type":"debug","z":"54efb553244c241f","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1030,"y":1040,"wires":[]},{"id":"e74c77e60cdab6d1","type":"function","z":"54efb553244c241f","name":"request","func":"let password = \"your password\"  // replace\nlet token = msg.payload.response.TokInfo[0]  // token from XML\nlet sessionID = msg.payload.response.SesInfo[0]  // sessionID from XML\n\nlet base64pass = Buffer.from(password).toString('base64')\n\nmsg.payload = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<request>\n<Username>admin</Username>\n<Password>${base64pass}</Password>\n<password_type>4</password_type>\n</request>`\n\n\nmsg.headers = {\n    \"Content-Type\": \"application/x-www-form-urlencoded; charset=UTF-8\",\n    \"X-Requested-With\": \"XMLHttpRequest\",\n    \"__RequestVerificationToken\": token,\n    \"Cookie\" : sessionID\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":1040,"wires":[["2bd2ae1f.24ec22"]]},{"id":"b2bb1968cea6f9f2","type":"debug","z":"54efb553244c241f","name":"1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":960,"wires":[]},{"id":"a40a61b15d00928d","type":"http request","z":"54efb553244c241f","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.1/api/webserver/SesTokInfo","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":310,"y":1040,"wires":[["fd99a01ab6dfe1cf"]]},{"id":"fd99a01ab6dfe1cf","type":"xml","z":"54efb553244c241f","name":"","property":"payload","attr":"","chr":"","x":490,"y":1040,"wires":[["b2bb1968cea6f9f2","e74c77e60cdab6d1"]]}]

Here is debug output, return code 108006 means the wrong password, I have changed the password in the requesting node for sure.
image

Debug output.

<?xml version="1.0" encoding="UTF-8"?>
<error>
<code>108006</code>
<message></message>
</error>

a different error message ... hurray progress :grinning_face_with_smiling_eyes:

i dont know whats going on with that base64? password conversion but maybe you could replace it with what you have captured with wireshark

let base64pass = "ZmUxNzJlY2RiNjU3OWI2ZWE5ODQ5Y2UwN2FmM2NlNzIyNDEyNzhjODQ2Y2ViZWVhMjI1MzFmYzZlNTBiZTgwMw=="