added on local at 2026-07-01 16:01:24
| 1 | #!/usr/bin/perl | |
| 2 | #====================================================================== | |
| 3 | # ABForge — login | |
| 4 | # Page body lives in TEMPLATES/abforge_login.html | |
| 5 | # | |
| 6 | # GET : show the login form | |
| 7 | # POST : verify credentials, mint session, set cookie, 302 to /dashboard.cgi | |
| 8 | # on failure, re-render the form with an error | |
| 9 | #====================================================================== | |
| 10 | use strict; | |
| 11 | use warnings; | |
| 12 | ||
| 13 | use lib '/var/www/vhosts/abforge.com/httpdocs'; | |
| 14 | use CGI; | |
| 15 | use MODS::Template; | |
| 16 | use MODS::Login; | |
| 17 | use MODS::ABForge::Wrapper; | |
| 18 | use MODS::ABForge::Config; | |
| 19 | ||
| 20 | my $q = CGI->new; | |
| 21 | my $form = $q->Vars; | |
| 22 | my $auth = MODS::Login->new; | |
| 23 | my $wrap = MODS::ABForge::Wrapper->new; | |
| 24 | my $tfile = MODS::Template->new; | |
| 25 | ||
| 26 | $|=1; | |
| 27 | ||
| 28 | # Already signed in? bounce to the dashboard. | |
| 29 | if (my $existing = $auth->login_verify()) { | |
| 30 | print "Status: 302 Found\nLocation: /dashboard.cgi\n\n"; | |
| 31 | exit; | |
| 32 | } | |
| 33 | ||
| 34 | my $error_msg = ''; | |
| 35 | my $email_val = ''; | |
| 36 | my $flash_msg = ''; | |
| 37 | if (defined $form->{reset} && $form->{reset} eq 'ok') { | |
| 38 | $flash_msg = 'Password updated. Sign in with your new password.'; | |
| 39 | } | |
| 40 | ||
| 41 | # ---------- POST handler ---------- | |
| 42 | if (($ENV{REQUEST_METHOD} || '') eq 'POST') { | |
| 43 | my $email = $form->{email} || ''; | |
| 44 | my $pass = $form->{password} || ''; | |
| 45 | ||
| 46 | my ($userinfo, $token) = $auth->login_exec($email, $pass); | |
| 47 | ||
| 48 | if ($userinfo && $token) { | |
| 49 | # Cookie BEFORE redirect — set-cookie must come before any other header. | |
| 50 | print $auth->set_cookie_header($token); | |
| 51 | print "Status: 302 Found\nLocation: /dashboard.cgi\n\n"; | |
| 52 | exit; | |
| 53 | } | |
| 54 | ||
| 55 | $error_msg = 'Email or password is incorrect.'; | |
| 56 | $email_val = _h($email); | |
| 57 | } | |
| 58 | ||
| 59 | print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n"; | |
| 60 | ||
| 61 | my $tvars = { | |
| 62 | error_msg => $error_msg, | |
| 63 | email_val => $email_val, | |
| 64 | flash_msg => $flash_msg, | |
| 65 | has_flash => length $flash_msg ? 1 : 0, | |
| 66 | }; | |
| 67 | ||
| 68 | my $body = join('', $tfile->template('abforge_login.html', $tvars, undef)); | |
| 69 | ||
| 70 | ||
| 71 | # === Maintenance lockdown overlay (auto-injected 2026-06-23) === | |
| 72 | # When maintenance_locked=1, render a modal over the login form. | |
| 73 | # X-close stays visible so an admin can sign in. Non-admin login | |
| 74 | # attempts fail and the page reloads, restoring the overlay. | |
| 75 | { | |
| 76 | my $_mcfg = MODS::ABForge::Config->new; | |
| 77 | if ($_mcfg->settings('maintenance_locked')) { | |
| 78 | my $_mmsg = $_mcfg->settings('maintenance_message') || '<p>The system is in maintenance mode.</p>'; | |
| 79 | my $_overlay = qq{<div id="maint-overlay" style="position:fixed;inset:0;background:rgba(0,0,0,0.88);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px"><div style="position:relative;background:#0f0f0f;border:1px solid rgba(217,119,6,0.6);border-radius:12px;max-width:680px;width:100%;padding:48px 40px;box-shadow:0 30px 90px rgba(0,0,0,0.6),0 0 0 1px rgba(217,119,6,0.15)"><button type="button" aria-label="Close" onclick="document.getElementById('maint-overlay').style.display='none'" style="position:absolute;top:14px;right:14px;width:36px;height:36px;background:transparent;border:1px solid rgba(255,255,255,0.12);color:#aaa;font-size:22px;line-height:1;border-radius:8px;cursor:pointer">×</button>$_mmsg</div><script>document.addEventListener('keydown',function(e){if(e.key==='Escape'){var o=document.getElementById('maint-overlay');if(o)o.style.display='none';}});</script></div>}; | |
| 80 | $body = $_overlay . $body; | |
| 81 | } | |
| 82 | } | |
| 83 | # === End maintenance lockdown overlay === | |
| 84 | $wrap->render({ | |
| 85 | userinfo => undef, | |
| 86 | title => 'Sign in', | |
| 87 | body => $body, | |
| 88 | }); | |
| 89 | ||
| 90 | #---------------------------------------------------------------------- | |
| 91 | sub _h { | |
| 92 | my $s = shift // ''; | |
| 93 | $s =~ s/&/&/g; $s =~ s/</</g; $s =~ s/>/>/g; | |
| 94 | $s =~ s/"/"/g; $s =~ s/'/'/g; | |
| 95 | return $s; | |
| 96 | } |