Remove debugging from recovery.cgi
[blerg.git] / aux / cgi / recovery.cgi
1 #!/usr/bin/perl
2 use CGI::Fast qw/:cgi/;
3 use Digest::SHA qw/hmac_sha256_base64/;
4 use Blerg::Database;
5 use strict;
6 use v5.10;
7
8 my $hmac_key;
9 open HMAC_KEY, "$ENV{BLERG_HOME}/etc/hmac_key"
10     or die "Could not open $ENV{BLERG_HOME}/etc/hmac_key";
11 read(HMAC_KEY, $hmac_key, 256);
12 close HMAC_KEY;
13
14 sub print_404 {
15     print header(-type => 'text/html',
16                  -status => '404 Not Found');
17     print <<DOC;
18 <!DOCTYPE html>
19 <h1>404 Not Found</h1>
20 DOC
21 }
22
23 sub print_403 {
24     print header(-type => 'text/html',
25                  -status => '403 Forbidden');
26     print <<DOC;
27 <!DOCTYPE html>
28 <h1>403 Forbidden</h1>
29 Please log in first.
30 DOC
31 }
32
33 sub generate_reset_url {
34     my ($username, $validity) = @_;
35
36     # generate reset data
37     my $expiry = time + $validity;
38     my $counter = Blerg::Database::auth_get_counter($username)
39         or return undef;
40     my $data = "$username;$expiry;$counter";
41         
42     # HMAC-SHA256 it
43     my $hmac = hmac_sha256_base64($data, $hmac_key);
44
45     return Blerg::Database::BASEURL . "#/recovery/$data;$hmac";
46 }
47
48 sub validate_reset_data {
49     my ($data) = @_;
50     my ($payload, $hmac);
51
52     if ($data =~ /^(.*);([^;]+)$/) {
53         $payload = $1;
54         $hmac = $2;
55     } else {
56         return undef;
57     }
58
59     my $computed_hmac = hmac_sha256_base64($payload, $hmac_key);
60     if ($hmac ne $computed_hmac) {
61         return undef;
62     }
63
64     my ($username, $expiry, $counter) = split(';', $payload);
65     if (time > $expiry
66         || $counter != Blerg::Database::auth_get_counter($username)) {
67         return undef;
68     }
69
70     return $username;
71 }
72
73 REQUEST:
74 while (my $q = new CGI::Fast) {
75     my (undef, $cmd, $args) = split '/', $ENV{PATH_INFO}, 3;
76
77     given ($cmd) {
78         when ('new') {
79             # determine that authentication is valid.
80             my $auth = $q->cookie('auth');
81             if (!defined $auth) {
82                 print_403;
83                 next REQUEST;
84             }
85             my ($username, $token) = split('/', $auth);
86             if (!Blerg::Database::auth_check_token($username, $token)) {
87                 print_403;
88                 next REQUEST;
89             }
90
91             my $validity = 365 * 86400;     # One year
92             print header(-type => 'text/plain');
93             print generate_reset_url($username, $validity);
94         }
95         when ('mail') {
96             # check that the user has a validated mail address
97             # generate reset message
98             # send mail
99         }
100         when ('validate') {
101             print header(-type => 'application/json');
102
103             my $username = validate_reset_data($q->param('data'));
104
105             if (!defined $username) {
106                 say '{"status": "failure"}';
107                 next REQUEST;
108             }
109
110             my $password = $q->param('password');
111             if (Blerg::Database::auth_set_password($username, $password)) {
112                 say '{"status": "success"}';
113             } else {
114                 say '{"status": "failure"}';
115             }
116         }
117         default {
118             print_404;
119         }
120     }
121 }