This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

https digest call to philips tv (jointSPACE)
#1
Hi

I own a Philips TV wich is supporting jointSPACE Rest-Calls. And I can do rest-calls to my Philips-TV with Curl without problems:
The folowing Curl-Example is successfully returning  the "Powerstate" of my TV ("tv on" or "tv off").
  • The Call is using digest authorization
  • The Call is using https
  • Insecure server connections has to be allowed ("-k" - because the TV is using a self signed certificate)
  • Beside SSL, it connects to Port 1926 where the jointSPACE API is answering the requests.

Code:
1
curl -XGET -u <user>:<password> https://192.168.3.123:1926/powerstate -k --digest -v

Now I try to do this curl-call on my SpaceLynk with Lua. So far it is not working. It returns code 404.
I also tried to use the Erwin's digest-example:  https://forum.logicmachine.net/showthrea...mpm_digest 3
But no luck so far Sad
Can somebody help me by providing a valid lua code which is doing this curl-call?

Thanks!
Reply
#2
Hi,

I've no experiance with your problem, but what I've seen is, that you need an HTTPS connection and Erwin Solution use only http?
You've seen that?
Reply
#3
(05.10.2019, 12:21)Habib Wrote: Hi,

I've no experiance with your problem, but what I've seen is, that you need an HTTPS connection and Erwin Solution use only http?
You've seen that?

Hi Habib

Oh, yes. I forget to mention, that i adaptet Erwin's Solution to https (line 366). But this is not working Sad
Code:
12
local s_http = require 'ssl.https' --local s_http = require "socket.http"
Reply
#4
Try digest code from this post:
https://forum.logicmachine.net/showthrea...64#pid9364

Replace
Code:
1
local skthttp = require('socket.http')
with
Code:
1
local skthttp = require('ssl.https')
Reply
#5
Thanks for you help! Unfortunately using this script I get again a 404.

Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
local skthttp = require('ssl.https') --local skthttp = require('socket.http') local skturl = require('socket.url') local ltn12 = require('ltn12') local md5sum = require('encdec').md5 local hash = function(...)   return md5sum(table.concat({...}, ':')) end local parse_header = function(header)   local result = {}   for key, value in (header .. ','):gmatch('(%w+)=(.-),') do     if value:sub(1, 1) == '"' then -- strip quotes       result[ key:lower() ] = value:sub(2, -2)     else       result[ key:lower() ] = value     end   end   return result end local make_digest_header = function(headers)   local digest = {}   for _, header in ipairs(headers) do     if not header.unquote then       header[ 2 ] = '"' .. header[ 2 ] .. '"'     end     digest[ #digest + 1 ] = header[ 1 ] .. '=' .. header[ 2 ]   end   return 'Digest ' .. table.concat(digest, ', ') end local _request = function(req)   if not req.url then     return nil, 'missing url'   end   local url = skturl.parse(req.url)   local user, password = url.user, url.password   if not user or not password then     return nil, 'missing credentials in url'   end   url.user, url.password, url.authority, url.userinfo = nil, nil, nil, nil   req.url = skturl.build(url)   local source   if req.source then     local chunks = {}     local capture = function(chunk)       if chunk then         chunks[ #chunks + 1 ] = chunk       end       return chunk     end     local chunk_id = 0     source = function()       chunk_id = chunk_id + 1       return chunks[ chunk_id ]     end     req.source = ltn12.source.chain(req.source, capture)   end   local body, code, hdrs = skthttp.request(req)   if code == 401 and hdrs['www-authenticate'] then     local ht = parse_header(hdrs['www-authenticate'])     if not ht.realm or not ht.nonce then       return nil, 'missing realm/nonce from response'     end     if ht.qop ~= 'auth' then       return nil, 'unsupported qop ' .. tostring(ht.qop)     end     if ht.algorithm and ht.algorithm:lower() ~= 'md5' then       return nil, 'unsupported algo ' .. tostring(ht.algorithm)     end     local nc = '00000001'     local cnonce = string.format('%08x', os.time())     local uri = skturl.build({ path = url.path, query = url.query })     local method = req.method or 'GET'     local response = hash(       hash(user, ht.realm, password),       ht.nonce,       nc,       cnonce,       'auth',       hash(method, uri)     )     req.headers = req.headers or {}     local auth = {       { 'username', user },       { 'realm', ht.realm },       { 'nonce', ht.nonce },       { 'uri', uri },       { 'cnonce', cnonce },       { 'nc', nc, unquote = true },       { 'qop', 'auth' },       { 'algorithm', 'MD5' },       { 'response', response },     }     if ht.opaque then       table.insert(auth, { 'opaque', ht.opaque })     end     req.headers.authorization = make_digest_header(auth)     if not req.headers.cookie and hdrs['set-cookie'] then       -- not really correct but enough for httpbin       local cookie = (hdrs['set-cookie'] .. ';'):match('(.-=.-)[;,]')       if cookie then         req.headers.cookie = '$Version: 0; ' .. cookie .. ';'       end     end     if req.source then       req.source = source     end     body, code, hdrs = skthttp.request(req)   end   return body, code, hdrs end local request = function(url)   local t = type(url)   if t == 'table' then     return _request(table.clone(url))   elseif t == 'string' then     local req = {}     local _, code, headers = _request({ url = url, sink = ltn12.sink.table(req) })     return table.concat(req), code, headers   end end url = 'https://<USER>:<PASSWORD>@192.168.3.123:1926/powerstate' image, err, hdrs = request(url) log (image) log (err) log (hdrs)

The url works in a Web-Browser. But not in this Script Sad

This Curl-Call does the Job too (-k Param is necessery. This allows self signed certificate):
Code:
1
curl -XGET -u <user>:<password> https://192.168.3.123:1926/powerstate -k --digest -v

Any further Ideas?
Reply
#6
Can you run curl in verbose mode (-v) and post the output?
Reply
#7
Curl-Request with verbose:
Code:
1
curl -XGET -u <user>:<password> https://192.168.3.151:1926/powerstate -k --digest -v

Response:
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
Note: Unnecessary use of -X or --request, GET is already inferred. *   Trying 192.168.3.151... * TCP_NODELAY set * Connected to 192.168.3.151 (192.168.3.151) port 1926 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: *   CAfile: /etc/ssl/certs/ca-certificates.crt   CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server did not agree to a protocol * Server certificate: *  subject: C=IN; ST=Karnataka; L=Bengaluru; O=TP VISION India Pvt. Ltd.; OU=Smart TV; CN=restfultv.tpvision.comstart date: May 19 10:51:53 2015 GMTexpire date: Oct  4 10:51:53 2042 GMTissuer: C=IN; ST=Karnataka; L=Bengaluru; O=TP VISION India Pvt. Ltd.; OU=Smart TV; CN=ca.tpvision.comSSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway. * Server auth using Digest with user '<user>' > GET /powerstate HTTP/1.1 > Host: 192.168.3.151:1926 > User-Agent: curl/7.58.0 > Accept: */* > < HTTP/1.1 401 Unauthorized < Date: Tue, 08 Oct 2019 16:11:17 GMT+00:00 < Accept-Ranges: bytes < Server: Restlet-Framework/2.3.12 < WWW-Authenticate: Digest realm="XTV", domain="/", nonce="MTU3MDU1MTA3NzcyNTplZGFiYzY4NWNmMDAzNTM2YjRiMzJjYmQxMGM1YzY0OA==", algorithm=MD5, qop="auth" < Content-Length: 424 < Content-Type: text/html; charset=UTF-8 < * Ignoring the response-body * Connection #0 to host 192.168.3.151 left intact * Issue another request to this URL: 'https://192.168.3.151:1926/powerstate' * Found bundle for host 192.168.3.151: 0x55f0b0f70a50 [can pipeline] * Re-using existing connection! (#0) with host 192.168.3.151 * Connected to 192.168.3.151 (192.168.3.151) port 1926 (#0) * Server auth using Digest with user '<user>' > GET /powerstate HTTP/1.1 > Host: 192.168.3.151:1926 > Authorization: Digest username="<user>", realm="XTV", nonce="MTU3MDU1MTA3NzcyNTplZGFiYzY4NWNmMDAzNTM2YjRiMzJjYmQxMGM1YzY0OA==", uri="/powerstate", cnonce="NzVmNDdjYzYwMDBiYjU0Y2FmMjFjNmM5ZjA4MWE1NDE=", nc=00000001, qop=auth, response="ad84deaff1b8f9cf07c651a689543991", algorithm="MD5" > User-Agent: curl/7.58.0 > Accept: */* > < HTTP/1.1 200 OK < Date: Tue, 08 Oct 2019 16:11:17 GMT+00:00 < Accept-Ranges: bytes < Server: Restlet-Framework/2.3.12 < Access-Control-Allow-Origin: * < Content-Length: 19 < Content-Type: application/json; charset=UTF-8 < * Connection #0 to host 192.168.3.151 left intact {"powerstate":"On"}
Reply
#8
Looks correct. Do you get error 401 with your script if you specify incorrect password? Can you provide remote access to your device?
Reply
#9
I get e 404

Script:
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
local skthttp = require('ssl.https') local skturl = require('socket.url') local ltn12 = require('ltn12') local md5sum = require('encdec').md5 local hash = function(...)   return md5sum(table.concat({...}, ':')) end local parse_header = function(header)   local result = {}   for key, value in (header .. ','):gmatch('(%w+)=(.-),') do     if value:sub(1, 1) == '"' then -- strip quotes       result[ key:lower() ] = value:sub(2, -2)     else       result[ key:lower() ] = value     end   end   return result end local make_digest_header = function(headers)   local digest = {}   for _, header in ipairs(headers) do     if not header.unquote then       header[ 2 ] = '"' .. header[ 2 ] .. '"'     end     digest[ #digest + 1 ] = header[ 1 ] .. '=' .. header[ 2 ]   end   return 'Digest ' .. table.concat(digest, ', ') end local _request = function(req)   if not req.url then     return nil, 'missing url'   end   local url = skturl.parse(req.url)   local user, password = url.user, url.password   if not user or not password then     return nil, 'missing credentials in url'   end   url.user, url.password, url.authority, url.userinfo = nil, nil, nil, nil   req.url = skturl.build(url)   local source   if req.source then     local chunks = {}     local capture = function(chunk)       if chunk then         chunks[ #chunks + 1 ] = chunk       end       return chunk     end     local chunk_id = 0     source = function()       chunk_id = chunk_id + 1       return chunks[ chunk_id ]     end     req.source = ltn12.source.chain(req.source, capture)   end   local body, code, hdrs = skthttp.request(req)   if code == 401 and hdrs['www-authenticate'] then     local ht = parse_header(hdrs['www-authenticate'])     if not ht.realm or not ht.nonce then       return nil, 'missing realm/nonce from response'     end     if ht.qop ~= 'auth' then       return nil, 'unsupported qop ' .. tostring(ht.qop)     end     if ht.algorithm and ht.algorithm:lower() ~= 'md5' then       return nil, 'unsupported algo ' .. tostring(ht.algorithm)     end     local nc = '00000001'     local cnonce = string.format('%08x', os.time())     local uri = skturl.build({ path = url.path, query = url.query })     local method = req.method or 'GET'     local response = hash(       hash(user, ht.realm, password),       ht.nonce,       nc,       cnonce,       'auth',       hash(method, uri)     )     req.headers = req.headers or {}     local auth = {       { 'username', user },       { 'realm', ht.realm },       { 'nonce', ht.nonce },       { 'uri', uri },       { 'cnonce', cnonce },       { 'nc', nc, unquote = true },       { 'qop', 'auth' },       { 'algorithm', 'MD5' },       { 'response', response },     }     if ht.opaque then       table.insert(auth, { 'opaque', ht.opaque })     end     req.headers.authorization = make_digest_header(auth)     if not req.headers.cookie and hdrs['set-cookie'] then       -- not really correct but enough for httpbin       local cookie = (hdrs['set-cookie'] .. ';'):match('(.-=.-)[;,]')       if cookie then         req.headers.cookie = '$Version: 0; ' .. cookie .. ';'       end     end     if req.source then       req.source = source     end     body, code, hdrs = skthttp.request(req)   end   return body, code, hdrs end local request = function(url)   local t = type(url)   if t == 'table' then     return _request(table.clone(url))   elseif t == 'string' then     local req = {}     local _, code, headers = _request({ url = url, sink = ltn12.sink.table(req) })     return table.concat(req), code, headers   end end url = 'https://<user>:<password>@192.168.3.151:1926/powerstate' image, err, hdrs = request(url) log (image) log (err) log (hdrs)



SpaceLynk Log:
Code:
1234567891011121314151617181920212223242526
GetStatePhilipsTV 09.10.2019 11:12:37 * string: <html> <head>    <title>Status page</title> </head> <body style="font-family: sans-serif;"> <p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Not Found</p> <p>The server has not found anything matching the request URI</p> <p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">here</a>.<br> Please continue your visit at our <a href="/">home page</a>. </p> </body> </html> GetStatePhilipsTV 09.10.2019 11:12:37 * number: 404 GetStatePhilipsTV 09.10.2019 11:12:37 * table: ["date"]   * string: Wed, 09 Oct 2019 09:12:37 GMT+00:00 ["content-length"]   * string: 439 ["content-type"]   * string: text/html; charset=UTF-8 ["server"]   * string: Restlet-Framework/2.3.12

Thank you very much for your Support Smile But a Remote-Session is not necessary. If we don't find a quick solution on the SpaceLynk I will go for a workaraound (using a Linux-Device for calling the TV).
Reply
#10
This issue might appear due to missing port part in HTTP host header.

Try replacing line 125:
Code:
1
local _, code, headers = _request({ url = url, sink = ltn12.sink.table(req), headers = { host = '192.168.3.151:1926' } })
Reply
#11
Yes, now it works! Thank you very much!! Smile
Reply


Forum Jump: