accept subscriptions, send confirmation emails

This commit is contained in:
Al Beano 2016-09-02 19:48:35 +01:00
parent 61de0371b1
commit eeaca1c333
6 changed files with 116 additions and 5 deletions

View File

@ -6,11 +6,14 @@ chown www:www /var/www/run
install -o www -g www -m 0400 httpd.conf /etc/
echo "permit nopass root as www" >> /etc/doas.conf
curl -L https://cpanmin.us | perl - App::cpanminus
cpanm -l /var/www/perl5 FCGI Switch Template::Simple File::Slurp Email::Valid
cpanm -l /var/www/perl5 FCGI Switch Template::Simple File::Slurp Email::Valid DBD::SQLite Math::Random::Secure Email::Sender::Simple Email::Simple Email::Simple::Creator Email::Sender::Transport::SMTPS YAML::Tiny
install -o www -g www -m 0500 tormon/* /var/www/tormon/
cat db.sql | sqlite3 /var/www/tormon.db
chown www:www /var/www/tormon.db
chown www:www /var/www
chmod 0600 /var/www/tormon.db
install -o www -g www -m 0400 tormon.yml /var/www/
# customise the values in /var/www/tormon.yml to your liking...
echo 'echo "Starting tormon" && doas -u www /var/www/tormon/tormon.fcgi &' >> /etc/rc.local
sh /etc/rc.local # assuming tormon is the only thing in rc.local
rcctl enable httpd

7
db.sql
View File

@ -1,6 +1,7 @@
create table users (
id int primary key not null,
id integer primary key,
email text not null,
confirmed int not null,
subscriptions text
confirmed integer not null,
fp text not null,
secret text
);

7
tormon.yml Normal file
View File

@ -0,0 +1,7 @@
baseurl: http://localhost:8080 # not including trailing /
mail:
# STARTTLS encryption is used
host: smtp.sparkpostmail.com
port: 587
user: SMTP_Injection
password: yourapikey

2
tormon/confirm.tt Normal file
View File

@ -0,0 +1,2 @@
<h1>Thank you</h1>
Your email address has been confirmed.

7
tormon/subscribe.tt Normal file
View File

@ -0,0 +1,7 @@
<h1>Success</h1>
<p>
You should receive a confirmation email shortly. Click the link to activate notifications.
</p>
<p>
<a href="/">&laquo; Go back</a>
</p>

View File

@ -7,15 +7,41 @@ use Switch;
use File::Slurp;
use Template::Simple;
use Email::Valid;
use DBI;
use Math::Random::Secure qw(rand);
use Email::Sender::Simple qw(sendmail);
use Email::Simple;
use Email::Simple::Creator;
use Email::Sender::Transport::SMTPS;
use YAML::Tiny;
use POSIX;
use FindBin qw($Bin);
my $VERSION = "1.0";
sub logmsg {
my $msg = shift;
return strftime("%F %T", localtime $^T)." $msg";
}
sub rand_string {
my $ret;
my @alpha = "a".."z";
for (1..16) {
$ret .= $alpha[int(rand(26))];
}
return $ret;
}
my $dbh = DBI->connect("dbi:SQLite:dbname=/var/www/tormon.db", "", "");
my $tmpl = new Template::Simple (
pre_delim => "<%",
post_delim => "%>",
);
my $config = YAML::Tiny->read("/var/www/tormon.yml")->[0] or die $!;
my $sock = FCGI::OpenSocket(
"/var/www/run/tormon.sock",
5,
@ -24,12 +50,14 @@ my $sock = FCGI::OpenSocket(
my $request = FCGI::Request(
\*STDIN,
\*STDOUT,
\*STDERR,
\*STDOUT,
\%ENV,
$sock,
0,
);
say logmsg "tormon v$VERSION now accepting requests";
while ($request->Accept() <= 0) {
my $content;
my $code;
@ -65,6 +93,69 @@ while ($request->Accept() <= 0) {
}
# Add the email to database
my $secret = rand_string();
my $sth = $dbh->prepare("insert into users (email, confirmed, fp, secret)
values (?, 0, ?, ?);");
$sth->bind_param(1, $input{"email"});
$sth->bind_param(2, $input{"fp"});
$sth->bind_param(3, $secret);
$sth->execute;
my $id = $dbh->last_insert_id("", "", "", "");
# A confirmation email
# TODO: async magic
my $email = Email::Simple->create(
header => [
To => $input{"email"},
From => '"Tor Relay Monitor" <tormon@tor.uptime.party>',
Subject => "Confirm your email",
],
body => "Hi,\n\nSomebody entered your email into the Tor relay monitor. If this was you, please click the link below to activate notifications.\n\n$config->{baseurl}/confirm?id=$id&s=$secret\n\nIf this wasn't you, just delete this email. If you'd like to contact the administrator, please send an email to albino\@autistici.org.\n",
);
my $trans = new Email::Sender::Transport::SMTPS (
host => $config->{mail}->{host},
port => $config->{mail}->{port},
ssl => "starttls",
sasl_username => $config->{mail}->{user},
sasl_password => $config->{mail}->{password},
debug => 0,
);
sendmail($email, {
transport => $trans,
});
$content = read_file("$Bin/subscribe.tt");
$code = "\n";
}
case (/^\/confirm\?id=([0-9]+)&s=([a-z]{16})$/) {
# limit scope or something
if ($ENV{REQUEST_URI} =~ /^\/confirm\?id=([0-9]+)&s=([a-z]{16})$/) {
my $id = $1;
my $secret = $2;
my $q = $dbh->prepare("select * from users where id=? and secret=?");
$q->bind_param(1, $id);
$q->bind_param(2, $secret);
$q->execute;
my $href = $q->fetchrow_hashref;
if ($q->rows != 1) {
$code = "Status: 403 Forbidden";
my $tt = read_file("$Bin/error.tt");
$content = ${ $tmpl->render($tt, {err => 403}) };
last;
}
$q->finish;
$q = $dbh->prepare("update users set confirmed=1 where id=? and secret=?");
$q->bind_param(1, $id);
$q->bind_param(2, $secret);
$q->execute;
$q->finish;
$content = read_file("$Bin/confirm.tt");
}
$code = "\n";
}
else {
my $tt = read_file("$Bin/error.tt");