package WWW::Suffit::AuthDB::Role::CRUD; use strict; use utf8; =encoding utf8 =head1 NAME WWW::Suffit::AuthDB::Role::CRUD - Suffit AuthDB methods for CRUD =head1 SYNOPSIS use WWW::Suffit::AuthDB; my $authdb = WWW::Suffit::AuthDB->with_roles('+CRUD')->new( ... ); =head1 DESCRIPTION Suffit AuthDB methods for CRUD =head1 METHODS This class extends L<WWW::Suffit::AuthDB> and implements the following new ones methods =head2 export_data $authdb->export_data->save; # to `sourcefile` $authdb->export_data("/tmp/authdb.json"); Export all data to JSON file =head2 group_del $authdb->group_del( "wheel" ) or die $authdb->error; Delete group by groupname =head2 group_enroll $authdb->group_enroll( groupname => "wheel", username => "alice", ) or die $authdb->error; Add user to group members =head2 group_get my %data = $authdb->group_get( "wheel" ); my @groups = $authdb->group_get; This method returns group's data or returns all groups as array of hashes =head2 group_members my @members = $authdb->group_members( "wheel" ); This method returns group's members =head2 group_pset $authdb->group_pset( groupname => "wheel", description => "Admin group", ) or die $authdb->error; This method adds new group or doing update data of existing group in pure mode =head2 group_pure_set This method is deprecated! See L</group_pset> =head2 group_set $authdb->group_set( groupname => "wheel", description => "Admin group", ) or die $authdb->error; This method adds new group or doing update data of existing group =head2 import_data $authdb->load->import_data; # from `sourcefile` preloaded data $authdb->import_data("/tmp/authdb.json"); Import all data from JSON file =head2 meta $authdb->meta("my.key", "my value") or die $authdb->error; Sets meta-value by key my $val = $authdb->meta("my.key"); # my value die $authdb->error if $authdb->error; Gets meta-value by key $authdb->meta("my.key", undef) or die $authdb->error; Deletes meta-value by key =head2 realm_del $authdb->realm_del( "default" ) or die $authdb->error; Delete realm by realmname =head2 realm_get my %data = $authdb->realm_get( "default" ); my @realms = $authdb->realm_get; This method returns realm's data or returns all realms as array of hashes =head2 realm_pset $authdb->realm_pset( realmname => "default", realm => "Strict Zone", description => "Default realm", ) or die $authdb->error; This method adds new realm or doing update data of existing realm in pure mode =head2 realm_pure_set This method is deprecated! See L</realm_pset> =head2 realm_requirements my @requirements = $authdb->realm_requirements( "default" ); This method returns list of realm's requirements =head2 realm_routes my @routes = $authdb->realm_routes( "default" ); This method returns list of realm's routes =head2 realm_set $authdb->realm_set( realmname => "default", realm => "Strict Zone", description => "Default realm", ) or die $authdb->error; This method adds new realm or doing update data of existing realm =head2 route_del $authdb->route_del( "root" ) or die $authdb->error; Delete route by routename =head2 route_get my %data = $authdb->route_get( "root" ); my @routes = $authdb->route_get; This method returns route's data or returns all routes as array of hashes =head2 route_pset $authdb->route_pset( realmname => "default", routename => "root", method => "GET", url => "https://localhost:8695/", base => "https://localhost:8695/", path => "/", ) or die $authdb->error; This method adds new route or doing update data of existing route in pure mode =head2 route_pure_set This method is deprecated! See L</route_pset> =head2 route_search my @routes = $authdb->route_search( $text ); This method performs search route by name fragment =head2 route_set $authdb->route_set( realmname => "default", routename => "root", method => "GET", url => "https://localhost:8695/", base => "https://localhost:8695/", path => "/", ) or die $authdb->error; This method adds new route or doing update data of existing route =head2 token_check $authdb->token_check($username, $jti) or die "The token is revoked"; This method checks status of the token in database =head2 token_del $authdb->token_del($username, $jti) or die $authdb->error; This method deletes token from database by username and token ID (jti) =head2 token_get my @tokens = $authdb->token_get(); my %data = $authdb->token_get( 123 ); my %issued = $authdb->token_get($username, $jti); Returns the token's metadata by id or pair - username and jti By default (without specified arguments) this method returns list of all tokens =head2 token_set $authdb->token_set( type => 'api', jti => $jti, username => $username, clientid => 'qwertyuiqwertyui', iat => time, exp => time + 3600, address => '127.0.0.1', ) or die($authdb->error); Adds new token to database $authdb->token_set( id => 123, type => 'api', jti => $jti, username => $username, clientid => 'qwertyuiqwertyui', iat => time, exp => time + 3600, address => '127.0.0.1', ) or die($authdb->error); Updates token's data by id =head2 user_del $authdb->user_del( "admin" ) or die $authdb->error; Delete user by username =head2 user_edit $authdb->user_edit( username => $username, comment => $comment, email => $email, name => $name, role => $role, ) or die($authdb->error); Edit general user data only =head2 user_get my %data = $authdb->user_get( "admin" ); my @users = $authdb->user_get; This method returns user's data or returns all users as array of hashes =head2 user_groups my @groups = $authdb->user_groups( "admin" ); This method returns all groups of the user =head2 user_passwd $authdb->user_passwd( username => "admin", password => "password", ) or die $authdb->error; This method sets password for user =head2 user_pset $authdb->user_pset( username => "foo", name => "Test User", email => 'test@localhost', password => "098f6bcd4621d373cade4e832627b4f6", algorithm => "MD5", role => "Test user", flags => 0, not_before => time(), not_after => undef, public_key => "", private_key => "", attributes => qq/{"disabled": 0}/, comment => "This user added for test", ) or die $authdb->error; This method adds new user or doing update data of existing user in pure mode =head2 user_pure_set This method is deprecated! See L</user_pset> =head2 user_search my @users = $authdb->user_search( $text ); This method performs search user by name fragment =head2 user_set $authdb->user_set( username => "foo", name => "Test User", email => 'test@localhost', password => "MyPassword", # Unsafe password algorithm => "SHA256", role => "Test user", flags => 0, not_before => time(), not_after => undef, public_key => "", private_key => "", attributes => qq/{"disabled": 0}/, comment => "This user added for test", ) or die $authdb->error; This method adds new user or doing update data of existing user =head2 user_setkeys $authdb->user_setkeys( username => "foo", public_key => $public_key, private_key => $private_key, ) or die $authdb->error; This method sets keys for user =head2 user_tokens my @tokens = $authdb->user_tokens( $username ); This method returns all tokens of specified user =head2 ERROR CODES List of error codes describes in L<WWW::Suffit::AuthDB> =head1 HISTORY See C<Changes> file =head1 TO DO See C<TODO> file =head1 SEE ALSO L<WWW::Suffit::AuthDB>, L<Mojolicious>, L<Role::Tiny> =head1 AUTHOR Serż Minus (Sergey Lepenkov) L<https://www.serzik.com> E<lt>abalama@cpan.orgE<gt> =head1 COPYRIGHT Copyright (C) 1998-2025 D&D Corporation. All Rights Reserved =head1 LICENSE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See C<LICENSE> file and L<https://dev.perl.org/licenses/> =cut use Mojo::Base -role; use Acrux::RefUtil qw/is_hash_ref is_array_ref is_true_flag/; use Mojo::Util qw/deprecated/; # Meta CRUD sub meta { my $self = shift; my $i = scalar(@_); my $key = shift // ''; my $val = shift; $self->clean; # Flush error # No key specified return $self->raise(400 => "E1330: No key specified") unless length($key); # Get model my $model = $self->model; # get/set/del if ($i == 1) { # get my %kv = $model->meta_get($key); return $self->raise(500 => "E1329: %s", $model->error) if $model->error; return $kv{"value"}; } elsif ($i > 1) { if (defined($val)) { # set $model->meta_set(key => $key, value => $val) or return $self->raise(500 => "E1331: %s", $model->error || 'Database request error (meta_set)'); } else { # del $model->meta_del($key) or return $self->raise(500 => "E1339: %s", $model->error || 'Database request error (meta_del)'); } } # Ok return 1; } # User CRUD sub user_set { my $self = shift; my %data = @_; $self->clean; # Flush error my $now = time(); # Get model my $model = $self->model; # Get password if (my $password = $data{password}) { my $digest = $self->checksum($password, $data{algorithm} // ''); return $self->raise(400 => "E1332: Incorrect digest algorithm") unless $digest; $data{password} = $digest; } # Get old data from model my %old = $model->user_get($data{username}); return $self->raise(500 => "E1333: %s", $model->error) if $model->error; # Set or add $data{not_after} ||= 0; if ($data{id}) { # Update (Set) $data{password} ||= $old{password}; $model->user_set(%data) or return $self->raise(500 => "E1351: %s", $model->error || 'Database request error (user_set)'); } else { # Insert (Add) return $self->raise(400 => "E1334: User already exists") if $old{id}; $data{created} = $now; $data{not_before} = $now; $model->user_add(%data) or return $self->raise(500 => "E1335: %s", $model->error || 'Database request error (user_add)'); } # Sets up the updated tag #return $self->meta(sprintf("user.%s.updated", $data{username}), $now); # Ok return 1; } sub user_pset { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get current data from model my %cur = $model->user_get($data{username}); return $self->raise(500 => "E1333: %s", $model->error) if $model->error; # Set or add if ($cur{id}) { # Update (Set) $model->user_set(%data) or return $self->raise(500 => "E1351: %s", $model->error || 'Database request error (user_set)'); } else { # Insert (Add) $model->user_add(%data) or return $self->raise(500 => "E1335: %s", $model->error || 'Database request error (user_add)'); } # Sets up the updated tag #return $self->meta(sprintf("user.%s.updated", $data{username}), time); # Ok return 1; } sub user_edit { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get old data from model my %old = $model->user_get($data{username}); return $self->raise(500 => "E1333: %s", $model->error) if $model->error; return $self->raise(400 => "E1336: User not found") unless $old{id}; # Set new data $model->user_edit(%data, id => $old{id}) or return $self->raise(500 => "E1337: %s", $model->error || 'Database request error (user_edit)'); # Sets up the updated tag #return $self->meta(sprintf("user.%s.updated", $data{username}), time); # Ok return 1; } sub user_get { my $self = shift; my $username = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get all users unless (length($username)) { my @table = $model->user_getall; $self->raise(500 => "E1338: %s", $model->error) if $model->error; return @table; } # Get user data my %data = $model->user_get($username); $self->raise(500 => "E1333: %s", $model->error) if $model->error; return %data; } sub user_del { my $self = shift; my $username = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Delete user $model->user_del($username) or return $self->raise(500 => "E1340: %s", $model->error || 'Database request error (user_del)'); # Delete all group relations $model->grpusr_del(username => $username) or return $self->raise(500 => "E1341: %s", $model->error || 'Database request error (grpusr_del)'); # Sets up the updated tag #return $self->meta(sprintf("user.%s.updated", $username), time); # Ok return 1; } sub user_search { my $self = shift; my $username = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Get data from model my @table = $model->user_search($username); $self->raise(500 => "E1342: %s", $model->error) if $model->error; return @table; } sub user_groups { my $self = shift; my $username = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Get groups list of user my @groups = $model->user_groups( $username ); $self->raise(500 => "E1343: %s", $model->error) if $model->error; return @groups; } sub user_passwd { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get old data from model my %old = $model->user_get($data{username}); return $self->raise(500 => "E1333: %s", $model->error) if $model->error; return $self->raise(400 => "E1336: User not found") unless $old{id}; # Get password if (my $password = $data{password}) { my $digest = $self->checksum($password, $old{algorithm}); return $self->raise(400 => "E1332: Incorrect digest algorithm") unless $digest; $data{password} = $digest; } else { return $self->raise(400 => "E1344: No password specified"); } # Set new password $model->user_passwd(%data) or return $self->raise(500 => "E1345: %s", $model->error || 'Database request error (user_passwd)'); # Sets up the updated tag #return $self->meta(sprintf("user.%s.updated", $data{username}), time); # Ok return 1; } sub user_setkeys { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get old data from model my %old = $model->user_get($data{username}); return $self->raise(500 => "E1333: %s", $model->error) if $model->error; return $self->raise(400 => "E1336: User not found") unless $old{id}; # Set new keys $model->user_setkeys(%data, id => $old{id}) or return $self->raise(500 => "E1346: %s", $model->error || 'Database request error (user_setkeys)'); # Sets up the updated tag #return $self->meta(sprintf("user.%s.updated", $data{username}), time); # Ok return 1; } sub user_tokens { my $self = shift; my $username = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get user tokens my @table = $model->user_tokens($username); $self->raise(500 => "E1347: %s", $model->error) if $model->error; return @table; } # Group CRUD sub group_set { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get old data from model my %old = $model->group_get($data{groupname}); return $self->raise(500 => "E1348: %s", $model->error) if $model->error; # Set or add group data if ($data{id}) { # Update (Set) $model->group_set(%data) or return $self->raise(500 => "E1353: %s", $model->error || 'Database request error (group_set)'); } else { # Insert (Add) return $self->raise(400 => "E1349: Group already exists") if $old{id}; $model->group_add(%data) or return $self->raise(500 => "E1350: %s", $model->error || 'Database request error (group_add)'); } # Set users my $users = $data{users} || []; $model->grpusr_del( groupname => $data{groupname} ) or return $self->raise(500 => "E1341: %s", $model->error || 'Database request error (grpusr_del)'); foreach my $username (@$users) { $model->grpusr_add(groupname => $data{groupname}, username => $username) or return $self->raise(500 => "E1352: %s", $model->error || 'Database request error (grpusr_add)'); #$self->meta(sprintf("user.%s.updated", $username), time); } $model->group_set(%data) or return $self->raise(500 => "E1353: %s", $model->error || 'Database request error (group_set)'); # Sets up the updated tag #return $self->meta(sprintf("group.%s.updated", $data{groupname}), time); # Ok return 1; } sub group_pset { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get current data from model my %cur = $model->group_get($data{groupname}); return $self->raise(500 => "E1348: %s", $model->error) if $model->error; # Set or add if ($cur{id}) { # Update (Set) $model->group_set(%data) or return $self->raise(500 => "E1353: %s", $model->error || 'Database request error (group_set)'); } else { # Insert (Add) $model->group_add(%data) or return $self->raise(500 => "E1350: %s", $model->error || 'Database request error (group_add)'); } # Sets up the updated tag #return $self->meta(sprintf("group.%s.updated", $data{groupname}), time); # Ok return 1; } sub group_get { my $self = shift; my $groupname = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get all groups unless (length($groupname)) { my @table = $model->group_getall; $self->raise(500 => "E1355: %s", $model->error) if $model->error; return @table; } # Get group data my %data = $model->group_get($groupname); $self->raise(500 => "E1348: %s", $model->error) if $model->error; return %data; } sub group_del { my $self = shift; my $groupname = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Delete group $model->group_del($groupname) or return $self->raise(500 => "E1356: %s", $model->error || 'Database request error (group_del)'); # Delete all user relations $model->grpusr_del(groupname => $groupname) or return $self->raise(500 => "E1341: %s", $model->error || 'Database request error (grpusr_del)'); # Sets up the updated tag #return $self->meta(sprintf("group.%s.updated", $groupname), time); # Ok return 1; } sub group_enroll { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get existed relation my %old = $model->grpusr_get(%data); return $self->raise(500 => "E1357: %s", $model->error) if $model->error; return 1 if $old{id}; # Enroll $model->grpusr_add(%data) or return $self->raise(500 => "E1352: %s", $model->error || 'Database request error (grpusr_add)'); # Sets up the updated tag #$self->meta(sprintf("user.%s.updated", $data{username}), time); #return 0 unless $model->status; #$self->meta(sprintf("group.%s.updated", $data{groupname}), time); #return 0 unless $model->status; # Ok return 1; } sub group_members { my $self = shift; my $groupname = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Get users list of group my @members = $model->group_members( $groupname ); $self->raise(500 => "E1358: %s", $model->error) if $model->error; return @members; } # Realm CRUD sub realm_set { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get old data from model my %old = $model->realm_get($data{realmname}); return $self->raise(500 => "E1359: %s", $model->error) if $model->error; # Set or add realm data if ($data{id}) { # Update (Set) $model->realm_set(%data) or return $self->raise(500 => "E1366: %s", $model->error || 'Database request error (realm_set)'); } else { # Insert (Add) return $self->raise(400 => "E1360: Realm already exists") if $old{id}; $model->realm_add(%data) or return $self->raise(500 => "E1361: %s", $model->error || 'Database request error (realm_add)'); } # Set routes my $routes = $data{routes} || []; $model->route_release( $data{realmname} ) or return $self->raise(500 => "E1362: %s", $model->error || 'Database request error (route_release)'); foreach my $routename (@$routes) { $model->route_assign(routename => $routename, realmname => $data{realmname}) or return $self->raise(500 => "E1363: %s", $model->error || 'Database request error (route_assign)'); } # Set requirements my $requirements = $data{requirements} || []; $model->realm_requirement_del( $data{realmname} ) or return $self->raise(500 => "E1364: %s", $model->error || 'Database request error (realm_requirement_del)'); foreach my $req (@$requirements) { next unless is_hash_ref($req); $model->realm_requirement_add(%$req, realmname => $data{realmname}) or return $self->raise(500 => "E1365: %s", $model->error || 'Database request error (realm_requirement_add)'); } # Sets up the updated tag #return $self->meta(sprintf("realm.%s.updated", $data{realmname}), time); # Ok return 1; } sub realm_pset { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get current data from model my %cur = $model->realm_get($data{realmname}); return $self->raise(500 => "E1359: %s", $model->error) if $model->error; # Set or add if ($cur{id}) { # Update (Set) $model->realm_set(%data) or return $self->raise(500 => "E1366: %s", $model->error || 'Database request error (realm_set)'); } else { # Insert (Add) $model->realm_add(%data) or return $self->raise(500 => "E1361: %s", $model->error || 'Database request error (realm_add)'); } # Sets up the updated tag #return $self->meta(sprintf("realm.%s.updated", $data{realmname}), time); # Ok return 1; } sub realm_get { my $self = shift; my $realmname = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get all realms unless (length($realmname)) { my @table = $model->realm_getall; $self->raise(500 => "E1367: %s", $model->error) if $model->error; return @table; } # Get realm data my %data = $model->realm_get($realmname); $self->raise(500 => "E1359: %s", $model->error) if $model->error; return %data; } sub realm_del { my $self = shift; my $realmname = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Delete realm $model->realm_del($realmname) or return $self->raise(500 => "E1368: %s", $model->error || 'Database request error (realm_del)'); # Delete realm's requirements $model->realm_requirement_del($realmname) or return $self->raise(500 => "E1364: %s", $model->error || 'Database request error (realm_requirement_del)'); # Release all related routes $model->route_release($realmname) or return $self->raise(500 => "E1362: %s", $model->error || 'Database request error (route_release)'); # Sets up the updated tag #return $self->meta(sprintf("realm.%s.updated", $realmname), time); # Ok return 1; } sub realm_requirements { my $self = shift; my $realmname = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get realm requirements my @table = $model->realm_requirements($realmname); $self->raise(500 => "E1371: %s", $model->error) if $model->error; return @table; } sub realm_routes { my $self = shift; my $realmname = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get realm routes my @table = $model->realm_routes($realmname); $self->raise(500 => "E1372: %s", $model->error) if $model->error; return @table; } # Route CRUD sub route_set { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get old data from model my %old = $model->route_get($data{routename}); return $self->raise(500 => "E1373: %s", $model->error) if $model->error; # Set or add route data if ($data{id}) { # Update (Set) $model->route_set(%data) or return $self->raise(500 => "E1375: %s", $model->error || 'Database request error (route_set)'); } else { # Insert (Add) return $self->raise(400 => "E1374: Route already exists") if $old{id}; $model->route_add(%data) or return $self->raise(500 => "E1370: %s", $model->error || 'Database request error (route_add)'); } # Sets up the updated tag #return $self->meta(sprintf("routes.%s.updated", $data{base} // '__default'), time); # Ok return 1; } sub route_pset { my $self = shift; my %data = @_; $self->clean; # Flush error # Get model my $model = $self->model; # Get current data from model my %cur = $model->route_get($data{routename}); return $self->raise(500 => "E1373: %s", $model->error) if $model->error; # Set or add if ($cur{id}) { # Update (Set) $data{id} = $cur{id}; $model->route_set(%data) or return $self->raise(500 => "E1375: %s", $model->error || 'Database request error (route_set)'); } else { # Insert (Add) $model->route_add(%data) or return $self->raise(500 => "E1370: %s", $model->error || 'Database request error (route_add)'); } # Sets up the updated tag #return $self->meta(sprintf("routes.%s.updated", $data{base} // '__default'), time); # Ok return 1; } sub route_get { my $self = shift; my $routename = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get all routes unless (length($routename)) { my @table = $model->route_getall(); $self->raise(500 => "E1376: %s", $model->error) if $model->error; return @table; } # Get route data my %data = $model->route_get($routename); $self->raise(500 => "E1373: %s", $model->error) if $model->error; return %data; } sub route_del { my $self = shift; my $routename = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Delete route $model->route_del($routename) or return $self->raise(500 => "E1377: %s", $model->error || 'Database request error (route_del)'); # Ok return 1; } sub route_search { my $self = shift; my $text = shift; $self->clean; # Flush error # Get model my $model = $self->model; # Get data from model my @table = $model->route_search($text); $self->raise(500 => "E1378: %s", $model->error) if $model->error; return @table; } # Token CRUD sub token_set { my $self = shift; my %data = @_; $self->clean; # Flush error $data{type} //= 'session'; # Get model my $model = $self->model; # Delete expired tokens $model->token_del or return $self->raise(500 => "E1379: %s", $model->error || 'Database request error (token_del)'); # Get old data from model my %old; if ($data{id}) { %old = $model->token_get($data{id}); return $self->raise(500 => "E1380: %s", $model->error) if $model->error; } elsif ($data{type} eq 'session') { %old = $model->token_get_cond('session', %data); return $self->raise(500 => "E1381: %s", $model->error) if $model->error; } # Set or add data if ($old{id}) { # Update (Set) $data{id} = $old{id}; $model->token_set(%data) or return $self->raise(500 => "E1382: %s", $model->error || 'Database request error (token_set)'); } else { # Insert (Add) $model->token_add(%data) or return $self->raise(500 => "E1369: %s", $model->error || 'Database request error (token_add)'); } # Ok return 1; } sub token_get { my $self = shift; my ($id, $username, $jti); if (scalar(@_) == 1) { $id = shift } elsif (scalar(@_) == 2) {($username, $jti) = @_} $self->clean; # Flush error # Get model my $model = $self->model; # Get data from model my @data = (); if ($id) { @data = $model->token_get($id); # hash returs $self->raise(500 => "E1380: %s", $model->error) if $model->error; } elsif ($jti) { @data = $model->token_get_cond('api', username => $username, jti => $jti); # hash returs $self->raise(500 => "E1381: %s", $model->error) if $model->error; } else { @data = $model->token_getall(); # table returs $self->raise(500 => "E1383: %s", $model->error) if $model->error; } return @data; } sub token_del { my $self = shift; my $username = shift // ''; my $jti = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get data from model my %data = $model->token_get_cond('api', username => $username, jti => $jti); return $self->raise(500 => "E1381: %s", $model->error) if $model->error; return 1 unless $data{id}; # Delete token $model->token_del($data{id}) or return $self->raise(500 => "E1379: %s", $model->error || 'Database request error (token_del)'); # Ok return 1; } sub token_check { my $self = shift; my $username = shift // ''; my $jti = shift // ''; $self->clean; # Flush error # Get model my $model = $self->model; # Get data from model my %data = $model->token_get_cond('api', username => $username, jti => $jti); return $self->raise(500 => "E1381: %s", $model->error) // 0 if $model->error; # Check return 1 if $data{id}; return 0; } # Working with dumps sub import_data { my $self = shift; my $file = shift; $self->clean; # Flush error my $model = $self->model; my $now = time(); # Get data struct from file if ($file) { $self->load($file); if ($self->error) { $self->code(500); return; } } my $data = $self->data; # Perl struct expected! # Get users my $users_array = $data->{"users"} // []; $users_array = [] unless is_array_ref($users_array); my %grpsusrs = (); foreach my $user (@$users_array) { next unless is_hash_ref($user); my $username = $user->{"username"} // ''; next unless length($username); # Add user $self->user_pset( username => $username, name => $user->{"name"} // '', email => $user->{"email"} // '', password => $user->{"password"} // '', algorithm => $user->{"algorithm"} // '', role => $user->{"role"} // '', flags => $user->{"flags"} || 0, created => $now, not_before => $now, not_after => is_true_flag($user->{"disabled"}) ? $now : undef, public_key => $user->{"public_key"} // '', private_key => $user->{"private_key"} // '', attributes => $user->{"attributes"} // '', comment => $user->{"comment"} // '', ) or return; # Add groups to grpsusrs my $groups = $user->{"groups"} || []; $groups = [] unless is_array_ref($groups); foreach my $g (@$groups) { $grpsusrs{"$g:$username"} = { groupname => $g, username => $username, }; } } # Get groups my $groups_array = $data->{"groups"} // []; $groups_array = [] unless is_array_ref($groups_array); foreach my $group (@$groups_array) { next unless is_hash_ref($group); my $groupname = $group->{"groupname"} // ''; next unless length($groupname); # Add group $self->group_pset( groupname => $groupname, description => $group->{"description"} // '', ) or return; # Add users to grpsusrs my $users = $group->{"users"} || []; $users = [] unless is_array_ref($users); foreach my $u (@$users) { $grpsusrs{"$groupname:$u"} = { groupname => $groupname, username => $u, }; } } # Add members to group foreach my $member (values %grpsusrs) { $self->group_enroll(%$member) or return; } # Get realms my $realms_array = $data->{"realms"} // []; $realms_array = [] unless is_array_ref($realms_array); foreach my $realm (@$realms_array) { next unless is_hash_ref($realm); my $realmname = $realm->{"realmname"} // ''; next unless length($realmname); # Add realm $self->realm_pset( realmname => $realmname, realm => $realm->{"realm"} // '', satisfy => $realm->{"satisfy"} // '', description => $realm->{"description"} // '', ) or return; # Delete all current requirements from realm $model->realm_requirement_del($realmname) or return $self->raise(500 => "E1364: %s", $model->error || 'Database request error (realm_requirement_del)'); # Set requirements my $requirements = $realm->{"requirements"} || []; $requirements = [] unless is_array_ref($requirements); foreach my $req (@$requirements) { next unless is_hash_ref($req); $model->realm_requirement_add(%$req, realmname => $realmname) or return $self->raise(500 => "E1365: %s", $model->error || 'Database request error (realm_requirement_add)'); } # Release all routes for realm $model->route_release($realmname) or return $self->raise(500 => "E1362: %s", $model->error || 'Database request error (route_release)'); } # Get routes my $routes_array = $data->{"routes"} // []; $routes_array = [] unless is_array_ref($routes_array); foreach my $route (@$routes_array) { next unless is_hash_ref($route); my $routename = $route->{"routename"} // ''; next unless length($routename); # Add route $self->route_pset( routename => $routename, realmname => $route->{"realmname"} // '', method => $route->{"method"} // '', url => $route->{"url"} // '', base => $route->{"base"} // '', path => $route->{"path"} // '', ) or return; } # Get meta my $meta_hash = $data->{"meta"} // {}; $meta_hash = {} unless is_hash_ref($meta_hash); while (my ($k, $v) = each %$meta_hash) { last unless (defined($k) && length($k)); $self->meta($k, $v) or return; delete $meta_hash->{$k}; # This is safe } # Save status data to meta $self->meta("data.file" => $file || $self->sourcefile) or return; $self->meta("data.inited" => $now) or return; # Ok return 1; } sub export_data { my $self = shift; my $file = shift; $self->clean; # Flush error my $model = $self->model; my $now = time(); # Get users my @users = $self->user_get(); return if $self->error; foreach my $u (@users) { my $not_after = $u->{not_after} || 0; $u->{disabled} = ($not_after && $not_after < $now) ? 'yes' : 'no'; delete($u->{$_}) for qw/created id not_before not_after/; } # Get groups my @groups = $self->group_get(); return if $self->error; foreach my $g (@groups) { my $groupname = $g->{groupname} // ''; next unless length $groupname; delete($g->{id}); # Get members my @members = $self->group_members($groupname); return if $self->error; my @usr = (); foreach my $m (@members) { push @usr, $m->{username}; } $g->{users} = [@usr]; } # Get realms my @realms = $self->realm_get(); return if $self->error; foreach my $r (@realms) { my $realmname = $r->{realmname} // ''; next unless length $realmname; delete($r->{id}); # Get requirements my @requirements = $self->realm_requirements($realmname); return if $self->error; my @reqs = (); foreach my $q (@requirements) { delete($q->{id}); delete($q->{realmname}); push @reqs, $q; } $r->{requirements} = [@reqs]; } # Get routes my @routes = $self->route_get(); return if $self->error; foreach my $r (@routes) { delete($r->{id}); } # Get meta my @metas = $model->meta_get(); return $self->raise(500 => "E1329: %s", $model->error) if $model->error; my %meta = (); foreach my $m (@metas) { $meta{$m->{key}} = $m->{value}; } #print Mojo::Util::dumper(\%meta); # Store data $self->data({ users => \@users, groups => \@groups, realms => \@realms, routes => \@routes, meta => \%meta, }); if ($file) { $self->save($file); if ($self->error) { $self->code(500); return; } } # Ok return 1; } # Deprecated methods sub user_pure_set { deprecated 'The "WWW::Suffit::AuthDB::user_pure_set" is deprecated in favor of "user_pset"'; goto &user_pset; } sub group_pure_set { deprecated 'The "WWW::Suffit::AuthDB::group_pure_set" is deprecated in favor of "group_pset"'; goto &group_pset; } sub realm_pure_set { deprecated 'The "WWW::Suffit::AuthDB::realm_pure_set" is deprecated in favor of "realm_pset"'; goto &realm_pset; } sub route_pure_set { deprecated 'The "WWW::Suffit::AuthDB::route_pure_set" is deprecated in favor of "route_pset"'; goto &route_pset; } 1; __END__