Updated EEPROM to latest Index.
This commit is contained in:
parent
f1513d1c0f
commit
1d4e7f0918
27 changed files with 784 additions and 464 deletions
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"require": {
|
||||
"flashwave/index": "^0.2410",
|
||||
"flashii/rpcii": "^3.0",
|
||||
"flashii/apii": "^0.3",
|
||||
"flashwave/index": "^0.2503",
|
||||
"flashii/rpcii": "^5.0",
|
||||
"flashii/apii": "^0.4",
|
||||
"sentry/sdk": "^4.0",
|
||||
"nesbot/carbon": "^3.7"
|
||||
"nesbot/carbon": "^3.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.0"
|
||||
"phpstan/phpstan": "^2.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
535
composer.lock
generated
535
composer.lock
generated
|
@ -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": "7009c2a98d8882c938653f4455f52a82",
|
||||
"content-hash": "2d07dcd636742c34625c576e67eaaf0b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
|
@ -77,18 +77,20 @@
|
|||
},
|
||||
{
|
||||
"name": "flashii/apii",
|
||||
"version": "v0.3.0",
|
||||
"version": "v0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://patchii.net/flashii/apii-php.git",
|
||||
"reference": "2d6c135faddd359341762afcb9c429e279d87059"
|
||||
"reference": "d330e0792515dbae2832bd8e2ac761cc685175e9"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
"guzzlehttp/guzzle": "~7.9",
|
||||
"php": ">=8.1",
|
||||
"psr/http-client": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.12",
|
||||
"phpunit/phpunit": "^10.5"
|
||||
"phpstan/phpstan": "~2.1",
|
||||
"phpunit/phpunit": "~10.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -110,24 +112,26 @@
|
|||
],
|
||||
"description": "Client library for the Flashii.net API.",
|
||||
"homepage": "https://api.flashii.net",
|
||||
"time": "2024-11-22T21:36:01+00:00"
|
||||
"time": "2025-03-20T17:05:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "flashii/rpcii",
|
||||
"version": "v3.0.0",
|
||||
"version": "v5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://patchii.net/flashii/rpcii-php.git",
|
||||
"reference": "25ac46d5dee60027032e175107e638dfb0b8f7f9"
|
||||
"reference": "28c25e0a342173524f8894d03158663842e03252"
|
||||
},
|
||||
"require": {
|
||||
"ext-msgpack": ">=2.2",
|
||||
"flashwave/index": "^0.2410",
|
||||
"php": ">=8.4"
|
||||
"flashwave/index": "^0.2503",
|
||||
"guzzlehttp/guzzle": "~7.0",
|
||||
"php": ">=8.4",
|
||||
"psr/http-client": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^11.5"
|
||||
"phpunit/phpunit": "^12.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -149,25 +153,27 @@
|
|||
],
|
||||
"description": "HTTP RPC client/server library.",
|
||||
"homepage": "https://railgun.sh/rpcii",
|
||||
"time": "2025-01-17T00:05:22+00:00"
|
||||
"time": "2025-03-21T19:38:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "flashwave/index",
|
||||
"version": "v0.2410.830205",
|
||||
"version": "v0.2503.221959",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://patchii.net/flash/index.git",
|
||||
"reference": "416c716b2efab9619d14be02a20cd6540e18a83f"
|
||||
"reference": "d99562db163589cc51e32e10e851085230fb3181"
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=8.3",
|
||||
"twig/html-extra": "^3.13",
|
||||
"twig/twig": "^3.14"
|
||||
"php": ">=8.4",
|
||||
"psr/http-message": "^2.0",
|
||||
"psr/http-server-handler": "^1.0",
|
||||
"twig/html-extra": "^3.20",
|
||||
"twig/twig": "^3.20"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpunit/phpunit": "^11.4"
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^12.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-memcache": "Support for the Index\\Cache\\Memcached namespace (only if you can't use ext-memcached for some reason).",
|
||||
|
@ -204,7 +210,216 @@
|
|||
],
|
||||
"description": "Composer package for the common library for my projects.",
|
||||
"homepage": "https://railgun.sh/index",
|
||||
"time": "2024-12-22T02:05:46+00:00"
|
||||
"time": "2025-03-22T19:59:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "d281ed313b989f213357e3be1a179f02196ac99b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
|
||||
"reference": "d281ed313b989f213357e3be1a179f02196ac99b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
|
||||
"guzzlehttp/psr7": "^2.7.0",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-client-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-curl": "*",
|
||||
"guzzle/client-integration-tests": "3.0.2",
|
||||
"php-http/message-factory": "^1.1",
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
|
||||
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "Required for CURL handler support",
|
||||
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
|
||||
"psr/log": "Required for using the Log middleware"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Lindblom",
|
||||
"email": "jeremeamia@gmail.com",
|
||||
"homepage": "https://github.com/jeremeamia"
|
||||
},
|
||||
{
|
||||
"name": "George Mponos",
|
||||
"email": "gmponos@gmail.com",
|
||||
"homepage": "https://github.com/gmponos"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com",
|
||||
"homepage": "https://github.com/sagikazarmark"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Schultze",
|
||||
"email": "webmaster@tubo-world.de",
|
||||
"homepage": "https://github.com/Tobion"
|
||||
}
|
||||
],
|
||||
"description": "Guzzle is a PHP HTTP client library",
|
||||
"keywords": [
|
||||
"client",
|
||||
"curl",
|
||||
"framework",
|
||||
"http",
|
||||
"http client",
|
||||
"psr-18",
|
||||
"psr-7",
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.9.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/Nyholm",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-24T11:22:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
|
||||
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Schultze",
|
||||
"email": "webmaster@tubo-world.de",
|
||||
"homepage": "https://github.com/Tobion"
|
||||
}
|
||||
],
|
||||
"description": "Guzzle promises library",
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/promises/issues",
|
||||
"source": "https://github.com/guzzle/promises/tree/2.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/Nyholm",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-17T10:06:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
|
@ -324,16 +539,16 @@
|
|||
},
|
||||
{
|
||||
"name": "jean85/pretty-package-versions",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Jean85/pretty-package-versions.git",
|
||||
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
|
||||
"reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
|
||||
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
|
||||
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a",
|
||||
"reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -343,8 +558,9 @@
|
|||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.2",
|
||||
"jean85/composer-provided-replaced-stub-package": "^1.0",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpunit/phpunit": "^7.5|^8.5|^9.6",
|
||||
"rector/rector": "^2.0",
|
||||
"vimeo/psalm": "^4.3 || ^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -377,22 +593,22 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
|
||||
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
|
||||
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1"
|
||||
},
|
||||
"time": "2024-11-18T16:19:46+00:00"
|
||||
"time": "2025-03-19T14:43:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "3.8.4",
|
||||
"version": "3.8.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/CarbonPHP/carbon.git",
|
||||
"reference": "129700ed449b1f02d70272d2ac802357c8c30c58"
|
||||
"reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58",
|
||||
"reference": "129700ed449b1f02d70272d2ac802357c8c30c58",
|
||||
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ff2f20cf83bd4d503720632ce8a426dc747bf7fd",
|
||||
"reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -468,8 +684,8 @@
|
|||
],
|
||||
"support": {
|
||||
"docs": "https://carbon.nesbot.com/docs",
|
||||
"issues": "https://github.com/briannesbitt/Carbon/issues",
|
||||
"source": "https://github.com/briannesbitt/Carbon"
|
||||
"issues": "https://github.com/CarbonPHP/carbon/issues",
|
||||
"source": "https://github.com/CarbonPHP/carbon"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -485,7 +701,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-27T09:25:35+00:00"
|
||||
"time": "2025-02-20T17:33:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/clock",
|
||||
|
@ -535,6 +751,58 @@
|
|||
},
|
||||
"time": "2022-11-25T14:36:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-client",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-client.git",
|
||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0 || ^8.0",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Client\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP clients",
|
||||
"homepage": "https://github.com/php-fig/http-client",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-client",
|
||||
"psr",
|
||||
"psr-18"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-client"
|
||||
},
|
||||
"time": "2023-09-23T14:17:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.1.0",
|
||||
|
@ -643,6 +911,62 @@
|
|||
},
|
||||
"time": "2023-04-04T09:54:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-server-handler",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-server-handler.git",
|
||||
"reference": "84c4fb66179be4caaf8e97bd239203245302e7d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4",
|
||||
"reference": "84c4fb66179be4caaf8e97bd239203245302e7d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP server-side request handler",
|
||||
"keywords": [
|
||||
"handler",
|
||||
"http",
|
||||
"http-interop",
|
||||
"psr",
|
||||
"psr-15",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response",
|
||||
"server"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-server-handler/tree/1.0.2"
|
||||
},
|
||||
"time": "2023-04-10T20:06:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.2",
|
||||
|
@ -1024,16 +1348,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.2.1",
|
||||
"version": "v7.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283"
|
||||
"reference": "87ca22046b78c3feaff04b337f33b38510fd686b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/7f9617fcf15cb61be30f8b252695ed5e2bfac283",
|
||||
"reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/87ca22046b78c3feaff04b337f33b38510fd686b",
|
||||
"reference": "87ca22046b78c3feaff04b337f33b38510fd686b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1088,7 +1412,7 @@
|
|||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.2.1"
|
||||
"source": "https://github.com/symfony/mime/tree/v7.2.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1104,7 +1428,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-07T08:50:44+00:00"
|
||||
"time": "2025-02-19T08:51:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
|
@ -1496,82 +1820,6 @@
|
|||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php81\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php83",
|
||||
"version": "v1.31.0",
|
||||
|
@ -1650,16 +1898,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v7.2.2",
|
||||
"version": "v7.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "e2674a30132b7cc4d74540d6c2573aa363f05923"
|
||||
"reference": "283856e6981286cc0d800b53bd5703e8e363f05a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923",
|
||||
"reference": "e2674a30132b7cc4d74540d6c2573aa363f05923",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/283856e6981286cc0d800b53bd5703e8e363f05a",
|
||||
"reference": "283856e6981286cc0d800b53bd5703e8e363f05a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1725,7 +1973,7 @@
|
|||
"description": "Provides tools to internationalize your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation/tree/v7.2.2"
|
||||
"source": "https://github.com/symfony/translation/tree/v7.2.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1741,7 +1989,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-07T08:18:10+00:00"
|
||||
"time": "2025-02-13T10:27:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation-contracts",
|
||||
|
@ -1823,20 +2071,20 @@
|
|||
},
|
||||
{
|
||||
"name": "twig/html-extra",
|
||||
"version": "v3.18.0",
|
||||
"version": "v3.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/html-extra.git",
|
||||
"reference": "c63b28e192c1b7c15bb60f81d2e48b140846239a"
|
||||
"reference": "f7d54d4de1b64182af745cfb66777f699b599734"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/html-extra/zipball/c63b28e192c1b7c15bb60f81d2e48b140846239a",
|
||||
"reference": "c63b28e192c1b7c15bb60f81d2e48b140846239a",
|
||||
"url": "https://api.github.com/repos/twigphp/html-extra/zipball/f7d54d4de1b64182af745cfb66777f699b599734",
|
||||
"reference": "f7d54d4de1b64182af745cfb66777f699b599734",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"php": ">=8.1.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/mime": "^5.4|^6.4|^7.0",
|
||||
"twig/twig": "^3.13|^4.0"
|
||||
|
@ -1875,7 +2123,7 @@
|
|||
"twig"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/html-extra/tree/v3.18.0"
|
||||
"source": "https://github.com/twigphp/html-extra/tree/v3.20.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1887,28 +2135,27 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-29T10:29:59+00:00"
|
||||
"time": "2025-01-31T20:45:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.18.0",
|
||||
"version": "v3.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50"
|
||||
"reference": "3468920399451a384bef53cf7996965f7cd40183"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50",
|
||||
"reference": "acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183",
|
||||
"reference": "3468920399451a384bef53cf7996965f7cd40183",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"php": ">=8.1.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-mbstring": "^1.3",
|
||||
"symfony/polyfill-php81": "^1.29"
|
||||
"symfony/polyfill-mbstring": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.0",
|
||||
|
@ -1955,7 +2202,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.18.0"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.20.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1967,22 +2214,22 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-29T10:51:50+00:00"
|
||||
"time": "2025-02-13T08:34:43+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.1",
|
||||
"version": "2.1.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7"
|
||||
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7",
|
||||
"reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f",
|
||||
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2027,7 +2274,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-05T16:43:48+00:00"
|
||||
"time": "2025-03-09T09:30:48+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -28,7 +28,8 @@ class AuthContext {
|
|||
|
||||
public function createClient(Credentials $credentials): FlashiiClient {
|
||||
return new FlashiiClient('EEPROM', $credentials, new FlashiiUrls(
|
||||
$this->config->getString('api', FlashiiUrls::PROD_API_URL)
|
||||
$this->config->getString('url', FlashiiUrls::PROD_URL),
|
||||
$this->config->getString('api', FlashiiUrls::PROD_API_URL),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
<?php
|
||||
namespace EEPROM\Auth;
|
||||
|
||||
use Index\Http\Routing\{HttpMiddleware,RouteHandler,RouteHandlerTrait};
|
||||
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\Routing\Processors\Preprocessor;
|
||||
use Index\Http\Routing\{HttpMiddleware,RouteHandler,RouteHandlerCommon};
|
||||
|
||||
class AuthRoutes implements RouteHandler {
|
||||
use RouteHandlerTrait;
|
||||
use RouteHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private AuthContext $authCtx
|
||||
) {}
|
||||
|
||||
#[HttpMiddleware('/')]
|
||||
public function getIndex($response, $request) {
|
||||
#[Preprocessor('eeprom:attempt-auth')]
|
||||
public function getIndex(HttpResponseBuilder $response, HttpRequest $request) {
|
||||
$auth = $request->getHeaderLine('Authorization');
|
||||
if(empty($auth)) {
|
||||
$cookie = (string)$request->getCookie('msz_auth');
|
||||
|
@ -21,7 +23,7 @@ class AuthRoutes implements RouteHandler {
|
|||
|
||||
if(!empty($auth)) {
|
||||
$parts = explode(' ', $auth, 2);
|
||||
$method = strval($parts[0] ?? '');
|
||||
$method = $parts[0];
|
||||
$token = strval($parts[1] ?? '');
|
||||
|
||||
$flashii = null;
|
||||
|
|
|
@ -3,22 +3,23 @@ namespace EEPROM;
|
|||
|
||||
use Index\Db\DbConnection;
|
||||
use Index\Db\Migration\{DbMigrationManager,DbMigrationRepo,FsDbMigrationRepo};
|
||||
use Index\Http\Routing\{HttpMiddleware,RouteHandler,RouteHandlerTrait};
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Filters\PrefixFilter;
|
||||
|
||||
class DatabaseContext implements RouteHandler {
|
||||
use RouteHandlerTrait;
|
||||
use RouteHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
public private(set) DbConnection $connection
|
||||
public private(set) DbConnection $conn
|
||||
) {}
|
||||
|
||||
public function getQueryCount(): int {
|
||||
$result = $this->connection->query('SHOW SESSION STATUS LIKE "Questions"');
|
||||
$result = $this->conn->query('SHOW SESSION STATUS LIKE "Questions"');
|
||||
return $result->next() ? $result->getInteger(1) : 0;
|
||||
}
|
||||
|
||||
public function createMigrationManager(): DbMigrationManager {
|
||||
return new DbMigrationManager($this->connection, 'prm_' . DbMigrationManager::DEFAULT_TABLE);
|
||||
return new DbMigrationManager($this->conn, 'prm_' . DbMigrationManager::DEFAULT_TABLE);
|
||||
}
|
||||
|
||||
public function createMigrationRepo(): DbMigrationRepo {
|
||||
|
@ -29,7 +30,7 @@ class DatabaseContext implements RouteHandler {
|
|||
return sys_get_temp_dir() . '/eeprom-migrate-' . hash('sha256', PRM_ROOT) . '.lock';
|
||||
}
|
||||
|
||||
#[HttpMiddleware('/')]
|
||||
#[PrefixFilter('/')]
|
||||
public function middleware() {
|
||||
if(is_file($this->getMigrateLockPath()))
|
||||
return 503;
|
||||
|
|
30
src/EEPROMAccessControlHandler.php
Normal file
30
src/EEPROMAccessControlHandler.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace EEPROM;
|
||||
|
||||
use Index\Http\HttpUri;
|
||||
use Index\Http\Routing\HandlerContext;
|
||||
use Index\Http\Routing\Routes\RouteInfo;
|
||||
use Index\Http\Routing\AccessControl\{AccessControl,SimpleAccessControlHandler};
|
||||
|
||||
class EEPROMAccessControlHandler extends SimpleAccessControlHandler {
|
||||
public function __construct(
|
||||
private array $origins,
|
||||
) {}
|
||||
|
||||
#[\Override]
|
||||
public function checkAccess(
|
||||
HandlerContext $context,
|
||||
AccessControl $accessControl,
|
||||
HttpUri $origin,
|
||||
?RouteInfo $routeInfo = null,
|
||||
): string|bool {
|
||||
if($accessControl->credentials) {
|
||||
$host = '.' . $origin->host;
|
||||
foreach($this->origins as $allowOrigin)
|
||||
if(str_ends_with($host, '.' . $allowOrigin))
|
||||
return (string)$origin;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
namespace EEPROM;
|
||||
|
||||
use EEPROM\Auth\AuthInfoWrapper;
|
||||
use Index\Dependencies;
|
||||
use Index\Config\Config;
|
||||
use Index\Db\DbConnection;
|
||||
use RPCii\HmacVerificationProvider;
|
||||
use RPCii\Server\HttpRpcServer;
|
||||
|
||||
class EEPROMContext {
|
||||
public private(set) DatabaseContext $database;
|
||||
public private(set) Dependencies $deps;
|
||||
|
||||
public private(set) DatabaseContext $dbCtx;
|
||||
public private(set) SnowflakeGenerator $snowflake;
|
||||
|
||||
public private(set) Auth\AuthContext $authCtx;
|
||||
|
@ -22,30 +24,26 @@ class EEPROMContext {
|
|||
private Config $config,
|
||||
DbConnection $dbConn
|
||||
) {
|
||||
$this->database = new DatabaseContext($dbConn);
|
||||
$this->snowflake = new SnowflakeGenerator;
|
||||
$this->deps = new Dependencies;
|
||||
$this->deps->register($this);
|
||||
$this->deps->register($this->deps);
|
||||
|
||||
$this->authCtx = new Auth\AuthContext($config->scopeTo('apii'));
|
||||
$this->denylistCtx = new Denylist\DenylistContext($dbConn);
|
||||
$this->poolsCtx = new Pools\PoolsContext($dbConn);
|
||||
$this->storageCtx = new Storage\StorageContext($config->scopeTo('storage'), $dbConn, $this->snowflake);
|
||||
$this->tasksCtx = new Tasks\TasksContext($config->scopeTo('domain'), $dbConn, $this->snowflake);
|
||||
$this->uploadsCtx = new Uploads\UploadsContext(
|
||||
$config->scopeTo('domain'), $dbConn, $this->snowflake, $this->poolsCtx, $this->storageCtx,
|
||||
);
|
||||
$this->deps->register($this->dbCtx = new DatabaseContext($dbConn));
|
||||
$this->deps->register($this->dbCtx->conn);
|
||||
|
||||
$this->deps->register($this->snowflake = $this->deps->constructLazy(SnowflakeGenerator::class));
|
||||
|
||||
$this->deps->register($this->authCtx = $this->deps->constructLazy(Auth\AuthContext::class, $config->scopeTo('apii')));
|
||||
$this->deps->register($this->denylistCtx = $this->deps->constructLazy(Denylist\DenylistContext::class));
|
||||
$this->deps->register($this->poolsCtx = $this->deps->constructLazy(Pools\PoolsContext::class));
|
||||
$this->deps->register($this->storageCtx = $this->deps->constructLazy(Storage\StorageContext::class, $config->scopeTo('storage')));
|
||||
$this->deps->register($this->tasksCtx = $this->deps->constructLazy(Tasks\TasksContext::class, $config->scopeTo('domain')));
|
||||
$this->deps->register($this->uploadsCtx = $this->deps->constructLazy(Uploads\UploadsContext::class, $config->scopeTo('domain')));
|
||||
}
|
||||
|
||||
public function createRouting(bool $isApiDomain): RoutingContext {
|
||||
$routingCtx = new RoutingContext($this->config->scopeTo('cors'));
|
||||
$routingCtx->register($this->database);
|
||||
|
||||
$routingCtx->register($uploadsViewsRoutes = new Uploads\UploadsViewRoutes(
|
||||
$this->poolsCtx,
|
||||
$this->uploadsCtx,
|
||||
$this->storageCtx,
|
||||
$this->denylistCtx,
|
||||
$isApiDomain,
|
||||
));
|
||||
$routingCtx->register($this->dbCtx);
|
||||
|
||||
if($isApiDomain) {
|
||||
$rpcServer = new HttpRpcServer;
|
||||
|
@ -53,33 +51,16 @@ class EEPROMContext {
|
|||
new HmacVerificationProvider(fn() => $this->config->getString('rpcii:secret'))
|
||||
));
|
||||
|
||||
$rpcServer->register(new Pools\PoolsRpcHandler(
|
||||
$this->poolsCtx,
|
||||
));
|
||||
$rpcServer->register(new Tasks\TasksRpcHandler(
|
||||
$this->tasksCtx,
|
||||
$this->poolsCtx,
|
||||
$this->uploadsCtx,
|
||||
$this->storageCtx,
|
||||
$this->denylistCtx,
|
||||
));
|
||||
$rpcServer->register(new Uploads\UploadsRpcHandler(
|
||||
$this->poolsCtx,
|
||||
$this->uploadsCtx,
|
||||
$this->storageCtx,
|
||||
));
|
||||
$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(new Auth\AuthRoutes($this->authCtx));
|
||||
$routingCtx->register(new Tasks\TasksRoutes($this->tasksCtx));
|
||||
$routingCtx->register(new Uploads\UploadsLegacyRoutes(
|
||||
$this->authCtx,
|
||||
$this->poolsCtx,
|
||||
$this->uploadsCtx,
|
||||
$this->storageCtx,
|
||||
$this->denylistCtx,
|
||||
));
|
||||
$routingCtx->register(new LandingRoutes($this->database));
|
||||
}
|
||||
$routingCtx->register($this->deps->constructLazy(Auth\AuthRoutes::class));
|
||||
$routingCtx->register($this->deps->constructLazy(Tasks\TasksRoutes::class));
|
||||
$routingCtx->register($this->deps->constructLazy(Uploads\UploadsLegacyRoutes::class));
|
||||
$routingCtx->register($this->deps->constructLazy(LandingRoutes::class));
|
||||
} else
|
||||
$routingCtx->register($this->deps->constructLazy(Uploads\UploadsViewRoutes::class));
|
||||
|
||||
return $routingCtx;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
<?php
|
||||
namespace EEPROM;
|
||||
|
||||
use Index\Http\{HttpErrorHandler,HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\HttpResponse;
|
||||
use Index\Http\Routing\HandlerContext;
|
||||
use Index\Http\Routing\ErrorHandling\ErrorHandler;
|
||||
use Index\Http\Streams\Stream;
|
||||
|
||||
class EEPROMErrorHandler implements HttpErrorHandler {
|
||||
public function handle(HttpResponseBuilder $response, HttpRequest $request, int $code, string $message): void {
|
||||
$response->setContent(sprintf('<!doctype html><title>%1$03d %2$s</title><strong>%1$03d %2$s</strong>', $code, $message));
|
||||
class EEPROMErrorHandler implements ErrorHandler {
|
||||
public function handle(HandlerContext $context): void {
|
||||
if(!$context->response->needsBody)
|
||||
return;
|
||||
|
||||
$context->response->setTypeHTML();
|
||||
$context->response->body = Stream::createStream(sprintf(
|
||||
'<!doctype html><title>%1$03d %2$s</title><strong>%1$03d %2$s</strong>',
|
||||
$context->response->statusCode,
|
||||
$context->response->reasonPhrase === ''
|
||||
? HttpResponse::defaultReasonPhase($context->response->statusCode)
|
||||
: $context->response->reasonPhrase
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,22 +2,24 @@
|
|||
namespace EEPROM;
|
||||
|
||||
use stdClass;
|
||||
use Index\Http\Routing\{HttpGet,RouteHandler,RouteHandlerTrait};
|
||||
use Index\Http\HttpResponseBuilder;
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Routes\ExactRoute;
|
||||
|
||||
class LandingRoutes implements RouteHandler {
|
||||
use RouteHandlerTrait;
|
||||
use RouteHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private DatabaseContext $dbCtx
|
||||
) {}
|
||||
|
||||
#[HttpGet('/')]
|
||||
public function getIndex($response) {
|
||||
#[ExactRoute('GET', '/')]
|
||||
public function getIndex(HttpResponseBuilder $response) {
|
||||
$response->accelRedirect('/index.html');
|
||||
$response->setContentType('text/html; charset=utf-8');
|
||||
}
|
||||
|
||||
#[HttpGet('/stats.json')]
|
||||
#[ExactRoute('GET', '/stats.json')]
|
||||
public function getStats() {
|
||||
$stats = new stdClass;
|
||||
$stats->uploads = 0;
|
||||
|
@ -26,13 +28,13 @@ class LandingRoutes implements RouteHandler {
|
|||
$stats->types = 0;
|
||||
$stats->members = 0;
|
||||
|
||||
$result = $this->dbCtx->connection->query('SELECT COUNT(*), COUNT(DISTINCT user_id) FROM prm_uploads');
|
||||
$result = $this->dbCtx->conn->query('SELECT COUNT(*), COUNT(DISTINCT user_id) FROM prm_uploads');
|
||||
if($result->next()) {
|
||||
$stats->uploads = $result->getInteger(0);
|
||||
$stats->members = $result->getInteger(1);
|
||||
}
|
||||
|
||||
$result = $this->dbCtx->connection->query('SELECT COUNT(*), SUM(file_size), COUNT(DISTINCT file_type) FROM prm_files');
|
||||
$result = $this->dbCtx->conn->query('SELECT COUNT(*), SUM(file_size), COUNT(DISTINCT file_type) FROM prm_files');
|
||||
if($result->next()) {
|
||||
$stats->files = $result->getInteger(0);
|
||||
$stats->size = $result->getInteger(1);
|
||||
|
@ -42,8 +44,8 @@ class LandingRoutes implements RouteHandler {
|
|||
return $stats;
|
||||
}
|
||||
|
||||
#[HttpGet('/eeprom.js')]
|
||||
public function getEepromJs($response) {
|
||||
#[ExactRoute('GET', '/eeprom.js')]
|
||||
public function getEepromJs(HttpResponseBuilder $response) {
|
||||
$response->accelRedirect('/scripts/eepromv1.js');
|
||||
$response->setContentType('application/javascript; charset=utf-8');
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
namespace EEPROM\Pools;
|
||||
|
||||
use RuntimeException;
|
||||
use EEPROM\Storage\StorageRecord;
|
||||
use EEPROM\Uploads\UploadVariantInfo;
|
||||
use Index\XArray;
|
||||
use Index\Db\DbConnection;
|
||||
|
||||
class PoolsContext {
|
||||
|
@ -34,7 +36,7 @@ class PoolsContext {
|
|||
);
|
||||
}
|
||||
|
||||
public function getPoolFromVariant(UploadVariantInfo $variantInfo): StorageRecord {
|
||||
public function getPoolFromVariant(UploadVariantInfo $variantInfo): PoolInfo {
|
||||
return $this->pools->getPool($variantInfo->fileId, PoolInfoGetField::Id);
|
||||
}
|
||||
|
||||
|
@ -69,7 +71,10 @@ class PoolsContext {
|
|||
if($removeStaleRule instanceof Rules\RemoveStaleRule && $removeStaleRule->inactiveForSeconds > 0)
|
||||
$body['idle_time'] = $removeStaleRule->inactiveForSeconds;
|
||||
|
||||
$ensureVariantRules = XArray::select($rules->getRules(Rules\EnsureVariantRule::TYPE), fn($ensureVariantRule) => $ensureVariantRule->variant);
|
||||
$ensureVariantRules = XArray::select(
|
||||
$rules->getRules(Rules\EnsureVariantRule::TYPE),
|
||||
fn($ensureVariantRule) => $ensureVariantRule->variant
|
||||
);
|
||||
if(!empty($ensureVariantRules))
|
||||
$body['variants'] = $ensureVariantRules;
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ class PoolsData {
|
|||
PoolInfoGetField::Id => 'pool_id = ?',
|
||||
PoolInfoGetField::Name => 'pool_name = ?',
|
||||
PoolInfoGetField::UploadId => 'pool_id = (SELECT pool_id FROM prm_uploads WHERE upload_id = ?)',
|
||||
default => throw new InvalidArgumentException('$field is not an acceptable value'),
|
||||
};
|
||||
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
|
@ -90,8 +89,10 @@ class PoolsData {
|
|||
SELECT rule_id, pool_id, rule_type, rule_params
|
||||
FROM prm_pools_rules
|
||||
SQL;
|
||||
if($hasPoolInfo)
|
||||
$query .= sprintf(' %s pool_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||||
if($hasPoolInfo) {
|
||||
++$args;
|
||||
$query .= ' WHERE pool_id = ?';
|
||||
}
|
||||
if($hasTypes)
|
||||
$query .= sprintf(' %s rule_type IN (%s)', ++$args > 1 ? 'AND' : 'WHERE', DbTools::prepareListString($types));
|
||||
|
||||
|
|
|
@ -2,42 +2,19 @@
|
|||
namespace EEPROM;
|
||||
|
||||
use Index\Config\Config;
|
||||
use Index\Http\HttpRequest;
|
||||
use Index\Http\Routing\{HttpRouter,Router,RouteHandler};
|
||||
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\Routing\{Router,RouteHandler};
|
||||
use Index\Http\Routing\Filters\FilterInfo;
|
||||
|
||||
class RoutingContext {
|
||||
private HttpRouter $router;
|
||||
public private(set) Router $router;
|
||||
|
||||
public function __construct(private Config $config) {
|
||||
$this->router = new HttpRouter(
|
||||
public function __construct(Config $config) {
|
||||
$this->router = new Router(
|
||||
errorHandler: new EEPROMErrorHandler,
|
||||
accessControlHandler: new EEPROMAccessControlHandler($config->getArray('origins')),
|
||||
);
|
||||
$this->router->use('/', $this->middleware(...));
|
||||
}
|
||||
|
||||
private function middleware($response, $request) {
|
||||
$response->setPoweredBy('EEPROM');
|
||||
|
||||
if($request->hasHeader('Origin')) {
|
||||
$origin = $request->getHeaderLine('Origin');
|
||||
$response->setHeader('Access-Control-Allow-Origin', $origin);
|
||||
$response->setHeader('Vary', 'Origin');
|
||||
$host = parse_url($origin, PHP_URL_HOST);
|
||||
if(is_string($host)) {
|
||||
$host = '.' . $host;
|
||||
$allowCookieOrigins = $this->config->getArray('origins');
|
||||
foreach($allowCookieOrigins as $allowCookieOrigin)
|
||||
if(str_ends_with($host, '.' . $allowCookieOrigin)) {
|
||||
$response->setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
$response->setHeader('Access-Control-Allow-Origin', '*');
|
||||
}
|
||||
|
||||
public function getRouter(): Router {
|
||||
return $this->router;
|
||||
$this->router->filter(FilterInfo::prefix('/', fn(HttpResponseBuilder $response) => $response->setPoweredBy('EEPROM')));
|
||||
}
|
||||
|
||||
public function register(RouteHandler $handler): void {
|
||||
|
|
|
@ -79,18 +79,13 @@ class StorageFiles {
|
|||
$target = $this->getLocalPath($hash, true);
|
||||
|
||||
if(is_file($target)) {
|
||||
if($mode === StorageImportMode::Move || $mode === StorageImportMode::Upload)
|
||||
if($mode === StorageImportMode::Move)
|
||||
unlink($path);
|
||||
} else {
|
||||
if($mode === StorageImportMode::Move)
|
||||
$success = rename($path, $target);
|
||||
elseif($mode === StorageImportMode::Copy)
|
||||
$success = copy($path, $target);
|
||||
elseif($mode === StorageImportMode::Upload)
|
||||
$success = move_uploaded_file($path, $target);
|
||||
else
|
||||
$success = false;
|
||||
|
||||
if(!$success)
|
||||
throw new RuntimeException('unable to move or copy $path using given $mode');
|
||||
}
|
||||
|
|
|
@ -4,5 +4,4 @@ namespace EEPROM\Storage;
|
|||
enum StorageImportMode {
|
||||
case Copy;
|
||||
case Move;
|
||||
case Upload;
|
||||
}
|
||||
|
|
|
@ -37,12 +37,13 @@ class StorageRecords {
|
|||
SQL;
|
||||
|
||||
$args = 0;
|
||||
if($orphaned !== null)
|
||||
if($orphaned !== null) {
|
||||
++$args;
|
||||
$query .= sprintf(
|
||||
' %s uf.file_id %s NULL',
|
||||
++$args > 1 ? 'OR' : 'WHERE',
|
||||
' WHERE uf.file_id %s NULL',
|
||||
$orphaned ? 'IS' : 'IS NOT'
|
||||
);
|
||||
}
|
||||
if($denied !== null)
|
||||
$query .= sprintf(
|
||||
' %s dl.deny_hash %s NULL',
|
||||
|
@ -63,7 +64,6 @@ class StorageRecords {
|
|||
$field = match($field) {
|
||||
StorageRecordGetFileField::Id => 'file_id',
|
||||
StorageRecordGetFileField::Hash => 'file_hash',
|
||||
default => throw new InvalidArgumentException('$field is not an acceptable value'),
|
||||
};
|
||||
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
|
@ -93,14 +93,14 @@ class StorageRecords {
|
|||
if($size < 0)
|
||||
throw new InvalidArgumentException('$size may not be negative');
|
||||
|
||||
$fileId = $this->snowflake->nextHash($hash);
|
||||
$fileId = (string)$this->snowflake->nextHash($hash);
|
||||
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
INSERT INTO prm_files (
|
||||
file_id, file_hash, file_type, file_size
|
||||
) VALUES (?, ?, ?, ?)
|
||||
SQL);
|
||||
$stmt->nextParameter($fileId); // generate snowflake
|
||||
$stmt->nextParameter($fileId);
|
||||
$stmt->nextParameter($hash);
|
||||
$stmt->nextParameter($type);
|
||||
$stmt->nextParameter($size);
|
||||
|
@ -120,7 +120,6 @@ class StorageRecords {
|
|||
$field = match($field) {
|
||||
StorageRecordGetFileField::Id => 'file_id',
|
||||
StorageRecordGetFileField::Hash => 'file_hash',
|
||||
default => throw new InvalidArgumentException('$field is not an acceptable value'),
|
||||
};
|
||||
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
|
@ -142,7 +141,6 @@ class StorageRecords {
|
|||
$field = match($field) {
|
||||
StorageRecordGetFileField::Id => '?',
|
||||
StorageRecordGetFileField::Hash => '(SELECT file_id FROM prm_files WHERE file_hash = ?)',
|
||||
default => throw new InvalidArgumentException('$field is not an acceptable value'),
|
||||
};
|
||||
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
|
|
|
@ -28,7 +28,7 @@ class TaskInfo {
|
|||
secret: $result->getString(1),
|
||||
userId: $result->getString(2),
|
||||
poolId: $result->getString(3),
|
||||
state: TaskState::tryFrom($result->getString(4)) ?? TaskState::Ready,
|
||||
state: TaskState::tryFrom($result->getString(4)) ?? TaskState::Pending,
|
||||
remoteAddress: $result->getString(5),
|
||||
name: $result->getString(6),
|
||||
size: $result->getInteger(7),
|
||||
|
|
|
@ -3,6 +3,7 @@ namespace EEPROM\Tasks;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Stringable;
|
||||
use EEPROM\SnowflakeGenerator;
|
||||
use EEPROM\Pools\PoolInfo;
|
||||
use Index\XString;
|
||||
|
@ -29,8 +30,10 @@ class TasksData {
|
|||
task_name, task_size, task_type, task_hash, UNIX_TIMESTAMP(task_created)
|
||||
FROM prm_tasks
|
||||
SQL;
|
||||
if($hasState)
|
||||
$query .= sprintf(' %s task_state = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||||
if($hasState) {
|
||||
++$args;
|
||||
$query .= ' WHERE task_state = ?';
|
||||
}
|
||||
|
||||
$stmt = $this->cache->get($query);
|
||||
if($hasState)
|
||||
|
@ -77,7 +80,7 @@ class TasksData {
|
|||
string $type,
|
||||
string $hash
|
||||
): TaskInfo {
|
||||
$taskId = $this->snowflake->nextRandom();
|
||||
$taskId = (string)$this->snowflake->nextRandom();
|
||||
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
INSERT INTO prm_tasks (
|
||||
|
|
|
@ -3,39 +3,36 @@ namespace EEPROM\Tasks;
|
|||
|
||||
use RuntimeException;
|
||||
use Index\{ByteFormat,XNumber};
|
||||
use Index\Http\StringHttpContent;
|
||||
use Index\Http\Routing\{HttpPut,RouteHandler,RouteHandlerTrait};
|
||||
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\Routing\{HttpPut,RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Routes\PatternRoute;
|
||||
|
||||
class TasksRoutes implements RouteHandler {
|
||||
use RouteHandlerTrait;
|
||||
use RouteHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private TasksContext $tasksCtx,
|
||||
) {}
|
||||
|
||||
#[HttpPut('/uploads/([A-Za-z0-9]+)(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function putUpload($response, $request, string $taskId, string $variant = '', string $extension = '') {
|
||||
#[PatternRoute('PUT', '/uploads/([A-Za-z0-9]+)(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function putUpload(
|
||||
HttpResponseBuilder $response,
|
||||
HttpRequest $request,
|
||||
string $taskId,
|
||||
string $variant = '',
|
||||
string $extension = '',
|
||||
) {
|
||||
if($request->getHeaderLine('Content-Type') !== 'application/octet-stream') {
|
||||
$response->setStatusCode(400);
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'bad_type',
|
||||
'english' => 'Content-Type must be application/octet-stream.',
|
||||
];
|
||||
}
|
||||
|
||||
$content = $request->getContent();
|
||||
if($content instanceof StringHttpContent) {
|
||||
$content = (string)$content;
|
||||
} else {
|
||||
$response->setStatusCode(400);
|
||||
return [
|
||||
'error' => 'bad_content',
|
||||
'english' => 'Request content could not be parsed as expected.',
|
||||
];
|
||||
}
|
||||
|
||||
$content = (string)$request->getBody();
|
||||
if(strlen($taskId) < 5) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'not_found',
|
||||
'english' => 'Requested upload task does not exist.',
|
||||
|
@ -43,8 +40,8 @@ class TasksRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if($variant !== '') {
|
||||
$response->setStatusCode(405);
|
||||
$response->setHeader('Allow', 'HEAD, GET');
|
||||
$response->statusCode = 405;
|
||||
$response->setAllow(['HEAD', 'GET']);
|
||||
return [
|
||||
'error' => 'method_not_allowed',
|
||||
'english' => 'PUT requests are not supported for upload variants.',
|
||||
|
@ -53,7 +50,7 @@ class TasksRoutes implements RouteHandler {
|
|||
|
||||
$length = (int)$request->getHeaderLine('Content-Length');
|
||||
if($length < 1) {
|
||||
$response->setStatusCode(411);
|
||||
$response->statusCode = 411;
|
||||
return [
|
||||
'error' => 'length_required',
|
||||
'english' => 'A Content-Length header with the size of the request body is required.',
|
||||
|
@ -61,7 +58,7 @@ class TasksRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if(strlen($content) !== $length) {
|
||||
$response->setStatusCode(400);
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'length_mismatch',
|
||||
'english' => 'Length specified in Content-Length differs from actual request body length.',
|
||||
|
@ -69,7 +66,7 @@ class TasksRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if($length > TasksContext::CHUNK_SIZE) {
|
||||
$response->setStatusCode(413);
|
||||
$response->statusCode = 413;
|
||||
return [
|
||||
'error' => 'content_too_large',
|
||||
'english' => sprintf(
|
||||
|
@ -84,7 +81,7 @@ class TasksRoutes implements RouteHandler {
|
|||
|
||||
if($request->hasHeader('X-Content-Index')) {
|
||||
if($request->hasParam('index')) {
|
||||
$response->setStatusCode(400);
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'bad_param',
|
||||
'english' => 'the index query parameter may not be used at the same time as the X-Content-Index header.',
|
||||
|
@ -93,19 +90,11 @@ class TasksRoutes implements RouteHandler {
|
|||
|
||||
$index = (int)filter_var($request->getHeaderLine('X-Content-Index'), FILTER_SANITIZE_NUMBER_INT);
|
||||
} elseif($request->hasParam('index')) {
|
||||
if($request->hasHeader('X-Content-Index')) {
|
||||
$response->setStatusCode(400);
|
||||
return [
|
||||
'error' => 'bad_param',
|
||||
'english' => 'the X-Content-Index header may not be used at the same time as the index query parameter.',
|
||||
];
|
||||
}
|
||||
|
||||
$index = (int)$request->getParam('index', FILTER_SANITIZE_NUMBER_INT);
|
||||
$index = (int)$request->getFilteredParam('index', FILTER_SANITIZE_NUMBER_INT);
|
||||
} else $index = 0;
|
||||
|
||||
if($index < 0) {
|
||||
$response->setStatusCode(400);
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'bad_index',
|
||||
'english' => 'index parameter must be greater than or equal to 0.',
|
||||
|
@ -113,19 +102,19 @@ class TasksRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
$taskSecret = substr($taskId, -16);
|
||||
$taskId = XNumber::fromBase62(substr($taskId, 0, -16));
|
||||
$taskId = (string)XNumber::fromBase62(substr($taskId, 0, -16));
|
||||
|
||||
try {
|
||||
$taskInfo = $this->tasksCtx->tasks->getTask($taskId);
|
||||
} catch(RuntimeException $ex) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'not_found',
|
||||
'english' => 'Requested upload task does not exist.',
|
||||
];
|
||||
}
|
||||
if(!$taskInfo->verifySecret($taskSecret)) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'not_found',
|
||||
'english' => 'Requested upload task does not exist.',
|
||||
|
@ -133,7 +122,7 @@ class TasksRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if($taskInfo->state !== TaskState::Pending) {
|
||||
$response->setStatusCode(409);
|
||||
$response->statusCode = 409;
|
||||
return [
|
||||
'error' => 'not_pending',
|
||||
'english' => 'Requested upload task is no longer accepting data.',
|
||||
|
@ -142,7 +131,7 @@ class TasksRoutes implements RouteHandler {
|
|||
|
||||
$offset = TasksContext::CHUNK_SIZE * $index;
|
||||
if($offset >= $taskInfo->size) {
|
||||
$response->setStatusCode(400);
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'offset_too_large',
|
||||
'english' => 'Provided offset is greater than file size.',
|
||||
|
@ -152,7 +141,7 @@ class TasksRoutes implements RouteHandler {
|
|||
$path = $this->tasksCtx->getTaskWorkingPath($taskInfo);
|
||||
if(!is_file($path)) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('working file despawned during PUT request: %s', $path));
|
||||
$response->setStatusCode(500);
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Working file no longer exist on the server, the upload process cannot continue.',
|
||||
|
@ -162,52 +151,50 @@ class TasksRoutes implements RouteHandler {
|
|||
$handle = fopen($path, 'rb+');
|
||||
if($handle === false) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to open during PUT request: %s', $path));
|
||||
$response->setStatusCode(500);
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to open working file, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
if(fseek($handle, $offset, SEEK_SET) < 0) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('was unable to seek during PUT request: %s', $path));
|
||||
$response->setStatusCode(500);
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to seek to provided offset, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
if(fwrite($handle, $content, $length) === false) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('was unable to write during PUT request: %s', $path));
|
||||
$response->setStatusCode(500);
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to seek to write to file, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
} finally {
|
||||
if(!fflush($handle)) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to flush file contents during PUT request: %s', $path));
|
||||
$response->setStatusCode(500);
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to flush file properly, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
if(!fclose($handle)) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to close file contents during PUT request: %s', $path));
|
||||
$response->setStatusCode(500);
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to close file properly, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
if(fseek($handle, $offset, SEEK_SET) < 0) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('was unable to seek during PUT request: %s', $path));
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to seek to provided offset, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
$response->setStatusCode(202);
|
||||
if(fwrite($handle, $content, $length) === false) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('was unable to write during PUT request: %s', $path));
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to seek to write to file, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
if(!fflush($handle)) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to flush file contents during PUT request: %s', $path));
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to flush file properly, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
if(!fclose($handle)) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to close file contents during PUT request: %s', $path));
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'server_error',
|
||||
'english' => 'Was not able to close file properly, the upload process cannot continue.',
|
||||
];
|
||||
}
|
||||
|
||||
$response->statusCode = 202;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,11 +65,8 @@ final class TasksRpcHandler implements RpcHandler {
|
|||
if($signature === null)
|
||||
return 'srpp';
|
||||
|
||||
if(!str_contains($signature, '=')) {
|
||||
if(!str_contains($signature, '='))
|
||||
$signature = UriBase64::decode($signature);
|
||||
if(!is_string($signature))
|
||||
$signature = '';
|
||||
}
|
||||
|
||||
$signature = array_column(XArray::select(
|
||||
explode(';', $signature),
|
||||
|
@ -94,7 +91,7 @@ final class TasksRpcHandler implements RpcHandler {
|
|||
if($sAlgo !== 'S256')
|
||||
return 'sanv';
|
||||
|
||||
if(abs($cTime - $sTime) >= 30)
|
||||
if(abs($cTime - (int)$sTime) >= 30)
|
||||
return 'stnv';
|
||||
|
||||
if(strlen($sSalt) < 20)
|
||||
|
@ -182,15 +179,13 @@ final class TasksRpcHandler implements RpcHandler {
|
|||
return 'wfcf';
|
||||
}
|
||||
|
||||
try {
|
||||
if(!ftruncate($data, $fileSize)) {
|
||||
$this->tasksCtx->tasks->setTaskError($taskInfo, sprintf('failed to reserve %d bytes for task working file: %s', $fileSize, $path));
|
||||
return 'wfrf';
|
||||
}
|
||||
} finally {
|
||||
if(!fclose($data))
|
||||
return 'wfff';
|
||||
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';
|
||||
}
|
||||
|
@ -210,7 +205,7 @@ final class TasksRpcHandler implements RpcHandler {
|
|||
#[RpcQuery('eeprom:tasks:get')]
|
||||
public function actionTasksGet(string $taskId): string|array {
|
||||
$taskSecret = substr($taskId, -16);
|
||||
$taskId = XNumber::fromBase62(substr($taskId, 0, -16));
|
||||
$taskId = (string)XNumber::fromBase62(substr($taskId, 0, -16));
|
||||
|
||||
try {
|
||||
$taskInfo = $this->tasksCtx->tasks->getTask($taskId);
|
||||
|
@ -256,7 +251,7 @@ final class TasksRpcHandler implements RpcHandler {
|
|||
#[RpcAction('eeprom:tasks:finish')]
|
||||
public function actionsTasksFinish(string $taskId) {
|
||||
$taskSecret = substr($taskId, -16);
|
||||
$taskId = XNumber::fromBase62(substr($taskId, 0, -16));
|
||||
$taskId = (string)XNumber::fromBase62(substr($taskId, 0, -16));
|
||||
|
||||
try {
|
||||
$taskInfo = $this->tasksCtx->tasks->getTask($taskId);
|
||||
|
|
|
@ -77,7 +77,7 @@ class UploadsContext {
|
|||
'hash' => $fileInfo->hashHexString,
|
||||
'created' => $uploadInfo->createdAt->toIso8601ZuluString(),
|
||||
'accessed' => $uploadInfo->accessedAt->toIso8601ZuluString(),
|
||||
'expires' => $uploadInfo->accessedAt->add(2, 'weeks')->toIso8601ZuluString(),
|
||||
'expires' => $uploadInfo->accessedAt->add('weeks', 2)->toIso8601ZuluString(),
|
||||
|
||||
// These can never be reached, and in situation where they technically could it's because of an outdated local record
|
||||
'deleted' => null,
|
||||
|
|
|
@ -13,7 +13,7 @@ class UploadsData {
|
|||
private DbStatementCache $cache;
|
||||
|
||||
public function __construct(
|
||||
private DbConnection $dbConn,
|
||||
DbConnection $dbConn,
|
||||
private SnowflakeGenerator $snowflake
|
||||
) {
|
||||
$this->cache = new DbStatementCache($dbConn);
|
||||
|
@ -48,8 +48,10 @@ class UploadsData {
|
|||
SQL;
|
||||
|
||||
$args = 0;
|
||||
if($hasPoolInfo)
|
||||
$query .= sprintf(' %s u.pool_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||||
if($hasPoolInfo) {
|
||||
++$args;
|
||||
$query .= ' WHERE u.pool_id = ?';
|
||||
}
|
||||
if($hasUserId)
|
||||
$query .= sprintf(' %s u.user_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||||
if($hasVariantExists)
|
||||
|
|
|
@ -5,12 +5,19 @@ use RuntimeException;
|
|||
use EEPROM\Auth\AuthContext;
|
||||
use EEPROM\Denylist\{DenylistContext,DenylistReason};
|
||||
use EEPROM\Pools\PoolsContext;
|
||||
use EEPROM\Pools\Rules\{ConstrainSizeRule,EnsureVariantRule,EnsureVariantRuleThumb};
|
||||
use EEPROM\Storage\{StorageContext,StorageImportMode,StorageRecordGetFileField};
|
||||
use Index\{ByteFormat,XNumber};
|
||||
use Index\Http\Routing\{HttpDelete,HttpOptions,HttpPost,RouteHandler,RouteHandlerTrait};
|
||||
use Index\{ByteFormat,XArray,XNumber};
|
||||
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\Content\MultipartFormContent;
|
||||
use Index\Http\Content\Multipart\FileMultipartFormData;
|
||||
use Index\Http\Routing\{HttpDelete,HttpOptions,HttpPost,RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\AccessControl\AccessControl;
|
||||
use Index\Http\Routing\Processors\Before;
|
||||
use Index\Http\Routing\Routes\{ExactRoute,PatternRoute};
|
||||
|
||||
class UploadsLegacyRoutes implements RouteHandler {
|
||||
use RouteHandlerTrait;
|
||||
use RouteHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private AuthContext $authCtx,
|
||||
|
@ -20,21 +27,111 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
private DenylistContext $denylistCtx
|
||||
) {}
|
||||
|
||||
#[HttpOptions('/uploads')]
|
||||
public function optionsUpload($response, $request): int {
|
||||
$response->setHeader('Access-Control-Allow-Headers', 'Authorization');
|
||||
$response->setHeader('Access-Control-Allow-Methods', 'POST');
|
||||
#[AccessControl]
|
||||
#[PatternRoute('GET', '/uploads/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function getUpload(
|
||||
HttpResponseBuilder $response,
|
||||
HttpRequest $request,
|
||||
string $uploadId,
|
||||
string $variant = '',
|
||||
string $extension = ''
|
||||
) {
|
||||
if(strlen($uploadId) < 5)
|
||||
return 404;
|
||||
|
||||
return 204;
|
||||
$variantQuery = false;
|
||||
if($variant === '' && $request->hasParam('v')) {
|
||||
$variantQuery = true;
|
||||
$variant = (string)$request->getParam('v');
|
||||
}
|
||||
|
||||
$isV1Json = ($variantQuery || $variant === '') && $extension === 'json';
|
||||
if($isV1Json)
|
||||
$variant = '';
|
||||
|
||||
if(strlen($uploadId) === 32) {
|
||||
$uploadId = $this->uploadsCtx->uploads->resolveLegacyId($uploadId) ?? $uploadId;
|
||||
$uploadSecret = null;
|
||||
} else {
|
||||
$uploadSecret = substr($uploadId, -4);
|
||||
$uploadId = XNumber::fromBase62(substr($uploadId, 0, -4));
|
||||
}
|
||||
|
||||
try {
|
||||
$uploadInfo = $this->uploadsCtx->uploads->getUpload(uploadId: $uploadId, secret: $uploadSecret);
|
||||
} catch(RuntimeException $ex) {
|
||||
return 404;
|
||||
}
|
||||
|
||||
try {
|
||||
$variantInfo = $this->uploadsCtx->uploads->getUploadVariant($uploadInfo, $variant);
|
||||
} catch(RuntimeException $ex) {
|
||||
if($variant === '')
|
||||
return 404;
|
||||
|
||||
try {
|
||||
$poolInfo = $this->poolsCtx->pools->getPool($uploadInfo->poolId);
|
||||
$originalInfo = $this->storageCtx->records->getFile(
|
||||
$this->uploadsCtx->uploads->getUploadVariant($uploadInfo, '')->fileId
|
||||
);
|
||||
|
||||
$rule = XArray::first(
|
||||
$this->poolsCtx->getPoolRules($poolInfo)->getRules(EnsureVariantRule::TYPE),
|
||||
fn($rule) => $rule->variant === $variant
|
||||
);
|
||||
if($rule instanceof EnsureVariantRule && $rule->onAccess) {
|
||||
if($rule->params instanceof EnsureVariantRuleThumb) {
|
||||
$storageInfo = $this->storageCtx->createThumbnailFromRule($originalInfo, $rule->params);
|
||||
$variantInfo = $this->uploadsCtx->uploads->createUploadVariant($uploadInfo, $rule->variant, $storageInfo);
|
||||
}
|
||||
}
|
||||
} catch(RuntimeException $ex) {
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($variantInfo))
|
||||
return 404;
|
||||
|
||||
if(!isset($storageInfo))
|
||||
try {
|
||||
$storageInfo = $this->storageCtx->records->getFile($variantInfo->fileId);
|
||||
} catch(RuntimeException $ex) {
|
||||
return 404;
|
||||
}
|
||||
|
||||
$this->uploadsCtx->uploads->updateUpload(
|
||||
$uploadInfo,
|
||||
accessedAt: true,
|
||||
);
|
||||
|
||||
$denyInfo = $this->denylistCtx->getDenylistEntry($storageInfo);
|
||||
if($denyInfo !== null)
|
||||
return $denyInfo->isCopyrightTakedown ? 451 : 410;
|
||||
|
||||
if($isV1Json)
|
||||
return $this->uploadsCtx->convertToClientJsonV1($uploadInfo, $variantInfo, $storageInfo);
|
||||
|
||||
$fileName = $uploadInfo->name;
|
||||
if($variantInfo->variant !== '') // FAIRLY SIGNIFICANT TODO: obviously this should support more file exts than .jpg...
|
||||
$fileName = sprintf('%s-%s.jpg', pathinfo($fileName, PATHINFO_FILENAME), $variantInfo->variant);
|
||||
|
||||
$contentType = $variantInfo->type ?? $storageInfo->type;
|
||||
if($contentType === 'application/octet-stream' || str_starts_with($contentType, 'text/'))
|
||||
$contentType = 'text/plain';
|
||||
|
||||
$response->accelRedirect($this->storageCtx->files->getRemotePath($storageInfo));
|
||||
$response->setContentType($contentType);
|
||||
$response->setFileName(addslashes($fileName));
|
||||
}
|
||||
|
||||
#[HttpPost('/uploads')]
|
||||
public function postUpload($response, $request) {
|
||||
if(!$request->isFormContent())
|
||||
return 400;
|
||||
|
||||
#[AccessControl(credentials: true, allowHeaders: ['Authorization'])]
|
||||
#[Before('input:multipart')]
|
||||
#[Before('eeprom:attempt-auth')]
|
||||
#[ExactRoute('POST', '/uploads')]
|
||||
public function postUpload(HttpResponseBuilder $response, HttpRequest $request, MultipartFormContent $content) {
|
||||
if(!$this->authCtx->info->authed) {
|
||||
$response->setStatusCode(401);
|
||||
$response->statusCode = 401;
|
||||
return [
|
||||
'error' => 'auth',
|
||||
'english' => "You must be logged in to upload files. If you are and you're getting this error anyway, try refreshing the page!",
|
||||
|
@ -42,29 +139,25 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if($this->authCtx->info->restricted) {
|
||||
$response->setStatusCode(403);
|
||||
$response->statusCode = 403;
|
||||
return [
|
||||
'error' => 'restricted',
|
||||
'english' => 'You are currently banned and are not allowed to upload or manage files.',
|
||||
];
|
||||
}
|
||||
|
||||
$content = $request->getContent();
|
||||
|
||||
try {
|
||||
$file = $content->getUploadedFile('file');
|
||||
} catch(RuntimeException $ex) {
|
||||
$response->setStatusCode(400);
|
||||
$file = $content->getParamData('file');
|
||||
if(!($file instanceof FileMultipartFormData)) {
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'file',
|
||||
'english' => 'File upload is missing from request body.',
|
||||
];
|
||||
}
|
||||
|
||||
$localFile = $file->getLocalFileName();
|
||||
$fileSize = filesize($localFile);
|
||||
$fileSize = $file->getSize();
|
||||
if($fileSize < 1) {
|
||||
$response->setStatusCode(400);
|
||||
$response->statusCode = 400;
|
||||
return [
|
||||
'error' => 'empty',
|
||||
'english' => 'The file you attempted to upload is empty.',
|
||||
|
@ -72,16 +165,16 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
try {
|
||||
$poolInfo = $this->poolsCtx->pools->getPool((string)$content->getParam('src', FILTER_VALIDATE_INT));
|
||||
$poolInfo = $this->poolsCtx->pools->getPool((string)$content->getFilteredParam('src', FILTER_VALIDATE_INT));
|
||||
if($poolInfo->protected) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'pool_incompatible',
|
||||
'english' => 'The target upload pool is not compatible with this endpoint.',
|
||||
];
|
||||
}
|
||||
} catch(RuntimeException $ex) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'pool',
|
||||
'english' => 'The target upload pool does not exist.',
|
||||
|
@ -92,8 +185,8 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
|
||||
// If there's no constrain_size rule on this pool its likely not meant to be used through this API!
|
||||
$maxSizeRule = $rules->getRule('constrain_size');
|
||||
if($maxSizeRule === null) {
|
||||
$response->setStatusCode(500);
|
||||
if(!($maxSizeRule instanceof ConstrainSizeRule)) {
|
||||
$response->statusCode = 500;
|
||||
return [
|
||||
'error' => 'size_rule_missing',
|
||||
'english' => 'A pool size constraint rule is required any this pool does not specify one.',
|
||||
|
@ -104,10 +197,10 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
if($maxSizeRule->allowLegacyMultiplier)
|
||||
$maxFileSize *= $this->authCtx->info->legacyMultiplier;
|
||||
|
||||
if($file->getSize() !== $fileSize || $fileSize > $maxFileSize) {
|
||||
$response->setStatusCode(413);
|
||||
if($fileSize > $maxFileSize) {
|
||||
$response->statusCode = 413;
|
||||
$response->setHeader('Access-Control-Expose-Headers', 'X-EEPROM-Max-Size');
|
||||
$response->setHeader('X-EEPROM-Max-Size', $maxFileSize);
|
||||
$response->setHeader('X-EEPROM-Max-Size', (string)$maxFileSize);
|
||||
return [
|
||||
'error' => 'size',
|
||||
'english' => sprintf(
|
||||
|
@ -120,11 +213,13 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
];
|
||||
}
|
||||
|
||||
$hash = hash_file('sha256', $localFile, true);
|
||||
$tmpFile = tempnam(sys_get_temp_dir(), 'eeprom-upload-');
|
||||
$file->moveTo($tmpFile);
|
||||
$hash = hash_file('sha256', $tmpFile, true);
|
||||
|
||||
$denyInfo = $this->denylistCtx->getDenylistEntry($hash);
|
||||
if($denyInfo !== null) {
|
||||
$response->setStatusCode(451);
|
||||
$response->statusCode = 451;
|
||||
return [
|
||||
'error' => 'takedown',
|
||||
'english' => sprintf(
|
||||
|
@ -139,17 +234,17 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
];
|
||||
}
|
||||
|
||||
$fileName = $file->getSuggestedFileName();
|
||||
$mediaType = (string)$file->getSuggestedMediaType();
|
||||
if($mediaType === '/' || $mediaType === 'application/octet-stream')
|
||||
$mediaType = mime_content_type($localFile);
|
||||
$fileName = $file->getClientFilename();
|
||||
$mediaType = $file->getClientMediaType();
|
||||
if($mediaType === null || $mediaType === 'application/octet-stream')
|
||||
$mediaType = mime_content_type($tmpFile);
|
||||
|
||||
try {
|
||||
$storageInfo = $this->storageCtx->records->getFile($hash, StorageRecordGetFileField::Hash);
|
||||
} catch(RuntimeException $ex) {
|
||||
$storageInfo = $this->storageCtx->importFile(
|
||||
$file->getLocalFileName(),
|
||||
StorageImportMode::Upload,
|
||||
$tmpFile,
|
||||
StorageImportMode::Move,
|
||||
$mediaType
|
||||
);
|
||||
}
|
||||
|
@ -172,14 +267,14 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
$poolInfo,
|
||||
$this->authCtx->info->userId,
|
||||
$fileName,
|
||||
$request->getRemoteAddress()
|
||||
$request->remoteAddress
|
||||
);
|
||||
$variantInfo = $this->uploadsCtx->uploads->createUploadVariant(
|
||||
$uploadInfo, '', $storageInfo, $mediaType
|
||||
);
|
||||
}
|
||||
|
||||
$response->setStatusCode(201);
|
||||
$response->statusCode = 201;
|
||||
$response->setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
|
||||
return $this->uploadsCtx->convertToClientJsonV1($uploadInfo, $variantInfo, $storageInfo, [
|
||||
|
@ -187,10 +282,12 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
]);
|
||||
}
|
||||
|
||||
#[HttpDelete('/uploads/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function deleteUpload($response, $request, string $uploadId) {
|
||||
#[AccessControl(credentials: true, allowHeaders: ['Authorization'])]
|
||||
#[Before('eeprom:attempt-auth')]
|
||||
#[PatternRoute('DELETE', '/uploads/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function deleteUpload(HttpResponseBuilder $response, HttpRequest $request, string $uploadId) {
|
||||
if(!$this->authCtx->info->authed) {
|
||||
$response->setStatusCode(401);
|
||||
$response->statusCode = 401;
|
||||
return [
|
||||
'error' => 'auth',
|
||||
'english' => "You must be logged in to delete uploaded files. If you are and you're getting this error anyway, try refreshing the page!",
|
||||
|
@ -198,7 +295,7 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if(strlen($uploadId) < 5) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'none',
|
||||
'english' => 'That file does not exist.',
|
||||
|
@ -216,7 +313,7 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
try {
|
||||
$uploadInfo = $this->uploadsCtx->uploads->getUpload(uploadId: $uploadId, secret: $uploadSecret);
|
||||
} catch(RuntimeException $ex) {
|
||||
$response->setStatusCode(404);
|
||||
$response->statusCode = 404;
|
||||
return [
|
||||
'error' => 'none',
|
||||
'english' => 'That file does not exist.',
|
||||
|
@ -224,7 +321,7 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if($this->authCtx->info->restricted) {
|
||||
$response->setStatusCode(403);
|
||||
$response->statusCode = 403;
|
||||
return [
|
||||
'error' => 'restricted',
|
||||
'english' => 'You are currently banned and are not allowed to upload or manage files.',
|
||||
|
@ -232,7 +329,7 @@ class UploadsLegacyRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
if($this->authCtx->info->userId !== $uploadInfo->userId) {
|
||||
$response->setStatusCode(403);
|
||||
$response->statusCode = 403;
|
||||
return [
|
||||
'error' => 'owner',
|
||||
'english' => "You aren't allowed to delete files uploaded by others.",
|
||||
|
|
|
@ -71,7 +71,7 @@ final class UploadsRpcHandler implements RpcHandler {
|
|||
return [
|
||||
'result' => $this->uploadsCtx->extractUpload(
|
||||
$this->uploadsCtx->uploads->getUpload(
|
||||
uploadId: XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
secret: substr($uploadId, -4),
|
||||
userId: $userId
|
||||
),
|
||||
|
@ -93,7 +93,7 @@ final class UploadsRpcHandler implements RpcHandler {
|
|||
|
||||
try {
|
||||
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
|
||||
uploadId: XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
secret: substr($uploadId, -4),
|
||||
);
|
||||
} catch(RuntimeException $ex) {
|
||||
|
@ -120,7 +120,7 @@ final class UploadsRpcHandler implements RpcHandler {
|
|||
|
||||
try {
|
||||
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
|
||||
uploadId: XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
secret: substr($uploadId, -4),
|
||||
);
|
||||
} catch(RuntimeException $ex) {
|
||||
|
@ -149,7 +149,7 @@ final class UploadsRpcHandler implements RpcHandler {
|
|||
|
||||
try {
|
||||
$uploadInfo = $this->uploadsCtx->uploads->getUpload(
|
||||
uploadId: XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
uploadId: (string)XNumber::fromBase62(substr($uploadId, 0, -4)),
|
||||
secret: substr($uploadId, -4),
|
||||
);
|
||||
} catch(RuntimeException $ex) {
|
||||
|
|
|
@ -7,39 +7,30 @@ use EEPROM\Pools\PoolsContext;
|
|||
use EEPROM\Pools\Rules\{EnsureVariantRule,EnsureVariantRuleThumb};
|
||||
use EEPROM\Storage\StorageContext;
|
||||
use Index\{XArray,XNumber};
|
||||
use Index\Http\Routing\{HandlerAttribute,HttpGet,HttpOptions,Router,RouteHandler};
|
||||
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||
use Index\Http\Routing\{Router,RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\AccessControl\AccessControl;
|
||||
use Index\Http\Routing\Routes\PatternRoute;
|
||||
|
||||
class UploadsViewRoutes implements RouteHandler {
|
||||
use RouteHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private PoolsContext $poolsCtx,
|
||||
private UploadsContext $uploadsCtx,
|
||||
private StorageContext $storageCtx,
|
||||
private DenylistContext $denylistCtx,
|
||||
private bool $isApiDomain
|
||||
private DenylistContext $denylistCtx
|
||||
) {}
|
||||
|
||||
public function registerRoutes(Router $router): void {
|
||||
if($this->isApiDomain)
|
||||
$router = $router->scopeTo('/uploads');
|
||||
|
||||
HandlerAttribute::register($router, $this);
|
||||
}
|
||||
|
||||
#[HttpOptions('/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function optionsUpload($response, $request, string $uploadId, string $variant = '', string $extension = ''): int {
|
||||
if($this->isApiDomain && $variant === '') {
|
||||
$response->setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type, Content-Length, X-Content-Index');
|
||||
$response->setHeader('Access-Control-Allow-Methods', 'HEAD, GET, PUT, DELETE');
|
||||
$response->setHeader('Access-Control-Max-Age', '300');
|
||||
} else {
|
||||
$response->setHeader('Access-Control-Allow-Methods', 'HEAD, GET');
|
||||
}
|
||||
|
||||
return 204;
|
||||
}
|
||||
|
||||
#[HttpGet('/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function getUpload($response, $request, string $uploadId, string $variant = '', string $extension = '') {
|
||||
#[AccessControl]
|
||||
#[PatternRoute('GET', '/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
|
||||
public function getUpload(
|
||||
HttpResponseBuilder $response,
|
||||
HttpRequest $request,
|
||||
string $uploadId,
|
||||
string $variant = '',
|
||||
string $extension = ''
|
||||
) {
|
||||
if(strlen($uploadId) < 5)
|
||||
return 404;
|
||||
|
||||
|
@ -49,10 +40,6 @@ class UploadsViewRoutes implements RouteHandler {
|
|||
$variant = (string)$request->getParam('v');
|
||||
}
|
||||
|
||||
$isV1Json = $this->isApiDomain && ($variantQuery || $variant === '') && $extension === 'json';
|
||||
if($isV1Json)
|
||||
$variant = '';
|
||||
|
||||
if(strlen($uploadId) === 32) {
|
||||
$uploadId = $this->uploadsCtx->uploads->resolveLegacyId($uploadId) ?? $uploadId;
|
||||
$uploadSecret = null;
|
||||
|
@ -113,9 +100,6 @@ class UploadsViewRoutes implements RouteHandler {
|
|||
if($denyInfo !== null)
|
||||
return $denyInfo->isCopyrightTakedown ? 451 : 410;
|
||||
|
||||
if($isV1Json)
|
||||
return $this->uploadsCtx->convertToClientJsonV1($uploadInfo, $variantInfo, $storageInfo);
|
||||
|
||||
$fileName = $uploadInfo->name;
|
||||
if($variantInfo->variant !== '') // FAIRLY SIGNIFICANT TODO: obviously this should support more file exts than .jpg...
|
||||
$fileName = sprintf('%s-%s.jpg', pathinfo($fileName, PATHINFO_FILENAME), $variantInfo->variant);
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
<?php
|
||||
require_once __DIR__ . '/../eeprom.php';
|
||||
|
||||
$lockPath = $eeprom->database->getMigrateLockPath();
|
||||
$lockPath = $eeprom->dbCtx->getMigrateLockPath();
|
||||
if(is_file($lockPath))
|
||||
die('A migration script is already running.' . PHP_EOL);
|
||||
|
||||
touch($lockPath);
|
||||
try {
|
||||
echo 'Creating migration manager...' . PHP_EOL;
|
||||
$manager = $eeprom->database->createMigrationManager();
|
||||
$manager = $eeprom->dbCtx->createMigrationManager();
|
||||
|
||||
echo 'Preparing to run migrations...' . PHP_EOL;
|
||||
$manager->init();
|
||||
|
||||
echo 'Creating migration repository...' . PHP_EOL;
|
||||
$repo = $eeprom->database->createMigrationRepo();
|
||||
$repo = $eeprom->dbCtx->createMigrationRepo();
|
||||
|
||||
echo 'Running migrations...' . PHP_EOL;
|
||||
$completed = $manager->processMigrations($repo);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<?php
|
||||
require_once __DIR__ . '/../eeprom.php';
|
||||
|
||||
$lockPath = $eeprom->database->getMigrateLockPath();
|
||||
$lockPath = $eeprom->dbCtx->getMigrateLockPath();
|
||||
if(is_file($lockPath)) {
|
||||
printf('Removing migration lock...%s', PHP_EOL);
|
||||
unlink($lockPath);
|
||||
|
|
|
@ -4,14 +4,14 @@ use Index\Db\Migration\FsDbMigrationRepo;
|
|||
|
||||
require_once __DIR__ . '/../eeprom.php';
|
||||
|
||||
$repo = $eeprom->database->createMigrationRepo();
|
||||
$repo = $eeprom->dbCtx->createMigrationRepo();
|
||||
if(!($repo instanceof FsDbMigrationRepo)) {
|
||||
echo 'Migration repository type does not support creation of templates.' . PHP_EOL;
|
||||
return;
|
||||
}
|
||||
|
||||
$baseName = implode(' ', array_slice($argv, 1));
|
||||
$manager = $eeprom->database->createMigrationManager();
|
||||
$manager = $eeprom->dbCtx->createMigrationManager();
|
||||
|
||||
try {
|
||||
$names = $manager->createNames($baseName);
|
||||
|
|
Reference in a new issue