Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/sessions.cgi
Diff

/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/sessions.cgi

added on local at 2026-07-01 21:47:18

Added
+111
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to e0d0f1d56aec
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2#======================================================================
3# RePricer -- active sessions / device management.
4#
5# GET /sessions.cgi list active sessions for this user
6# POST act=revoke id=UUID revoke one session by id
7# POST act=revoke_all revoke every session EXCEPT the current one
8#======================================================================
9use strict;
10use warnings;
11use lib '/var/www/vhosts/3dshawn.com/repricer.3dshawn.com';
12use CGI;
13use MODS::DBConnect;
14use MODS::Login;
15use MODS::RePricer::Config;
16use MODS::RePricer::Wrapper;
17
18$|=1;
19my $q = CGI->new;
20my $form = $q->Vars;
21my $auth = MODS::Login->new;
22my $wrap = MODS::RePricer::Wrapper->new;
23my $db = MODS::DBConnect->new;
24my $cfg = MODS::RePricer::Config->new;
25my $DB = $cfg->settings('database_name');
26
27my $userinfo = $auth->login_verify();
28unless ($userinfo) { print "Status: 302 Found\nLocation: /login.cgi\n\n"; exit; }
29my $uid = $userinfo->{user_id}; $uid =~ s/[^0-9]//g;
30my $sid = $userinfo->{session_id}; $sid =~ s/[^a-zA-Z0-9\-]//g;
31
32sub _h { my $s = shift // ''; $s =~ s/&/&amp;/g; $s =~ s/</&lt;/g; $s =~ s/>/&gt;/g; $s =~ s/"/&quot;/g; $s }
33
34my $dbh = $db->db_connect();
35my $flash = '';
36if (($ENV{REQUEST_METHOD} || '') eq 'POST') {
37 my $act = $form->{act} || '';
38 if ($act eq 'revoke') {
39 my $target = $form->{id} || ''; $target =~ s/[^a-zA-Z0-9\-]//g;
40 if ($target && $target ne $sid) {
41 $db->db_readwrite($dbh, qq~
42 UPDATE `${DB}`.user_sessions SET revoked_at=NOW()
43 WHERE id='$target' AND user_id='$uid'
44 ~, $ENV{SCRIPT_NAME}, __LINE__);
45 $flash = 'Session revoked.';
46 }
47 } elsif ($act eq 'revoke_all') {
48 $db->db_readwrite($dbh, qq~
49 UPDATE `${DB}`.user_sessions SET revoked_at=NOW()
50 WHERE user_id='$uid' AND id<>'$sid' AND revoked_at IS NULL
51 ~, $ENV{SCRIPT_NAME}, __LINE__);
52 $flash = 'All other sessions revoked.';
53 }
54}
55
56my $rows = $db->db_readwrite_multiple($dbh, qq~
57 SELECT id, ip_address, user_agent, issued_at, expires_at,
58 TIMESTAMPDIFF(MINUTE, issued_at, NOW()) AS mins_old
59 FROM `${DB}`.user_sessions
60 WHERE user_id='$uid' AND revoked_at IS NULL AND expires_at > NOW()
61 ORDER BY issued_at DESC
62~, $ENV{SCRIPT_NAME}, __LINE__);
63$db->db_disconnect($dbh);
64
65my $body = '<div style="max-width:800px;margin:0 auto;padding:24px 28px;color:#e6ecf6">';
66$body .= '<h1 style="font-size:26px;color:#fff;margin:0 0 6px">Active sessions</h1>';
67$body .= '<p style="color:#7e92b6;margin:0 0 18px">Every browser / device currently signed in. If you see something you don&apos;t recognize, revoke it now and change your password.</p>';
68
69if ($flash) {
70 $body .= '<div style="background:#10b98122;border-left:3px solid #10b981;color:#10b981;padding:10px 14px;border-radius:6px;margin-bottom:14px">' . _h($flash) . '</div>';
71}
72
73$body .= '<section style="background:#0b1226;border:1px solid #1f2a4a;border-radius:12px;overflow:hidden">';
74$body .= '<table style="width:100%;font-size:13px;border-collapse:collapse">';
75$body .= '<thead><tr style="background:#0a0f1f;color:#7e92b6;text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:1px"><th style="padding:10px 14px">IP</th><th style="padding:10px 14px">User agent</th><th style="padding:10px 14px">Signed in</th><th style="padding:10px 14px">Expires</th><th style="padding:10px 14px"></th></tr></thead><tbody>';
76
77foreach my $r (@$rows) {
78 my $is_current = $r->{id} eq $sid ? 1 : 0;
79 my $ip = $r->{ip_address} ? unpack('H*', $r->{ip_address}) : '?';
80 my $ua = substr($r->{user_agent} // '', 0, 60);
81 $ua .= '...' if length($r->{user_agent} // '') > 60;
82 my $age = $r->{mins_old} // 0;
83 my $age_str = $age < 60 ? "$age min ago"
84 : $age < 1440 ? int($age/60) . " hr ago"
85 : int($age/1440) . " days ago";
86 my $cur_pill = $is_current ? ' <span style="background:#064e3b;color:#a7f3d0;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:700;letter-spacing:1px">CURRENT</span>' : '';
87 $body .= '<tr style="border-top:1px solid #1f2a4a">';
88 $body .= '<td style="padding:10px 14px;font-family:ui-monospace,Menlo,monospace;color:#cbd5e1;font-size:11px">' . _h($ip) . '</td>';
89 $body .= '<td style="padding:10px 14px;color:#e6ecf6">' . _h($ua) . $cur_pill . '</td>';
90 $body .= '<td style="padding:10px 14px;color:#7e92b6">' . _h($age_str) . '</td>';
91 $body .= '<td style="padding:10px 14px;color:#7e92b6">' . _h($r->{expires_at}) . '</td>';
92 if ($is_current) {
93 $body .= '<td style="padding:10px 14px;color:#7e92b6;font-size:11px">--</td>';
94 } else {
95 $body .= '<td style="padding:10px 14px"><form method="POST" style="display:inline" onsubmit="return confirm(\'Revoke this session?\')"><input type="hidden" name="act" value="revoke"><input type="hidden" name="id" value="' . _h($r->{id}) . '"><button type="submit" style="background:transparent;color:#fca5a5;border:0;cursor:pointer;font-size:12px">Revoke</button></form></td>';
96 }
97 $body .= '</tr>';
98}
99$body .= '</tbody></table></section>';
100
101$body .= '<form method="POST" style="margin-top:14px" onsubmit="return confirm(\'Revoke every session except your current one?\')">';
102$body .= ' <input type="hidden" name="act" value="revoke_all">';
103$body .= ' <button type="submit" style="background:#1f2a4a;color:#fca5a5;border:1px solid #ef4444;padding:8px 16px;border-radius:6px;cursor:pointer;font-size:13px">Revoke all other sessions</button>';
104$body .= '</form>';
105
106$body .= '<div style="margin-top:24px;color:#7e92b6;font-size:12px">Lost a device? Revoke its session here. Spotted something suspicious? Revoke + change your <a href="/profile.cgi" style="color:#14b8a6">password</a> + enable <a href="/two_factor_setup.cgi" style="color:#14b8a6">2FA</a>.</div>';
107$body .= '</div>';
108
109print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nExpires: 0\n\n";
110$wrap->render({ userinfo => $userinfo, title => 'Active sessions', body => $body });
111exit;
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help