Removed local user storage.

This commit is contained in:
flash 2025-01-03 19:45:50 +00:00
parent 25599ddd08
commit 36994255f7
12 changed files with 125 additions and 145 deletions

View file

@ -0,0 +1,18 @@
<?php
use Index\Db\DbConnection;
use Index\Db\Migration\DbMigration;
final class RemoveLocalUsersTable_20250103_190130 implements DbMigration {
public function migrate(DbConnection $conn): void {
// Remove foreign key from prm_uploads
$conn->execute(<<<SQL
ALTER TABLE prm_uploads
DROP INDEX prm_uploads_user_foreign,
ADD INDEX prm_uploads_user_index (user_id) USING BTREE,
DROP FOREIGN KEY prm_uploads_user_foreign
SQL);
// Nuke table
$conn->execute('DROP TABLE prm_users');
}
}

View file

@ -1,30 +1,9 @@
<?php
namespace EEPROM\Auth;
use EEPROM\Users\UserInfo;
class AuthInfo {
public private(set) ?UserInfo $userInfo;
public function __construct() {
$this->setInfo();
}
public function setInfo(
?UserInfo $userInfo = null
): void {
$this->userInfo = $userInfo;
}
public function removeInfo(): void {
$this->setInfo();
}
public bool $loggedIn {
get => $this->userInfo !== null;
}
public ?string $userId {
get => $this->userInfo?->id;
}
interface AuthInfo {
public bool $authed { get; }
public ?string $userId { get; }
public bool $restricted { get; }
public int $legacyMultiplier { get; }
}

View file

@ -0,0 +1,26 @@
<?php
namespace EEPROM\Auth;
class AuthInfoWrapper implements AuthInfo {
public AuthInfo $value;
public function __construct(?AuthInfo $authInfo = null) {
$this->value = $authInfo ?? BlankAuthInfo::instance();
}
public bool $authed {
get => $this->value->authed;
}
public ?string $userId {
get => $this->value->userId;
}
public bool $restricted {
get => $this->value->restricted;
}
public int $legacyMultiplier {
get => $this->value->legacyMultiplier;
}
}

View file

@ -1,7 +1,7 @@
<?php
namespace EEPROM\Auth;
use EEPROM\Users\UsersContext;
use EEPROM\Auth\{BlankAuthInfo,FlashiiAuthInfo};
use Flashii\{FlashiiClient,FlashiiUrls};
use Flashii\Credentials\{BearerCredentials,MisuzuCredentials};
use Index\Config\Config;
@ -12,8 +12,7 @@ class AuthRoutes implements RouteHandler {
public function __construct(
private Config $config,
private AuthInfo $authInfo,
private UsersContext $usersCtx
private AuthInfoWrapper $authInfo
) {}
#[HttpMiddleware('/')]
@ -39,9 +38,8 @@ class AuthRoutes implements RouteHandler {
$this->config->getString('api', FlashiiUrls::PROD_API_URL)
));
$authInfo = $flashii->v1()->me();
if($authInfo !== null)
$this->authInfo->setInfo($this->usersCtx->getUser($authInfo->getId()));
$userInfo = $flashii->v1()->me();
$this->authInfo->value = $userInfo === null ? BlankAuthInfo::instance() : new FlashiiAuthInfo($userInfo);
}
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace EEPROM\Auth;
class BlankAuthInfo implements AuthInfo {
public private(set) bool $authed = false;
public private(set) ?string $userId = null;
public private(set) bool $restricted = true;
public private(set) int $legacyMultiplier = 0;
private static BlankAuthInfo $instance;
public static function init(): void {
self::$instance = new BlankAuthInfo;
}
public static function instance(): BlankAuthInfo {
return self::$instance;
}
}
BlankAuthInfo::init();

View file

@ -0,0 +1,29 @@
<?php
namespace EEPROM\Auth;
use Flashii\V1\Users\V1User;
class FlashiiAuthInfo implements AuthInfo {
public function __construct(
private V1User $userInfo
) {}
public private(set) bool $authed = true;
public ?string $userId {
get => $this->userInfo->getId();
}
public bool $restricted {
// temporary hack
get => $this->userInfo->hasRole('x-banned');
}
// replace this with an extended version of constrain_size that supports role specific size limits
public int $legacyMultiplier {
get => $this->userInfo->hasRole('admin')
|| $this->userInfo->hasRole('gmod')
|| $this->userInfo->hasRole('dev')
|| $this->userInfo->hasRole('tenshi') ? 2 : 1;
}
}

View file

@ -3,37 +3,32 @@ namespace EEPROM;
use Index\Config\Config;
use Index\Db\DbConnection;
use EEPROM\Auth\AuthInfo;
use EEPROM\Auth\AuthInfoWrapper;
use RPCii\HmacVerificationProvider;
use RPCii\Server\HttpRpcServer;
class EEPROMContext {
public private(set) DatabaseContext $database;
public private(set) SnowflakeGenerator $snowflake;
private AuthInfo $authInfo;
public private(set) AuthInfoWrapper $authInfo;
public private(set) Denylist\DenylistContext $denylistCtx;
public private(set) Pools\PoolsContext $poolsCtx;
public private(set) Storage\StorageContext $storageCtx;
public private(set) Uploads\UploadsContext $uploadsCtx;
private Users\UsersContext $usersCtx;
public function __construct(
private Config $config,
DbConnection $dbConn
) {
$this->snowflake = new SnowflakeGenerator;
$this->database = new DatabaseContext($dbConn);
$this->authInfo = new AuthInfo;
$this->snowflake = new SnowflakeGenerator;
$this->authInfo = new AuthInfoWrapper;
$this->denylistCtx = new Denylist\DenylistContext($dbConn);
$this->poolsCtx = new Pools\PoolsContext($dbConn);
$this->storageCtx = new Storage\StorageContext($config->scopeTo('storage'), $dbConn, $this->snowflake);
$this->uploadsCtx = new Uploads\UploadsContext($config->scopeTo('domain'), $dbConn, $this->snowflake);
$this->usersCtx = new Users\UsersContext($dbConn);
}
public function createRouting(bool $isApiDomain): RoutingContext {
@ -48,8 +43,7 @@ class EEPROMContext {
$routingCtx->register(new Auth\AuthRoutes(
$this->config->scopeTo('apii'),
$this->authInfo,
$this->usersCtx
$this->authInfo
));
$routingCtx->register(new LandingRoutes($this->database));

View file

@ -8,7 +8,6 @@ use Index\Db\{DbConnection,DbStatementCache,DbTools};
use EEPROM\SnowflakeGenerator;
use EEPROM\Pools\PoolInfo;
use EEPROM\Storage\StorageRecord;
use EEPROM\Users\UserInfo;
class UploadsData {
private DbStatementCache $cache;
@ -64,12 +63,12 @@ class UploadsData {
public function getUpload(
?string $uploadId = null,
PoolInfo|string|null $poolInfo = null,
UserInfo|string|null $userInfo = null,
string|null|false $userId = false,
?string $secret = null,
): UploadInfo {
$hasUploadId = $uploadId !== null;
$hasPoolInfo = $poolInfo !== null;
$hasUserInfo = $userInfo !== null;
$hasUserId = $userId !== false;
$hasSecret = $secret !== null;
$args = 0;
@ -80,8 +79,8 @@ class UploadsData {
}
if($hasPoolInfo)
$query .= sprintf(' %s pool_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
if($hasUserInfo)
$query .= sprintf(' %s user_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
if($hasUserId)
$query .= sprintf(' %s user_id %s', ++$args > 1 ? 'AND' : 'WHERE', $userId === null ? 'IS NULL' : '= ?');
if($hasSecret)
$query .= sprintf(' %s upload_secret = ?', ++$args > 1 ? 'AND' : 'WHERE');
@ -90,8 +89,8 @@ class UploadsData {
$stmt->nextParameter($uploadId);
if($hasPoolInfo)
$stmt->nextParameter($poolInfo instanceof PoolInfo ? $poolInfo->id : $poolInfo);
if($hasUserInfo)
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
if($hasUserId && $userId !== null)
$stmt->nextParameter($userId);
if($hasSecret)
$stmt->nextParameter($secret);
$stmt->execute();
@ -105,7 +104,7 @@ class UploadsData {
public function resolveUploadFromVariant(
PoolInfo|string $poolInfo,
UserInfo|string $userInfo,
?string $userId,
StorageRecord|string $fileInfo,
string $variant
): string {
@ -120,7 +119,7 @@ class UploadsData {
AND uf.upload_variant = ?
SQL);
$stmt->nextParameter($poolInfo instanceof PoolInfo ? $poolInfo->id : $poolInfo);
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
$stmt->nextParameter($userId);
$stmt->nextParameter($fileInfo instanceof StorageRecord ? $fileInfo->id : $fileInfo);
$stmt->nextParameter($variant);
$stmt->execute();
@ -134,7 +133,7 @@ class UploadsData {
public function createUpload(
PoolInfo|string $poolInfo,
UserInfo|string $userInfo,
?string $userId,
string $fileName,
string $remoteAddr
): UploadInfo {
@ -143,7 +142,7 @@ class UploadsData {
$stmt = $this->cache->get('INSERT INTO prm_uploads (upload_id, pool_id, user_id, upload_secret, upload_name, upload_ip) VALUES (?, ?, ?, ?, ?, INET6_ATON(?))');
$stmt->nextParameter($uploadId);
$stmt->nextParameter($poolInfo instanceof PoolInfo ? $poolInfo->id : $poolInfo);
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
$stmt->nextParameter($userId);
$stmt->nextParameter(XString::random(4));
$stmt->nextParameter($fileName);
$stmt->nextParameter($remoteAddr);

View file

@ -157,11 +157,10 @@ class UploadsRoutes implements RouteHandler {
if($request->getMethod() === 'OPTIONS')
return 204;
if(!$this->authInfo->loggedIn)
if(!$this->authInfo->authed)
return 401;
$userInfo = $this->authInfo->userInfo;
if($userInfo->restricted)
if($this->authInfo->restricted)
return 403;
if(!$request->isFormContent())
@ -197,7 +196,7 @@ class UploadsRoutes implements RouteHandler {
$maxFileSize = $maxSizeRule->maxSize;
if($maxSizeRule->allowLegacyMultiplier)
$maxFileSize *= $userInfo->dataSizeMultiplier;
$maxFileSize *= $this->authInfo->legacyMultiplier;
if($file->getSize() !== $fileSize || $fileSize > $maxFileSize) {
$response->setHeader('Access-Control-Expose-Headers', 'X-EEPROM-Max-Size');
@ -230,7 +229,7 @@ class UploadsRoutes implements RouteHandler {
// TODO: Okay so we're reading from the prm_uploads_files table, then fetching the info from prm_uploads,
// and then fetching the info again from the prm_uploads_files table... this can be done better but this will do for now
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
uploadId: $this->uploadsCtx->uploads->resolveUploadFromVariant($poolInfo, $userInfo, $storageInfo, '')
uploadId: $this->uploadsCtx->uploads->resolveUploadFromVariant($poolInfo, $this->authInfo->userId, $storageInfo, '')
);
$variantInfo = $this->uploadsCtx->uploads->getUploadVariant($uploadInfo, '');
@ -242,7 +241,7 @@ class UploadsRoutes implements RouteHandler {
} catch(RuntimeException $ex) {
$uploadInfo = $this->uploadsCtx->uploads->createUpload(
$poolInfo,
$userInfo,
$this->authInfo->userId,
$fileName,
$request->getRemoteAddress()
);
@ -267,7 +266,7 @@ class UploadsRoutes implements RouteHandler {
$response->setHeader('Access-Control-Allow-Headers', 'Authorization');
$response->setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, DELETE');
if(!$this->authInfo->loggedIn)
if(!$this->authInfo->authed)
return 401;
if(strlen($uploadId) === 32) {
@ -290,8 +289,7 @@ class UploadsRoutes implements RouteHandler {
return 404;
}
$userInfo = $this->authInfo->userInfo;
if($userInfo->restricted || $userInfo->id !== $uploadInfo->userId)
if($this->authInfo->restricted || $this->authInfo->userId !== $uploadInfo->userId)
return 403;
$this->uploadsCtx->uploads->deleteUpload($uploadInfo);

View file

@ -1,35 +0,0 @@
<?php
namespace EEPROM\Users;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;
class UserInfo {
public function __construct(
public private(set) string $id,
public private(set) int $createdTime,
public private(set) ?int $restrictedTime,
public private(set) int $dataSizeMultiplier,
) {}
public static function fromResult(DbResult $result): UserInfo {
return new UserInfo(
id: $result->getString(0),
createdTime: $result->getInteger(1),
restrictedTime: $result->getIntegerOrNull(2),
dataSizeMultiplier: $result->getInteger(3),
);
}
public CarbonImmutable $createdAt {
get => CarbonImmutable::createFromTimestampUTC($this->createdTime);
}
public bool $restricted {
get => $this->restrictedTime !== null;
}
public ?CarbonImmutable $restrictedAt {
get => $this->restrictedTime === null ? null : CarbonImmutable::createFromTimestampUTC($this->restrictedTime);
}
}

View file

@ -1,17 +0,0 @@
<?php
namespace EEPROM\Users;
use Index\Db\DbConnection;
class UsersContext {
public private(set) UsersData $users;
public function __construct(DbConnection $dbConn) {
$this->users = new UsersData($dbConn);
}
public function getUser(string $userId): UserInfo {
$this->users->ensureUserExists($userId);
return $this->users->getUser($userId);
}
}

View file

@ -1,30 +0,0 @@
<?php
namespace EEPROM\Users;
use Index\Db\{DbConnection,DbStatementCache};
// restrictions and permissions should be checked with misuzu or cached or something
// size multiplier should also just be replaced with an alternate max size value for premioids, maybe based on rank?
class UsersData {
private DbStatementCache $cache;
public function __construct(DbConnection $dbConn) {
$this->cache = new DbStatementCache($dbConn);
}
public function getUser(string $userId): ?UserInfo {
$stmt = $this->cache->get('SELECT user_id, UNIX_TIMESTAMP(user_created), UNIX_TIMESTAMP(user_restricted), user_size_multiplier FROM prm_users WHERE user_id = ?');
$stmt->nextParameter($userId);
$stmt->execute();
$result = $stmt->getResult();
return $result->next() ? UserInfo::fromResult($result) : null;
}
public function ensureUserExists(string $userId): void {
$stmt = $this->cache->get('INSERT IGNORE INTO prm_users (user_id) VALUES (?)');
$stmt->nextParameter($userId);
$stmt->execute();
}
}