mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-25 16:05:19 +00:00
LandroidUtils.pm: optimizing auth-token usage
git-svn-id: https://svn.fhem.de/fhem/trunk@27461 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
519c9a39eb
commit
cbe20a4420
@ -12,6 +12,13 @@ use warnings;
|
|||||||
# attr m2c connectFn {use LandroidUtils;;Landroid_connect($NAME,"worx",1)}
|
# attr m2c connectFn {use LandroidUtils;;Landroid_connect($NAME,"worx",1)}
|
||||||
# set m2c password mySecret
|
# set m2c password mySecret
|
||||||
# If the last parameter to Landroid_connect is 1, devices will be autocreated
|
# If the last parameter to Landroid_connect is 1, devices will be autocreated
|
||||||
|
# For debugging use "attr m2c verbose 4"
|
||||||
|
#
|
||||||
|
# Developer stuff:
|
||||||
|
# - access_token is a three-part entity, it is used for HTTP requesting data
|
||||||
|
# or MQTT-Connect, it is valid for 1h
|
||||||
|
# - refresh_token is used to get a new access_token, validity period unclear
|
||||||
|
# - auth with user/pw should be avoided, unclear why
|
||||||
|
|
||||||
my %types = (
|
my %types = (
|
||||||
worx => {
|
worx => {
|
||||||
@ -45,8 +52,15 @@ sub
|
|||||||
Landroid_connect($$;$)
|
Landroid_connect($$;$)
|
||||||
{
|
{
|
||||||
my ($m2c_name, $type, $autocreate) = @_;
|
my ($m2c_name, $type, $autocreate) = @_;
|
||||||
my $errPrefix = "ERROR: Landroid_connect $m2c_name -";
|
|
||||||
my $m2c = $defs{$m2c_name};
|
my $m2c = $defs{$m2c_name};
|
||||||
|
|
||||||
|
if($m2c->{NEXT_OPEN} && gettimeofday() < $m2c->{NEXT_OPEN}) {
|
||||||
|
delete($m2c->{inConnectFn});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete($m2c->{NEXT_OPEN});
|
||||||
|
|
||||||
|
my $errPrefix = "ERROR: Landroid_connect $m2c_name -";
|
||||||
my $usr = AttrVal($m2c_name, "username", "");
|
my $usr = AttrVal($m2c_name, "username", "");
|
||||||
my $pwd = getKeyValue($m2c_name);
|
my $pwd = getKeyValue($m2c_name);
|
||||||
|
|
||||||
@ -56,14 +70,19 @@ Landroid_connect($$;$)
|
|||||||
return Log 1, "$errPrefix unknown type $type" if(!$types{$type});
|
return Log 1, "$errPrefix unknown type $type" if(!$types{$type});
|
||||||
|
|
||||||
$m2c->{landroidType} = $type;
|
$m2c->{landroidType} = $type;
|
||||||
$m2c->{autocreate} = 1 if($autocreate);
|
$m2c->{autocreate} = $autocreate ? 1 : 0;
|
||||||
my $t = $types{$type};
|
my $t = $types{$type};
|
||||||
RemoveInternalTimer("landroidTmr_$m2c_name");
|
|
||||||
|
if(ReadingsVal($m2c_name, ".access_token", undef) &&
|
||||||
|
ReadingsAge($m2c_name, ".access_token", 0) <
|
||||||
|
ReadingsVal($m2c_name, ".expires_in", 0)) {
|
||||||
|
Log3 $m2c, 4, "$m2c_name: reusing the acess_token";
|
||||||
|
return Landroid_connect2($m2c_name);
|
||||||
|
}
|
||||||
|
|
||||||
my $rt = ReadingsVal($m2c_name, ".refresh_token", undef);
|
my $rt = ReadingsVal($m2c_name, ".refresh_token", undef);
|
||||||
my $ra = ReadingsAge($m2c_name, ".refresh_token", 0);
|
|
||||||
my $data;
|
my $data;
|
||||||
if($rt && $ra < 3600) { # refresh
|
if($rt) { # try refresh first
|
||||||
$data = { grant_type=>"refresh_token", refresh_token=>$rt,
|
$data = { grant_type=>"refresh_token", refresh_token=>$rt,
|
||||||
client_id=>$t->{clientId}, scope=>"*" };
|
client_id=>$t->{clientId}, scope=>"*" };
|
||||||
|
|
||||||
@ -77,20 +96,24 @@ Landroid_connect($$;$)
|
|||||||
timeout=>60,
|
timeout=>60,
|
||||||
callback=> sub($$$){
|
callback=> sub($$$){
|
||||||
my ($h,$e,$d) = @_;
|
my ($h,$e,$d) = @_;
|
||||||
return Log3 $m2c, 1, "$errPrefix $e" if($e);
|
return Landroid_retry($m2c, "$errPrefix $e") if($e);
|
||||||
return Log3 $m2c, 1, "$errPrefix no data" if(!$d);
|
return Landroid_retry($m2c, "$errPrefix no data") if(!$d);
|
||||||
Log3 $m2c, 5, $d;
|
Log3 $m2c, 5, $d;
|
||||||
$m2c->{".auth"} = json2nameValue($d);
|
my $auth = json2nameValue($d);
|
||||||
return Log3 $m2c, 1, "$errPrefix no access_token / $d"
|
if(!$auth->{access_token}) {
|
||||||
if(!$m2c->{".auth"}{access_token});
|
if($data->{grant_type} eq "refresh_token") {
|
||||||
Log3 $m2c, 4, "$m2c_name: Got auth info, request: ".$data->{grant_type};
|
readingsDelete($m2c, ".refresh_token");
|
||||||
setReadingsVal($m2c, ".refresh_token",
|
Log3 $m2c, 4, "$errPrefix refresh_token failed, trying full auth";
|
||||||
$m2c->{".auth"}{refresh_token}, TimeNow());
|
Landroid_connect($m2c_name, $type, $autocreate);
|
||||||
InternalTimer(gettimeofday()+3540,
|
} else {
|
||||||
sub(){
|
Landroid_retry($m2c, "$errPrefix got no access_token", $d);
|
||||||
Log3 $m2c, 4, "$m2c_name: requesting new token";
|
}
|
||||||
Landroid_connect($m2c_name, $type)
|
return;
|
||||||
}, "landroidTmr_$m2c_name", 0);
|
}
|
||||||
|
|
||||||
|
Log3 $m2c, 4, "$m2c_name: Got auth info, type ".$data->{grant_type};
|
||||||
|
map { setReadingsVal($m2c, ".$_", $auth->{$_}, TimeNow()) }
|
||||||
|
( "refresh_token", "access_token", "expires_in", "token_type");
|
||||||
Landroid_connect2($m2c_name);
|
Landroid_connect2($m2c_name);
|
||||||
},
|
},
|
||||||
header => {
|
header => {
|
||||||
@ -110,22 +133,31 @@ Landroid_connect2($)
|
|||||||
|
|
||||||
my $errPrefix = "ERROR: Landroid_connect2 $m2c_name -";
|
my $errPrefix = "ERROR: Landroid_connect2 $m2c_name -";
|
||||||
my $t = $types{$m2c->{landroidType}};
|
my $t = $types{$m2c->{landroidType}};
|
||||||
my $p = $m2c->{".auth"};
|
|
||||||
|
|
||||||
HttpUtils_NonblockingGet({
|
HttpUtils_NonblockingGet({
|
||||||
url => "https://$t->{url}/api/v2/users/me",
|
url => "https://$t->{url}/api/v2/users/me",
|
||||||
header => {
|
header => {
|
||||||
"Accept"=>"application/json",
|
"Accept"=>"application/json",
|
||||||
"Authorization"=>"Bearer ".$p->{access_token},
|
"Authorization"=>"Bearer ".ReadingsVal($m2c_name,".access_token","")
|
||||||
},
|
},
|
||||||
callback=>sub($$$){
|
callback=>sub($$$){
|
||||||
my ($h,$e,$d) = @_;
|
my ($h,$e,$d) = @_;
|
||||||
return Log3 $m2c, 1, "$errPrefix $e" if($e);
|
return Landroid_retry($m2c, "$errPrefix $e") if($e);
|
||||||
return Log3 $m2c, 1, "$errPrefix no data" if(!$d);
|
return Landroid_retry($m2c, "$errPrefix no data") if(!$d);
|
||||||
Log3 $m2c, 5, $d;
|
Log3 $m2c, 5, $d;
|
||||||
my $me = json2nameValue($d);
|
my $me = json2nameValue($d);
|
||||||
return Log3 $m2c, 1, "$errPrefix no userId"
|
if(!$me->{id}) {
|
||||||
if(!$me->{id});
|
if($m2c->{authRetry}) {
|
||||||
|
Landroid_retry($m2c, "$errPrefix no userId after auth retry", $d);
|
||||||
|
} else {
|
||||||
|
$m2c->{authRetry} = 1;
|
||||||
|
readingsDelete($m2c, ".access_token");
|
||||||
|
Log3 $m2c, 4, "$errPrefix no userId, retrying auth / $d";
|
||||||
|
Landroid_connect($m2c_name, $m2c->{landroidType}, $m2c->{autocreate});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete($m2c->{authRetry});
|
||||||
Log3 $m2c, 4, "$m2c_name: Got userId: $me->{id}";
|
Log3 $m2c, 4, "$m2c_name: Got userId: $me->{id}";
|
||||||
$m2c->{userId} = $me->{id};
|
$m2c->{userId} = $me->{id};
|
||||||
Landroid_connect3($m2c_name);
|
Landroid_connect3($m2c_name);
|
||||||
@ -139,7 +171,6 @@ Landroid_connect3($)
|
|||||||
{
|
{
|
||||||
my ($m2c_name) = @_;
|
my ($m2c_name) = @_;
|
||||||
my $m2c = $defs{$m2c_name};
|
my $m2c = $defs{$m2c_name};
|
||||||
my $p = $m2c->{".auth"};
|
|
||||||
my $t = $types{$m2c->{landroidType}};
|
my $t = $types{$m2c->{landroidType}};
|
||||||
my $errPrefix = "ERROR: Landroid_connect3 $m2c_name -";
|
my $errPrefix = "ERROR: Landroid_connect3 $m2c_name -";
|
||||||
|
|
||||||
@ -147,15 +178,15 @@ Landroid_connect3($)
|
|||||||
url => "https://$t->{url}/api/v2/product-items?status=1",
|
url => "https://$t->{url}/api/v2/product-items?status=1",
|
||||||
header => {
|
header => {
|
||||||
"Accept"=>"application/json",
|
"Accept"=>"application/json",
|
||||||
"Authorization"=>"Bearer ".$p->{access_token},
|
"Authorization"=>"Bearer ".ReadingsVal($m2c_name,".access_token","")
|
||||||
},
|
},
|
||||||
callback => sub(){
|
callback => sub(){
|
||||||
my ($h,$e,$d) = @_;
|
my ($h,$e,$d) = @_;
|
||||||
return Log3 $m2c, 1, "$errPrefix $e" if($e);
|
return Landroid_retry($m2c, "$errPrefix $e") if($e);
|
||||||
return Log3 $m2c, 1, "$errPrefix no data" if(!$d);
|
return Landroid_retry($m2c, "$errPrefix no data") if(!$d);
|
||||||
Log3 $m2c, 5, $d;
|
Log3 $m2c, 5, $d;
|
||||||
my $dl = json2nameValue($d); # DeviceList
|
my $dl = json2nameValue($d); # DeviceList
|
||||||
return Log3 $m2c, 1, "$errPrefix no devicelist" if(!$dl);
|
return Landroid_retry($m2c, "$errPrefix no devicelist") if(!$dl);
|
||||||
Log3 $m2c, 4, "$m2c_name: Got device info";
|
Log3 $m2c, 4, "$m2c_name: Got device info";
|
||||||
my %sn;
|
my %sn;
|
||||||
for my $d (keys %defs) {
|
for my $d (keys %defs) {
|
||||||
@ -174,8 +205,7 @@ Landroid_connect3($)
|
|||||||
my $m2d_name = makeDeviceName($m2c_name."_".$dl->{$i1."_name"});
|
my $m2d_name = makeDeviceName($m2c_name."_".$dl->{$i1."_name"});
|
||||||
DoTrigger("global", "UNDEFINED $m2d_name MQTT2_DEVICE $sn");
|
DoTrigger("global", "UNDEFINED $m2d_name MQTT2_DEVICE $sn");
|
||||||
$m2d = $defs{$m2d_name};
|
$m2d = $defs{$m2d_name};
|
||||||
next if(!$m2d);
|
$attr{$m2d_name}{IODev} = $m2c->{NAME} if($m2d);
|
||||||
$attr{$m2d_name}{IODev} = $m2c->{NAME};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $key (keys %{$dl}) {
|
for my $key (keys %{$dl}) {
|
||||||
@ -185,13 +215,16 @@ Landroid_connect3($)
|
|||||||
my $val = $dl->{$key};
|
my $val = $dl->{$key};
|
||||||
next if(!defined($val));
|
next if(!defined($val));
|
||||||
$val =~ s,\\/,/,g; # Bug in the backend?
|
$val =~ s,\\/,/,g; # Bug in the backend?
|
||||||
setReadingsVal($m2d, $readingName, $val, $now) if($m2c->{autocreate});
|
if($m2d) { # autocreate deactivated
|
||||||
push @cmds, $val if($readingName eq "mqtt_topics_command_in");
|
my $m2d_name = $m2d->{NAME};
|
||||||
if($readingName eq "mqtt_topics_command_out") {
|
setReadingsVal($m2d, $readingName,$val,$now) if($m2c->{autocreate});
|
||||||
push @subs, $val;
|
push @cmds, $val if($readingName eq "mqtt_topics_command_in");
|
||||||
$attr{$m2d->{NAME}}{readingList}="$val:.* {json2nameValue(\$EVENT)}"
|
if($readingName eq "mqtt_topics_command_out") {
|
||||||
if($m2c->{autocreate} &&
|
push @subs, $val;
|
||||||
!AttrVal($m2d->{NAME}, "readingList", undef));
|
$attr{$m2d_name}{readingList}="$val:.* {json2nameValue(\$EVENT)}"
|
||||||
|
if($m2c->{autocreate} &&
|
||||||
|
!AttrVal($m2d->{NAME}, "readingList", undef));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$m2c->{mqttEndpoint} = $val if($readingName eq "mqtt_endpoint");
|
$m2c->{mqttEndpoint} = $val if($readingName eq "mqtt_endpoint");
|
||||||
}
|
}
|
||||||
@ -212,7 +245,7 @@ Landroid_connect4($)
|
|||||||
my ($m2c_name) = @_;
|
my ($m2c_name) = @_;
|
||||||
my $m2c = $defs{$m2c_name};
|
my $m2c = $defs{$m2c_name};
|
||||||
|
|
||||||
my $at = $m2c->{".auth"}{access_token};
|
my $at = ReadingsVal($m2c_name, ".access_token", "");
|
||||||
$at =~ tr,_-,/+,; # base64 url-safe to standard base64
|
$at =~ tr,_-,/+,; # base64 url-safe to standard base64
|
||||||
my @token = map { urlEncode($_) } split('[.]', $at);
|
my @token = map { urlEncode($_) } split('[.]', $at);
|
||||||
$m2c->{".usr"} = "FHEM?jwt=$token[0].$token[1]&".
|
$m2c->{".usr"} = "FHEM?jwt=$token[0].$token[1]&".
|
||||||
@ -221,6 +254,7 @@ Landroid_connect4($)
|
|||||||
$m2c->{DeviceName} = "$m2c->{mqttEndpoint}:443";
|
$m2c->{DeviceName} = "$m2c->{mqttEndpoint}:443";
|
||||||
$m2c->{sslargs}{SSL_alpn_protocols} = "mqtt";
|
$m2c->{sslargs}{SSL_alpn_protocols} = "mqtt";
|
||||||
$m2c->{SSL} = 1;
|
$m2c->{SSL} = 1;
|
||||||
|
$m2c->{devioLoglevel} = AttrVal($m2c_name, "verbose", 4);
|
||||||
|
|
||||||
my $wxid = ReadingsVal($m2c_name, "wxid", undef);
|
my $wxid = ReadingsVal($m2c_name, "wxid", undef);
|
||||||
if(!defined($wxid)) {
|
if(!defined($wxid)) {
|
||||||
@ -237,8 +271,26 @@ Landroid_connect4($)
|
|||||||
if(!defined(AttrVal($m2c_name, "maxFailedConnects", undef)));
|
if(!defined(AttrVal($m2c_name, "maxFailedConnects", undef)));
|
||||||
$a->{nextOpenDelay} = 180
|
$a->{nextOpenDelay} = 180
|
||||||
if(!defined(AttrVal($m2c_name, "nextOpenDelay", undef)));
|
if(!defined(AttrVal($m2c_name, "nextOpenDelay", undef)));
|
||||||
MQTT2_CLIENT_Disco($m2c, 1); # Make sure reconnect will work
|
|
||||||
|
MQTT2_CLIENT_Disco($m2c); # Make sure reconnect will work
|
||||||
|
delete $readyfnlist{"$m2c_name.".$m2c->{DeviceName}};
|
||||||
|
delete $m2c->{DevIoJustClosed};
|
||||||
MQTT2_CLIENT_connect($m2c, 1);
|
MQTT2_CLIENT_connect($m2c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Log error, and retry it later, triggered from ReadyFn
|
||||||
|
sub
|
||||||
|
Landroid_retry($$;$)
|
||||||
|
{
|
||||||
|
my ($m2c, $err, $debug) = @_;
|
||||||
|
my $m2c_name = $m2c->{NAME};
|
||||||
|
|
||||||
|
Log3 $m2c, 1, $err;
|
||||||
|
Log3 $m2c, 4, $debug if($debug);
|
||||||
|
|
||||||
|
$m2c->{NEXT_OPEN} = gettimeofday()+AttrVal($m2c_name, "nextOpenDelay", 180);
|
||||||
|
delete($m2c->{inConnectFn});
|
||||||
|
$readyfnlist{"$m2c_name.$m2c->{DeviceName}"} = $m2c;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user