Posts: 60
Threads: 22
Joined: Jul 2017
Reputation:
0
Hello!
Is there anyone that can provide me with a script to recieve a JSON table from an API using the Digest Auth?
Posts: 8100
Threads: 43
Joined: Jun 2015
Reputation:
471
Posts: 119
Threads: 15
Joined: Nov 2019
Reputation:
6
15.07.2023, 14:44
(This post was last modified: 15.07.2023, 15:07 by Joep .)
I tried the script from the thread but i got this as a result:
* arg: 1
* string:
* arg: 2
* string: missing credentials in url
* arg: 3
* nil
The credentials are in the url like:
https://myemail@gmail.com :password@url
Is it because the username is an email address or is there something else what's wrong? I try to get the data of some JSON string.
When i try the complete url in the browser it does work.
(15.07.2023, 14:44) Joep Wrote: I tried the script from the thread but i got this as a result:
* arg: 1
* string:
* arg: 2
* string: missing credentials in url
* arg: 3
* nil
The credentials are in the url like: https://myemail@gmail.com :password@url
Is it because the username is an email address or is there something else what's wrong? I try to get the data of some JSON string.
When i try the complete url in the browser it does work.
Yes the email address for the user seems to be the problem. When logging log(url.user) i just got the first part of the email address back and not the complete email address. That makes sense as the part after the @ is seen as the url of course. But how to solve this as i can't change the user.
Posts: 119
Threads: 15
Joined: Nov 2019
Reputation:
6
Google is your best friend..
I replaced the @ with %40 so the credentials part is solved. But now i get this error: missing realm/nonce from response
I have no idea what it means.. How can i solve this? I'm trying to get the status of my sauna controllers API
https://api.huum.eu/action/home/status
Posts: 119
Threads: 15
Joined: Nov 2019
Reputation:
6
(15.07.2023, 15:58) Joep Wrote: Google is your best friend..
I replaced the @ with %40 so the credentials part is solved. But now i get this error: missing realm/nonce from response
I have no idea what it means.. How can i solve this? I'm trying to get the status of my sauna controllers API https://api.huum.eu/action/home/status
This is the raw header:
WWW-Authenticate Basic realm="HUUM api"
Is it a problem due to the capital characters or the whitespace in the header name?
Hope someone can help me out. Below the code so far.
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 136 137 138 139 140 141
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
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
local sink =
req.sink
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
req.sink =
nil
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
local qop =
ht.qop
if qop and qop ~=
'auth' then
return nil ,
'unsupported qop ' ..
tostring (
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
req.sink =
sink
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://myemail%40gmail.com:Password@api.huum.eu/action/home/status'
data ,
err ,
hdrs =
request (
url )
require (
'json' )
data =
json.pdecode (
data )
log (
data ,
err )
With the result:
* arg: 1
* nil
* arg: 2
* string: missing realm/nonce from response
Posts: 8100
Threads: 43
Joined: Jun 2015
Reputation:
471
You need to use basic auth instead of digest. Simply use socket.http.request
Posts: 119
Threads: 15
Joined: Nov 2019
Reputation:
6
(17.07.2023, 15:20) admin Wrote: You need to use basic auth instead of digest. Simply use socket.http.request
I got a 403 error back. If i try the complete url in the webbrowser it works correct. I replaced the @ with %40 in the username of the url.
Sauna Huum status 19.07.2023 14:49:57
* string: {"state":{"code":403,"message":"Error 403. Access denied."}}
Posts: 8100
Threads: 43
Joined: Jun 2015
Reputation:
471
Try passing username/password like in this example:
https://forum.logicmachine.net/showthrea...8#pid26618
Try both username variants - with @ and %40.
Posts: 119
Threads: 15
Joined: Nov 2019
Reputation:
6
19.07.2023, 13:55
(This post was last modified: 19.07.2023, 14:32 by Joep .)
(19.07.2023, 13:04) admin Wrote: Try passing username/password like in this example: https://forum.logicmachine.net/showthrea...8#pid26618
Try both username variants - with @ and %40.
Yes that works like a charm
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
http =
require (
'socket.http' )
mime =
require (
'mime' )
json =
require (
'json' )
result =
http.request ({
url =
'http://api.huum.eu/action/home/status' ,
headers = {
Authorization =
'Basic ' ..
mime.b64 (
'username:password' )
}
})
data =
json.pdecode (
result )
log (
data )
And now my next question is how to send a JSON POST command?
The url is then:
https://api.huum.eu/action/home/start
And the JSON command: {'targetTemperature' : 80}
(19.07.2023, 13:55) Joep Wrote: (19.07.2023, 13:04) admin Wrote: Try passing username/password like in this example: https://forum.logicmachine.net/showthrea...8#pid26618
Try both username variants - with @ and %40.
Yes that works like a charm
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
http =
require (
'socket.http' )
mime =
require (
'mime' )
json =
require (
'json' )
result =
http.request ({
url =
'http://api.huum.eu/action/home/status' ,
headers = {
Authorization =
'Basic ' ..
mime.b64 (
'username:password' )
}
})
data =
json.pdecode (
result )
log (
data )
And now my next question is how to send a JSON POST command?
The url is then: https://api.huum.eu/action/home/start
And the JSON command: {'targetTemperature' : 80}
I already found the solution.
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
function post (
url ,
body )
local ltn12 =
require (
'ltn12' )
local http =
require (
'socket.http' )
local sink = {}
local res ,
err =
http.request ({
url =
url ,
method =
'POST' ,
headers = {
[
'Authorization' ] =
'Basic ' ..(
mime.b64 (
'username:password' )),
[
'Content-Length' ] = #
body ,
[
'Content-Type' ] =
'application/json' ,
},
sink =
ltn12.sink.table (
sink ),
source =
ltn12.source.string (
body ),
})
if res then
return table.concat (
sink )
else
return nil ,
err
end
end
require (
'json' )
url =
'https://api.huum.eu/action/home/start'
body =
'{"targetTemperature" : 70}'
result =
post (
url ,
body )
data =
json.pdecode (
result )
log (
data )