support for active fetching of user info
parent
47efd74b6c
commit
63532c54ea
|
@ -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) {
|
if (preg_match("/^acct:([^@]+)@(.*)$/", $_resource, $matches) != 1 || $matches[2] !== $domain) {
|
||||||
throw new \Federator\Exceptions\InvalidArgument();
|
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) {
|
if ($user->id == 0) {
|
||||||
throw new \Federator\Exceptions\FileNotFound();
|
throw new \Federator\Exceptions\FileNotFound();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,15 @@ namespace Federator\Cache;
|
||||||
*/
|
*/
|
||||||
interface Cache extends \Federator\Connector\Connector
|
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
|
* save remote user by given session
|
||||||
*
|
*
|
||||||
|
|
|
@ -13,6 +13,14 @@ namespace Federator\Connector;
|
||||||
*/
|
*/
|
||||||
interface 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
|
* get remote user by given session
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,9 +22,7 @@ class User
|
||||||
*/
|
*/
|
||||||
protected static function addLocalUser($dbh, $user, $_user)
|
protected static function addLocalUser($dbh, $user, $_user)
|
||||||
{
|
{
|
||||||
echo "a new user\n";
|
|
||||||
// needed fields: RSA key pair, user name (handle)
|
// needed fields: RSA key pair, user name (handle)
|
||||||
|
|
||||||
$private_key = openssl_pkey_new();
|
$private_key = openssl_pkey_new();
|
||||||
if ($private_key === false) {
|
if ($private_key === false) {
|
||||||
throw new \Federator\Exceptions\ServerError();
|
throw new \Federator\Exceptions\ServerError();
|
||||||
|
@ -32,14 +30,20 @@ class User
|
||||||
$public = openssl_pkey_get_details($private_key)['key'];
|
$public = openssl_pkey_get_details($private_key)['key'];
|
||||||
$private = '';
|
$private = '';
|
||||||
openssl_pkey_export($private_key, $private);
|
openssl_pkey_export($private_key, $private);
|
||||||
$sql = 'insert into users (id, externalid, rsapublic, rsaprivate) values (?, ?, ?, ?)';
|
try {
|
||||||
$stmt = $dbh->prepare($sql);
|
$sql = 'insert into users (id, externalid, rsapublic, rsaprivate, validuntil)';
|
||||||
if ($stmt === false) {
|
$sql .= ' values (?, ?, ?, ?, now() + interval 1 day) on duplicate key update validuntil=now() + interval 1 day';
|
||||||
throw new \Federator\Exceptions\ServerError();
|
$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
|
* database handle
|
||||||
* @param string $_name
|
* @param string $_name
|
||||||
* user 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
|
* @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);
|
$stmt = $dbh->prepare($sql);
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
throw new \Federator\Exceptions\ServerError();
|
throw new \Federator\Exceptions\ServerError();
|
||||||
}
|
}
|
||||||
$stmt->bind_param("s", $_name);
|
$stmt->bind_param("s", $_name);
|
||||||
$user = new \Federator\Data\User();
|
$user = new \Federator\Data\User();
|
||||||
$ret = $stmt->bind_result($user->id);
|
$ret = $stmt->bind_result($user->id, $user->externalid);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
if ($ret) {
|
if ($ret) {
|
||||||
$stmt->fetch();
|
$stmt->fetch();
|
||||||
}
|
}
|
||||||
$stmt->close();
|
$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;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
namespace Federator;
|
namespace Federator;
|
||||||
|
|
||||||
require_once($_SERVER['DOCUMENT_ROOT'] . '../vendor/autoload.php');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for Api and related classes
|
* Base class for Api and related classes
|
||||||
* @author Sascha Nitsch
|
* @author Sascha Nitsch
|
||||||
|
@ -74,6 +72,7 @@ class Main
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '../vendor/autoload.php');
|
||||||
$this->responseCode = 200;
|
$this->responseCode = 200;
|
||||||
$rootDir = $_SERVER['DOCUMENT_ROOT'] . '../';
|
$rootDir = $_SERVER['DOCUMENT_ROOT'] . '../';
|
||||||
$config = parse_ini_file($rootDir . 'config.ini', true);
|
$config = parse_ini_file($rootDir . 'config.ini', true);
|
||||||
|
@ -131,6 +130,26 @@ class Main
|
||||||
return [$ret, $info];
|
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
|
* get config
|
||||||
* @return Array<String, Mixed>
|
* @return Array<String, Mixed>
|
||||||
|
|
|
@ -112,7 +112,8 @@ class Maintenance
|
||||||
{
|
{
|
||||||
echo "usage php maintenance.php <command>\n";
|
echo "usage php maintenance.php <command>\n";
|
||||||
echo "command can be one of:\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();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,13 @@
|
||||||
*/
|
*/
|
||||||
class ContentNation implements Connector
|
class ContentNation implements Connector
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* config parameter
|
||||||
|
*
|
||||||
|
* @var array<string, mixed> $config
|
||||||
|
*/
|
||||||
|
private $config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* service-URL
|
* service-URL
|
||||||
*
|
*
|
||||||
|
@ -23,13 +30,43 @@ class ContentNation implements Connector
|
||||||
/**
|
/**
|
||||||
* constructor
|
* 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'];
|
$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
|
* get remote user by given session
|
||||||
*
|
*
|
||||||
|
@ -78,6 +115,6 @@ namespace Federator;
|
||||||
*/
|
*/
|
||||||
function contentnation_load($main)
|
function contentnation_load($main)
|
||||||
{
|
{
|
||||||
$cn = new Connector\ContentNation($main->getConfig()['contentnation']);
|
$cn = new Connector\ContentNation();
|
||||||
$main->setConnector($cn);
|
$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
|
* get remote user by given session
|
||||||
* @param string $_session session id
|
* @param string $_session session id
|
||||||
|
|
|
@ -69,16 +69,34 @@ class RedisCache implements Cache
|
||||||
* create key from session and user
|
* create key from session and user
|
||||||
*
|
*
|
||||||
* @param string $prefix prefix to create name spaces
|
* @param string $prefix prefix to create name spaces
|
||||||
* @param string $_session session id
|
* @param string $input key name
|
||||||
* @param string $_user user/profile name
|
|
||||||
* @return string key
|
* @return string key
|
||||||
*/
|
*/
|
||||||
private static function createKey($prefix, $_session, $_user)
|
private static function createKey($prefix, $input)
|
||||||
{
|
{
|
||||||
$key = $prefix . '_';
|
return $prefix . '_' . md5($input);
|
||||||
$key .= md5($_session . $_user);
|
|
||||||
return $key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* get remote user by given session
|
||||||
*
|
*
|
||||||
|
@ -91,7 +109,7 @@ class RedisCache implements Cache
|
||||||
if (!$this->connected) {
|
if (!$this->connected) {
|
||||||
$this->connect();
|
$this->connect();
|
||||||
}
|
}
|
||||||
$key = self::createKey('u', $_session, $_user);
|
$key = self::createKey('s', $_session . $_user);
|
||||||
$data = $this->redis->get($key);
|
$data = $this->redis->get($key);
|
||||||
if ($data === false) {
|
if ($data === false) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -100,6 +118,20 @@ class RedisCache implements Cache
|
||||||
return $user;
|
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
|
* save remote user by given session
|
||||||
*
|
*
|
||||||
|
@ -110,7 +142,7 @@ class RedisCache implements Cache
|
||||||
*/
|
*/
|
||||||
public function saveRemoteUserBySession($_session, $_user, $user)
|
public function saveRemoteUserBySession($_session, $_user, $user)
|
||||||
{
|
{
|
||||||
$key = self::createKey('u', $_session, $_user);
|
$key = self::createKey('s', $_session . $_user);
|
||||||
$serialized = $user->toJson();
|
$serialized = $user->toJson();
|
||||||
$this->redis->setEx($key, $this->userTTL, $serialized,);
|
$this->redis->setEx($key, $this->userTTL, $serialized,);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 New Issue