-
Notifications
You must be signed in to change notification settings - Fork 3
/
oauth2-helper.pl
executable file
·134 lines (102 loc) · 4.19 KB
/
oauth2-helper.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/perl
use warnings;
use strict;
# See http://billauer.co.il/blog/2022/10/git-send-email-with-oauth2-gmail/
# for how to use this script.
use HTTP::Request::Common qw(POST);
use LWP::UserAgent;
use JSON;
my $reftokenfile = "$ENV{HOME}/.oauth2_reftoken";
my $acctokenfile = "$ENV{HOME}/.oauth2_acctoken";
# These three parameters are taken from Thunderbird's OAuth2Providers.jsm
my $tokenserver = 'https://www.googleapis.com/oauth2/v3/token';
my $client_id = '406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com';
my $client_secret = 'kSmqreRr0qwBWJgbf5Y-PjSU';
###########################################################
if (open(my $fd, "<", $acctokenfile)) {
my $line = <$fd>;
close $fd;
my ($expiry, $token) = ($line =~ /^(\d+):([^\n\r]+)/);
if (defined $expiry) {
if ($expiry > time()) {
print STDERR "Using cached access token in $acctokenfile\n";
print $token;
exit 0;
}
} else {
warn("$acctokenfile exists, but was ignored as it's poorly formatted\n");
}
}
open(my $fd, "<", $reftokenfile) or
die("Failed to open $reftokenfile: $!\n\n".helptext());
my $refresh_token = <$fd>;
close $fd;
$refresh_token =~ s/[ \t\n\r]*//g;
die("No data in $reftokenfile\n\n".helptext())
unless ($refresh_token);
print STDERR "Fetching access token based upon refresh token in $reftokenfile...\n";
my $ua = LWP::UserAgent->new;
my $req = POST $tokenserver,
[
'grant_type' => 'refresh_token',
'client_id' => $client_id,
'client_secret' => $client_secret,
'refresh_token', $refresh_token,
];
my $res = $ua->request($req);
unless ($res->is_success) {
print STDERR "\nFailed to obtain an access token. See transcript:\n";
print STDERR $ua->request($req)->content;
die "\nError: " . $res->status_line . "\n\nIf the error indicates an invalid refresh token (invalid_grant), do as follows:\n".helptext();
}
my $json = $res->content;
my $tree = decode_json($json);
# If "expires_in" doesn't appear in the answer, the access token has is
# valid forever. In theory. In reality, the server will reject it sooner or
# later. So default to a very short time, in order to avoid an authentication
# failure in the SMTP phase.
my $access_token = $tree->{access_token};
my $ttl = $tree->{expires_in} || 120;
my $new_refresh = $tree->{refresh_token};
unless (defined $access_token) {
print STDERR "Huh? A proper response should offer \"access_token\".\n";
print STDERR "Instead, I got just this:\n\n$json\n";
die("Something is seriously wrong. Aborting.\n");
}
if (defined $new_refresh) {
print STDERR << "END";
**************************************************************************
IMPORTANT: The token server returned a refresh token:
$new_refresh
Update the password in Thunderbird as well as $reftokenfile
with this, or subsequent attempts to log in will fail. Alternatively,
attempt to send a mail through the server in Thunderbird, which is likely
to require a renewed login to the account in a browser window.
Note that this came with an access token as well, so it's still possible
to send emails in the next $ttl seconds.
**************************************************************************
END
}
my $expiry = time() + $ttl - 30; # 30 seconds room for Internet delays
umask 0077; # Create file accessible by user only
if (open (my $out, ">", $acctokenfile)) {
print $out "$expiry:$access_token\n";
close $out;
} else {
warn("Failed to open $acctokenfile for write, access token is hence not saved:\n$!\n");
}
print $access_token; # This is the whole purpose of this script
exit 0;
#######################################################################
sub helptext {
return << "TEXT";
First, make sure that Thunderbird has access to the mail account itself,
possibly by attempting to send an email through the relevant server.
Then go to Thunderbird's Preferences > Privacy & Security and click on Saved
Passwords. Look for the account, where the Provider start with oauth://.
Right click that line and choose "Copy Password". Paste that blob into
$reftokenfile (instead of what it is now).
Note that access to this file gives anyone full access to your email account.
To mitigate this inherent security risk, change its permissions to 0600.
TEXT
}