commit b49424b6eec0851f96c0276bc00aee4c3f67a964 Author: Benjamin Date: Thu Jan 29 18:43:58 2026 +0100 Begin RHPZ Server. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f209606 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +.idea +node_modules +vendor \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f566bd7 --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "romhackplaza/file-server", + "type": "project", + "authors": [ + { + "name": "Benjamin", + "email": "benjamin@cartememoire.org" + } + ], + "autoload": { + "psr-4": { + "RomhackPlazaFS\\": "src/" + } + }, + "require": { + "vlucas/phpdotenv": "^5.6" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..82eb6b3 --- /dev/null +++ b/composer.lock @@ -0,0 +1,492 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "66c99d67287c11e948f7517be5bc239c", + "packages": [ + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:41:33+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "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 for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "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\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/data/translations/3/private/toto.txt b/data/translations/3/private/toto.txt new file mode 100644 index 0000000..25ecf8e --- /dev/null +++ b/data/translations/3/private/toto.txt @@ -0,0 +1 @@ +fv \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..bf170e8 --- /dev/null +++ b/public/index.php @@ -0,0 +1,4 @@ +fs = &$FS; + if( $this->private_endpoint() ) + RomhackPlazaFS::allow_only_for_main_site(); + + if( $this->require_token() ) + $this->check_token(); + + $this->get_post_params(); + $this->process(); + + } + + private function check_token( string $token_name = "zeus" ){ + + $token = $this->fs->give_token( $token_name ); + if( $token === "" ) + RomhackPlazaFS::fatal_stop( 400, "Zeus is dead... Really sad..." ); + + try{ + $this->token_info = $this->verify_token( $token ) ?? null; + } catch ( InvalidTokenException $e ){ + RomhackPlazaFS::fatal_stop( 400, "You can't reach Zeus, sad..." ); + } catch ( TokenExpiredException $e ){ + RomhackPlazaFS::fatal_stop( 400, "Zeus is not here anymore, sad..."); + } catch ( WrongServerException $e ){ + RomhackPlazaFS::fatal_stop( 400, "Why you want to reach Zeus ?"); + } + + if( $this->token_info['action'] !== $this->fs->endpoint_requested ) + RomhackPlazaFS::fatal_stop( 400, "There are not two Zeus..." ); + + } + + abstract protected function private_endpoint(): bool; + abstract protected function require_token(): bool; + abstract protected function get_post_params(): void; + abstract protected function process(): void; + +} \ No newline at end of file diff --git a/src/Endpoints/Checkexistence.php b/src/Endpoints/Checkexistence.php new file mode 100644 index 0000000..36811fd --- /dev/null +++ b/src/Endpoints/Checkexistence.php @@ -0,0 +1,58 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + } + + protected function process(): void { + + $file_exists = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name + )->file_exists(); + + $resp = [ + 'file_exists' => $file_exists, + ]; + + RomhackPlazaFS::success_response( $resp ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Deletefile.php b/src/Endpoints/Deletefile.php new file mode 100644 index 0000000..01a0db2 --- /dev/null +++ b/src/Endpoints/Deletefile.php @@ -0,0 +1,66 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + ); + + if( !$data->file_exists() ) + RomhackPlazaFS::fatal_stop( 404, "File not found." ); + + $new_data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + Data::F_DELETED_FILE + ); + + if( $data->change_data_location( $new_data ) ) + RomhackPlazaFS::success_response( [ 'status' => Data::STATUS_DELETED ] ); + + RomhackPlazaFS::fatal_stop( 500, "Error during file marking" ); + + } + +} \ No newline at end of file diff --git a/src/Endpoints/Downloadfilelist.php b/src/Endpoints/Downloadfilelist.php new file mode 100644 index 0000000..ac2eac8 --- /dev/null +++ b/src/Endpoints/Downloadfilelist.php @@ -0,0 +1,56 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id + ); + $archived = Data::setup( + $this->custom_post_type, + $this->post_id, + flags: Data::F_ARCHIVED_FILE + ); + + $response = []; + $response['files'] = $data->list_files( $this->custom_post_type, $this->post_id ); + $response['archived'] = $archived->list_files( $this->custom_post_type, $this->post_id ); + + RomhackPlazaFS::success_response( $response ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Editorfilelist.php b/src/Endpoints/Editorfilelist.php new file mode 100644 index 0000000..be68aeb --- /dev/null +++ b/src/Endpoints/Editorfilelist.php @@ -0,0 +1,62 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id + ); + $private = Data::setup( + $this->custom_post_type, + $this->post_id, + flags: Data::F_PRIVATE_FILE + ); + $archived = Data::setup( + $this->custom_post_type, + $this->post_id, + flags: Data::F_ARCHIVED_FILE + ); + + $response = []; + $response['files'] = $data->list_files( $this->custom_post_type, $this->post_id ); + $response['private'] = $private->list_files( $this->custom_post_type, $this->post_id ); + $response['archived'] = $archived->list_files( $this->custom_post_type, $this->post_id ); + + RomhackPlazaFS::success_response( $response ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Fileexplorer.php b/src/Endpoints/Fileexplorer.php new file mode 100644 index 0000000..d58f149 --- /dev/null +++ b/src/Endpoints/Fileexplorer.php @@ -0,0 +1,79 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + $this->is_private = $this->swiffer_post( "is_private", "string" ); + if( $this->is_private !== "no" && $this->is_private !== "yes" ) + $this->is_private = "no"; + + $this->is_archived = $this->swiffer_post( "is_archived", "string" ); + if( $this->is_archived !== "no" && $this->is_archived !== "yes" ) + $this->is_archived = "no"; + + } + + protected function process(): void { + + $flags = 0; + if( $this->is_private === "yes" ) + $flags |= Data::F_PRIVATE_FILE; + else if( $this->is_archived === "yes" ) + $flags |= Data::F_ARCHIVED_FILE; + + $data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + $flags + ); + + if( !$data->file_exists() ) + RomhackPlazaFS::fatal_stop( 404, "File not found." ); + + $response = []; + $response['files'] = $data->list_files( $this->custom_post_type, $this->post_id ); + $response['private'] = $private->list_files( $this->custom_post_type, $this->post_id ); + $response['archived'] = $archived->list_files( $this->custom_post_type, $this->post_id ); + + RomhackPlazaFS::success_response( $response ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Generatetestkey.php b/src/Endpoints/Generatetestkey.php new file mode 100644 index 0000000..6c8c18b --- /dev/null +++ b/src/Endpoints/Generatetestkey.php @@ -0,0 +1,48 @@ +action = $this->swiffer_get( "want_action", "string" ); + if( $this->action === "" ) + RomhackPlazaFS::fatal_stop( 400, "Invalid want_action GET parameter." ); + + } + + protected function process(): void { + + $info = [ + 'user_id' => 1, + 'to' => $_ENV['ROMHACKPLAZAFS_URL'], + 'action' => $this->action, + 'generated_at' => time(), + 'expires_at' => time() + 900, + 'romhackplaza' => \bin2hex( random_bytes( 16 ) ), + ]; + + $json = json_encode( $info ); + $sig = hash_hmac( 'sha256', $json, $_ENV['ROMHACKPLAZAFS_SECRET_KEY'] ); + + $end = base64_encode( $json ) . "|" . $sig; + RomhackPlazaFS::success_response( [ 'zeus' => $end ] ); + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Markasarchived.php b/src/Endpoints/Markasarchived.php new file mode 100644 index 0000000..dd6f5a9 --- /dev/null +++ b/src/Endpoints/Markasarchived.php @@ -0,0 +1,70 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + ); + + if( !$data->file_exists() ) + RomhackPlazaFS::fatal_stop( 404, "File not found." ); + + $new_data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + Data::F_ARCHIVED_FILE + ); + + if( $new_data->file_exists() ) + RomhackPlazaFS::fatal_stop( 500, "File already exists. You can't archive that have the same name than an other archived file." ); + + if( $data->change_data_location( $new_data ) ) + RomhackPlazaFS::success_response( [ 'status' => Data::STATUS_ARCHIVED ] ); + + RomhackPlazaFS::fatal_stop( 500, "Error during file marking" ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Markasprivate.php b/src/Endpoints/Markasprivate.php new file mode 100644 index 0000000..eb68792 --- /dev/null +++ b/src/Endpoints/Markasprivate.php @@ -0,0 +1,70 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name + ); + + if( !$data->file_exists() ) + RomhackPlazaFS::fatal_stop( 404, "File not found." ); + + $new_data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + Data::F_PRIVATE_FILE + ); + + if( $new_data->file_exists() ) + RomhackPlazaFS::fatal_stop( 500, "File already exists. Can't replace. Please delete private file before." ); + + if( $data->change_data_location( $new_data ) ) + RomhackPlazaFS::success_response( [ 'status' => Data::STATUS_PRIVATE ] ); + + RomhackPlazaFS::fatal_stop( 500, "Error during file marking" ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Markaspublic.php b/src/Endpoints/Markaspublic.php new file mode 100644 index 0000000..2e461ee --- /dev/null +++ b/src/Endpoints/Markaspublic.php @@ -0,0 +1,70 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name, + Data::F_PRIVATE_FILE + ); + + if( !$data->file_exists() ) + RomhackPlazaFS::fatal_stop( 404, "File not found." ); + + $new_data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name + ); + + if( $new_data->file_exists() ) + RomhackPlazaFS::fatal_stop( 500, "File already exists. Can't replace. Please delete published file before." ); + + if( $data->change_data_location( $new_data ) ) + RomhackPlazaFS::success_response( [ 'status' => Data::STATUS_PUBLISH ] ); + + RomhackPlazaFS::fatal_stop( 500, "Error during file marking" ); + + } + + +} \ No newline at end of file diff --git a/src/Endpoints/Uploadchunk.php b/src/Endpoints/Uploadchunk.php new file mode 100644 index 0000000..111ff48 --- /dev/null +++ b/src/Endpoints/Uploadchunk.php @@ -0,0 +1,66 @@ +post_id = $this->swiffer_post( "post_id", "int" ); + if( $this->post_id < 1 ) + RomhackPlazaFS::invalid_parameter_stop( "post_id", "POST" ); + + $this->custom_post_type = $this->swiffer_post( "post_type", "string" ); + if( $this->custom_post_type === "" ) + RomhackPlazaFS::invalid_parameter_stop( "post_type", "POST" ); + + $this->file_name = $this->swiffer_post( "filename", "filename" ); + if( $this->file_name === "" ) + RomhackPlazaFS::invalid_parameter_stop( "filename", "POST" ); + + $this->current_chunk = $this->swiffer_post( "current_chunk", "int" ); + $this->total_chunks = $this->swiffer_post( "total_chunks", "int" ); + if( $this->total_chunks < $this->current_chunk ) + RomhackPlazaFS::invalid_parameter_stop( "current_chunk", "POST" ); + + } + + protected function process(): void { + + $data = Data::setup( + $this->custom_post_type, + $this->post_id, + $this->file_name + ); + + $data->file_path_to_temp(); + + if( $data->write( $this->current_chunk, $this->total_chunks ) ) + RomhackPlazaFS::success_response( [ 'chunk' => $this->current_chunk, 'total_chunks' => $this->total_chunks, 'uploaded' => true ] ); + + RomhackPlazaFS::fatal_stop( 500, "Error during file writing" ); + + } + + +} \ No newline at end of file diff --git a/src/Exceptions/InvalidArgumentException.php b/src/Exceptions/InvalidArgumentException.php new file mode 100644 index 0000000..3c2a274 --- /dev/null +++ b/src/Exceptions/InvalidArgumentException.php @@ -0,0 +1,6 @@ +folder_path = $folder_path; + $this->file_path = $file_path; + $this->old_file_path = $file_path; + $this->flags = $flags; + } + + public function file_path_to_temp(): void { + $this->old_file_path = $this->file_path; + $this->file_path .= '.part'; + $this->flags |= self::F_TEMPORARY_FILE; + } + + public function file_path_to_real(): void { + + $this->file_path = $this->old_file_path; + $this->flags &= ~self::F_TEMPORARY_FILE; + + } + + public function file_exists(): bool { + + if( $this->file_path === null ) + return false; + + return file_exists($this->file_path); + + } + + public function size(): int { + + if( !$this->file_exists() ) + return 0; + + return filesize($this->file_path); + } + + public function pretty_size(): string { + + $bytes = $this->size(); + + if ($bytes >= 1073741824) { + $bytes = number_format($bytes / 1073741824, 2) . ' GB'; + } elseif ($bytes >= 1048576) { + $bytes = number_format($bytes / 1048576, 2) . ' MB'; + } elseif ($bytes >= 1024) { + $bytes = number_format($bytes / 1024, 2) . ' KB'; + } else { + $bytes = ($bytes == 0) ? '0 bytes' : $bytes . ' bytes'; + } + + return $bytes; + } + + public function status(): string + { + if( !$this->file_exists() ) + return self::STATUS_DELETED; + + if( $this->flags & self::F_PRIVATE_FILE ) + return self::STATUS_PRIVATE; + if( $this->flags & self::F_ARCHIVED_FILE ) + return self::ARCHIVE_SUBFOLDER; + return self::STATUS_PUBLISH; + + } + + public function write( int $current_chunk, int $total_chunks ): bool { + + if( $this->file_path === null ) + RomhackPlazaFS::fatal_stop( 500, "Filepath is not registred."); + + if( $this->flags & !self::F_TEMPORARY_FILE ) + RomhackPlazaFS::fatal_stop( 500, "Filepath is not temporary."); + + if( !isset( $_FILES['file'] ) ) + RomhackPlazaFS::invalid_parameter_stop( "file" ); + + $in = fopen($_FILES['file']['tmp_name'], 'rb'); + if( !$in ) + RomhackPlazaFS::fatal_stop( 500, "Could not open input file." ); + + $out = fopen( $this->file_path, 'ab' ); + if( !$out ) + RomhackPlazaFS::fatal_stop( 500, "Could not open output file." ); + + while( $chunk = fread( $in, self::CHUNK_SIZE ) ) + fwrite( $out, $chunk ); + + fclose( $in ); + fclose( $out ); + + $this->rename_if_final_chunk( $current_chunk, $total_chunks ); + return true; + + } + + private function rename_if_final_chunk( int $current_chunk, int $total_chunks ) + { + if( $this->file_path === null || $this->old_file_path === null ) + RomhackPlazaFS::fatal_stop( 500, "Filepath is not registred."); + + if( $current_chunk + 1 === $total_chunks ) + rename( $this->file_path, $this->old_file_path ); + } + + public function change_data_location( Data &$new_data_location ): bool { + + if( $this->file_path === null || $new_data_location->file_path === null ) + RomhackPlazaFS::fatal_stop( 500, "Filepath is not registred."); + + if( !rename( $this->file_path, $new_data_location->file_path ) ) + RomhackPlazaFS::fatal_stop( 500, "The file hasn't been moved."); + + $this->file_path = $new_data_location->file_path; + return true; + + } + + public function can_be_explored(): bool { + + if( $this->file_path === null ) + return false; + + return in_array( mime_content_type( $this->file_path ), [ 'application/zip', 'application/x-rar', 'application/x-7z-compressed' ] ); + + } + + public function can_be_patched(): bool { + + if( $this->file_path === null ) + return false; + + $file_arr = explode('.', $this->file_path); + $file_ext = end($file_arr ); + + return mime_content_type( $this->file_path ) === 'application/zip' || in_array( $file_ext, RomhackPlazaFS::dotenv_array( "ROMHACKPLAZAFS_PATCHER_ALLOWED_EXT" ) ); + } + + private function _return_list_files( array $files_array, string $custom_post_type, int $post_id ){ + + $return_files = array_map( function( $file_name ) use ( $custom_post_type, $post_id ){ + + $download_url = RomhackPlazaFS::build_url( 'Download', [ 'filename' => $file_name, 'post_type' => $custom_post_type, 'entry_id' => $post_id ] ); + $file = new self( $this->folder_path, $this->folder_path . $file_name, $this->flags ); + + return [ + 'name' => $file_name, + 'size' => $file->size(), + 'pretty_size' => $file->pretty_size(), + 'status' => $file->status(), + 'download' => $download_url, + 'explorer' => $file->can_be_explored() ? RomhackPlazaFS::build_url( "FileExplorer", [ 'filename' => urlencode( $file_name ), 'post_type' => $custom_post_type, 'entry_id' => $post_id ] ) : null, + 'patcher' => $file->can_be_patched() ? RomhackPlazaFS::build_patcher_url( $download_url, $post_id ) : null, + ]; + + }, array_values( $files_array ) ); + + return $return_files; + } + + public function list_files( string $custom_post_type = "", int $post_id = 0 ): array { + + if( !\file_exists( $this->folder_path ) ) + return []; + + $files = array_diff( scandir( $this->folder_path ), [ '.', '..', rtrim( self::PRIVATE_SUBFOLDER, '/' ), rtrim( self::ARCHIVE_SUBFOLDER, '/' ) ] ); + return $this->_return_list_files( $files, $custom_post_type, $post_id ); + + } + +} \ No newline at end of file diff --git a/src/RomhackPlazaFS.php b/src/RomhackPlazaFS.php new file mode 100644 index 0000000..0633785 --- /dev/null +++ b/src/RomhackPlazaFS.php @@ -0,0 +1,121 @@ + $value ) { + $url .= '&' . $key . '=' . $value; + } + return $url; + + } + + public static function build_patcher_url( string $download_url, int $post_id ) + { + return $_ENV['ROMHACKPLAZAFS_PATCHER_URL'] . '?download=' . base64_encode( $download_url ) . '&entry=' . $post_id; + } + + public static function dotenv_array( string $env_name ){ + + return explode( " ", $_ENV[$env_name] ); + + } + + public function __construct(){ + + $this->endpoint_requested = $this->swiffer_get( 'action', 'string' ); + $this->is_index = str_contains( $_SERVER['REQUEST_URI'], 'index.php' ); + + if( $this->is_index ) + $this->fs_api(); + + } + + public function give_token( string $token_name ): string { + + $token = $this->swiffer_post( $token_name, 'string' ); + if( $token === "" ) + $token = $this->swiffer_get( $token_name, 'string' ); + + return $token; + } + + private function fs_api(){ + + if( $this->endpoint_requested === "" ) + self::fatal_stop( 400, "action GET parameter not found." ); + + $this->endpoint_requested = preg_replace('/[^a-zA-Z0-9]/', '', $this->endpoint_requested); + + $endpoint_class = 'RomhackPlazaFS\\Endpoints\\'. ucfirst( strtolower( $this->endpoint_requested ) ); + if( !class_exists( $endpoint_class ) ) + self::fatal_stop( 404, "This endpoint is not defined." ); + + $endpoint = new $endpoint_class(); + if( !$endpoint instanceof Abstract_Endpoint ) + self::fatal_stop( 500, "This endpoint is not valid." ); + + $endpoint->exec( $this ); + + } + +} \ No newline at end of file diff --git a/src/SecurityTrait.php b/src/SecurityTrait.php new file mode 100644 index 0000000..cdf7fdd --- /dev/null +++ b/src/SecurityTrait.php @@ -0,0 +1,53 @@ + WordPress user ID. + * 'to' => Server URL + * 'action' => The action he wants to do. + * 'generated_at' => Timestamp generated value. + * 'expires_at' => Timestamp theory expiration value. (5 minutes...), + * 'romhackplaza' => Random value. + */ + $info = json_decode( $json, true ); + + if( $info['expires_at'] < time() ) + throw new TokenExpiredException(); + + if( $info['to'] !== $_ENV['ROMHACKPLAZAFS_URL'] ) + throw new WrongServerException(); + + return $info; + + } + +} \ No newline at end of file diff --git a/src/SwifferTrait.php b/src/SwifferTrait.php new file mode 100644 index 0000000..c91baf1 --- /dev/null +++ b/src/SwifferTrait.php @@ -0,0 +1,57 @@ +getMessage() ); + } + + return null; + } + + public function swiffer_get( string $name, string $type ): mixed { + return $this->swiffer( INPUT_GET, $name, $type ); + } + + public function swiffer_post( string $name, string $type ): mixed { + return $this->swiffer( INPUT_POST, $name, $type ); + } + + +} \ No newline at end of file diff --git a/src/bootstrap.php b/src/bootstrap.php new file mode 100644 index 0000000..d10d53d --- /dev/null +++ b/src/bootstrap.php @@ -0,0 +1,25 @@ +load(); + +} + +_romhackplazafs_define_constants(); +_romhackplazafs_read_env(); + +$_romhackplazafs = new RomhackPlazaFS(); \ No newline at end of file