Posts: 28
Threads: 8
Joined: Mar 2018
Reputation:
1
05.10.2019, 10:25
(This post was last modified: 05.10.2019, 10:26 by ralwet .)
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
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
Can somebody help me by providing a valid lua code which is doing this curl-call?
Thanks!
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
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?
Posts: 28
Threads: 8
Joined: Mar 2018
Reputation:
1
(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
Code:
1 2
local s_http =
require 'ssl.https'
Posts: 8079
Threads: 43
Joined: Jun 2015
Reputation:
471
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' )
Posts: 28
Threads: 8
Joined: Mar 2018
Reputation:
1
Thanks for you help! Unfortunately using this script I get again a 404.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
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
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
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
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
Any further Ideas?
Posts: 8079
Threads: 43
Joined: Jun 2015
Reputation:
471
Can you run curl in verbose mode (-v) and post the output?
Posts: 28
Threads: 8
Joined: Mar 2018
Reputation:
1
08.10.2019, 16:13
(This post was last modified: 08.10.2019, 16:14 by ralwet .)
Curl-Request with verbose:
Code:
1
curl -
XGET -
u <
user >:<
password >
https ://
192.168.3.151 :
1926 /
powerstate -
k
Response:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
Note :
Unnecessary use of -
X or
*
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.com
*
start date :
May 19 10 :
51 :
53 2015 GMT
*
expire date :
Oct 4 10 :
51 :
53 2042 GMT
*
issuer :
C =
IN ;
ST =
Karnataka ;
L =
Bengaluru ;
O =
TP VISION India Pvt. Ltd. ;
OU =
Smart TV ;
CN =
ca.tpvision.com
*
SSL 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" }
Posts: 8079
Threads: 43
Joined: Jun 2015
Reputation:
471
Looks correct. Do you get error 401 with your script if you specify incorrect password? Can you provide remote access to your device?
Posts: 28
Threads: 8
Joined: Mar 2018
Reputation:
1
I get e 404
Script:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
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
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
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
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
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).
Posts: 8079
Threads: 43
Joined: Jun 2015
Reputation:
471
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' } })
Posts: 28
Threads: 8
Joined: Mar 2018
Reputation:
1
Yes, now it works! Thank you very much!!