#!/usr/bin/perl use CGI::Fast qw/:cgi/; use Digest::SHA qw/hmac_sha256_base64/; use Blerg::Database; use strict; use v5.10; my $hmac_key; open HMAC_KEY, "$ENV{BLERG_HOME}/etc/hmac_key" or die "Could not open $ENV{BLERG_HOME}/etc/hmac_key"; read(HMAC_KEY, $hmac_key, 256); close HMAC_KEY; sub print_404 { print header(-type => 'text/html', -status => '404 Not Found'); print <

404 Not Found

DOC } sub print_403 { print header(-type => 'text/html', -status => '403 Forbidden'); print <

403 Forbidden

Please log in first. DOC } sub generate_reset_url { my ($username, $validity) = @_; # generate reset data my $expiry = time + $validity; my $counter = Blerg::Database::auth_get_counter($username) or return undef; my $data = "$username;$expiry;$counter"; # HMAC-SHA256 it my $hmac = hmac_sha256_base64($data, $hmac_key); return Blerg::Database::BASEURL . "#/recovery/$data;$hmac"; } sub validate_reset_data { my ($data) = @_; my ($payload, $hmac); if ($data =~ /^(.*);([^;]+)$/) { $payload = $1; $hmac = $2; } else { return undef; } my $computed_hmac = hmac_sha256_base64($payload, $hmac_key); if ($hmac ne $computed_hmac) { return undef; } my ($username, $expiry, $counter) = split(';', $payload); if (time > $expiry || $counter != Blerg::Database::auth_get_counter($username)) { return undef; } return $username; } REQUEST: while (my $q = new CGI::Fast) { my (undef, $cmd, $args) = split '/', $ENV{PATH_INFO}, 3; given ($cmd) { when ('new') { # determine that authentication is valid. my $auth = $q->cookie('auth'); if (!defined $auth) { print_403; next REQUEST; } my ($username, $token) = split('/', $auth); if (!Blerg::Database::auth_check_token($username, $token)) { print_403; next REQUEST; } my $validity = 365 * 86400; # One year print header(-type => 'text/plain'); print generate_reset_url($username, $validity); } when ('mail') { # check that the user has a validated mail address # generate reset message # send mail } when ('validate') { print header(-type => 'application/json'); my $username = validate_reset_data($q->param('data')); if (!defined $username) { say '{"status": "failure"}'; next REQUEST; } my $password = $q->param('password'); if (Blerg::Database::auth_set_password($username, $password)) { say '{"status": "success"}'; } else { say '{"status": "failure"}'; } } default { print_404; } } }