diff options
| author | Daniel Friesel <derf@finalrewind.org> | 2021-09-13 20:55:11 +0200 | 
|---|---|---|
| committer | Daniel Friesel <derf@finalrewind.org> | 2021-09-13 20:55:11 +0200 | 
| commit | a34a67b2f9127440860eb7228b295c17e592d6c8 (patch) | |
| tree | 2570042bc6a4dfde92244dffdb11839f8b822e2b /lib | |
| parent | 85fcf63dd843e928a9a3149568682aa89795a1c9 (diff) | |
Add account add / delete CLI for sites with web registration disabled
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Travelynx/Command/account.pm | 125 | ||||
| -rw-r--r-- | lib/Travelynx/Model/Users.pm | 10 | 
2 files changed, 133 insertions, 2 deletions
| diff --git a/lib/Travelynx/Command/account.pm b/lib/Travelynx/Command/account.pm new file mode 100644 index 0000000..6cd3498 --- /dev/null +++ b/lib/Travelynx/Command/account.pm @@ -0,0 +1,125 @@ +package Travelynx::Command::account; + +# Copyright (C) 2021 Daniel Friesel +# +# SPDX-License-Identifier: AGPL-3.0-or-later +use Mojo::Base 'Mojolicious::Command'; +use Crypt::Eksblowfish::Bcrypt qw(bcrypt en_base64); +use UUID::Tiny qw(:std); + +has description => 'Add or remove user accounts'; + +has usage => sub { shift->extract_usage }; + +sub hash_password { +	my ($password) = @_; +	my @salt_bytes = map { int( rand(255) ) + 1 } ( 1 .. 16 ); +	my $salt       = en_base64( pack( 'C[16]', @salt_bytes ) ); + +	return bcrypt( $password, '$2a$12$' . $salt ); +} + +sub add_user { +	my ( $self, $name, $email ) = @_; + +	my $db = $self->app->pg->db; + +	if ( my $error = $self->app->users->is_name_invalid( name => $name ) ) { +		say "Cannot add account '$name': $error"; +		die; +	} + +	my $token         = "tmp"; +	my $password      = substr( create_uuid_as_string(UUID_V4), 0, 18 ); +	my $password_hash = hash_password($password); + +	my $tx      = $db->begin; +	my $user_id = $self->app->users->add_user( +		db            => $db, +		name          => $name, +		email         => $email, +		token         => $token, +		password_hash => $password_hash, +	); +	my $success = $self->app->users->verify_registration_token( +		db             => $db, +		uid            => $user_id, +		token          => $token, +		in_transaction => 1, +	); + +	if ($success) { +		$tx->commit; +		say "Added user $name ($email) with UID $user_id"; +		say "Temporary password for login: $password"; +	} +} + +sub delete_user { +	my ( $self, $uid ) = @_; + +	my $user_data = $self->app->users->get_data( uid => $uid ); + +	if ( not $user_data ) { +		say "UID $uid does not exist."; +		return; +	} + +	$self->app->users->flag_deletion( uid => $uid ); + +	say "User $user_data->{name} (UID $uid) has been flagged for deletion."; +} + +sub really_delete_user { +	my ( $self, $uid, $name ) = @_; + +	my $user_data = $self->app->users->get_data( uid => $uid ); + +	if ( $user_data->{name} ne $name ) { +		say +		  "User name $name does not match UID $uid. Account deletion aborted."; +		return; +	} + +	say "Immediate deletion is not implemented yet."; +	return; +} + +sub run { +	my ( $self, $command, @args ) = @_; + +	if ( $command eq 'add' ) { +		$self->add_user(@args); +	} +	elsif ( $command eq 'delete' ) { +		$self->delete_user(@args); +	} +	elsif ( $command eq 'DELETE' ) { +		$self->really_delete_user(@args); +	} +	else { +		$self->help; +	} +} + +1; + +__END__ + +=head1 SYNOPSIS + +  Usage: index.pl account add [name] [email] + +  Adds user [name] with a temporary password, which is shown on stdout. +  Users can change the password once logged in. + +  Usage: index.pl account delete [uid] + +  Request deletion of user [uid]. This has the same effect as using the +  account deletion button. The user account and all corresponding data will +  be deleted by a maintenance run after three days. + +  Usage: index.pl account DELETE [uid] [name] + +  Immediately delete user [uid]/[name] and all associated data. Deletion is +  irrevocable. Deletion is only performed if [name] matches the name of [uid]. diff --git a/lib/Travelynx/Model/Users.pm b/lib/Travelynx/Model/Users.pm index 535b938..1371b8a 100644 --- a/lib/Travelynx/Model/Users.pm +++ b/lib/Travelynx/Model/Users.pm @@ -34,7 +34,11 @@ sub verify_registration_token {  	my $token = $opt{token};  	my $db    = $opt{db} // $self->{pg}->db; -	my $tx = $db->begin; +	my $tx; + +	if ( not $opt{in_transaction} ) { +		$tx = $db->begin; +	}  	my $res = $db->select(  		'pending_registrations', @@ -48,7 +52,9 @@ sub verify_registration_token {  	if ( $res->hash->{count} ) {  		$db->update( 'users', { status => 1 }, { id => $uid } );  		$db->delete( 'pending_registrations', { user_id => $uid } ); -		$tx->commit; +		if ( not $opt{in_transaction} ) { +			$tx->commit; +		}  		return 1;  	}  	return; | 
