Auth-GoogleAuth-1.05/0000775000175200017520000000000014610313750014340 5ustar gryphongryphonAuth-GoogleAuth-1.05/Makefile.PL0000644000175200017520000000306514610313750016314 0ustar gryphongryphon# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.031. use strict; use warnings; use 5.008; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "Google Authenticator TBOT Abstraction", "AUTHOR" => "Gryphon Shafer ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Auth-GoogleAuth", "LICENSE" => "artistic_2", "MIN_PERL_VERSION" => "5.008", "NAME" => "Auth::GoogleAuth", "PREREQ_PM" => { "Carp" => 0, "Class::Accessor" => 0, "Convert::Base32" => 0, "Digest::HMAC_SHA1" => 0, "Math::Random::MT" => 0, "URI::Escape" => 0, "base" => 0, "strict" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "File::Spec" => 0, "IO::Handle" => 0, "IPC::Open3" => 0, "Test2::V0" => 0, "Test::More" => 0 }, "VERSION" => "1.05", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "Class::Accessor" => 0, "Convert::Base32" => 0, "Digest::HMAC_SHA1" => 0, "File::Spec" => 0, "IO::Handle" => 0, "IPC::Open3" => 0, "Math::Random::MT" => 0, "Test2::V0" => 0, "Test::More" => 0, "URI::Escape" => 0, "base" => 0, "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); Auth-GoogleAuth-1.05/Changes0000644000175200017520000000155314610313750015635 0ustar gryphongryphonRevision history for Auth::GoogleAuth 1.05 2024-04-18 15:00:06-07:00 America/Los_Angeles - Switch from Google Chart API to Quick Chart API 1.04 2022-03-18 08:49:53-07:00 America/Los_Angeles - Minor documentation update 1.03 2021-01-10 13:38:22-08:00 America/Los_Angeles - Migrate to Test2::V0 - Improve .gitignore file - License migrate to Artistic 2.0 - Migrate Travis CI and Coveralls to GitHub Actions and Codecov - Update copyright year - Update Travis YAML 1.02 2017-12-26 13:50:58-08:00 America/Los_Angeles - Adding Perl versions to test; annual general update for 2018 1.01 2015-08-03 18:04:30-07:00 America/Los_Angeles - Minor POD clean-up 1.00 2015-08-03 17:57:59-07:00 America/Los_Angeles - First version, released on an unsuspecting world. Auth-GoogleAuth-1.05/cpanfile0000644000175200017520000000215214610313750016042 0ustar gryphongryphon# This file is generated by Dist::Zilla::Plugin::CPANFile v6.031 # Do not edit this file directly. To change prereqs, edit the `dist.ini` file. requires "Carp" => "0"; requires "Class::Accessor" => "0"; requires "Convert::Base32" => "0"; requires "Digest::HMAC_SHA1" => "0"; requires "Math::Random::MT" => "0"; requires "URI::Escape" => "0"; requires "base" => "0"; requires "perl" => "5.008"; requires "strict" => "0"; requires "warnings" => "0"; on 'test' => sub { requires "File::Spec" => "0"; requires "IO::Handle" => "0"; requires "IPC::Open3" => "0"; requires "Test2::V0" => "0"; requires "Test::More" => "0"; requires "perl" => "5.008"; }; on 'configure' => sub { requires "ExtUtils::MakeMaker" => "0"; requires "perl" => "5.008"; }; on 'develop' => sub { requires "Pod::Coverage::TrustPod" => "0"; requires "Test::EOL" => "0"; requires "Test::Kwalitee" => "1.21"; requires "Test::More" => "0.88"; requires "Test::NoTabs" => "0"; requires "Test::Pod" => "1.41"; requires "Test::Pod::Coverage" => "1.08"; requires "Test::Portability::Files" => "0"; requires "Test::Synopsis" => "0"; }; Auth-GoogleAuth-1.05/dist.ini0000644000175200017520000000133214610313750016001 0ustar gryphongryphonname = Auth-GoogleAuth author = Gryphon Shafer license = Artistic_2_0 copyright_holder = Gryphon Shafer copyright_year = 2015-2050 [Git::NextVersion] [@Basic] [PruneFiles] match = ^cover_db [MinimumPerl] [NextRelease] [AutoPrereqs] [OurPkgVersion] [MetaJSON] [CPANFile] [PodWeaver] [ReadmeAnyFromPod] type = markdown location = root filename = README.md [Run::BeforeBuild] run = rm -f Makefile.PL [Run::AfterBuild] run = cp %d/Makefile.PL . run = cp README.md %d/. [PodCoverageTests] [PodSyntaxTests] [Test::NoTabs] [Test::EOL] [Test::Compile] [Test::Portability] [Test::Synopsis] [Test::Kwalitee] [Clean] [GithubMeta] issues = 1 [@Git] untracked_files = ignore Auth-GoogleAuth-1.05/weaver.ini0000644000175200017520000000054614610313750016335 0ustar gryphongryphon[@CorePrep] [-Transformer] transformer = List [-SingleEncoding] [Name] [Version] [Region / badges] [Region / prelude] [Generic / SYNOPSIS] [Generic / DESCRIPTION] [Generic / OVERVIEW] [Collect / ATTRIBUTES] command = attr [Collect / METHODS] command = method [Collect / FUNCTIONS] command = func [Leftovers] [Region / postlude] [Authors] [Legal] Auth-GoogleAuth-1.05/META.json0000644000175200017520000000425514610313750015765 0ustar gryphongryphon{ "abstract" : "Google Authenticator TBOT Abstraction", "author" : [ "Gryphon Shafer " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Auth-GoogleAuth", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0", "perl" : "5.008" } }, "develop" : { "requires" : { "Pod::Coverage::TrustPod" : "0", "Test::EOL" : "0", "Test::Kwalitee" : "1.21", "Test::More" : "0.88", "Test::NoTabs" : "0", "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.08", "Test::Portability::Files" : "0", "Test::Synopsis" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Class::Accessor" : "0", "Convert::Base32" : "0", "Digest::HMAC_SHA1" : "0", "Math::Random::MT" : "0", "URI::Escape" : "0", "base" : "0", "perl" : "5.008", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "File::Spec" : "0", "IO::Handle" : "0", "IPC::Open3" : "0", "Test2::V0" : "0", "Test::More" : "0", "perl" : "5.008" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/gryphonshafer/Auth-GoogleAuth/issues" }, "homepage" : "https://github.com/gryphonshafer/Auth-GoogleAuth", "repository" : { "type" : "git", "url" : "https://github.com/gryphonshafer/Auth-GoogleAuth.git", "web" : "https://github.com/gryphonshafer/Auth-GoogleAuth" } }, "version" : "1.05", "x_generated_by_perl" : "v5.38.2", "x_serialization_backend" : "Cpanel::JSON::XS version 4.37", "x_spdx_expression" : "Artistic-2.0" } Auth-GoogleAuth-1.05/t/0000775000175200017520000000000014610313750014603 5ustar gryphongryphonAuth-GoogleAuth-1.05/t/author-eol.t0000644000175200017520000000115214610313750017044 0ustar gryphongryphon BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::EOL 0.19 use Test::More 0.88; use Test::EOL; my @files = ( 'lib/Auth/GoogleAuth.pm', 't/00-compile.t', 't/author-eol.t', 't/author-no-tabs.t', 't/author-pod-coverage.t', 't/author-pod-syntax.t', 't/author-portability.t', 't/author-synopsis.t', 't/module.t', 't/release-kwalitee.t' ); eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files; done_testing; Auth-GoogleAuth-1.05/t/author-pod-coverage.t0000644000175200017520000000056714610313750020651 0ustar gryphongryphon#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests. use strict; use warnings; use Test::Pod::Coverage 1.08; use Pod::Coverage::TrustPod; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); Auth-GoogleAuth-1.05/t/author-pod-syntax.t0000644000175200017520000000045414610313750020377 0ustar gryphongryphon#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); Auth-GoogleAuth-1.05/t/author-portability.t0000644000175200017520000000033214610313750020626 0ustar gryphongryphon BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use strict; use warnings; use Test::More; use Test::Portability::Files; run_tests(); Auth-GoogleAuth-1.05/t/author-synopsis.t0000644000175200017520000000026214610313750020155 0ustar gryphongryphon#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use Test::Synopsis; all_synopsis_ok(); Auth-GoogleAuth-1.05/t/00-compile.t0000644000175200017520000000264014610313750016635 0ustar gryphongryphonuse 5.006; use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::Compile 2.058 use Test::More; plan tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0); my @module_files = ( 'Auth/GoogleAuth.pm' ); # no fake home requested my @switches = ( -d 'blib' ? '-Mblib' : '-Ilib', ); use File::Spec; use IPC::Open3; use IO::Handle; open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!"; my @warnings; for my $lib (@module_files) { # see L my $stderr = IO::Handle->new; diag('Running: ', join(', ', map { my $str = $_; $str =~ s/'/\\'/g; q{'} . $str . q{'} } $^X, @switches, '-e', "require q[$lib]")) if $ENV{PERL_COMPILE_TEST_DEBUG}; my $pid = open3($stdin, '>&STDERR', $stderr, $^X, @switches, '-e', "require q[$lib]"); binmode $stderr, ':crlf' if $^O eq 'MSWin32'; my @_warnings = <$stderr>; waitpid($pid, 0); is($?, 0, "$lib loaded ok"); shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/ and not eval { +require blib; blib->VERSION('1.01') }; if (@_warnings) { warn @_warnings; push @warnings, @_warnings; } } is(scalar(@warnings), 0, 'no warnings found') or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) ) if $ENV{AUTHOR_TESTING}; Auth-GoogleAuth-1.05/t/module.t0000644000175200017520000000444414610313750016261 0ustar gryphongryphonuse Test2::V0; use Auth::GoogleAuth; my $obj; ok( $obj = Auth::GoogleAuth->new, 'new' ); is( ref $obj, 'Auth::GoogleAuth', 'ref $object' ); my $secret32 = $obj->generate_secret32; ok( $secret32 =~ /^[a-z2-7]{16}$/, 'generate_secret32() length and content' ); is( $secret32, $obj->secret32, 'generate_secret32() stored as secret32()' ); ok( lives { $obj = Auth::GoogleAuth->new( { map { $_ => 'data' } qw( secret secret32 issuer key_id ) } ) }, 'new({...})', ) or note $@; is( $obj->$_, 'data', "$_ set in instantiator" ) for ( qw( secret secret32 issuer key_id ) ); ok( lives { $obj->clear }, 'clear' ) or note $@; is( $obj->$_, undef, "$_ unset after clear" ) for ( qw( secret secret32 issuer key_id ) ); ok( $obj->qr_code =~ m| https://quickchart.io/chart \? chs=200x200&cht=qr&chl= otpauth%3A%2F%2Ftotp%2FUndefined%3AUndefined%3Fsecret%3D [a-z0-9]{16} %26issuer%3DUndefined |x, 'qr_code from clear state' ); ok( $obj->qr_code( 'bv5o3disbutz4tl3', 'gryphon@cpan.org', 'Gryphon Shafer' ) =~ m| https://quickchart.io/chart \? chs=200x200&cht=qr&chl= otpauth%3A%2F%2Ftotp%2FGryphon%2520Shafer%3Agryphon%2540cpan.org%3Fsecret%3D bv5o3disbutz4tl3 %26issuer%3DGryphon%2520Shafer |x, 'qr_code from specific state' ); ok( $obj->qr_code( 'bv5o3disbutz4tl3', 'gryphon@cpan.org', 'Gryphon Shafer', 1 ) =~ m| otpauth://totp/Gryphon%20Shafer:gryphon%40cpan.org\?secret=bv5o3disbutz4tl3&issuer=Gryphon%20Shafer |x, 'qr_code otpauth from specific state' ); is( $obj->code( undef, 1438643789 ), '007176', 'code()' ); is( $obj->code( 'utz4tl3bv5o3disb', 1438643789 ), '879364', 'code( $s32, $time )' ); is( $obj->code( 'utz4tl3bv5o3disb', 1438643789, 30 ), '879364', 'code( $s32, $time, 30 )' ); is( $obj->code( undef, 1438643789 ), '879364', 'code() again' ); is( $obj->verify( '879364', 0, 'utz4tl3bv5o3disb', 1438643789 ), 1, 'verify(tight) works' ); is( $obj->verify( '879364', 0, 'utz4tl3bv5o3disb', 1438643790 ), 0, 'verify(tight, mis-time) fails' ); is( $obj->verify( '879364', 1, 'utz4tl3bv5o3disb', 1438643790 ), 1, 'verify(loose, mis-time) works' ); is( $obj->verify( '879364', 1, 'utz4tl3bv5o3disb', 1438643820 ), 0, 'verify(loose, mis-time++) fails' ); is( $obj->verify( '879364', 2, 'utz4tl3bv5o3disb', 1438643820 ), 1, 'verify(looser, mis-time++) works' ); done_testing; Auth-GoogleAuth-1.05/t/release-kwalitee.t0000644000175200017520000000050414610313750020210 0ustar gryphongryphon BEGIN { unless ($ENV{RELEASE_TESTING}) { print qq{1..0 # SKIP these tests are for release candidate testing\n}; exit } } # this test was generated with Dist::Zilla::Plugin::Test::Kwalitee 2.12 use strict; use warnings; use Test::More 0.88; use Test::Kwalitee 1.21 'kwalitee_ok'; kwalitee_ok(); done_testing; Auth-GoogleAuth-1.05/t/author-no-tabs.t0000644000175200017520000000112014610313750017623 0ustar gryphongryphon BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::NoTabs 0.15 use Test::More 0.88; use Test::NoTabs; my @files = ( 'lib/Auth/GoogleAuth.pm', 't/00-compile.t', 't/author-eol.t', 't/author-no-tabs.t', 't/author-pod-coverage.t', 't/author-pod-syntax.t', 't/author-portability.t', 't/author-synopsis.t', 't/module.t', 't/release-kwalitee.t' ); notabs_ok($_) foreach @files; done_testing; Auth-GoogleAuth-1.05/META.yml0000644000175200017520000000203214610313750015604 0ustar gryphongryphon--- abstract: 'Google Authenticator TBOT Abstraction' author: - 'Gryphon Shafer ' build_requires: File::Spec: '0' IO::Handle: '0' IPC::Open3: '0' Test2::V0: '0' Test::More: '0' perl: '5.008' configure_requires: ExtUtils::MakeMaker: '0' perl: '5.008' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Auth-GoogleAuth requires: Carp: '0' Class::Accessor: '0' Convert::Base32: '0' Digest::HMAC_SHA1: '0' Math::Random::MT: '0' URI::Escape: '0' base: '0' perl: '5.008' strict: '0' warnings: '0' resources: bugtracker: https://github.com/gryphonshafer/Auth-GoogleAuth/issues homepage: https://github.com/gryphonshafer/Auth-GoogleAuth repository: https://github.com/gryphonshafer/Auth-GoogleAuth.git version: '1.05' x_generated_by_perl: v5.38.2 x_serialization_backend: 'YAML::Tiny version 1.74' x_spdx_expression: Artistic-2.0 Auth-GoogleAuth-1.05/README0000644000175200017520000000051114610313750015213 0ustar gryphongryphonThis archive contains the distribution Auth-GoogleAuth, version 1.05: Google Authenticator TBOT Abstraction This software is Copyright (c) 2015-2050 by Gryphon Shafer. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) This README file was generated by Dist::Zilla::Plugin::Readme v6.031. Auth-GoogleAuth-1.05/lib/0000775000175200017520000000000014610313750015106 5ustar gryphongryphonAuth-GoogleAuth-1.05/lib/Auth/0000775000175200017520000000000014610313750016007 5ustar gryphongryphonAuth-GoogleAuth-1.05/lib/Auth/GoogleAuth.pm0000644000175200017520000002555414610313750020414 0ustar gryphongryphonpackage Auth::GoogleAuth; # ABSTRACT: Google Authenticator TBOT Abstraction use 5.008; use strict; use warnings; use base 'Class::Accessor'; use Digest::HMAC_SHA1 'hmac_sha1_hex'; use Math::Random::MT 'rand'; use URI::Escape 'uri_escape'; use Convert::Base32 qw( encode_base32 decode_base32 ); use Carp 'croak'; our $VERSION = '1.05'; # VERSION my @accessors = qw( secret secret32 issuer key_id otpauth ); __PACKAGE__->mk_accessors(@accessors); sub generate_secret32 { my ($self) = @_; my @chars = ( 'a' .. 'z', 2 .. 7 ); return $self->secret32( join( '', @chars[ map { rand( scalar(@chars) ) } 1 .. 16 ] ) ); } sub clear { my ($self) = @_; $self->$_(undef) for (@accessors); return; } sub qr_code { my ( $self, $secret32, $key_id, $issuer, $return_otpauth ) = @_; $self->_secret_check($secret32); $self->key_id($key_id) if ($key_id); $self->issuer($issuer) if ($issuer); $self->key_id('Undefined') unless ( $self->key_id ); $self->issuer('Undefined') unless ( $self->issuer ); $self->otpauth( 'otpauth://totp/' . uri_escape( $self->issuer ) . ':' . uri_escape( $self->key_id ) . '?secret=' . $self->secret32 . '&issuer=' . uri_escape( $self->issuer ) ); return ($return_otpauth) ? $self->otpauth : 'https://quickchart.io/chart?chs=200x200&cht=qr&chl=' . uri_escape( $self->otpauth ); } sub code { my ( $self, $secret32, $timestamp, $interval ) = @_; $self->_secret_check($secret32); $timestamp ||= time; $interval ||= 30; my $hmac = hmac_sha1_hex( pack( 'H*', sprintf( '%016x', int( $timestamp / $interval ) ) ), _decode_base32( $self->secret32 ), ); return sprintf( '%06d', ( hex( substr( $hmac, hex( substr( $hmac, -1 ) ) * 2, 8 ) ) & 0x7fffffff ) % 1000000 ); } sub verify { my ( $self, $code, $range, $secret32, $timestamp, $interval ) = @_; $self->_secret_check($secret32); $code ||= ''; $range ||= 0; $timestamp ||= time; $interval ||= 30; croak('Range value not zero or a positive number') unless ( $range =~ /^\d+$/ and $range >= 0 ); for ( 0 .. $range ) { return 1 if ( not $_ and $code eq $self->code( $secret32, $timestamp, $interval ) or $code eq $self->code( $secret32, $timestamp + $interval * $_, $interval ) or $code eq $self->code( $secret32, $timestamp - $interval * $_, $interval ) ); } return 0; } sub _secret_check { my ( $self, $secret32 ) = @_; if ($secret32) { $self->secret32($secret32); $self->secret( _decode_base32($secret32) ); } if ( not $self->secret32 ) { if ( not $self->secret ) { $self->secret( _decode_base32( $self->generate_secret32 ) ); } else { $self->secret32( encode_base32( $self->secret ) ); } } return; } sub _decode_base32 { my ($data) = @_; my $rv; eval{ $rv = decode_base32($data) }; croak("Error decoding what should be base32 data: $data") if ( $@ =~ /Data contains non-base32 characters/ ); return $rv; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Auth::GoogleAuth - Google Authenticator TBOT Abstraction =head1 VERSION version 1.05 =for markdown [![test](https://github.com/gryphonshafer/Auth-GoogleAuth/workflows/test/badge.svg)](https://github.com/gryphonshafer/Auth-GoogleAuth/actions?query=workflow%3Atest) [![codecov](https://codecov.io/gh/gryphonshafer/Auth-GoogleAuth/graph/badge.svg)](https://codecov.io/gh/gryphonshafer/Auth-GoogleAuth) =head1 SYNOPSIS use Auth::GoogleAuth; my $auth = Auth::GoogleAuth->new; $auth = Auth::GoogleAuth->new({ secret => 'some secret string thing', issuer => 'Gryphon Shafer', key_id => 'gryphon@cpan.org', }); $auth->secret(); # get/set $auth->secret32(); # get/set $auth->issuer(); # get/set $auth->key_id(); # get/set my $secret32 = $auth->generate_secret32; $auth->clear; my $url_0 = $auth->qr_code; my $url_1 = $auth->qr_code( 'bv5o3disbutz4tl3', # secret32 'gryphon@cpan.org', # key_id 'Gryphon Shafer', # issuer ); my $url_2 = $auth->qr_code( 'bv5o3disbutz4tl3', 'gryphon@cpan.org', 'Gryphon Shafer', 1, ); my $otpauth = $auth->otpauth; my $code_0 = $auth->code; my $code_1 = $auth->code( 'utz4tl3bv5o3disb', 1438643789, 30 ); my $verification_0 = $auth->verify('879364'); my $verification_1 = $auth->verify( '879364', # code 1, # range 'utz4tl3bv5o3disb', # secret32 1438643820, # timestamp (defaults to now) 30, # interval (default 30) ); =head1 DESCRIPTION This module provides a simplified interface to supporting typical two-factor authentication (i.e. "2FA") with L using the L as defined by L. Although Google Authenticator supports both TOTP and HOTP, at the moment, this module only supports TOTP. =head1 METHODS The following are the supported methods of this module: =head2 new This is a simple instantiator to which you can pass optional default values. my $auth = Auth::GoogleAuth->new; $auth = Auth::GoogleAuth->new({ secret => 'some secret string thing', issuer => 'Gryphon Shafer', key_id => 'gryphon@cpan.org', }); The object returned will support the following attribute get/set methods: =head3 secret This can be any string. It'll be used as the internal secret key to create the QR codes and authentication codes. =head3 secret32 This is a base-32 encoded copy of the secret string. If this is left undefined and you run one of the methods that require it (like C or C), the method called will try to create the "secret32" by looking for a value in "secret". If none exists, a random "secret32" will be generated. =head3 issuer This is the label name of the "issuer" of the authentication. See the L for more information. =head3 key_id This is the label name of the "key ID" of the authentication. See the L for more information. =head3 otpauth This method returns the otpauth key URI generated when you call C. =head2 generate_secret32 This method will generate a reasonable random "secret32" value, store it in the get/set method, and return it. my $secret32 = $auth->generate_secret32; =head2 clear Given that the "secret" and "secret32" values may persist in this object, which could be a bad idea in some contexts, this C method lets your clear out all attribute values. $auth->clear; =head2 qr_code This method will return a Quick Chart API URL that will return a QR code based on the data either in the object or provided to this method. my $url_0 = $auth->qr_code; my $url_1 = $auth->qr_code( 'bv5o3disbutz4tl3', # secret32 'gryphon@cpan.org', # key_id 'Gryphon Shafer', # issuer ); You can optionally add a final true value, and if you do, the method will return the generated otpauth key URI rather than the Quick Chart API URL. my $url_2 = $auth->qr_code( 'bv5o3disbutz4tl3', 'gryphon@cpan.org', 'Gryphon Shafer', 1, ); =head2 code This method returns an authentication code, as if you were using L with the "secret32" value. my $code_0 = $auth->code; You can optionally pass override values similar to C: my $code_1 = $auth->code( 'utz4tl3bv5o3disb', # secret32 1438643789, # timestamp (defaults to now) 30, # interval (default 30) ); =head2 verify This method is used for verification of codes entered by a user. Pass in the code (required) and optionally a range value and any override values. my $verification_0 = $auth->verify('879364'); The range value is useful because the algorithm checks codes that are time- based. If clocks are not exactly in sync, it's possible that a "nearly valid" code would be entered and should be accepted as valid but will be seen as invalid. By passing in an integer as a range value, you can stipulate how "fuzzy" the time should be. The default range is 0. A value of 1 will mean that a code based on a time 1 iteration plus or minus should verify. my $verification_1 = $auth->verify( '879364', # code 1, # range 'utz4tl3bv5o3disb', # secret32 1438643820, # timestamp (defaults to now) 30, # interval (default 30) ); =head1 TYPICAL USE-CASE Typically, you're probably going to want to either randomly generate a secret or secret32 (C) for a user and store it, or use a specific value or hash of some value as the secret. In either case, once you have a secret and its stored, generate a QR code (C) for the user. You can alternatively provide the "secret32" to the user for them to manually enter it. That's it for setup. To authenticate, present the user with a way to provide you a code (which will be a series of 6-digits). Verify that code (C) with either no range or some small range like 1. =head1 DEPENDENCIES L, L, L, L, L, L. =head1 SEE ALSO You can look for additional information about this module at: =over 4 =item * L =item * L =item * L =item * L =item * L =item * L =back You can look for additional information about things related to this module at: =over 4 =item * L =item * L =item * L =item * L =item * L =back =head1 AUTHOR Gryphon Shafer =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2015-2050 by Gryphon Shafer. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) =cut Auth-GoogleAuth-1.05/MANIFEST0000644000175200017520000000055614610313750015475 0ustar gryphongryphon# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.031. Changes LICENSE MANIFEST META.json META.yml Makefile.PL README cpanfile dist.ini lib/Auth/GoogleAuth.pm t/00-compile.t t/author-eol.t t/author-no-tabs.t t/author-pod-coverage.t t/author-pod-syntax.t t/author-portability.t t/author-synopsis.t t/module.t t/release-kwalitee.t weaver.ini Auth-GoogleAuth-1.05/LICENSE0000644000175200017520000002153014610313750015344 0ustar gryphongryphonThis software is Copyright (c) 2015-2050 by Gryphon Shafer. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.