flashii/eeprom
Archived
3
0
Fork 1

Removed RPC code from EEPROM.

This commit is contained in:
flash 2025-03-25 13:14:55 +00:00
parent c215037810
commit 4ebab430d3
Signed by: flash
GPG key ID: 2C9C2C574D47FE3E
6 changed files with 1 additions and 610 deletions

View file

@ -1,7 +1,6 @@
{
"require": {
"flashwave/index": "^0.2503",
"flashii/rpcii": "^5.0",
"flashii/apii": "^0.5",
"sentry/sdk": "^4.0",
"nesbot/carbon": "^3.8"

43
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "69bfd5e53bc3f331bc88d7f340ab3f98",
"content-hash": "312396765b1b560e34d33bdc8c6c23ec",
"packages": [
{
"name": "carbonphp/carbon-doctrine-types",
@ -114,47 +114,6 @@
"homepage": "https://api.flashii.net",
"time": "2025-03-25T11:42:32+00:00"
},
{
"name": "flashii/rpcii",
"version": "v5.0.1",
"source": {
"type": "git",
"url": "https://patchii.net/flashii/rpcii-php.git",
"reference": "28c25e0a342173524f8894d03158663842e03252"
},
"require": {
"ext-msgpack": ">=2.2",
"flashwave/index": "^0.2503",
"guzzlehttp/guzzle": "~7.0",
"php": ">=8.4",
"psr/http-client": "^1.0"
},
"require-dev": {
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^12.0"
},
"type": "library",
"autoload": {
"psr-4": {
"RPCii\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"bsd-3-clause-clear"
],
"authors": [
{
"name": "flashwave",
"email": "packagist@flash.moe",
"homepage": "https://flash.moe",
"role": "mom"
}
],
"description": "HTTP RPC client/server library.",
"homepage": "https://railgun.sh/rpcii",
"time": "2025-03-21T19:38:29+00:00"
},
{
"name": "flashwave/index",
"version": "v0.2503.230355",

View file

@ -4,8 +4,6 @@ namespace EEPROM;
use Index\Dependencies;
use Index\Config\Config;
use Index\Db\DbConnection;
use RPCii\HmacVerificationProvider;
use RPCii\Server\HttpRpcServer;
class EEPROMContext {
public private(set) Dependencies $deps;
@ -46,15 +44,6 @@ class EEPROMContext {
$routingCtx->register($this->dbCtx);
if($isApiDomain) {
$rpcServer = new HttpRpcServer;
$routingCtx->register($rpcServer->createRouteHandler(
new HmacVerificationProvider(fn() => $this->config->getString('rpcii:secret'))
));
$rpcServer->register($this->deps->constructLazy(Pools\PoolsRpcHandler::class));
$rpcServer->register($this->deps->constructLazy(Tasks\TasksRpcHandler::class));
$rpcServer->register($this->deps->constructLazy(Uploads\UploadsRpcHandler::class));
$routingCtx->register($this->deps->constructLazy(Auth\AuthRoutes::class));
$routingCtx->register($this->deps->constructLazy(Tasks\TasksRoutes::class));
$routingCtx->register($this->deps->constructLazy(Uploads\UploadsLegacyRoutes::class));

View file

@ -1,43 +0,0 @@
<?php
namespace EEPROM\Pools;
use RuntimeException;
use Index\XArray;
use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcQuery};
final class PoolsRpcHandler implements RpcHandler {
use RpcHandlerCommon;
public function __construct(
private PoolsContext $poolsCtx,
) {}
#[RpcQuery('eeprom:pools:all')]
public function queryAll(
bool $protected = false,
bool $deprecated = false
): array {
return [
'result' => XArray::select(
$this->poolsCtx->pools->getPools(
protected: $protected ? null : false,
deprecated: $deprecated ? null : false,
),
fn($poolInfo) => $this->poolsCtx->extractPool($poolInfo)
),
];
}
#[RpcQuery('eeprom:pools:get')]
public function queryGet(string $name): array|string {
try {
return [
'result' => $this->poolsCtx->extractPool(
$this->poolsCtx->pools->getPool($name, PoolInfoGetField::Name)
),
];
} catch(RuntimeException $ex) {
return 'pnf';
}
}
}

View file

@ -1,338 +0,0 @@
<?php
namespace EEPROM\Tasks;
use Exception;
use InvalidArgumentException;
use RuntimeException;
use EEPROM\HashHelpers;
use EEPROM\Denylist\DenylistContext;
use EEPROM\Pools\{CheckablePoolRuleArgs,CheckRuleException,PoolsContext,PoolInfoGetField};
use EEPROM\Storage\{StorageContext,StorageRecordGetFileField};
use EEPROM\Uploads\UploadsContext;
use Index\{UriBase64,XArray,XNumber};
use RPCii\Server\{RpcAction,RpcHandler,RpcHandlerCommon,RpcQuery};
final class TasksRpcHandler implements RpcHandler {
use RpcHandlerCommon;
public function __construct(
private TasksContext $tasksCtx,
private PoolsContext $poolsCtx,
private UploadsContext $uploadsCtx,
private StorageContext $storageCtx,
private DenylistContext $denylistCtx,
) {}
#[RpcAction('eeprom:tasks:create')]
public function actionTasksCreate(
string $remoteAddr,
string $userId,
string $poolName,
string $fileName,
int $fileSize,
string $fileType,
string $fileHash,
#[\SensitiveParameter] ?string $signature = null
) {
$cTime = time();
if($fileSize < 1)
return 'fsts';
if(strlen($fileType) > 255)
return 'fttl';
if(substr_count($fileType, '/') > 1)
return 'ftiv';
if(mb_strlen($fileName, 'UTF-8') > 255)
return 'fntl';
if(!ctype_digit($userId))
return 'uinn';
if(!filter_var($remoteAddr, FILTER_VALIDATE_IP))
return 'raiv';
try {
$fileHashBytes = HashHelpers::toBytes($fileHash);
} catch(InvalidArgumentException $ex) {
return 'fhiv';
}
try {
$poolInfo = $this->poolsCtx->pools->getPool($poolName, PoolInfoGetField::Name);
} catch(RuntimeException $ex) {
return 'pnnf';
}
if($poolInfo->protected) {
if($signature === null)
return 'srpp';
if(!str_contains($signature, '='))
$signature = UriBase64::decode($signature);
$signature = array_column(XArray::select(
explode(';', $signature),
fn($item) => XArray::select(
explode('=', $item, 2),
fn($item) => trim($item)
)
), 1, 0);
if(!array_key_exists('algo', $signature))
return 'sans';
if(!array_key_exists('hash', $signature))
return 'shns';
if(!array_key_exists('time', $signature))
return 'stns';
if(!array_key_exists('salt', $signature))
return 'ssns';
['algo' => $sAlgo, 'hash' => $sHash, 'time' => $sTime, 'salt' => $sSalt] = $signature;
$sAlgo = strtoupper($sAlgo);
if($sAlgo !== 'S256')
return 'sanv';
if(abs($cTime - (int)$sTime) >= 30)
return 'stnv';
if(strlen($sSalt) < 20)
return 'ssts';
try {
$sHash = HashHelpers::toBytes($sHash);
} catch(InvalidArgumentException $ex) {
return 'shnv';
}
$sData = sprintf('<|%s|>', implode('#!#', [$sTime, $userId, $poolName, $fileName, $fileSize, $fileType, $fileHash, $sSalt]));
if(!$poolInfo->verifyHash($sData, $sHash))
return 'shvf';
} elseif($signature !== null)
return 'smbn';
$denyInfo = $this->denylistCtx->getDenylistEntry($fileHash);
if($denyInfo !== null)
return [
'error' => 'fhdl',
'reason' => $denyInfo->reason->value,
];
try {
$ruleArgs = new CheckablePoolRuleArgs($fileName, $fileSize, $fileType, $fileHash);
$rules = $this->poolsCtx->getPoolRules($poolInfo)->getCheckableRules();
foreach($rules as $rule)
$rule->checkRule($ruleArgs);
} catch(CheckRuleException $ex) {
return [
'error' => 'prcf',
'rule' => $ex->rule,
'args' => $ex->args,
];
}
try {
$storageInfo = $this->storageCtx->records->getFile($fileHashBytes, StorageRecordGetFileField::Hash);
if($storageInfo->size !== $fileSize)
return 'fsnm';
try {
$variantInfo = $this->uploadsCtx->uploads->resolveUploadVariant($poolInfo, $userId, $storageInfo, '');
if(($variantInfo->type ?? $storageInfo->type) !== $fileType)
throw new RuntimeException;
$uploadInfo = $this->uploadsCtx->uploads->getUpload(uploadId: $variantInfo->uploadId);
if($uploadInfo->name !== $fileName)
throw new RuntimeException;
$this->uploadsCtx->uploads->updateUpload(
$uploadInfo,
fileName: $fileName,
accessedAt: true,
);
} catch(RuntimeException $ex) {
$uploadInfo = $this->uploadsCtx->uploads->createUpload($poolInfo, $userId, $fileName, $remoteAddr);
$variantInfo = $this->uploadsCtx->uploads->createUploadVariant($uploadInfo, '', $storageInfo, $fileType);
}
return [
'result' => [
'state' => TaskState::Complete->value,
'upload' => $this->uploadsCtx->extractUpload($uploadInfo, true, $poolInfo->name),
],
];
} catch(RuntimeException $ex) {}
try {
$taskInfo = $this->tasksCtx->tasks->createTask(
$poolInfo,
$userId,
$remoteAddr,
$fileName,
$fileSize,
$fileType,
$fileHashBytes
);
$path = $this->tasksCtx->getTaskWorkingPath($taskInfo);
$data = fopen($path, 'wb');
if($data === false) {
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to create task working file: %s', $path));
return 'wfcf';
}
if(!ftruncate($data, $fileSize)) {
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to reserve %d bytes for task working file: %s', $fileSize, $path));
return 'wfrf';
}
if(!fclose($data))
return 'wfff';
} catch(RuntimeException $ex) {
return 'utcf';
}
return [
'result' => [
'state' => $taskInfo->state->value,
'task_id' => $taskInfo->idWeb,
'task_url' => $this->tasksCtx->getTaskUrl($taskInfo),
'upload_id' => $taskInfo->uploadIdWeb,
'upload_url' => $this->uploadsCtx->getUploadUrl($taskInfo),
'expires_at' => $taskInfo->expiresAt->toIso8601ZuluString(),
],
];
}
#[RpcQuery('eeprom:tasks:get')]
public function actionTasksGet(string $taskId): string|array {
$taskSecret = substr($taskId, -16);
$taskId = (string)XNumber::fromBase62(substr($taskId, 0, -16));
try {
$taskInfo = $this->tasksCtx->tasks->getTask($taskId);
} catch(RuntimeException $ex) {
return 'tnf';
}
if(!$taskInfo->verifySecret($taskSecret))
return 'svf';
$body = [
'state' => $taskInfo->state->value,
];
switch($taskInfo->state) {
case TaskState::Pending:
$body['task_id'] = $taskInfo->idWeb;
$body['task_url'] = $this->tasksCtx->getTaskUrl($taskInfo);
$body['upload_id'] = $taskInfo->uploadIdWeb;
$body['upload_url'] = $this->uploadsCtx->getUploadUrl($taskInfo);
$body['expires_at'] = $taskInfo->expiresAt->toIso8601ZuluString();
break;
case TaskState::Complete:
$body['upload'] = [
'id' => $taskInfo->uploadIdWeb,
'user_id' => $taskInfo->userId,
'name' => $taskInfo->name,
'created_at' => $taskInfo->createdAt->toIso8601ZuluString(),
'type' => $taskInfo->type,
'size' => $taskInfo->size,
'hash' => $taskInfo->hashString,
'url' => $this->uploadsCtx->getUploadUrl($taskInfo),
];
break;
}
return [
'result' => $body,
];
}
#[RpcAction('eeprom:tasks:finish')]
public function actionsTasksFinish(string $taskId) {
$taskSecret = substr($taskId, -16);
$taskId = (string)XNumber::fromBase62(substr($taskId, 0, -16));
try {
$taskInfo = $this->tasksCtx->tasks->getTask($taskId);
} catch(RuntimeException $ex) {
return 'tnf';
}
if(!$taskInfo->verifySecret($taskSecret))
return 'svf';
if($taskInfo->state === TaskState::Pending)
try {
$path = $this->tasksCtx->getTaskWorkingPath($taskInfo);
if(!is_file($path)) {
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('working file does not exist: %s', $path));
return 'fne';
}
$hash = hash_file('sha256', $path, true);
if(!hash_equals($taskInfo->hash, $hash)) {
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('hash does not match, got %s, expected %s for path: %s', bin2hex($hash), bin2hex($taskInfo->hash), $path));
return 'hnm';
}
$fileType = trim($taskInfo->type, '/');
if($fileType === '')
$fileType = mime_content_type($path);
$storageInfo = $this->storageCtx->importFile($path, type: $fileType, hash: $hash);
try {
$variantInfo = $this->uploadsCtx->uploads->resolveUploadVariant(
$taskInfo->poolId, $taskInfo->userId, $storageInfo, ''
);
if(($variantInfo->type ?? $storageInfo->type) !== $fileType)
throw new RuntimeException;
$uploadInfo = $this->uploadsCtx->uploads->getUpload(uploadId: $variantInfo->uploadId);
$this->uploadsCtx->uploads->updateUpload(
$uploadInfo,
fileName: $taskInfo->name,
accessedAt: true,
);
} catch(RuntimeException $ex) {
$uploadInfo = $this->uploadsCtx->uploads->createUpload(
$taskInfo->poolId,
$taskInfo->userId,
$taskInfo->name,
$taskInfo->remoteAddress,
$taskInfo->id,
$taskInfo->uploadSecret,
$taskInfo->createdTime
);
$variantInfo = $this->uploadsCtx->uploads->createUploadVariant(
$uploadInfo, '', $storageInfo, $fileType
);
}
$this->tasksCtx->tasks->setTaskState($taskInfo, TaskState::Complete);
} catch(Exception $ex) {
$this->tasksCtx->tasks->setTaskError($taskInfo, $ex);
return 'tcf';
}
elseif($taskInfo->state === TaskState::Complete)
try {
$storageInfo = $this->storageCtx->records->getFile($taskInfo->hash, StorageRecordGetFileField::Hash);
$variantInfo = $this->uploadsCtx->uploads->resolveUploadVariant(
$taskInfo->poolId, $taskInfo->userId, $storageInfo, ''
);
$uploadInfo = $this->uploadsCtx->uploads->getUpload(uploadId: $variantInfo->uploadId);
} catch(RuntimeException $ex) {
return 'fnf';
}
else
return 'tnp';
return [
'result' => [
'state' => TaskState::Complete->value,
'upload' => $this->uploadsCtx->extractUpload($uploadInfo, true, true, [$variantInfo]),
],
];
}
}

View file

@ -1,175 +0,0 @@
<?php
namespace EEPROM\Uploads;
use RuntimeException;
use EEPROM\Pools\{PoolsContext,PoolInfoGetField};
use EEPROM\Storage\{StorageContext,StorageRecord,StorageRecordGetFileField};
use Index\{XArray,XNumber};
use RPCii\Server\{RpcAction,RpcHandler,RpcHandlerCommon,RpcQuery};
final class UploadsRpcHandler implements RpcHandler {
use RpcHandlerCommon;
public function __construct(
private PoolsContext $poolsCtx,
private UploadsContext $uploadsCtx,
private StorageContext $storageCtx,
) {}
#[RpcQuery('eeprom:uploads:all')]
public function queryAll(
?string $beforeId = null,
?int $limit = null,
?string $poolName = null,
bool $revealProtectedPool = false,
?string $userId = null
): array|string {
$poolInfo = null;
if($poolName !== null)
try {
$poolInfo = $this->poolsCtx->pools->getPool($poolName, PoolInfoGetField::Name);
if($poolInfo->protected && !$revealProtectedPool)
return 'pip';
} catch(RuntimeException $ex) {
return 'pnf';
}
if($beforeId !== null) {
if(strlen($beforeId) < 5)
return 'biv';
$beforeId = XNumber::fromBase62(substr($beforeId, 0, -4));
}
return [
'result' => XArray::select(
$this->uploadsCtx->uploads->getUploads(
poolInfo: $poolInfo,
userId: $userId,
ascending: false,
limit: $limit ?? 20,
beforeId: $beforeId,
),
fn($uploadInfo) => $this->uploadsCtx->extractUpload(
$uploadInfo,
$userId === null,
$poolInfo === null
),
),
];
}
#[RpcQuery('eeprom:uploads:get')]
public function queryGet(
string $uploadId,
?string $userId = null
): array|string {
if(strlen($uploadId) < 5)
return 'unf';
try {
return [
'result' => $this->uploadsCtx->extractUpload(
$this->uploadsCtx->uploads->getUpload(
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
secret: substr($uploadId, -4),
userId: $userId
),
$userId === null, true
),
];
} catch(RuntimeException $ex) {
return 'unf';
}
}
#[RpcAction('eeprom:uploads:delete')]
public function actionDelete(
string $uploadId,
?string $userId = null
): string {
if(strlen($uploadId) < 5)
return 'unf';
try {
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
secret: substr($uploadId, -4),
);
} catch(RuntimeException $ex) {
return 'unf';
}
if($userId !== null && $userId !== $uploadInfo->userId)
return 'dna';
try {
$this->uploadsCtx->uploads->deleteUpload($uploadInfo);
return '';
} catch(RuntimeException $ex) {
return 'duf';
}
}
#[RpcQuery('eeprom:uploads:variants:all')]
public function queryVariantsAll(
string $uploadId
): array|string {
if(strlen($uploadId) < 5)
return 'unf';
try {
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
secret: substr($uploadId, -4),
);
} catch(RuntimeException $ex) {
return 'unf';
}
return [
'result' => XArray::select(
$this->uploadsCtx->uploads->getUploadVariants($uploadInfo),
fn($variantInfo) => $this->uploadsCtx->extractUploadVariant(
$uploadInfo,
$variantInfo,
$this->storageCtx->records->getFile($variantInfo->fileId)
),
),
];
}
#[RpcQuery('eeprom:uploads:variants:get')]
public function queryVariantsGet(
string $uploadId,
string $variant
): array|string {
if(strlen($uploadId) < 5)
return 'unf';
try {
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
secret: substr($uploadId, -4),
);
} catch(RuntimeException $ex) {
return 'unf';
}
try {
$variantInfo = $this->uploadsCtx->uploads->getUploadVariant($uploadInfo, $variant);
} catch(RuntimeException $ex) {
return 'vnf';
}
try {
$storageInfo = $this->storageCtx->records->getFile($variantInfo->fileId);
} catch(RuntimeException $ex) {
return 'fnf';
}
return [
'result' => $this->uploadsCtx->extractUploadVariant($uploadInfo, $variantInfo, $storageInfo),
];
}
}