From 393b768687f33a828f9b5aeca92c7fb3c32e32ed Mon Sep 17 00:00:00 2001 From: betateilchen <> Date: Sat, 14 Jan 2017 23:16:08 +0000 Subject: [PATCH] 98_GoogleAuth.pm: under development git-svn-id: https://svn.fhem.de/fhem/trunk@13073 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/98_GoogleAuth.pm | 134 ++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 fhem/contrib/98_GoogleAuth.pm diff --git a/fhem/contrib/98_GoogleAuth.pm b/fhem/contrib/98_GoogleAuth.pm new file mode 100644 index 000000000..0c38ff8c7 --- /dev/null +++ b/fhem/contrib/98_GoogleAuth.pm @@ -0,0 +1,134 @@ +$Id$ + +package main; +use strict; +use warnings; + +## apt-get install libconvert-base32-perl libauthen-oath-perl libcrypt-urandom-perl + +use Convert::Base32; +use Authen::OATH; +use URI::Escape; +use Crypt::URandom qw( urandom ); + + +sub GoogleAuth_Initialize($) { + my ($hash) = @_; + + $hash->{DefFn} = "GoogleAuth_Define"; + $hash->{UndefFn} = "GoogleAuth_Undefine"; + $hash->{DeleteFn} = "GoogleAuth_Delete"; + $hash->{SetFn} = "GoogleAuth_Set"; + $hash->{GetFn} = "GoogleAuth_Get"; +# $hash->{AttrFn} = "GoogleAuth_Attr"; + $hash->{AttrList} = "ga_qrsize ". + "$readingFnAttributes"; +} + +sub GoogleAuth_Define($$) { + my ($hash, $def) = @_; + my $name = $hash->{NAME}; + my @a = split("[ \t][ \t]*", $def); + return "Usage: Use Google Authenticator" if(@a != 2); + +## ich würde keine Prüfung auf bereits vorhandene GA machen, +## es kann durchaus Fälle geben, in denen man mehr als 1 Schlüssel definieren möchte + +# my $d = $modules{$hash->{TYPE}}{defptr}; +# return "$hash->{TYPE} device already defined as $d->{NAME}." if( defined($d) ); + Log3($hash,4,"googleAuth $name: defined"); + readingsSingleUpdate($hash,'state','defined',1); + return undef; +} + +sub GoogleAuth_Undefine($$) { + my ($hash, $arg) = @_; + delete $modules{$hash->{TYPE}}{defptr}; + return undef; +} + +sub GoogleAuth_Delete() { + my ($hash, $arg) = @_; + my $name = $hash->{NAME}; + setKeyValue("googleAuth$name",undef); +} + +sub GoogleAuth_Set($$@) { + my ($hash, $name, $cmd, @args) = @_; + my $usage = "Unknown argument, choose one of new:noArg"; + + if($cmd eq "new") { + #SOURCE: https://blog.darkpan.com/article/6/Perl-and-Google-Authenticator.html + my $secret_bytes = urandom(50); + my $secret_base32 = encode_base32( $secret_bytes ); + Log3($hash,5,"googleAuth $name: secret_bytes=$secret_bytes"); + Log3($hash,5,"googleAuth $name: set secret_base32=$secret_base32"); + + setKeyValue("googleAuth$name",$secret_base32); # write to fhem keystore + + my $label = "FHEM%20Authentication%20$name"; + my $qrsize = AttrVal("$name",'ga_qrsize','200x200'); + my $url = "otpauth://totp/$label?secret=$secret_base32"; + my $qr_url = "https://chart.googleapis.com/chart?cht=qr&chs=$qrsize"."&chl=".uri_escape($url); + + readingsSingleUpdate($hash,'qr_url',$qr_url,1); + my $ret = "<\/a>"; + return $ret; + ; + + } + return $usage; +} + +sub GoogleAuth_Get($$@) { + my ($hash, $name, $cmd, @args) = @_; + my $usage = "Unknown argument, choose one of check"; + + if ($cmd eq "check") { + my $given_token = shift @args; + return "Token missing!" unless (defined($given_token) && $given_token); + + $given_token = _ga_make_token_6($given_token); + Log3($hash,4,"googleAuth $name: given: $given_token"); + + my $secret_base32 = getKeyValue("googleAuth$name"); # read from fhem keystore + Log3($hash,5,"googleAuth $name: get secret_base32=$secret_base32"); + $secret_base32 = decode_base32($secret_base32); + Log3($hash,5,"googleAuth $name: secret_bytes=$secret_base32"); + + my $oath = Authen::OATH->new; + my @possible = map { _ga_make_token_6($oath->totp($secret_base32, $_)) } time-30, time, time+30; + Log3($hash,4,"googleAuth $name: possible: ".join ' ',@possible); + + my $result = (grep /^$given_token$/, @possible) ? 1 : -1; + Log3($hash,4,"googleAuth $name: result: $result"); + return $result; + } + return $usage; +} + +sub _ga_make_token_6($) { + my $token = shift; + while (length $token < 6) { + $token = "0$token"; + } + return $token; +} + + +1; + +=pod +=item helper +=item summary Module to use GoogleAuthnticator +=item summary_DE Modul zur Nutzung von GoogleAuthenticator +=begin html + + +

GoogleAuthenticator

+ +
+=end html +=cut \ No newline at end of file