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…
Reference in a new issue