Pull Arris SB8200 Cable Modem Status With Curl - authentication

Short Version:
I use Node-RED automation to manage network.
Via Node-RED I query the Arris SB8200 Cable Modem to get connection and event status hourly and store in a database.
A recent Comcast modem firmware update forces usage of user/pw on the modem to retrieve status.
I have been unable to successfully authenticate and retrieve status via cURL but can do so from a browser.
I have googled and tried a dozen different cURL authentication approaches without success. There are 3 complicating factors:
Username/password authentication. I am assuming this is just basic auth and shouldn't be an issue but see #2.
There is a session cookie "credential" that must be maintained across requests. This shouldn't be a problem but no matter what I try no cookies are captured in my specified cookies.txt file.
A manual login (to https://192.168.100.1/) is immediately followed by a redirect (to https://192.168.100.1/cmconnectionstatus.html). When I try to use the chrome dev tools "save as cURL" only the redirect is available, not the initial login so I cannot capture the login cURL.
I am hoping somebody who reads this has cURL'd into an SB8200 cable modem (or similar) with user/pw authentication and can just post the details. More likely will be many suggestions of things to try and some google result links, most of which I likely tried already. What would be most helpful to start I think is troubleshooting why I cannot get a successful login and the credential cookie set on my initial cURL.
BTW - The username and password are known to me, were set by me, and work fine to login from a browser. I think no matter how I have passed in the credentials I am just being returned the login form again. Maybe basic auth will never work and I need to do something else.
EDIT: I discovered the "Preserve Log" option in Chrome dev tools. This allowed me to copy as curl both the login and the redirect actions. And running the login curl (which does use basic auth) does return me on stdout a credential cookie. I was not able to get this cookie stored in my cookies.txt file using the cookie options in curl. And immediately using the returned cookie in the redirect curl does not get me the expected results and instead returns the login page. But I am getting closer.
Here is the Chrome-captured cURL for the login and redirect from the browser:
curl 'https://192.168.100.1/cmconnectionstatus.html?<REDACTED>' \
-H 'Connection: keep-alive' \
-H 'sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"' \
-H 'DNT: 1' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'Authorization: Basic <REDACTED>' \
-H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \
-H 'Accept: */*' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Accept-Language: en-US,en;q=0.9' \
-H 'Cookie: HttpOnly: true, Secure: true' \
--compressed \
--insecure
curl 'https://192.168.100.1/cmconnectionstatus.html' \
-H 'Connection: keep-alive' \
-H 'sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'DNT: 1' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36' \
-H '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' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Sec-Fetch-Mode: navigate' \
-H 'Sec-Fetch-User: ?1' \
-H 'Sec-Fetch-Dest: document' \
-H 'Accept-Language: en-US,en;q=0.9' \
-H 'Cookie: HttpOnly: true, Secure: true; credential=gmhyY4SjR3qiWBiNIOtivpj4TF5Zwad' \
--compressed \
--insecure
Here is the HTML document returned when I try to login:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<script src="jquery-1.7.1.min.js"></script>
<script src="json2.js"></script>
<script src="main_arris.js"></script>
<script src="jquery-2.0.3.min.js"></script>
<script>
$(document).ready(function(){
$("#htmlheader").load("htmlheader.htm");
});
</script>
</head>
<body>
<div id="htmlheader"></div>
<div class="header">
<script>
$(document).ready(function(){
$("#pageheaderA").load("pageheaderA.htm");
});
</script>
<div id="binnacleWrapper1" class="binnacleItems_hide" style="display:none;">
<div id="binnacleWrapper2" class="binnacleItems_hide" style="display:none;">
<div id="binnacleWrapperLeft"><img src="px1_Ux.png" alt="" class="binnacleWrapperShim"></div>
<div id="binnacleWrapperRight"><img src="px1_Ux.png" alt="" class="binnacleWrapperShim"></div>
<div id="binnacleWrapperMiddle">
<div id="binnacleInnards">
<div id="binnacleIndicatorWrap"></div>
<div id="binnacleModelName">
<span id="thisModelNumberIs">
<label id="model">SB8200</label></span></div>
</div>
</div>
</div>
</div>
<div id="pageheaderA"></div>
<div class="container">
<div class="subHeader">
<div class="subHeadcontent">Login</div>
</div>
<form action="">
<br>
<b>Username:</b><br>
<input type="text" id="username" onkeypress="return checkForActivate(event)">
<br>
<br>
<b>Password:</b><br>
<input type="password" id="password" onkeypress="return checkForActivate(event)">
<br>
<br>
<input type="button" id="loginButton" onclick="validate(this.form)" value="Login">
</form>
</div>
<div class="spacer40" style="text-align: center; color: red; font-weight: bold;"></div>
<div class="spacer70"></div>
</div>
<!--gap<div id="bmtg"><div class="gap1"><div class="gap2"><div class="gap3"><div class="gap4"></div></div></div></div></div>-->
<div id="fg1"><div id="fg2"><div id="fg3"><div id="fg4"><div id="fg5"><div id="fg6"><div id="fg7">
<div id="logo_bottom"><img src="px1_Ux.png" alt="ARRIS" title="ARRIS" class="logo_bottom"></div>
<div id="copyright">
©CommScope, Inc. All rights reserved. ARRIS, SURFBOARD and SURFBOARD MAX are trademarks of CommScope, Inc.<br />All other trademarks are the property of their respective owners.
</div>
</div></div></div></div></div></div></div>
<!--/div-->
<script>
function authenticateUser(user, password)
{
var token = user + ":" + password;
// Base64 Encoding -> btoa
var hash = btoa(token);
var auth = hash;
sessionStorage.setItem('auth', auth);
return auth;
}
function validate( form )
{
$(".spacer40")[0].innerHTML = "";
authenticateUser(form.username.value, form.password.value);
localStorage.setItem('username', form.username.value);
eraseCookie("credential");
$.ajax({
type: 'GET',
url:"/cmconnectionstatus.html?" + sessionStorage.getItem('auth'),
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
xhrFields: {
withCredentials: true
},
headers: {
'Authorization': 'Basic ' + sessionStorage.getItem('auth')
},
success: function (result) {
var token = result;
createCookie("credential", result);
window.location.href = "/cmconnectionstatus.html";
},
error: function (req, status, error) {
alert(error);
}
});
}
function checkForActivate( e )
{
if( e.keyCode == 13 )
{
document.getElementById("loginButton").click();
}
return true;
}
</script>
<!--/div-->
</body>
</html>

Solved it myself. Once I was able to save the login as curl in chrome, things fell in place. Looks like I was missing some required curl options in my initial attempts. I still need to skinny this down to the minimal necessary options, eliminate the double copy of user/pw chrome encoded, and add error checking. But the following will successfully login and pull modem status for an Arris SB8200. Never did get curl to store the credential cookie in a cookies.txt file so just used a local shell variable.
cookie=`curl 'https://192.168.100.1/cmconnectionstatus.html?<REDACTED>' -H 'Connection: keep-alive' -H 'sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"' -H 'DNT: 1' -H 'sec-ch-ua-mobile: ?0' -H 'Authorization: Basic <REDACTED>' -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' -H 'Accept: */*' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Dest: empty' -H 'Accept-Language: en-US,en;q=0.9' -H 'Cookie: HttpOnly: true, Secure: true' --compressed --insecure`
curl 'https://192.168.100.1/cmconnectionstatus.html' -H 'Connection: keep-alive' -H 'sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"' -H 'sec-ch-ua-mobile: ?0' -H 'Upgrade-Insecure-Requests: 1' -H 'DNT: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36' -H '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' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-User: ?1' -H 'Sec-Fetch-Dest: document' -H 'Accept-Language: en-US,en;q=0.9' -H 'Cookie: HttpOnly: true, Secure: true; credential='$cookie --compressed --insecure

Related

How can I send this curl as tcl/http instead?

I'm trying to trigger "play" -funtion with spotify API and tcl/http.
Here is the concept, in curl: https://developer.spotify.com/console/put-play/
curl -X "PUT" "https://api.spotify.com/v1/me/player/play" --data "{\"context_uri\":\"spotify:album:5ht7ItJgpBH7W6vJ5BqpPr\",\"offset\":{\"position\":5},\"position_ms\":0}" -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer "
Here's a working example with tcl using exec curl:
set url https://api.spotify.com/v1/me/player/play?device_id=$device_id
set data "{\"context_uri\":\"spotify:album:5ht7ItJgpBH7W6vJ5BqpPr\",\"offset\":{\"position\":5},\"position_ms\":0}"
if {[catch {
exec curl -X "PUT" "$url" --data $data -H "Accept: application/json" \
-H "Content-Type: application/json" -H "Authorization: Bearer $oauth"
} msg]} then {
puts $msg
}
But i'd like to do it with tcl/http, if it's possible.
Here is my best shot so far doing this with http, but it says "malformed json".
if {$incoming == ".play"} {
::http::register https 443 {::tls::socket -autoservername 1}
::http::config -urlencoding utf-8 -useragent {JSON curl/7.55. 1}
set spot_url [http::geturl https://api.spotify.com/v1/me/player/play? \
-method PUT \
-query {{device_id:"d70b1f06*MASKED*36c308",
"context_uri":"spotify:album:5ht7ItJgpBH7W6vJ5BqpPr","offset":{"position":5},"position_ms":0}} \
-headers [list Accept application/json Content-Type application/json Authorization "Bearer $::access_token"]]
set spot_temp [::http::data $spot_url]
::http::cleanup $spot_temp
::http::cleanup $spot_url
return $spot_temp
}
Any idea how to send it correct to avoid malformed json? :D
Thanks!

Error when testing Shopify checkout API with Stripe "Cannot complete the checkout without any transactions."

I am trying to complete a checkout with the /checkout API integrated with Stripe, following this documentation: https://shopify.dev/tutorials/complete-a-sales-channel-payment-with-checkout-api#integrate-stripe-wi...
I am getting this response on my final request:
Request:
curl --location --request POST 'https://<nameofmyshop>.myshopify.com/admin/api/2021-04/checkouts/<shopify-checkout-token>/complete.json' \
--header 'Content-Type: application/json' \
--header 'X-Shopify-Access-Token: <shpat_shopify-access-token>' \
--data-raw '{
"payment": {
"amount": "1.00",
"unique_token": "unique token I made",
"payment_token": {
"payment_data": "<tok_stripe-vault-token>",
"type": "stripe_vault_token"
},
"request_details": {
"ip_address": "123.1.1.1",
"accept_language": "en",
"user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.98 Safari\/537.36"
}
}
}'
(error) Response:
422 Unprocessable Entity
{
"errors": {
"base": [
{
"code": "missing_transactions",
"message": "Cannot complete the checkout without any transactions.",
"options": {}
}
]
}
}
Some details about my Shopify Shop, and Stripe setup:
I have Shopify Payments enabled
test mode is on
I successfully placed an order though the shop's website with CC# 4242 4242 4242 4242
I have a test Stripe Connect account for my "customer"
I can successfully get a Stripe token generated for the customer
Here is my flow:
create a checkout POST https://{{store_name}}.myshopify.com/admin/api/{{api_version}}/checkouts.json
Save checkout.token, and checkout.shopify_payments_account_id from the response
Get Stripe token for customer:
curl --location --request POST 'https://api.stripe.com/v1/tokens' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Stripe-Account: {{shopify_payments_account_id}}' \
--header 'Authorization: Bearer {{stripe-token}}' \
--data-urlencode 'customer=<cus_customers-stripe-connect-id>'
save id from response "id: <tok_stripe-vault-token>"
complete checkout with Stripe token (request above)
Should we be able to complete a checkout using Shopify /checkout API + Stripe-Connect Test Accounts?
Thank you for any help!
I was using the wrong endpoint:
final request should go to /payments.json, not /complete.json
url --location --request POST 'https://<nameofmyshop>.myshopify.com/admin/api/2021-04/checkouts/<shopify-checkout-token>/payments.json' \
--header 'Content-Type: application/json' \
--header 'X-Shopify-Access-Token: <shpat_shopify-access-token>' \
--data-raw '{
"payment": {
"amount": "1.00",
"unique_token": "unique token I made",
"payment_token": {
"payment_data": "<tok_stripe-vault-token>",
"type": "stripe_vault_token"
},
"request_details": {
"ip_address": "123.1.1.1",
"accept_language": "en",
"user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.98 Safari\/537.36"
}
}
}'

Segment.io HTTP API not collecting events

The documentation and help for this particular Segment.io is limited and sparse, so I hope it's OK to ask in here.
I have just set up a Segment.io workspace and a HTTP API source
Per the docs, I sent some POST requests (with Postman) to the https://api.segment.io/v1/track and https://api.segment.io/v1/page endpoints. The requests were structured like this:
curl -X POST \
https://api.segment.io/v1/track \
-H 'Accept: */*' \
-H 'Authorization: My4w3s0m3k3y' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Host: api.segment.io' \
-H 'Postman-Token: 474d7fbe-15af-43d2-b629-61e15945e662,2c3d5fbe-2c09-4fe6-b7ea-a04e3221201b' \
-H 'User-Agent: PostmanRuntime/7.11.0' \
-H 'accept-encoding: gzip, deflate' \
-H 'cache-control: no-cache' \
-H 'content-length: 117' \
-d '{
"userId": "abc123",
"event": "My tests",
"properties": {
"name": "test 1"
}
}'
which all returned a 200 response and the following message:
{
"success": true
}
However, when I got to my dashboard, no events have been recorded.
The debugger is also empty
What am I missing here?
It looks like your write key isn't base64 encoded. When you encode your write key, remember to add the : at the end of it, before it's encoded.
Also, for the Authorization key:value, be sure to add Basic before the encoded write key. So your Authorization key:value would look like:
Authorization: Basic {encoded write key}
An example from the segment documentation:
In practice that means taking a Segment source Write Key,'abc123', as the username, adding a colon, and then the password field is left empty. After base64 encoding 'abc123:' becomes 'YWJjMTIzOg=='; and this is passed in the authorization header like so: 'Authorization: Basic YWJjMTIzOg=='.
I have been dealing with the same issue.
I found the solution as Todd said.
You should add a header Authorization: Basic + base64 encoding write key.
So, you look for the Segment source setting and get the write key.
After that, i have used an online base64 encoding tool to encode my write key.
Finally, you should add this header (Authorization) with 'Basic' and the encoded write key.
You should be able to see the tracked event in the Debugging panel in Segment web page.
I hope this helps!
You can try this code
const { promisify } = require("util");
var Analytics = require("analytics-node");
var analytics = new Analytics("xxxxxxxxxxxxxxxxxxxxxxx", {
flushAt: 1,
});
const [identify, track] = [
analytics.identify.bind(analytics),
analytics.track.bind(analytics),
].map(promisify);
console.log("user id: ", req.body.event.app_user_id);
let app_user_id = req.body.event.app_user_id;
let period_type = req.body.event.period_type;
let expiration_at_ms = req.body.event.expiration_at_ms;
let ret = "Initial";
try {
await identify({
userId: app_user_id,
traits: {
period_type: period_type,
expiration_at_ms: expiration_at_ms,
},
});
ret = "Done : Sengment done";
} catch (err) {
console.log("err: ", err);
ret = "Error : " + err;
}
return {
rafsan: ret,
};
Try to clear your browser's cache or use a different browser. I had the same problem and worked for me.
Hope this helps.

Reading POST body: java.lang.IllegalStateException: Only one connection receive subscriber allowed

In Spring Webflux, when I read a POST body, and try to work with it, it always results in the IllegalStateException from the title.
Here the code:
#Bean
public RouterFunction<ServerResponse> selectByPost(SasoSecurityFacade solrHandler) {
return RouterFunctions.route(RequestPredicates.POST("/v1/{collection}/select")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), request -> request.bodyToMono(String.class)
.flatMap(s -> {
System.out.println(s);
return ServerResponse.ok()
.syncBody(s);
}));
}
Also important (as it turns out), the request TO the server:
curl 'https://<myserver>:9443/v1/banana-int/select' -H 'Pragma: no-cache' -H 'Origin: https://<myserver>:9443' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' -H 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' -H 'Content-type: application/x-www-form-urlencoded' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'Referer: https://<myserver>:9443/banana/src/index.html' -H 'Connection: keep-alive' -H 'DNT: 1' --data 'q=*:*&rows=20&wt=json' --compressed
What am I doing wrong? How can I debug this? Who else is reading my post body, so that I get this error message?
The request you're sending is a POST Form request, which is automatically read by HiddenHttpMethodFilter. This filter is consuming the form data to mutate the HTTP method in case an alternate method is specified through a "_method" parameter.
In this case, consuming the form data with the dedicated request.formData() API in WebFlux annotation/functional is the best choice, this it is cached for future use and does not trigger a new subscription.
If you wish to completely disable this behavior, you'll be able to set a property in Spring Boot 2.1.

paypal authentication failure in sandbox

I encounter an issue when I try to use the Paypal sandbox API.
I've created my 2 sandbox accounts (the facilitator and the buyer), and I've created my app to get the credentials.
Then, I use the curl example provided by Paypal to get a token :
curl -v https://api.sandbox.paypal.com/v1/oauth2/token \
-H "Accept: application/json" \
-H "Accept-Language: en_US" \
-u "my-client-id:my-secret" \
-d "grant_type=client_credentials"
I get a 200 response, with an "access_token".
Then, I use this access token to get another resource, for example :
curl -v -X GET https://api.sandbox.paypal.com/v1/invoicing/invoices?page=3&page_size=4&total_count_required=true \
-H "Content-Type: application/json" \
-H "Authorization: Bearer the-token-received-above"
Then, I get a 401 error :
{
"name":"AUTHENTICATION_FAILURE",
"message":"Authentication failed due to invalid authentication credentials or a missing Authorization header.",
"links":[{
"href":"https://developer.paypal.com/docs/api/overview/#error",
"rel":"information_link"
}]
}
I don't understand what I'm doing wrong, since I've followed every step decribed in the Paypal doc (at least, I think I have... probably not)
Thanks for your help
curl -v -X GET "https://api.sandbox.paypal.com/v1/invoicing/invoices?page=3&page_size=4&total_count_required=true" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer the-token-received-above"
Actually had this exact same issue but didn't know what was wrong with my curl. For me, the issue was I forgot to put "Bearer" in the Authorization section.
For this, you are required to wrap the URL with quotation marks.
After get access_token. Please try this
try {
$params = array('access_token' => $jsonResponse->access_token);
$userInfo = OpenIdUserinfo::getUserinfo($params, $this->_api_context);
} catch (Exception $ex) {
ResultPrinter::printError("User Information", "User Info", null, $params, $ex);
exit(1);
}
ResultPrinter::printResult("User Information", "User Info", $userInfo->getUserId(), $params, $userInfo);
Don't forget to add
use PayPal\Api\OpenIdTokeninfo;
use PayPal\Api\OpenIdUserinfo;
That's worked for me.