|
|
@@ -81,6 +81,8 @@ class Organizr
|
|
|
public $commit;
|
|
|
public $fileHash;
|
|
|
public $cookieName;
|
|
|
+ public $log;
|
|
|
+ public $logger;
|
|
|
public $organizrLog;
|
|
|
public $organizrLoginLog;
|
|
|
public $timeExecution;
|
|
|
@@ -123,9 +125,12 @@ class Organizr
|
|
|
$this->fileHash = trim($this->fileHash);
|
|
|
// Load Config file
|
|
|
$this->config = $this->config();
|
|
|
- // Set organizr Log file location
|
|
|
+ // Set organizr Logs and logger
|
|
|
+ $this->log = $this->setOrganizrLog();
|
|
|
+ $this->setLoggerChannel();
|
|
|
+ // Set organizr Log file location - will deprecate soon
|
|
|
$this->organizrLog = ($this->hasDB()) ? $this->config['dbLocation'] . 'organizrLog.json' : false;
|
|
|
- // Set organizr Login Log file location
|
|
|
+ // Set organizr Login Log file location - will deprecate soon
|
|
|
$this->organizrLoginLog = ($this->hasDB()) ? $this->config['dbLocation'] . 'organizrLoginLog.json' : false;
|
|
|
// Set Paths
|
|
|
$this->paths = array(
|
|
|
@@ -204,6 +209,7 @@ class Organizr
|
|
|
}
|
|
|
}
|
|
|
$this->user = ($user) ?: $this->guestUser();
|
|
|
+ $this->setLoggerChannel();
|
|
|
if ($validate) {
|
|
|
$this->checkUserTokenForValidation();
|
|
|
}
|
|
|
@@ -242,7 +248,7 @@ class Organizr
|
|
|
$currentIP = $this->userIP();
|
|
|
if ($this->config['blacklisted'] !== '') {
|
|
|
if (in_array($currentIP, $this->arrayIP($this->config['blacklisted']))) {
|
|
|
- $this->debug('User was sent to blackhole - Blacklisted IPs: ' . $this->config['blacklisted']);
|
|
|
+ $this->setLoggerChannel('Authentication')->debug('User was sent to black hole', $this->config['blacklisted']);
|
|
|
die($this->showHTML('Blacklisted', $this->config['blacklistedMessage']));
|
|
|
}
|
|
|
}
|
|
|
@@ -948,7 +954,7 @@ class Organizr
|
|
|
// Update config.php version if different to the installed version
|
|
|
if ($updateSuccess && $this->version !== $this->config['configVersion']) {
|
|
|
$this->updateConfig(array('apply_CONFIG_VERSION' => $this->version));
|
|
|
- $this->debug('Updated config version to ' . $this->version);
|
|
|
+ $this->setLoggerChannel('Update')->debug('Updated config version to ' . $this->version);
|
|
|
}
|
|
|
if ($updateSuccess == false) {
|
|
|
die($this->showHTML('Database update failed', 'Please manually check logs and fix - Then reload this page'));
|
|
|
@@ -1375,9 +1381,9 @@ class Organizr
|
|
|
{
|
|
|
if (isset($_COOKIE[$this->cookieName])) {
|
|
|
if ($token == $_COOKIE[$this->cookieName]) {
|
|
|
+ $this->setLoggerChannel('Authentication')->debug('Token was invalid - deleting cookie and user session');
|
|
|
$this->coookie('delete', $this->cookieName);
|
|
|
$this->user = null;
|
|
|
- $this->debug('Token was invalid - deleting cookie and user session');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -1392,7 +1398,7 @@ class Organizr
|
|
|
$user = $this->getUserById($userInfo['userID']);
|
|
|
$tokenCheck = ($this->searchArray($allTokens, 'token', $token) !== false);
|
|
|
if (!$tokenCheck) {
|
|
|
- $this->debug('Token failed check Token listing: ' . json_encode($allTokens) . ' User Id: ' . $userInfo['userID']);
|
|
|
+ $this->setLoggerChannel('Authentication')->debug('Token failed check against all token listings', $allTokens);
|
|
|
$this->invalidToken($token);
|
|
|
if ($api) {
|
|
|
$this->setResponse(403, 'Token was not in approved list');
|
|
|
@@ -1423,7 +1429,7 @@ class Organizr
|
|
|
if ($api) {
|
|
|
$this->setResponse(403, 'Token was invalid');
|
|
|
}
|
|
|
- $this->debug('Token was invalid');
|
|
|
+ $this->setLoggerChannel('Authentication')->debug('User token was invalid', $token);
|
|
|
$this->invalidToken($token);
|
|
|
}
|
|
|
if ($api) {
|
|
|
@@ -2651,6 +2657,38 @@ class Organizr
|
|
|
'attr' => 'rows="10"',
|
|
|
),
|
|
|
),
|
|
|
+ 'Logs' => array(
|
|
|
+ array(
|
|
|
+ 'type' => 'select',
|
|
|
+ 'name' => 'logLevel',
|
|
|
+ 'label' => 'Log Level',
|
|
|
+ 'value' => $this->config['logLevel'],
|
|
|
+ 'options' => $this->logLevels()
|
|
|
+ ),
|
|
|
+ array(
|
|
|
+ 'type' => 'number',
|
|
|
+ 'name' => 'maxLogFiles',
|
|
|
+ 'label' => 'Maximum Log Files',
|
|
|
+ 'help' => 'Number of log files to preserve',
|
|
|
+ 'value' => $this->config['maxLogFiles'],
|
|
|
+ 'placeholder' => '',
|
|
|
+ 'attr' => 'min="1"'
|
|
|
+ ),
|
|
|
+ array(
|
|
|
+ 'type' => 'select',
|
|
|
+ 'name' => 'logLiveUpdateRefresh',
|
|
|
+ 'label' => 'Live Update Refresh',
|
|
|
+ 'value' => $this->config['logLiveUpdateRefresh'],
|
|
|
+ 'options' => $this->timeOptions()
|
|
|
+ ),
|
|
|
+ array(
|
|
|
+ 'type' => 'select',
|
|
|
+ 'name' => 'logPageSize',
|
|
|
+ 'label' => 'Log Page Size',
|
|
|
+ 'value' => $this->config['logPageSize'],
|
|
|
+ 'options' => [['name' => '10 Items', 'value' => '10'], ['name' => '25 Items', 'value' => '25'], ['name' => '50 Items', 'value' => '50'], ['name' => '100 Items', 'value' => '100']]
|
|
|
+ ),
|
|
|
+ ),
|
|
|
'Login' => array(
|
|
|
array(
|
|
|
'type' => 'password-alt',
|
|
|
@@ -3684,6 +3722,7 @@ class Organizr
|
|
|
|
|
|
public function createToken($username, $email, $days = 1)
|
|
|
{
|
|
|
+ $this->setLoggerChannel('Authentication', $username)->debug('Starting token creation function');
|
|
|
$days = ($days > 365) ? 365 : $days;
|
|
|
//Quick get user ID
|
|
|
$result = $this->getUserByUsernameAndEmail($username, $email);
|
|
|
@@ -3727,6 +3766,7 @@ class Organizr
|
|
|
),
|
|
|
];
|
|
|
$token = $this->processQueries($response);
|
|
|
+ $this->logger->debug('Token creation function has finished');
|
|
|
return $jwttoken;
|
|
|
|
|
|
}
|
|
|
@@ -3744,6 +3784,9 @@ class Organizr
|
|
|
$output = $array['output'] ?? null;
|
|
|
$username = (strpos($this->config['authBackend'], 'emby') !== false) ? $username : strtolower($username);
|
|
|
$days = (isset($remember)) ? $this->config['rememberMeDays'] : 1;
|
|
|
+ // Set logger channel
|
|
|
+ $this->setLoggerChannel('Authentication', $username);
|
|
|
+ $this->logger->debug('Starting login function');
|
|
|
// Set other variables
|
|
|
$function = 'plugin_auth_' . $this->config['authBackend'];
|
|
|
$authSuccess = false;
|
|
|
@@ -3752,6 +3795,7 @@ class Organizr
|
|
|
// Check Login attempts and kill if over limit
|
|
|
if ($loginAttempts > $this->config['loginAttempts'] || isset($_COOKIE['lockout'])) {
|
|
|
$this->coookieSeconds('set', 'lockout', $this->config['loginLockout'], $this->config['loginLockout']);
|
|
|
+ $this->logger->warning('User is locked out');
|
|
|
$this->setAPIResponse('error', 'User is locked out', 403);
|
|
|
return false;
|
|
|
}
|
|
|
@@ -3760,16 +3804,17 @@ class Organizr
|
|
|
if (isset($this->getallheaders()[$this->config['authProxyHeaderName']])) {
|
|
|
$usernameHeader = $this->getallheaders()[$this->config['authProxyHeaderName']] ?? $username;
|
|
|
$emailHeader = $this->getallheaders()[$this->config['authProxyHeaderNameEmail']] ?? null;
|
|
|
- $this->writeLog('success', 'Auth Proxy Function - Starting Verification for IP: ' . $this->userIP() . ' for request on: ' . $_SERVER['REMOTE_ADDR'] . ' against IP/Subnet: ' . $this->config['authProxyWhitelist'], $usernameHeader);
|
|
|
+ $this->setLoggerChannel('Authentication', $usernameHeader);
|
|
|
+ $this->logger->debug('Starting Auth Proxy verification');
|
|
|
$whitelistRange = $this->analyzeIP($this->config['authProxyWhitelist']);
|
|
|
$authProxy = $this->authProxyRangeCheck($whitelistRange['from'], $whitelistRange['to']);
|
|
|
$username = ($authProxy) ? $usernameHeader : $username;
|
|
|
$password = ($password == null) ? $this->random_ascii_string(10) : $password;
|
|
|
$addEmailToAuthProxy = ($authProxy && $emailHeader) ? ['email' => $emailHeader] : true;
|
|
|
if ($authProxy) {
|
|
|
- $this->writeLog('success', 'Auth Proxy Function - IP: ' . $this->userIP() . ' has been verified', $usernameHeader);
|
|
|
+ $this->logger->info('User has been verified using Auth Proxy');
|
|
|
} else {
|
|
|
- $this->writeLog('error', 'Auth Proxy Function - IP: ' . $this->userIP() . ' has failed verification', $usernameHeader);
|
|
|
+ $this->logger->warning('User has failed verification using Auth Proxy');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -3794,6 +3839,7 @@ class Organizr
|
|
|
if (!$authSuccess) {
|
|
|
// perform the internal authentication step
|
|
|
if (password_verify($password, $result['password'])) {
|
|
|
+ $this->logger->debug('User password has been verified');
|
|
|
$authSuccess = true;
|
|
|
}
|
|
|
}
|
|
|
@@ -3804,6 +3850,7 @@ class Organizr
|
|
|
switch ($oAuthType) {
|
|
|
case 'plex':
|
|
|
if ($this->config['plexoAuth']) {
|
|
|
+ $this->logger->debug('Starting Plex oAuth verification');
|
|
|
$tokenInfo = $this->checkPlexToken($oAuth);
|
|
|
if ($tokenInfo) {
|
|
|
$authSuccess = array(
|
|
|
@@ -3813,10 +3860,14 @@ class Organizr
|
|
|
'token' => $tokenInfo['user']['authToken'],
|
|
|
'oauth' => 'plex'
|
|
|
);
|
|
|
+ $this->logger->debug('User\'s Plex Token has been verified');
|
|
|
$this->coookie('set', 'oAuth', 'true', $this->config['rememberMeDays']);
|
|
|
$authSuccess = ((!empty($this->config['plexAdmin']) && strtolower($this->config['plexAdmin']) == strtolower($tokenInfo['user']['username'])) || (!empty($this->config['plexAdmin']) && strtolower($this->config['plexAdmin']) == strtolower($tokenInfo['user']['email'])) || $this->checkPlexUser($tokenInfo['user']['username'])) ? $authSuccess : false;
|
|
|
+ } else {
|
|
|
+ $this->logger->warning('User\'s Plex Token has failed verification');
|
|
|
}
|
|
|
} else {
|
|
|
+ $this->logger->debug('Plex oAuth is not setup');
|
|
|
$this->setAPIResponse('error', 'Plex oAuth is not setup', 422);
|
|
|
return false;
|
|
|
}
|
|
|
@@ -3842,12 +3893,12 @@ class Organizr
|
|
|
//does org password need to be updated
|
|
|
if (!$passwordMatches) {
|
|
|
$this->updateUserPassword($password, $result['id']);
|
|
|
- $this->writeLog('success', 'Login Function - User Password updated from backend', $username);
|
|
|
+ $this->setLoggerChannel('Authentication', $username)->info('User Password updated from backend');
|
|
|
}
|
|
|
if ($token !== '') {
|
|
|
if ($token !== $result['plex_token']) {
|
|
|
$this->updateUserPlexToken($token, $result['id']);
|
|
|
- $this->writeLog('success', 'Login Function - User Plex Token updated from backend', $username);
|
|
|
+ $this->setLoggerChannel('Authentication', $username)->info('User Plex Token updated from backend');
|
|
|
}
|
|
|
}
|
|
|
// 2FA might go here
|
|
|
@@ -3866,46 +3917,55 @@ class Organizr
|
|
|
}
|
|
|
}
|
|
|
if ($tfaProceed) {
|
|
|
+ $this->setLoggerChannel('Authentication', $username)->debug('Starting 2FA verification');
|
|
|
$TFA = explode('::', $result['auth_service']);
|
|
|
// Is code with login info?
|
|
|
if ($tfaCode == '') {
|
|
|
+ $this->logger->debug('Sending 2FA response to login UI');
|
|
|
$this->setAPIResponse('warning', '2FA Code Needed', 422);
|
|
|
return false;
|
|
|
} else {
|
|
|
if (!$this->verify2FA($TFA[1], $tfaCode, $TFA[0])) {
|
|
|
- $this->writeLoginLog($username, 'error');
|
|
|
- $this->writeLog('error', 'Login Function - Wrong 2FA', $username);
|
|
|
+ $this->logger->warning('Incorrect 2FA');
|
|
|
$this->setAPIResponse('error', 'Wrong 2FA', 422);
|
|
|
return false;
|
|
|
+ } else {
|
|
|
+ $this->logger->info('2FA verification passed');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// End 2FA
|
|
|
// authentication passed - 1) mark active and update token
|
|
|
+ $this->logger->debug('Starting token creation function');
|
|
|
$createToken = $this->createToken($result['username'], $result['email'], $days);
|
|
|
if ($createToken) {
|
|
|
- $this->writeLoginLog($username, 'success');
|
|
|
- $this->writeLog('success', 'Login Function - A User has logged in', $username);
|
|
|
+ $this->logger->debug('Token has been created');
|
|
|
+ $this->logger->debug('Token creation function has finished');
|
|
|
+ $this->logger->info('User has logged in');
|
|
|
+ $this->logger->debug('Starting SSO check function');
|
|
|
$this->ssoCheck($result, $password, $token); //need to work on this
|
|
|
return ($output) ? array('name' => $this->cookieName, 'token' => (string)$createToken) : true;
|
|
|
} else {
|
|
|
+ $this->logger->warning('Token creation error');
|
|
|
$this->setAPIResponse('error', 'Token creation error', 500);
|
|
|
return false;
|
|
|
}
|
|
|
} else {
|
|
|
// Create User
|
|
|
+ $this->setLoggerChannel('Authentication', (is_array($authSuccess) && isset($authSuccess['username']) ? $authSuccess['username'] : $username))->debug('Starting Registration function');
|
|
|
return $this->authRegister((is_array($authSuccess) && isset($authSuccess['username']) ? $authSuccess['username'] : $username), $password, (is_array($authSuccess) && isset($authSuccess['email']) ? $authSuccess['email'] : ''), $token);
|
|
|
}
|
|
|
} else {
|
|
|
// authentication failed
|
|
|
- $this->writeLoginLog($username, 'error');
|
|
|
- $this->writeLog('error', 'Login Function - Wrong Password', $username);
|
|
|
+ $this->setLoggerChannel('Authentication', $username)->warning('Wrong Password');
|
|
|
if ($loginAttempts >= $this->config['loginAttempts']) {
|
|
|
+ $this->logger->warning('User exceeded maximum login attempts');
|
|
|
$this->coookieSeconds('set', 'lockout', $this->config['loginLockout'], $this->config['loginLockout']);
|
|
|
$this->setAPIResponse('error', 'User is locked out', 403);
|
|
|
return false;
|
|
|
} else {
|
|
|
+ $this->logger->debug('User has not exceeded maximum login attempts');
|
|
|
$this->setAPIResponse('error', 'User credentials incorrect', 401);
|
|
|
return false;
|
|
|
}
|
|
|
@@ -3914,6 +3974,9 @@ class Organizr
|
|
|
|
|
|
public function logout()
|
|
|
{
|
|
|
+ $this->setLoggerChannel('Authentication');
|
|
|
+ $this->logger->debug('Starting log out process');
|
|
|
+ $this->logger->info('User has logged out');
|
|
|
$this->coookie('delete', $this->cookieName);
|
|
|
$this->coookie('delete', 'mpt');
|
|
|
$this->coookie('delete', 'Auth');
|
|
|
@@ -3924,6 +3987,7 @@ class Organizr
|
|
|
$this->clearJellyfinTokens();
|
|
|
$this->revokeTokenCurrentUser($this->user['token']);
|
|
|
$this->clearKomgaToken();
|
|
|
+ $this->logger->debug('Log out process has finished');
|
|
|
$this->user = null;
|
|
|
return true;
|
|
|
}
|
|
|
@@ -4011,6 +4075,7 @@ class Organizr
|
|
|
|
|
|
public function authRegister($username, $password, $email, $token = null)
|
|
|
{
|
|
|
+ $this->setLoggerChannel('Authentication', $username);
|
|
|
if ($this->config['authBackend'] !== '') {
|
|
|
$this->ombiImport($this->config['authBackend']);
|
|
|
}
|
|
|
@@ -4401,72 +4466,6 @@ class Organizr
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- public function getLog($log, $reverse = true)
|
|
|
- {
|
|
|
- switch ($log) {
|
|
|
- case 'login':
|
|
|
- case 'loginLog':
|
|
|
- case 'loginlog':
|
|
|
- $file = $this->organizrLoginLog;
|
|
|
- $parent = 'auth';
|
|
|
- break;
|
|
|
- case 'org':
|
|
|
- case 'organizr':
|
|
|
- case 'organizrLog':
|
|
|
- case 'orglog':
|
|
|
- $file = $this->organizrLog;
|
|
|
- $parent = 'log_items';
|
|
|
- break;
|
|
|
- default:
|
|
|
- $this->setAPIResponse('error', 'Log not defined', 404);
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (!file_exists($file)) {
|
|
|
- $this->setAPIResponse('error', 'Log does not exist', 404);
|
|
|
- return null;
|
|
|
- }
|
|
|
- $getLog = str_replace("\r\ndate", "date", file_get_contents($file));
|
|
|
- $gotLog = json_decode($getLog, true);
|
|
|
- return ($reverse) ? array_reverse($gotLog[$parent]) : $gotLog[$parent];
|
|
|
- }
|
|
|
-
|
|
|
- public function purgeLog($log)
|
|
|
- {
|
|
|
-
|
|
|
- switch ($log) {
|
|
|
- case 'login':
|
|
|
- case 'loginLog':
|
|
|
- case 'loginlog':
|
|
|
- $file = $this->organizrLoginLog;
|
|
|
- break;
|
|
|
- case 'org':
|
|
|
- case 'organizr':
|
|
|
- case 'organizrLog':
|
|
|
- case 'orgLog':
|
|
|
- case 'orglog':
|
|
|
- $file = $this->organizrLog;
|
|
|
- break;
|
|
|
- default:
|
|
|
- $this->setAPIResponse('error', 'Log not defined', 404);
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (file_exists($file)) {
|
|
|
- if (unlink($file)) {
|
|
|
- $this->writeLog('success', 'Log Management Function - Log: ' . $log . ' has been purged/deleted', 'SYSTEM');
|
|
|
- $this->setAPIResponse(null, 'Log purged');
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- $this->writeLog('error', 'Log Management Function - Log: ' . $log . ' - Error Occurred', 'SYSTEM');
|
|
|
- $this->setAPIResponse('error', 'Log could not be purged', 500);
|
|
|
- return false;
|
|
|
- }
|
|
|
- } else {
|
|
|
- $this->setAPIResponse('error', 'Log does not exist', 404);
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
public function checkLog($path)
|
|
|
{
|
|
|
if (file_exists($path)) {
|
|
|
@@ -7220,7 +7219,7 @@ class Organizr
|
|
|
'options' => $options,
|
|
|
'data' => $apiData
|
|
|
];
|
|
|
- //$this->debug(json_encode($debugInformation));
|
|
|
+ $this->setLoggerChannel('Socks')->debug('Sending Socks request', $debugInformation);
|
|
|
try {
|
|
|
switch ($requestObject->getMethod()) {
|
|
|
case 'GET':
|
|
|
@@ -7241,6 +7240,7 @@ class Organizr
|
|
|
return $call->body;
|
|
|
} catch (Requests_Exception $e) {
|
|
|
$this->setAPIResponse('error', $e->getMessage(), 500);
|
|
|
+ $this->setLoggerChannel('Socks')->critical($e, $debugInformation);
|
|
|
return null;
|
|
|
}
|
|
|
} else {
|
|
|
@@ -7375,11 +7375,11 @@ class Organizr
|
|
|
|
|
|
protected function processQueries(array $request, $migration = false)
|
|
|
{
|
|
|
+ $this->setLoggerChannel('Database')->debug('Submitting query to database', $request);
|
|
|
$results = array();
|
|
|
$firstKey = '';
|
|
|
try {
|
|
|
foreach ($request as $k => $v) {
|
|
|
-
|
|
|
$query = ($migration) ? $this->otherDb->query($v['query']) : $this->db->query($v['query']);
|
|
|
$keyName = (isset($v['key'])) ? $v['key'] : $k;
|
|
|
$firstKey = (isset($v['key']) && $k == 0) ? $v['key'] : $k;
|
|
|
@@ -7410,11 +7410,11 @@ class Organizr
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
} catch (Exception $e) {
|
|
|
- $this->debug($e->getMessage());
|
|
|
+ $this->logger->critical($e, $request);
|
|
|
return false;
|
|
|
}
|
|
|
+ $this->logger->debug('Results from database', $results);
|
|
|
return count($request) > 1 ? $results : $results[$firstKey];
|
|
|
}
|
|
|
|