AmberDB
view release on metacpan or search on metacpan
lib/AmberDB/Base.pm view on Meta::CPAN
},
simple => sub {
my $val = shift;
$self->{_cfg}->{simple} = $val ? 1 : 0;
$self->_invalidate_table_paths();
},
use_ramdisk => sub {
my $val = shift;
my $tier = $self->_normalize_ramdisk_tier($val);
if ( $tier == 3 ) {
$tier = 0;
}
$self->{_cfg}->{use_ramdisk} = $tier;
$self->_invalidate_table_paths();
},
};
while ( my ( $key, $val ) = each %pairs ) {
if ( exists $hooks->{$key} ) {
$hooks->{$key}->($val);
}
else {
$self->{_cfg}->{$key} = $val;
if ( $key eq 'user' ) {
$self->{_connect}->{username} = $val;
}
}
}
return $self;
}
# my $dbase_dir = $adb->path("dbase_dir"); # getter
# $adb->path({ backup_dir => "$tmpdir/backup" }); # setter
# $adb->path( custom_path => "/opt/data" ); # setter
# ------------------------------------------------
sub path {
my ( $self, @args ) = @_;
# 1. No arguments: return shallow copy of all path mappings
if ( !@args ) {
return { %{ $self->{_path} || {} } };
}
# 2. Single scalar argument: getter -> $adb->path('dbase_dir')
if ( @args == 1 && !ref( $args[0] ) ) {
return $self->{_path}->{ $args[0] } // '';
}
# 3. Setter: key-value list or hashref
my %pairs = ( @args == 1 && ref( $args[0] ) eq 'HASH' ) ? %{ $args[0] } : @args;
for my $key ( keys %pairs ) {
$self->{_path}->{$key} = $pairs{$key};
}
$self->_invalidate_table_paths();
return $self;
}
# Invalidate cached table paths if global path-affecting configurations change
# ------------------------------------------------
sub _invalidate_table_paths {
my ($self) = @_;
if ( $self->{_table} && ref( $self->{_table} ) eq 'HASH' ) {
for my $tbl ( keys %{ $self->{_table} } ) {
delete $self->{_table}->{$tbl}->{_path}
if ref( $self->{_table}->{$tbl} ) eq 'HASH';
}
}
}
# ============================================================================
# AUTHENTICATION & PASSWORD CRYPTOGRAPHY (Salted SHA-256)
# ============================================================================
# my $shadow = $adb->hash_password($password, [$salt]);
# ---------------------------------------------------------------------
sub hash_password {
my ( $self, $password, $salt ) = @_;
return '' unless defined $password && length $password;
# 16-character cryptographically secure hex salt
$salt //= sprintf( "%08x%08x", int( rand(0xFFFFFFFF) ), int( rand(0xFFFFFFFF) ) );
my $hash = sha256_hex( $salt . $password );
return "sha256\$$salt\$$hash";
}
# my $ok = $adb->verify_password($password, $stored_shadow);
# ---------------------------------------------------------------------
sub verify_password {
my ( $self, $password, $stored_shadow ) = @_;
# Passwordless allowed if stored shadow is empty or undef
return 1 if !defined $stored_shadow || !length $stored_shadow;
$password //= '';
my ( $algo, $salt, $expected ) = split /\$/, $stored_shadow;
return 0 unless defined $algo && defined $salt && defined $expected;
if ( $algo eq 'sha256' ) {
my $computed = sha256_hex( $salt . $password );
return lc($computed) eq lc($expected) ? 1 : 0;
}
return $stored_shadow eq $password ? 1 : 0;
}
# ============================================================================
# DATABASE CONNECTION & CLIENT AUTH PROFILE (connect.pl)
# ============================================================================
sub _connect_file {
my ($self) = @_;
my $config_dir = $self->path('config_dir') || ( ( $self->path('dbase_dir') || "." ) . "/config" );
return "$config_dir/connect.pl";
}
sub _load_connect_config {
my ($self) = @_;
my $file = $self->_connect_file();
( run in 3.918 seconds using v1.01-cache-2.11-cpan-4716db65a44 )