diff options
author | Malf Furious <m@lfurio.us> | 2018-10-27 18:28:22 -0400 |
---|---|---|
committer | Malf Furious <m@lfurio.us> | 2018-10-27 18:28:22 -0400 |
commit | 0421aa1b60f4fe6bf140888159c58059c1013588 (patch) | |
tree | c3285276f6c53b6789e2f6dc82cb3b0fd17b38a4 /app/class/user.class.php | |
parent | 495157341d60522084dcc9f6219877b6ba497312 (diff) | |
parent | 6512655aee73d3d295daa4de0e4ef25c08cfec9e (diff) | |
download | scrott-0421aa1b60f4fe6bf140888159c58059c1013588.tar.gz scrott-0421aa1b60f4fe6bf140888159c58059c1013588.zip |
Merge branch 'rel/v0.1'v0.1
Diffstat (limited to 'app/class/user.class.php')
-rw-r--r-- | app/class/user.class.php | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/app/class/user.class.php b/app/class/user.class.php new file mode 100644 index 0000000..90aac44 --- /dev/null +++ b/app/class/user.class.php @@ -0,0 +1,336 @@ +<?php + +/* + * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to UNLICENSE + */ + +require_once "class/agent.class.php"; + +/* + * This class models Scrott users, including users without valid logins + * (external-users). + */ +class user extends agent +{ + /* + * Constructor + */ + public function __construct(?string $guid = NULL) + { + $this->fields['users'] = array( + "guid", + "auth", + "salt", + "alias", + "email", + "emailVer", + "admin", + "reg", + "emailConf", + ); + + parent::__construct($guid); + $this->expectType("user"); + } + + /* + * Get the GUID of a user object from a given username, or NULL if + * the username is not in use. Therefore, this function can be + * used to test the existence of a user with the given username. + */ + public static function getGuidByUname(string $uname) : ?string + { + $uname = database::esc($uname); + + $query = "SELECT guid FROM objects WHERE objtype = 'user' AND name = '" . $uname . "'"; + $res = database::query($query); + + if (count($res) == 0) + return NULL; + + return $res[0]['guid']; + } + + /* + * Get a user object from a given username, or NULL if the username + * is not in use. This function can be used to test the existence + * of a user with the given username. + */ + public static function getByUname(string $uname) : ?user + { + if (($guid = self::getGuidByUname($uname))) + return new user($guid); + + return NULL; + } + + /* + * Get an array of all users, sorted by username + */ + public static function getAll_ordByUname() : array + { + $query = "SELECT guid FROM objects WHERE objtype = 'user' ORDER BY name"; + $res = database::query($query); + + $users = array(); + + foreach ($res as $u) + $users[] = new user($u['guid']); + + return $users; + } + + /* + * Get an array of all users, sorted by admin (descending, admins + * first), then by username. + */ + public static function getAll_ordByAdminByUname() : array + { + $query = "SELECT o.guid FROM objects o JOIN users u ON o.guid = u.guid " . + "WHERE o.objtype = 'user' ORDER BY u.admin DESC, o.name"; + $res = database::query($query); + + $users = array(); + + foreach ($res as $u) + $users[] = new user($u['guid']); + + return $users; + } + + /* + * Get an array of all admins, sorted by username + */ + public static function getAllAdmin_ordByUname() : array + { + $query = "SELECT o.guid FROM objects o JOIN users u ON o.guid = u.guid " . + "WHERE o.objtype = 'user' AND u.admin = 1 ORDER BY o.name"; + $res = database::query($query); + + $users = array(); + + foreach ($res as $u) + $users[] = new user($u['guid']); + + return $users; + } + + /* + * Get the currently logged in user, or NULL if logged out. This + * function will throw if unable to aquire a PHP session. This + * function will also forcibly log the current user out if it + * detects any changes in the user-agent or remote IP address. + */ + public static function getCurrent() : ?user + { + if ((session_status() != PHP_SESSION_ACTIVE) && !session_start()) + throw new Exception("Unable to aquire a PHP session"); + + if (!isset($_SESSION['userguid'])) + return NULL; + + /* detect session hijacking */ + if (($_SESSION['useragent'] != $_SERVER['HTTP_USER_AGENT']) || + ($_SESSION['userip'] != $_SERVER['REMOTE_ADDR'])) + { + self::setCurrent(); + location("/"); + return NULL; + } + + try + { + return new user($_SESSION['userguid']); + } + catch (Exception $e) + { + /* invalid user */ + self::setCurrent(); + location("/"); + return NULL; + } + } + + /* + * Set the currently logged in user. Using NULL will logout any + * current user. This function will throw if unable to aquire a + * PHP session. This function will also cache the user-agent and + * remote IP address of the current request to help validate future + * requests made under the same session. + */ + public static function setCurrent(?user $user = NULL) : void + { + if ((session_status() != PHP_SESSION_ACTIVE) && !session_start()) + throw new Exception("Unable to aquire a PHP session"); + + unset($_SESSION['userguid']); + unset($_SESSION['useragent']); + unset($_SESSION['userip']); + + if ($user) + { + $_SESSION['userguid'] = $user->guid; + $_SESSION['useragent'] = $_SERVER['HTTP_USER_AGENT']; + $_SESSION['userip'] = $_SERVER['REMOTE_ADDR']; + } + } + + /* + * Initialize a new user object with the given username and plain + * text password. This function returns NULL if $uname is already + * being used. + */ + public static function initNew(string $uname, string $passwd) : ?user + { + if (self::getByUname($uname)) + return NULL; + + $user = new user(); + + /* if there exist no users already, make this new one an admin */ + if (count(self::getAll_ordByUname()) == 0) + $user->admin = 1; + + $user->name = $uname; + $user->objtype = "user"; + $user->setPasswd($passwd); + $user->setEmail(""); + $user->reg = 1; + $user->saveObj(); + + return $user; + } + + /* + * Get the salted and hashed form of a password + */ + private static function getAuth(string $passwd, string $salt) : string + { + return hash("sha256", $passwd . $salt); + } + + /* + * Validate the given plain-text password for this user. Returns true if + * correct, false otherwise. + */ + public function validatePasswd(string $passwd) : bool + { + $auth = self::getAuth($passwd, $this->salt); + return $auth == $this->auth; + } + + /* + * Update the auth and salt for this user, given a new plain-text + * password. + */ + public function setPasswd(string $passwd) : void + { + $this->salt = self::getBlob(); + $this->auth = self::getAuth($passwd, $this->salt); + $this->saveObj(); + } + + /* + * Validate the email confirmation code for this user. Returns true if + * correct, false otherwise. On success, $this->emailConf is also set + * to 1 + */ + public function verifyEmail(string $ver) : bool + { + if ($ver != $this->emailVer) + return false; + + $this->emailConf = 1; + $this->saveObj(); + return true; + } + + /* + * Update the email address for this user. This function will automatically + * reset the emailConf flag and confirmation code for this user as well. + */ + public function setEmail(string $email) : void + { + $this->email = $email; + $this->emailVer = substr(self::getBlob(), 0, 8); + $this->emailConf = 0; + $this->saveObj(); + } + + /* + * Get all groups this user owns or is a member of. This isn't necessarily + * all groups this user has access permissions for. Results are sorted by + * ownership, then by name. + */ + public function getGroups_ordByOwnByName() : array + { + $groups = array(); + + /* owner */ + $query = "SELECT guid FROM objects WHERE objtype = 'group' AND owner = '" . database::esc($this->guid) . "' " . + "ORDER BY name"; + $res = database::query($query); + + foreach ($res as $g) + $groups[] = new group($g['guid']); + + /* member */ + $query = "SELECT o.guid FROM objects o JOIN members m ON o.guid = m.guid WHERE o.objtype = 'group' AND " . + "m.member = '" . database::esc($this->guid) . "' ORDER BY o.name"; + $res = database::query($query); + + foreach ($res as $g) + $groups[] = new group($g['guid']); + + return $groups; + } + + /* + * Send an email message to this user using stored configuration + * parameters. If config is not established, delivery is not + * attempted. Return status. + */ + public function sendEmail(string $subj, string $mesg, + ?string $attachPath = NULL, ?string $attachName = NULL, + bool $ignoreEmailConf = false) : bool + { + if (settings::smtpServer() == "") + return false; + + if (!$ignoreEmailConf && !$this->emailConf) + return true; + + if ($this->email == "") + return true; + + $mail = new PHPMailer(); + $mail->isSMTP(); + $mail->SMTPAuth = true; + + $mail->Host = settings::smtpServer(); + $mail->Port = settings::smtpPort(); + $mail->Username = settings::smtpUname(); + $mail->Password = settings::smtpPasswd(); + $mail->SMTPSecure = settings::smtpSecurity(); + + $mail->setFrom(settings::smtpEmailAddress(), settings::smtpFrom()); + $mail->addAddress($this->email, $this->getDisplayName()); + $mail->Subject = $subj; + $mail->Body = $mesg; + + if ($attachPath && $attachName) + $mail->addAttachment($attachPath, $attachName); + + return $mail->send(); + } +} + +?> |