<?php namespace HashOver;// Copyright (C) 2015-2021 Jacob Barkdull// This file is part of HashOver.//// HashOver is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as// published by the Free Software Foundation, either version 3 of the// License, or (at your option) any later version.//// HashOver 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.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.class Login extends Secrets{	protected $setup;	protected $cookies;	protected $formData;	protected $locale;	protected $crypto;	protected $loginMethod;	protected $fieldNeeded;	public $name = '';	public $password = '';	public $loginHash = '';	public $email = '';	public $website = '';	public $userIsLoggedIn = false;	public $userIsAdmin = false;	public function __construct (Setup $setup)	{		// Store parameters as properties		$this->setup = $setup;		// Instantiate various classes		$this->cookies = new Cookies ($setup, $this);		$this->formData = new FormData ($setup, $this->cookies);		$this->locale = new Locale ($setup);		$this->crypto = new Crypto ();		// Name of login method class to instantiate		$login_class = 'HashOver\\' . $setup->loginMethod;		// Instantiate login method class		$this->loginMethod = new $login_class ($setup, $this->cookies, $this->locale);		// Error message to display to the user		$this->fieldNeeded = $this->locale->text['field-needed'];		// Check if user is logged in		$this->getLogin ();	}	// Prepares login credentials	public function prepareCredentials ()	{		// Set name		if (isset ($this->formData->data['name'])) {			$this->loginMethod->name = $this->formData->data['name'];		}		// Attempt to get name		$name = $this->setup->getRequest ('name');		// Attempt to get password		$password = $this->setup->getRequest ('password');		// Set password		if ($password !== false) {			$this->loginMethod->password = $this->crypto->createHash ($password);		} else {			$this->loginMethod->password = '';		}		// Check if login hash is not set		if ($this->loginHash === '') {			// If so, generate a random password			$random_password = bin2hex (openssl_random_pseudo_bytes (16));			// And use user password or random password			$password = $password ?: $random_password;		}		// Generate a RIPEMD-160 hash to indicate user login		$this->loginMethod->loginHash = hash ('ripemd160', $name . $password);		// Set e-mail address		if (isset ($this->formData->data['email'])) {			$this->loginMethod->email = $this->formData->data['email'];		}		// Set website URL		if (isset ($this->formData->data['website'])) {			$this->loginMethod->website = $this->formData->data['website'];		}	}	// Update login credentials	public function updateCredentials ()	{		$this->name = $this->loginMethod->name;		$this->password = $this->loginMethod->password;		$this->loginHash = $this->loginMethod->loginHash;		$this->email = $this->loginMethod->email;		$this->website = $this->loginMethod->website;		// Validate e-mail address		if (!empty ($this->email)) {			if (!filter_var ($this->email, FILTER_VALIDATE_EMAIL)) {				$this->email = '';			}		}		// Prepend "http://" to website URL if missing		if (!empty ($this->website)) {			if (!preg_match ('/htt(p|ps):\/\//i', $this->website)) {				$this->website = 'http://' . $this->website;			}		}	}	// Set login credentials	public function setCredentials ()	{		// Prepare login credentials		$this->prepareCredentials ();		// Set login method credentials		$this->loginMethod->setCredentials ();		// Update login credentials		$this->updateCredentials ();	}	// Get login method credentials	public function getCredentials ()	{		$this->loginMethod->getCredentials ();		$this->updateCredentials ();	}	// Checks if required fields have values	public function validateFields ()	{		// Run through login field options		foreach ($this->setup->formFields as $field => $status) {			// Check if current field is required and is empty			if ($status === 'required' and empty ($this->$field)) {				// If so, set cookies if request is not AJAX				if ($this->formData->viaAJAX !== true) {					$this->cookies->setFailedOn ($field, $this->formData->replyTo);				}				// And throw exception				throw new \Exception (sprintf (					$this->fieldNeeded, $this->locale->text[$field]				));			}		}		// Otherwise, fields are valid		return true;	}	// Checks login requirements	public function checkRequirements ($message)	{		// Check if a login is required		if ($this->setup->requiresLogin === true) {			// If so, throw exception if user is not logged in			if ($this->userIsLoggedIn === false) {				throw new \Exception ($message);			}		}		// Otherwise, login requirements are met		return true;	}	// Main login method	public function setLogin ()	{		// Do nothing if login is disabled		if ($this->setup->allowsLogin === false) {			return;		}		// Do nothing if login method is disabled		if ($this->loginMethod->enabled === false) {			return;		}		// Otherwise, throw exception if a non-HashOver login is required		$this->checkRequirements ('Normal login not allowed!');		// Set login method credentials		$this->setCredentials ();		// Check if required fields have values		$this->validateFields ();		// Execute login method's setLogin		$this->loginMethod->setLogin ();	}	// Admin login method	public function setAdminLogin ()	{		// Set login method credentials		$this->setCredentials ();		// Execute login method's setLogin		$this->loginMethod->setLogin ();	}	// Weak verification of an admin login	public function isAdmin ()	{		// Create login hash		$hash = hash ('ripemd160', $this->adminName . $this->adminPassword);		// Check if the hashes match		$match = ($this->loginHash === $hash);		// And return match		return $match;	}	// Logs user in as admin	public function adminLogin ()	{		// Do nothing if login isn't admin		if ($this->isAdmin () === false) {			return;		}		// Set e-mail to admin e-mail address		$this->loginMethod->email = $this->notificationEmail;		// Set website to current domain		$this->loginMethod->website = $this->setup->scheme . '://' . $this->setup->domain;		// Set login method credentials		$this->loginMethod->setCredentials ();		// Update login credentials		$this->updateCredentials ();		// And login method's setLogin		$this->loginMethod->setLogin ();	}	// Strict verification of an admin login	public function verifyAdmin ($password = false)	{		// If no password was given use the current password		$password = ($password === false) ? $this->password : $password;		// Check if passwords match		$match = $this->crypto->verifyHash ($this->adminPassword, $password);		//  And return match		return $match;	}	// Check if user is logged in	public function getLogin ()	{		// Get login method credentials		$this->getCredentials ();		// Check if user is logged in		if (!empty ($this->loginHash)) {			// If so, set login indicator			$this->userIsLoggedIn = true;			// Check if user is logged in as admin			if ($this->isAdmin () === true) {				$this->userIsAdmin = true;			}		}	}	// Main logout method	public function clearLogin ()	{		$this->loginMethod->clearLogin ();	}}