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
+
+
+