support for active fetching of user info
This commit is contained in:
		
							parent
							
								
									47efd74b6c
								
							
						
					
					
						commit
						63532c54ea
					
				
					 11 changed files with 188 additions and 27 deletions
				
			
		
							
								
								
									
										2
									
								
								contentnation.ini
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								contentnation.ini
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
[contentnation]
 | 
			
		||||
service-uri = http://local.contentnation.net
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,12 @@ class WebFinger
 | 
			
		|||
        if (preg_match("/^acct:([^@]+)@(.*)$/", $_resource, $matches) != 1 || $matches[2] !== $domain) {
 | 
			
		||||
            throw new \Federator\Exceptions\InvalidArgument();
 | 
			
		||||
        }
 | 
			
		||||
        $user = \Federator\DIO\User::getUserByName($this->main->getDatabase(), $matches[1]);
 | 
			
		||||
        $user = \Federator\DIO\User::getUserByName(
 | 
			
		||||
            $this->main->getDatabase(),
 | 
			
		||||
            $matches[1],
 | 
			
		||||
            $this->main->getConnector(),
 | 
			
		||||
            $this->main->getCache()
 | 
			
		||||
        );
 | 
			
		||||
        if ($user->id == 0) {
 | 
			
		||||
            throw new \Federator\Exceptions\FileNotFound();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								php/federator/cache/cache.php
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								php/federator/cache/cache.php
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -13,6 +13,15 @@ namespace Federator\Cache;
 | 
			
		|||
 */
 | 
			
		||||
interface Cache extends \Federator\Connector\Connector
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * save remote user by given name
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_name user/profile name
 | 
			
		||||
     * @param \Federator\Data\User $user user data
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function saveRemoteUserByName($_name, $user);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * save remote user by given session
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,14 @@ namespace Federator\Connector;
 | 
			
		|||
 */
 | 
			
		||||
interface Connector
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given name
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_name user/profile name
 | 
			
		||||
     * @return \Federator\Data\User | false
 | 
			
		||||
     */
 | 
			
		||||
    public function getRemoteUserByName(string $_name);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given session
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,9 +22,7 @@ class User
 | 
			
		|||
     */
 | 
			
		||||
    protected static function addLocalUser($dbh, $user, $_user)
 | 
			
		||||
    {
 | 
			
		||||
        echo "a new user\n";
 | 
			
		||||
        // needed fields: RSA key pair, user name (handle)
 | 
			
		||||
 | 
			
		||||
        $private_key = openssl_pkey_new();
 | 
			
		||||
        if ($private_key === false) {
 | 
			
		||||
            throw new \Federator\Exceptions\ServerError();
 | 
			
		||||
| 
						 | 
				
			
			@ -32,14 +30,20 @@ class User
 | 
			
		|||
        $public = openssl_pkey_get_details($private_key)['key'];
 | 
			
		||||
        $private = '';
 | 
			
		||||
        openssl_pkey_export($private_key, $private);
 | 
			
		||||
        $sql = 'insert into users (id, externalid, rsapublic, rsaprivate) values (?, ?, ?, ?)';
 | 
			
		||||
        $stmt = $dbh->prepare($sql);
 | 
			
		||||
        if ($stmt === false) {
 | 
			
		||||
            throw new \Federator\Exceptions\ServerError();
 | 
			
		||||
        try {
 | 
			
		||||
            $sql = 'insert into users (id, externalid, rsapublic, rsaprivate, validuntil)';
 | 
			
		||||
            $sql .= ' values (?, ?, ?, ?, now() + interval 1 day) on duplicate key update validuntil=now() + interval 1 day';
 | 
			
		||||
            $stmt = $dbh->prepare($sql);
 | 
			
		||||
            if ($stmt === false) {
 | 
			
		||||
                throw new \Federator\Exceptions\ServerError();
 | 
			
		||||
            }
 | 
			
		||||
            $stmt->bind_param("ssss", $_user, $user->externalid, $public, $private);
 | 
			
		||||
            $stmt->execute();
 | 
			
		||||
            $stmt->close();
 | 
			
		||||
            $user->id = $_user;
 | 
			
		||||
        } catch (\mysqli_sql_exception $e) {
 | 
			
		||||
            error_log($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
        $stmt->bind_param("ssss", $_user, $user->externalid, $public, $private);
 | 
			
		||||
        $stmt->execute();
 | 
			
		||||
        $stmt->close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -77,23 +81,50 @@ class User
 | 
			
		|||
     *          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)
 | 
			
		||||
    public static function getUserByName($dbh, $_name, $connector, $cache)
 | 
			
		||||
    {
 | 
			
		||||
        $sql = 'select id from users where id=?';
 | 
			
		||||
        $user = false;
 | 
			
		||||
        // ask cache
 | 
			
		||||
        if ($cache !== null) {
 | 
			
		||||
            $user = $cache->getRemoteUserByName($_name);
 | 
			
		||||
        }
 | 
			
		||||
        if ($user !== false) {
 | 
			
		||||
            return $user;
 | 
			
		||||
        }
 | 
			
		||||
        // check our db
 | 
			
		||||
        $sql = 'select id,externalid 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);
 | 
			
		||||
        $ret = $stmt->bind_result($user->id, $user->externalid);
 | 
			
		||||
        $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) {
 | 
			
		||||
            print_r($user);
 | 
			
		||||
            if ($user->id === null) {
 | 
			
		||||
                self::addLocalUser($dbh, $user, $_name);
 | 
			
		||||
            }
 | 
			
		||||
            $cache->saveRemoteUserByName($_name, $user);
 | 
			
		||||
        }
 | 
			
		||||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,8 +9,6 @@
 | 
			
		|||
 | 
			
		||||
namespace Federator;
 | 
			
		||||
 | 
			
		||||
require_once($_SERVER['DOCUMENT_ROOT'] . '../vendor/autoload.php');
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base class for Api and related classes
 | 
			
		||||
 * @author Sascha Nitsch
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +72,7 @@ class Main
 | 
			
		|||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        require_once($_SERVER['DOCUMENT_ROOT'] . '../vendor/autoload.php');
 | 
			
		||||
        $this->responseCode = 200;
 | 
			
		||||
        $rootDir = $_SERVER['DOCUMENT_ROOT'] . '../';
 | 
			
		||||
        $config = parse_ini_file($rootDir . 'config.ini', true);
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +130,26 @@ class Main
 | 
			
		|||
        return [$ret, $info];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get cache
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Federator\Cache\Cache
 | 
			
		||||
     */
 | 
			
		||||
    public function getCache()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->cache;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get connector
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Federator\Connector\Connector
 | 
			
		||||
     */
 | 
			
		||||
    public function getConnector()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->connector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get config
 | 
			
		||||
     * @return Array<String, Mixed>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,7 +112,8 @@ class Maintenance
 | 
			
		|||
    {
 | 
			
		||||
        echo "usage php maintenance.php <command>\n";
 | 
			
		||||
        echo "command can be one of:\n";
 | 
			
		||||
        echo " dbupgrade - this upgrades the db to the most recent version. Run this after you updated the program files\n";
 | 
			
		||||
        echo " dbupgrade - this upgrades the db to the most recent version.\n";
 | 
			
		||||
        echo " Run this after you updated the program files\n";
 | 
			
		||||
        exit();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,13 @@
 | 
			
		|||
  */
 | 
			
		||||
class ContentNation implements Connector
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * config parameter
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string, mixed> $config
 | 
			
		||||
     */
 | 
			
		||||
    private $config;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * service-URL
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -23,13 +30,43 @@ class ContentNation implements Connector
 | 
			
		|||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     *
 | 
			
		||||
     * @param array<string, mixed> $config
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($config)
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $config = parse_ini_file($_SERVER['DOCUMENT_ROOT'] . '../contentnation.ini');
 | 
			
		||||
        $this->service = $config['service-uri'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   /**
 | 
			
		||||
     * get remote user by given name
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_name user/profile name
 | 
			
		||||
     * @return \Federator\Data\User | false
 | 
			
		||||
     */
 | 
			
		||||
    public function getRemoteUserByName(string $_name)
 | 
			
		||||
    {
 | 
			
		||||
        // validate name
 | 
			
		||||
        if (preg_match("/^[a-zA-Z0-9_\-]+$/", $_name) != 1) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        $remoteURL = $this->service . '/api/users/info?user=' . urlencode($_name);
 | 
			
		||||
        $headers = ['Accept: application/json'];
 | 
			
		||||
        [$response, $info] = \Federator\Main::getFromRemote($remoteURL, $headers);
 | 
			
		||||
        if ($info['http_code'] != 200) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        $r = json_decode($response, true);
 | 
			
		||||
        if ($r === false || $r === null || !is_array($r)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (!array_key_exists('name', $r) || $r['name'] !== $_name) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        $user = new \Federator\Data\User();
 | 
			
		||||
        $user->externalid = $_name;
 | 
			
		||||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given session
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +115,6 @@ namespace Federator;
 | 
			
		|||
 */
 | 
			
		||||
function contentnation_load($main)
 | 
			
		||||
{
 | 
			
		||||
    $cn = new Connector\ContentNation($main->getConfig()['contentnation']);
 | 
			
		||||
    $cn = new Connector\ContentNation();
 | 
			
		||||
    $main->setConnector($cn);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,21 @@ class DummyConnector implements Connector
 | 
			
		|||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by name
 | 
			
		||||
     * @param string $_name user or profile name
 | 
			
		||||
     * @return \Federator\Data\User | false
 | 
			
		||||
     */
 | 
			
		||||
    public function getRemoteUserByName(string $_name)
 | 
			
		||||
    {
 | 
			
		||||
        // validate $_session and $user
 | 
			
		||||
        $user = new \Federator\Data\User();
 | 
			
		||||
        $user->externalid = $_name;
 | 
			
		||||
        $user->permissions = [];
 | 
			
		||||
        $user->session = '';
 | 
			
		||||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given session
 | 
			
		||||
     * @param string $_session session id
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,16 +69,34 @@ class RedisCache implements Cache
 | 
			
		|||
     * create key from session and user
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $prefix prefix to create name spaces
 | 
			
		||||
     * @param string $_session session id
 | 
			
		||||
     * @param string $_user user/profile name
 | 
			
		||||
     * @param string $input key name
 | 
			
		||||
     * @return string key
 | 
			
		||||
     */
 | 
			
		||||
    private static function createKey($prefix, $_session, $_user)
 | 
			
		||||
    private static function createKey($prefix, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $key = $prefix . '_';
 | 
			
		||||
        $key .= md5($_session . $_user);
 | 
			
		||||
        return $key;
 | 
			
		||||
        return $prefix . '_' . md5($input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given name
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_name user/profile name
 | 
			
		||||
     * @return \Federator\Data\User | false
 | 
			
		||||
     */
 | 
			
		||||
    public function getRemoteUserByName(string $_name)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->connected) {
 | 
			
		||||
            $this->connect();
 | 
			
		||||
        }
 | 
			
		||||
        $key = self::createKey('u', $_name);
 | 
			
		||||
        $data = $this->redis->get($key);
 | 
			
		||||
        if ($data === false) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        $user = \Federator\Data\User::createFromJson($data);
 | 
			
		||||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get remote user by given session
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +109,7 @@ class RedisCache implements Cache
 | 
			
		|||
        if (!$this->connected) {
 | 
			
		||||
            $this->connect();
 | 
			
		||||
        }
 | 
			
		||||
        $key = self::createKey('u', $_session, $_user);
 | 
			
		||||
        $key = self::createKey('s', $_session . $_user);
 | 
			
		||||
        $data = $this->redis->get($key);
 | 
			
		||||
        if ($data === false) {
 | 
			
		||||
            return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +118,20 @@ class RedisCache implements Cache
 | 
			
		|||
        return $user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * save remote user by namr
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $_name user/profile name
 | 
			
		||||
     * @param \Federator\Data\User $user user data
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function saveRemoteUserByName($_name, $user)
 | 
			
		||||
    {
 | 
			
		||||
        $key = self::createKey('u', $_name);
 | 
			
		||||
        $serialized = $user->toJson();
 | 
			
		||||
        $this->redis->setEx($key, $this->userTTL, $serialized,);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * save remote user by given session
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +142,7 @@ class RedisCache implements Cache
 | 
			
		|||
     */
 | 
			
		||||
    public function saveRemoteUserBySession($_session, $_user, $user)
 | 
			
		||||
    {
 | 
			
		||||
        $key = self::createKey('u', $_session, $_user);
 | 
			
		||||
        $key = self::createKey('s', $_session . $_user);
 | 
			
		||||
        $serialized = $user->toJson();
 | 
			
		||||
        $this->redis->setEx($key, $this->userTTL, $serialized,);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								sql/2024-07-21.sql
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								sql/2024-07-21.sql
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
alter table users add `validuntil` timestamp default 0;
 | 
			
		||||
update settings set `value`="2024-07-21" where `key`="database_version";
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue