]> iEval git - gruntmaster-page.git/commitdiff
Merge branch 'master' into newmc
authorMarius Gavrilescu <marius@ieval.ro>
Mon, 2 Mar 2015 15:08:18 +0000 (17:08 +0200)
committerMarius Gavrilescu <marius@ieval.ro>
Mon, 2 Mar 2015 15:08:18 +0000 (17:08 +0200)
Conflicts:
js/90-themes.js
tmpl/skel.en

Makefile.PL
a/account.en
app.psgi
js/90-themes.js
lib/Plack/App/Gruntmaster.pm
lib/Plack/App/Gruntmaster/Auth.pm [new file with mode: 0644]
make_static.PL [new file with mode: 0644]
static/gm.css [deleted file]
tmpl/skel.en

index 796f5d7ee2bf802bf58c8b5512aef5bf95448446..2f3a50f2784e73f70334031e465446dc62ca0723 100644 (file)
@@ -9,14 +9,19 @@ WriteMakefile(
        MIN_PERL_VERSION  => '5.14.0',
        LICENSE           => 'AGPL_3',
        SIGN              => 1,
+       clean             => {
+               FILES => 'static/css/ static/js.js'
+       },
        BUILD_REQUIRES    => {
-               qw/Test::MockTime             0
+               qw/CSS::Minifier::XS          0
+                  File::Slurp                0
+                  JavaScript::Minifier::XS   0
+                  Test::MockTime             0
                   Test::More                 0
                   Test::WWW::Mechanize::PSGI 0/,
        },
        PREREQ_PM         => {
                qw/Carp        0
-                  Digest::SHA 0
                   Encode      0
                   List::Util  0
                   POSIX       0
@@ -26,22 +31,19 @@ WriteMakefile(
                   strict      0
                   warnings    0
 
-                  CSS::Minifier::XS           0
-                  Email::Simple               0
-                  Email::Sender::Simple       0
-                  File::Slurp                 0
-                  Gruntmaster::Data           0
-                  HTML::Seamstress            0
-                  JavaScript::Minifier::XS    0
-                  JSON::MaybeXS               0
-                  Log::Log4perl               0
-                  PerlX::Maybe                0
-                  Plack::Builder              0
-                  Plack::Request              0
-                  Plack::Util                 0
-                  Scope::Upper                0
-                  Tie::Hash::Expire           0
-                  Web::Simple                 0.019/,
+                  Email::Simple                    0
+                  Email::Sender::Simple            0
+                  File::Slurp                      0
+                  Gruntmaster::Data                0
+                  HTML::Seamstress                 0
+                  JSON::MaybeXS                    0
+                  Log::Log4perl                    0
+                  PerlX::Maybe                     0
+                  Plack::Builder                   0
+                  Plack::Middleware::Auth::Complex 0
+                  Plack::Util                      0
+                  Scope::Upper                     0
+                  Web::Simple                      0.019/,
        },
        META_MERGE        => {
                dynamic_config => 0,
index 422b94991eb7db62fd9f8b13e31d9305e48de180..6c1b8cce5afc88c3b6680a89cebdcae33f3cf963 100644 (file)
 <h1>Reset password</h1>
 <form action="/action/reset" method="POST" class="jsform" role="form">
 <div class="form-group"><label for="rst_username">Username</label><input type="text" id="rst_username" name="username" class="form-control" required></div>
-<div class="form-group"><label for="rst_password">New password</label><input type="password" id="rst_password" name="password" class="form-control" required></div>
+<div class="form-group"><label for="rst_new_password">New password</label><input type="password" id="rst_new_password" name="new_password" class="form-control" required></div>
+<div class="form-group"><label for="rst_confirm_new_password">Confirm new password</label><input type="password" id="rst_confirm_new_password" name="confirm_new_password" class="form-control" required></div>
 <div class="form-group"><label for="rst_token">Reset token</label><input type="text" id="rst_token" name="token" class="form-control" required></div>
 <input type="submit" class="btn btn-default" value="Reset password">
 </form>
index 728e144e4cf0b742cf7f22765925419d51f350e1..be72e9b18b9bd2fa4dd7ea7317d41d84a44e035c 100644 (file)
--- a/app.psgi
+++ b/app.psgi
@@ -5,11 +5,8 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch';
 use Gruntmaster::Data;
 use Plack::App::Gruntmaster;
 use Plack::Builder;
-use Plack::Request;
 use Plack::Util;
-use Digest::SHA qw/sha256/;
 use Log::Log4perl;
-use Tie::Hash::Expire;
 
 use constant AUTH_TIMEOUT => 5 * 60;
 use constant ACCESSLOG_FORMAT => '%{X-Forwarded-For}i %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"';
@@ -22,8 +19,8 @@ form-action 'self'
 frame-ancestors 'none'
 img-src 'self' https://static.mindcoding.ro https://www.google-analytics.com/collect
 referrer origin-when-cross-origin
-script-src https://static.mindcoding.ro/js.js https://www.google-analytics.com/analytics.js
-style-src https://static.mindcoding.ro/css/
+script-src https://static.mindcoding.ro/static/js.js https://www.google-analytics.com/analytics.js
+style-src https://static.mindcoding.ro/static/css/
 CSP
        chomp $csp;
        $csp =~ s/\n/; /gr;
@@ -31,17 +28,6 @@ CSP
 
 my $db;
 
-tie my %auth, 'Tie::Hash::Expire', {expire_seconds => AUTH_TIMEOUT};
-
-sub authenticate {
-       my ($user, $pass, $env) = @_;
-       my $key = sha256 "$user:$pass";
-       $env->{'gruntmaster.user'} = $user;
-       return 1 if exists $auth{$key};
-       return unless $db->user($user) && $db->user($user)->check_passphrase($pass);
-       $auth{key} = 1;
-}
-
 sub add_database {
        my $app = $_[0];
        sub {
@@ -76,6 +62,9 @@ builder {
        enable 'Static', path => qr,^/static/,;
        enable 'Log4perl', category => 'plack';
        enable \&add_database;
-       enable_if { shift->{HTTP_AUTHORIZATION} } 'Auth::Basic', authenticator => \&authenticate, realm => 'Gruntmaster 6000';
+       enable '+Plack::App::Gruntmaster::Auth',
+         dbi_connect => [$ENV{GRUNTMASTER_DSN} // 'dbi:Pg:', '', ''],
+         realm       => 'Gruntmaster 6000',
+         mail_from   => $ENV{GRUNTMASTER_RESET_FROM};
        Plack::App::Gruntmaster->run_if_script
 }
index 3c5d5c57b5f82db72b7b5310ae10d8560dfaa164..b7d73221bc1a255a63c1f6570a0e1fd9ecc0d045 100644 (file)
@@ -1,7 +1,7 @@
 (function(){
        'use strict';
        function set_style(name){
-               $('#stylesheet').attr("href", "https://static.mindcoding.ro/css/" + name + ".css");
+               $('#stylesheet').attr("href", "https://static.mindcoding.ro/static/css/" + name + ".css");
                localStorage.setItem("theme", name);
                $(document).ready(function() {
                        if(name == 'slate' || name == 'cyborg')
index 3a7b9db121302ed83d9dcba510193693050324cb..35d788e8887c7e5589c38ffd19d3b80d7fe66e06 100644 (file)
@@ -4,10 +4,8 @@ use 5.014000;
 use strict;
 our $VERSION = '5999.000_001';
 
-use CSS::Minifier::XS;
 use Encode qw/encode decode/;
 use File::Slurp qw/read_file/;
-use JavaScript::Minifier::XS;
 use JSON::MaybeXS qw/encode_json/;
 use PerlX::Maybe;
 use Scope::Upper qw/unwind SUB UP/;
@@ -54,16 +52,13 @@ use constant FORMAT_EXTENSION => {
 };
 
 use constant NOT_FOUND => [404, ['X-Forever' => 1, 'Content-Type' => 'text/plain'], ['Not found']];
-use constant FORBIDDEN => [401, ['Content-Type' => 'text/plain', 'WWW-Authenticate' => 'Basic realm="Gruntmaster 6000"'], ['Forbidden']];
-
-sub development() { ($ENV{PLACK_ENV} // 'development') eq 'development' }
 
 my ($env, $privacy);
 
 sub db { $env->{'gruntmaster.dbic'} }
 
 sub remote_user {
-       my $user = $env->{'gruntmaster.user'};
+       my $user = $env->{REMOTE_USER};
        $user &&= db->user($user);
        $user
 }
@@ -91,7 +86,7 @@ sub forbid {
        my ($condition) = @_;
        $privacy = 'private' if $condition;
        return if !$condition || admin;
-       unwind FORBIDDEN, SUB UP
+       unwind $env->{authcomplex}->unauthorized, SUB UP
 }
 
 sub dispatch_request{
@@ -99,22 +94,6 @@ sub dispatch_request{
        $privacy = 'public';
 
        sub (GET) {
-               sub (/css/:theme) {
-                       my $theme = $_{theme};
-                       return NOT_FOUND unless -e "css/themes/$theme.css";
-                       my $css = read_file "css/themes/$theme.css";
-                       $css .= read_file $_ for <css/*.css>;
-                       my @headers = ('X-Forever' => 1, 'Cache-Control' => 'public, max-age=604800', 'Content-Type' => 'text/css; charset=utf-8');
-                       [200, \@headers, [development ? $css : CSS::Minifier::XS::minify $css]]
-               },
-
-               sub (/js.js) {
-                       my $js;
-                       $js .= read_file $_ for <js/*.js>;
-                       my @headers = ('X-Forever' => 1, 'Cache-Control' => 'public, max-age=604800', 'Content-Type' => 'application/javascript; charset=utf-8');
-                       [200, \@headers, [development ? $js : JavaScript::Minifier::XS::minify $js]]
-               },
-
                sub (/robots.txt) { NOT_FOUND },
 
                sub (/src/:job) {
@@ -217,26 +196,6 @@ sub dispatch_request{
        },
 
        sub (POST) {
-               sub (/action/register + %:username=&:password=&:confirm_password=&:name=&:email=&:phone=&:town=&:university=&:country=&:level=) {
-                       return reply 'Parameter too long' if grep { length > 200 } values %_;
-                       return reply 'Bad username. Allowed characters are letters, digits and underscores, and the username must be between 2 and 20 characters long.' unless $_{username} =~ USER_REGEX;
-                       return reply 'Username already in use' if db->user($_{username});
-                       return reply 'The two passwords do not match' unless $_{password} eq $_{confirm_password};
-
-                       db->users->create({id => $_{username}, name => $_{name}, email => $_{email}, phone => $_{phone}, town => $_{town}, university => $_{university}, country => $_{country}, level => $_{level}});
-                       db->user($_{username})->set_passphrase($_{password});
-
-                       reply 'Registered successfully';
-               },
-
-               sub (/action/passwd + %:password=&:new_password=&:confirm_new_password=) {
-                       forbid !remote_user;
-                       return reply 'Incorrect password' unless remote_user->check_passphrase($_{password});
-                       return reply 'The two passwords do not match' unless $_{new_password} eq $_{confirm_new_password};
-                       remote_user->set_passphrase($_{new_password});
-                       reply 'Password changed successfully';
-               },
-
                sub (/action/submit + %:problem=&:contest~&:prog_format=&:source_code~ + *prog~) {
                        my (undef, undef, $prog) = @_;
                        forbid !remote_user;
@@ -264,51 +223,6 @@ sub dispatch_request{
 
                        [303, [Location => '/log/' . $newjob->id], []]
                },
-
-               sub (/action/request-reset + %:username=) {
-                       return reply 'Password resets are disabled' unless $ENV{GRUNTMASTER_RESET_FROM};
-                       my $user = db->user($_{username});
-                       return reply 'No such user' unless $user;
-                       my $token = join ':', $user->make_reset_hmac;
-                       my $body = <<EOF;
-Someone has requested a password reset for your account.
-
-To reset your password, please submit the reset password form on the
-website using the following information:
-
-Username: $_{username}
-Password: <your new password>
-Reset token: $token
-
-The token is valid for 24 hours.
-EOF
-                       my $email = Email::Simple->create(
-                               header => [
-                                       From    => $ENV{GRUNTMASTER_RESET_FROM},
-                                       To      => $user->email,
-                                       Subject => 'Password reset token',
-                               ],
-                               body => $body,
-                       );
-
-                       my $ok = 0;
-                       eval {
-                               sendmail $email;
-                               $ok = 1;
-                       };
-                       return reply 'Email sent' if $ok;
-                       reply "Failure sending email: $@";
-               },
-
-               sub (/action/reset + %:username=&:password=&:token=) {
-                       my $user = db->user($_{username});
-                       return reply 'No such user' unless $user;
-                       my ($token, $exp) = split ':', $_{token};
-                       return reply 'Reset token is expired' if time >= $exp;
-                       return reply 'Bad reset token' unless $user->make_reset_hmac($exp) eq $token;
-                       $user->set_passphrase($_{password});
-                       reply 'Password reset successfully';
-               },
        }
 }
 
diff --git a/lib/Plack/App/Gruntmaster/Auth.pm b/lib/Plack/App/Gruntmaster/Auth.pm
new file mode 100644 (file)
index 0000000..40ff41b
--- /dev/null
@@ -0,0 +1,24 @@
+package Plack::App::Gruntmaster::Auth;
+
+use 5.014000;
+use strict;
+our $VERSION = '5999.000_001';
+
+use parent qw/Plack::Middleware::Auth::Complex/;
+
+sub call_register {
+       my ($self, $req) = @_;
+       return $self->bad_request('Parameter too long') if grep { length > 100 } $req->parameters->values;
+
+       $self->SUPER::call_register($req);
+}
+
+sub create_user {
+       my ($self, $parms) = @_;
+       my %parms = $parms->flatten;
+       my $sth = $self->{dbh}->prepare_cached('INSERT INTO users (id, name, email, phone, town, university, country, level, passphrase) VALUES (?,?,?,?,?,?,?,?,?)');
+       $sth->execute(@parms{qw/username name email phone town university country level/}, $self->hash_passphrase($parms{password}));
+}
+
+1;
+__END__
diff --git a/make_static.PL b/make_static.PL
new file mode 100644 (file)
index 0000000..a47df2d
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+
+use CSS::Minifier::XS qw//;
+use JavaScript::Minifier::XS qw//;
+
+use File::Slurp qw/read_file write_file/;
+
+mkdir 'static';
+mkdir 'static/css';
+
+my $common_css;
+$common_css .= read_file $_ for <css/*.css>;
+for (<css/themes/*>) {
+       my ($theme) = m,themes/(.*)\.css,;
+       my $css = read_file $_;
+       $css .= $common_css;
+       write_file "static/css/$theme.css", CSS::Minifier::XS::minify $css;
+}
+
+my $js;
+$js .= read_file $_ for <js/*.js>;
+write_file 'static/js.js', JavaScript::Minifier::XS::minify $js;
diff --git a/static/gm.css b/static/gm.css
deleted file mode 100644 (file)
index f87a30c..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-html,body{
-       background-color: black;
-       color: white;
-}
-
-div#title,div#subtitle{
-       font-family: "Liberation Mono","DejaVu Sans Mono","Lucida Console",monospace;
-       font-weight: bold;
-       text-align: center;
-       padding: 0;
-       margin: 0;
-}
-
-div#title{
-       font-size: 7em;
-}
-
-div#subtitle{
-       font-size: 3em;
-}
-
-div#result{
-       padding: 0.5em;
-       text-align: center;
-/*     border: thin dotted white; */
-}
-
-textarea{
-       width: 100%;
-       height: 10em;
-       display: block;
-}
-
-table,td,th{
-       text-align: center;
-       border-collapse: collapse;
-       border: thin dotted white;
-       padding: 0.1em;
-}
-
-table{
-       width: 98%;
-       margin: 1%
-}
-
-table.upsstats{
-       width: auto;
-       margin: 1em auto;
-}
-
-table.upsstats table, table.upsstats table tr, table.upsstats table th, table.upsstats table td { 
-       border-width: 0;
-       width: auto;
-}
-
-a:link,a:visited{
-       color: white;
-}
-
-table.alternating>tbody>tr:nth-child(odd){
-       background-color: #222;
-}
-
-span.i{
-       color: #F00;
-}
-
-span.Eval{
-       color: #0F0;
-}
-
-div.centertext{
-       text-align: center;
-}
-
-h1.nomargintop{
-       margin-top: 0;
-}
-
-span.yes{
-       color: #0F0;
-}
-
-span.no{
-       color: #F00;
-}
-
-span.lowyes{
-       color: #8F8;
-}
-
-td.size{
-       color: #EEE;
-       font-size: 0.9em;
-}
-
-ul.stats{
-       margin:0;
-       padding:0;
-}
-
-ul.stats li{
-       display: inline-block;
-       margin-right: 1em;
-}
-
-a.nounderline:link{
-       text-decoration: none;
-}
-
-td.r0{
-       color: green;
-}
-
-td.r10{
-       color: gold;
-}
-
-td.r1{
-       color: darkred;
-}
-
-td.r3{
-       color: aqua;
-}
-
-td.r-1{
-       color: red;
-}
-
-table.sample, table.sample th, tample.sample td{
-       width: auto;
-       vertical-align: top;
-       margin: 0;
-       padding: 0.2em 1em;
-       text-align: left !important;
-}
-
-nav ul{
-       list-style: none;
-       padding: 0;
-       text-align: center;
-}
-
-nav li a{
-       padding: 0.5em;
-       display: inline-block;
-       text-decoration: none;
-}
-
-nav li{
-       margin: 0.5em;
-       background-color: #222;
-       display: inline-block;
-       border: thin dotted white;
-}
-
-nav li:hover{
-       background-color: #444;
-}
-
-footer{
-       width: 60em;
-       margin: auto;
-       margin-top: 6em;
-       white-space: pre-wrap;
-       font-size: 75%;
-       color: #777;
-}
-
-a.disabled{
-       pointer-events: none;
-       text-decoration: none;
-}
-
-#admin{
-       font-size: 75%;
-       color: #777;
-       position: absolute;
-       top: 1px;
-       right: 1px;
-}
index 17804ad0eff9098e9c8eb205c8e97008c476a84b..1f7f60e8aa8e30ffefac3777b04873d0720bf43c 100644 (file)
@@ -3,8 +3,8 @@
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
-<link rel="stylesheet" href="https://static.mindcoding.ro/css/slate.css" id="stylesheet">
-<script src="https://static.mindcoding.ro/js.js" type="text/javascript" async defer></script>
+<link rel="stylesheet" href="https://static.mindcoding.ro/static/css/cyborg.css" id="stylesheet">
+<script src="https://static.mindcoding.ro/static/js.js" type="text/javascript" async defer></script>
 
 <body>
 <nav role="navigation">
This page took 0.056445 seconds and 4 git commands to generate.