forked from grumpydevelop/federator
		
	- fixed rewrites to properly support @username/outbox, username/outbox, users/username/outbox, ... - initial support for sending follow to e.g. mastodon (code commented out in api.php) - database migration for follows table and fedusers table - save retrieved fedusers in cache and db - depend more on configs externaldomain, less on server_name - properly implemented following-logic in dio - made postForuUser static in newContent and inbox - provide rsaprivate for signing reuests -> actPub-Servers - change contenttype depending on use-case - changed user json-template to have loop-back between user-template and webfinger (mastodon f.e. needs this)
		
			
				
	
	
		
			262 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
 | 
						|
 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
						|
 *
 | 
						|
 * @author Sascha Nitsch (grumpydeveloper)
 | 
						|
 **/
 | 
						|
 | 
						|
namespace Federator\DIO;
 | 
						|
 | 
						|
/**
 | 
						|
 * IO functions related to users
 | 
						|
 */
 | 
						|
class User
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * add local user based on given user object received from remote service
 | 
						|
     * @param \mysqli $dbh database handle
 | 
						|
     * @param \Federator\Data\User $user user object to use
 | 
						|
     * @param string $_user user/profile name
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    protected static function addLocalUser($dbh, $user, $_user)
 | 
						|
    {
 | 
						|
        // check if it is timed out user
 | 
						|
        $sql = 'select unix_timestamp(`validuntil`) from users where id=?';
 | 
						|
        $stmt = $dbh->prepare($sql);
 | 
						|
        if ($stmt === false) {
 | 
						|
            throw new \Federator\Exceptions\ServerError();
 | 
						|
        }
 | 
						|
        $stmt->bind_param("s", $_user);
 | 
						|
        $validuntil = 0;
 | 
						|
        $ret = $stmt->bind_result($validuntil);
 | 
						|
        $stmt->execute();
 | 
						|
        if ($ret) {
 | 
						|
            $stmt->fetch();
 | 
						|
        }
 | 
						|
        $stmt->close();
 | 
						|
        if ($validuntil == 0) {
 | 
						|
            $private_key = openssl_pkey_new();
 | 
						|
            if ($private_key === false) {
 | 
						|
                throw new \Federator\Exceptions\ServerError();
 | 
						|
            }
 | 
						|
            $public = openssl_pkey_get_details($private_key)['key'];
 | 
						|
            $user->publicKey = $public;
 | 
						|
            $private = '';
 | 
						|
            openssl_pkey_export($private_key, $private);
 | 
						|
            $sql = 'insert into users (id, externalid, rsapublic, rsaprivate, validuntil,';
 | 
						|
            $sql .= ' type, name, summary, registered, iconmediatype, iconurl, imagemediatype, imageurl)';
 | 
						|
            $sql .= ' values (?, ?, ?, ?, now() + interval 1 day, ?, ?, ?, ?, ?, ?, ?, ?)';
 | 
						|
            $stmt = $dbh->prepare($sql);
 | 
						|
            if ($stmt === false) {
 | 
						|
                throw new \Federator\Exceptions\ServerError();
 | 
						|
            }
 | 
						|
            $registered = gmdate('Y-m-d H:i:s', $user->registered);
 | 
						|
            $stmt->bind_param(
 | 
						|
                "ssssssssssss",
 | 
						|
                $_user,
 | 
						|
                $user->externalid,
 | 
						|
                $public,
 | 
						|
                $private,
 | 
						|
                $user->type,
 | 
						|
                $user->name,
 | 
						|
                $user->summary,
 | 
						|
                $registered,
 | 
						|
                $user->iconMediaType,
 | 
						|
                $user->iconURL,
 | 
						|
                $user->imageMediaType,
 | 
						|
                $user->imageURL
 | 
						|
            );
 | 
						|
        } else {
 | 
						|
            // update to existing user
 | 
						|
            $sql = 'update users set validuntil=now() + interval 1 day, type=?, name=?, summary=?, registered=?,';
 | 
						|
            $sql .= ' iconmediatype=?, iconurl=?, imagemediatype=?, imageurl=? where id=?';
 | 
						|
            $stmt = $dbh->prepare($sql);
 | 
						|
            if ($stmt === false) {
 | 
						|
                throw new \Federator\Exceptions\ServerError();
 | 
						|
            }
 | 
						|
            $registered = gmdate('Y-m-d H:i:s', $user->registered);
 | 
						|
            $stmt->bind_param(
 | 
						|
                "sssssssss",
 | 
						|
                $user->type,
 | 
						|
                $user->name,
 | 
						|
                $user->summary,
 | 
						|
                $registered,
 | 
						|
                $user->iconMediaType,
 | 
						|
                $user->iconURL,
 | 
						|
                $user->imageMediaType,
 | 
						|
                $user->imageURL,
 | 
						|
                $_user
 | 
						|
            );
 | 
						|
        }
 | 
						|
        try {
 | 
						|
            $stmt->execute();
 | 
						|
            $stmt->close();
 | 
						|
            $user->id = $_user;
 | 
						|
        } catch (\mysqli_sql_exception $e) {
 | 
						|
            error_log($sql);
 | 
						|
            error_log(print_r($user, true));
 | 
						|
            error_log($e->getMessage());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * get private rsa key
 | 
						|
     * @return string|false key or false
 | 
						|
     */
 | 
						|
    public static function getrsaprivate(\mysqli $dbh, string $_user)
 | 
						|
    {
 | 
						|
        $sql = "select rsaprivate from users where id=?";
 | 
						|
        $stmt = $dbh->prepare($sql);
 | 
						|
        if ($stmt === false) {
 | 
						|
            throw new \Federator\Exceptions\ServerError();
 | 
						|
        }
 | 
						|
        $stmt->bind_param("s", $_user);
 | 
						|
        $ret = $stmt->bind_result($rsaPrivateKey);
 | 
						|
        $stmt->execute();
 | 
						|
        if ($ret) {
 | 
						|
            $stmt->fetch();
 | 
						|
        }
 | 
						|
        $stmt->close();
 | 
						|
        if ($rsaPrivateKey !== null) {
 | 
						|
            return $rsaPrivateKey;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * extend the given user with internal data
 | 
						|
     * @param \mysqli $dbh database  handle
 | 
						|
     * @param \Federator\Data\User $user user to extend
 | 
						|
     * @param string $_user user/profile name
 | 
						|
     */
 | 
						|
    protected static function extendUser(\mysqli $dbh, $user, $_user): void
 | 
						|
    {
 | 
						|
        $sql = 'select id,unix_timestamp(`validuntil`) from users where id=?';
 | 
						|
        $stmt = $dbh->prepare($sql);
 | 
						|
        if ($stmt === false) {
 | 
						|
            throw new \Federator\Exceptions\ServerError();
 | 
						|
        }
 | 
						|
        $stmt->bind_param("s", $_user);
 | 
						|
        $validuntil = 0;
 | 
						|
        $ret = $stmt->bind_result($user->id, $validuntil);
 | 
						|
        $stmt->execute();
 | 
						|
        if ($ret) {
 | 
						|
            $stmt->fetch();
 | 
						|
        }
 | 
						|
        $stmt->close();
 | 
						|
        // if a new user, create own database entry with additionally needed info
 | 
						|
        if ($user->id === null || $validuntil < time()) {
 | 
						|
            self::addLocalUser($dbh, $user, $_user);
 | 
						|
        }
 | 
						|
 | 
						|
        // no further processing for now
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * get user by name
 | 
						|
     *
 | 
						|
     * @param \mysqli $dbh
 | 
						|
     *          database handle
 | 
						|
     * @param string $_name
 | 
						|
     *          user name
 | 
						|
     * @param \Federator\Connector\Connector $connector
 | 
						|
     *          connector to fetch use with
 | 
						|
     * @param \Federator\Cache\Cache|null $cache
 | 
						|
     *          optional caching service
 | 
						|
     * @return \Federator\Data\User
 | 
						|
     */
 | 
						|
    public static function getUserByName($dbh, $_name, $connector, $cache)
 | 
						|
    {
 | 
						|
        $user = false;
 | 
						|
 | 
						|
        // ask cache
 | 
						|
        if ($cache !== null) {
 | 
						|
            $user = $cache->getRemoteUserByName($_name);
 | 
						|
        }
 | 
						|
        if ($user !== false) {
 | 
						|
            return $user;
 | 
						|
        }
 | 
						|
        // check our db
 | 
						|
        $sql = 'select id,externalid,type,name,summary,unix_timestamp(registered),rsapublic,';
 | 
						|
        $sql .= 'iconmediatype,iconurl,imagemediatype,imageurl from users where id=? and validuntil>=now()';
 | 
						|
        $stmt = $dbh->prepare($sql);
 | 
						|
        if ($stmt === false) {
 | 
						|
            throw new \Federator\Exceptions\ServerError();
 | 
						|
        }
 | 
						|
        $stmt->bind_param("s", $_name);
 | 
						|
        $user = new \Federator\Data\User();
 | 
						|
        $ret = $stmt->bind_result(
 | 
						|
            $user->id,
 | 
						|
            $user->externalid,
 | 
						|
            $user->type,
 | 
						|
            $user->name,
 | 
						|
            $user->summary,
 | 
						|
            $user->registered,
 | 
						|
            $user->publicKey,
 | 
						|
            $user->iconMediaType,
 | 
						|
            $user->iconURL,
 | 
						|
            $user->imageMediaType,
 | 
						|
            $user->imageURL,
 | 
						|
        );
 | 
						|
        $stmt->execute();
 | 
						|
        if ($ret) {
 | 
						|
            $stmt->fetch();
 | 
						|
        }
 | 
						|
        $stmt->close();
 | 
						|
 | 
						|
        if ($user->id === null) {
 | 
						|
            // ask connector for user-id
 | 
						|
            $ruser = $connector->getRemoteUserByName($_name);
 | 
						|
            if ($ruser !== false) {
 | 
						|
                $user = $ruser;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($cache !== null) {
 | 
						|
            if ($user->id === null && $user->externalid !== null) {
 | 
						|
                self::addLocalUser($dbh, $user, $_name);
 | 
						|
            }
 | 
						|
            $cache->saveRemoteUserByName($_name, $user);
 | 
						|
        }
 | 
						|
        return $user;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * get User by session id
 | 
						|
     *
 | 
						|
     * @param \mysqli $dbh
 | 
						|
     *          database handle
 | 
						|
     * @param string $_session
 | 
						|
     *          session
 | 
						|
     * @param string $_user
 | 
						|
     *          user/profile name
 | 
						|
     * @param \Federator\Connector\Connector $connector
 | 
						|
     *          connector to fetch use with
 | 
						|
     * @param \Federator\Cache\Cache|null $cache
 | 
						|
     *          optional caching service
 | 
						|
     * @return \Federator\Data\User|false
 | 
						|
     */
 | 
						|
    public static function getUserBySession($dbh, $_session, $_user, $connector, $cache)
 | 
						|
    {
 | 
						|
        $saveToCache = false;
 | 
						|
        $user = false;
 | 
						|
        if ($cache !== null) {
 | 
						|
            $user = $cache->getRemoteUserBySession($_session, $_user);
 | 
						|
        }
 | 
						|
 | 
						|
        if ($user === false) {
 | 
						|
            // ask connector for user-id
 | 
						|
            $user = $connector->getRemoteUserBySession($_session, $_user);
 | 
						|
            $saveToCache = true;
 | 
						|
        }
 | 
						|
        if ($user === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        self::extendUser($dbh, $user, $_user);
 | 
						|
        if ($cache !== null && $saveToCache) {
 | 
						|
            $cache->saveRemoteUserBySession($_session, $_user, $user);
 | 
						|
        }
 | 
						|
        return $user;
 | 
						|
    }
 | 
						|
}
 |