File Coverage

blib/lib/GitHub/Authorization.pm
Criterion Covered Total %
statement 33 54 61.1
branch 0 6 0.0
condition 0 6 0.0
subroutine 11 16 68.7
pod 3 3 100.0
total 47 85 55.2


line stmt bran cond sub pod time code
1             #
2             # This file is part of GitHub-Authorization
3             #
4             # This software is Copyright (c) 2012 by Chris Weyl.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package GitHub::Authorization;
11             {
12             $GitHub::Authorization::VERSION = '0.001';
13             }
14              
15             # ABSTRACT: Generate a GitHub OAuth2 non-web authorization token
16              
17 1     1   27516 use strict;
  1         4  
  1         42  
18 1     1   6 use warnings;
  1         3  
  1         33  
19 1     1   6 use Carp 'confess';
  1         1  
  1         78  
20              
21 1     1   961 use autobox::JSON;
  1         37596  
  1         10  
22 1     1   1973 use HTTP::Tiny;
  1         72780  
  1         47  
23 1     1   1031 use MIME::Base64;
  1         1013  
  1         79  
24 1     1   911 use Params::Validate ':all';
  1         12375  
  1         255  
25              
26             # for SSL and SSL CA verification
27 1     1   1466 use IO::Socket::SSL 1.56;
  1         58588  
  1         8  
28 1     1   1133 use Mozilla::CA;
  1         304  
  1         33  
29              
30 1     1   1001 use namespace::clean;
  1         12859  
  1         8  
31              
32 1         8 use Sub::Exporter::Progressive -setup => {
33             exports => [ qw{ is_legal_scope legal_scopes get_gh_token } ],
34 1     1   605 };
  1         2  
35              
36             # debugging...
37             #use Smart::Comments '###';
38              
39             sub _default_agent {
40 0   0 0     'GitHub::Authorization/'
41             . (__PACKAGE__->VERSION || 0)
42             . q{ }
43             }
44              
45 0     0     sub _url { 'https://api.github.com' . shift }
46              
47              
48             sub get_gh_token {
49              
50 0     0 1   my %_opt = ( type => SCALAR | UNDEF, optional => 1 );
51 0           my %args = validate @_ => {
52             user => { type => SCALAR, regex => qr/^[A-Za-z0-9\.@]+$/ },
53             password => { type => SCALAR },
54             scopes => { type => ARRAYREF, default => [ ] },
55              
56             # optional args
57             note => { %_opt },
58             note_url => { %_opt },
59             client_id => { %_opt, regex => qr/^[a-f0-9]{20}$/ },
60             client_secret => { %_opt, regex => qr/^[a-f0-9]{40}$/ },
61             };
62              
63 0           my ($user, $password, $scopes) = delete @args{qw{user password scopes}};
64              
65 0   0       $scopes ||= [];
66              
67 0           my @illegal =
68 0           map { "illegal_scope: $_" }
69 0           grep { ! is_legal_scope($_) }
70             @$scopes;
71              
72 0 0         confess "Bad scopes: @illegal"
73             if @illegal;
74              
75 0 0         $args{scopes} = $scopes
76             if @$scopes;
77              
78             # now, to the real stuff
79              
80 0           my $ua = HTTP::Tiny->new(
81             agent => _default_agent,
82             verify_SSL => 1,
83             );
84              
85 0           my $url = _url('/authorizations');
86 0           my $hash = MIME::Base64::encode_base64("$user:$password", '');
87 0           my $headers = { Authorization => 'Basic ' . $hash };
88 0           my $content = { scopes => $scopes, %args };
89              
90             ### $url
91             ### $headers
92             ### $content
93              
94 0           my $res = $ua->post($url, {
95             headers => $headers,
96             content => $content->to_json,
97             });
98              
99             ### $res;
100              
101 0 0         confess "Failed: $res->{status}/$res->{reason} / " . $res->{content}->from_json->{message}
102             unless $res->{success};
103              
104 0           return $res->{content}->from_json;
105             }
106              
107              
108             {
109             my %scopes =
110             map { $_ => 1 }
111             qw{
112             user user:email user:follow public_repo repo repo:status
113             delete_repo notifications gist
114             }, q{}
115             ;
116              
117 0     0 1   sub legal_scopes { sort keys %scopes }
118 0   0 0 1   sub is_legal_scope { $scopes{shift || q{}} }
119             }
120              
121             !!42;
122              
123             __END__