package ONO::ToolBox::Auth;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use strict;
use ONO::IO;
use ONO::DB;
use ONO::ToolBox::Auth::Auth;
use ONO::ToolBox::Auth::Login;
use ONO::ToolBox::Auth::Logout;
use ONO::ToolBox::Auth::PIN;
use ONO::ToolBox::Auth::ToolBox;
use ONO::Lib::Web::Community;
use ONO::Lib::Web::Cookie;
use ONO::Lib::Web::Client;
use ONO::Lib::Data::Crypt;
use ONO::Lib::Data::Geo;
use ONO::FW::User::Init;
###############################################################################
# ONO
###############################################################################
sub sudo {
#: Replace the current username with the currently selected user the sudoer
#: wishes to impersonate.
my (
$self,
$community,
$vars_ref,
) = @_;
my %vars = %$vars_ref;
my $sudo = ONO::IO->load(ONO::FW::User::Init->getuserdir($vars{'username'},$community)."/sudo/username.txt");
if ($sudo && $vars{'community_screen'} !~ /^admin/) {
$vars{'username'} = $sudo;
$vars{'username_sudo_mode'} = 1;
}
return \%vars;
}
sub admin {
#: Administrator login, logout and authentication using the ono_auth_asid cookie.
#: Note that this feature seems to be DEPRECATED, it may be removed soon.
my $vars_ref = $_[1];
my %vars = %$vars_ref;
# my $status;
#
# if ($vars{'mode'} eq "login") {
#
# ($status,$vars{'sid'}) = ONO::ToolBox::Auth::Login->login($vars{'username'},$vars{'password'});
#
# if ($vars{'sid'}) {
# if ($vars{'keep_session'}) {
# $vars{'cookie_sid'} = ONO::Lib::Web::Cookie->make("ono_auth_asid",$vars{'sid'},"90d");
# } else {
# $vars{'cookie_sid'} = ONO::Lib::Web::Cookie->make("ono_auth_asid",$vars{'sid'});
# }
# }
# $vars{'mode'} = "";
#
# }
#
# if (!$vars{'sid'}) {
# $vars{'sid'} = ONO::Lib::Web::Cookie->get("ono_auth_asid");
# }
#
# if ($vars{'sid'}) {
# ($vars{'sid'},$vars{'username'}) = ONO::ToolBox::Auth::Auth->auth($vars{'sid'});
# }
#
# if ($vars{'mode'} eq "logout") {
#
# ONO::ToolBox::Auth::Logout->logout($vars{'username'});
# $vars{'cookie_sid'} = ONO::Lib::Web::Cookie->make("ono_auth_asid","","now");
# $vars{'sid'} = "";
# $vars{'mode'} = "";
#
# }
return \%vars;
}
sub ono {
#: ONO Admin and Desk authentication, also supporting IP based access
#: limitations via /etc/security/onoaccess.conf.
my $vars_ref = $_[1];
my %vars = %$vars_ref;
my $block_ip;
if (ONO::IO->exists("etc/security/onoaccess.conf")) {
my $mode = "User";
if ($_[2] =~ /admin/i) {
$mode = "Admin";
}
my $IP = ONO::Lib::Web::Client->ip();
foreach my $line (ONO::IO->list("etc/security/onoaccess.conf")) {
if ($line =~ /^${mode}IPDeny ALL/) {
$block_ip++;
}
if ($line =~ /^${mode}IPAllow "(.*?)"/) {
my $VALID_IP = $1;
if ($IP eq $VALID_IP || $IP =~ /^$VALID_IP\./) {
$block_ip = 0;
}
}
}
}
if ($block_ip) {
$vars{'ono_blocked_ip'}++;
} else {
$vars{'sid'} = ONO::Lib::Web::Cookie->get("ono_session");
if ($vars{'sid'} =~ /^(.*?)-(.*?)$/) {
if ($vars{'sid'} eq ONO::IO->load("var/ono/sessions/$1.txt")) {
$vars{'username'} = $1;
} else {
$vars{'sid'} = "";
}
}
}
return (\%vars,%vars);
}
sub auth {
#: The main ONO platform authentication logic, using the ono_auth_sid_v2107
#: cookie (latest version as of July 2021).
#:
#: This handles login, logout and authentication, it provides basic user
#: info and keeps statistics up to date.
my ($self,$db,$community,$vars_ref) = @_;
my %vars;
if ($vars_ref) {
%vars = %$vars_ref;
}
my $request = $ENV{'REQUEST_URI'};
my $REDIRECT;
# reset group variables
$vars{'groupname'} = "";
$vars{'groupid'} = "";
# if there's no sid then we'll check the cookies
if (!$vars{'sid'}) {
$vars{'sid'} = ONO::Lib::Web::Cookie->get("ono_auth_sid_v2107");
}
# the standard login procedure
if ($vars{'mode'} eq "login" && $db) {
foreach my $line (ONO::DB->select($db,"${community}_community_users","username = '$vars{'username'}'")) {
my @row = ONO::DB->readcols($line);
if ($row[2] == 1 && ONO::Lib::Data::Crypt->pwdchk($vars{'password'},$row[4])) {
$vars{'sid'} = &makesid($vars{'username'},$community);
if ($vars{'keep_session'}) {
$vars{'cookie_sid'} = ONO::Lib::Web::Cookie->make("ono_auth_sid_v2107",$vars{'sid'},"90d",$vars_ref);
} else {
$vars{'cookie_sid'} = ONO::Lib::Web::Cookie->make("ono_auth_sid_v2107",$vars{'sid'},"",$vars_ref);
}
}
}
$vars{'mode'} = "";
}
# mobile logic
my $MOBILE = &mobile_identifier;
# web logic
my $WEBSITE;
if ($ENV{'REQUEST_URI'} =~ m~/web/-/(.*?)/~) {
$WEBSITE = $1;
} else {
if ($vars{'auth_mode'} eq "website" && $vars{'website'}) {
$WEBSITE = $vars{'website'};
}
}
# devstation test code...
if (ONO::IO->devstation) {
$vars{'userdata_country'} = "LU";
$vars{'userdata_territory'} = "EU";
}
# authentication
if ($vars{'sid'}) {
($vars{'sid'},$vars{'username'}) = ONO::Lib::Web::Community->auth($vars{'sid'},$community,"",$WEBSITE);
if ($db) {
# check profile, as required by EU laws
foreach my $line (ONO::DB->select($db,"${community}_community_profiles","username = '$vars{'username'}'")) {
my @row = ONO::DB->readcols($line);
$vars{'userdata_realname'} = $row[1];
$vars{'userdata_sex'} = $row[2];
$vars{'userdata_birthday'} = $row[3];
$vars{'userdata_country'} = $row[4];
$vars{'userdata_language'} = $row[7];
$vars{'userdata_languages'} = $row[8];
$vars{'userdata_xp'} = $row[15];
$vars{'userdata_rank'} = $row[16];
$vars{'userdata_timezone'} = $row[18];
$vars{'userdata_flags'} = $row[21];
# this will tell us if the user is an EU citizen, and/or if data has to be censored
$vars{'userdata_territory'} = ONO::Lib::Data::Geo->country_to_territory($row[4]);
# we need to censor the EU because of the new copyright directive
# we automatically censor CHina, as they only spam and scam sites...
if ($vars{'userdata_territory'} eq "EU" || $vars{'userdata_territory'} eq "CH") {
$vars{'userdata_censored'} = 1;
if ($vars{'userdata_flags'} =~ /E/) {
$vars{'userdata_uncensored'} = 1;
}
}
}
}
# randomly update the last login info and the user agent...
if ($vars{'sid'} && !$WEBSITE && $db) {
my $rand = int(rand(20));
if ($rand == 10) {
my $timestamp = ONO::IO->timestamp("var/community/$community/accounts/sessions/$vars{'username'}$MOBILE.sid");
ONO::DB->command($db,"UPDATE ${community}_community_status SET lastlogin = '$timestamp', domain = '$ENV{'SERVER_NAME'}' WHERE username = '$vars{'username'}';");
}
if ($rand == 11) {
my $time = time();
ONO::DB->command($db,"UPDATE ${community}_community_status SET lastonline = '$time', domain = '$ENV{'SERVER_NAME'}' WHERE username = '$vars{'username'}';");
}
if ($rand == 12) {
my $dir = ONO::FW::User::Init->getuserdir($vars{'username'},$community);
ONO::IO->store("$dir/user_agent.txt","$ENV{'REMOTE_ADDR'} - $ENV{'HTTP_USER_AGENT'} - $ENV{'HTTP_HOST'}");
}
}
}
# logout
if ($vars{'mode'} eq "logout" || $vars{'menubar_option'} eq "user_logout") {
if ($WEBSITE) {
ONO::IO->rm("var/community/$community/accounts/web/$WEBSITE/$vars{'username'}$MOBILE.sid");
} else {
ONO::IO->mkpath("var/community/$community/accounts/sessions_expired");
ONO::IO->rm("var/community/$community/accounts/sessions_expired/$vars{'username'}$MOBILE.sid");
ONO::IO->mv(
"var/community/$community/accounts/sessions/$vars{'username'}$MOBILE.sid",
"var/community/$community/accounts/sessions_expired/$vars{'username'}$MOBILE.sid",
);
}
$vars{'cookie_sid'} = ONO::Lib::Web::Cookie->make("ono_auth_sid_v2107","","now",$vars_ref);
$vars{'mode'} = "";
$vars{'sid'} = "";
}
return \%vars;
}
sub makesid {
#: Generate an ONO SID (Session ID), combining the username with a random string,
#: and store it in the user's data directory.
my ($username,$community) = @_;
ONO::Lib::Web::Community->log("$username -> generating session ID",$community);
my $boundary = ONO::Lib::Web::Community->makesid($community,$username);
return ("$username-$boundary");
}
sub mobile_identifier {
#: Check if we're using a mobile device.
my $MOBILE;
if ($ENV{'HTTP_USER_AGENT'} =~ /(mobile|tablet|ipad|phone)/i) {
$MOBILE = ".mobile";
if ($ENV{'HTTP_USER_AGENT'} =~ /(phone)/i) {
$MOBILE = ".phone";
}
}
return $MOBILE;
}
###############################################################################
# end of script
###############################################################################
1;
__END__