package WWWDBI; use strict; use warnings; use DBI; use LWP::UserAgent; use Crypt::Eksblowfish::Bcrypt qw(bcrypt en_base64); use Exporter qw(import); our @EXPORT = qw(dob paste pushOver getPasted deleteMessage); sub new { my ($class, %args) = @_; my %auth; open my $AUTH, "<", "/home/rendler/.dbi.auth" or die $!; while (<$AUTH>) { chomp; s/\s//g; my ($key, $value) = split /=/, $_; if ($key =~ /^user(name)?$/i) { $auth{dbUser} = $value; } elsif ($key =~ /^pass(word)?$/i) { $auth{dbPass} = $value; } } close $AUTH; my $dsn = "DBI:MariaDB:www"; my $self = bless { dsn => $dsn, dbUser => $auth{dbUser}, dbPass => $auth{dbPass}, %args }, $class; $self->connect(); return $self; } sub connect { my ($self) = @_; $self->{dbh} = DBI->connect($self->{dsn}, $self->{dbUser}, $self->{dbPass}, { PrintError => 0, RaiseError => 1 }) or die $DBI::errstr; } sub ensure_connection { my ($self) = @_; eval { # Try a simple query to check the connection $self->{dbh}->do('SELECT 1'); }; if ($@) { # Connection is dead, reconnect $self->connect(); } } sub dob { my ($self) = @_; $self->ensure_connection; return $self->{dbh}->selectall_hashref("SELECT * FROM dob", 'name'); } sub paste { my ($self, $paste) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("INSERT INTO copy (text) VALUES(?)"); $sth->execute($paste); } sub pushOver { my ($self, $message) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("SELECT * FROM pushover"); $sth->execute(); my $pushOver = $sth->fetchrow_hashref(); my $ua = LWP::UserAgent->new(); my $res = $ua->post( 'https://api.pushover.net/1/messages.json', [ token => $pushOver->{token}, user => $pushOver->{user}, message => $message ] ); } sub getPasted { my ($self) = @_; $self->ensure_connection; my @messages; for my $m (@{ $self->{dbh}->selectall_arrayref("SELECT id, text FROM copy ORDER BY id DESC") }) { my ($id, $text) = @$m; if ($text =~ /^http/) { $text =~ s/(http\S+)/$1<\/a>/g; $text =~ s/\n/
/g; } push @messages, { id => $id, text => $text }; } return @messages; } sub deleteMessage { my ($self, $id) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("DELETE FROM copy WHERE id = ?"); $sth->execute($id); } sub getAppSecret { my ($self) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("SELECT secret_value FROM app_secrets WHERE key_name = 'mojo_app_secret'"); $sth->execute(); my ($secret) = $sth->fetchrow_array(); return $secret; } sub userExists { my ($self, $username) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("SELECT COUNT(*) FROM users WHERE username = ?"); $sth->execute($username); my ($count) = $sth->fetchrow_array(); return $count > 0; } sub createUser { my ($self, $username, $password, $email) = @_; $self->ensure_connection; my $hashed_password; eval { my $salt = en_base64(join('', map chr(int(rand(256))), 1..16)); $hashed_password = bcrypt($password, '$2a$10$'.$salt); }; if ($@) { die "Failed to hash password: $@"; } eval { my $sth = $self->{dbh}->prepare("INSERT INTO users (username, password, email) VALUES (?, ?, ?)"); $sth->execute($username, $hashed_password, $email); }; if ($@) { die "Failed to insert user into database: $@"; } return 1; } sub authenticateUser { my ($self, $username, $password) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("SELECT password FROM users WHERE username = ?"); $sth->execute($username); my ($stored_hash) = $sth->fetchrow_array(); return 0 unless $stored_hash; # Return false if user doesn't exist return (bcrypt($password, $stored_hash) eq $stored_hash) ? 1 : 0; } sub is_admin { my ($self, $username) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("SELECT is_admin FROM users WHERE username = ?"); $sth->execute($username); my ($is_admin) = $sth->fetchrow_array(); return $is_admin ? 1 : 0; } sub get_all_users { my ($self) = @_; $self->ensure_connection; my $sth = $self->{dbh}->prepare("SELECT id, username, email, created_at, is_admin FROM users"); $sth->execute(); return $sth->fetchall_arrayref({}); } 1;