diff --git a/database/2025_01_03_190130_remove_local_users_table.php b/database/2025_01_03_190130_remove_local_users_table.php new file mode 100644 index 0000000..f676120 --- /dev/null +++ b/database/2025_01_03_190130_remove_local_users_table.php @@ -0,0 +1,18 @@ +execute(<<execute('DROP TABLE prm_users'); + } +} diff --git a/src/Auth/AuthInfo.php b/src/Auth/AuthInfo.php index 615d2c0..38b3009 100644 --- a/src/Auth/AuthInfo.php +++ b/src/Auth/AuthInfo.php @@ -1,30 +1,9 @@ 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; } } diff --git a/src/Auth/AuthInfoWrapper.php b/src/Auth/AuthInfoWrapper.php new file mode 100644 index 0000000..da5b70a --- /dev/null +++ b/src/Auth/AuthInfoWrapper.php @@ -0,0 +1,26 @@ +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; + } +} diff --git a/src/Auth/AuthRoutes.php b/src/Auth/AuthRoutes.php index 40010a9..7301f13 100644 --- a/src/Auth/AuthRoutes.php +++ b/src/Auth/AuthRoutes.php @@ -1,7 +1,7 @@ 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); } } } diff --git a/src/Auth/BlankAuthInfo.php b/src/Auth/BlankAuthInfo.php new file mode 100644 index 0000000..ae02aa9 --- /dev/null +++ b/src/Auth/BlankAuthInfo.php @@ -0,0 +1,21 @@ + $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; + } +} diff --git a/src/EEPROMContext.php b/src/EEPROMContext.php index 8d8cadf..8d23c3b 100644 --- a/src/EEPROMContext.php +++ b/src/EEPROMContext.php @@ -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)); diff --git a/src/Uploads/UploadsData.php b/src/Uploads/UploadsData.php index ab0a065..18b52aa 100644 --- a/src/Uploads/UploadsData.php +++ b/src/Uploads/UploadsData.php @@ -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); diff --git a/src/Uploads/UploadsRoutes.php b/src/Uploads/UploadsRoutes.php index ddb9a4e..64f2c0c 100644 --- a/src/Uploads/UploadsRoutes.php +++ b/src/Uploads/UploadsRoutes.php @@ -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); diff --git a/src/Users/UserInfo.php b/src/Users/UserInfo.php deleted file mode 100644 index 341399e..0000000 --- a/src/Users/UserInfo.php +++ /dev/null @@ -1,35 +0,0 @@ -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); - } -} diff --git a/src/Users/UsersContext.php b/src/Users/UsersContext.php deleted file mode 100644 index f5e8bf3..0000000 --- a/src/Users/UsersContext.php +++ /dev/null @@ -1,17 +0,0 @@ -users = new UsersData($dbConn); - } - - public function getUser(string $userId): UserInfo { - $this->users->ensureUserExists($userId); - return $this->users->getUser($userId); - } -} diff --git a/src/Users/UsersData.php b/src/Users/UsersData.php deleted file mode 100644 index 51bdb23..0000000 --- a/src/Users/UsersData.php +++ /dev/null @@ -1,30 +0,0 @@ -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(); - } -}