diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..d8a888ed2 --- /dev/null +++ b/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["es2015"], + "compact": true, + "minified": true, + "only": "public/themes/pterodactyl/js/frontend/files/src/*.js", + "sourceMaps": "inline", + "comments": false +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..bc49d523e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.env.example b/.env.example index ba98b1c75..fa7e20965 100644 --- a/.env.example +++ b/.env.example @@ -1,12 +1,11 @@ APP_ENV=production APP_DEBUG=false APP_KEY=SomeRandomString3232RandomString -APP_THEME=default +APP_THEME=pterodactyl APP_TIMEZONE=UTC APP_CLEAR_TASKLOG=720 APP_DELETE_MINUTES=10 -CONSOLE_PUSH_FREQ=250 -CONSOLE_PUSH_COUNT=10 +APP_URL=http://yoursite.com/ DB_HOST=localhost DB_PORT=3306 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 1674b0b9e..346d32290 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,61 +1,6 @@ - - -## Product -Please check the corresponding boxes below for which products this is about. +Please describe your issue in full below. Include what products are affected, as well as what version(s) you are running. Please also include information about your system, such as `uname -a` and `php -v` and `docker info` if applicable. -- [ ] Panel -- [ ] Daemon -- [ ] Dockerfile(s) [Please list if so: __ ] +If you're just making a suggestion, be descriptive, and link to any issues that might be releated as well. -## Type -- [ ] Bug or Issue -- [ ] Feature Request -- [ ] Enhancement -- [ ] Other - - - - -## What Happens - - -## How to Reproduce - - -1. Step 1 -2. Step 2 -3. etc. - -## Error Logs - - - - -``` -error logs -``` - -## System Information -#### Output of `uname -a`: - -``` -paste here -``` - -#### Output of `php -v` (if Panel): - -``` -paste here -``` - -#### Output of `node -v` (if Daemon): - -``` -paste here -``` - -#### Output of `docker info` and `docker -v` (if Daemon or Dockerfiles): - -``` -paste here -``` +You can delete from this line up. +--------------------- diff --git a/.gitignore b/.gitignore index 9dfd2bc12..595557b70 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,4 @@ Homestead.yaml Vagrantfile Vagrantfile -node_modules -.babelrc \ No newline at end of file +node_modules \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d612005e8..f2ee47a5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,100 @@ This file is a running track of new features and fixes to each version of the pa This project follows [Semantic Versioning](http://semver.org) guidelines. +## v0.6.0-pre.1 +### Added +* Remote routes for daemon to contact in order to allow Daemon to retrieve updated service configuration files on boot. Centralizes services to the panel rather than to each daemon. +* Basic service pack implementation to allow assignment of modpacks or software to a server to pre-install applications and allow users to update. +* Users can now have a username as well as client name assigned to their account. +* Ability to create a node through the CLI using `pterodactyl:node` as well as locations via `pterodactyl:location`. +* New theme (AdminLTE) for front-end with tweaks to backend files to work properly with it. + +### Fixed +* Bug causing error logs to be spammed if someone timed out on an ajax based page. +* Fixes edge case where specific server names could cause daemon errors due to an invalid SFTP username being created by the panel. + +### Changed +* Admin API and base routes for user management now define the fields that should be passed to repositories rather than passing all fields. +* User model now defines mass assignment fields using `$fillable` rather than `$guarded`. + +### Deprecated + +## v0.5.6 (Bodacious Boreopterus) +### Added +* Added the following languages: Estonian `et`, Dutch `nl`, Norwegian `nb` (partial), Romanian `ro`, and Russian `ru`. Interested in helping us translate the panel into more languages, or improving existing translations? Contact us on Discord and let us know. +* Added missing `strings.password` to language file for English. +* Allow listing of users from the API by passing either the user ID or their email. + +### Fixed +* Fixes bug where assigning a variable a default value (or valid value) of `0` would cause the panel to reject the value thinking it did not exist. +* Addresses potential for crash by limiting total ports that can be assigned per-range to 2000. +* Fixes server names requiring at minimum 4 characters. Name can now be 1 to 200 characters long. :pencil2: +* Fixes bug that would allow adding the owner of a server as a subuser for that same server. +* Fixes bug that would allow creating multiple subusers with the same email address. +* Fixes bug where Sponge servers were improperly tagged as a spigot server in the daemon causing issues when booting or modifying configuration files. +* Use transpiled ES6 -> ES5 filemanager code in browsers. +* Fixes service option name displaying the name of a nwly added variable after the variable is added and until the page is refreshed. (see #208) + +### Changed +* Filemanager and EULA checking javascript is now written in pure ES6 code rather than as a blade-syntax template. This allows the use of babel to transpile into ES5 as a minified version. + +## v0.5.5 (Bodacious Boreopterus) +### Added +* New API route to return allocations given a server ID. This adds support for a community-driven WHMCS module :rocket: available [here](https://github.com/hammerdawn/Pterodactyl-WHMCS). + +### Fixed +* Fixes subuser display when trying to edit an existing subuser. + +## v0.5.4 (Bodacious Boreopterus) +### Added +* Changing node configuration values now automatically makes a call to the daemon and updates the configuration there. Changing daemon tokens now does not require any intervention, and takes effect immediately. SSL & Port configurations will still require a daemon reboot. +* New button in file manager that triggers the right click menu to enable support on mobile devices and those who cannot right click (blessed be them). +* Support for filtering users when listing all users on the system. +* Container ID and User ID on the daemon are now shown when viewing a server in the panel. + +### Changed +* File uploads now account for a maximum file size that is assigned for the daemon, and gives cleaner errors when that limit is reached. +* File upload limit can now be controlled from the panel. +* Updates regex and default values for some Minecraft services to reflect current technology. + +### Fixed +* Fixes potential for generated password to not meet own validation requirements. +* Fixes some regex checking issues with newer versions of Minecraft. + +## v0.5.3 (Bodacious Boreopterus) +### Fixed +* Fixed an error that occurred when viewing a node listing when no nodes were created yet due to a mis-declared variable. Also fixes a bug that would have all nodes trying to connect to the daemon using the same secret token on the node listing, causing only the last node to display properly. +* Fixes a bug that displayed the panel version rather than the daemon version when viewing a node. +* Fixes a multiplicator being applied to an overallocation field rather than a storage space field when adding a node. + +### Changed +* Added a few new configuration variables for nodes to the default config, as well as a variable that will be used in future versions of the daemon. + +## v0.5.2 (Bodacious Boreopterus) +### Fixed +* Time axis on server graphs is corrected to show the minutes rather than the current month. +* Node deletion now works correctly and deletes allocations as well. +* Fixes a bug that would leave orphaned databases on the system if there was an error during creation. +* Fixes an issue that could occur if a UUID contained `#e#` formatting within it when it comes to creating databases. +* Fixed node status display to account for updated daemon security changes. +* Fixes default language being selected as German (defaults to English now). +* Fixes bug preventing the deletion of database servers. + +### Changed +* Using `node:` when filtering servers now properly filters the servers by node name, rather than looking for the node ID. +* Using `owner:` when filtering servers now properly filters by the owner's email rather than ID. +* Added some quick help buttons to the admin index page for getting support or checking the documentation. +* Panel now displays `Pterodactyl Panel` as the company name if one is not set. + +### Added +* Added basic information about the daemon when viewing a node, including the host OS and version, CPU count, and the daemon version. +* Added version checking for the daemon and panel that alerts admins when daemons or the panel is out of date. +* Added multiplicator support to certain memory and disk fields that allow users to enter `10g` and have it converted to MB automatically. + +## v0.5.1 (Bodacious Boreopterus) +### Fixed +* Fixes a bug that allowed a user to bypass 2FA authentication if using the correct username and password for an account. + ## v0.5.0 (Bodacious Boreopterus) After nearly a month in the works, version `v0.5.0` is finally here! 🎉 diff --git a/LICENSE.md b/LICENSE.md index b4b61b7c2..929536020 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ # The MIT License (MIT) ``` -Copyright (c) 2015 - 2016 Dane Everitt +Copyright (c) 2015 - 2017 Dane Everitt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 88c02a171..30f0062b4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Support for using Pterodactyl can be found on our [wiki](https://github.com/Pter ## License ``` -Copyright (c) 2015 - 2016 Dane Everitt +Copyright (c) 2015 - 2017 Dane Everitt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,8 @@ A huge thanks to [PhraseApp](https://phraseapp.com) who provide us the software Ace Editor - [license](https://github.com/ajaxorg/ace/blob/master/LICENSE) - [homepage](https://ace.c9.io) +AdminLTE - [license](https://github.com/almasaeed2010/AdminLTE/blob/master/LICENSE) - [homepage](https://almsaeedstudio.com) + Animate.css - [license](https://github.com/daneden/animate.css/blob/master/LICENSE) - [homepage](http://daneden.github.io/animate.css/) Async.js - [license](https://github.com/caolan/async/blob/master/LICENSE) - [homepage](https://github.com/caolan/async/) @@ -57,8 +59,12 @@ jQuery Terminal - [license](https://github.com/jcubic/jquery.terminal/blob/maste Lodash - [license](https://github.com/lodash/lodash/blob/master/LICENSE) - [homepage](https://lodash.com/) +Select2 - [license](https://github.com/select2/select2/blob/master/LICENSE.md) - [homepage](https://select2.github.io) + Socket.io - [license](https://github.com/socketio/socket.io/blob/master/LICENSE) - [homepage](http://socket.io) +Socket.io File Upload - [license](https://github.com/vote539/socketio-file-upload/blob/master/server.js#L1-L27) - [homepage](https://github.com/vote539/socketio-file-upload) + SweetAlert - [license](https://github.com/t4t5/sweetalert/blob/master/LICENSE) - [homepage](http://t4t5.github.io/sweetalert/) Typeahead — [license](https://github.com/bassjobsen/Bootstrap-3-Typeahead/blob/master/bootstrap3-typeahead.js) — [homepage](https://github.com/bassjobsen/Bootstrap-3-Typeahead) diff --git a/app/Console/Commands/AddLocation.php b/app/Console/Commands/AddLocation.php new file mode 100644 index 000000000..d9da92466 --- /dev/null +++ b/app/Console/Commands/AddLocation.php @@ -0,0 +1,75 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Console\Commands; + +use Illuminate\Console\Command; +use Pterodactyl\Repositories\LocationRepository; + +class AddLocation extends Command +{ + protected $data = []; + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'pterodactyl:location + {--short= : The shortcode name of this location (ex. us1).} + {--long= : A longer description of this location.}'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Creates a new location on the system via the CLI.'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->data['short'] = (is_null($this->option('short'))) ? $this->ask('Location Short Code') : $this->option('short'); + $this->data['long'] = (is_null($this->option('long'))) ? $this->ask('Location Description') : $this->option('long'); + + $repo = new LocationRepository; + $id = $repo->create($this->data); + + $this->info('Location ' . $this->data['short'] . ' created with ID: ' . $id); + } +} diff --git a/app/Console/Commands/AddNode.php b/app/Console/Commands/AddNode.php new file mode 100644 index 000000000..4b4468422 --- /dev/null +++ b/app/Console/Commands/AddNode.php @@ -0,0 +1,112 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Console\Commands; + +use Illuminate\Console\Command; +use Pterodactyl\Models\Location; +use Pterodactyl\Repositories\NodeRepository; + +class AddNode extends Command +{ + protected $data = []; + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'pterodactyl:node + {--name= : Name of the node.} + {--location= : The shortcode of the location to add this node to.} + {--fqdn= : The fully-qualified domain for the node.} + {--ssl= : Should the daemon use SSL for connections (T/F).} + {--memory= : The total memory available on this node for servers.} + {--disk= : The total disk space available on this node for servers.} + {--daemonBase= : The directory in which server files will be stored.} + {--daemonListen= : The port the daemon will listen on for connections.} + {--daemonSFTP= : The port to be used for SFTP conncetions to the daemon.}'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Adds a new node to the system via the CLI.'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $locations = Location::all(['id', 'short', 'long']); + + $this->data['name'] = (is_null($this->option('name'))) ? $this->ask('Node Name') : $this->option('name'); + + if (is_null($this->option('location'))) { + $this->table(['ID', 'Short Code', 'Description'], $locations->toArray()); + $selectedLocation = $this->anticipate('Node Location (Short Name)', $locations->pluck('short')->toArray()); + } else { + $selectedLocation = $this->option('location'); + } + + $this->data['location'] = $locations->where('short', $selectedLocation)->first()->id; + + if (is_null($this->option('fqdn'))) { + $this->line('Please enter domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node.'); + $this->data['fqdn'] = $this->ask('Fully Qualified Domain Name'); + } else { + $this->data['fqdn'] = $this->option('fqdn'); + } + + $useSSL = (is_null($this->option('ssl'))) ? $this->confirm('Use SSL', true) : $this->option('ssl'); + + $this->data['scheme'] = ($useSSL) ? 'https' : 'http'; + $this->data['memory'] = (is_null($this->option('memory'))) ? $this->ask('Total Memory (in MB)') : $this->option('memory'); + $this->data['memory_overallocate'] = 0; + $this->data['disk'] = (is_null($this->option('disk'))) ? $this->ask('Total Disk Space (in MB)') : $this->option('disk'); + $this->data['disk_overallocate'] = 0; + $this->data['public'] = 1; + $this->data['daemonBase'] = (is_null($this->option('daemonBase'))) ? $this->ask('Daemon Server File Location', '/srv/daemon-data') : $this->option('daemonBase'); + $this->data['daemonListen'] = (is_null($this->option('daemonListen'))) ? $this->ask('Daemon Listening Port', 8080) : $this->option('daemonListen'); + $this->data['daemonSFTP'] = (is_null($this->option('daemonSFTP'))) ? $this->ask('Daemon SFTP Port', 2022) : $this->option('daemonSFTP'); + + $repo = new NodeRepository; + $id = $repo->create($this->data); + + $this->info('Node created with ID: ' . $id); + } +} diff --git a/app/Console/Commands/CleanServiceBackup.php b/app/Console/Commands/CleanServiceBackup.php new file mode 100644 index 000000000..0a6a3e272 --- /dev/null +++ b/app/Console/Commands/CleanServiceBackup.php @@ -0,0 +1,74 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Console\Commands; + +use Carbon; +use Storage; +use Illuminate\Console\Command; + +class CleanServiceBackup extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'pterodactyl:cleanservices'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Cleans .bak files assocaited with service backups whene editing files through the panel.'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $files = Storage::files('services/.bak'); + + foreach ($files as $file) { + $lastModified = Carbon::createFromTimestamp(Storage::lastModified($file)); + if ($lastModified->diffInMinutes(Carbon::now()) > 5) { + $this->info('Deleting ' . $file); + Storage::delete($file); + } + } + } +} diff --git a/app/Console/Commands/ClearServices.php b/app/Console/Commands/ClearServices.php index 626d7720f..db62d268c 100644 --- a/app/Console/Commands/ClearServices.php +++ b/app/Console/Commands/ClearServices.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; use DB; - use Illuminate\Console\Command; class ClearServices extends Command @@ -60,8 +60,7 @@ class ClearServices extends Command */ public function handle() { - - if (!$this->confirm('This is a destructive operation, are you sure you wish to continue?')) { + if (! $this->confirm('This is a destructive operation, are you sure you wish to continue?')) { $this->error('Canceling.'); exit(); } diff --git a/app/Console/Commands/ClearTasks.php b/app/Console/Commands/ClearTasks.php index 4f2181ca0..26f0da761 100644 --- a/app/Console/Commands/ClearTasks.php +++ b/app/Console/Commands/ClearTasks.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; -use DB; use Carbon; use Pterodactyl\Models; use Illuminate\Console\Command; use Illuminate\Foundation\Bus\DispatchesJobs; -use Pterodactyl\Jobs\SendScheduledTask; - class ClearTasks extends Command { - use DispatchesJobs; /** diff --git a/app/Console/Commands/Inspire.php b/app/Console/Commands/Inspire.php index 6efa5aa73..b579f2c86 100644 --- a/app/Console/Commands/Inspire.php +++ b/app/Console/Commands/Inspire.php @@ -28,6 +28,6 @@ class Inspire extends Command */ public function handle() { - $this->comment(PHP_EOL.Inspiring::quote().PHP_EOL); + $this->comment(PHP_EOL . Inspiring::quote() . PHP_EOL); } } diff --git a/app/Console/Commands/MakeUser.php b/app/Console/Commands/MakeUser.php index a1d507b79..05803dd3b 100644 --- a/app/Console/Commands/MakeUser.php +++ b/app/Console/Commands/MakeUser.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,11 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; -use Hash; use Illuminate\Console\Command; - use Pterodactyl\Repositories\UserRepository; class MakeUser extends Command @@ -36,6 +35,9 @@ class MakeUser extends Command * @var string */ protected $signature = 'pterodactyl:user + {--firstname= : First name to use for this account.} + {--lastname= : Last name to use for this account.} + {--username= : Username to use for this account.} {--email= : Email address to use for this account.} {--password= : Password to assign to the user.} {--admin= : Boolean flag for if user should be an admin.}'; @@ -64,19 +66,23 @@ class MakeUser extends Command */ public function handle() { - $email = is_null($this->option('email')) ? $this->ask('Email') : $this->option('email'); - $password = is_null($this->option('password')) ? $this->secret('Password') : $this->option('password'); + $data['name_first'] = is_null($this->option('firstname')) ? $this->ask('First Name') : $this->option('firstname'); + $data['name_last'] = is_null($this->option('lastname')) ? $this->ask('Last Name') : $this->option('lastname'); + $data['username'] = is_null($this->option('username')) ? $this->ask('Username') : $this->option('username'); + $data['email'] = is_null($this->option('email')) ? $this->ask('Email') : $this->option('email'); + $data['password'] = is_null($this->option('password')) ? $this->secret('Password') : $this->option('password'); $password_confirmation = is_null($this->option('password')) ? $this->secret('Confirm Password') : $this->option('password'); - if ($password !== $password_confirmation) { + if ($data['password'] !== $password_confirmation) { return $this->error('The passwords provided did not match!'); } - $admin = is_null($this->option('admin')) ? $this->confirm('Is this user a root administrator?') : $this->option('admin'); + $data['root_admin'] = is_null($this->option('admin')) ? $this->confirm('Is this user a root administrator?') : $this->option('admin'); try { $user = new UserRepository; - $user->create($email, $password, $admin); + $user->create($data); + return $this->info('User successfully created.'); } catch (\Exception $ex) { return $this->error($ex->getMessage()); diff --git a/app/Console/Commands/RunTasks.php b/app/Console/Commands/RunTasks.php index 3047dc54e..7807f8dbd 100644 --- a/app/Console/Commands/RunTasks.php +++ b/app/Console/Commands/RunTasks.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; -use DB; use Carbon; use Pterodactyl\Models; use Illuminate\Console\Command; -use Illuminate\Foundation\Bus\DispatchesJobs; - use Pterodactyl\Jobs\SendScheduledTask; +use Illuminate\Foundation\Bus\DispatchesJobs; class RunTasks extends Command { - use DispatchesJobs; /** diff --git a/app/Console/Commands/ShowVersion.php b/app/Console/Commands/ShowVersion.php index 0dcce04a1..199a905b1 100644 --- a/app/Console/Commands/ShowVersion.php +++ b/app/Console/Commands/ShowVersion.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; +use Version; use Illuminate\Console\Command; class ShowVersion extends Command @@ -58,6 +60,6 @@ class ShowVersion extends Command */ public function handle() { - $this->info('You are running Pterodactyl Panel ' . config('app.version')); + $this->info('You are running Pterodactyl Panel v' . Version::getCurrentPanel() . ' (' . ((Version::isLatestPanel()) ? 'Up to Date' : 'Latest: ' . Version::getDaemon()) . ')'); } } diff --git a/app/Console/Commands/UpdateEmailSettings.php b/app/Console/Commands/UpdateEmailSettings.php index f6dd5a304..620982b98 100644 --- a/app/Console/Commands/UpdateEmailSettings.php +++ b/app/Console/Commands/UpdateEmailSettings.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; use Illuminate\Console\Command; @@ -66,7 +67,7 @@ class UpdateEmailSettings extends Command { $variables = []; $file = base_path() . '/.env'; - if (!file_exists($file)) { + if (! file_exists($file)) { $this->error('Missing environment file! It appears that you have not installed this panel correctly.'); exit(); } @@ -75,35 +76,35 @@ class UpdateEmailSettings extends Command $this->table([ 'Option', - 'Description' + 'Description', ], [ [ 'smtp', - 'SMTP Server Email' + 'SMTP Server Email', ], [ 'mail', - 'PHP\'s Internal Mail Server' + 'PHP\'s Internal Mail Server', ], [ 'mailgun', - 'Mailgun Email Service' + 'Mailgun Email Service', ], [ 'mandrill', - 'Mandrill Transactional Email Service' + 'Mandrill Transactional Email Service', ], [ 'postmark', - 'Postmark Transactional Email Service' - ] + 'Postmark Transactional Email Service', + ], ]); $variables['MAIL_DRIVER'] = is_null($this->option('driver')) ? $this->choice('Which email driver would you like to use?', [ 'smtp', 'mail', 'mailgun', 'mandrill', - 'postmark' + 'postmark', ]) : $this->option('driver'); switch ($variables['MAIL_DRIVER']) { diff --git a/app/Console/Commands/UpdateEnvironment.php b/app/Console/Commands/UpdateEnvironment.php index 7afa3e7e2..085b081df 100644 --- a/app/Console/Commands/UpdateEnvironment.php +++ b/app/Console/Commands/UpdateEnvironment.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Console\Commands; use Uuid; @@ -66,10 +67,9 @@ class UpdateEnvironment extends Command */ public function handle() { - $variables = []; $file = base_path() . '/.env'; - if (!file_exists($file)) { + if (! file_exists($file)) { $this->error('Missing environment file! It appears that you have not installed this panel correctly.'); exit(); } @@ -77,12 +77,12 @@ class UpdateEnvironment extends Command $envContents = file_get_contents($file); $this->info('Simply leave blank and press enter to fields that you do not wish to update.'); - if (!env('SERVICE_AUTHOR', false)) { + if (! env('SERVICE_AUTHOR', false)) { $this->info('No service author set, setting one now.'); $variables['SERVICE_AUTHOR'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); } - if (!env('QUEUE_STANDARD', false) || !env('QUEUE_DRIVER', false)) { + if (! env('QUEUE_STANDARD', false) || ! env('QUEUE_DRIVER', false)) { $this->info('Setting default queue settings.'); $variables['QUEUE_DRIVER'] = env('QUEUE_DRIVER', 'database'); $variables['QUEUE_HIGH'] = env('QUEUE_HIGH', 'high'); @@ -91,25 +91,25 @@ class UpdateEnvironment extends Command } if (is_null($this->option('dbhost'))) { - $variables['DB_HOST'] = $this->anticipate('Database Host', [ 'localhost', '127.0.0.1', env('DB_HOST') ], env('DB_HOST')); + $variables['DB_HOST'] = $this->anticipate('Database Host', ['localhost', '127.0.0.1', env('DB_HOST')], env('DB_HOST')); } else { $variables['DB_HOST'] = $this->option('dbhost'); } if (is_null($this->option('dbport'))) { - $variables['DB_PORT'] = $this->anticipate('Database Port', [ 3306, env('DB_PORT') ], env('DB_PORT')); + $variables['DB_PORT'] = $this->anticipate('Database Port', [3306, env('DB_PORT')], env('DB_PORT')); } else { $variables['DB_PORT'] = $this->option('dbport'); } if (is_null($this->option('dbname'))) { - $variables['DB_DATABASE'] = $this->anticipate('Database Name', [ 'pterodactyl', 'homestead', ENV('DB_DATABASE') ], env('DB_DATABASE')); + $variables['DB_DATABASE'] = $this->anticipate('Database Name', ['pterodactyl', 'homestead', ENV('DB_DATABASE')], env('DB_DATABASE')); } else { $variables['DB_DATABASE'] = $this->option('dbname'); } if (is_null($this->option('dbuser'))) { - $variables['DB_USERNAME'] = $this->anticipate('Database Username', [ ENV('DB_DATABASE') ], env('DB_USERNAME')); + $variables['DB_USERNAME'] = $this->anticipate('Database Username', [ENV('DB_DATABASE')], env('DB_USERNAME')); } else { $variables['DB_USERNAME'] = $this->option('dbuser'); } @@ -122,7 +122,7 @@ class UpdateEnvironment extends Command } if (is_null($this->option('url'))) { - $variables['APP_URL'] = $this->ask('Panel URL', env('APP_URL')); + $variables['APP_URL'] = $this->ask('Panel URL (include http(s)://)', env('APP_URL')); } else { $variables['APP_URL'] = $this->option('url'); } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index c8276b447..d55c3525f 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -21,6 +21,9 @@ class Kernel extends ConsoleKernel \Pterodactyl\Console\Commands\ClearTasks::class, \Pterodactyl\Console\Commands\ClearServices::class, \Pterodactyl\Console\Commands\UpdateEmailSettings::class, + \Pterodactyl\Console\Commands\CleanServiceBackup::class, + \Pterodactyl\Console\Commands\AddNode::class, + \Pterodactyl\Console\Commands\AddLocation::class, ]; /** @@ -33,5 +36,6 @@ class Kernel extends ConsoleKernel { $schedule->command('pterodactyl:tasks')->everyMinute()->withoutOverlapping(); $schedule->command('pterodactyl:tasks:clearlog')->twiceDaily(3, 15); + $schedule->command('pterodactyl:cleanservices')->twiceDaily(1, 13); } } diff --git a/app/Events/ServerDeleted.php b/app/Events/Server/Created.php similarity index 84% rename from app/Events/ServerDeleted.php rename to app/Events/Server/Created.php index 4451b01bc..d5a308876 100644 --- a/app/Events/ServerDeleted.php +++ b/app/Events/Server/Created.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,11 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -namespace Pterodactyl\Events; +namespace Pterodactyl\Events\Server; + +use Pterodactyl\Models\Server; use Illuminate\Queue\SerializesModels; -class ServerDeleted +class Created { use SerializesModels; @@ -36,9 +38,8 @@ class ServerDeleted * * @return void */ - public function __construct($id) + public function __construct(Server $server) { - $this->server = $id; + $this->server = $server; } - } diff --git a/resources/lang/de/passwords.php b/app/Events/Server/Creating.php similarity index 53% rename from resources/lang/de/passwords.php rename to app/Events/Server/Creating.php index 4202eba0b..cbba63eb1 100644 --- a/resources/lang/de/passwords.php +++ b/app/Events/Server/Creating.php @@ -1,8 +1,7 @@ - * Translated by Jakob Schrettenbrunner + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,23 +21,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -return [ - /* - |-------------------------------------------------------------------------- - | Password Reminder Language Lines - |-------------------------------------------------------------------------- - | - | The following language lines are the default lines which match reasons - | that are given by the password broker for a password update attempt - | has failed, such as for an invalid token or invalid new password. - | - */ +namespace Pterodactyl\Events\Server; - 'password' => 'Dein Passwort muss länger als 6 Zeichen sein und mit der Wiederolung übereinstimmen.', - 'reset' => 'Dein Passwort wurde zurückgesetzt!', - 'sent' => 'Du erhältst eine E-Mail mit dem Zurücksetzungslink!', - 'token' => 'Dieses Paswortrücksetzungstoken ist ungültig.', - 'user' => 'Wir können keinen Nutzer mit dieser Email Adresse finden.', +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; -]; +class Creating +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Deleted.php b/app/Events/Server/Deleted.php new file mode 100644 index 000000000..b36dca12d --- /dev/null +++ b/app/Events/Server/Deleted.php @@ -0,0 +1,45 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Deleted +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Deleting.php b/app/Events/Server/Deleting.php new file mode 100644 index 000000000..bb18e1ee9 --- /dev/null +++ b/app/Events/Server/Deleting.php @@ -0,0 +1,45 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Deleting +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/User/Created.php b/app/Events/User/Created.php new file mode 100644 index 000000000..a00bdd450 --- /dev/null +++ b/app/Events/User/Created.php @@ -0,0 +1,45 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Created +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Creating.php b/app/Events/User/Creating.php new file mode 100644 index 000000000..39a50f0c8 --- /dev/null +++ b/app/Events/User/Creating.php @@ -0,0 +1,45 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Creating +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Deleted.php b/app/Events/User/Deleted.php new file mode 100644 index 000000000..348c859c9 --- /dev/null +++ b/app/Events/User/Deleted.php @@ -0,0 +1,45 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Deleted +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Deleting.php b/app/Events/User/Deleting.php new file mode 100644 index 000000000..5bbd91366 --- /dev/null +++ b/app/Events/User/Deleting.php @@ -0,0 +1,45 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Deleting +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Exceptions/AccountNotFoundException.php b/app/Exceptions/AccountNotFoundException.php index 166031644..f8e36ed49 100644 --- a/app/Exceptions/AccountNotFoundException.php +++ b/app/Exceptions/AccountNotFoundException.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Exceptions; class AccountNotFoundException extends \Exception { - } diff --git a/app/Exceptions/DisplayException.php b/app/Exceptions/DisplayException.php index ae06f983a..c1b701f36 100644 --- a/app/Exceptions/DisplayException.php +++ b/app/Exceptions/DisplayException.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Exceptions; use Log; class DisplayException extends \Exception { - private $_logging = null; public function __construct($message, $log = null) @@ -44,5 +44,4 @@ class DisplayException extends \Exception { return $this->_logging; } - } diff --git a/app/Exceptions/DisplayValidationException.php b/app/Exceptions/DisplayValidationException.php index e8d319f4c..3d8a4fda2 100644 --- a/app/Exceptions/DisplayValidationException.php +++ b/app/Exceptions/DisplayValidationException.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Exceptions; class DisplayValidationException extends \Exception diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 2230c771d..6aac7cc02 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -3,12 +3,8 @@ namespace Pterodactyl\Exceptions; use Log; - use Exception; use DisplayException; -use DisplayValidationException; -use AccountNotFoundException; - use Illuminate\Auth\AuthenticationException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; @@ -50,13 +46,12 @@ class Handler extends ExceptionHandler */ public function render($request, Exception $exception) { - if ($request->isXmlHttpRequest() || $request->ajax() || $request->is('remote/*')) { + if ($request->expectsJson()) { $response = response()->json([ - 'error' => ($exception instanceof DisplayException) ? $exception->getMessage() : 'An unhandled error occured while attempting to process this request.' - ], 500); + 'error' => ($exception instanceof DisplayException) ? $exception->getMessage() : 'An unhandled error occured while attempting to process this request.', + ], ($this->isHttpException($exception)) ? $exception->getStatusCode() : 500); - // parent::render() will log it, we are bypassing it in this case. - Log::error($exception); + parent::report($exception); } return (isset($response)) ? $response : parent::render($request, $exception); @@ -74,7 +69,7 @@ class Handler extends ExceptionHandler if ($request->expectsJson()) { return response()->json(['error' => 'Unauthenticated.'], 401); } + return redirect()->guest('/auth/login'); } - } diff --git a/app/Facades/Version.php b/app/Facades/Version.php new file mode 100644 index 000000000..2ce007360 --- /dev/null +++ b/app/Facades/Version.php @@ -0,0 +1,35 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Facades; + +use Illuminate\Support\Facades\Facade; + +class Version extends Facade +{ + protected static function getFacadeAccessor() + { + return '\Pterodactyl\Services\VersionService'; + } +} diff --git a/app/Http/Controllers/API/BaseController.php b/app/Http/Controllers/API/BaseController.php index 7d897fe55..085803a11 100755 --- a/app/Http/Controllers/API/BaseController.php +++ b/app/Http/Controllers/API/BaseController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API; use Dingo\Api\Routing\Helpers; diff --git a/app/Http/Controllers/API/LocationController.php b/app/Http/Controllers/API/LocationController.php index 27f192679..3bae975d8 100755 --- a/app/Http/Controllers/API/LocationController.php +++ b/app/Http/Controllers/API/LocationController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API; use DB; @@ -32,14 +33,13 @@ use Pterodactyl\Models\Location; */ class LocationController extends BaseController { - public function __construct() { // } /** - * List All Locations + * List All Locations. * * Lists all locations currently on the system. * @@ -47,18 +47,13 @@ class LocationController extends BaseController * @Versions({"v1"}) * @Response(200) */ - public function list(Request $request) + public function lists(Request $request) { - $locations = Location::select('locations.*', DB::raw('GROUP_CONCAT(nodes.id) as nodes')) + return Location::select('locations.*', DB::raw('GROUP_CONCAT(nodes.id) as nodes')) ->join('nodes', 'locations.id', '=', 'nodes.location') ->groupBy('locations.id') - ->get(); - - foreach($locations as &$location) { - $location->nodes = explode(',', $location->nodes); - } - - return $locations->toArray(); + ->get()->each(function ($location) { + $location->nodes = explode(',', $location->nodes); + })->all(); } - } diff --git a/app/Http/Controllers/API/NodeController.php b/app/Http/Controllers/API/NodeController.php index a0da14af5..0eda949f4 100755 --- a/app/Http/Controllers/API/NodeController.php +++ b/app/Http/Controllers/API/NodeController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API; -use Illuminate\Http\Request; - use Pterodactyl\Models; -use Pterodactyl\Transformers\NodeTransformer; -use Pterodactyl\Transformers\AllocationTransformer; -use Pterodactyl\Repositories\NodeRepository; - -use Pterodactyl\Exceptions\DisplayValidationException; -use Pterodactyl\Exceptions\DisplayException; +use Illuminate\Http\Request; use Dingo\Api\Exception\ResourceException; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\NodeRepository; +use Pterodactyl\Exceptions\DisplayValidationException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; @@ -42,14 +39,13 @@ use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; */ class NodeController extends BaseController { - public function __construct() { // } /** - * List All Nodes + * List All Nodes. * * Lists all nodes currently on the system. * @@ -60,13 +56,13 @@ class NodeController extends BaseController * }) * @Response(200) */ - public function list(Request $request) + public function lists(Request $request) { return Models\Node::all()->toArray(); } /** - * Create a New Node + * Create a New Node. * * @Post("/nodes") * @Versions({"v1"}) @@ -102,7 +98,8 @@ class NodeController extends BaseController try { $node = new NodeRepository; $new = $node->create($request->all()); - return [ 'id' => $new ]; + + return ['id' => $new]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { @@ -113,7 +110,7 @@ class NodeController extends BaseController } /** - * List Specific Node + * List Specific Node. * * Lists specific fields about a server or all fields pertaining to that node. * @@ -129,16 +126,16 @@ class NodeController extends BaseController { $node = Models\Node::where('id', $id); - if (!is_null($request->input('fields'))) { - foreach(explode(',', $request->input('fields')) as $field) { - if (!empty($field)) { + if (! is_null($request->input('fields'))) { + foreach (explode(',', $request->input('fields')) as $field) { + if (! empty($field)) { $node->addSelect($field); } } } try { - if (!$node->first()) { + if (! $node->first()) { throw new NotFoundHttpException('No node by that ID was found.'); } @@ -146,8 +143,8 @@ class NodeController extends BaseController 'node' => $node->first(), 'allocations' => [ 'assigned' => Models\Allocation::where('node', $id)->whereNotNull('assigned_to')->get(), - 'unassigned' => Models\Allocation::where('node', $id)->whereNull('assigned_to')->get() - ] + 'unassigned' => Models\Allocation::where('node', $id)->whereNull('assigned_to')->get(), + ], ]; } catch (NotFoundHttpException $ex) { throw $ex; @@ -158,77 +155,105 @@ class NodeController extends BaseController public function config(Request $request, $id) { - if (!$request->secure()) { + if (! $request->secure()) { throw new BadRequestHttpException('This API route can only be accessed using a secure connection.'); } $node = Models\Node::where('id', $id)->first(); - if (!$node) { + if (! $node) { throw new NotFoundHttpException('No node by that ID was found.'); } return [ 'web' => [ 'listen' => $node->daemonListen, + 'host' => '0.0.0.0', 'ssl' => [ 'enabled' => ($node->scheme === 'https'), 'certificate' => '/etc/certs/' . $node->fqdn . '/fullchain.pem', - 'key' => '/etc/certs/' . $node->fqdn . '/privkey.pem' - ] + 'key' => '/etc/certs/' . $node->fqdn . '/privkey.pem', + ], ], 'docker' => [ 'socket' => '/var/run/docker.sock', - 'autoupdate_images' => true + 'autoupdate_images' => true, ], 'sftp' => [ 'path' => $node->daemonBase, 'port' => (int) $node->daemonSFTP, - 'container' => '0x0000' + 'container' => 'ptdl-sftp', + ], + 'query' => [ + 'kill_on_fail' => true, + 'fail_limit' => 5, ], 'logger' => [ 'path' => 'logs/', 'src' => false, 'level' => 'info', 'period' => '1d', - 'count' => 3 + 'count' => 3, ], 'remote' => [ + 'base' => config('app.url'), 'download' => route('remote.download'), - 'installed' => route('remote.install') + 'installed' => route('remote.install'), ], 'uploads' => [ - 'maximumSize' => 100000000 + 'size_limit' => $node->upload_size, ], 'keys' => [ - $node->daemonSecret + $node->daemonSecret, ], - 'query' => [ - 'kill_on_fail' => true, - 'fail_limit' => 3 - ] ]; } - /** - * List all Node Allocations - * - * Returns a listing of all allocations for every node. - * - * @Get("/nodes/allocations") - * @Versions({"v1"}) - * @Response(200) - */ + /** + * List all Node Allocations. + * + * Returns a listing of all allocations for every node. + * + * @Get("/nodes/allocations") + * @Versions({"v1"}) + * @Response(200) + */ public function allocations(Request $request) { $allocations = Models\Allocation::all(); if ($allocations->count() < 1) { throw new NotFoundHttpException('No allocations have been created.'); } + return $allocations; } + /** + * List Node Allocation based on assigned to ID. + * + * Returns a listing of the allocation for the specified server id. + * + * @Get("/nodes/allocations/{id}") + * @Versions({"v1"}) + * @Response(200) + */ + public function allocationsView(Request $request, $id) + { + $query = Models\Allocation::where('assigned_to', $id)->get(); + try { + if (empty($query)) { + throw new NotFoundHttpException('No allocations for that server were found.'); + } + + return $query; + } catch (NotFoundHttpException $ex) { + throw $ex; + } catch (\Exception $ex) { + throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); + } + } + /** - * Delete Node + * Delete Node. * * @Delete("/nodes/{id}") * @Versions({"v1"}) @@ -242,12 +267,12 @@ class NodeController extends BaseController try { $node = new NodeRepository; $node->delete($id); + return $this->response->noContent(); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); - } catch(\Exception $e) { + } catch (\Exception $e) { throw new ServiceUnavailableHttpException('An error occured while attempting to delete this node.'); } } - } diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API/ServerController.php index 2b9f0986c..b24cdac62 100755 --- a/app/Http/Controllers/API/ServerController.php +++ b/app/Http/Controllers/API/ServerController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -namespace Pterodactyl\Http\Controllers\API; -use Illuminate\Http\Request; +namespace Pterodactyl\Http\Controllers\API; use Log; use Pterodactyl\Models; -use Pterodactyl\Transformers\ServerTransformer; -use Pterodactyl\Repositories\ServerRepository; - -use Pterodactyl\Exceptions\DisplayValidationException; -use Pterodactyl\Exceptions\DisplayException; +use Illuminate\Http\Request; use Dingo\Api\Exception\ResourceException; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\ServerRepository; +use Pterodactyl\Exceptions\DisplayValidationException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; @@ -42,14 +40,13 @@ use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; */ class ServerController extends BaseController { - public function __construct() { // } /** - * List All Servers + * List All Servers. * * Lists all servers currently on the system. * @@ -60,24 +57,25 @@ class ServerController extends BaseController * }) * @Response(200) */ - public function list(Request $request) + public function lists(Request $request) { return Models\Server::all()->toArray(); } /** - * Create Server - * - * @Post("/servers") - * @Versions({"v1"}) - * @Response(201) + * Create Server. + * + * @Post("/servers") + * @Versions({"v1"}) + * @Response(201) */ public function create(Request $request) { try { $server = new ServerRepository; $new = $server->create($request->all()); - return [ 'id' => $new ]; + + return ['id' => $new]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { @@ -89,7 +87,7 @@ class ServerController extends BaseController } /** - * List Specific Server + * List Specific Server. * * Lists specific fields about a server or all fields pertaining to that server. * @@ -105,16 +103,16 @@ class ServerController extends BaseController { $query = Models\Server::where('id', $id); - if (!is_null($request->input('fields'))) { - foreach(explode(',', $request->input('fields')) as $field) { - if (!empty($field)) { + if (! is_null($request->input('fields'))) { + foreach (explode(',', $request->input('fields')) as $field) { + if (! empty($field)) { $query->addSelect($field); } } } try { - if (!$query->first()) { + if (! $query->first()) { throw new NotFoundHttpException('No server by that ID was found.'); } @@ -126,8 +124,8 @@ class ServerController extends BaseController $response = $client->request('GET', '/servers', [ 'headers' => [ - 'X-Access-Token' => $node->daemonSecret - ] + 'X-Access-Token' => $node->daemonSecret, + ], ]); // Only return the daemon token if the request is using HTTPS @@ -140,14 +138,14 @@ class ServerController extends BaseController } return $server->toArray(); - } catch (NotFoundHttpException $ex) { throw $ex; } catch (\GuzzleHttp\Exception\TransferException $ex) { // Couldn't hit the daemon, return what we have though. $server->daemon = [ - 'error' => 'There was an error encountered while attempting to connect to the remote daemon.' + 'error' => 'There was an error encountered while attempting to connect to the remote daemon.', ]; + return $server->toArray(); } catch (\Exception $ex) { throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); @@ -155,7 +153,7 @@ class ServerController extends BaseController } /** - * Update Server configuration + * Update Server configuration. * * Updates display information on panel. * @@ -179,6 +177,7 @@ class ServerController extends BaseController try { $server = new ServerRepository; $server->updateDetails($id, $request->all()); + return Models\Server::findOrFail($id); } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); @@ -190,7 +189,7 @@ class ServerController extends BaseController } /** - * Update Server Build Configuration + * Update Server Build Configuration. * * Updates server build information on panel and on node. * @@ -221,10 +220,9 @@ class ServerController extends BaseController public function build(Request $request, $id) { try { - throw new BadRequestHttpException('There was an error while attempting to add this node to the system.'); - $server = new ServerRepository; $server->changeBuild($id, $request->all()); + return Models\Server::findOrFail($id); } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); @@ -236,7 +234,7 @@ class ServerController extends BaseController } /** - * Suspend Server + * Suspend Server. * * @Post("/servers/{id}/suspend") * @Versions({"v1"}) @@ -250,6 +248,7 @@ class ServerController extends BaseController try { $server = new ServerRepository; $server->suspend($id); + return $this->response->noContent(); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); @@ -259,7 +258,7 @@ class ServerController extends BaseController } /** - * Unsuspend Server + * Unsuspend Server. * * @Post("/servers/{id}/unsuspend") * @Versions({"v1"}) @@ -273,6 +272,7 @@ class ServerController extends BaseController try { $server = new ServerRepository; $server->unsuspend($id); + return $this->response->noContent(); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); @@ -282,7 +282,7 @@ class ServerController extends BaseController } /** - * Delete Server + * Delete Server. * * @Delete("/servers/{id}/{force}") * @Versions({"v1"}) @@ -297,12 +297,12 @@ class ServerController extends BaseController try { $server = new ServerRepository; $server->deleteServer($id, $force); + return $this->response->noContent(); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); - } catch(\Exception $e) { + } catch (\Exception $e) { throw new ServiceUnavailableHttpException('An error occured while attempting to delete this server.'); } } - } diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index 5a60990e6..aa8b4ac29 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API; -use Illuminate\Http\Request; - use Pterodactyl\Models; -use Pterodactyl\Transformers\ServiceTransformer; - +use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -35,13 +33,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; */ class ServiceController extends BaseController { - public function __construct() { // } - public function list(Request $request) + public function lists(Request $request) { return Models\Service::all()->toArray(); } @@ -49,20 +46,16 @@ class ServiceController extends BaseController public function view(Request $request, $id) { $service = Models\Service::find($id); - if (!$service) { + if (! $service) { throw new NotFoundHttpException('No service by that ID was found.'); } - $options = Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image')->where('parent_service', $service->id)->get(); - foreach($options as &$opt) { - $opt->variables = Models\ServiceVariables::where('option_id', $opt->id)->get(); - } - return [ 'service' => $service, - 'options' => $options + 'options' => Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image') + ->where('parent_service', $service->id) + ->with('variables') + ->get(), ]; - } - } diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 2e2e3a03b..00923b866 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,38 +21,31 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API\User; -use Auth; -use Dingo; use Pterodactyl\Models; use Illuminate\Http\Request; - use Pterodactyl\Http\Controllers\API\BaseController; class InfoController extends BaseController { public function me(Request $request) { - $servers = Models\Server::getUserServers(); - $response = []; - - foreach($servers as &$server) { - $response = array_merge($response, [[ + return Models\Server::getUserServers()->map(function ($server) { + return [ 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, 'node' => $server->nodeName, 'ip' => [ 'set' => $server->ip, - 'alias' => $server->ip_alias + 'alias' => $server->ip_alias, ], 'port' => $server->port, 'service' => $server->a_serviceName, - 'option' => $server->a_serviceOptionName - ]]); - } - - return $response; + 'option' => $server->a_serviceOptionName, + ]; + })->all(); } } diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 613f90582..c63a482fa 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API\User; -use Auth; use Log; +use Auth; use Pterodactyl\Models; use Illuminate\Http\Request; - use Pterodactyl\Http\Controllers\API\BaseController; class ServerController extends BaseController { - public function info(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); @@ -43,28 +42,29 @@ class ServerController extends BaseController $response = $client->request('GET', '/server', [ 'headers' => [ 'X-Access-Token' => $server->daemonSecret, - 'X-Access-Server' => $server->uuid - ] + 'X-Access-Server' => $server->uuid, + ], ]); $json = json_decode($response->getBody()); $daemon = [ 'status' => $json->status, 'stats' => $json->proc, - 'query' => $json->query + 'query' => $json->query, ]; } catch (\Exception $ex) { $daemon = [ - 'error' => 'An error was encountered while trying to connect to the daemon to collece information. It might be offline.' + 'error' => 'An error was encountered while trying to connect to the daemon to collece information. It might be offline.', ]; Log::error($ex); } $allocations = Models\Allocation::select('id', 'ip', 'port', 'ip_alias as alias')->where('assigned_to', $server->id)->get(); - foreach($allocations as &$allocation) { + foreach ($allocations as &$allocation) { $allocation->default = ($allocation->id === $server->allocation); unset($allocation->id); } + return [ 'uuidShort' => $server->uuidShort, 'uuid' => $server->uuid, @@ -76,23 +76,22 @@ class ServerController extends BaseController 'disk' => $server->disk, 'io' => $server->io, 'cpu' => $server->cpu, - 'oom_disabled' => (bool) $server->oom_disabled + 'oom_disabled' => (bool) $server->oom_disabled, ], 'allocations' => $allocations, 'sftp' => [ - 'username' => (Auth::user()->can('view-sftp', $server)) ? $server->username : null + 'username' => (Auth::user()->can('view-sftp', $server)) ? $server->username : null, ], 'daemon' => [ 'token' => ($request->secure()) ? $server->daemonSecret : false, - 'response' => $daemon - ] + 'response' => $daemon, + ], ]; } public function power(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); - $node = Models\Node::getByID($server->node); $client = Models\Node::guzzleRequest($server->node); Auth::user()->can('power-' . $request->input('action'), $server); @@ -100,12 +99,12 @@ class ServerController extends BaseController $res = $client->request('PUT', '/server/power', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $server->daemonSecret + 'X-Access-Token' => $server->daemonSecret, ], 'exceptions' => false, 'json' => [ - 'action' => $request->input('action') - ] + 'action' => $request->input('action'), + ], ]); if ($res->getStatusCode() !== 204) { diff --git a/app/Http/Controllers/API/UserController.php b/app/Http/Controllers/API/UserController.php index 564f69215..a330ef61c 100755 --- a/app/Http/Controllers/API/UserController.php +++ b/app/Http/Controllers/API/UserController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\API; -use Illuminate\Http\Request; - -use Dingo\Api\Exception\ResourceException; - use Pterodactyl\Models; -use Pterodactyl\Transformers\UserTransformer; -use Pterodactyl\Repositories\UserRepository; - -use Pterodactyl\Exceptions\DisplayValidationException; +use Illuminate\Http\Request; +use Dingo\Api\Exception\ResourceException; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\UserRepository; +use Pterodactyl\Exceptions\DisplayValidationException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; @@ -42,14 +39,12 @@ use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; */ class UserController extends BaseController { - public function __construct() { - } /** - * List All Users + * List All Users. * * Lists all users currently on the system. * @@ -60,13 +55,13 @@ class UserController extends BaseController * }) * @Response(200) */ - public function list(Request $request) + public function lists(Request $request) { return Models\User::all()->toArray(); } /** - * List Specific User + * List Specific User. * * Lists specific fields about a user or all fields pertaining to that user. * @@ -80,24 +75,24 @@ class UserController extends BaseController */ public function view(Request $request, $id) { - $query = Models\User::where('id', $id); + $query = Models\User::where((is_numeric($id) ? 'id' : 'email'), $id); - if (!is_null($request->input('fields'))) { - foreach(explode(',', $request->input('fields')) as $field) { - if (!empty($field)) { + if (! is_null($request->input('fields'))) { + foreach (explode(',', $request->input('fields')) as $field) { + if (! empty($field)) { $query->addSelect($field); } } } try { - if (!$query->first()) { + if (! $query->first()) { throw new NotFoundHttpException('No user by that ID was found.'); } $user = $query->first(); $userArray = $user->toArray(); - $userArray['servers'] = Models\Server::select('id', 'uuid', 'node', 'suspended')->where('owner', $user->id)->get(); + $userArray['servers'] = Models\Server::select('id', 'uuid', 'node', 'suspended')->where('owner', $user->id)->get(); return $userArray; } catch (NotFoundHttpException $ex) { @@ -105,11 +100,10 @@ class UserController extends BaseController } catch (\Exception $ex) { throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); } - } /** - * Create a New User + * Create a New User. * * @Post("/users") * @Versions({"v1"}) @@ -128,8 +122,12 @@ class UserController extends BaseController { try { $user = new UserRepository; + $create = $user->create($request->only([ + 'email', 'username', 'name_first', 'name_last', 'password', 'root_admin', 'custom_id', + ])); $create = $user->create($request->input('email'), $request->input('password'), $request->input('admin'), $request->input('custom_id')); - return [ 'id' => $create ]; + + return ['id' => $create]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { @@ -140,7 +138,7 @@ class UserController extends BaseController } /** - * Update an Existing User + * Update an Existing User. * * The data sent in the request will be used to update the existing user on the system. * @@ -161,7 +159,10 @@ class UserController extends BaseController { try { $user = new UserRepository; - $user->update($id, $request->all()); + $user->update($id, $request->only([ + 'username', 'email', 'name_first', 'name_last', 'password', 'root_admin', 'language', + ])); + return Models\User::findOrFail($id); } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); @@ -173,7 +174,7 @@ class UserController extends BaseController } /** - * Delete a User + * Delete a User. * * @Delete("/users/{id}") * @Versions({"v1"}) @@ -191,6 +192,7 @@ class UserController extends BaseController try { $user = new UserRepository; $user->delete($id); + return $this->response->noContent(); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); @@ -198,5 +200,4 @@ class UserController extends BaseController throw new ServiceUnavailableHttpException('Unable to delete this user due to an error.'); } } - } diff --git a/app/Http/Controllers/Admin/BaseController.php b/app/Http/Controllers/Admin/BaseController.php index f44ac06f4..0f54a8ee6 100644 --- a/app/Http/Controllers/Admin/BaseController.php +++ b/app/Http/Controllers/Admin/BaseController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,20 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; use Alert; use Settings; use Validator; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; class BaseController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -57,7 +56,7 @@ class BaseController extends Controller 'company' => 'required|between:1,256', 'default_language' => 'required|alpha_dash|min:2|max:5', 'email_from' => 'required|email', - 'email_sender_name' => 'required|between:1,256' + 'email_sender_name' => 'required|between:1,256', ]); if ($validator->fails()) { @@ -70,8 +69,7 @@ class BaseController extends Controller Settings::set('email_sender_name', $request->input('email_sender_name')); Alert::success('Settings have been successfully updated.')->flash(); + return redirect()->route('admin.settings'); - } - } diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index e30278f81..4a7fc3631 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,25 +21,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; -use Alert; use DB; use Log; - +use Alert; use Pterodactyl\Models; -use Pterodactyl\Repositories\DatabaseRepository; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\DatabaseRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class DatabaseController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -63,7 +61,7 @@ class DatabaseController extends Controller 'nodes.name as a_linkedNode', DB::raw('(SELECT COUNT(*) FROM `databases` WHERE `databases`.`db_server` = database_servers.id) as c_databases') )->leftJoin('nodes', 'nodes.id', '=', 'database_servers.linked_node') - ->paginate(20) + ->paginate(20), ]); } @@ -72,7 +70,7 @@ class DatabaseController extends Controller return view('admin.databases.new', [ 'nodes' => Models\Node::select('nodes.id', 'nodes.name', 'locations.long as a_location') ->join('locations', 'locations.id', '=', 'nodes.location') - ->get() + ->get(), ]); } @@ -81,12 +79,13 @@ class DatabaseController extends Controller try { $repo = new DatabaseRepository; $repo->add($request->except([ - '_token' + '_token', ])); Alert::success('Successfully added a new database server to the system.')->flash(); + return redirect()->route('admin.databases', [ - 'tab' => 'tab_dbservers' + 'tab' => 'tab_dbservers', ]); } catch (DisplayValidationException $ex) { return redirect()->route('admin.databases.new')->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -97,6 +96,7 @@ class DatabaseController extends Controller Log::error($ex); Alert::danger('An error occurred while attempting to delete this database server from the system.')->flash(); } + return redirect()->route('admin.databases.new')->withInput(); } } @@ -108,8 +108,9 @@ class DatabaseController extends Controller $repo->drop($id); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ - 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database from the system.' + 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database from the system.', ], 500); } } @@ -121,10 +122,10 @@ class DatabaseController extends Controller $repo->delete($id); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ - 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database server from the system.' + 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database server from the system.', ], 500); } } - } diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index 86f32c8e6..889123b43 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,23 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; use DB; use Alert; - use Pterodactyl\Models; -use Pterodactyl\Repositories\LocationRepository; -use Pterodactyl\Http\Controllers\Controller; - -use Pterodactyl\Exceptions\DisplayValidationException; -use Pterodactyl\Exceptions\DisplayException; - use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\LocationRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class LocationsController extends Controller { - public function __construct() { // @@ -50,7 +47,7 @@ class LocationsController extends Controller 'locations.*', DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') - )->paginate(20) + )->paginate(20), ]); } @@ -62,19 +59,20 @@ class LocationsController extends Controller DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') )->where('id', $id)->first(); - if (!$model) { + if (! $model) { return response()->json([ - 'error' => 'No location with that ID exists on the system.' + 'error' => 'No location with that ID exists on the system.', ], 404); } if ($model->a_nodeCount > 0 || $model->a_serverCount > 0) { return response()->json([ - 'error' => 'You cannot remove a location that is currently assigned to a node or server.' + 'error' => 'You cannot remove a location that is currently assigned to a node or server.', ], 422); } $model->delete(); + return response('', 204); } @@ -83,10 +81,11 @@ class LocationsController extends Controller try { $location = new LocationRepository; $location->edit($id, $request->all()); + return response('', 204); } catch (DisplayValidationException $ex) { return response()->json([ - 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 10 characters with no spaces or special characters.' + 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 10 characters with no spaces or special characters.', ], 422); } catch (\Exception $ex) { // This gets caught and processed into JSON anyways. @@ -99,9 +98,10 @@ class LocationsController extends Controller try { $location = new LocationRepository; $id = $location->create($request->except([ - '_token' + '_token', ])); Alert::success('New location successfully added.')->flash(); + return redirect()->route('admin.locations'); } catch (DisplayValidationException $ex) { return redirect()->route('admin.locations')->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -111,7 +111,7 @@ class LocationsController extends Controller Log::error($ex); Alert::danger('An unhandled exception occured while attempting to add this location. Please try again.')->flash(); } + return redirect()->route('admin.locations')->withInput(); } - } diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 24ac37614..594365f73 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,27 +21,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; -use Alert; -use Debugbar; -use Log; use DB; +use Log; +use Alert; +use Carbon; use Validator; - use Pterodactyl\Models; -use Pterodactyl\Repositories\NodeRepository; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\NodeRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class NodesController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -50,7 +48,7 @@ class NodesController extends Controller public function getScript(Request $request, $id) { - return response()->view('admin.nodes.remote.deploy', [ 'node' => Models\Node::findOrFail($id) ])->header('Content-Type', 'text/plain'); + return response()->view('admin.nodes.remote.deploy', ['node' => Models\Node::findOrFail($id)])->header('Content-Type', 'text/plain'); } public function getIndex(Request $request) @@ -66,13 +64,14 @@ class NodesController extends Controller public function getNew(Request $request) { - if (!Models\Location::all()->count()) { + if (! Models\Location::all()->count()) { Alert::warning('You must add a location before you can add a new node.')->flash(); + return redirect()->route('admin.locations'); } return view('admin.nodes.new', [ - 'locations' => Models\Location::all() + 'locations' => Models\Location::all(), ]); } @@ -81,12 +80,14 @@ class NodesController extends Controller try { $node = new NodeRepository; $new = $node->create($request->except([ - '_token' + '_token', ])); Alert::success('Successfully created new node. Before you can add any servers you need to first assign some IP addresses and ports.')->flash(); + Alert::info('To simplify the node setup you can generate a token on the configuration tab.')->flash(); + return redirect()->route('admin.nodes.view', [ 'id' => $new, - 'tab' => 'tab_allocation' + 'tab' => 'tab_allocation', ]); } catch (DisplayValidationException $e) { return redirect()->route('admin.nodes.new')->withErrors(json_decode($e->getMessage()))->withInput(); @@ -96,6 +97,7 @@ class NodesController extends Controller Log::error($e); Alert::danger('An unhandled exception occured while attempting to add this node. Please try again.')->flash(); } + return redirect()->route('admin.nodes.new')->withInput(); } @@ -129,12 +131,13 @@ class NodesController extends Controller try { $node = new NodeRepository; $node->update($id, $request->except([ - '_token' + '_token', ])); Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); + return redirect()->route('admin.nodes.view', [ 'id' => $id, - 'tab' => 'tab_settings' + 'tab' => 'tab_settings', ]); } catch (DisplayValidationException $e) { return redirect()->route('admin.nodes.view', $id)->withErrors(json_decode($e->getMessage()))->withInput(); @@ -144,9 +147,10 @@ class NodesController extends Controller Log::error($e); Alert::danger('An unhandled exception occured while attempting to edit this node. Please try again.')->flash(); } + return redirect()->route('admin.nodes.view', [ 'id' => $id, - 'tab' => 'tab_settings' + 'tab' => 'tab_settings', ])->withInput(); } @@ -155,9 +159,10 @@ class NodesController extends Controller $query = Models\Allocation::where('node', $node)->whereNull('assigned_to')->where('id', $allocation)->delete(); if ((int) $query === 0) { return response()->json([ - 'error' => 'Unable to find an allocation matching those details to delete.' + 'error' => 'Unable to find an allocation matching those details to delete.', ], 400); } + return response('', 204); } @@ -166,21 +171,23 @@ class NodesController extends Controller $query = Models\Allocation::where('node', $node)->whereNull('assigned_to')->where('ip', $request->input('ip'))->delete(); if ((int) $query === 0) { Alert::danger('There was an error while attempting to delete allocations on that IP.')->flash(); + return redirect()->route('admin.nodes.view', [ 'id' => $node, - 'tab' => 'tab_allocations' + 'tab' => 'tab_allocations', ]); } Alert::success('Deleted all unallocated ports for ' . $request->input('ip') . '.')->flash(); + return redirect()->route('admin.nodes.view', [ 'id' => $node, - 'tab' => 'tab_allocation' + 'tab' => 'tab_allocation', ]); } public function setAlias(Request $request, $node) { - if (!$request->input('allocation')) { + if (! $request->input('allocation')) { return response('Missing required parameters.', 422); } @@ -198,36 +205,36 @@ class NodesController extends Controller public function getAllocationsJson(Request $request, $id) { $allocations = Models\Allocation::select('ip')->where('node', $id)->groupBy('ip')->get(); + return response()->json($allocations); } public function postAllocations(Request $request, $id) { - $validator = Validator::make($request->all(), [ 'allocate_ip.*' => 'required|string', - 'allocate_port.*' => 'required' + 'allocate_port.*' => 'required', ]); if ($validator->fails()) { return redirect()->route('admin.nodes.view', [ 'id' => $id, - 'tab' => 'tab_allocation' + 'tab' => 'tab_allocation', ])->withErrors($validator->errors())->withInput(); } $processedData = []; - foreach($request->input('allocate_ip') as $ip) { - if (!array_key_exists($ip, $processedData)) { + foreach ($request->input('allocate_ip') as $ip) { + if (! array_key_exists($ip, $processedData)) { $processedData[$ip] = []; } } - foreach($request->input('allocate_port') as $portid => $ports) { + foreach ($request->input('allocate_port') as $portid => $ports) { if (array_key_exists($portid, $request->input('allocate_ip'))) { $json = json_decode($ports); - if (json_last_error() === 0 && !empty($json)) { - foreach($json as &$parsed) { + if (json_last_error() === 0 && ! empty($json)) { + foreach ($json as &$parsed) { array_push($processedData[$request->input('allocate_ip')[$portid]], $parsed->value); } } @@ -246,27 +253,49 @@ class NodesController extends Controller } finally { return redirect()->route('admin.nodes.view', [ 'id' => $id, - 'tab' => 'tab_allocation' + 'tab' => 'tab_allocation', ]); } } public function deleteNode(Request $request, $id) { - $node = Models\Node::findOrFail($id); - $servers = Models\Server::where('node', $id)->count(); - if ($servers > 0) { - Alert::danger('You cannot delete a node with servers currently attached to it.')->flash(); - return redirect()->route('admin.nodes.view', [ - 'id' => $id, - 'tab' => 'tab_delete' - ]); + try { + $repo = new NodeRepository; + $repo->delete($id); + Alert::success('Successfully deleted the requested node from the panel.')->flash(); + + return redirect()->route('admin.nodes'); + } catch (DisplayException $e) { + Alert::danger($e->getMessage())->flash(); + } catch (\Exception $e) { + Log::error($e); + Alert::danger('An unhandled exception occured while attempting to delete this node. Please try again.')->flash(); } - $node->delete(); - Alert::success('Node successfully deleted.')->flash(); - return redirect()->route('admin.nodes'); - + return redirect()->route('admin.nodes.view', [ + 'id' => $id, + 'tab' => 'tab_delete', + ]); } + public function getConfigurationToken(Request $request, $id) + { + // Check if Node exists. Will lead to 404 if not. + Models\Node::findOrFail($id); + + // Create a token + $token = new Models\NodeConfigurationToken(); + $token->node = $id; + $token->token = str_random(32); + $token->expires_at = Carbon::now()->addMinutes(5); // Expire in 5 Minutes + $token->save(); + + $token_response = [ + 'token' => $token->token, + 'expires_at' => $token->expires_at->toDateTimeString(), + ]; + + return response()->json($token_response, 200); + } } diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php new file mode 100644 index 000000000..628cd54b8 --- /dev/null +++ b/app/Http/Controllers/Admin/PackController.php @@ -0,0 +1,244 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Http\Controllers\Admin; + +use DB; +use Log; +use Alert; +use Storage; +use Pterodactyl\Models; +use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\ServiceRepository\Pack; +use Pterodactyl\Exceptions\DisplayValidationException; + +class PackController extends Controller +{ + public function __construct() + { + // + } + + protected function formatServices() + { + $options = Models\ServiceOptions::select( + 'services.name AS p_service', + 'service_options.id', + 'service_options.name' + )->join('services', 'services.id', '=', 'service_options.parent_service')->get(); + + $array = []; + foreach ($options as &$option) { + if (! array_key_exists($option->p_service, $array)) { + $array[$option->p_service] = []; + } + + $array[$option->p_service] = array_merge($array[$option->p_service], [[ + 'id' => $option->id, + 'name' => $option->name, + ]]); + } + + return $array; + } + + public function listAll(Request $request) + { + return view('admin.services.packs.index', [ + 'services' => Models\Service::all(), + ]); + } + + public function listByOption(Request $request, $id) + { + $option = Models\ServiceOptions::findOrFail($id); + + return view('admin.services.packs.byoption', [ + 'packs' => Models\ServicePack::where('option', $option->id)->get(), + 'service' => Models\Service::findOrFail($option->parent_service), + 'option' => $option, + ]); + } + + public function listByService(Request $request, $id) + { + return view('admin.services.packs.byservice', [ + 'service' => Models\Service::findOrFail($id), + 'options' => Models\ServiceOptions::select( + 'service_options.id', + 'service_options.name', + DB::raw('(SELECT COUNT(id) FROM service_packs WHERE service_packs.option = service_options.id) AS p_count') + )->where('parent_service', $id)->get(), + ]); + } + + public function new(Request $request, $opt = null) + { + return view('admin.services.packs.new', [ + 'services' => $this->formatServices(), + 'packFor' => $opt, + ]); + } + + public function create(Request $request) + { + try { + $repo = new Pack; + $id = $repo->create($request->except([ + '_token', + ])); + Alert::success('Successfully created new service!')->flash(); + + return redirect()->route('admin.services.packs.edit', $id)->withInput(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.packs.new', $request->input('option'))->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add a new service pack.')->flash(); + } + + return redirect()->route('admin.services.packs.new', $request->input('option'))->withInput(); + } + + public function edit(Request $request, $id) + { + $pack = Models\ServicePack::findOrFail($id); + $option = Models\ServiceOptions::select('id', 'parent_service', 'name')->where('id', $pack->option)->first(); + + return view('admin.services.packs.edit', [ + 'pack' => $pack, + 'services' => $this->formatServices(), + 'files' => Storage::files('packs/' . $pack->uuid), + 'service' => Models\Service::findOrFail($option->parent_service), + 'option' => $option, + ]); + } + + public function update(Request $request, $id) + { + if (! is_null($request->input('action_delete'))) { + try { + $repo = new Pack; + $repo->delete($id); + Alert::success('The requested service pack has been deleted from the system.')->flash(); + + return redirect()->route('admin.services.packs'); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to delete this pack.')->flash(); + } + + return redirect()->route('admin.services.packs.edit', $id); + } else { + try { + $repo = new Pack; + $repo->update($id, $request->except([ + '_token', + ])); + Alert::success('Service pack has been successfully updated.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.packs.edit', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add edit this pack.')->flash(); + } + + return redirect()->route('admin.services.packs.edit', $id); + } + } + + public function export(Request $request, $id, $files = false) + { + $pack = Models\ServicePack::findOrFail($id); + $json = [ + 'name' => $pack->name, + 'version' => $pack->version, + 'description' => $pack->dscription, + 'selectable' => (bool) $pack->selectable, + 'visible' => (bool) $pack->visible, + ]; + + $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); + if ((bool) $files) { + $zip = new \ZipArchive; + if (! $zip->open($filename, \ZipArchive::CREATE)) { + abort(503, 'Unable to open file for writing.'); + } + + $files = Storage::files('packs/' . $pack->uuid); + foreach ($files as $file) { + $zip->addFile(storage_path('app/' . $file), basename(storage_path('app/' . $file))); + } + + $zip->addFromString('import.json', json_encode($json, JSON_PRETTY_PRINT)); + $zip->close(); + + return response()->download($filename, 'pack-' . $pack->name . '.zip')->deleteFileAfterSend(true); + } else { + $fp = fopen($filename, 'a+'); + fwrite($fp, json_encode($json, JSON_PRETTY_PRINT)); + fclose($fp); + + return response()->download($filename, 'pack-' . $pack->name . '.json', [ + 'Content-Type' => 'application/json', + ])->deleteFileAfterSend(true); + } + } + + public function uploadForm(Request $request, $for = null) + { + return view('admin.services.packs.upload', [ + 'services' => $this->formatServices(), + 'for' => $for, + ]); + } + + public function postUpload(Request $request) + { + try { + $repo = new Pack; + $id = $repo->createWithTemplate($request->except([ + '_token', + ])); + Alert::success('Successfully created new service!')->flash(); + + return redirect()->route('admin.services.packs.edit', $id)->withInput(); + } catch (DisplayValidationException $ex) { + return redirect()->back()->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add a new service pack.')->flash(); + } + + return redirect()->back(); + } +} diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 8f0b184c6..9aece9c4e 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,28 +21,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; -use Alert; -use Debugbar; use DB; use Log; - +use Alert; use Pterodactyl\Models; +use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\ServerRepository; use Pterodactyl\Repositories\DatabaseRepository; - -use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; -use Pterodactyl\Http\Controllers\Controller; -use Illuminate\Http\Request; - class ServersController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -62,20 +58,29 @@ class ServersController extends Controller ->join('users', 'servers.owner', '=', 'users.id') ->join('allocations', 'servers.allocation', '=', 'allocations.id'); - if ($request->input('filter') && !is_null($request->input('filter'))) { + if ($request->input('filter') && ! is_null($request->input('filter'))) { preg_match_all('/[^\s"\']+|"([^"]*)"|\'([^\']*)\'/', urldecode($request->input('filter')), $matches); - foreach($matches[0] as $match) { + foreach ($matches[0] as $match) { $match = str_replace('"', '', $match); if (strpos($match, ':')) { list($field, $term) = explode(':', $match); - $field = (strpos($field, '.')) ? $field : 'servers.' . $field; + if ($field === 'node') { + $field = 'nodes.name'; + } elseif ($field === 'owner') { + $field = 'users.email'; + } elseif (! strpos($field, '.')) { + $field = 'servers.' . $field; + } + $query->orWhere($field, 'LIKE', '%' . $term . '%'); } else { $query->where('servers.name', 'LIKE', '%' . $match . '%'); - $query->orWhere('servers.username', 'LIKE', '%' . $match . '%'); - $query->orWhere('users.email', 'LIKE', '%' . $match . '%'); - $query->orWhere('allocations.port', 'LIKE', '%' . $match . '%'); - $query->orWhere('allocations.ip', 'LIKE', '%' . $match . '%'); + $query->orWhere([ + ['servers.username', 'LIKE', '%' . $match . '%'], + ['users.email', 'LIKE', '%' . $match . '%'], + ['allocations.port', 'LIKE', '%' . $match . '%'], + ['allocations.ip', 'LIKE', '%' . $match . '%'], + ]); } } } @@ -98,7 +103,7 @@ class ServersController extends Controller } return view('admin.servers.index', [ - 'servers' => $servers + 'servers' => $servers, ]); } @@ -106,7 +111,7 @@ class ServersController extends Controller { return view('admin.servers.new', [ 'locations' => Models\Location::all(), - 'services' => Models\Service::all() + 'services' => Models\Service::all(), ]); } @@ -114,9 +119,7 @@ class ServersController extends Controller { $server = Models\Server::withTrashed()->select( 'servers.*', - 'nodes.name as a_nodeName', 'users.email as a_ownerEmail', - 'locations.long as a_locationName', 'services.name as a_serviceName', DB::raw('IFNULL(service_options.executable, services.executable) as a_serviceExecutable'), 'service_options.docker_image', @@ -126,19 +129,24 @@ class ServersController extends Controller 'allocations.ip_alias' )->join('nodes', 'servers.node', '=', 'nodes.id') ->join('users', 'servers.owner', '=', 'users.id') - ->join('locations', 'nodes.location', '=', 'locations.id') ->join('services', 'servers.service', '=', 'services.id') ->join('service_options', 'servers.option', '=', 'service_options.id') ->join('allocations', 'servers.allocation', '=', 'allocations.id') ->where('servers.id', $id) ->first(); - if (!$server) { + if (! $server) { return abort(404); } return view('admin.servers.view', [ 'server' => $server, + 'node' => Models\Node::select( + 'nodes.*', + 'locations.long as a_locationName' + )->join('locations', 'nodes.location', '=', 'locations.id') + ->where('nodes.id', $server->node) + ->first(), 'assigned' => Models\Allocation::where('assigned_to', $id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), 'unassigned' => Models\Allocation::where('node', $server->node)->whereNull('assigned_to')->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), 'startup' => Models\ServiceVariables::select('service_variables.*', 'server_variables.variable_value as a_serverValue') @@ -150,28 +158,29 @@ class ServersController extends Controller ->where('server_id', $server->id) ->join('database_servers', 'database_servers.id', '=', 'databases.db_server') ->get(), - 'db_servers' => Models\DatabaseServer::all() + 'db_servers' => Models\DatabaseServer::all(), ]); } public function postNewServer(Request $request) { - try { $server = new ServerRepository; $response = $server->create($request->all()); - return redirect()->route('admin.servers.view', [ 'id' => $response ]); + + return redirect()->route('admin.servers.view', ['id' => $response]); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + return redirect()->route('admin.servers.new')->withInput(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to add this server. Please try again.')->flash(); + return redirect()->route('admin.servers.new')->withInput(); } - } /** @@ -182,15 +191,13 @@ class ServersController extends Controller */ public function postNewServerGetNodes(Request $request) { - - if(!$request->input('location')) { + if (! $request->input('location')) { return response()->json([ - 'error' => 'Missing location in request.' + 'error' => 'Missing location in request.', ], 500); } return response()->json(Models\Node::select('id', 'name', 'public')->where('location', $request->input('location'))->get()); - } /** @@ -201,25 +208,24 @@ class ServersController extends Controller */ public function postNewServerGetIps(Request $request) { - - if(!$request->input('node')) { + if (! $request->input('node')) { return response()->json([ - 'error' => 'Missing node in request.' + 'error' => 'Missing node in request.', ], 500); } $ips = Models\Allocation::where('node', $request->input('node'))->whereNull('assigned_to')->get(); $listing = []; - foreach($ips as &$ip) { + foreach ($ips as &$ip) { if (array_key_exists($ip->ip, $listing)) { $listing[$ip->ip] = array_merge($listing[$ip->ip], [$ip->port]); } else { $listing[$ip->ip] = [$ip->port]; } } - return response()->json($listing); + return response()->json($listing); } /** @@ -230,16 +236,15 @@ class ServersController extends Controller */ public function postNewServerServiceOptions(Request $request) { - - if(!$request->input('service')) { + if (! $request->input('service')) { return response()->json([ - 'error' => 'Missing service in request.' + 'error' => 'Missing service in request.', ], 500); } $service = Models\Service::select('executable', 'startup')->where('id', $request->input('service'))->first(); - return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get()); + return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get()); } /** @@ -248,12 +253,11 @@ class ServersController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Contracts\View\View */ - public function postNewServerServiceVariables(Request $request) + public function postNewServerOptionDetails(Request $request) { - - if(!$request->input('option')) { + if (! $request->input('option')) { return response()->json([ - 'error' => 'Missing option in request.' + 'error' => 'Missing option in request.', ], 500); } @@ -265,30 +269,28 @@ class ServersController extends Controller ->first(); return response()->json([ + 'packs' => Models\ServicePack::select('id', 'name', 'version')->where('option', $request->input('option'))->where('selectable', true)->get(), 'variables' => Models\ServiceVariables::where('option_id', $request->input('option'))->get(), 'exec' => $option->executable, - 'startup' => $option->startup + 'startup' => $option->startup, ]); - } public function postUpdateServerDetails(Request $request, $id) { - try { - $server = new ServerRepository; $server->updateDetails($id, [ 'owner' => $request->input('owner'), 'name' => $request->input('name'), - 'reset_token' => ($request->input('reset_token', false) === 'on') ? true : false + 'reset_token' => ($request->input('reset_token', false) === 'on') ? true : false, ]); Alert::success('Server details were successfully updated.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_details' + 'tab' => 'tab_details', ])->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -299,21 +301,22 @@ class ServersController extends Controller return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_details' + 'tab' => 'tab_details', ])->withInput(); } - public function postUpdateContainerDetails(Request $request, $id) { + public function postUpdateContainerDetails(Request $request, $id) + { try { $server = new ServerRepository; $server->updateContainer($id, [ - 'image' => $request->input('docker_image') + 'image' => $request->input('docker_image'), ]); Alert::success('Successfully updated this server\'s docker image.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_details' + 'tab' => 'tab_details', ])->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -324,11 +327,12 @@ class ServersController extends Controller return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_details' + 'tab' => 'tab_details', ]); } - public function postUpdateServerToggleBuild(Request $request, $id) { + public function postUpdateServerToggleBuild(Request $request, $id) + { $server = Models\Server::findOrFail($id); $node = Models\Node::findOrFail($server->node); $client = Models\Node::guzzleRequest($server->node); @@ -337,8 +341,8 @@ class ServersController extends Controller $res = $client->request('POST', '/server/rebuild', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret - ] + 'X-Access-Token' => $node->daemonSecret, + ], ]); Alert::success('A rebuild has been queued successfully. It will run the next time this server is booted.')->flash(); } catch (\GuzzleHttp\Exception\TransferException $ex) { @@ -348,14 +352,13 @@ class ServersController extends Controller return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_manage' + 'tab' => 'tab_manage', ]); } public function postUpdateServerUpdateBuild(Request $request, $id) { try { - $server = new ServerRepository; $server->changeBuild($id, [ 'default' => $request->input('default'), @@ -370,13 +373,14 @@ class ServersController extends Controller } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_build' + 'tab' => 'tab_build', ])->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_build' + 'tab' => 'tab_build', ]); } catch (\Exception $ex) { Log::error($ex); @@ -385,7 +389,7 @@ class ServersController extends Controller return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_build' + 'tab' => 'tab_build', ]); } @@ -395,16 +399,18 @@ class ServersController extends Controller $server = new ServerRepository; $server->deleteServer($id, $force); Alert::success('Server has been marked for deletion on the system.')->flash(); + return redirect()->route('admin.servers'); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); - } catch(\Exception $ex) { + } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to delete this server. Please try again.')->flash(); } + return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_delete' + 'tab' => 'tab_delete', ]); } @@ -416,13 +422,13 @@ class ServersController extends Controller Alert::success('Server status was successfully toggled.')->flash(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); - } catch(\Exception $ex) { + } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to toggle this servers status.')->flash(); } finally { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_manage' + 'tab' => 'tab_manage', ]); } } @@ -432,18 +438,18 @@ class ServersController extends Controller try { $server = new ServerRepository; $server->updateStartup($id, $request->except([ - '_token' + '_token', ]), true); Alert::success('Server startup variables were successfully updated.')->flash(); } catch (\Pterodactyl\Exceptions\DisplayException $e) { Alert::danger($e->getMessage())->flash(); - } catch(\Exception $e) { + } catch (\Exception $e) { Log::error($e); Alert::danger('An unhandled exception occured while attemping to update startup variables for this server. Please try again.')->flash(); } finally { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_startup' + 'tab' => 'tab_startup', ])->withInput(); } } @@ -453,13 +459,13 @@ class ServersController extends Controller try { $repo = new DatabaseRepository; $repo->create($id, $request->except([ - '_token' + '_token', ])); Alert::success('Added new database to this server.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_database' + 'tab' => 'tab_database', ])->withInput()->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (\Exception $ex) { Log::error($ex); @@ -468,7 +474,7 @@ class ServersController extends Controller return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_database' + 'tab' => 'tab_database', ])->withInput(); } @@ -480,13 +486,13 @@ class ServersController extends Controller Alert::success('Server has been suspended on the system. All running processes have been stopped and will not be startable until it is un-suspended.'); } catch (DisplayException $e) { Alert::danger($e->getMessage())->flash(); - } catch(\Exception $e) { + } catch (\Exception $e) { Log::error($e); Alert::danger('An unhandled exception occured while attemping to suspend this server. Please try again.')->flash(); } finally { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_manage' + 'tab' => 'tab_manage', ]); } } @@ -499,13 +505,13 @@ class ServersController extends Controller Alert::success('Server has been unsuspended on the system. Access has been re-enabled.'); } catch (DisplayException $e) { Alert::danger($e->getMessage())->flash(); - } catch(\Exception $e) { + } catch (\Exception $e) { Log::error($e); Alert::danger('An unhandled exception occured while attemping to unsuspend this server. Please try again.')->flash(); } finally { return redirect()->route('admin.servers.view', [ 'id' => $id, - 'tab' => 'tab_manage' + 'tab' => 'tab_manage', ]); } } @@ -514,27 +520,31 @@ class ServersController extends Controller { try { $repo = new ServerRepository; - if (!is_null($request->input('cancel'))) { + if (! is_null($request->input('cancel'))) { $repo->cancelDeletion($id); Alert::success('Server deletion has been cancelled. This server will remain suspended until you unsuspend it.')->flash(); + return redirect()->route('admin.servers.view', $id); - } else if(!is_null($request->input('delete'))) { + } elseif (! is_null($request->input('delete'))) { $repo->deleteNow($id); Alert::success('Server was successfully deleted from the system.')->flash(); + return redirect()->route('admin.servers'); - } else if(!is_null($request->input('force_delete'))) { + } elseif (! is_null($request->input('force_delete'))) { $repo->deleteNow($id, true); Alert::success('Server was successfully force deleted from the system.')->flash(); + return redirect()->route('admin.servers'); } } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + return redirect()->route('admin.servers.view', $id); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled error occured while attempting to perform this action.')->flash(); + return redirect()->route('admin.servers.view', $id); } } - } diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index dc5977470..7a70c58da 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,24 +21,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; -use Alert; use DB; use Log; -use Validator; - +use Alert; +use Storage; use Pterodactyl\Models; -use Pterodactyl\Repositories\ServiceRepository; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\ServiceRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class ServiceController extends Controller { - public function __construct() { // @@ -50,7 +48,7 @@ class ServiceController extends Controller 'services' => Models\Service::select( 'services.*', DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.service = services.id) as c_servers') - )->get() + )->get(), ]); } @@ -64,9 +62,10 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Service; $id = $repo->create($request->except([ - '_token' + '_token', ])); Alert::success('Successfully created new service!')->flash(); + return redirect()->route('admin.services.service', $id); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.new')->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -76,6 +75,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occured while attempting to add a new service.')->flash(); } + return redirect()->route('admin.services.new')->withInput(); } @@ -86,7 +86,7 @@ class ServiceController extends Controller 'options' => Models\ServiceOptions::select( 'service_options.*', DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.option = service_options.id) as c_servers') - )->where('parent_service', $service)->get() + )->where('parent_service', $service)->get(), ]); } @@ -95,7 +95,7 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Service; $repo->update($service, $request->except([ - '_token' + '_token', ])); Alert::success('Successfully updated this service.')->flash(); } catch (DisplayValidationException $ex) { @@ -106,6 +106,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occurred while attempting to update this service.')->flash(); } + return redirect()->route('admin.services.service', $service)->withInput(); } @@ -115,6 +116,7 @@ class ServiceController extends Controller $repo = new ServiceRepository\Service; $repo->delete($service); Alert::success('Successfully deleted that service.')->flash(); + return redirect()->route('admin.services'); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -122,12 +124,14 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error was encountered while attempting to delete that service.')->flash(); } + return redirect()->route('admin.services.service', $service); } public function getOption(Request $request, $service, $option) { $opt = Models\ServiceOptions::findOrFail($option); + return view('admin.services.options.view', [ 'service' => Models\Service::findOrFail($opt->parent_service), 'option' => $opt, @@ -135,7 +139,7 @@ class ServiceController extends Controller 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail') ->join('users', 'users.id', '=', 'servers.owner') ->where('option', $option) - ->paginate(10) + ->paginate(10), ]); } @@ -144,7 +148,7 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Option; $repo->update($option, $request->except([ - '_token' + '_token', ])); Alert::success('Option settings successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -153,6 +157,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occured while attempting to modify this option.')->flash(); } + return redirect()->route('admin.services.option', [$service, $option])->withInput(); } @@ -164,6 +169,7 @@ class ServiceController extends Controller $repo->delete($option); Alert::success('Successfully deleted that option.')->flash(); + return redirect()->route('admin.services.service', $service->parent_service); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -171,6 +177,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error was encountered while attempting to delete this option.')->flash(); } + return redirect()->route('admin.services.option', [$service, $option]); } @@ -184,18 +191,19 @@ class ServiceController extends Controller $data = [ 'user_viewable' => '0', 'user_editable' => '0', - 'required' => '0' + 'required' => '0', ]; - foreach($request->except(['_token']) as $id => $val) { - $data[str_replace($variable.'_', '', $id)] = $val; + foreach ($request->except(['_token']) as $id => $val) { + $data[str_replace($variable . '_', '', $id)] = $val; } $repo->update($variable, $data); Alert::success('Successfully updated variable.')->flash(); } catch (DisplayValidationException $ex) { $data = []; - foreach(json_decode($ex->getMessage(), true) as $id => $val) { - $data[$variable.'_'.$id] = $val; + foreach (json_decode($ex->getMessage(), true) as $id => $val) { + $data[$variable . '_' . $id] = $val; } + return redirect()->route('admin.services.option', [$service, $option])->withErrors((object) $data)->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -203,6 +211,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occurred while attempting to update this service.')->flash(); } + return redirect()->route('admin.services.option', [$service, $option])->withInput(); } @@ -210,7 +219,7 @@ class ServiceController extends Controller { return view('admin.services.options.variable', [ 'service' => Models\Service::findOrFail($service), - 'option' => Models\ServiceOptions::where('parent_service', $service)->where('id', $option)->firstOrFail() + 'option' => Models\ServiceOptions::where('parent_service', $service)->where('id', $option)->firstOrFail(), ]); } @@ -219,10 +228,11 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Variable; $repo->create($option, $request->except([ - '_token' + '_token', ])); Alert::success('Successfully added new variable to this option.')->flash(); - return redirect()->route('admin.services.option', [$service, $option])->withInput(); + + return redirect()->route('admin.services.option', [$service, $option]); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.option.variable.new', [$service, $option])->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -231,6 +241,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occurred while attempting to add this variable.')->flash(); } + return redirect()->route('admin.services.option.variable.new', [$service, $option])->withInput(); } @@ -246,9 +257,10 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Option; $id = $repo->create($service, $request->except([ - '_token' + '_token', ])); Alert::success('Successfully created new service option.')->flash(); + return redirect()->route('admin.services.option', [$service, $id]); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.option.new', $service)->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -256,6 +268,7 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occured while attempting to add this service option.')->flash(); } + return redirect()->route('admin.services.option.new', $service)->withInput(); } @@ -271,7 +284,42 @@ class ServiceController extends Controller Log::error($ex); Alert::danger('An error occured while attempting to delete that variable.')->flash(); } + return redirect()->route('admin.services.option', [$service, $option]); } + public function getConfiguration(Request $request, $serviceId) + { + $service = Models\Service::findOrFail($serviceId); + + return view('admin.services.config', [ + 'service' => $service, + 'contents' => [ + 'json' => Storage::get('services/' . $service->file . '/main.json'), + 'index' => Storage::get('services/' . $service->file . '/index.js'), + ], + ]); + } + + public function postConfiguration(Request $request, $serviceId) + { + try { + $repo = new ServiceRepository\Service; + $repo->updateFile($serviceId, $request->except([ + '_token', + ])); + + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 503); + } catch (\Exception $ex) { + Log::error($ex); + + return response()->json([ + 'error' => 'An error occured while attempting to save the file.', + ], 503); + } + } } diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 18ec6f1a1..9a2c6fd04 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,27 +22,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Admin; -use Alert; -use Settings; -use Mail; use Log; -use Pterodactyl\Models\User; -use Pterodactyl\Repositories\UserRepository; -use Pterodactyl\Models\Server; - -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - -use Pterodactyl\Http\Controllers\Controller; +use Alert; use Illuminate\Http\Request; +use Pterodactyl\Models\User; +use Pterodactyl\Models\Server; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\UserRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class UserController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -51,8 +47,33 @@ class UserController extends Controller public function getIndex(Request $request) { + $query = User::select('users.*'); + if ($request->input('filter') && ! is_null($request->input('filter'))) { + preg_match_all('/[^\s"\']+|"([^"]*)"|\'([^\']*)\'/', urldecode($request->input('filter')), $matches); + foreach ($matches[0] as $match) { + $match = str_replace('"', '', $match); + if (strpos($match, ':')) { + list($field, $term) = explode(':', $match); + $query->orWhere($field, 'LIKE', '%' . $term . '%'); + } else { + $query->where('email', 'LIKE', '%' . $match . '%'); + $query->orWhere([ + ['uuid', 'LIKE', '%' . $match . '%'], + ['root_admin', 'LIKE', '%' . $match . '%'], + ]); + } + } + } + + try { + $users = $query->paginate(20); + } catch (\Exception $ex) { + Alert::warning('There was an error with the search parameters provided.'); + $users = User::all()->paginate(20); + } + return view('admin.users.index', [ - 'users' => User::paginate(20) + 'users' => $users, ]); } @@ -79,13 +100,15 @@ class UserController extends Controller $repo = new UserRepository; $repo->delete($id); Alert::success('Successfully deleted user from system.')->flash(); + return redirect()->route('admin.users'); - } catch(DisplayException $ex) { + } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An exception was encountered while attempting to delete this user.')->flash(); } + return redirect()->route('admin.users.view', $id); } @@ -93,33 +116,39 @@ class UserController extends Controller { try { $user = new UserRepository; - $userid = $user->create($request->input('email'), $request->input('password')); + $userid = $user->create($request->only([ + 'email', + 'password', + 'name_first', + 'name_last', + 'username', + 'root_admin', + ])); Alert::success('Account has been successfully created.')->flash(); + return redirect()->route('admin.users.view', $userid); } catch (DisplayValidationException $ex) { return redirect()->route('admin.users.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An error occured while attempting to add a new user.')->flash(); + return redirect()->route('admin.users.new'); } } public function updateUser(Request $request, $user) { - $data = [ - 'email' => $request->input('email'), - 'root_admin' => $request->input('root_admin'), - 'password_confirmation' => $request->input('password_confirmation'), - ]; - - if ($request->input('password')) { - $data['password'] = $request->input('password'); - } - try { $repo = new UserRepository; - $repo->update($user, $data); + $repo->update($user, $request->only([ + 'email', + 'password', + 'name_first', + 'name_last', + 'username', + 'root_admin', + ])); Alert::success('User account was successfully updated.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.users.view', $user)->withErrors(json_decode($ex->getMessage())); @@ -127,15 +156,16 @@ class UserController extends Controller Log::error($e); Alert::danger('An error occured while attempting to update this user.')->flash(); } + return redirect()->route('admin.users.view', $user); } public function getJson(Request $request) { - foreach(User::select('email')->get() as $user) { + foreach (User::select('email')->get() as $user) { $resp[] = $user->email; } + return $resp; } - } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 197e69592..9890077f1 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,20 +22,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -namespace Pterodactyl\Http\Controllers\Auth; -use Pterodactyl\Models\User; +namespace Pterodactyl\Http\Controllers\Auth; use Auth; use Alert; -use Validator; - -use Pterodactyl\Http\Controllers\Controller; -use PragmaRX\Google2FA\Google2FA; use Illuminate\Http\Request; -use Illuminate\Foundation\Auth\ThrottlesLogins; -use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; - +use Pterodactyl\Models\User; +use PragmaRX\Google2FA\Google2FA; +use Pterodactyl\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; class LoginController extends Controller @@ -62,14 +57,14 @@ class LoginController extends Controller /** * Lockout time for failed login requests. * - * @var integer + * @var int */ protected $lockoutTime = 120; /** * After how many attempts should logins be throttled and locked. * - * @var integer + * @var int */ protected $maxLoginAttempts = 3; @@ -91,7 +86,6 @@ class LoginController extends Controller */ public function login(Request $request) { - $this->validate($request, [ 'email' => 'required|email', 'password' => 'required', @@ -99,44 +93,40 @@ class LoginController extends Controller if ($lockedOut = $this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); + return $this->sendLockoutResponse($request); } // Is the email & password valid? - if (!Auth::attempt([ + if (! Auth::once([ 'email' => $request->input('email'), - 'password' => $request->input('password') + 'password' => $request->input('password'), ], $request->has('remember'))) { - - if (!$lockedOut) { + if (! $lockedOut) { $this->incrementLoginAttempts($request); } return $this->sendFailedLoginResponse($request); - } - $G2FA = new Google2FA(); - $user = User::select('use_totp', 'totp_secret')->where('email', $request->input('email'))->first(); - // Verify TOTP Token was Valid - if($user->use_totp === 1) { - if(!$G2FA->verifyKey($user->totp_secret, $request->input('totp_token'))) { - - Auth::logout(); - - if (!$lockedOut) { + if (Auth::user()->use_totp === 1) { + $G2FA = new Google2FA(); + if (is_null($request->input('totp_token')) || ! $G2FA->verifyKey(Auth::user()->totp_secret, $request->input('totp_token'))) { + if (! $lockedOut) { $this->incrementLoginAttempts($request); } Alert::danger(trans('auth.totp_failed'))->flash(); - return $this->sendFailedLoginResponse($request); + return $this->sendFailedLoginResponse($request); } } - return $this->sendLoginResponse($request); + // Successfully Authenticated. + Auth::login(Auth::user(), $request->has('remember')); + return $this->sendLoginResponse($request); } /** @@ -149,5 +139,4 @@ class LoginController extends Controller { return response()->json(User::select('id')->where('email', $request->input('email'))->where('use_totp', 1)->first()); } - } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index e2663825a..d28692293 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -2,8 +2,8 @@ namespace Pterodactyl\Http\Controllers\Auth; -use Pterodactyl\User; use Validator; +use Pterodactyl\User; use Pterodactyl\Http\Controllers\Controller; use Illuminate\Foundation\Auth\RegistersUsers; diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index e9989ec83..fca008051 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -33,8 +33,8 @@ class ResetPasswordController extends Controller $this->middleware('guest'); } - - protected function rules() { + protected function rules() + { return [ 'token' => 'required', 'email' => 'required|email', 'password' => 'required|confirmed|' . User::PASSWORD_RULES, diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index da9a20d78..611638c95 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,35 +22,33 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Base; -use Alert; use Log; - +use Alert; use Pterodactyl\Models; - +use Illuminate\Http\Request; use Pterodactyl\Repositories\APIRepository; -use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; - -use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayValidationException; class APIController extends Controller { public function index(Request $request) { $keys = Models\APIKey::where('user', $request->user()->id)->get(); - foreach($keys as &$key) { + foreach ($keys as &$key) { $key->permissions = Models\APIPermission::where('key_id', $key->id)->get(); } return view('base.api.index', [ - 'keys' => $keys + 'keys' => $keys, ]); } - public function new(Request $request) + public function create(Request $request) { return view('base.api.new'); } @@ -59,8 +57,9 @@ class APIController extends Controller { try { $repo = new APIRepository($request->user()); - $secret = $repo->new($request->except(['_token'])); + $secret = $repo->create($request->except(['_token'])); Alert::success('An API Keypair has successfully been generated. The API secret for this public key is shown below and will not be shown again.

' . $secret . '')->flash(); + return redirect()->route('account.api'); } catch (DisplayValidationException $ex) { return redirect()->route('account.api.new')->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -70,6 +69,7 @@ class APIController extends Controller Log::error($ex); Alert::danger('An unhandled exception occured while attempting to add this API key.')->flash(); } + return redirect()->route('account.api.new')->withInput(); } @@ -78,10 +78,11 @@ class APIController extends Controller try { $repo = new APIRepository($request->user()); $repo->revoke($key); + return response('', 204); } catch (\Exception $ex) { return response()->json([ - 'error' => 'An error occured while attempting to remove this key.' + 'error' => 'An error occured while attempting to remove this key.', ], 503); } } diff --git a/app/Http/Controllers/Base/AccountController.php b/app/Http/Controllers/Base/AccountController.php index a58c691a8..8db513bd5 100644 --- a/app/Http/Controllers/Base/AccountController.php +++ b/app/Http/Controllers/Base/AccountController.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,15 +22,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Base; +use Log; use Alert; - -use Pterodactyl\Models\User; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Http\Controllers\Controller; - use Illuminate\Http\Request; +use Pterodactyl\Models\User; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\UserRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class AccountController extends Controller { @@ -46,64 +47,57 @@ class AccountController extends Controller } /** - * Update an account email. - * + * Update details for a users account. * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response + * @return void */ - public function email(Request $request) + public function update(Request $request) { + $data = []; - $this->validate($request, [ - 'new_email' => 'required|email', - 'password' => 'required' - ]); + // Request to update account Password + if ($request->input('do_action') === 'password') { + $this->validate($request, [ + 'current_password' => 'required', + 'new_password' => 'required|confirmed|' . User::PASSWORD_RULES, + 'new_password_confirmation' => 'required', + ]); - $user = $request->user(); + $data['password'] = $request->input('new_password'); - if (!password_verify($request->input('password'), $user->password)) { - Alert::danger('The password provided was not valid for this account.')->flash(); - return redirect()->route('account'); + // Request to update account Email + } elseif ($request->input('do_action') === 'email') { + $data['email'] = $request->input('new_email'); + + // Request to update account Identity + } elseif ($request->input('do_action') === 'identity') { + $data = $request->only(['name_first', 'name_last', 'username']); + + // Unknown, hit em with a 404 + } else { + return abort(404); } - $user->email = $request->input('new_email'); - $user->save(); + if ( + in_array($request->input('do_action'), ['email', 'password']) + && ! password_verify($request->input('password'), $request->user()->password) + ) { + Alert::danger(trans('base.account.invalid_pass'))->flash(); - Alert::success('Your email address has successfully been updated.')->flash(); - return redirect()->route('account'); - - } - - /** - * Update an account password. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - */ - public function password(Request $request) - { - - $this->validate($request, [ - 'current_password' => 'required', - 'new_password' => 'required|confirmed|different:current_password|' . User::PASSWORD_RULES, - 'new_password_confirmation' => 'required' - ]); - - $user = $request->user(); - - if (!password_verify($request->input('current_password'), $user->password)) { - Alert::danger('The password provided was not valid for this account.')->flash(); return redirect()->route('account'); } try { - $user->setPassword($request->input('new_password')); - Alert::success('Your password has successfully been updated.')->flash(); - } catch (DisplayException $e) { - Alert::danger($e->getMessage())->flash(); + $repo = new UserRepository; + $repo->update($request->user()->id, $data); + Alert::success('Your account details were successfully updated.')->flash(); + } catch (DisplayValidationException $ex) { + return redirect()->route('account')->withErrors(json_decode($ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger(trans('base.account.exception'))->flash(); } return redirect()->route('account'); - } } diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index bed1cb988..160bc67e6 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,18 +22,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Base; +use Illuminate\Http\Request; use Pterodactyl\Models\Server; use Pterodactyl\Http\Controllers\Controller; -use Illuminate\Http\Request; - class IndexController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -62,7 +61,15 @@ class IndexController extends Controller public function getPassword(Request $request, $length = 16) { $length = ($length < 8) ? 8 : $length; - return str_random($length); - } + $returnable = false; + while (! $returnable) { + $generated = str_random($length); + if (preg_match('/[A-Z]+[a-z]+[0-9]+/', $generated)) { + $returnable = true; + } + } + + return $generated; + } } diff --git a/app/Http/Controllers/Base/LanguageController.php b/app/Http/Controllers/Base/LanguageController.php index c4afc1e50..e4967ee5e 100644 --- a/app/Http/Controllers/Base/LanguageController.php +++ b/app/Http/Controllers/Base/LanguageController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,33 +21,30 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Base; use Auth; use Session; - -use Pterodactyl\Models\User; use Illuminate\Http\Request; +use Pterodactyl\Models\User; use Pterodactyl\Http\Controllers\Controller; class LanguageController extends Controller { - protected $languages = [ - 'de' => 'Danish', + 'de' => 'German', 'en' => 'English', - 'es' => 'Spanish', - 'fr' => 'French', - 'it' => 'Italian', - 'pl' => 'Polish', + 'et' => 'Estonian', + 'nb' => 'Norwegian', + 'nl' => 'Dutch', 'pt' => 'Portuguese', + 'ro' => 'Romanian', 'ru' => 'Russian', - 'se' => 'Swedish', - 'zh' => 'Chinese', ]; /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -64,7 +61,7 @@ class LanguageController extends Controller } Session::set('applocale', $language); } + return redirect()->back(); } - } diff --git a/app/Http/Controllers/Base/SecurityController.php b/app/Http/Controllers/Base/SecurityController.php index dec2f3fd1..cf8bf2dc1 100644 --- a/app/Http/Controllers/Base/SecurityController.php +++ b/app/Http/Controllers/Base/SecurityController.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,19 +22,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Base; -use Google2FA; use Alert; - +use Google2FA; +use Illuminate\Http\Request; use Pterodactyl\Models\Session; use Pterodactyl\Http\Controllers\Controller; -use Illuminate\Http\Request; - class SecurityController extends Controller { - /** * Returns Security Management Page. * @@ -44,7 +42,7 @@ class SecurityController extends Controller public function index(Request $request) { return view('base.security', [ - 'sessions' => Session::where('user_id', $request->user()->id)->get() + 'sessions' => Session::where('user_id', $request->user()->id)->get(), ]); } @@ -57,7 +55,6 @@ class SecurityController extends Controller */ public function generateTotp(Request $request) { - $user = $request->user(); $user->totp_secret = Google2FA::generateSecretKey(); @@ -69,9 +66,8 @@ class SecurityController extends Controller $user->email, $user->totp_secret ), - 'secret' => $user->totp_secret + 'secret' => $user->totp_secret, ]); - } /** @@ -82,18 +78,18 @@ class SecurityController extends Controller */ public function setTotp(Request $request) { - - if (!$request->has('token')) { - return response(null, 500); + if (! $request->has('token')) { + return response()->json([ + 'error' => 'Request is missing token parameter.', + ], 500); } $user = $request->user(); - if($user->toggleTotp($request->input('token'))) { + if ($user->toggleTotp($request->input('token'))) { return response('true'); } return response('false'); - } /** @@ -104,27 +100,27 @@ class SecurityController extends Controller */ public function disableTotp(Request $request) { - - if (!$request->has('token')) { + if (! $request->has('token')) { Alert::danger('Missing required `token` field in request.')->flash(); - return redirect()->route('account.totp'); + + return redirect()->route('account.security'); } $user = $request->user(); - if($user->toggleTotp($request->input('token'))) { + if ($user->toggleTotp($request->input('token'))) { return redirect()->route('account.security'); } Alert::danger('The TOTP token provided was invalid.')->flash(); - return redirect()->route('account.security'); + return redirect()->route('account.security'); } public function revoke(Request $request, $id) { $session = Session::where('id', $id)->where('user_id', $request->user()->id)->firstOrFail(); $session->delete(); + return redirect()->route('account.security'); } - } diff --git a/app/Http/Controllers/Daemon/PackController.php b/app/Http/Controllers/Daemon/PackController.php new file mode 100644 index 000000000..e96aa6ee5 --- /dev/null +++ b/app/Http/Controllers/Daemon/PackController.php @@ -0,0 +1,95 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Http\Controllers\Daemon; + +use Storage; +use Pterodactyl\Models; +use Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; + +class PackController extends Controller +{ + /** + * Controller Constructor. + */ + public function __construct() + { + // + } + + /** + * Pulls an install pack archive from the system. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function pull(Request $request, $uuid) + { + $pack = Models\ServicePack::where('uuid', $uuid)->first(); + + if (! $pack) { + return response()->json(['error' => 'No such pack.'], 404); + } + + if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { + return response()->json(['error' => 'There is no archive available for this pack.'], 503); + } + + return response()->download(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')); + } + + /** + * Returns the hash information for a pack. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function hash(Request $request, $uuid) + { + $pack = Models\ServicePack::where('uuid', $uuid)->first(); + + if (! $pack) { + return response()->json(['error' => 'No such pack.'], 404); + } + + if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { + return response()->json(['error' => 'There is no archive available for this pack.'], 503); + } + + return response()->json([ + 'archive.tar.gz' => sha1_file(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')), + ]); + } + + /** + * Pulls an update pack archive from the system. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function pullUpdate(Request $request) + { + } +} diff --git a/app/Http/Controllers/Daemon/ServiceController.php b/app/Http/Controllers/Daemon/ServiceController.php new file mode 100644 index 000000000..e362f0d06 --- /dev/null +++ b/app/Http/Controllers/Daemon/ServiceController.php @@ -0,0 +1,79 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Http\Controllers\Daemon; + +use Storage; +use Pterodactyl\Models; +use Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; + +class ServiceController extends Controller +{ + /** + * Controller Constructor. + */ + public function __construct() + { + // + } + + /** + * Returns a listing of all services currently on the system, + * as well as the associated files and the file hashes for + * caching purposes. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function list(Request $request) + { + $response = []; + foreach (Models\Service::all() as &$service) { + $response[$service->file] = [ + 'main.json' => sha1_file(storage_path('app/services/' . $service->file . '/main.json')), + 'index.js' => sha1_file(storage_path('app/services/' . $service->file . '/index.js')), + ]; + } + + return response()->json($response); + } + + /** + * Returns the contents of the requested file for the given service. + * + * @param \Illuminate\Http\Request $request + * @param string $service + * @param string $file + * @return \Illuminate\Http\Response + */ + public function pull(Request $request, $service, $file) + { + if (! Storage::exists('services/' . $service . '/' . $file)) { + return response()->json(['error' => 'No such file.'], 404); + } + + return response()->file(storage_path('app/services/' . $service . '/' . $file)); + } +} diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index ee1b86b4c..b0aa0983e 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,47 +21,48 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Remote; +use Carbon\Carbon; use Pterodactyl\Models; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Services\NotificationService; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Services\NotificationService; class RemoteController extends Controller { - /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { // No middleware for this route. } - public function postDownload(Request $request) { + public function postDownload(Request $request) + { $download = Models\Download::where('token', $request->input('token', '00'))->first(); - if (!$download) { + if (! $download) { return response()->json([ - 'error' => 'An invalid request token was recieved with this request.' + 'error' => 'An invalid request token was recieved with this request.', ], 403); } $download->delete(); + return response()->json([ 'path' => $download->path, - 'server' => $download->server + 'server' => $download->server, ]); } public function postInstall(Request $request) { $server = Models\Server::where('uuid', $request->input('server'))->first(); - if (!$server) { + if (! $server) { return response()->json([ - 'error' => 'No server by that ID was found on the system.' + 'error' => 'No server by that ID was found on the system.', ], 422); } @@ -71,7 +72,7 @@ class RemoteController extends Controller if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { return response()->json([ - 'error' => 'Signed HMAC was invalid.' + 'error' => 'Signed HMAC was invalid.', ], 403); } @@ -79,16 +80,16 @@ class RemoteController extends Controller $server->save(); return response()->json([ - 'message' => 'Recieved!' + 'message' => 'Recieved!', ], 200); } public function event(Request $request) { $server = Models\Server::where('uuid', $request->input('server'))->first(); - if (!$server) { + if (! $server) { return response()->json([ - 'error' => 'No server by that ID was found on the system.' + 'error' => 'No server by that ID was found on the system.', ], 422); } @@ -97,7 +98,7 @@ class RemoteController extends Controller $hmac = $request->input('signed'); if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { return response()->json([ - 'error' => 'Signed HMAC was invalid.' + 'error' => 'Signed HMAC was invalid.', ], 403); } @@ -108,4 +109,28 @@ class RemoteController extends Controller return response('', 201); } + public function getConfiguration(Request $request, $tokenString) + { + // Try to query the token and the node from the database + try { + $token = Models\NodeConfigurationToken::where('token', $tokenString)->firstOrFail(); + $node = Models\Node::findOrFail($token->node); + } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) { + return response()->json(['error' => 'token_invalid'], 403); + } + + // Check if token is expired + if ($token->expires_at->lt(Carbon::now())) { + $token->delete(); + + return response()->json(['error' => 'token_expired'], 403); + } + + // Delete the token, it's one-time use + $token->delete(); + + // Manually as getConfigurationAsJson() returns it in correct format already + return response($node->getConfigurationAsJson(), 200) + ->header('Content-Type', 'application/json'); + } } diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index f2db322ec..da4d058ac 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,24 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Server; use Log; use Pterodactyl\Models; - -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - -use Pterodactyl\Repositories; -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; - -use GuzzleHttp\Client; +use Pterodactyl\Repositories; use GuzzleHttp\Exception\RequestException; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Exceptions\DisplayValidationException; class AjaxController extends Controller { - /** * @var array */ @@ -55,7 +51,7 @@ class AjaxController extends Controller protected $directory; /** - * Controller Constructor + * Controller Constructor. */ public function __construct() { @@ -73,7 +69,7 @@ class AjaxController extends Controller { $server = Models\Server::getByUUID($uuid); - if (!$server) { + if (! $server) { return response()->json([], 404); } @@ -81,14 +77,15 @@ class AjaxController extends Controller try { $res = $client->request('GET', '/server', [ - 'headers' => Models\Server::getGuzzleHeaders($uuid) + 'headers' => Models\Server::getGuzzleHeaders($uuid), ]); - if($res->getStatusCode() === 200) { + if ($res->getStatusCode() === 200) { return response()->json(json_decode($res->getBody())); } } catch (RequestException $e) { // } + return response()->json([]); } @@ -101,13 +98,12 @@ class AjaxController extends Controller */ public function postDirectoryList(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); $this->directory = '/' . trim(urldecode($request->input('directory', '/')), '/'); $this->authorize('list-files', $server); $prevDir = [ - 'header' => ($this->directory !== '/') ? $this->directory : '' + 'header' => ($this->directory !== '/') ? $this->directory : '', ]; if ($this->directory !== '/') { $prevDir['first'] = true; @@ -116,7 +112,7 @@ class AjaxController extends Controller // Determine if we should show back links in the file browser. // This code is strange, and could probably be rewritten much better. $goBack = explode('/', trim($this->directory, '/')); - if (!empty(array_filter($goBack)) && count($goBack) >= 2) { + if (! empty(array_filter($goBack)) && count($goBack) >= 2) { $prevDir['show'] = true; array_pop($goBack); $prevDir['link'] = '/' . implode('/', $goBack); @@ -131,6 +127,7 @@ class AjaxController extends Controller return response($ex->getMessage(), 500); } catch (\Exception $ex) { Log::error($ex); + return response('An error occured while attempting to load the requested directory, please try again.', 500); } @@ -139,9 +136,8 @@ class AjaxController extends Controller 'files' => $directoryContents->files, 'folders' => $directoryContents->folders, 'editableMime' => Repositories\HelperRepository::editableFiles(), - 'directory' => $prevDir + 'directory' => $prevDir, ]); - } /** @@ -153,7 +149,6 @@ class AjaxController extends Controller */ public function postSaveFile(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); $this->authorize('save-files', $server); @@ -161,39 +156,39 @@ class AjaxController extends Controller try { $controller->saveFileContents($request->input('file'), $request->input('contents')); + return response(null, 204); } catch (DisplayException $ex) { return response($ex->getMessage(), 500); } catch (\Exception $ex) { Log::error($ex); + return response('An error occured while attempting to save this file, please try again.', 500); } - } /** - * [postSetPrimary description] + * [postSetPrimary description]. * @param Request $request * @param string $uuid * @return \Illuminate\Http\Response */ public function postSetPrimary(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); $this->authorize('set-connection', $server); if ((int) $request->input('allocation') === $server->allocation) { return response()->json([ - 'error' => 'You are already using this as your default connection.' + 'error' => 'You are already using this as your default connection.', ], 409); } try { $allocation = Models\Allocation::where('id', $request->input('allocation'))->where('assigned_to', $server->id)->first(); - if (!$allocation) { + if (! $allocation) { return response()->json([ - 'error' => 'No allocation matching your request was found in the system.' + 'error' => 'No allocation matching your request was found in the system.', ], 422); } @@ -201,6 +196,7 @@ class AjaxController extends Controller $repo->changeBuild($server->id, [ 'default' => $allocation->ip . ':' . $allocation->port, ]); + return response('The default connection for this server has been updated. Please be aware that you will need to restart your server for this change to go into effect.'); } catch (DisplayValidationException $ex) { return response()->json([ @@ -212,8 +208,9 @@ class AjaxController extends Controller ], 503); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ - 'error' => 'An unhandled exception occured while attemping to modify the default connection for this server.' + 'error' => 'An unhandled exception occured while attemping to modify the default connection for this server.', ], 503); } } @@ -225,21 +222,21 @@ class AjaxController extends Controller $this->authorize('reset-db-password', $server); try { - $repo = new Repositories\DatabaseRepository; $password = str_random(16); $repo->modifyPassword($request->input('database'), $password); + return response($password); } catch (\Pterodactyl\Exceptions\DisplayException $ex) { return response()->json([ 'error' => $ex->getMessage(), ], 503); - } catch(\Exception $ex) { + } catch (\Exception $ex) { Log::error($ex); + return response()->json([ - 'error' => 'An unhandled error occured while attempting to modify this database\'s password.' + 'error' => 'An unhandled error occured while attempting to modify this database\'s password.', ], 503); } } - } diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 810223303..593049ca1 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,30 +21,26 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Server; -use Auth; use DB; +use Log; use Uuid; use Alert; -use Log; - +use Javascript; use Pterodactyl\Models; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; -use Pterodactyl\Repositories\Daemon\FileRepository; -use Pterodactyl\Repositories\ServerRepository; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; - -use InvalidArgumentException; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\ServerRepository; +use Pterodactyl\Repositories\Daemon\FileRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class ServerController extends Controller { - /** - * Controller Constructor + * Controller Constructor. * * @return void */ @@ -53,24 +49,6 @@ class ServerController extends Controller // } - public function getJavascript(Request $request, $uuid, $folder, $file) - { - $server = Models\Server::getByUUID($uuid); - - $info = pathinfo($file); - $routeFile = str_replace('/', '.', $info['dirname']) . '.' . $info['filename']; - try { - return response()->view('server.js.' . $folder . '.' . $routeFile, [ - 'server' => $server, - 'node' => Models\Node::find($server->node) - ])->header('Content-Type', 'application/javascript'); - } catch (InvalidArgumentException $ex) { - return abort(404); - } catch (\Exception $ex) { - throw $ex; - } - } - /** * Renders server index page for specified server. * @@ -80,10 +58,20 @@ class ServerController extends Controller public function getIndex(Request $request) { $server = Models\Server::getByUUID($request->route()->server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + 'meta' => [ + 'saveFile' => route('server.files.save', $server->uuidShort), + 'csrfToken' => csrf_token(), + ], + ]); + return view('server.index', [ 'server' => $server, - 'allocations' => Models\Allocation::where('assigned_to', $server->id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), - 'node' => Models\Node::find($server->node) + 'node' => $node, ]); } @@ -93,15 +81,34 @@ class ServerController extends Controller * @param Request $request * @return \Illuminate\Contracts\View\View */ - public function getFiles(Request $request) + public function getFiles(Request $request, $uuid) { - - $server = Models\Server::getByUUID($request->route()->server); + $server = Models\Server::getByUUID($uuid); $this->authorize('list-files', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only('uuid', 'uuidShort', 'daemonSecret'), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + 'meta' => [ + 'directoryList' => route('server.files.directory-list', $server->uuidShort), + 'csrftoken' => csrf_token(), + ], + 'permissions' => [ + 'moveFiles' => $request->user()->can('move-files', $server), + 'copyFiles' => $request->user()->can('copy-files', $server), + 'compressFiles' => $request->user()->can('compress-files', $server), + 'decompressFiles' => $request->user()->can('decompress-files', $server), + 'createFiles' => $request->user()->can('create-files', $server), + 'downloadFiles' => $request->user()->can('download-files', $server), + 'deleteFiles' => $request->user()->can('delete-files', $server), + ], + ]); + return view('server.files.index', [ 'server' => $server, - 'node' => Models\Node::find($server->node) + 'node' => $node, ]); } @@ -111,16 +118,21 @@ class ServerController extends Controller * @param Request $request * @return \Illuminate\Contracts\View\View */ - public function getAddFile(Request $request) + public function getAddFile(Request $request, $uuid) { - - $server = Models\Server::getByUUID($request->route()->server); + $server = Models\Server::getByUUID($uuid); $this->authorize('add-files', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.files.add', [ 'server' => $server, - 'node' => Models\Node::find($server->node), - 'directory' => (in_array($request->get('dir'), [null, '/', ''])) ? '' : trim($request->get('dir'), '/') . '/' + 'node' => $node, + 'directory' => (in_array($request->get('dir'), [null, '/', ''])) ? '' : trim($request->get('dir'), '/') . '/', ]); } @@ -134,9 +146,9 @@ class ServerController extends Controller */ public function getEditFile(Request $request, $uuid, $file) { - $server = Models\Server::getByUUID($uuid); $this->authorize('edit-files', $server); + $node = Models\Node::find($server->node); $fileInfo = (object) pathinfo($file); $controller = new FileRepository($uuid); @@ -145,22 +157,29 @@ class ServerController extends Controller $fileContent = $controller->returnFileContents($file); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + return redirect()->route('server.files.index', $uuid); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An error occured while attempting to load the requested file for editing, please try again.')->flash(); + return redirect()->route('server.files.index', $uuid); } + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + 'stat' => $fileContent['stat'], + ]); + return view('server.files.edit', [ 'server' => $server, - 'node' => Models\Node::find($server->node), + 'node' => $node, 'file' => $file, 'stat' => $fileContent['stat'], 'contents' => $fileContent['file']->content, - 'directory' => (in_array($fileInfo->dirname, ['.', './', '/'])) ? '/' : trim($fileInfo->dirname, '/') . '/' + 'directory' => (in_array($fileInfo->dirname, ['.', './', '/'])) ? '/' : trim($fileInfo->dirname, '/') . '/', ]); - } /** @@ -173,7 +192,6 @@ class ServerController extends Controller */ public function getDownloadFile(Request $request, $uuid, $file) { - $server = Models\Server::getByUUID($uuid); $node = Models\Node::find($server->node); @@ -187,21 +205,39 @@ class ServerController extends Controller $download->save(); - return redirect( $node->scheme . '://' . $node->fqdn . ':' . $node->daemonListen . '/server/file/download/' . $download->token); - + return redirect($node->scheme . '://' . $node->fqdn . ':' . $node->daemonListen . '/server/file/download/' . $download->token); } - /** - * Renders server settings page. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\View\View - */ - public function getSettings(Request $request, $uuid) + public function getAllocation(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); + $this->authorize('view-allocation', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); + + return view('server.settings.allocation', [ + 'server' => $server, + 'allocations' => Models\Allocation::where('assigned_to', $server->id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), + 'node' => $node, + ]); + } + + public function getStartup(Request $request, $uuid) + { + $server = Models\Server::getByUUID($uuid); + $this->authorize('view-startup', $server); + $node = Models\Node::find($server->node); $allocation = Models\Allocation::findOrFail($server->allocation); + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); + $variables = Models\ServiceVariables::select( 'service_variables.*', DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_serverValue') @@ -224,17 +260,13 @@ class ServerController extends Controller ]; $processed = str_replace(array_keys($serverVariables), array_values($serverVariables), $server->startup); - foreach($variables as &$variable) { + foreach ($variables as &$variable) { $replace = ($variable->user_viewable === 1) ? $variable->a_serverValue : '**'; $processed = str_replace('{{' . $variable->env_variable . '}}', $replace, $processed); } - return view('server.settings', [ + return view('server.settings.startup', [ 'server' => $server, - 'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port') - ->where('server_id', $server->id) - ->join('database_servers', 'database_servers.id', '=', 'databases.db_server') - ->get(), 'node' => Models\Node::find($server->node), 'variables' => $variables->where('user_viewable', 1), 'service' => $service, @@ -242,6 +274,44 @@ class ServerController extends Controller ]); } + public function getDatabases(Request $request, $uuid) + { + $server = Models\Server::getByUUID($uuid); + $this->authorize('view-databases', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); + + return view('server.settings.databases', [ + 'server' => $server, + 'node' => $node, + 'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port') + ->where('server_id', $server->id) + ->join('database_servers', 'database_servers.id', '=', 'databases.db_server') + ->get(), + ]); + } + + public function getSFTP(Request $request, $uuid) + { + $server = Models\Server::getByUUID($uuid); + $this->authorize('view-sftp', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); + + return view('server.settings.sftp', [ + 'server' => $server, + 'node' => $node, + ]); + } + public function postSettingsSFTP(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); @@ -252,14 +322,15 @@ class ServerController extends Controller $repo->updateSFTPPassword($server->id, $request->input('sftp_pass')); Alert::success('Successfully updated this servers SFTP password.')->flash(); } catch (DisplayValidationException $ex) { - return redirect()->route('server.settings', $uuid)->withErrors(json_decode($ex->getMessage())); + return redirect()->route('server.settings.sftp', $uuid)->withErrors(json_decode($ex->getMessage())); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unknown error occured while attempting to update this server\'s SFTP settings.')->flash(); } - return redirect()->route('server.settings', $uuid); + + return redirect()->route('server.settings.sftp', $uuid); } public function postSettingsStartup(Request $request, $uuid) @@ -270,19 +341,19 @@ class ServerController extends Controller try { $repo = new ServerRepository; $repo->updateStartup($server->id, $request->except([ - '_token' + '_token', ])); Alert::success('Server startup variables were successfully updated.')->flash(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); - } catch(\Exception $ex) { + } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to update startup variables for this server. Please try again.')->flash(); } + return redirect()->route('server.settings', [ 'uuid' => $uuid, - 'tab' => 'tab_startup' + 'tab' => 'tab_startup', ]); } - } diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index 963ea99a1..a8761c717 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,27 +21,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Server; use DB; +use Log; use Auth; use Alert; -use Log; - +use Javascript; use Pterodactyl\Models; -use Pterodactyl\Repositories\SubuserRepository; - -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - use Illuminate\Http\Request; +use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\SubuserRepository; +use Pterodactyl\Exceptions\DisplayValidationException; class SubuserController extends Controller { - /** - * Controller Constructor + * Controller Constructor. * * @return void */ @@ -54,29 +52,40 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('list-subusers', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.users.index', [ 'server' => $server, - 'node' => Models\Node::find($server->node), - 'subusers' => Models\Subuser::select('subusers.*', 'users.email as a_userEmail') + 'node' => $node, + 'subusers' => Models\Subuser::select('subusers.*', 'users.email', 'users.username', 'users.use_totp') ->join('users', 'users.id', '=', 'subusers.user_id') ->where('server_id', $server->id) - ->get() + ->get(), ]); - } public function getView(Request $request, $uuid, $id) { $server = Models\Server::getByUUID($uuid); $this->authorize('view-subuser', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); $subuser = Models\Subuser::select('subusers.*', 'users.email as a_userEmail') ->join('users', 'users.id', '=', 'subusers.user_id') ->where(DB::raw('md5(subusers.id)'), $id)->where('subusers.server_id', $server->id) ->first(); - if (!$subuser) { + if (! $subuser) { abort(404); } @@ -85,13 +94,13 @@ class SubuserController extends Controller ->where('user_id', $subuser->user_id)->where('server_id', $server->id) ->get(); - foreach($modelPermissions as &$perm) { + foreach ($modelPermissions as &$perm) { $permissions[$perm->permission] = true; } return view('server.users.view', [ 'server' => $server, - 'node' => Models\Node::find($server->node), + 'node' => $node, 'subuser' => $subuser, 'permissions' => $permissions, ]); @@ -99,17 +108,15 @@ class SubuserController extends Controller public function postView(Request $request, $uuid, $id) { - $server = Models\Server::getByUUID($uuid); $this->authorize('edit-subuser', $server); $subuser = Models\Subuser::where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); try { - - if (!$subuser) { + if (! $subuser) { throw new DisplayException('Unable to locate a subuser by that ID.'); - } else if ($subuser->user_id === Auth::user()->id) { + } elseif ($subuser->user_id === Auth::user()->id) { throw new DisplayException('You are not authorized to edit you own account.'); } @@ -117,14 +124,14 @@ class SubuserController extends Controller $repo->update($subuser->id, [ 'permissions' => $request->input('permissions'), 'server' => $server->id, - 'user' => $subuser->user_id + 'user' => $subuser->user_id, ]); Alert::success('Subuser permissions have successfully been updated.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('server.subusers.view', [ 'uuid' => $uuid, - 'id' => $id + 'id' => $id, ])->withErrors(json_decode($ex->getMessage())); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); @@ -132,9 +139,10 @@ class SubuserController extends Controller Log::error($ex); Alert::danger('An unknown error occured while attempting to update this subuser.')->flash(); } + return redirect()->route('server.subusers.view', [ 'uuid' => $uuid, - 'id' => $id + 'id' => $id, ]); } @@ -142,10 +150,16 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('create-subuser', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.users.new', [ 'server' => $server, - 'node' => Models\Node::find($server->node) + 'node' => $node, ]); } @@ -157,12 +171,13 @@ class SubuserController extends Controller try { $repo = new SubuserRepository; $id = $repo->create($server->id, $request->except([ - '_token' + '_token', ])); Alert::success('Successfully created new subuser.')->flash(); + return redirect()->route('server.subusers.view', [ 'uuid' => $uuid, - 'id' => md5($id) + 'id' => md5($id), ]); } catch (DisplayValidationException $ex) { return redirect()->route('server.subusers.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -172,6 +187,7 @@ class SubuserController extends Controller Log::error($ex); Alert::danger('An unknown error occured while attempting to add a new subuser.')->flash(); } + return redirect()->route('server.subusers.new', $uuid)->withInput(); } @@ -182,23 +198,23 @@ class SubuserController extends Controller try { $subuser = Models\Subuser::select('id')->where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); - if (!$subuser) { + if (! $subuser) { throw new DisplayException('No subuser by that ID was found on the system.'); } $repo = new SubuserRepository; $repo->delete($subuser->id); + return response('', 204); } catch (DisplayException $ex) { response()->json([ - 'error' => $ex->getMessage() + 'error' => $ex->getMessage(), ], 422); } catch (\Exception $ex) { Log::error($ex); response()->json([ - 'error' => 'An unknown error occured while attempting to delete this subuser.' + 'error' => 'An unknown error occured while attempting to delete this subuser.', ], 503); } } - } diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index 0ef5e7bc5..8c49ad6bc 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Controllers\Server; -use Alert; use Log; -use Cron; - -use Pterodactyl\Repositories; +use Alert; +use Javascript; use Pterodactyl\Models; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\DisplayValidationException; - -use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; +use Pterodactyl\Repositories; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Exceptions\DisplayValidationException; class TaskController extends Controller { @@ -46,15 +45,21 @@ class TaskController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('list-tasks', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.tasks.index', [ 'server' => $server, - 'node' => Models\Node::findOrFail($server->node), + 'node' => $node, 'tasks' => Models\Task::where('server', $server->id)->get(), 'actions' => [ - 'command' => 'Send Command', - 'power' => 'Set Power Status' - ] + 'command' => trans('server.tasks.actions.command'), + 'power' => trans('server.tasks.actions.power'), + ], ]); } @@ -62,10 +67,16 @@ class TaskController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('create-task', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.tasks.new', [ 'server' => $server, - 'node' => Models\Node::findOrFail($server->node) + 'node' => $node, ]); } @@ -77,30 +88,20 @@ class TaskController extends Controller try { $repo = new Repositories\TaskRepository; $repo->create($server->id, $request->except([ - '_token' + '_token', ])); + + return redirect()->route('server.tasks', $uuid); } catch (DisplayValidationException $ex) { - return redirect()->route('server.tasks', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route('server.tasks.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unknown error occured while attempting to create this task.')->flash(); } - return redirect()->route('server.tasks', $uuid); - } - - public function getView(Request $request, $uuid, $id) - { - $server = Models\Server::getByUUID($uuid); - $this->authorize('view-task', $server); - - return view('server.tasks.view', [ - 'server' => $server, - 'node' => Models\Node::findOrFail($server->node), - 'task' => Models\Task::where('id', $id)->where('server', $server->id)->firstOrFail() - ]); + return redirect()->route('server.tasks.new', $uuid); } public function deleteTask(Request $request, $uuid, $id) @@ -110,20 +111,22 @@ class TaskController extends Controller $task = Models\Task::findOrFail($id); - if (!$task || $server->id !== $task->server) { + if (! $task || $server->id !== $task->server) { return response()->json([ - 'error' => 'No task by that ID was found associated with this server.' + 'error' => 'No task by that ID was found associated with this server.', ], 404); } try { $repo = new Repositories\TaskRepository; $repo->delete($id); + return response()->json([], 204); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ - 'error' => 'A server error occured while attempting to delete this task.' + 'error' => 'A server error occured while attempting to delete this task.', ], 503); } } @@ -135,22 +138,24 @@ class TaskController extends Controller $task = Models\Task::findOrFail($id); - if (!$task || $server->id !== $task->server) { + if (! $task || $server->id !== $task->server) { return response()->json([ - 'error' => 'No task by that ID was found associated with this server.' + 'error' => 'No task by that ID was found associated with this server.', ], 404); } try { $repo = new Repositories\TaskRepository; $resp = $repo->toggle($id); + return response()->json([ - 'status' => $resp + 'status' => $resp, ]); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ - 'error' => 'A server error occured while attempting to toggle this task.' + 'error' => 'A server error occured while attempting to toggle this task.', ], 503); } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index d4c1cf1f1..971835dac 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -53,6 +53,7 @@ class Kernel extends HttpKernel 'guest' => \Pterodactyl\Http\Middleware\RedirectIfAuthenticated::class, 'server' => \Pterodactyl\Http\Middleware\CheckServer::class, 'admin' => \Pterodactyl\Http\Middleware\AdminAuthenticate::class, + 'daemon' => \Pterodactyl\Http\Middleware\DaemonAuthenticate::class, 'csrf' => \Pterodactyl\Http\Middleware\VerifyCsrfToken::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, diff --git a/app/Http/Middleware/APISecretToken.php b/app/Http/Middleware/APISecretToken.php index fab4d177d..a1c203c9d 100755 --- a/app/Http/Middleware/APISecretToken.php +++ b/app/Http/Middleware/APISecretToken.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Middleware; use Auth; @@ -28,24 +29,20 @@ use Crypt; use Config; use IPTools\IP; use IPTools\Range; - +use Dingo\Api\Routing\Route; +use Illuminate\Http\Request; +use Pterodactyl\Models\User; use Pterodactyl\Models\APIKey; use Pterodactyl\Models\APIPermission; -use Pterodactyl\Models\User; use Pterodactyl\Services\APILogService; - -use Illuminate\Http\Request; -use Dingo\Api\Routing\Route; use Dingo\Api\Auth\Provider\Authorization; - -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; // 400 -use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; // 401 +use Symfony\Component\HttpKernel\Exception\HttpException; // 400 +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; // 401 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; // 403 -use Symfony\Component\HttpKernel\Exception\HttpException; //500 +use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; //500 class APISecretToken extends Authorization { - protected $algo = 'sha256'; protected $permissionAllowed = false; @@ -64,7 +61,7 @@ class APISecretToken extends Authorization public function authenticate(Request $request, Route $route) { - if (!$request->bearerToken() || empty($request->bearerToken())) { + if (! $request->bearerToken() || empty($request->bearerToken())) { APILogService::log($request, 'The authentication header was missing or malformed.'); throw new UnauthorizedHttpException('The authentication header was missing or malformed.'); } @@ -72,22 +69,22 @@ class APISecretToken extends Authorization list($public, $hashed) = explode('.', $request->bearerToken()); $key = APIKey::where('public', $public)->first(); - if (!$key) { + if (! $key) { APILogService::log($request, 'Invalid API Key.'); throw new AccessDeniedHttpException('Invalid API Key.'); } // Check for Resource Permissions - if (!empty($request->route()->getName())) { - if(!is_null($key->allowed_ips)) { + if (! empty($request->route()->getName())) { + if (! is_null($key->allowed_ips)) { $inRange = false; - foreach(json_decode($key->allowed_ips) as $ip) { + foreach (json_decode($key->allowed_ips) as $ip) { if (Range::parse($ip)->contains(new IP($request->ip()))) { $inRange = true; break; } } - if (!$inRange) { + if (! $inRange) { APILogService::log($request, 'This IP address <' . $request->ip() . '> does not have permission to use this API key.'); throw new AccessDeniedHttpException('This IP address <' . $request->ip() . '> does not have permission to use this API key.'); } @@ -98,11 +95,11 @@ class APISecretToken extends Authorization // Suport Wildcards if (starts_with($request->route()->getName(), 'api.user')) { $permission->orWhere('permission', 'api.user.*'); - } else if(starts_with($request->route()->getName(), 'api.admin')) { + } elseif (starts_with($request->route()->getName(), 'api.admin')) { $permission->orWhere('permission', 'api.admin.*'); } - if (!$permission->first()) { + if (! $permission->first()) { APILogService::log($request, 'You do not have permission to access this resource. This API Key requires the ' . $request->route()->getName() . ' permission node.'); throw new AccessDeniedHttpException('You do not have permission to access this resource. This API Key requires the ' . $request->route()->getName() . ' permission node.'); } @@ -116,21 +113,21 @@ class APISecretToken extends Authorization } $this->url = urldecode($request->fullUrl()); - if($this->_generateHMAC($request->getContent(), $decrypted) !== base64_decode($hashed)) { + if ($this->_generateHMAC($request->getContent(), $decrypted) !== base64_decode($hashed)) { APILogService::log($request, 'The hashed body was not valid. Potential modification of contents in route.'); throw new BadRequestHttpException('The hashed body was not valid. Potential modification of contents in route.'); } // Log the Route Access APILogService::log($request, null, true); - return Auth::loginUsingId($key->user); + return Auth::loginUsingId($key->user); } protected function _generateHMAC($body, $key) { $data = $this->url . $body; + return hash_hmac($this->algo, $data, $key, true); } - } diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index e4c3f91bb..c0d74f262 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Middleware; +use Theme; use Closure; use Illuminate\Contracts\Auth\Guard; @@ -63,10 +65,13 @@ class AdminAuthenticate } } - if($this->auth->user()->root_admin !== 1) { + if ($this->auth->user()->root_admin !== 1) { return abort(403); } + // @TODO: eventually update admin themes + Theme::set('default'); + return $next($request); } } diff --git a/app/Http/Middleware/CheckServer.php b/app/Http/Middleware/CheckServer.php index 7ae0c115f..cd83bd9d1 100644 --- a/app/Http/Middleware/CheckServer.php +++ b/app/Http/Middleware/CheckServer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Middleware; -use Closure; use Auth; +use Closure; use Pterodactyl\Models\Server; -use Debugbar; class CheckServer { @@ -39,13 +39,12 @@ class CheckServer */ public function handle($request, Closure $next) { - - if (!Auth::user()) { + if (! Auth::user()) { return redirect()->guest('auth/login'); } $server = Server::getByUUID($request->route()->server); - if (!$server) { + if (! $server) { return response()->view('errors.404', [], 404); } @@ -58,6 +57,5 @@ class CheckServer } return $next($request); - } } diff --git a/app/Listeners/DeleteServerListener.php b/app/Http/Middleware/DaemonAuthenticate.php similarity index 57% rename from app/Listeners/DeleteServerListener.php rename to app/Http/Middleware/DaemonAuthenticate.php index 6a7833504..73cb029d4 100644 --- a/app/Listeners/DeleteServerListener.php +++ b/app/Http/Middleware/DaemonAuthenticate.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,44 +21,51 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -namespace Pterodactyl\Listeners; -use Carbon; +namespace Pterodactyl\Http\Middleware; -use Pterodactyl\Events\ServerDeleted; -use Illuminate\Foundation\Bus\DispatchesJobs; +use Closure; +use Pterodactyl\Models\Node; +use Illuminate\Contracts\Auth\Guard; -use Pterodactyl\Jobs\SuspendServer; -use Pterodactyl\Jobs\DeleteServer; - -class DeleteServerListener +class DaemonAuthenticate { - - use DispatchesJobs; + /** + * The Guard implementation. + * + * @var Guard + */ + protected $auth; /** - * Create the event listener. + * Create a new filter instance. * + * @param Guard $auth * @return void */ - public function __construct() + public function __construct(Guard $auth) { - // + $this->auth = $auth; } /** - * Handle the event. + * Handle an incoming request. * - * @param DeleteServerEvent $event - * @return void + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed */ - public function handle(ServerDeleted $event) + public function handle($request, Closure $next) { - $this->dispatch((new SuspendServer($event->server))->onQueue(env('QUEUE_HIGH', 'high'))); - $this->dispatch( - (new DeleteServer($event->server)) - ->delay(Carbon::now()->addMinutes(env('APP_DELETE_MINUTES', 10))) - ->onQueue(env('QUEUE_STANDARD', 'standard')) - ); + if (! $request->header('X-Access-Node')) { + return abort(403); + } + + $node = Node::where('daemonSecret', $request->header('X-Access-Node'))->first(); + if (! $node) { + return abort(404); + } + + return $next($request); } } diff --git a/app/Http/Middleware/LanguageMiddleware.php b/app/Http/Middleware/LanguageMiddleware.php index 5b52705c6..58426063f 100644 --- a/app/Http/Middleware/LanguageMiddleware.php +++ b/app/Http/Middleware/LanguageMiddleware.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Middleware; use Auth; use Closure; use Session; use Settings; - use Illuminate\Support\Facades\App; class LanguageMiddleware { - public function __construct() { // @@ -49,12 +48,13 @@ class LanguageMiddleware { if (Session::has('applocale')) { App::setLocale(Session::get('applocale')); - } else if(Auth::check() && isset(Auth::user()->language)) { + } elseif (Auth::check() && isset(Auth::user()->language)) { Session::set('applocale', Auth::user()->language); App::setLocale(Auth::user()->language); } else { App::setLocale(Settings::get('default_language', 'en')); } + return $next($request); } } diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index be7b74e42..08d960353 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -13,6 +13,7 @@ class VerifyCsrfToken extends BaseVerifier */ protected $except = [ 'remote/*', - 'api/*' + 'daemon/*', + 'api/*', ]; } diff --git a/app/Http/Routes/APIRoutes.php b/app/Http/Routes/APIRoutes.php index 33d3d7177..a4fb84c60 100755 --- a/app/Http/Routes/APIRoutes.php +++ b/app/Http/Routes/APIRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,162 +21,164 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; -use Pterodactyl\Models; use Illuminate\Routing\Router; class APIRoutes { - - public function map(Router $router) { - + public function map(Router $router) + { $api = app('Dingo\Api\Routing\Router'); $api->version('v1', ['prefix' => 'api/me', 'middleware' => 'api.auth'], function ($api) { $api->get('/', [ 'as' => 'api.user.me', - 'uses' => 'Pterodactyl\Http\Controllers\API\User\InfoController@me' + 'uses' => 'Pterodactyl\Http\Controllers\API\User\InfoController@me', ]); $api->get('/server/{uuid}', [ 'as' => 'api.user.server', - 'uses' => 'Pterodactyl\Http\Controllers\API\User\ServerController@info' + 'uses' => 'Pterodactyl\Http\Controllers\API\User\ServerController@info', ]); $api->put('/server/{uuid}', [ 'as' => 'api.user.server.power', - 'uses' => 'Pterodactyl\Http\Controllers\API\User\ServerController@power' + 'uses' => 'Pterodactyl\Http\Controllers\API\User\ServerController@power', ]); }); $api->version('v1', ['prefix' => 'api', 'middleware' => 'api.auth'], function ($api) { - /** + /* * User Routes */ $api->get('users', [ 'as' => 'api.admin.users.list', - 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@list' + 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@lists', ]); $api->post('users', [ 'as' => 'api.admin.users.create', - 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@create' + 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@create', ]); $api->get('users/{id}', [ 'as' => 'api.admin.users.view', - 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@view' + 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@view', ]); $api->patch('users/{id}', [ 'as' => 'api.admin.users.update', - 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@update' + 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@update', ]); $api->delete('users/{id}', [ 'as' => 'api.admin.users.delete', - 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@delete' + 'uses' => 'Pterodactyl\Http\Controllers\API\UserController@delete', ]); - /** + /* * Server Routes */ $api->get('servers', [ 'as' => 'api.admin.servers.list', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@list' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@lists', ]); $api->post('servers', [ 'as' => 'api.admin.servers.create', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@create' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@create', ]); $api->get('servers/{id}', [ 'as' => 'api.admin.servers.view', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@view' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@view', ]); $api->patch('servers/{id}/config', [ 'as' => 'api.admin.servers.config', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@config' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@config', ]); $api->patch('servers/{id}/build', [ 'as' => 'api.admin.servers.build', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@build' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@build', ]); $api->post('servers/{id}/suspend', [ 'as' => 'api.admin.servers.suspend', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@suspend' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@suspend', ]); $api->post('servers/{id}/unsuspend', [ 'as' => 'api.admin.servers.unsuspend', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@unsuspend' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@unsuspend', ]); $api->delete('servers/{id}/{force?}', [ 'as' => 'api.admin.servers.delete', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@delete' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServerController@delete', ]); - /** + /* * Node Routes */ $api->get('nodes', [ 'as' => 'api.admin.nodes.list', - 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@list' + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@lists', ]); $api->post('nodes', [ 'as' => 'api.admin.nodes.create', - 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@create' + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@create', ]); $api->get('nodes/allocations', [ 'as' => 'api.admin.nodes.allocations', - 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@allocations' + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@allocations', + ]); + + $api->get('nodes/allocations/{id}', [ + 'as' => 'api.admin.nodes.allocations', + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@allocationsView', ]); $api->get('nodes/{id}', [ 'as' => 'api.admin.nodes.view', - 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@view' + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@view', ]); $api->get('nodes/{id}/config', [ 'as' => 'api.admin.nodes.view', - 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@config' + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@config', ]); $api->delete('nodes/{id}', [ 'as' => 'api.admin.nodes.delete', - 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@delete' + 'uses' => 'Pterodactyl\Http\Controllers\API\NodeController@delete', ]); - /** + /* * Location Routes */ $api->get('locations', [ 'as' => 'api.admin.locations.list', - 'uses' => 'Pterodactyl\Http\Controllers\API\LocationController@list' + 'uses' => 'Pterodactyl\Http\Controllers\API\LocationController@lists', ]); - /** + /* * Service Routes */ $api->get('services', [ 'as' => 'api.admin.services.list', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServiceController@list' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServiceController@lists', ]); $api->get('services/{id}', [ 'as' => 'api.admin.services.view', - 'uses' => 'Pterodactyl\Http\Controllers\API\ServiceController@view' + 'uses' => 'Pterodactyl\Http\Controllers\API\ServiceController@view', ]); - }); } - } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index bfc07b725..e3a81cb66 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; use Illuminate\Routing\Router; -class AdminRoutes { - - public function map(Router $router) { +class AdminRoutes +{ + public function map(Router $router) + { // Admin Index $router->get('admin', [ @@ -36,9 +38,9 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' + 'csrf', ], - 'uses' => 'Admin\BaseController@getIndex' + 'uses' => 'Admin\BaseController@getIndex', ]); $router->group([ @@ -46,15 +48,15 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'admin.settings', - 'uses' => 'Admin\BaseController@getSettings' + 'uses' => 'Admin\BaseController@getSettings', ]); $router->post('/', [ - 'uses' => 'Admin\BaseController@postSettings' + 'uses' => 'Admin\BaseController@postSettings', ]); }); @@ -63,48 +65,47 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { // View All Accounts on System $router->get('/', [ 'as' => 'admin.users', - 'uses' => 'Admin\UserController@getIndex' + 'uses' => 'Admin\UserController@getIndex', ]); $router->get('/accounts.json', [ 'as' => 'admin.users.json', - 'uses' => 'Admin\UserController@getJson' + 'uses' => 'Admin\UserController@getJson', ]); // View Specific Account $router->get('/view/{id}', [ 'as' => 'admin.users.view', - 'uses' => 'Admin\UserController@getView' + 'uses' => 'Admin\UserController@getView', ]); // View Specific Account $router->post('/view/{id}', [ - 'uses' => 'Admin\UserController@updateUser' + 'uses' => 'Admin\UserController@updateUser', ]); // Delete an Account Matching an ID $router->delete('/view/{id}', [ - 'uses' => 'Admin\UserController@deleteUser' + 'uses' => 'Admin\UserController@deleteUser', ]); // Show Create Account Page $router->get('/new', [ 'as' => 'admin.users.new', - 'uses' => 'Admin\UserController@getNew' + 'uses' => 'Admin\UserController@getNew', ]); // Handle Creating New Account $router->post('/new', [ - 'uses' => 'Admin\UserController@postNew' + 'uses' => 'Admin\UserController@postNew', ]); - }); // Server Routes @@ -113,108 +114,107 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { // View All Servers $router->get('/', [ 'as' => 'admin.servers', - 'uses' => 'Admin\ServersController@getIndex' ]); + 'uses' => 'Admin\ServersController@getIndex', ]); // View Create Server Page $router->get('/new', [ 'as' => 'admin.servers.new', - 'uses' => 'Admin\ServersController@getNew' + 'uses' => 'Admin\ServersController@getNew', ]); // Handle POST Request for Creating Server $router->post('/new', [ - 'uses' => 'Admin\ServersController@postNewServer' + 'uses' => 'Admin\ServersController@postNewServer', ]); // Assorted Page Helpers $router->post('/new/get-nodes', [ - 'uses' => 'Admin\ServersController@postNewServerGetNodes' + 'uses' => 'Admin\ServersController@postNewServerGetNodes', ]); $router->post('/new/get-ips', [ - 'uses' => 'Admin\ServersController@postNewServerGetIps' + 'uses' => 'Admin\ServersController@postNewServerGetIps', ]); $router->post('/new/service-options', [ - 'uses' => 'Admin\ServersController@postNewServerServiceOptions' + 'uses' => 'Admin\ServersController@postNewServerServiceOptions', ]); - $router->post('/new/service-variables', [ - 'uses' => 'Admin\ServersController@postNewServerServiceVariables' + $router->post('/new/option-details', [ + 'uses' => 'Admin\ServersController@postNewServerOptionDetails', ]); // End Assorted Page Helpers // View Specific Server $router->get('/view/{id}', [ 'as' => 'admin.servers.view', - 'uses' => 'Admin\ServersController@getView' + 'uses' => 'Admin\ServersController@getView', ]); // Database Stuffs $router->post('/view/{id}/database', [ 'as' => 'admin.servers.database', - 'uses' => 'Admin\ServersController@postDatabase' + 'uses' => 'Admin\ServersController@postDatabase', ]); // Change Server Details $router->post('/view/{id}/details', [ - 'uses' => 'Admin\ServersController@postUpdateServerDetails' + 'uses' => 'Admin\ServersController@postUpdateServerDetails', ]); // Change Server Details $router->post('/view/{id}/container', [ 'as' => 'admin.servers.post.container', - 'uses' => 'Admin\ServersController@postUpdateContainerDetails' + 'uses' => 'Admin\ServersController@postUpdateContainerDetails', ]); // Change Server Details $router->post('/view/{id}/startup', [ 'as' => 'admin.servers.post.startup', - 'uses' => 'Admin\ServersController@postUpdateServerStartup' + 'uses' => 'Admin\ServersController@postUpdateServerStartup', ]); // Rebuild Server $router->post('/view/{id}/rebuild', [ - 'uses' => 'Admin\ServersController@postUpdateServerToggleBuild' + 'uses' => 'Admin\ServersController@postUpdateServerToggleBuild', ]); // Change Build Details $router->post('/view/{id}/build', [ - 'uses' => 'Admin\ServersController@postUpdateServerUpdateBuild' + 'uses' => 'Admin\ServersController@postUpdateServerUpdateBuild', ]); // Suspend Server $router->post('/view/{id}/suspend', [ - 'uses' => 'Admin\ServersController@postSuspendServer' + 'uses' => 'Admin\ServersController@postSuspendServer', ]); // Unsuspend Server $router->post('/view/{id}/unsuspend', [ - 'uses' => 'Admin\ServersController@postUnsuspendServer' + 'uses' => 'Admin\ServersController@postUnsuspendServer', ]); // Change Install Status $router->post('/view/{id}/installed', [ - 'uses' => 'Admin\ServersController@postToggleInstall' + 'uses' => 'Admin\ServersController@postToggleInstall', ]); // Delete [force delete] $router->delete('/view/{id}/{force?}', [ - 'uses' => 'Admin\ServersController@deleteServer' + 'uses' => 'Admin\ServersController@deleteServer', ]); $router->post('/view/{id}/queuedDeletion', [ 'uses' => 'Admin\ServersController@postQueuedDeletionHandler', - 'as' => 'admin.servers.post.queuedDeletion' + 'as' => 'admin.servers.post.queuedDeletion', ]); - }); // Node Routes @@ -223,70 +223,74 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { // View All Nodes $router->get('/', [ 'as' => 'admin.nodes', - 'uses' => 'Admin\NodesController@getIndex' + 'uses' => 'Admin\NodesController@getIndex', ]); // Add New Node $router->get('/new', [ 'as' => 'admin.nodes.new', - 'uses' => 'Admin\NodesController@getNew' + 'uses' => 'Admin\NodesController@getNew', ]); $router->post('/new', [ - 'uses' => 'Admin\NodesController@postNew' + 'uses' => 'Admin\NodesController@postNew', ]); // View Node $router->get('/view/{id}', [ 'as' => 'admin.nodes.view', - 'uses' => 'Admin\NodesController@getView' + 'uses' => 'Admin\NodesController@getView', ]); $router->post('/view/{id}', [ - 'uses' => 'Admin\NodesController@postView' + 'uses' => 'Admin\NodesController@postView', ]); $router->delete('/view/{id}/deallocate/single/{allocation}', [ - 'uses' => 'Admin\NodesController@deallocateSingle' + 'uses' => 'Admin\NodesController@deallocateSingle', ]); $router->post('/view/{id}/deallocate/block', [ - 'uses' => 'Admin\NodesController@deallocateBlock' + 'uses' => 'Admin\NodesController@deallocateBlock', ]); $router->post('/view/{id}/alias', [ 'as' => 'admin.nodes.alias', - 'uses' => 'Admin\NodesController@setAlias' + 'uses' => 'Admin\NodesController@setAlias', ]); $router->get('/view/{id}/allocations.json', [ 'as' => 'admin.nodes.view.allocations', - 'uses' => 'Admin\NodesController@getAllocationsJson' + 'uses' => 'Admin\NodesController@getAllocationsJson', ]); $router->post('/view/{id}/allocations', [ 'as' => 'admin.nodes.post.allocations', - 'uses' => 'Admin\NodesController@postAllocations' + 'uses' => 'Admin\NodesController@postAllocations', ]); // View Deploy $router->get('/view/{id}/deploy', [ 'as' => 'admin.nodes.deply', - 'uses' => 'Admin\NodesController@getScript' + 'uses' => 'Admin\NodesController@getScript', ]); $router->delete('/view/{id}', [ 'as' => 'admin.nodes.delete', - 'uses' => 'Admin\NodesController@deleteNode' + 'uses' => 'Admin\NodesController@deleteNode', ]); + $router->get('/{id}/configurationtoken', [ + 'as' => 'admin.nodes.configuration-token', + 'uses' => 'Admin\NodesController@getConfigurationToken', + ]); }); // Location Routes @@ -295,21 +299,21 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'admin.locations', - 'uses' => 'Admin\LocationsController@getIndex' + 'uses' => 'Admin\LocationsController@getIndex', ]); $router->delete('/{id}', [ - 'uses' => 'Admin\LocationsController@deleteLocation' + 'uses' => 'Admin\LocationsController@deleteLocation', ]); $router->patch('/{id}', [ - 'uses' => 'Admin\LocationsController@patchLocation' + 'uses' => 'Admin\LocationsController@patchLocation', ]); $router->post('/', [ - 'uses' => 'Admin\LocationsController@postLocation' + 'uses' => 'Admin\LocationsController@postLocation', ]); }); @@ -319,27 +323,27 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'admin.databases', - 'uses' => 'Admin\DatabaseController@getIndex' + 'uses' => 'Admin\DatabaseController@getIndex', ]); $router->get('/new', [ 'as' => 'admin.databases.new', - 'uses' => 'Admin\DatabaseController@getNew' + 'uses' => 'Admin\DatabaseController@getNew', ]); $router->post('/new', [ - 'uses' => 'Admin\DatabaseController@postNew' + 'uses' => 'Admin\DatabaseController@postNew', ]); $router->delete('/delete/{id}', [ 'as' => 'admin.databases.delete', - 'uses' => 'Admin\DatabaseController@deleteDatabase' + 'uses' => 'Admin\DatabaseController@deleteDatabase', ]); $router->delete('/delete-server/{id}', [ 'as' => 'admin.databases.delete-server', - 'uses' => 'Admin\DatabaseController@deleteServer' + 'uses' => 'Admin\DatabaseController@deleteServer', ]); }); @@ -349,78 +353,133 @@ class AdminRoutes { 'middleware' => [ 'auth', 'admin', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'admin.services', - 'uses' => 'Admin\ServiceController@getIndex' + 'uses' => 'Admin\ServiceController@getIndex', ]); $router->get('/new', [ 'as' => 'admin.services.new', - 'uses' => 'Admin\ServiceController@getNew' + 'uses' => 'Admin\ServiceController@getNew', ]); $router->post('/new', [ - 'uses' => 'Admin\ServiceController@postNew' + 'uses' => 'Admin\ServiceController@postNew', ]); $router->get('/service/{id}', [ 'as' => 'admin.services.service', - 'uses' => 'Admin\ServiceController@getService' + 'uses' => 'Admin\ServiceController@getService', ]); $router->post('/service/{id}', [ - 'uses' => 'Admin\ServiceController@postService' + 'uses' => 'Admin\ServiceController@postService', ]); $router->delete('/service/{id}', [ - 'uses' => 'Admin\ServiceController@deleteService' + 'uses' => 'Admin\ServiceController@deleteService', + ]); + + $router->get('/service/{id}/configuration', [ + 'as' => 'admin.services.service.config', + 'uses' => 'Admin\ServiceController@getConfiguration', + ]); + + $router->post('/service/{id}/configuration', [ + 'uses' => 'Admin\ServiceController@postConfiguration', ]); $router->get('/service/{service}/option/new', [ 'as' => 'admin.services.option.new', - 'uses' => 'Admin\ServiceController@newOption' + 'uses' => 'Admin\ServiceController@newOption', ]); $router->post('/service/{service}/option/new', [ - 'uses' => 'Admin\ServiceController@postNewOption' + 'uses' => 'Admin\ServiceController@postNewOption', ]); $router->get('/service/{service}/option/{option}', [ 'as' => 'admin.services.option', - 'uses' => 'Admin\ServiceController@getOption' + 'uses' => 'Admin\ServiceController@getOption', ]); $router->post('/service/{service}/option/{option}', [ - 'uses' => 'Admin\ServiceController@postOption' + 'uses' => 'Admin\ServiceController@postOption', ]); $router->delete('/service/{service}/option/{id}', [ - 'uses' => 'Admin\ServiceController@deleteOption' + 'uses' => 'Admin\ServiceController@deleteOption', ]); $router->get('/service/{service}/option/{option}/variable/new', [ 'as' => 'admin.services.option.variable.new', - 'uses' => 'Admin\ServiceController@getNewVariable' + 'uses' => 'Admin\ServiceController@getNewVariable', ]); $router->post('/service/{service}/option/{option}/variable/new', [ - 'uses' => 'Admin\ServiceController@postNewVariable' + 'uses' => 'Admin\ServiceController@postNewVariable', ]); $router->post('/service/{service}/option/{option}/variable/{variable}', [ 'as' => 'admin.services.option.variable', - 'uses' => 'Admin\ServiceController@postOptionVariable' + 'uses' => 'Admin\ServiceController@postOptionVariable', ]); $router->get('/service/{service}/option/{option}/variable/{variable}/delete', [ 'as' => 'admin.services.option.variable.delete', - 'uses' => 'Admin\ServiceController@deleteVariable' + 'uses' => 'Admin\ServiceController@deleteVariable', ]); }); + // Service Packs + $router->group([ + 'prefix' => 'admin/services/packs', + 'middleware' => [ + 'auth', + 'admin', + 'csrf', + ], + ], function () use ($router) { + $router->get('/new/{option?}', [ + 'as' => 'admin.services.packs.new', + 'uses' => 'Admin\PackController@new', + ]); + $router->post('/new', [ + 'uses' => 'Admin\PackController@create', + ]); + $router->get('/upload/{option?}', [ + 'as' => 'admin.services.packs.uploadForm', + 'uses' => 'Admin\PackController@uploadForm', + ]); + $router->post('/upload', [ + 'uses' => 'Admin\PackController@postUpload', + ]); + $router->get('/', [ + 'as' => 'admin.services.packs', + 'uses' => 'Admin\PackController@listAll', + ]); + $router->get('/for/option/{option}', [ + 'as' => 'admin.services.packs.option', + 'uses' => 'Admin\PackController@listByOption', + ]); + $router->get('/for/service/{service}', [ + 'as' => 'admin.services.packs.service', + 'uses' => 'Admin\PackController@listByService', + ]); + $router->get('/edit/{pack}', [ + 'as' => 'admin.services.packs.edit', + 'uses' => 'Admin\PackController@edit', + ]); + $router->post('/edit/{pack}', [ + 'uses' => 'Admin\PackController@update', + ]); + $router->get('/edit/{pack}/export/{archive?}', [ + 'as' => 'admin.services.packs.export', + 'uses' => 'Admin\PackController@export', + ]); + }); } - } diff --git a/app/Http/Routes/AuthRoutes.php b/app/Http/Routes/AuthRoutes.php index a447f3c5e..491bebe41 100644 --- a/app/Http/Routes/AuthRoutes.php +++ b/app/Http/Routes/AuthRoutes.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,71 +22,69 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; -use Illuminate\Routing\Router; -use Request; -use Pterodactyl\Models\User as User; - use Auth; -class AuthRoutes { +use Illuminate\Routing\Router; - public function map(Router $router) { +class AuthRoutes +{ + public function map(Router $router) + { $router->group([ 'prefix' => 'auth', 'middleware' => [ 'guest', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { // Display Login Page $router->get('login', [ 'as' => 'auth.login', - 'uses' => 'Auth\LoginController@showLoginForm' + 'uses' => 'Auth\LoginController@showLoginForm', ]); // Handle Login $router->post('login', [ - 'uses' => 'Auth\LoginController@login' + 'uses' => 'Auth\LoginController@login', ]); // Determine if we need to ask for a TOTP Token $router->post('login/totp', [ - 'uses' => 'Auth\LoginController@checkTotp' + 'uses' => 'Auth\LoginController@checkTotp', ]); // Show Password Reset Form $router->get('password', [ 'as' => 'auth.password', - 'uses' => 'Auth\ForgotPasswordController@showLinkRequestForm' + 'uses' => 'Auth\ForgotPasswordController@showLinkRequestForm', ]); // Handle Password Reset $router->post('password', [ - 'uses' => 'Auth\ForgotPasswordController@sendResetLinkEmail' + 'uses' => 'Auth\ForgotPasswordController@sendResetLinkEmail', ]); // Show Verification Checkpoint $router->get('password/reset/{token}', [ 'as' => 'auth.reset', - 'uses' => 'Auth\ResetPasswordController@showResetForm' + 'uses' => 'Auth\ResetPasswordController@showResetForm', ]); // Handle Verification $router->post('password/reset', [ - 'uses' => 'Auth\ResetPasswordController@reset' + 'as' => 'auth.reset.post', + 'uses' => 'Auth\ResetPasswordController@reset', ]); - }); // Not included above because we don't want the guest middleware $router->get('auth/logout', [ 'as' => 'auth.logout', 'middleware' => 'auth', - 'uses' => 'Auth\LoginController@logout' + 'uses' => 'Auth\LoginController@logout', ]); - } - } diff --git a/app/Http/Routes/BaseRoutes.php b/app/Http/Routes/BaseRoutes.php index 6841ea1b6..41bb93b53 100644 --- a/app/Http/Routes/BaseRoutes.php +++ b/app/Http/Routes/BaseRoutes.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,19 +22,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; use Illuminate\Routing\Router; -class BaseRoutes { - - public function map(Router $router) { +class BaseRoutes +{ + public function map(Router $router) + { // Index of Panel $router->get('/', [ 'as' => 'index', 'middleware' => 'auth', - 'uses' => 'Base\IndexController@getIndex' + 'uses' => 'Base\IndexController@getIndex', ]); // Handle Index. Redirect /index to / @@ -46,7 +48,7 @@ class BaseRoutes { $router->get('/password-gen/{length}', [ 'as' => 'password-gen', 'middleware' => 'auth', - 'uses' => 'Base\IndexController@getPassword' + 'uses' => 'Base\IndexController@getPassword', ]); // Account Routes @@ -54,18 +56,15 @@ class BaseRoutes { 'prefix' => 'account', 'middleware' => [ 'auth', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'account', - 'uses' => 'Base\AccountController@index' + 'uses' => 'Base\AccountController@index', ]); - $router->post('/password', [ - 'uses' => 'Base\AccountController@password' - ]); - $router->post('/email', [ - 'uses' => 'Base\AccountController@email' + $router->post('/', [ + 'uses' => 'Base\AccountController@update', ]); }); @@ -74,23 +73,23 @@ class BaseRoutes { 'prefix' => 'account/api', 'middleware' => [ 'auth', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'account.api', - 'uses' => 'Base\APIController@index' + 'uses' => 'Base\APIController@index', ]); $router->get('/new', [ 'as' => 'account.api.new', - 'uses' => 'Base\APIController@new' + 'uses' => 'Base\APIController@create', ]); $router->post('/new', [ - 'uses' => 'Base\APIController@save' + 'uses' => 'Base\APIController@save', ]); $router->delete('/revoke/{key}', [ - 'uses' => 'Base\APIController@revoke' + 'uses' => 'Base\APIController@revoke', ]); }); @@ -99,28 +98,27 @@ class BaseRoutes { 'prefix' => 'account/security', 'middleware' => [ 'auth', - 'csrf' - ] + 'csrf', + ], ], function () use ($router) { $router->get('/', [ 'as' => 'account.security', - 'uses' => 'Base\SecurityController@index' + 'uses' => 'Base\SecurityController@index', ]); $router->get('/revoke/{id}', [ 'as' => 'account.security.revoke', - 'uses' => 'Base\SecurityController@revoke' + 'uses' => 'Base\SecurityController@revoke', ]); $router->put('/totp', [ - 'uses' => 'Base\SecurityController@generateTotp' + 'as' => 'account.security.totp', + 'uses' => 'Base\SecurityController@generateTotp', ]); $router->post('/totp', [ - 'uses' => 'Base\SecurityController@setTotp' + 'uses' => 'Base\SecurityController@setTotp', ]); $router->delete('/totp', [ - 'uses' => 'Base\SecurityController@disableTotp' + 'uses' => 'Base\SecurityController@disableTotp', ]); }); - } - } diff --git a/app/Http/Routes/DaemonRoutes.php b/app/Http/Routes/DaemonRoutes.php new file mode 100644 index 000000000..7367fae5f --- /dev/null +++ b/app/Http/Routes/DaemonRoutes.php @@ -0,0 +1,54 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Http\Routes; + +use Illuminate\Routing\Router; + +class DaemonRoutes +{ + public function map(Router $router) + { + $router->group(['prefix' => 'daemon', 'middleware' => 'daemon'], function () use ($router) { + $router->get('services', [ + 'as' => 'daemon.services', + 'uses' => 'Daemon\ServiceController@list', + ]); + + $router->get('services/pull/{service}/{file}', [ + 'as' => 'remote.install', + 'uses' => 'Daemon\ServiceController@pull', + ]); + + $router->get('packs/pull/{uuid}', [ + 'as' => 'daemon.pack.pull', + 'uses' => 'Daemon\PackController@pull', + ]); + $router->get('packs/pull/{uuid}/hash', [ + 'as' => 'daemon.pack.hash', + 'uses' => 'Daemon\PackController@hash', + ]); + }); + } +} diff --git a/app/Http/Routes/LanguageRoutes.php b/app/Http/Routes/LanguageRoutes.php index 4989f7ca6..588711023 100644 --- a/app/Http/Routes/LanguageRoutes.php +++ b/app/Http/Routes/LanguageRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,18 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; use Illuminate\Routing\Router; -class LanguageRoutes { - +class LanguageRoutes +{ public function map(Router $router) { $router->get('language/{lang}', [ 'as' => 'langauge.set', - 'uses' => 'Base\LanguageController@setLanguage' + 'uses' => 'Base\LanguageController@setLanguage', ]); } - } diff --git a/app/Http/Routes/RemoteRoutes.php b/app/Http/Routes/RemoteRoutes.php index 802f1d923..9ece1fb2e 100644 --- a/app/Http/Routes/RemoteRoutes.php +++ b/app/Http/Routes/RemoteRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,31 +21,31 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; use Illuminate\Routing\Router; -use Request; -class RemoteRoutes { - - public function map(Router $router) { +class RemoteRoutes +{ + public function map(Router $router) + { $router->group(['prefix' => 'remote'], function () use ($router) { // Handles Remote Download Authentication Requests $router->post('download', [ 'as' => 'remote.download', - 'uses' => 'Remote\RemoteController@postDownload' + 'uses' => 'Remote\RemoteController@postDownload', ]); $router->post('install', [ 'as' => 'remote.install', - 'uses' => 'Remote\RemoteController@postInstall' + 'uses' => 'Remote\RemoteController@postInstall', ]); - $router->post('event', [ - 'as' => 'remote.event', - 'uses' => 'Remote\RemoteController@event' + $router->get('configuration/{token}', [ + 'as' => 'remote.configuration', + 'uses' => 'Remote\RemoteController@getConfiguration', ]); }); } - } diff --git a/app/Http/Routes/ServerRoutes.php b/app/Http/Routes/ServerRoutes.php index 5916287e2..079bbf449 100644 --- a/app/Http/Routes/ServerRoutes.php +++ b/app/Http/Routes/ServerRoutes.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,161 +21,170 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Http\Routes; use Illuminate\Routing\Router; -class ServerRoutes { - - public function map(Router $router) { - +class ServerRoutes +{ + public function map(Router $router) + { $router->group([ 'prefix' => 'server/{server}', 'middleware' => [ 'auth', 'server', - 'csrf' - ] + 'csrf', + ], ], function ($server) use ($router) { // Index View for Server $router->get('/', [ 'as' => 'server.index', - 'uses' => 'Server\ServerController@getIndex' + 'uses' => 'Server\ServerController@getIndex', ]); // Settings $router->get('/settings', [ 'as' => 'server.settings', - 'uses' => 'Server\ServerController@getSettings' + 'uses' => 'Server\ServerController@getSettings', + ]); + + $router->get('/settings/databases', [ + 'as' => 'server.settings.databases', + 'uses' => 'Server\ServerController@getDatabases', + ]); + + $router->get('/settings/sftp', [ + 'as' => 'server.settings.sftp', + 'uses' => 'Server\ServerController@getSFTP', ]); $router->post('/settings/sftp', [ - 'as' => 'server.settings.sftp', - 'uses' => 'Server\ServerController@postSettingsSFTP' + 'uses' => 'Server\ServerController@postSettingsSFTP', + ]); + + $router->get('/settings/startup', [ + 'as' => 'server.settings.startup', + 'uses' => 'Server\ServerController@getStartup', ]); $router->post('/settings/startup', [ - 'as' => 'server.settings.startup', - 'uses' => 'Server\ServerController@postSettingsStartup' + 'uses' => 'Server\ServerController@postSettingsStartup', + ]); + + $router->get('/settings/allocation', [ + 'as' => 'server.settings.allocation', + 'uses' => 'Server\ServerController@getAllocation', ]); // File Manager Routes $router->get('/files', [ 'as' => 'server.files.index', - 'uses' => 'Server\ServerController@getFiles' + 'uses' => 'Server\ServerController@getFiles', ]); $router->get('/files/edit/{file}', [ 'as' => 'server.files.edit', - 'uses' => 'Server\ServerController@getEditFile' + 'uses' => 'Server\ServerController@getEditFile', ])->where('file', '.*'); $router->get('/files/download/{file}', [ 'as' => 'server.files.download', - 'uses' => 'Server\ServerController@getDownloadFile' + 'uses' => 'Server\ServerController@getDownloadFile', ])->where('file', '.*'); $router->get('/files/add', [ 'as' => 'server.files.add', - 'uses' => 'Server\ServerController@getAddFile' + 'uses' => 'Server\ServerController@getAddFile', ]); $router->post('files/directory-list', [ 'as' => 'server.files.directory-list', - 'uses' => 'Server\AjaxController@postDirectoryList' + 'uses' => 'Server\AjaxController@postDirectoryList', ]); $router->post('files/save', [ 'as' => 'server.files.save', - 'uses' => 'Server\AjaxController@postSaveFile' + 'uses' => 'Server\AjaxController@postSaveFile', ]); // Sub-User Routes $router->get('users', [ 'as' => 'server.subusers', - 'uses' => 'Server\SubuserController@getIndex' + 'uses' => 'Server\SubuserController@getIndex', ]); $router->get('users/new', [ 'as' => 'server.subusers.new', - 'uses' => 'Server\SubuserController@getNew' + 'uses' => 'Server\SubuserController@getNew', ]); $router->post('users/new', [ - 'uses' => 'Server\SubuserController@postNew' + 'uses' => 'Server\SubuserController@postNew', ]); $router->get('users/view/{id}', [ 'as' => 'server.subusers.view', - 'uses' => 'Server\SubuserController@getView' + 'uses' => 'Server\SubuserController@getView', ]); $router->post('users/view/{id}', [ - 'uses' => 'Server\SubuserController@postView' + 'uses' => 'Server\SubuserController@postView', ]); $router->delete('users/delete/{id}', [ - 'uses' => 'Server\SubuserController@deleteSubuser' + 'uses' => 'Server\SubuserController@deleteSubuser', ]); $router->get('tasks/', [ 'as' => 'server.tasks', - 'uses' => 'Server\TaskController@getIndex' + 'uses' => 'Server\TaskController@getIndex', ]); $router->get('tasks/view/{id}', [ 'as' => 'server.tasks.view', - 'uses' => 'Server\TaskController@getView' + 'uses' => 'Server\TaskController@getView', ]); $router->get('tasks/new', [ 'as' => 'server.tasks.new', - 'uses' => 'Server\TaskController@getNew' + 'uses' => 'Server\TaskController@getNew', ]); $router->post('tasks/new', [ - 'uses' => 'Server\TaskController@postNew' + 'uses' => 'Server\TaskController@postNew', ]); $router->delete('tasks/delete/{id}', [ 'as' => 'server.tasks.delete', - 'uses' => 'Server\TaskController@deleteTask' + 'uses' => 'Server\TaskController@deleteTask', ]); $router->post('tasks/toggle/{id}', [ 'as' => 'server.tasks.toggle', - 'uses' => 'Server\TaskController@toggleTask' + 'uses' => 'Server\TaskController@toggleTask', ]); // Assorted AJAX Routes $router->group(['prefix' => 'ajax'], function ($server) use ($router) { // Returns Server Status $router->get('status', [ - 'uses' => 'Server\AjaxController@getStatus' + 'as' => 'server.ajax.status', + 'uses' => 'Server\AjaxController@getStatus', ]); // Sets the Default Connection for the Server $router->post('set-primary', [ - 'uses' => 'Server\AjaxController@postSetPrimary' + 'uses' => 'Server\AjaxController@postSetPrimary', ]); $router->post('settings/reset-database-password', [ 'as' => 'server.ajax.reset-database-password', - 'uses' => 'Server\AjaxController@postResetDatabasePassword' + 'uses' => 'Server\AjaxController@postResetDatabasePassword', ]); }); - - // Assorted AJAX Routes - $router->group(['prefix' => 'js'], function ($server) use ($router) { - // Returns Server Status - $router->get('{folder}/{file}', [ - 'as' => 'server.js', - 'uses' => 'Server\ServerController@getJavascript' - ])->where('file', '.*'); - - }); }); } - } diff --git a/app/Jobs/DeleteServer.php b/app/Jobs/DeleteServer.php index 78e1e1f48..a42637ff2 100644 --- a/app/Jobs/DeleteServer.php +++ b/app/Jobs/DeleteServer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Jobs; -use DB; - -use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; - -use Pterodactyl\Models; use Pterodactyl\Repositories\ServerRepository; class DeleteServer extends Job implements ShouldQueue @@ -46,7 +42,7 @@ class DeleteServer extends Job implements ShouldQueue /** * Create a new job instance. * - * @param integer $server + * @param int $server * @return void */ public function __construct($id) diff --git a/app/Jobs/SendScheduledTask.php b/app/Jobs/SendScheduledTask.php index 96d4a669a..dd7a56e27 100644 --- a/app/Jobs/SendScheduledTask.php +++ b/app/Jobs/SendScheduledTask.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Jobs; -use Pterodactyl\Jobs\Job; +use Cron; +use Carbon; +use Pterodactyl\Models; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; - -use DB; -use Carbon; -use Cron; -use Pterodactyl\Models; -use Pterodactyl\Repositories\Daemon\CommandRepository; use Pterodactyl\Repositories\Daemon\PowerRepository; +use Pterodactyl\Repositories\Daemon\CommandRepository; class SendScheduledTask extends Job implements ShouldQueue { @@ -76,7 +74,7 @@ class SendScheduledTask extends Job implements ShouldQueue if ($this->task->action === 'command') { $repo = new CommandRepository($this->server); $response = $repo->send($this->task->data); - } else if ($this->task->action === 'power') { + } elseif ($this->task->action === 'power') { $repo = new PowerRepository($this->server); $response = $repo->do($this->task->data); } @@ -84,14 +82,14 @@ class SendScheduledTask extends Job implements ShouldQueue 'task_id' => $this->task->id, 'run_time' => $time, 'run_status' => 0, - 'response' => $response + 'response' => $response, ]); } catch (\Exception $ex) { $log->fill([ 'task_id' => $this->task->id, 'run_time' => $time, 'run_status' => 1, - 'response' => $ex->getMessage() + 'response' => $ex->getMessage(), ]); } finally { $cron = Cron::factory(sprintf('%s %s %s %s %s %s', @@ -105,7 +103,7 @@ class SendScheduledTask extends Job implements ShouldQueue $this->task->fill([ 'last_run' => $time, 'next_run' => $cron->getNextRunDate(), - 'queued' => 0 + 'queued' => 0, ]); $this->task->save(); $log->save(); diff --git a/app/Jobs/SuspendServer.php b/app/Jobs/SuspendServer.php index 912f8a0a9..e4920f263 100644 --- a/app/Jobs/SuspendServer.php +++ b/app/Jobs/SuspendServer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,14 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Jobs; -use Debugbar; -use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; - use Pterodactyl\Repositories\ServerRepository; class SuspendServer extends Job implements ShouldQueue @@ -44,7 +42,7 @@ class SuspendServer extends Job implements ShouldQueue /** * Create a new job instance. * - * @param integer $id + * @param int $id * @return void */ public function __construct($id) diff --git a/app/Models/APIKey.php b/app/Models/APIKey.php index ae40b2036..4b94b6782 100644 --- a/app/Models/APIKey.php +++ b/app/Models/APIKey.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class APIKey extends Model { - /** * The table associated with the model. * @@ -48,5 +48,4 @@ class APIKey extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; - } diff --git a/app/Models/APILog.php b/app/Models/APILog.php index 41a7f8e47..5b481d8ff 100644 --- a/app/Models/APILog.php +++ b/app/Models/APILog.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class APILog extends Model { - /** * The table associated with the model. * @@ -49,13 +49,12 @@ class APILog extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ - 'authorized' => 'boolean' + 'authorized' => 'boolean', ]; - } diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php index 99c564b2a..5bed095ff 100644 --- a/app/Models/APIPermission.php +++ b/app/Models/APIPermission.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class APIPermission extends Model { - /** * The table associated with the model. * @@ -42,11 +42,11 @@ class APIPermission extends Model */ protected $guarded = ['id']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'key_id' => 'integer', ]; @@ -54,8 +54,7 @@ class APIPermission extends Model /** * Disable timestamps for this table. * - * @var boolean + * @var bool */ public $timestamps = false; - } diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 2eeff851d..10308ebdd 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Allocation extends Model { - /** * The table associated with the model. * @@ -42,15 +42,14 @@ class Allocation extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'node' => 'integer', 'port' => 'integer', 'assigned_to' => 'integer', ]; - } diff --git a/app/Models/Checksum.php b/app/Models/Checksum.php new file mode 100644 index 000000000..6db275624 --- /dev/null +++ b/app/Models/Checksum.php @@ -0,0 +1,53 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Models; + +use Illuminate\Database\Eloquent\Model; + +class Checksum extends Model +{ + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'checksums'; + + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'service' => 'integer', + ]; +} diff --git a/app/Models/Database.php b/app/Models/Database.php index c682b296e..99e768c29 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Database extends Model { - /** * The table associated with the model. * @@ -49,14 +49,13 @@ class Database extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'server' => 'integer', 'db_server' => 'integer', ]; - } diff --git a/app/Models/DatabaseServer.php b/app/Models/DatabaseServer.php index 78b45d953..74fd88694 100644 --- a/app/Models/DatabaseServer.php +++ b/app/Models/DatabaseServer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class DatabaseServer extends Model { - /** * The table associated with the model. * @@ -49,15 +49,14 @@ class DatabaseServer extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'id' => 'integer', 'server_id' => 'integer', - 'db_server' => 'integer' + 'db_server' => 'integer', ]; - } diff --git a/app/Models/Download.php b/app/Models/Download.php index c3ee39d88..d2c3dd885 100644 --- a/app/Models/Download.php +++ b/app/Models/Download.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; -use Debugbar; use Illuminate\Database\Eloquent\Model; class Download extends Model { - /** * The table associated with the model. * * @var string */ protected $table = 'downloads'; - } diff --git a/app/Models/Location.php b/app/Models/Location.php index 9778283f9..5c8feb9fa 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Location extends Model { - /** * The table associated with the model. * @@ -41,5 +41,4 @@ class Location extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; - } diff --git a/app/Models/Node.php b/app/Models/Node.php index 7bfc37cec..a5cbce464 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use GuzzleHttp\Client; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; class Node extends Model { + use Notifiable; /** * The table associated with the model. @@ -43,11 +46,11 @@ class Node extends Model */ protected $hidden = ['daemonSecret']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'public' => 'integer', 'location' => 'integer', @@ -88,9 +91,9 @@ class Node extends Model return self::$nodes[$id]; } - self::$nodes[$id] = Node::where('id', $id)->first(); - return self::$nodes[$id]; + self::$nodes[$id] = self::where('id', $id)->first(); + return self::$nodes[$id]; } /** @@ -116,7 +119,62 @@ class Node extends Model ]); return self::$guzzle[$node]; - } + /** + * Returns the configuration in JSON format. + * + * @param bool $pretty Wether to pretty print the JSON or not + * @return string The configration in JSON format + */ + public function getConfigurationAsJson($pretty = false) + { + $config = [ + 'web' => [ + 'host' => '0.0.0.0', + 'listen' => $this->daemonListen, + 'ssl' => [ + 'enabled' => $this->scheme === 'https', + 'certificate' => '/etc/letsencrypt/live/' . $this->fqdn . '/fullchain.pem', + 'key' => '/etc/letsencrypt/live/' . $this->fqdn . '/privkey.pem', + ], + ], + 'docker' => [ + 'socket' => '/var/run/docker.sock', + 'autoupdate_images' => true, + ], + 'sftp' => [ + 'path' => $this->daemonBase, + 'port' => $this->daemonSFTP, + 'container' => 'ptdl-sftp', + ], + 'query' => [ + 'kill_on_fail' => true, + 'fail_limit' => 5, + ], + 'logger' => [ + 'path' => 'logs/', + 'src' => false, + 'level' => 'info', + 'period' => '1d', + 'count' => 3, + ], + 'remote' => [ + 'base' => config('app.url'), + 'download' => route('remote.download'), + 'installed' => route('remote.install'), + ], + 'uploads' => [ + 'size_limit' => $this->upload_size, + ], + 'keys' => [$this->daemonSecret], + ]; + + $json_options = JSON_UNESCAPED_SLASHES; + if ($pretty) { + $json_options |= JSON_PRETTY_PRINT; + } + + return json_encode($config, $json_options); + } } diff --git a/resources/lang/pt/passwords.php b/app/Models/NodeConfigurationToken.php similarity index 55% rename from resources/lang/pt/passwords.php rename to app/Models/NodeConfigurationToken.php index 9ade02b62..dd029ec78 100644 --- a/resources/lang/pt/passwords.php +++ b/app/Models/NodeConfigurationToken.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,20 +21,31 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -return [ - /* - |-------------------------------------------------------------------------- - | Password Reminder Language Lines - |-------------------------------------------------------------------------- - | - | The following language lines are the default lines which match reasons - | that are given by the password broker for a password update attempt - | has failed, such as for an invalid token or invalid new password. - | - */ - 'password' => 'Senhas precisam ter ao menos 6 caracteres e combinar com a confirmação.', - 'reset' => 'Sua senha foi resetada!', - 'sent' => 'Nós te enviamos um email com o link para resetar sua senha!', - 'token' => 'O token para resetar esta senha é inválido.', - 'user' => "Nós não pudemos achar um usuário com este endereço de email.", -]; + +namespace Pterodactyl\Models; + +use Illuminate\Database\Eloquent\Model; + +class NodeConfigurationToken extends Model +{ + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'node_configuration_tokens'; + + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * The attributes that should be mutated to dates. + * + * @var array + */ + protected $dates = ['created_at', 'updated_at', 'expires_at']; +} diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 5a59d579d..008473f3c 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Permission extends Model { - /** * The table associated with the model. * @@ -42,11 +42,11 @@ class Permission extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'user_id' => 'integer', 'server_id' => 'integer', @@ -61,5 +61,4 @@ class Permission extends Model { return $query->where('server_id', $server->id); } - } diff --git a/app/Models/Server.php b/app/Models/Server.php index 9948c7a10..3a11603c2 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Auth; -use Pterodactyl\Models\Subuser; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\SoftDeletes; -use Pterodactyl\Exceptions\DisplayException; - class Server extends Model { - - use SoftDeletes; + use Notifiable, SoftDeletes; /** * The table associated with the model. @@ -63,11 +61,11 @@ class Server extends Model */ protected $guarded = ['id', 'installed', 'created_at', 'updated_at', 'deleted_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'node' => 'integer', 'suspended' => 'integer', @@ -95,7 +93,7 @@ class Server extends Model protected static $user; /** - * Constructor + * Constructor. */ public function __construct() { @@ -112,7 +110,6 @@ class Server extends Model */ public static function getUserDaemonSecret(Server $server) { - if (self::$user->id === $server->owner || self::$user->root_admin === 1) { return $server->daemonSecret; } @@ -124,7 +121,6 @@ class Server extends Model } return $subuser->daemonSecret; - } /** @@ -135,7 +131,6 @@ class Server extends Model */ public static function getUserServers($paginate = null) { - $query = self::select( 'servers.*', 'nodes.name as nodeName', @@ -160,7 +155,6 @@ class Server extends Model } return $query->get(); - } /** @@ -173,7 +167,6 @@ class Server extends Model */ public static function getByUUID($uuid) { - if (array_key_exists($uuid, self::$serverUUIDInstance)) { return self::$serverUUIDInstance[$uuid]; } @@ -189,33 +182,30 @@ class Server extends Model $result = $query->first(); - if(!is_null($result)) { + if (! is_null($result)) { $result->daemonSecret = self::getUserDaemonSecret($result); } self::$serverUUIDInstance[$uuid] = $result; - return self::$serverUUIDInstance[$uuid]; + return self::$serverUUIDInstance[$uuid]; } /** - * Returns non-administrative headers for accessing a server on Scales + * Returns non-administrative headers for accessing a server on the daemon. * * @param string $uuid * @return array */ public static function getGuzzleHeaders($uuid) { - if (array_key_exists($uuid, self::$serverUUIDInstance)) { return [ 'X-Access-Server' => self::$serverUUIDInstance[$uuid]->uuid, - 'X-Access-Token' => self::$serverUUIDInstance[$uuid]->daemonSecret + 'X-Access-Token' => self::$serverUUIDInstance[$uuid]->daemonSecret, ]; } return []; - } - } diff --git a/app/Models/ServerVariables.php b/app/Models/ServerVariables.php index d5d062489..c6c6970bc 100644 --- a/app/Models/ServerVariables.php +++ b/app/Models/ServerVariables.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class ServerVariables extends Model { - /** * The table associated with the model. * @@ -42,14 +42,13 @@ class ServerVariables extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'server_id' => 'integer', 'variable_id' => 'integer', ]; - } diff --git a/app/Models/Service.php b/app/Models/Service.php index e1d3e23e6..8c0f27790 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Service extends Model { - /** * The table associated with the model. * @@ -41,5 +41,4 @@ class Service extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; - } diff --git a/app/Models/ServiceOptions.php b/app/Models/ServiceOptions.php index 393445a48..fe7e23f10 100644 --- a/app/Models/ServiceOptions.php +++ b/app/Models/ServiceOptions.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class ServiceOptions extends Model { - /** * The table associated with the model. * @@ -42,13 +42,22 @@ class ServiceOptions extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'parent_service' => 'integer', ]; + /** + * Gets all variables associated with this service. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function variables() + { + return $this->hasMany(ServiceVariables::class, 'option_id'); + } } diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php new file mode 100644 index 000000000..cefcc0a32 --- /dev/null +++ b/app/Models/ServicePack.php @@ -0,0 +1,59 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Models; + +use Illuminate\Database\Eloquent\Model; + +class ServicePack extends Model +{ + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'service_packs'; + + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'option' => 'integer', + 'build_memory' => 'integer', + 'build_swap' => 'integer', + 'build_cpu' => 'integer', + 'build_io' => 'integer', + 'selectable' => 'boolean', + 'visible' => 'boolean', + ]; +} diff --git a/app/Models/ServiceVariables.php b/app/Models/ServiceVariables.php index 8b7f203b3..5082d714e 100644 --- a/app/Models/ServiceVariables.php +++ b/app/Models/ServiceVariables.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class ServiceVariables extends Model { - /** * The table associated with the model. * @@ -42,16 +42,15 @@ class ServiceVariables extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'option_id' => 'integer', 'user_viewable' => 'integer', 'user_editable' => 'integer', 'required' => 'integer', ]; - } diff --git a/app/Models/Session.php b/app/Models/Session.php index 2b17bf6ce..9af347bbe 100644 --- a/app/Models/Session.php +++ b/app/Models/Session.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Session extends Model { - /** * The table associated with the model. * @@ -35,14 +35,13 @@ class Session extends Model */ protected $table = 'sessions'; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'id' => 'string', 'user_id' => 'integer', ]; - } diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 5c22adfb7..8d4a5b133 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Auth; @@ -28,7 +29,6 @@ use Illuminate\Database\Eloquent\Model; class Subuser extends Model { - /** * The table associated with the model. * @@ -50,11 +50,11 @@ class Subuser extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'user_id' => 'integer', 'server_id' => 'integer', @@ -66,7 +66,7 @@ class Subuser extends Model protected static $user; /** - * Constructor + * Constructor. */ public function __construct() { @@ -80,18 +80,8 @@ class Subuser extends Model */ public static function accessServers() { - - $access = []; - $union = self::select('server_id')->where('user_id', self::$user->id); - $select = Server::select('id')->where('owner', self::$user->id)->union($union)->get(); - - foreach($select as &$select) { - $access = array_merge($access, [ $select->id ]); - } - - return $access; + return Server::select('id')->where('owner', self::$user->id)->union($union)->pluck('id'); } - } diff --git a/app/Models/Task.php b/app/Models/Task.php index cfac1f5b7..7f5e18182 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class Task extends Model { - /** * The table associated with the model. * @@ -42,22 +42,21 @@ class Task extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'id' => 'integer', 'server' => 'integer', 'queued' => 'integer', ]; - /** + /** * The attributes that should be mutated to dates. * * @var array */ protected $dates = ['last_run', 'next_run', 'created_at', 'updated_at']; - } diff --git a/app/Models/TaskLog.php b/app/Models/TaskLog.php index d2e2519d1..0ec947ae9 100644 --- a/app/Models/TaskLog.php +++ b/app/Models/TaskLog.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; class TaskLog extends Model { - /** * The table associated with the model. * @@ -42,22 +42,21 @@ class TaskLog extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'id' => 'integer', 'task_id' => 'integer', - 'run_status' => 'integer' + 'run_status' => 'integer', ]; - /** + /** * The attributes that should be mutated to dates. * * @var array */ protected $dates = ['run_time', 'created_at', 'updated_at']; - } diff --git a/app/Models/User.php b/app/Models/User.php index 990511ecb..8d1d7fb71 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,30 +21,40 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Models; use Hash; use Google2FA; -use Pterodactyl\Exceptions\AccountNotFoundException; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Models\Permission; -use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification; - use Illuminate\Auth\Authenticatable; -use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; +use Pterodactyl\Exceptions\DisplayException; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Foundation\Auth\Access\Authorizable; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; +use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification; -class User extends Model implements AuthenticatableContract, - AuthorizableContract, - CanResetPasswordContract +class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract { use Authenticatable, Authorizable, CanResetPassword, Notifiable; + /** + * The rules for user passwords. + * + * @var string + */ + const PASSWORD_RULES = 'regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})'; + + /** + * The regex rules for usernames. + * + * @var string + */ + const USERNAME_RULES = 'regex:/^([\w\d\.\-]{1,255})$/'; + /** * The table associated with the model. * @@ -53,20 +63,21 @@ class User extends Model implements AuthenticatableContract, protected $table = 'users'; /** - * The attributes that are not mass assignable. + * A list of mass-assignable variables. * - * @var array + * @var [type] */ - protected $guarded = ['id', 'remeber_token', 'created_at', 'updated_at']; + protected $fillable = ['username', 'email', 'name_first', 'name_last', 'password', 'language', 'use_totp', 'totp_secret', 'gravatar', 'root_admin']; - /** - * Cast values to correct type. - * - * @var array - */ + /** + * Cast values to correct type. + * + * @var array + */ protected $casts = [ 'root_admin' => 'integer', 'use_totp' => 'integer', + 'gravatar' => 'integer', ]; /** @@ -77,12 +88,10 @@ class User extends Model implements AuthenticatableContract, protected $hidden = ['password', 'remember_token', 'totp_secret']; /** - * The rules for user passwords - * - * @var string - */ - const PASSWORD_RULES = 'min:8|regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})'; - + * Determines if a user has permissions. + * + * @return bool + */ public function permissions() { return $this->hasMany(Permission::class); @@ -92,20 +101,18 @@ class User extends Model implements AuthenticatableContract, * Enables or disables TOTP on an account if the token is valid. * * @param int $token The token that we want to verify. - * @return boolean + * @return bool */ public function toggleTotp($token) { - - if (!Google2FA::verifyKey($this->totp_secret, $token)) { + if (! Google2FA::verifyKey($this->totp_secret, $token)) { return false; } - $this->use_totp = !$this->use_totp; + $this->use_totp = ! $this->use_totp; $this->save(); return true; - } /** @@ -113,7 +120,7 @@ class User extends Model implements AuthenticatableContract, * - 8 or more characters in length * - at least one uppercase character * - at least one lowercase character - * - at least one number + * - at least one number. * * @param string $password The raw password to set the account password to. * @param string $regex The regex to use when validating the password. Defaults to '((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})'. @@ -121,16 +128,12 @@ class User extends Model implements AuthenticatableContract, */ public function setPassword($password, $regex = '((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})') { - - if (!preg_match($regex, $password)) { + if (! preg_match($regex, $password)) { throw new DisplayException('The password passed did not meet the minimum password requirements.'); } $this->password = Hash::make($password); $this->save(); - - return; - } /** @@ -144,4 +147,13 @@ class User extends Model implements AuthenticatableContract, $this->notify(new ResetPasswordNotification($token)); } + /** + * Return true or false depending on wether the user is root admin or not. + * + * @return bool the user is root admin + */ + public function isRootAdmin() + { + return $this->root_admin === 1; + } } diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index 806aa9408..55cfe416b 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Notifications; use Illuminate\Bus\Queueable; @@ -73,5 +74,4 @@ class AccountCreated extends Notification implements ShouldQueue ->line('Email: ' . $notifiable->email) ->action('Setup Your Account', url('/auth/password/reset/' . $this->token . '?email=' . $notifiable->email)); } - } diff --git a/app/Notifications/SendPasswordReset.php b/app/Notifications/SendPasswordReset.php index b7aa49ec0..31939945e 100644 --- a/app/Notifications/SendPasswordReset.php +++ b/app/Notifications/SendPasswordReset.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Notifications; use Illuminate\Bus\Queueable; diff --git a/app/Notifications/ServerCreated.php b/app/Notifications/ServerCreated.php index 3d2b21344..a867e26c7 100644 --- a/app/Notifications/ServerCreated.php +++ b/app/Notifications/ServerCreated.php @@ -1,4 +1,26 @@ . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ namespace Pterodactyl\Notifications; @@ -44,13 +66,12 @@ class ServerCreated extends Notification implements ShouldQueue public function toMail($notifiable) { return (new MailMessage) - ->line('A new server as been assigned to your account.') - ->line('Server Name: ' . $this->server->name) - ->line('Memory: ' . $this->server->memory . ' MB') - ->line('Node: ' . $this->server->node) - ->line('Type: ' . $this->server->service . ' - ' . $this->server->option) - ->action('Peel Off the Protective Wrap', route('server.index', $this->server->uuidShort)) - ->line('Please let us know if you have any additional questions or concerns!'); + ->line('A new server as been assigned to your account.') + ->line('Server Name: ' . $this->server->name) + ->line('Memory: ' . $this->server->memory . ' MB') + ->line('Node: ' . $this->server->node) + ->line('Type: ' . $this->server->service . ' - ' . $this->server->option) + ->action('Peel Off the Protective Wrap', route('server.index', $this->server->uuidShort)) + ->line('Please let us know if you have any additional questions or concerns!'); } - } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php new file mode 100644 index 000000000..6506f03f2 --- /dev/null +++ b/app/Observers/ServerObserver.php @@ -0,0 +1,109 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Observers; + +use Carbon; +use Pterodactyl\Events; +use Pterodactyl\Models; +use Pterodactyl\Models\Server; +use Pterodactyl\Jobs\DeleteServer; +use Pterodactyl\Jobs\SuspendServer; +use Pterodactyl\Notifications\ServerCreated; +use Illuminate\Foundation\Bus\DispatchesJobs; + +class ServerObserver +{ + use DispatchesJobs; + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function creating(Server $server) + { + event(new Events\Server\Creating($server)); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function created(Server $server) + { + event(new Events\Server\Created($server)); + + // Queue Notification Email + $user = Models\User::findOrFail($server->owner); + $node = Models\Node::select('name')->where('id', $server->node)->first(); + $service = Models\Service::select('services.name', 'service_options.name as optionName') + ->join('service_options', 'service_options.parent_service', '=', 'services.id') + ->where('services.id', $server->service) + ->where('service_options.id', $server->option) + ->first(); + + $user->notify((new ServerCreated([ + 'name' => $server->name, + 'memory' => $server->memory, + 'node' => $node->name, + 'service' => $service->name, + 'option' => $service->optionName, + 'uuidShort' => $server->uuidShort, + ]))); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function deleting(Server $server) + { + event(new Events\Server\Deleting($server)); + + $this->dispatch((new SuspendServer($server->id))->onQueue(env('QUEUE_HIGH', 'high'))); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function deleted(Server $server) + { + event(new Events\Server\Deleted($server)); + + $this->dispatch( + (new DeleteServer($server->id)) + ->delay(Carbon::now()->addMinutes(env('APP_DELETE_MINUTES', 10))) + ->onQueue(env('QUEUE_STANDARD', 'standard')) + ); + } +} diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php new file mode 100644 index 000000000..e0624e268 --- /dev/null +++ b/app/Observers/UserObserver.php @@ -0,0 +1,75 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Observers; + +use Pterodactyl\Events; +use Pterodactyl\Models\User; + +class UserObserver +{ + /** + * Listen to the User creating event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function creating(User $user) + { + event(new Events\User\Creating($user)); + } + + /** + * Listen to the User created event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function created(User $user) + { + event(new Events\User\Created($user)); + } + + /** + * Listen to the User deleting event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function deleting(User $user) + { + event(new Events\User\Deleting($user)); + } + + /** + * Listen to the User deleted event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function deleted(User $user) + { + event(new Events\User\Deleted($user)); + } +} diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 2615149f0..f297fe829 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Policies; use Pterodactyl\Models\User; @@ -28,7 +29,6 @@ use Pterodactyl\Models\Server; class ServerPolicy { - /** * Create a new policy instance. * @@ -42,9 +42,9 @@ class ServerPolicy /** * Determine if current user is the owner of a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ protected function isOwner(User $user, Server $server) { @@ -54,9 +54,9 @@ class ServerPolicy /** * Runs before any of the functions are called. Used to determine if user is root admin, if so, ignore permissions. * - * @param Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\User $user * @param string $ability - * @return boolean + * @return bool */ public function before(User $user, $ability) { @@ -68,578 +68,474 @@ class ServerPolicy /** * Check if user has permission to control power for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function power(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('power')->exists(); + return $this->checkPermission($user, $server, 'power'); } /** * Check if user has permission to start a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function powerStart(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('power-start')->exists(); + return $this->checkPermission($user, $server, 'power-start'); } /** * Check if user has permission to stop a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function powerStop(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('power-stop')->exists(); + return $this->checkPermission($user, $server, 'power-stop'); } /** * Check if user has permission to restart a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function powerRestart(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('power-restart')->exists(); + return $this->checkPermission($user, $server, 'power-restart'); } /** * Check if user has permission to kill a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function powerKill(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('power-kill')->exists(); + return $this->checkPermission($user, $server, 'power-kill'); } /** * Check if user has permission to run a command on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function sendCommand(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('send-command')->exists(); + return $this->checkPermission($user, $server, 'send-command'); } /** * Check if user has permission to list files on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function listFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('list-files')->exists(); + return $this->checkPermission($user, $server, 'list-files'); } /** * Check if user has permission to edit files on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function editFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('edit-files')->exists(); + return $this->checkPermission($user, $server, 'edit-files'); } /** * Check if user has permission to save files on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function saveFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('save-files')->exists(); + return $this->checkPermission($user, $server, 'save-files'); } /** * Check if user has permission to move and rename files and folders on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function moveFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('move-files')->exists(); + return $this->checkPermission($user, $server, 'move-files'); } /** * Check if user has permission to copy folders and files on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function copyFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('copy-files')->exists(); + return $this->checkPermission($user, $server, 'copy-files'); } /** * Check if user has permission to compress files and folders on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function compressFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('compress-files')->exists(); + return $this->checkPermission($user, $server, 'compress-files'); } /** * Check if user has permission to decompress files on a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function decompressFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('decompress-files')->exists(); + return $this->checkPermission($user, $server, 'decompress-files'); } /** * Check if user has permission to add files to a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function addFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('add-files')->exists(); + return $this->checkPermission($user, $server, 'add-files'); } /** * Check if user has permission to upload files to a server. * This permission relies on the user having the 'add-files' permission as well due to page authorization. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function uploadFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('upload-files')->exists(); + return $this->checkPermission($user, $server, 'upload-files'); } /** * Check if user has permission to download files from a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function downloadFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('download-files')->exists(); + return $this->checkPermission($user, $server, 'download-files'); } /** * Check if user has permission to delete files from a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function deleteFiles(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('delete-files')->exists(); + return $this->checkPermission($user, $server, 'delete-files'); } /** * Check if user has permission to view subusers for the server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function listSubusers(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('list-subusers')->exists(); + return $this->checkPermission($user, $server, 'list-subusers'); } /** * Check if user has permission to view specific subuser permissions. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function viewSubuser(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('view-subuser')->exists(); + return $this->checkPermission($user, $server, 'view-subuser'); } /** * Check if user has permission to edit a subuser. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function editSubuser(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('edit-subuser')->exists(); + return $this->checkPermission($user, $server, 'edit-subuser'); } /** * Check if user has permission to delete a subuser. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function deleteSubuser(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('delete-subuser')->exists(); + return $this->checkPermission($user, $server, 'delete-subuser'); } /** * Check if user has permission to edit a subuser. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function createSubuser(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('create-subuser')->exists(); + return $this->checkPermission($user, $server, 'create-subuser'); } /** * Check if user has permission to set the default connection for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function setConnection(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('set-connection')->exists(); + return $this->checkPermission($user, $server, 'set-connection'); } /** * Check if user has permission to view the startup command used for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function viewStartup(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('view-startup')->exists(); + return $this->checkPermission($user, $server, 'view-startup'); } /** * Check if user has permission to edit the startup command used for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function editStartup(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('edit-startup')->exists(); + return $this->checkPermission($user, $server, 'edit-startup'); } /** * Check if user has permission to view the SFTP information for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function viewSftp(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('view-sftp')->exists(); + return $this->checkPermission($user, $server, 'view-sftp'); } /** * Check if user has permission to reset the SFTP password for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function resetSftp(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('reset-sftp')->exists(); + return $this->checkPermission($user, $server, 'reset-sftp'); } /** * Check if user has permission to view the SFTP password for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function viewSftpPassword(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('view-sftp-password')->exists(); + return $this->checkPermission($user, $server, 'view-sftp-password'); } /** * Check if user has permission to view databases for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function viewDatabases(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('view-databases')->exists(); + return $this->checkPermission($user, $server, 'view-databases'); } /** * Check if user has permission to reset database passwords. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function resetDbPassword(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('reset-db-password')->exists(); + return $this->checkPermission($user, $server, 'reset-db-password'); } /** * Check if user has permission to view all tasks for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function listTasks(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('list-tasks')->exists(); + return $this->checkPermission($user, $server, 'list-tasks'); } /** * Check if user has permission to view a specific task for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function viewTask(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('view-task')->exists(); + return $this->checkPermission($user, $server, 'view-task'); } /** * Check if user has permission to view a toggle a task for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function toggleTask(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('toggle-task')->exists(); + return $this->checkPermission($user, $server, 'toggle-task'); } /** * Check if user has permission to queue a task for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function queueTask(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('queue-task')->exists(); + return $this->checkPermission($user, $server, 'queue-task'); } /** * Check if user has permission to delete a specific task for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function deleteTask(User $user, Server $server) { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission('delete-task')->exists(); + return $this->checkPermission($user, $server, 'delete-task'); } /** * Check if user has permission to create a task for a server. * - * @param Pterodactyl\Models\User $user - * @param Pterodactyl\Models\Server $server - * @return boolean + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool */ public function createTask(User $user, Server $server) + { + return $this->checkPermission($user, $server, 'create-task'); + } + + /** + * Check if user has permission to view server allocations. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool + */ + public function viewAllocation(User $user, Server $server) + { + return $this->checkPermission($user, $server, 'view-allocation'); + } + + /** + * Check if user has permission to set the default allocation. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @return bool + */ + public function setAllocation(User $user, Server $server) + { + return $this->checkPermission($user, $server, 'set-allocation'); + } + + /** + * Checks if the user has the given permission on/for the server. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @param $permission + * @return bool + */ + private function checkPermission(User $user, Server $server, $permission) { if ($this->isOwner($user, $server)) { return true; } - return $user->permissions()->server($server)->permission('create-task')->exists(); + return $user->permissions()->server($server)->permission($permission)->exists(); } - } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index d0d1dd9e4..d71ea056b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,8 +1,34 @@ . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ namespace Pterodactyl\Providers; +use Pterodactyl\Models\User; +use Pterodactyl\Models\Server; use Illuminate\Support\ServiceProvider; +use Pterodactyl\Observers\UserObserver; +use Pterodactyl\Observers\ServerObserver; class AppServiceProvider extends ServiceProvider { @@ -13,7 +39,8 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // + User::observe(UserObserver::class); + Server::observe(ServerObserver::class); } /** diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 757101e2d..86c94d99f 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -13,7 +13,7 @@ class AuthServiceProvider extends ServiceProvider * @var array */ protected $policies = [ - 'Pterodactyl\Models\Server' => 'Pterodactyl\Policies\ServerPolicy' + 'Pterodactyl\Models\Server' => 'Pterodactyl\Policies\ServerPolicy', ]; /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 7ec0d48ae..0e31100c3 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -12,11 +12,7 @@ class EventServiceProvider extends ServiceProvider * * @var array */ - protected $listen = [ - 'Pterodactyl\Events\ServerDeleted' => [ - 'Pterodactyl\Listeners\DeleteServerListener', - ], - ]; + protected $listen = []; /** * Register any other events for your application. diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index c093c86ed..7ce94f34b 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,21 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; -use Auth; use DB; +use Auth; use Crypt; use Validator; use IPTools\Network; - use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class APIRepository { - /** * Valid API permissions. * @var array @@ -97,7 +96,7 @@ class APIRepository protected $user; /** - * Constructor + * Constructor. */ public function __construct(Models\User $user = null) { @@ -117,17 +116,17 @@ class APIRepository * * @return string Returns the generated secret token. */ - public function new(array $data) + public function create(array $data) { $validator = Validator::make($data, [ 'memo' => 'string|max:500', 'permissions' => 'sometimes|required|array', - 'adminPermissions' => 'sometimes|required|array' + 'adminPermissions' => 'sometimes|required|array', ]); - $validator->after(function($validator) use ($data) { - if (array_key_exists('allowed_ips', $data) && !empty($data['allowed_ips'])) { - foreach(explode("\n", $data['allowed_ips']) as $ip) { + $validator->after(function ($validator) use ($data) { + if (array_key_exists('allowed_ips', $data) && ! empty($data['allowed_ips'])) { + foreach (explode("\n", $data['allowed_ips']) as $ip) { $ip = trim($ip); try { Network::parse($ip); @@ -155,14 +154,16 @@ class APIRepository 'secret' => Crypt::encrypt($secretKey), 'allowed_ips' => empty($this->allowed) ? null : json_encode($this->allowed), 'memo' => $data['memo'], - 'expires_at' => null + 'expires_at' => null, ]); $key->save(); $totalPermissions = 0; if (isset($data['permissions'])) { - foreach($data['permissions'] as $permNode) { - if (!strpos($permNode, ':')) continue; + foreach ($data['permissions'] as $permNode) { + if (! strpos($permNode, ':')) { + continue; + } list($toss, $permission) = explode(':', $permNode); if (in_array($permission, $this->permissions['user'])) { @@ -170,7 +171,7 @@ class APIRepository $model = new Models\APIPermission; $model->fill([ 'key_id' => $key->id, - 'permission' => 'api.user.' . $permission + 'permission' => 'api.user.' . $permission, ]); $model->save(); } @@ -178,8 +179,10 @@ class APIRepository } if ($this->user->root_admin === 1 && isset($data['adminPermissions'])) { - foreach($data['adminPermissions'] as $permNode) { - if (!strpos($permNode, ':')) continue; + foreach ($data['adminPermissions'] as $permNode) { + if (! strpos($permNode, ':')) { + continue; + } list($toss, $permission) = explode(':', $permNode); if (in_array($permission, $this->permissions['admin'])) { @@ -187,7 +190,7 @@ class APIRepository $model = new Models\APIPermission; $model->fill([ 'key_id' => $key->id, - 'permission' => 'api.admin.' . $permission + 'permission' => 'api.admin.' . $permission, ]); $model->save(); } @@ -199,12 +202,12 @@ class APIRepository } DB::commit(); + return $secretKey; } catch (\Exception $ex) { DB::rollBack(); throw $ex; } - } /** @@ -216,13 +219,13 @@ class APIRepository * * @return void */ - public function revoke(string $key) + public function revoke($key) { DB::beginTransaction(); try { $model = Models\APIKey::where('public', $key)->where('user', $this->user->id)->firstOrFail(); - $permissions = Models\APIPermission::where('key_id', $model->id)->delete(); + Models\APIPermission::where('key_id', $model->id)->delete(); $model->delete(); DB::commit(); @@ -231,5 +234,4 @@ class APIRepository throw $ex; } } - } diff --git a/app/Repositories/Daemon/CommandRepository.php b/app/Repositories/Daemon/CommandRepository.php index ebaf9dc61..5631518dc 100644 --- a/app/Repositories/Daemon/CommandRepository.php +++ b/app/Repositories/Daemon/CommandRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories\Daemon; +use GuzzleHttp\Client; use Pterodactyl\Models; +use GuzzleHttp\Exception\RequestException; use Pterodactyl\Exceptions\DisplayException; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\RequestException; - -class CommandRepository { - +class CommandRepository +{ protected $server; protected $node; protected $client; @@ -43,9 +43,9 @@ class CommandRepository { } /** - * [send description] + * [send description]. * @param string $command - * @return boolean + * @return bool * @throws DisplayException * @throws RequestException */ @@ -59,11 +59,11 @@ class CommandRepository { $response = $this->client->request('POST', '/server/command', [ 'headers' => [ 'X-Access-Token' => $this->server->daemonSecret, - 'X-Access-Server' => $this->server->uuid + 'X-Access-Server' => $this->server->uuid, ], 'json' => [ - 'command' => $command - ] + 'command' => $command, + ], ]); if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { @@ -75,5 +75,4 @@ class CommandRepository { throw $ex; } } - } diff --git a/app/Repositories/Daemon/FileRepository.php b/app/Repositories/Daemon/FileRepository.php index 1d6bf7aac..d1319cf91 100644 --- a/app/Repositories/Daemon/FileRepository.php +++ b/app/Repositories/Daemon/FileRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,22 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories\Daemon; -use \Exception; -use Log; - -use Pterodactyl\Models\Server; -use Pterodactyl\Models\Node; -use Pterodactyl\Repositories\HelperRepository; -use Pterodactyl\Exceptions\DisplayException; - +use Exception; use GuzzleHttp\Client; -use GuzzleHttp\Exception\RequestException; +use Pterodactyl\Models\Node; +use Pterodactyl\Models\Server; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\HelperRepository; class FileRepository { - /** * The Eloquent Model associated with the requested server. * @@ -60,25 +56,23 @@ class FileRepository /** * The Guzzle Client headers associated with the requested server and node. - * (non-administrative headers) + * (non-administrative headers). * * @var array */ protected $headers; /** - * Constructor + * Constructor. * * @param string $server The server Short UUID */ public function __construct($uuid) { - $this->server = Server::getByUUID($uuid); $this->node = Node::getByID($this->server->node); $this->client = Node::guzzleRequest($this->server->node); $this->headers = Server::getGuzzleHeaders($uuid); - } /** @@ -89,7 +83,6 @@ class FileRepository */ public function returnFileContents($file) { - if (empty($file)) { throw new Exception('Not all parameters were properly passed to the function.'); } @@ -98,16 +91,16 @@ class FileRepository $file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/'; - $res = $this->client->request('GET', '/server/file/stat/' . rawurlencode($file->dirname.$file->basename) , [ - 'headers' => $this->headers + $res = $this->client->request('GET', '/server/file/stat/' . rawurlencode($file->dirname . $file->basename), [ + 'headers' => $this->headers, ]); $stat = json_decode($res->getBody()); - if($res->getStatusCode() !== 200 || !isset($stat->size)) { + if ($res->getStatusCode() !== 200 || ! isset($stat->size)) { throw new DisplayException('The daemon provided a non-200 error code on stat lookup: HTTP\\' . $res->getStatusCode()); } - if (!in_array($stat->mime, HelperRepository::editableFiles())) { + if (! in_array($stat->mime, HelperRepository::editableFiles())) { throw new DisplayException('You cannot edit that type of file (' . $stat->mime . ') through the panel.'); } @@ -115,24 +108,23 @@ class FileRepository throw new DisplayException('That file is too large to open in the browser, consider using a SFTP client.'); } - $res = $this->client->request('GET', '/server/file/f/' . rawurlencode($file->dirname.$file->basename) , [ - 'headers' => $this->headers + $res = $this->client->request('GET', '/server/file/f/' . rawurlencode($file->dirname . $file->basename), [ + 'headers' => $this->headers, ]); $json = json_decode($res->getBody()); - if($res->getStatusCode() !== 200 || !isset($json->content)) { + if ($res->getStatusCode() !== 200 || ! isset($json->content)) { throw new DisplayException('The daemon provided a non-200 error code: HTTP\\' . $res->getStatusCode()); } return [ 'file' => $json, - 'stat' => $stat + 'stat' => $stat, ]; - } /** - * Save the contents of a requested file on the Scales instance. + * Save the contents of a requested file on the daemon. * * @param string $file * @param string $content @@ -140,7 +132,6 @@ class FileRepository */ public function saveFileContents($file, $content) { - if (empty($file)) { throw new Exception('A valid file and path must be specified to save a file.'); } @@ -152,9 +143,9 @@ class FileRepository $res = $this->client->request('POST', '/server/file/save', [ 'headers' => $this->headers, 'json' => [ - 'path' => rawurlencode($file->dirname.$file->basename), - 'content' => $content - ] + 'path' => rawurlencode($file->dirname . $file->basename), + 'content' => $content, + ], ]); if ($res->getStatusCode() !== 204) { @@ -162,67 +153,57 @@ class FileRepository } return true; - } /** - * Returns a listing of all files and folders within a specified Scales directory. + * Returns a listing of all files and folders within a specified directory on the daemon. * * @param string $directory * @return object */ public function returnDirectoryListing($directory) { - if (empty($directory)) { throw new Exception('A valid directory must be specified in order to list its contents.'); } $res = $this->client->request('GET', '/server/directory/' . rawurlencode($directory), [ - 'headers' => $this->headers + 'headers' => $this->headers, ]); $json = json_decode($res->getBody()); - if($res->getStatusCode() !== 200) { + if ($res->getStatusCode() !== 200) { throw new DisplayException('An error occured while attempting to save this file. ' . $res->getBody()); } // Iterate through results $files = []; $folders = []; - foreach($json as &$value) { - + foreach ($json as &$value) { if ($value->directory === true) { - // @TODO Handle Symlinks - $folders = array_merge($folders, [[ + $folders[] = [ 'entry' => $value->name, 'directory' => trim($directory, '/'), 'size' => null, 'date' => strtotime($value->modified), - 'mime' => $value->mime - ]]); - - } else if ($value->file === true) { - - $files = array_merge($files, [[ + 'mime' => $value->mime, + ]; + } elseif ($value->file === true) { + $files[] = [ 'entry' => $value->name, 'directory' => trim($directory, '/'), 'extension' => pathinfo($value->name, PATHINFO_EXTENSION), 'size' => HelperRepository::bytesToHuman($value->size), 'date' => strtotime($value->modified), - 'mime' => $value->mime - ]]); - + 'mime' => $value->mime, + ]; } - } return (object) [ 'files' => $files, 'folders' => $folders, ]; - } - } diff --git a/app/Repositories/Daemon/PowerRepository.php b/app/Repositories/Daemon/PowerRepository.php index 2fa56d5da..705ea3e82 100644 --- a/app/Repositories/Daemon/PowerRepository.php +++ b/app/Repositories/Daemon/PowerRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories\Daemon; +use GuzzleHttp\Client; use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\RequestException; - -class PowerRepository { - +class PowerRepository +{ protected $server; protected $node; protected $client; @@ -52,11 +51,11 @@ class PowerRepository { $response = $this->client->request('PUT', '/server/power', [ 'headers' => [ 'X-Access-Token' => $this->server->daemonSecret, - 'X-Access-Server' => $this->server->uuid + 'X-Access-Server' => $this->server->uuid, ], 'json' => [ - 'action' => $action - ] + 'action' => $action, + ], ]); if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { @@ -88,5 +87,4 @@ class PowerRepository { { $this->do('kill'); } - } diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index c1c9b4e37..1abf8e155 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,21 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; -use Crypt; -use Log; use DB; +use Crypt; use Validator; - use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; +use Illuminate\Database\Capsule\Manager as Capsule; use Pterodactyl\Exceptions\DisplayValidationException; -use Illuminate\Database\Capsule\Manager as Capsule; - -class DatabaseRepository { - +class DatabaseRepository +{ /** * Adds a new database to a given database server. * @param int $server Id of the server to add a database for. @@ -56,16 +54,15 @@ class DatabaseRepository { } DB::beginTransaction(); - try { $db = new Models\Database; $db->fill([ 'server_id' => $server->id, 'db_server' => $options['db_server'], - 'database' => $server->uuidShort . '_' . $options['database'], + 'database' => "s{$server->id}_{$options['database']}", 'username' => $server->uuidShort . '_' . str_random(7), 'remote' => $options['remote'], - 'password' => Crypt::encrypt(str_random(20)) + 'password' => Crypt::encrypt(str_random(20)), ]); $db->save(); @@ -85,21 +82,33 @@ class DatabaseRepository { 'prefix' => '', 'options' => [ \PDO::ATTR_TIMEOUT => 3, - ] + ], ]); $capsule->setAsGlobal(); - - Capsule::statement('CREATE DATABASE ' . $db->database); - Capsule::statement('CREATE USER \'' . $db->username . '\'@\'' . $db->remote . '\' IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); - Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON ' . $db->database . '.* TO \'' . $db->username . '\'@\'' . $db->remote . '\''); - Capsule::statement('FLUSH PRIVILEGES'); - - DB::commit(); - return true; } catch (\Exception $ex) { - DB::rollback(); - throw $ex; + DB::rollBack(); + throw new DisplayException('There was an error while connecting to the Database Host Server. Please check the error logs.', $ex); + } + + try { + Capsule::statement('CREATE DATABASE `' . $db->database . '`'); + Capsule::statement('CREATE USER `' . $db->username . '`@`' . $db->remote . '` IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); + Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `' . $db->database . '`.* TO `' . $db->username . '`@`' . $db->remote . '`'); + Capsule::statement('FLUSH PRIVILEGES'); + DB::commit(); + } catch (\Exception $ex) { + try { + Capsule::statement('DROP DATABASE `' . $db->database . '`'); + Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); + } catch (\Exception $exi) { + // ignore it, if it fails its probably + // because we failed to ever make the DB + // or the user on the system. + } finally { + DB::rollBack(); + throw $ex; + } } } @@ -116,7 +125,6 @@ class DatabaseRepository { DB::beginTransaction(); try { - $db->password = Crypt::encrypt($password); $db->save(); @@ -133,28 +141,28 @@ class DatabaseRepository { 'prefix' => '', 'options' => [ \PDO::ATTR_TIMEOUT => 3, - ] + ], ]); $capsule->setAsGlobal(); Capsule::statement(sprintf( - 'SET PASSWORD FOR \'%s\'@\'%s\' = PASSWORD(\'%s\')', + 'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')', $db->username, $db->remote, $password )); DB::commit(); - } catch(\Exception $ex) { + } catch (\Exception $ex) { DB::rollback(); throw $ex; } } /** - * Drops a database from the associated MySQL Server + * Drops a database from the associated MySQL Server. * @param int $database The ID of the database to drop. - * @return boolean + * @return bool */ public function drop($database) { @@ -177,23 +185,23 @@ class DatabaseRepository { 'prefix' => '', 'options' => [ \PDO::ATTR_TIMEOUT => 3, - ] + ], ]); $capsule->setAsGlobal(); - Capsule::statement('DROP USER \'' . $db->username . '\'@\'' . $db->remote . '\''); - Capsule::statement('DROP DATABASE ' . $db->database); + Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); + Capsule::statement('DROP DATABASE `' . $db->database . '`'); $db->delete(); DB::commit(); + return true; } catch (\Exception $ex) { DB::rollback(); throw $ex; } - } /** @@ -219,6 +227,10 @@ class DatabaseRepository { */ public function add(array $data) { + if (isset($data['host'])) { + $data['host'] = gethostbyname($data['host']); + } + $validator = Validator::make($data, [ 'name' => 'required|string|max:255', 'host' => 'required|ip|unique:database_servers,host', @@ -248,7 +260,7 @@ class DatabaseRepository { 'prefix' => '', 'options' => [ \PDO::ATTR_TIMEOUT => 3, - ] + ], ]); $capsule->setAsGlobal(); @@ -263,8 +275,8 @@ class DatabaseRepository { 'port' => $data['port'], 'username' => $data['username'], 'password' => Crypt::encrypt($data['password']), - 'max_databases' => NULL, - 'linked_node' => (!empty($data['linked_node']) && $data['linked_node'] > 0) ? $data['linked_node'] : NULL + 'max_databases' => null, + 'linked_node' => (! empty($data['linked_node']) && $data['linked_node'] > 0) ? $data['linked_node'] : null, ]); $dbh->save(); @@ -274,5 +286,4 @@ class DatabaseRepository { throw $ex; } } - } diff --git a/app/Repositories/HelperRepository.php b/app/Repositories/HelperRepository.php index 6eaa68329..1e3248173 100644 --- a/app/Repositories/HelperRepository.php +++ b/app/Repositories/HelperRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,10 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; -class HelperRepository { - +class HelperRepository +{ /** * Listing of editable files in the control panel. * @var array @@ -40,10 +41,9 @@ class HelperRepository { 'text/plain', 'text/x-perl', 'text/x-shellscript', - 'inode/x-empty' + 'inode/x-empty', ]; - public function __construct() { // @@ -58,17 +58,14 @@ class HelperRepository { */ public static function bytesToHuman($bytes, $decimals = 2) { - $sz = explode(',', 'B,KB,MB,GB'); $factor = floor((strlen($bytes) - 1) / 3); - return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)).' '.$sz[$factor]; - + return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . $sz[$factor]; } public static function editableFiles() { return self::$editable; } - } diff --git a/app/Repositories/LocationRepository.php b/app/Repositories/LocationRepository.php index e70cfbd3e..79196ff35 100644 --- a/app/Repositories/LocationRepository.php +++ b/app/Repositories/LocationRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; use Validator; - use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayValidationException; class LocationRepository { - public function __construct() { // @@ -40,13 +39,13 @@ class LocationRepository * Creates a new location on the system. * @param array $data * @throws Pterodactyl\Exceptions\DisplayValidationException - * @return integer + * @return int */ public function create(array $data) { $validator = Validator::make($data, [ 'short' => 'required|regex:/^[a-z0-9_.-]{1,10}$/i|unique:locations,short', - 'long' => 'required|string|min:1|max:255' + 'long' => 'required|string|min:1|max:255', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -58,7 +57,7 @@ class LocationRepository $location = new Models\Location; $location->fill([ 'long' => $data['long'], - 'short' => $data['short'] + 'short' => $data['short'], ]); $location->save(); @@ -67,16 +66,16 @@ class LocationRepository /** * Modifies a location based on the fields passed in $data. - * @param integer $id + * @param int $id * @param array $data * @throws Pterodactyl\Exceptions\DisplayValidationException - * @return boolean + * @return bool */ public function edit($id, array $data) { $validator = Validator::make($data, [ 'short' => 'regex:/^[a-z0-9_.-]{1,10}$/i', - 'long' => 'string|min:1|max:255' + 'long' => 'string|min:1|max:255', ]); // Run validator, throw catchable and displayable exception if it fails. diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index a23cc7455..d55446196 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,20 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; use DB; use Validator; - +use IPTools\Network; use Pterodactyl\Models; use Pterodactyl\Services\UuidService; - -use IPTools\Network; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; -class NodeRepository { - +class NodeRepository +{ public function __construct() { // @@ -70,7 +69,7 @@ class NodeRepository { } // Verify FQDN is resolvable, or if not using SSL that the IP is valid. - if (!filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { + if (! filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { throw new DisplayException('The FQDN (or IP Address) provided does not resolve to a valid IP address.'); } @@ -88,7 +87,6 @@ class NodeRepository { $node->save(); return $node->id; - } public function update($id, array $data) @@ -106,6 +104,7 @@ class NodeRepository { 'memory_overallocate' => 'numeric|min:-1', 'disk' => 'numeric|min:1', 'disk_overallocate' => 'numeric|min:-1', + 'upload_size' => 'numeric|min:0', 'daemonBase' => 'regex:/^([\/][\d\w.\-\/]+)$/', 'daemonSFTP' => 'numeric|between:1,65535', 'daemonListen' => 'numeric|between:1,65535', @@ -122,17 +121,16 @@ class NodeRepository { if (isset($data['fqdn'])) { // Verify the FQDN if using SSL - if ((isset($data['scheme']) && $data['scheme'] === 'https') || (!isset($data['scheme']) && $node->scheme === 'https')) { + if ((isset($data['scheme']) && $data['scheme'] === 'https') || (! isset($data['scheme']) && $node->scheme === 'https')) { if (filter_var($data['fqdn'], FILTER_VALIDATE_IP)) { throw new DisplayException('A fully qualified domain name is required to use secure comunication on this node.'); } } // Verify FQDN is resolvable, or if not using SSL that the IP is valid. - if (!filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { + if (! filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { throw new DisplayException('The FQDN (or IP Address) provided does not resolve to a valid IP address.'); } - } // Should we be nulling the overallocations? @@ -151,9 +149,43 @@ class NodeRepository { unset($data['reset_secret']); } - // Store the Data - return $node->update($data); - + $oldDaemonKey = $node->daemonSecret; + $node->update($data); + try { + $client = Models\Node::guzzleRequest($node->id); + $client->request('PATCH', '/config', [ + 'headers' => [ + 'X-Access-Token' => $oldDaemonKey, + ], + 'json' => [ + 'web' => [ + 'listen' => $node->daemonListen, + 'ssl' => [ + 'enabled' => ($node->scheme === 'https'), + 'certificate' => '/etc/letsencrypt/live/' . $node->fqdn . '/fullchain.pem', + 'key' => '/etc/letsencrypt/live/' . $node->fqdn . '/privkey.pem', + ], + ], + 'sftp' => [ + 'path' => $node->daemonBase, + 'port' => $node->daemonSFTP, + ], + 'remote' => [ + 'base' => config('app.url'), + 'download' => route('remote.download'), + 'installed' => route('remote.install'), + ], + 'uploads' => [ + 'size_limit' => $node->upload_size, + ], + 'keys' => [ + $node->daemonSecret, + ], + ], + ]); + } catch (\Exception $ex) { + throw new DisplayException('Failed to update the node configuration, however your changes have been saved to the database. You will need to manually update the configuration file for the node to apply these changes.'); + } } public function addAllocations($id, array $allocations) @@ -163,7 +195,7 @@ class NodeRepository { DB::beginTransaction(); try { - foreach($allocations as $rawIP => $ports) { + foreach ($allocations as $rawIP => $ports) { try { $setAlias = null; $parsedIP = Network::parse($rawIP); @@ -175,25 +207,31 @@ class NodeRepository { throw $ex; } } - foreach($parsedIP as $ip) { - foreach($ports as $port) { - if (!is_int($port) && !preg_match('/^(\d{1,5})-(\d{1,5})$/', $port)) { + foreach ($parsedIP as $ip) { + foreach ($ports as $port) { + if (! is_int($port) && ! preg_match('/^(\d{1,5})-(\d{1,5})$/', $port)) { throw new DisplayException('The mapping for ' . $port . ' is invalid and cannot be processed.'); } if (preg_match('/^(\d{1,5})-(\d{1,5})$/', $port, $matches)) { - foreach(range($matches[1], $matches[2]) as $assignPort) { + $portBlock = range($matches[1], $matches[2]); + + if (count($portBlock) > 2000) { + throw new DisplayException('Adding more than 2000 ports at once is not currently supported. Please consider using a smaller port range.'); + } + + foreach ($portBlock as $assignPort) { $alloc = Models\Allocation::firstOrNew([ 'node' => $node->id, 'ip' => $ip, - 'port' => $assignPort + 'port' => $assignPort, ]); - if (!$alloc->exists) { + if (! $alloc->exists) { $alloc->fill([ 'node' => $node->id, 'ip' => $ip, 'port' => $assignPort, 'ip_alias' => $setAlias, - 'assigned_to' => null + 'assigned_to' => null, ]); $alloc->save(); } @@ -202,15 +240,15 @@ class NodeRepository { $alloc = Models\Allocation::firstOrNew([ 'node' => $node->id, 'ip' => $ip, - 'port' => $port + 'port' => $port, ]); - if (!$alloc->exists) { + if (! $alloc->exists) { $alloc->fill([ 'node' => $node->id, 'ip' => $ip, 'port' => $port, 'ip_alias' => $setAlias, - 'assigned_to' => null + 'assigned_to' => null, ]); $alloc->save(); } @@ -220,7 +258,6 @@ class NodeRepository { } DB::commit(); - // return true; } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -229,8 +266,32 @@ class NodeRepository { public function delete($id) { - // @TODO: add logic; - return true; - } + $node = Models\Node::findOrFail($id); + if (Models\Server::where('node', $id)->count() > 0) { + throw new DisplayException('You cannot delete a node with servers currently attached to it.'); + } + DB::beginTransaction(); + + try { + // Unlink Database Servers + Models\DatabaseServer::where('linked_node', $node->id)->update([ + 'linked_node' => null, + ]); + + // Delete Allocations + Models\Allocation::where('node', $node->id)->delete(); + + // Delete configure tokens + Models\NodeConfigurationToken::where('node', $node->id)->delete(); + + // Delete Node + $node->delete(); + + DB::commit(); + } catch (\Exception $ex) { + DB::rollback(); + throw $ex; + } + } } diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 47b1a4a97..beb5d94a6 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,29 +21,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; -use Crypt; use DB; -use Debugbar; -use Validator; use Log; - +use Crypt; +use Validator; use Pterodactyl\Models; use Pterodactyl\Services\UuidService; use Pterodactyl\Services\DeploymentService; -use Pterodactyl\Notifications\ServerCreated; -use Pterodactyl\Events\ServerDeleted; - use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Exceptions\AccountNotFoundException; use Pterodactyl\Exceptions\DisplayValidationException; class ServerRepository { - protected $daemonPermissions = [ - 's:*' + 's:*', ]; public function __construct() @@ -53,24 +47,35 @@ class ServerRepository /** * Generates a SFTP username for a server given a server name. - * format: mumble_67c7a4b0 + * format: mumble_67c7a4b0. * * @param string $name - * @param string $uuid + * @param string $identifier * @return string */ - protected function generateSFTPUsername($name, $uuid = null) + protected function generateSFTPUsername($name, $identifier = null) { + if (is_null($identifier) || ! ctype_alnum($identifier)) { + $unique = str_random(8); + } else { + if (strlen($identifier) < 8) { + $unique = $identifier . str_random((8 - strlen($identifier))); + } else { + $unique = substr($identifier, 0, 8); + } + } - $uuid = is_null($uuid) ? str_random(8) : $uuid; - return strtolower(substr(preg_replace('/\s+/', '', $name), 0, 6) . '_' . $uuid); + // Filter the Server Name + $name = trim(preg_replace('/[^\w]+/', '', $name), '_'); + $name = (strlen($name) < 1) ? str_random(6) : $name; + return strtolower(substr($name, 0, 6) . '_' . $unique); } /** * Adds a new server to the system. * @param array $data An array of data descriptors for creating the server. These should align to the columns in the database. - * @return integer + * @return int */ public function create(array $data) { @@ -78,36 +83,38 @@ class ServerRepository // Validate Fields $validator = Validator::make($data, [ 'owner' => 'bail|required', - 'name' => 'required|regex:/^([\w -]{4,35})$/', + 'name' => 'required|regex:/^([\w .-]{1,200})$/', 'memory' => 'required|numeric|min:0', 'swap' => 'required|numeric|min:-1', 'io' => 'required|numeric|min:10|max:1000', 'cpu' => 'required|numeric|min:0', 'disk' => 'required|numeric|min:0', - 'service' => 'bail|required|numeric|min:1|exists:services,id', - 'option' => 'bail|required|numeric|min:1|exists:service_options,id', + 'service' => 'required|numeric|min:1|exists:services,id', + 'option' => 'required|numeric|min:1|exists:service_options,id', + 'location' => 'required|numeric|min:1|exists:locations,id', + 'pack' => 'sometimes|nullable|numeric|min:0', 'startup' => 'string', 'custom_image_name' => 'required_if:use_custom_image,on', - 'auto_deploy' => 'sometimes|boolean' + 'auto_deploy' => 'sometimes|boolean', + 'custom_id' => 'sometimes|required|numeric|unique:servers,id', ]); $validator->sometimes('node', 'bail|required|numeric|min:1|exists:nodes,id', function ($input) { - return !($input->auto_deploy); + return ! ($input->auto_deploy); }); $validator->sometimes('ip', 'required|ip', function ($input) { - return (!$input->auto_deploy && !$input->allocation); + return ! $input->auto_deploy && ! $input->allocation; }); $validator->sometimes('port', 'required|numeric|min:1|max:65535', function ($input) { - return (!$input->auto_deploy && !$input->allocation); + return ! $input->auto_deploy && ! $input->allocation; }); $validator->sometimes('allocation', 'numeric|exists:allocations,id', function ($input) { - return !($input->auto_deploy || ($input->port && $input->ip)); + return ! ($input->auto_deploy || ($input->port && $input->ip)); }); - // Run validator, throw catchable and displayable exception if it fails. // Exception includes a JSON result of failed validation rules. if ($validator->fails()) { @@ -120,12 +127,12 @@ class ServerRepository $user = Models\User::select('id', 'email')->where('email', $data['owner'])->first(); } - if (!$user) { + if (! $user) { throw new DisplayException('The user id or email passed to the function was not found on the system.'); } $autoDeployed = false; - if (isset($data['auto_deploy']) && in_array($data['auto_deploy'], [true, 1, "1"])) { + if (isset($data['auto_deploy']) && in_array($data['auto_deploy'], [true, 1, '1'])) { // This is an auto-deployment situation // Ignore any other passed node data unset($data['node'], $data['ip'], $data['port'], $data['allocation']); @@ -139,16 +146,16 @@ class ServerRepository // Verify IP & Port are a.) free and b.) assigned to the node. // We know the node exists because of 'exists:nodes,id' in the validation - if (!$autoDeployed) { - if (!isset($data['allocation'])) { + if (! $autoDeployed) { + if (! isset($data['allocation'])) { $allocation = Models\Allocation::where('ip', $data['ip'])->where('port', $data['port'])->where('node', $data['node'])->whereNull('assigned_to')->first(); } else { - $allocation = Models\Allocation::where('id' , $data['allocation'])->where('node', $data['node'])->whereNull('assigned_to')->first(); + $allocation = Models\Allocation::where('id', $data['allocation'])->where('node', $data['node'])->whereNull('assigned_to')->first(); } } // Something failed in the query, either that combo doesn't exist, or it is in use. - if (!$allocation) { + if (! $allocation) { throw new DisplayException('The selected IP/Port combination or Allocation ID is either already in use, or unavaliable for this node.'); } @@ -157,10 +164,22 @@ class ServerRepository // We need to verify that the option exists for the service, and then check for // any required variable fields. (fields are labeled env_) $option = Models\ServiceOptions::where('id', $data['option'])->where('parent_service', $data['service'])->first(); - if (!$option) { + if (! $option) { throw new DisplayException('The requested service option does not exist for the specified service.'); } + // Validate the Pack + if ($data['pack'] == 0) { + $data['pack'] = null; + } + + if (! is_null($data['pack'])) { + $pack = Models\ServicePack::where('id', $data['pack'])->where('option', $data['option'])->first(); + if (! $pack) { + throw new DisplayException('The requested service pack does not seem to exist for this combination.'); + } + } + // Load up the Service Information $service = Models\Service::find($option->parent_service); @@ -168,46 +187,45 @@ class ServerRepository $variables = Models\ServiceVariables::where('option_id', $data['option'])->get(); $variableList = []; if ($variables) { - foreach($variables as $variable) { + foreach ($variables as $variable) { // Is the variable required? - if (!$data['env_' . $variable->env_variable]) { + if (! isset($data['env_' . $variable->env_variable])) { if ($variable->required === 1) { throw new DisplayException('A required service option variable field (env_' . $variable->env_variable . ') was missing from the request.'); } - $variableList = array_merge($variableList, [[ + $variableList[] = [ 'id' => $variable->id, 'env' => $variable->env_variable, - 'val' => $variable->default_value - ]]); + 'val' => $variable->default_value, + ]; continue; } // Check aganist Regex Pattern - if (!is_null($variable->regex) && !preg_match($variable->regex, $data['env_' . $variable->env_variable])) { + if (! is_null($variable->regex) && ! preg_match($variable->regex, $data['env_' . $variable->env_variable])) { throw new DisplayException('Failed to validate service option variable field (env_' . $variable->env_variable . ') aganist regex (' . $variable->regex . ').'); } - $variableList = array_merge($variableList, [[ + $variableList[] = [ 'id' => $variable->id, 'env' => $variable->env_variable, - 'val' => $data['env_' . $variable->env_variable] - ]]); + 'val' => $data['env_' . $variable->env_variable], + ]; continue; } } // Check Overallocation - if (!$autoDeployed) { + if (! $autoDeployed) { if (is_numeric($node->memory_overallocate) || is_numeric($node->disk_overallocate)) { - $totals = Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first(); // Check memory limits if (is_numeric($node->memory_overallocate)) { $newMemory = $totals->memory + $data['memory']; $memoryLimit = ($node->memory * (1 + ($node->memory_overallocate / 100))); - if($newMemory > $memoryLimit) { + if ($newMemory > $memoryLimit) { throw new DisplayException('The amount of memory allocated to this server would put the node over its allocation limits. This node is allowed ' . ($node->memory_overallocate + 100) . '% of its assigned ' . $node->memory . 'Mb of memory (' . $memoryLimit . 'Mb) of which ' . (($totals->memory / $node->memory) * 100) . '% (' . $totals->memory . 'Mb) is in use already. By allocating this server the node would be at ' . (($newMemory / $node->memory) * 100) . '% (' . $newMemory . 'Mb) usage.'); } } @@ -216,7 +234,7 @@ class ServerRepository if (is_numeric($node->disk_overallocate)) { $newDisk = $totals->disk + $data['disk']; $diskLimit = ($node->disk * (1 + ($node->disk_overallocate / 100))); - if($newDisk > $diskLimit) { + if ($newDisk > $diskLimit) { throw new DisplayException('The amount of disk allocated to this server would put the node over its allocation limits. This node is allowed ' . ($node->disk_overallocate + 100) . '% of its assigned ' . $node->disk . 'Mb of disk (' . $diskLimit . 'Mb) of which ' . (($totals->disk / $node->disk) * 100) . '% (' . $totals->disk . 'Mb) is in use already. By allocating this server the node would be at ' . (($newDisk / $node->disk) * 100) . '% (' . $newDisk . 'Mb) usage.'); } } @@ -232,6 +250,11 @@ class ServerRepository $server = new Models\Server; $genUuid = $uuid->generate('servers', 'uuid'); $genShortUuid = $uuid->generateShort('servers', 'uuidShort', $genUuid); + + if (isset($data['custom_id'])) { + $server->id = $data['custom_id']; + } + $server->fill([ 'uuid' => $genUuid, 'uuidShort' => $genShortUuid, @@ -248,11 +271,12 @@ class ServerRepository 'allocation' => $allocation->id, 'service' => $data['service'], 'option' => $data['option'], + 'pack' => $data['pack'], 'startup' => $data['startup'], 'daemonSecret' => $uuid->generate('servers', 'daemonSecret'), 'image' => (isset($data['custom_image_name'])) ? $data['custom_image_name'] : $option->docker_image, 'username' => $this->generateSFTPUsername($data['name'], $genShortUuid), - 'sftp_password' => Crypt::encrypt('not set') + 'sftp_password' => Crypt::encrypt('not set'), ]); $server->save(); @@ -261,35 +285,24 @@ class ServerRepository $allocation->save(); // Add Variables - $environmentVariables = []; - $environmentVariables = array_merge($environmentVariables, [ - 'STARTUP' => $data['startup'] - ]); - foreach($variableList as $item) { - $environmentVariables = array_merge($environmentVariables, [ - $item['env'] => $item['val'] - ]); + $environmentVariables = [ + 'STARTUP' => $data['startup'], + ]; + + foreach ($variableList as $item) { + $environmentVariables[$item['env']] = $item['val']; + Models\ServerVariables::create([ 'server_id' => $server->id, 'variable_id' => $item['id'], - 'variable_value' => $item['val'] + 'variable_value' => $item['val'], ]); } - // Queue Notification Email - $user->notify((new ServerCreated([ - 'name' => $server->name, - 'memory' => $server->memory, - 'node' => $node->name, - 'service' => $service->name, - 'option' => $option->name, - 'uuidShort' => $server->uuidShort - ]))); - $client = Models\Node::guzzleRequest($node->id); $client->request('POST', '/servers', [ 'headers' => [ - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ 'uuid' => (string) $server->uuid, @@ -297,10 +310,10 @@ class ServerRepository 'build' => [ 'default' => [ 'ip' => $allocation->ip, - 'port' => (int) $allocation->port + 'port' => (int) $allocation->port, ], 'ports' => [ - (string) $allocation->ip => [ (int) $allocation->port ] + (string) $allocation->ip => [(int) $allocation->port], ], 'env' => $environmentVariables, 'memory' => (int) $server->memory, @@ -308,20 +321,22 @@ class ServerRepository 'io' => (int) $server->io, 'cpu' => (int) $server->cpu, 'disk' => (int) $server->disk, - 'image' => (isset($data['custom_image_name'])) ? $data['custom_image_name'] : $option->docker_image + 'image' => (isset($data['custom_image_name'])) ? $data['custom_image_name'] : $option->docker_image, ], 'service' => [ 'type' => $service->file, - 'option' => $option->tag + 'option' => $option->tag, + 'pack' => (isset($pack)) ? $pack->uuid : null, ], 'keys' => [ - (string) $server->daemonSecret => $this->daemonPermissions + (string) $server->daemonSecret => $this->daemonPermissions, ], - 'rebuild' => false - ] + 'rebuild' => false, + ], ]); DB::commit(); + return $server->id; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -330,25 +345,23 @@ class ServerRepository DB::rollBack(); throw $ex; } - } /** - * [updateDetails description] - * @param integer $id + * [updateDetails description]. + * @param int $id * @param array $data - * @return boolean + * @return bool */ public function updateDetails($id, array $data) { - $uuid = new UuidService; $resetDaemonKey = false; // Validate Fields $validator = Validator::make($data, [ 'owner' => 'email|exists:users,email', - 'name' => 'regex:([\w -]{4,35})' + 'name' => 'regex:([\w .-]{1,200})', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -385,8 +398,9 @@ class ServerRepository $server->save(); // Do we need to update? If not, return successful. - if (!$resetDaemonKey) { + if (! $resetDaemonKey) { DB::commit(); + return true; } @@ -397,19 +411,20 @@ class ServerRepository $res = $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'exceptions' => false, 'json' => [ 'keys' => [ (string) $oldDaemonKey => [], - (string) $server->daemonSecret => $this->daemonPermissions - ] - ] + (string) $server->daemonSecret => $this->daemonPermissions, + ], + ], ]); if ($res->getStatusCode() === 204) { DB::commit(); + return true; } else { throw new DisplayException('Daemon returned a a non HTTP/204 error code. HTTP/' + $res->getStatusCode()); @@ -419,11 +434,10 @@ class ServerRepository Log::error($ex); throw new DisplayException('An error occured while attempting to update this server\'s information.'); } - } /** - * [updateContainer description] + * [updateContainer description]. * @param int $id * @param array $data * @return bool @@ -431,7 +445,7 @@ class ServerRepository public function updateContainer($id, array $data) { $validator = Validator::make($data, [ - 'image' => 'required|string' + 'image' => 'required|string', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -453,16 +467,17 @@ class ServerRepository $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ 'build' => [ - 'image' => $server->image - ] - ] + 'image' => $server->image, + ], + ], ]); DB::commit(); + return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -471,22 +486,20 @@ class ServerRepository DB::rollBack(); throw $ex; } - } /** - * [changeBuild description] - * @param integer $id + * [changeBuild description]. + * @param int $id * @param array $data - * @return boolean + * @return bool */ public function changeBuild($id, array $data) { - $validator = Validator::make($data, [ 'default' => [ 'string', - 'regex:/^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])):(\d{1,5})$/' + 'regex:/^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])):(\d{1,5})$/', ], 'add_additional' => 'nullable|array', 'remove_additional' => 'nullable|array', @@ -494,7 +507,7 @@ class ServerRepository 'swap' => 'integer|min:-1', 'io' => 'integer|min:10|max:1000', 'cpu' => 'integer|min:0', - 'disk' => 'integer|min:0' + 'disk' => 'integer|min:0', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -515,14 +528,14 @@ class ServerRepository list($ip, $port) = explode(':', $data['default']); if ($ip !== $allocation->ip || (int) $port !== $allocation->port) { $selection = Models\Allocation::where('ip', $ip)->where('port', $port)->where('assigned_to', $server->id)->first(); - if (!$selection) { + if (! $selection) { throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.'); } $server->allocation = $selection->id; $newBuild['default'] = [ 'ip' => $ip, - 'port' => (int) $port + 'port' => (int) $port, ]; // Re-Run to keep updated for rest of function @@ -536,7 +549,7 @@ class ServerRepository foreach ($data['remove_additional'] as $id => $combo) { list($ip, $port) = explode(':', $combo); // Invalid, not worth killing the whole thing, we'll just skip over it. - if (!filter_var($ip, FILTER_VALIDATE_IP) || !preg_match('/^(\d{1,5})$/', $port)) { + if (! filter_var($ip, FILTER_VALIDATE_IP) || ! preg_match('/^(\d{1,5})$/', $port)) { break; } @@ -547,7 +560,7 @@ class ServerRepository $newPorts = true; Models\Allocation::where('ip', $ip)->where('port', $port)->where('assigned_to', $server->id)->update([ - 'assigned_to' => null + 'assigned_to' => null, ]); } } @@ -557,7 +570,7 @@ class ServerRepository foreach ($data['add_additional'] as $id => $combo) { list($ip, $port) = explode(':', $combo); // Invalid, not worth killing the whole thing, we'll just skip over it. - if (!filter_var($ip, FILTER_VALIDATE_IP) || !preg_match('/^(\d{1,5})$/', $port)) { + if (! filter_var($ip, FILTER_VALIDATE_IP) || ! preg_match('/^(\d{1,5})$/', $port)) { break; } @@ -568,7 +581,7 @@ class ServerRepository $newPorts = true; Models\Allocation::where('ip', $ip)->where('port', $port)->whereNull('assigned_to')->update([ - 'assigned_to' => $server->id + 'assigned_to' => $server->id, ]); } } @@ -578,9 +591,9 @@ class ServerRepository $assignments = Models\Allocation::where('assigned_to', $server->id)->get(); foreach ($assignments as &$assignment) { if (array_key_exists((string) $assignment->ip, $additionalAssignments)) { - array_push($additionalAssignments[ (string) $assignment->ip ], (int) $assignment->port); + array_push($additionalAssignments[(string) $assignment->ip], (int) $assignment->port); } else { - $additionalAssignments[ (string) $assignment->ip ] = [ (int) $assignment->port ]; + $additionalAssignments[(string) $assignment->ip] = [(int) $assignment->port]; } } @@ -621,22 +634,23 @@ class ServerRepository // This won't be committed unless the HTTP request succeedes anyways $server->save(); - if (!empty($newBuild)) { + if (! empty($newBuild)) { $node = Models\Node::getByID($server->node); $client = Models\Node::guzzleRequest($server->node); $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ - 'build' => $newBuild - ] + 'build' => $newBuild, + ], ]); } DB::commit(); + return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -645,12 +659,10 @@ class ServerRepository DB::rollBack(); throw $ex; } - } public function updateStartup($id, array $data, $admin = false) { - $server = Models\Server::findOrFail($id); DB::beginTransaction(); @@ -672,24 +684,24 @@ class ServerRepository $variableList = []; if ($variables) { - foreach($variables as &$variable) { + foreach ($variables as &$variable) { // Move on if the new data wasn't even sent - if (!isset($data[$variable->env_variable])) { - $variableList = array_merge($variableList, [[ + if (! isset($data[$variable->env_variable])) { + $variableList[] = [ 'id' => $variable->id, 'env' => $variable->env_variable, - 'val' => $variable->a_currentValue - ]]); + 'val' => $variable->a_currentValue, + ]; continue; } // Update Empty but skip validation if (empty($data[$variable->env_variable])) { - $variableList = array_merge($variableList, [[ + $variableList[] = [ 'id' => $variable->id, 'env' => $variable->env_variable, - 'val' => null - ]]); + 'val' => null, + ]; continue; } @@ -702,37 +714,34 @@ class ServerRepository } // Variable hidden and/or not user editable - if (($variable->user_viewable === 0 || $variable->user_editable === 0) && !$admin) { + if (($variable->user_viewable === 0 || $variable->user_editable === 0) && ! $admin) { throw new DisplayException('A service option variable field (' . $variable->env_variable . ') does not exist or you do not have permission to edit it.'); } // Check aganist Regex Pattern - if (!is_null($variable->regex) && !preg_match($variable->regex, $data[$variable->env_variable])) { + if (! is_null($variable->regex) && ! preg_match($variable->regex, $data[$variable->env_variable])) { throw new DisplayException('Failed to validate service option variable field (' . $variable->env_variable . ') aganist regex (' . $variable->regex . ').'); } - $variableList = array_merge($variableList, [[ + $variableList[] = [ 'id' => $variable->id, 'env' => $variable->env_variable, - 'val' => $data[$variable->env_variable] - ]]); + 'val' => $data[$variable->env_variable], + ]; } } // Add Variables - $environmentVariables = []; - $environmentVariables = array_merge($environmentVariables, [ - 'STARTUP' => $server->startup - ]); - foreach($variableList as $item) { - $environmentVariables = array_merge($environmentVariables, [ - $item['env'] => $item['val'] - ]); + $environmentVariables = [ + 'STARTUP' => $server->startup, + ]; + foreach ($variableList as $item) { + $environmentVariables[$item['env']] = $item['val']; // Update model or make a new record if it doesn't exist. $model = Models\ServerVariables::firstOrNew([ 'variable_id' => $item['id'], - 'server_id' => $server->id + 'server_id' => $server->id, ]); $model->variable_value = $item['val']; $model->save(); @@ -744,16 +753,17 @@ class ServerRepository $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ 'build' => [ - 'env|overwrite' => $environmentVariables - ] - ] + 'env|overwrite' => $environmentVariables, + ], + ], ]); DB::commit(); + return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -762,7 +772,6 @@ class ServerRepository DB::rollBack(); throw $ex; } - } public function deleteServer($id, $force) @@ -777,22 +786,22 @@ class ServerRepository } $server->delete(); - DB::commit(); - event(new ServerDeleted($server->id)); + return DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } } - public function deleteNow($id, $force = false) { + public function deleteNow($id, $force = false) + { $server = Models\Server::withTrashed()->findOrFail($id); $node = Models\Node::findOrFail($server->node); // Handle server being restored previously or // an accidental queue. - if (!$server->trashed()) { + if (! $server->trashed()) { return; } @@ -800,7 +809,7 @@ class ServerRepository try { // Unassign Allocations Models\Allocation::where('assigned_to', $server->id)->update([ - 'assigned_to' => null + 'assigned_to' => null, ]); // Remove Variables @@ -822,7 +831,7 @@ class ServerRepository // This is the one un-recoverable point where // transactions will not save us. $repository = new DatabaseRepository; - foreach(Models\Database::select('id')->where('server_id', $server->id)->get() as &$database) { + foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as &$database) { $repository->drop($database->id); } @@ -830,8 +839,8 @@ class ServerRepository $client->request('DELETE', '/servers', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, - 'X-Access-Server' => $server->uuid - ] + 'X-Access-Server' => $server->uuid, + ], ]); $server->forceDelete(); @@ -867,13 +876,14 @@ class ServerRepository throw new DisplayException('This server was marked as having a failed install, you cannot override this.'); } $server->installed = ($server->installed === 1) ? 0 : 1; + return $server->save(); } /** * Suspends a server instance making it unable to be booted or used by a user. - * @param integer $id - * @return boolean + * @param int $id + * @return bool */ public function suspend($id, $deleted = false) { @@ -896,8 +906,8 @@ class ServerRepository $client->request('POST', '/server/suspend', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, - 'X-Access-Server' => $server->uuid - ] + 'X-Access-Server' => $server->uuid, + ], ]); return DB::commit(); @@ -912,8 +922,8 @@ class ServerRepository /** * Unsuspends a server instance. - * @param integer $id - * @return boolean + * @param int $id + * @return bool */ public function unsuspend($id) { @@ -936,8 +946,8 @@ class ServerRepository $client->request('POST', '/server/unsuspend', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, - 'X-Access-Server' => $server->uuid - ] + 'X-Access-Server' => $server->uuid, + ], ]); return DB::commit(); @@ -958,7 +968,7 @@ class ServerRepository $validator = Validator::make([ 'password' => $password, ], [ - 'password' => 'required|regex:/^((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})$/' + 'password' => 'required|regex:/^((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})$/', ]); if ($validator->fails()) { @@ -975,7 +985,7 @@ class ServerRepository $client->request('POST', '/server/password', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, - 'X-Access-Server' => $server->uuid + 'X-Access-Server' => $server->uuid, ], 'json' => [ 'password' => $password, @@ -983,6 +993,7 @@ class ServerRepository ]); DB::commit(); + return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -991,7 +1002,5 @@ class ServerRepository DB::rollBack(); throw $ex; } - } - } diff --git a/app/Repositories/ServiceRepository/Option.php b/app/Repositories/ServiceRepository/Option.php index 60476b50e..8ddcdc006 100644 --- a/app/Repositories/ServiceRepository/Option.php +++ b/app/Repositories/ServiceRepository/Option.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,20 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories\ServiceRepository; use DB; use Validator; - use Pterodactyl\Models; -use Pterodactyl\Services\UuidService; - use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class Option { - public function __construct() { // @@ -50,7 +47,7 @@ class Option 'tag' => 'required|string|max:255', 'executable' => 'sometimes|string|max:255', 'docker_image' => 'required|string|max:255', - 'startup' => 'sometimes|string' + 'startup' => 'sometimes|string', ]); if ($validator->fails()) { @@ -105,7 +102,7 @@ class Option 'tag' => 'sometimes|required|string|max:255', 'executable' => 'sometimes|string|max:255', 'docker_image' => 'sometimes|required|string|max:255', - 'startup' => 'sometimes|string' + 'startup' => 'sometimes|string', ]); if ($validator->fails()) { @@ -121,7 +118,7 @@ class Option } $option->fill($data); - $option->save(); - } + return $option->save(); + } } diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php new file mode 100644 index 000000000..03858ed67 --- /dev/null +++ b/app/Repositories/ServiceRepository/Pack.php @@ -0,0 +1,196 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Repositories\ServiceRepository; + +use DB; +use Uuid; +use Storage; +use Validator; +use Pterodactyl\Models; +use Pterodactyl\Services\UuidService; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +class Pack +{ + public function __construct() + { + // + } + + public function create(array $data) + { + $validator = Validator::make($data, [ + 'name' => 'required|string', + 'version' => 'required|string', + 'description' => 'sometimes|nullable|string', + 'option' => 'required|exists:service_options,id', + 'selectable' => 'sometimes|boolean', + 'visible' => 'sometimes|boolean', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + if (isset($data['file_upload'])) { + if (! $data['file_upload']->isValid()) { + throw new DisplayException('The file provided does not appear to be valid.'); + } + + if (! in_array($data['file_upload']->getMimeType(), ['application/gzip', 'application/x-gzip'])) { + throw new DisplayException('The file provided (' . $data['file_upload']->getMimeType() . ') does not meet the required filetype of application/gzip.'); + } + } + + DB::beginTransaction(); + try { + $uuid = new UuidService; + $pack = Models\ServicePack::create([ + 'option' => $data['option'], + 'uuid' => $uuid->generate('servers', 'uuid'), + 'name' => $data['name'], + 'version' => $data['version'], + 'description' => (empty($data['description'])) ? null : $data['description'], + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']), + ]); + + Storage::makeDirectory('packs/' . $pack->uuid); + if (isset($data['file_upload'])) { + $data['file_upload']->storeAs('packs/' . $pack->uuid, 'archive.tar.gz'); + } + + DB::commit(); + } catch (\Exception $ex) { + DB::rollBack(); + throw $ex; + } + + return $pack->id; + } + + public function createWithTemplate(array $data) + { + if (! isset($data['file_upload'])) { + throw new DisplayException('No template file was found submitted with this request.'); + } + + if (! $data['file_upload']->isValid()) { + throw new DisplayException('The file provided does not appear to be valid.'); + } + + if (! in_array($data['file_upload']->getMimeType(), [ + 'application/zip', + 'text/plain', + 'application/json', + ])) { + throw new DisplayException('The file provided (' . $data['file_upload']->getMimeType() . ') does not meet the required filetypes of application/zip or application/json.'); + } + + if ($data['file_upload']->getMimeType() === 'application/zip') { + $zip = new \ZipArchive; + if (! $zip->open($data['file_upload']->path())) { + throw new DisplayException('The uploaded archive was unable to be opened.'); + } + + $isTar = $zip->locateName('archive.tar.gz'); + + if (! $zip->locateName('import.json') || ! $isTar) { + throw new DisplayException('This contents of the provided archive were in an invalid format.'); + } + + $json = json_decode($zip->getFromName('import.json')); + $id = $this->create([ + 'name' => $json->name, + 'version' => $json->version, + 'description' => $json->description, + 'option' => $data['option'], + 'selectable' => $json->selectable, + 'visible' => $json->visible, + ]); + + $pack = Models\ServicePack::findOrFail($id); + if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), 'archive.tar.gz')) { + $pack->delete(); + throw new DisplayException('Unable to extract the archive file to the correct location.'); + } + + $zip->close(); + + return $pack->id; + } else { + $json = json_decode(file_get_contents($data['file_upload']->path())); + + return $this->create([ + 'name' => $json->name, + 'version' => $json->version, + 'description' => $json->description, + 'option' => $data['option'], + 'selectable' => $json->selectable, + 'visible' => $json->visible, + ]); + } + } + + public function update($id, array $data) + { + $validator = Validator::make($data, [ + 'name' => 'required|string', + 'version' => 'required|string', + 'description' => 'string', + 'option' => 'required|exists:service_options,id', + 'selectable' => 'sometimes|boolean', + 'visible' => 'sometimes|boolean', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + DB::transaction(function () use ($id, $data) { + Models\ServicePack::findOrFail($id)->update([ + 'option' => $data['option'], + 'name' => $data['name'], + 'version' => $data['version'], + 'description' => (empty($data['description'])) ? null : $data['description'], + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']), + ]); + + return true; + }); + } + + public function delete($id) + { + $pack = Models\ServicePack::findOrFail($id); + // @TODO Check for linked servers; foreign key should block this. + DB::transaction(function () use ($pack) { + $pack->delete(); + Storage::deleteDirectory('packs/' . $pack->uuid); + }); + } +} diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 8feb92c1e..eb41a9fee 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,21 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories\ServiceRepository; use DB; -use Validator; use Uuid; - +use Storage; +use Validator; use Pterodactyl\Models; -use Pterodactyl\Services\UuidService; - use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class Service { - public function __construct() { // @@ -46,24 +44,32 @@ class Service $validator = Validator::make($data, [ 'name' => 'required|string|min:1|max:255', 'description' => 'required|string', - 'file' => 'required|regex:/^[\w.-]{1,50}$/', + 'file' => 'required|unique:services,file|regex:/^[\w.-]{1,50}$/', 'executable' => 'max:255|regex:/^(.*)$/', - 'startup' => 'string' + 'startup' => 'string', ]); if ($validator->fails()) { throw new DisplayValidationException($validator->errors()); } - if (Models\Service::where('file', $data['file'])->first()) { - throw new DisplayException('A service using that configuration file already exists on the system.'); - } - $data['author'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); $service = new Models\Service; - $service->fill($data); - $service->save(); + DB::beginTransaction(); + + try { + $service->fill($data); + $service->save(); + + Storage::put('services/' . $data['file'] . '/main.json', '{}'); + Storage::copy('services/.templates/index.js', 'services/' . $data['file'] . '/index.js'); + + DB::commit(); + } catch (\Exception $ex) { + DB::rollBack(); + throw $ex; + } return $service->id; } @@ -77,7 +83,7 @@ class Service 'description' => 'sometimes|required|string', 'file' => 'sometimes|required|regex:/^[\w.-]{1,50}$/', 'executable' => 'sometimes|max:255|regex:/^(.*)$/', - 'startup' => 'sometimes|string' + 'startup' => 'sometimes|string', ]); if ($validator->fails()) { @@ -85,7 +91,8 @@ class Service } $service->fill($data); - $service->save(); + + return $service->save(); } public function delete($id) @@ -103,6 +110,8 @@ class Service Models\ServiceVariables::whereIn('option_id', $options->get()->toArray())->delete(); $options->delete(); $service->delete(); + + Storage::deleteDirectory('services/' . $service->file); DB::commit(); } catch (\Exception $ex) { DB::rollBack(); @@ -110,4 +119,29 @@ class Service } } + public function updateFile($id, array $data) + { + $service = Models\Service::findOrFail($id); + + $validator = Validator::make($data, [ + 'file' => 'required|in:index,main', + 'contents' => 'required|string', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + $filename = ($data['file'] === 'main') ? 'main.json' : 'index.js'; + $filepath = 'services/' . $service->file . '/' . $filename; + $backup = 'services/.bak/' . str_random(12) . '.bak'; + + try { + Storage::move($filepath, $backup); + Storage::put($filepath, $data['contents']); + } catch (\Exception $ex) { + Storage::move($backup, $filepath); + throw $ex; + } + } } diff --git a/app/Repositories/ServiceRepository/Variable.php b/app/Repositories/ServiceRepository/Variable.php index 154a8b061..fbd258444 100644 --- a/app/Repositories/ServiceRepository/Variable.php +++ b/app/Repositories/ServiceRepository/Variable.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,20 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories\ServiceRepository; use DB; use Validator; - use Pterodactyl\Models; -use Pterodactyl\Services\UuidService; - use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class Variable { - public function __construct() { // @@ -52,14 +49,14 @@ class Variable 'user_viewable' => 'sometimes|required|numeric|size:1', 'user_editable' => 'sometimes|required|numeric|size:1', 'required' => 'sometimes|required|numeric|size:1', - 'regex' => 'required|string|min:1' + 'regex' => 'required|string|min:1', ]); if ($validator->fails()) { throw new DisplayValidationException($validator->errors()); } - if ($data['default_value'] !== '' && !preg_match($data['regex'], $data['default_value'])) { + if ($data['default_value'] !== '' && ! preg_match($data['regex'], $data['default_value'])) { throw new DisplayException('The default value you entered cannot violate the regex requirements.'); } @@ -74,10 +71,12 @@ class Variable $variable = new Models\ServiceVariables; $variable->option_id = $option->id; $variable->fill($data); - $variable->save(); + + return $variable->save(); } - public function delete($id) { + public function delete($id) + { $variable = Models\ServiceVariables::findOrFail($id); DB::beginTransaction(); @@ -104,7 +103,7 @@ class Variable 'user_viewable' => 'sometimes|required|numeric|boolean', 'user_editable' => 'sometimes|required|numeric|boolean', 'required' => 'sometimes|required|numeric|boolean', - 'regex' => 'sometimes|required|string|min:1' + 'regex' => 'sometimes|required|string|min:1', ]); if ($validator->fails()) { @@ -114,7 +113,7 @@ class Variable $data['default_value'] = (isset($data['default_value'])) ? $data['default_value'] : $variable->default_value; $data['regex'] = (isset($data['regex'])) ? $data['regex'] : $variable->regex; - if ($data['default_value'] !== '' && !preg_match($data['regex'], $data['default_value'])) { + if ($data['default_value'] !== '' && ! preg_match($data['regex'], $data['default_value'])) { throw new DisplayException('The default value you entered cannot violate the regex requirements.'); } @@ -127,7 +126,7 @@ class Variable $data['required'] = (isset($data['required']) && in_array((int) $data['required'], [0, 1])) ? $data['required'] : $variable->required; $variable->fill($data); - $variable->save(); - } + return $variable->save(); + } } diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index 1e812a14a..afa27493e 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,23 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; use DB; +use Mail; use Settings; use Validator; -use Mail; - use Pterodactyl\Models; -use Pterodactyl\Repositories\UserRepository; use Pterodactyl\Services\UuidService; - -use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; class SubuserRepository { - /** * Core permissions required for every subuser on the daemon. * Without this we cannot connect the websocket or get basic @@ -46,7 +43,7 @@ class SubuserRepository */ protected $coreDaemonPermissions = [ 's:get', - 's:console' + 's:console', ]; /** @@ -101,7 +98,7 @@ class SubuserRepository // Databases 'view-databases' => null, - 'reset-db-password' => null + 'reset-db-password' => null, ]; public function __construct() @@ -111,18 +108,19 @@ class SubuserRepository /** * Creates a new subuser on the server. - * @param integer $id The ID of the server to add this subuser to. + * @param int $id The ID of the server to add this subuser to. * @param array $data * @throws DisplayValidationException * @throws DisplayException - * @return integer Returns the ID of the newly created subuser. + * @return int Returns the ID of the newly created subuser. */ public function create($sid, array $data) { $server = Models\Server::findOrFail($sid); + $validator = Validator::make($data, [ 'permissions' => 'required|array', - 'email' => 'required|email' + 'email' => 'required|email', ]); if ($validator->fails()) { @@ -134,15 +132,24 @@ class SubuserRepository try { // Determine if this user exists or if we need to make them an account. $user = Models\User::where('email', $data['email'])->first(); - if (!$user) { - $password = str_random(16); + if (! $user) { try { $repo = new UserRepository; - $uid = $repo->create($data['email'], $password); + $uid = $repo->create([ + 'email' => $data['email'], + 'username' => substr(str_replace('@', '', $data['email']), 0, 8), + 'name_first' => 'John', + 'name_last' => 'Doe', + 'root_admin' => false, + ]); $user = Models\User::findOrFail($uid); } catch (\Exception $ex) { throw $ex; } + } elseif ($server->owner === $user->id) { + throw new DisplayException('You cannot add the owner of a server as a subuser.'); + } elseif (Models\Subuser::select('id')->where('user_id', $user->id)->where('server_id', $server->id)->first()) { + throw new DisplayException('A subuser with that email already exists for this server.'); } $uuid = new UuidService; @@ -151,22 +158,23 @@ class SubuserRepository $subuser->fill([ 'user_id' => $user->id, 'server_id' => $server->id, - 'daemonSecret' => (string) $uuid->generate('servers', 'uuid') + 'daemonSecret' => (string) $uuid->generate('servers', 'uuid'), ]); $subuser->save(); $daemonPermissions = $this->coreDaemonPermissions; - foreach($data['permissions'] as $permission) { + foreach ($data['permissions'] as $permission) { if (array_key_exists($permission, $this->permissions)) { // Build the daemon permissions array for sending. - if (!is_null($this->permissions[$permission])) { + if (! is_null($this->permissions[$permission])) { array_push($daemonPermissions, $this->permissions[$permission]); } + $model = new Models\Permission; $model->fill([ 'user_id' => $user->id, 'server_id' => $server->id, - 'permission' => $permission + 'permission' => $permission, ]); $model->save(); } @@ -182,13 +190,13 @@ class SubuserRepository $res = $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ 'keys' => [ - $subuser->daemonSecret => $daemonPermissions - ] - ] + $subuser->daemonSecret => $daemonPermissions, + ], + ], ]); $email = $data['email']; @@ -201,6 +209,7 @@ class SubuserRepository $message->subject(Settings::get('company') . ' - Added to Server'); }); DB::commit(); + return $subuser->id; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -209,12 +218,13 @@ class SubuserRepository DB::rollBack(); throw $ex; } + return false; } /** * Revokes a users permissions on a server. - * @param integer $id The ID of the subuser row in MySQL. + * @param int $id The ID of the subuser row in MySQL. * @param array $data * @throws DisplayValidationException * @throws DisplayException @@ -236,17 +246,18 @@ class SubuserRepository $res = $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ 'keys' => [ - $subuser->daemonSecret => [] - ] - ] + $subuser->daemonSecret => [], + ], + ], ]); $subuser->delete(); DB::commit(); + return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -255,12 +266,13 @@ class SubuserRepository DB::rollBack(); throw $ex; } + return false; } /** * Updates permissions for a given subuser. - * @param integer $id The ID of the subuser row in MySQL. (Not the user ID) + * @param int $id The ID of the subuser row in MySQL. (Not the user ID) * @param array $data * @throws DisplayValidationException * @throws DisplayException @@ -287,17 +299,17 @@ class SubuserRepository Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); $daemonPermissions = $this->coreDaemonPermissions; - foreach($data['permissions'] as $permission) { + foreach ($data['permissions'] as $permission) { if (array_key_exists($permission, $this->permissions)) { // Build the daemon permissions array for sending. - if (!is_null($this->permissions[$permission])) { + if (! is_null($this->permissions[$permission])) { array_push($daemonPermissions, $this->permissions[$permission]); } $model = new Models\Permission; $model->fill([ 'user_id' => $data['user'], 'server_id' => $data['server'], - 'permission' => $permission + 'permission' => $permission, ]); $model->save(); } @@ -312,16 +324,17 @@ class SubuserRepository $res = $client->request('PATCH', '/server', [ 'headers' => [ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret + 'X-Access-Token' => $node->daemonSecret, ], 'json' => [ 'keys' => [ - $subuser->daemonSecret => $daemonPermissions - ] - ] + $subuser->daemonSecret => $daemonPermissions, + ], + ], ]); DB::commit(); + return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); @@ -330,7 +343,7 @@ class SubuserRepository DB::rollBack(); throw $ex; } + return false; } - } diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index 5722ab929..c42a00482 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,19 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; use Cron; use Validator; - use Pterodactyl\Models; - -use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; class TaskRepository { - protected $defaults = [ 'year' => '*', 'day_of_week' => '*', @@ -64,6 +62,7 @@ class TaskRepository $task = Models\Task::findOrFail($id); try { $task->delete(); + return true; } catch (\Exception $ex) { throw $ex; @@ -111,20 +110,20 @@ class TaskRepository 'month' => 'string|sometimes', 'day_of_month' => 'string|sometimes', 'hour' => 'string|sometimes', - 'minute' => 'string|sometimes' + 'minute' => 'string|sometimes', ]); if ($validator->fails()) { throw new DisplayValidationException(json_encode($validator->errors())); } - if (!in_array($data['action'], $this->actions)) { + if (! in_array($data['action'], $this->actions)) { throw new DisplayException('The action provided is not valid.'); } $cron = $this->defaults; foreach ($this->defaults as $setting => $value) { - if (array_key_exists($setting, $data) && !is_null($data[$setting]) && $data[$setting] !== '') { + if (array_key_exists($setting, $data) && ! is_null($data[$setting]) && $data[$setting] !== '') { $cron[$setting] = $data[$setting]; } } @@ -157,11 +156,9 @@ class TaskRepository 'hour' => $cron['hour'], 'minute' => $cron['minute'], 'last_run' => null, - 'next_run' => $buildCron->getNextRunDate() + 'next_run' => $buildCron->getNextRunDate(), ]); return $task->save(); - } - } diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 01cad4269..b46727e1b 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -1,8 +1,8 @@ - * Some Modifications (c) 2015 Dylan Seidt + * Copyright (c) 2015 - 2017 Dane Everitt + * Some Modifications (c) 2015 Dylan Seidt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,26 +22,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Repositories; use DB; -use Settings; -use Hash; -use Validator; -use Mail; -use Carbon; use Auth; - +use Hash; +use Carbon; +use Settings; +use Validator; use Pterodactyl\Models; use Pterodactyl\Services\UuidService; -use Pterodactyl\Notifications\AccountCreated; - -use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Notifications\AccountCreated; +use Pterodactyl\Exceptions\DisplayValidationException; class UserRepository { - public function __construct() { // @@ -54,20 +51,18 @@ class UserRepository * @param string|null $password An unhashed version of the user's password. * @param bool $admin Boolean value if user should be an admin or not. * @param int $token A custom user ID. - * @return bool|integer + * @return bool|int */ - public function create($email, $password = null, $admin = false, $token = null) + public function create(array $data) { - $validator = Validator::make([ - 'email' => $email, - 'password' => $password, - 'root_admin' => $admin, - 'custom_id' => $token, - ], [ + $validator = Validator::make($data, [ 'email' => 'required|email|unique:users,email', - 'password' => 'nullable|regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})', + 'username' => 'required|string|between:1,255|unique:users,username|' . Models\User::USERNAME_RULES, + 'name_first' => 'required|string|between:1,255', + 'name_last' => 'required|string|between:1,255', + 'password' => 'sometimes|nullable|' . Models\User::PASSWORD_RULES, 'root_admin' => 'required|boolean', - 'custom_id' => 'nullable|unique:users,id', + 'custom_id' => 'sometimes|nullable|unique:users,id', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -83,28 +78,39 @@ class UserRepository $uuid = new UuidService; // Support for API Services - if (!is_null($token)) { + if (isset($data['custom_id']) && ! is_null($data['custom_id'])) { $user->id = $token; } + // UUIDs are not mass-fillable. $user->uuid = $uuid->generate('users', 'uuid'); - $user->email = $email; - $user->password = Hash::make((is_null($password)) ? str_random(30) : $password); - $user->language = 'en'; - $user->root_admin = ($admin) ? 1 : 0; + + $user->fill([ + 'email' => $data['email'], + 'username' => $data['username'], + 'name_first' => $data['name_first'], + 'name_last' => $data['name_last'], + 'password' => Hash::make((empty($data['password'])) ? str_random(30) : $data['password']), + 'root_admin' => $data['root_admin'], + 'language' => Settings::get('default_language', 'en'), + ]); $user->save(); // Setup a Password Reset to use when they set a password. - $token = str_random(32); - DB::table('password_resets')->insert([ - 'email' => $user->email, - 'token' => $token, - 'created_at' => Carbon::now()->toDateTimeString() - ]); + // Only used if no password is provided. + if (empty($data['password'])) { + $token = str_random(32); + DB::table('password_resets')->insert([ + 'email' => $user->email, + 'token' => $token, + 'created_at' => Carbon::now()->toDateTimeString(), + ]); - $user->notify((new AccountCreated($token))); + $user->notify((new AccountCreated($token))); + } DB::commit(); + return $user->id; } catch (\Exception $ex) { DB::rollBack(); @@ -115,9 +121,9 @@ class UserRepository /** * Updates a user on the panel. * - * @param integer $id + * @param int $id * @param array $data An array of columns and their associated values to update for the user. - * @return boolean + * @return bool */ public function update($id, array $data) { @@ -125,11 +131,14 @@ class UserRepository $validator = Validator::make($data, [ 'email' => 'sometimes|required|email|unique:users,email,' . $id, - 'password' => 'sometimes|required|regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})', + 'username' => 'sometimes|required|string|between:1,255|unique:users,username,' . $user->id . '|' . Models\User::USERNAME_RULES, + 'name_first' => 'sometimes|required|string|between:1,255', + 'name_last' => 'sometimes|required|string|between:1,255', + 'password' => 'sometimes|nullable|' . Models\User::PASSWORD_RULES, 'root_admin' => 'sometimes|required|boolean', 'language' => 'sometimes|required|string|min:1|max:5', 'use_totp' => 'sometimes|required|boolean', - 'totp_secret' => 'sometimes|required|size:16' + 'totp_secret' => 'sometimes|required|size:16', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -138,33 +147,33 @@ class UserRepository throw new DisplayValidationException($validator->errors()); } - if(array_key_exists('password', $data)) { + // The password and root_admin fields are not mass assignable. + if (! empty($data['password'])) { $data['password'] = Hash::make($data['password']); - } - - if (isset($data['password_confirmation'])) { - unset($data['password_confirmation']); + } else { + unset($data['password']); } $user->fill($data); - $user->save(); + + return $user->save(); } /** * Deletes a user on the panel, returns the number of records deleted. * - * @param integer $id - * @return integer + * @param int $id + * @return int */ public function delete($id) { - if(Models\Server::where('owner', $id)->count() > 0) { + if (Models\Server::where('owner', $id)->count() > 0) { throw new DisplayException('Cannot delete a user with active servers attached to thier account.'); } // @TODO: this should probably be checked outside of this method because we won't always have Auth::user() - if(!is_null(Auth::user()) && Auth::user()->id === $id) { - throw new DisplayException('Cannot delete your own account.'); + if (! is_null(Auth::user()) && Auth::user()->id === $id) { + throw new DisplayException('Cannot delete your own account.'); } DB::beginTransaction(); @@ -175,11 +184,11 @@ class UserRepository Models\User::destroy($id); DB::commit(); + return true; } catch (\Exception $ex) { DB::rollBack(); throw $ex; } } - } diff --git a/app/Services/APILogService.php b/app/Services/APILogService.php index f1d8255be..f43693aca 100644 --- a/app/Services/APILogService.php +++ b/app/Services/APILogService.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Services; use Log; - use Illuminate\Http\Request; use Pterodactyl\Models\APILog; class APILogService { - public function __constructor() { // @@ -38,7 +37,7 @@ class APILogService public static function log(Request $request, $error = null, $authorized = false) { - if ($request->bearerToken() && !empty($request->bearerToken())) { + if ($request->bearerToken() && ! empty($request->bearerToken())) { list($public, $hashed) = explode('.', $request->bearerToken()); } else { $public = null; @@ -53,7 +52,7 @@ class APILogService 'route' => $request->fullUrl(), 'content' => (empty($request->getContent())) ? null : $request->getContent(), 'user_agent' => $request->header('User-Agent'), - 'request_ip' => $request->ip() + 'request_ip' => $request->ip(), ]); $log->save(); } catch (\Exception $ex) { diff --git a/app/Services/DeploymentService.php b/app/Services/DeploymentService.php index 5d0c7d5e1..5f2a99473 100644 --- a/app/Services/DeploymentService.php +++ b/app/Services/DeploymentService.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Services; use DB; - use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; class DeploymentService { - public function __constructor() { // @@ -62,12 +61,12 @@ class DeploymentService public static function randomNode($location, array $not = []) { $useLocation = Models\Location::where('id', $location)->first(); - if (!$useLocation) { - throw new DisplayException("The location passed was not valid and could not be found."); + if (! $useLocation) { + throw new DisplayException('The location passed was not valid and could not be found.'); } $node = Models\Node::where('location', $useLocation->id)->where('public', 1)->whereNotIn('id', $not)->inRandomOrder()->first(); - if (!$node) { + if (! $node) { throw new DisplayException("Unable to find a node in location {$useLocation->short} (id: {$useLocation->id}) that is available and has space."); } @@ -84,18 +83,19 @@ class DeploymentService * * @throws \Pterodactyl\Exceptions\DisplayException */ - public static function smartRandomNode($memory, $disk, $location = null) { + public static function smartRandomNode($memory, $disk, $location = null) + { $node = self::randomNode($location); $notIn = []; do { $return = self::checkNodeAllocation($node, $memory, $disk); - if (!$return) { + if (! $return) { $notIn = array_merge($notIn, [ - $node->id + $node->id, ]); $node = self::randomNode($location, $notIn); } - } while (!$return); + } while (! $return); return $node; } @@ -108,7 +108,7 @@ class DeploymentService public static function randomAllocation($node) { $allocation = Models\Allocation::where('node', $node)->whereNull('assigned_to')->inRandomOrder()->first(); - if (!$allocation) { + if (! $allocation) { throw new DisplayException('No available allocation could be found for the assigned node.'); } @@ -139,7 +139,7 @@ class DeploymentService $diskLimitReached = (($totals->disk + $disk) > $limit); } - return (!$diskLimitReached && !$memoryLimitReached); + return ! $diskLimitReached && ! $memoryLimitReached; } } } diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index 0ae6192f9..bb76db9b6 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,15 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Services; -use Pterodactyl\Models\Server; use Pterodactyl\Models\User; - +use Pterodactyl\Models\Server; use Pterodactyl\Notifications\Daemon; -class NotificationService { - +class NotificationService +{ protected $server; protected $user; @@ -53,7 +53,7 @@ class NotificationService { public function pass(array $notification) { - if (!$notification->type) { + if (! $notification->type) { return; } diff --git a/app/Services/UuidService.php b/app/Services/UuidService.php index 430c82f82..6f81f1465 100644 --- a/app/Services/UuidService.php +++ b/app/Services/UuidService.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Services; use DB; @@ -28,9 +29,8 @@ use Uuid; class UuidService { - /** - * Constructor + * Constructor. */ public function __construct() { @@ -39,28 +39,24 @@ class UuidService /** * Generate a unique UUID validating against specified table and column. - * Defaults to `users.uuid` + * Defaults to `users.uuid`. * * @param string $table * @param string $field - * @param integer $type The type of UUID to generate. + * @param int $type The type of UUID to generate. * @return string */ public function generate($table = 'users', $field = 'uuid', $type = 4) { - $return = false; do { - $uuid = Uuid::generate($type); - if (!DB::table($table)->where($field, $uuid)->exists()) { + if (! DB::table($table)->where($field, $uuid)->exists()) { $return = $uuid; } - - } while (!$return); + } while (! $return); return (string) $return; - } /** @@ -72,21 +68,16 @@ class UuidService */ public function generateShort($table = 'servers', $field = 'uuidShort', $attachedUuid = null) { - $return = false; do { - $short = (is_null($attachedUuid)) ? substr(Uuid::generate(4), 0, 8) : substr($attachedUuid, 0, 8); $attachedUuid = null; - if (!DB::table($table)->where($field, $short)->exists()) { + if (! DB::table($table)->where($field, $short)->exists()) { $return = $short; } - - } while (!$return); + } while (! $return); return (string) $return; - } - } diff --git a/app/Services/VersionService.php b/app/Services/VersionService.php new file mode 100644 index 000000000..d12c77760 --- /dev/null +++ b/app/Services/VersionService.php @@ -0,0 +1,92 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Services; + +use Cache; +use GuzzleHttp\Client; + +class VersionService +{ + protected static $versions; + + /** + * Constructor. + */ + public function __construct() + { + self::$versions = Cache::remember('versions', env('VERSION_CACHE_TIME', 60), function () { + $client = new Client(); + + try { + $response = $client->request('GET', env('VERSION_CHECK_URL', 'https://cdn.pterodactyl.io/releases/latest.json')); + + if ($response->getStatusCode() === 200) { + return json_decode($response->getBody()); + } else { + throw new \Exception('Invalid response code.'); + } + } catch (\Exception $ex) { + // Failed request, just return errored version. + return (object) [ + 'panel' => 'error', + 'daemon' => 'error', + ]; + } + }); + } + + public static function getPanel() + { + return self::$versions->panel; + } + + public static function getDaemon() + { + return self::$versions->daemon; + } + + public function getCurrentPanel() + { + return config('app.version'); + } + + public static function isLatestPanel() + { + if (config('app.version') === 'canary') { + return true; + } + + return version_compare(config('app.version'), self::$versions->panel) >= 0; + } + + public static function isLatestDaemon($daemon) + { + if ($daemon === '0.0.0-canary') { + return true; + } + + return version_compare($daemon, self::$versions->daemon) >= 0; + } +} diff --git a/app/Transformers/AllocationTransformer.php b/app/Transformers/AllocationTransformer.php index 2ab9e5b1f..8ca06a9c8 100644 --- a/app/Transformers/AllocationTransformer.php +++ b/app/Transformers/AllocationTransformer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Transformers; use Pterodactyl\Models\Allocation; @@ -28,9 +29,8 @@ use League\Fractal\TransformerAbstract; class AllocationTransformer extends TransformerAbstract { - /** - * Turn this item object into a generic array + * Turn this item object into a generic array. * * @return array */ @@ -38,5 +38,4 @@ class AllocationTransformer extends TransformerAbstract { return array_except($allocation, ['created_at', 'updated_at']); } - } diff --git a/app/Transformers/NodeTransformer.php b/app/Transformers/NodeTransformer.php index 9b3224c37..01d707f37 100755 --- a/app/Transformers/NodeTransformer.php +++ b/app/Transformers/NodeTransformer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Transformers; use Pterodactyl\Models\Node; @@ -28,9 +29,8 @@ use League\Fractal\TransformerAbstract; class NodeTransformer extends TransformerAbstract { - /** - * Turn this item object into a generic array + * Turn this item object into a generic array. * * @return array */ @@ -38,5 +38,4 @@ class NodeTransformer extends TransformerAbstract { return $node; } - } diff --git a/app/Transformers/ServerTransformer.php b/app/Transformers/ServerTransformer.php index 482cf8419..12707cd04 100755 --- a/app/Transformers/ServerTransformer.php +++ b/app/Transformers/ServerTransformer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Transformers; use Pterodactyl\Models\Server; @@ -28,9 +29,8 @@ use League\Fractal\TransformerAbstract; class ServerTransformer extends TransformerAbstract { - /** - * Turn this item object into a generic array + * Turn this item object into a generic array. * * @return array */ @@ -38,5 +38,4 @@ class ServerTransformer extends TransformerAbstract { return $server; } - } diff --git a/app/Transformers/UserTransformer.php b/app/Transformers/UserTransformer.php index abd90c34d..c36baaa69 100755 --- a/app/Transformers/UserTransformer.php +++ b/app/Transformers/UserTransformer.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + namespace Pterodactyl\Transformers; use Pterodactyl\Models\User; @@ -28,9 +29,8 @@ use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { - /** - * Turn this item object into a generic array + * Turn this item object into a generic array. * * @return array */ @@ -38,5 +38,4 @@ class UserTransformer extends TransformerAbstract { return $user; } - } diff --git a/bootstrap/app.php b/bootstrap/app.php index 81378a886..f35c15929 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -12,7 +12,7 @@ */ $app = new Illuminate\Foundation\Application( - realpath(__DIR__.'/../') + realpath(__DIR__ . '/../') ); /* diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php index 383013796..0f7519510 100644 --- a/bootstrap/autoload.php +++ b/bootstrap/autoload.php @@ -14,7 +14,7 @@ define('LARAVEL_START', microtime(true)); | */ -require __DIR__.'/../vendor/autoload.php'; +require __DIR__ . '/../vendor/autoload.php'; /* |-------------------------------------------------------------------------- @@ -27,7 +27,7 @@ require __DIR__.'/../vendor/autoload.php'; | */ -$compiledPath = __DIR__.'/cache/compiled.php'; +$compiledPath = __DIR__ . '/cache/compiled.php'; if (file_exists($compiledPath)) { require $compiledPath; diff --git a/composer.json b/composer.json index b015adbd0..de637a3f4 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,9 @@ "dingo/api": "1.0.0-beta6", "aws/aws-sdk-php": "3.19.20", "predis/predis": "1.1.1", - "fideloper/proxy": "3.2.0" + "fideloper/proxy": "3.2.0", + "laracasts/utilities": "2.1.0", + "lord/laroute": "2.3.0" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/config/app.php b/config/app.php index 957848eae..dfed5c9ee 100644 --- a/config/app.php +++ b/config/app.php @@ -4,7 +4,7 @@ return [ 'env' => env('APP_ENV', 'production'), - 'version' => env('APP_VERSION', 'v0.5.0'), + 'version' => env('APP_VERSION', 'canary'), /* |-------------------------------------------------------------------------- @@ -159,6 +159,8 @@ return [ Prologue\Alerts\AlertsServiceProvider::class, Krucas\Settings\Providers\SettingsServiceProvider::class, Fideloper\Proxy\TrustedProxyServiceProvider::class, + Laracasts\Utilities\JavaScript\JavaScriptServiceProvider::class, + Lord\Laroute\LarouteServiceProvider::class, ], @@ -199,6 +201,7 @@ return [ 'Hash' => Illuminate\Support\Facades\Hash::class, 'Input' => Illuminate\Support\Facades\Input::class, 'Inspiring' => Illuminate\Foundation\Inspiring::class, + 'Javascript' => Laracasts\Utilities\JavaScript\JavaScriptFacade::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, @@ -218,6 +221,7 @@ return [ 'URL' => Illuminate\Support\Facades\URL::class, 'Uuid' => Webpatser\Uuid\Uuid::class, 'Validator' => Illuminate\Support\Facades\Validator::class, + 'Version' => Pterodactyl\Facades\Version::class, 'View' => Illuminate\Support\Facades\View::class, ], diff --git a/config/debugbar.php b/config/debugbar.php index bae876c70..4c1349b40 100644 --- a/config/debugbar.php +++ b/config/debugbar.php @@ -1,6 +1,6 @@ array( + 'storage' => [ 'enabled' => true, 'driver' => 'file', // redis, file, pdo 'path' => storage_path() . '/debugbar', // For file driver 'connection' => null, // Leave null for default connection (Redis/PDO) - ), + ], /* |-------------------------------------------------------------------------- @@ -81,7 +81,7 @@ return array( | */ - 'collectors' => array( + 'collectors' => [ 'phpinfo' => true, // Php version 'messages' => true, // Messages 'time' => true, // Time Datalogger @@ -102,7 +102,7 @@ return array( 'auth' => false, // Display Laravel authentication status 'gate' => false, // Display Laravel Gate checks 'session' => true, // Display session data - ), + ], /* |-------------------------------------------------------------------------- @@ -113,33 +113,33 @@ return array( | */ - 'options' => array( - 'auth' => array( + 'options' => [ + 'auth' => [ 'show_name' => false, // Also show the users name/email in the debugbar - ), - 'db' => array( + ], + 'db' => [ 'with_params' => true, // Render SQL with the parameters substituted 'timeline' => false, // Add the queries to the timeline 'backtrace' => false, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files. - 'explain' => array( // EXPERIMENTAL: Show EXPLAIN output on queries + 'explain' => [ // EXPERIMENTAL: Show EXPLAIN output on queries 'enabled' => false, - 'types' => array('SELECT'), // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ - ), + 'types' => ['SELECT'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ + ], 'hints' => true, // Show hints for common mistakes - ), - 'mail' => array( - 'full_log' => false - ), - 'views' => array( + ], + 'mail' => [ + 'full_log' => false, + ], + 'views' => [ 'data' => false, //Note: Can slow down the application, because the data can be quite large.. - ), - 'route' => array( - 'label' => true // show complete route on bar - ), - 'logs' => array( - 'file' => null - ), - ), + ], + 'route' => [ + 'label' => true, // show complete route on bar + ], + 'logs' => [ + 'file' => null, + ], + ], /* |-------------------------------------------------------------------------- @@ -166,4 +166,4 @@ return array( */ 'route_prefix' => '_debugbar', -); +]; diff --git a/config/javascript.php b/config/javascript.php new file mode 100644 index 000000000..2a5cda584 --- /dev/null +++ b/config/javascript.php @@ -0,0 +1,32 @@ + [ + 'layouts.master', + ], + + /* + |-------------------------------------------------------------------------- + | JavaScript Namespace + |-------------------------------------------------------------------------- + | + | By default, we'll add variables to the global window object. However, + | it's recommended that you change this to some namespace - anything. + | That way, you can access vars, like "SomeNamespace.someVariable." + | + */ + 'js_namespace' => 'Pterodactyl', + +]; diff --git a/config/laroute.php b/config/laroute.php new file mode 100644 index 000000000..7b332c40a --- /dev/null +++ b/config/laroute.php @@ -0,0 +1,58 @@ + 'public/js', + + /* + * The destination filename for the javascript file. + */ + 'filename' => 'laroute', + + /* + * The namespace for the helper functions. By default this will bind them to + * `window.laroute`. + */ + 'namespace' => 'Router', + + /* + * Generate absolute URLs + * + * Set the Application URL in config/app.php + */ + 'absolute' => false, + + /* + * The Filter Method + * + * 'all' => All routes except "'laroute' => false" + * 'only' => Only "'laroute' => true" routes + * 'force' => All routes, ignored "laroute" route parameter + */ + 'filter' => 'all', + + /* + * Controller Namespace + * + * Set here your controller namespace (see RouteServiceProvider -> $namespace) for cleaner action calls + * e.g. 'App\Http\Controllers' + */ + 'action_namespace' => '', + + /* + * The path to the template `laroute.js` file. This is the file that contains + * the ported helper Laravel url/route functions and the route data to go + * with them. + */ + 'template' => 'vendor/lord/laroute/src/templates/laroute.js', + + /* + * Appends a prefix to URLs. By default the prefix is an empty string. + * + */ + 'prefix' => '', + +]; diff --git a/config/themes.php b/config/themes.php index 870529767..03a0b6155 100644 --- a/config/themes.php +++ b/config/themes.php @@ -12,5 +12,10 @@ return [ 'views-path' => 'default', 'asset-path' => 'themes/default', ], + 'pterodactyl' => [ + 'extends' => null, + 'views-path' => 'pterodactyl', + 'asset-path' => 'themes/pterodactyl', + ], ], ]; diff --git a/database/migrations/2016_03_18_155649_add_nullable_field_lastrun.php b/database/migrations/2016_03_18_155649_add_nullable_field_lastrun.php index 65a0b3d9c..9065947d6 100644 --- a/database/migrations/2016_03_18_155649_add_nullable_field_lastrun.php +++ b/database/migrations/2016_03_18_155649_add_nullable_field_lastrun.php @@ -1,6 +1,5 @@ wrapTable('tasks'); - DB::statement('ALTER TABLE '.$table.' CHANGE `last_run` `last_run` TIMESTAMP NULL;'); + DB::statement('ALTER TABLE ' . $table . ' CHANGE `last_run` `last_run` TIMESTAMP NULL;'); } /** @@ -24,6 +23,6 @@ class AddNullableFieldLastrun extends Migration public function down() { $table = DB::getQueryGrammar()->wrapTable('tasks'); - DB::statement('ALTER TABLE '.$table.' CHANGE `last_run` `last_run` TIMESTAMP;'); + DB::statement('ALTER TABLE ' . $table . ' CHANGE `last_run` `last_run` TIMESTAMP;'); } } diff --git a/database/migrations/2016_08_30_212718_add_ip_alias.php b/database/migrations/2016_08_30_212718_add_ip_alias.php index 4726e5068..e75930edd 100644 --- a/database/migrations/2016_08_30_212718_add_ip_alias.php +++ b/database/migrations/2016_08_30_212718_add_ip_alias.php @@ -17,12 +17,12 @@ class AddIpAlias extends Migration }); $allocations = DB::select('SELECT id, ip FROM allocations'); - foreach($allocations as $allocation) { + foreach ($allocations as $allocation) { DB::update( 'UPDATE allocations SET ip_alias = :ip WHERE id = :id', [ 'ip' => $allocation->ip, - 'id' => $allocation->id + 'id' => $allocation->id, ] ); } diff --git a/database/migrations/2016_08_30_213301_modify_ip_storage_method.php b/database/migrations/2016_08_30_213301_modify_ip_storage_method.php index e49d335d5..b77ccbea6 100644 --- a/database/migrations/2016_08_30_213301_modify_ip_storage_method.php +++ b/database/migrations/2016_08_30_213301_modify_ip_storage_method.php @@ -18,13 +18,13 @@ class ModifyIpStorageMethod extends Migration // Parse All Servers $servers = DB::select('SELECT id, ip, port, node FROM servers'); - foreach($servers as $server) { + foreach ($servers as $server) { $allocation = DB::select( 'SELECT id FROM allocations WHERE ip = :ip AND port = :port AND node = :node', [ 'ip' => $server->ip, 'port' => $server->port, - 'node' => $server->node + 'node' => $server->node, ] ); @@ -33,7 +33,7 @@ class ModifyIpStorageMethod extends Migration 'UPDATE servers SET allocation = :alocid WHERE id = :id', [ 'alocid' => $allocation[0]->id, - 'id' => $server->id + 'id' => $server->id, ] ); } @@ -44,7 +44,6 @@ class ModifyIpStorageMethod extends Migration $table->dropColumn('ip'); $table->dropColumn('port'); }); - } /** @@ -54,7 +53,6 @@ class ModifyIpStorageMethod extends Migration */ public function down() { - Schema::table('servers', function (Blueprint $table) { $table->text('ip')->after('allocation'); $table->integer('port')->unsigned()->after('ip'); @@ -62,8 +60,8 @@ class ModifyIpStorageMethod extends Migration // Find the allocations and reset the servers... $servers = DB::select('SELECT id, allocation FROM servers'); - foreach($servers as $server) { - $allocation = DB::select('SELECT * FROM allocations WHERE id = :alocid', [ 'alocid' => $server->allocation ]); + foreach ($servers as $server) { + $allocation = DB::select('SELECT * FROM allocations WHERE id = :alocid', ['alocid' => $server->allocation]); if (isset($allocation[0])) { DB::update( @@ -71,7 +69,7 @@ class ModifyIpStorageMethod extends Migration [ 'ip' => $allocation[0]->ip, 'port' => $allocation[0]->port, - 'id' => $server->id + 'id' => $server->id, ] ); } diff --git a/database/migrations/2016_09_17_194246_add_docker_image_column.php b/database/migrations/2016_09_17_194246_add_docker_image_column.php index bea676a08..58e4b87a3 100644 --- a/database/migrations/2016_09_17_194246_add_docker_image_column.php +++ b/database/migrations/2016_09_17_194246_add_docker_image_column.php @@ -4,8 +4,6 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; -use Pterodactyl\Models\Server; - class AddDockerImageColumn extends Migration { /** diff --git a/database/migrations/2016_09_29_213518_rename_double_insurgency.php b/database/migrations/2016_09_29_213518_rename_double_insurgency.php index 6c0ea8070..4fecb8bdf 100644 --- a/database/migrations/2016_09_29_213518_rename_double_insurgency.php +++ b/database/migrations/2016_09_29_213518_rename_double_insurgency.php @@ -1,7 +1,5 @@ text('user_agent'); $table->ipAddress('request_ip'); $table->timestampsTz(); - }); } diff --git a/database/migrations/2016_10_23_181719_update_misnamed_bungee.php b/database/migrations/2016_10_23_181719_update_misnamed_bungee.php index 5a91e0138..0a5316755 100644 --- a/database/migrations/2016_10_23_181719_update_misnamed_bungee.php +++ b/database/migrations/2016_10_23_181719_update_misnamed_bungee.php @@ -1,7 +1,5 @@ select('env_variable')->where('env_variable', 'BUNGE_VERSION')->update([ - 'env_variable' => 'BUNGEE_VERSION' + 'env_variable' => 'BUNGEE_VERSION', ]); } @@ -25,6 +23,5 @@ class UpdateMisnamedBungee extends Migration */ public function down() { - return; } } diff --git a/database/migrations/2016_10_23_201624_add_foreign_allocations.php b/database/migrations/2016_10_23_201624_add_foreign_allocations.php index 6b73df2d6..8ff9bdd2f 100644 --- a/database/migrations/2016_10_23_201624_add_foreign_allocations.php +++ b/database/migrations/2016_10_23_201624_add_foreign_allocations.php @@ -12,17 +12,17 @@ class AddForeignAllocations extends Migration * @return void */ public function up() - { - DB::statement('ALTER TABLE allocations + { + DB::statement('ALTER TABLE allocations MODIFY COLUMN assigned_to INT(10) UNSIGNED NULL, MODIFY COLUMN node INT(10) UNSIGNED NOT NULL '); - Schema::table('allocations', function (Blueprint $table) { - $table->foreign('assigned_to')->references('id')->on('servers'); - $table->foreign('node')->references('id')->on('nodes'); - }); - } + Schema::table('allocations', function (Blueprint $table) { + $table->foreign('assigned_to')->references('id')->on('servers'); + $table->foreign('node')->references('id')->on('nodes'); + }); + } /** * Reverse the migrations. diff --git a/database/migrations/2016_10_23_203522_add_foreign_permissions.php b/database/migrations/2016_10_23_203522_add_foreign_permissions.php index 8de3f3b8f..153ab27ce 100644 --- a/database/migrations/2016_10_23_203522_add_foreign_permissions.php +++ b/database/migrations/2016_10_23_203522_add_foreign_permissions.php @@ -34,5 +34,4 @@ class AddForeignPermissions extends Migration $table->dropIndex('permissions_server_id_foreign'); }); } - } diff --git a/database/migrations/2016_10_23_203857_add_foreign_server_variables.php b/database/migrations/2016_10_23_203857_add_foreign_server_variables.php index 116434161..c232176c7 100644 --- a/database/migrations/2016_10_23_203857_add_foreign_server_variables.php +++ b/database/migrations/2016_10_23_203857_add_foreign_server_variables.php @@ -44,5 +44,4 @@ class AddForeignServerVariables extends Migration MODIFY COLUMN variable_id MEDIUMINT(8) UNSIGNED NOT NULL '); } - } diff --git a/database/migrations/2016_10_23_204321_add_foreign_service_variables.php b/database/migrations/2016_10_23_204321_add_foreign_service_variables.php index 4f7f43ae2..291ca24e2 100644 --- a/database/migrations/2016_10_23_204321_add_foreign_service_variables.php +++ b/database/migrations/2016_10_23_204321_add_foreign_service_variables.php @@ -34,4 +34,4 @@ class AddForeignServiceVariables extends Migration DB::statement('ALTER TABLE service_variables MODIFY option_id MEDIUMINT(8) UNSIGNED NOT NULL'); } - } +} diff --git a/database/migrations/2016_11_04_000949_add_ark_service_option_fixed.php b/database/migrations/2016_11_04_000949_add_ark_service_option_fixed.php index fa8d5dde6..5a2dd6da4 100644 --- a/database/migrations/2016_11_04_000949_add_ark_service_option_fixed.php +++ b/database/migrations/2016_11_04_000949_add_ark_service_option_fixed.php @@ -1,7 +1,5 @@ select('id')->where('author', 'ptrdctyl-v040-11e6-8b77-86f30ca893d3')->where('name', 'Source Engine')->first(); // No SRCDS Service, Skipping - if (!$service) { + if (! $service) { return; } @@ -33,7 +31,7 @@ class AddArkServiceOptionFixed extends Migration 'tag' => 'ark', 'docker_image' => 'quay.io/pterodactyl/srcds:ark', 'executable' => './ShooterGameServer', - 'startup' => 'TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}' + 'startup' => 'TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}', ]); DB::table('service_variables')->insert([ @@ -45,7 +43,7 @@ class AddArkServiceOptionFixed extends Migration 'user_viewable' => 1, 'user_editable' => 1, 'required' => 0, - 'regex' => '/^(\w\.*)$/' + 'regex' => '/^(\w\.*)$/', ]); DB::table('service_variables')->insert([ @@ -57,7 +55,7 @@ class AddArkServiceOptionFixed extends Migration 'user_viewable' => 1, 'user_editable' => 1, 'required' => 0, - 'regex' => '/^(\w\.*)$/' + 'regex' => '/^(\w\.*)$/', ]); DB::table('service_variables')->insert([ @@ -69,10 +67,9 @@ class AddArkServiceOptionFixed extends Migration 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\d{1,4})$/' + 'regex' => '/^(\d{1,4})$/', ]); }); - } /** diff --git a/database/migrations/2016_11_11_220649_add_pack_support.php b/database/migrations/2016_11_11_220649_add_pack_support.php new file mode 100644 index 000000000..7cb3eb10e --- /dev/null +++ b/database/migrations/2016_11_11_220649_add_pack_support.php @@ -0,0 +1,40 @@ +increments('id'); + $table->unsignedInteger('option'); + $table->char('uuid', 36)->unique(); + $table->string('name'); + $table->string('version'); + $table->text('description')->nullable(); + $table->boolean('selectable')->default(true); + $table->boolean('visible')->default(true); + $table->timestamps(); + + $table->foreign('option')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('service_packs'); + } +} diff --git a/database/migrations/2016_11_11_231731_set_service_name_unique.php b/database/migrations/2016_11_11_231731_set_service_name_unique.php new file mode 100644 index 000000000..4db76f8e8 --- /dev/null +++ b/database/migrations/2016_11_11_231731_set_service_name_unique.php @@ -0,0 +1,32 @@ +unique('name'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('services', function (Blueprint $table) { + $table->dropUnique('services_name_unique'); + }); + } +} diff --git a/database/migrations/2016_11_27_142519_add_pack_column.php b/database/migrations/2016_11_27_142519_add_pack_column.php new file mode 100644 index 000000000..f2c2f0964 --- /dev/null +++ b/database/migrations/2016_11_27_142519_add_pack_column.php @@ -0,0 +1,36 @@ +unsignedInteger('pack')->nullable()->after('option'); + + $table->foreign('pack')->references('id')->on('service_packs'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('servers', function (Blueprint $table) { + $table->dropForeign('servers_pack_foreign'); + $table->dropIndex('servers_pack_foreign'); + $table->dropColumn('pack'); + }); + } +} diff --git a/database/migrations/2016_12_01_173018_add_configurable_upload_limit.php b/database/migrations/2016_12_01_173018_add_configurable_upload_limit.php new file mode 100644 index 000000000..91ef1fbbd --- /dev/null +++ b/database/migrations/2016_12_01_173018_add_configurable_upload_limit.php @@ -0,0 +1,32 @@ +unsignedInteger('upload_size')->after('disk_overallocate')->default(100); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('nodes', function (Blueprint $table) { + $table->dropColumn('upload_size'); + }); + } +} diff --git a/database/migrations/2016_12_02_185206_correct_service_variables.php b/database/migrations/2016_12_02_185206_correct_service_variables.php new file mode 100644 index 000000000..dd99c1223 --- /dev/null +++ b/database/migrations/2016_12_02_185206_correct_service_variables.php @@ -0,0 +1,77 @@ +where([ + ['name', 'Spigot'], + ['tag', 'spigot'], + ['startup', '-Xms128M -Xmx{{SERVER_MEMORY}}M -Djline.terminal=jline.UnsupportedTerminal -jar {{SERVER_JARFILE}}'], + ])->update([ + 'startup' => null, + ]); + + // Correct Spigot Version Checking + DB::table('service_variables')->where([ + ['name', 'Spigot Version'], + ['env_variable', 'DL_VERSION'], + ['default_value', 'latest'], + ['regex', '/^(latest|[a-zA-Z0-9_\.-]{5,6})$/'], + ])->update([ + 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{3,7})$/', + ]); + + // Correct Vanilla Version Checking (as well as naming) + DB::table('service_variables')->where([ + ['name', 'Server Jar File'], + ['env_variable', 'VANILLA_VERSION'], + ['default_value', 'latest'], + ['regex', '/^(latest|[a-zA-Z0-9_\.-]{5,6})$/'], + ])->update([ + 'name' => 'Server Version', + 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{3,7})$/', + ]); + + // Update Sponge Version Checking and Update Default Version + DB::table('service_variables')->where([ + ['name', 'Sponge Version'], + ['env_variable', 'SPONGE_VERSION'], + ['default_value', '1.8.9-4.2.0-BETA-351'], + ['regex', '/^(.*)$/'], + ])->update([ + 'default_value' => '1.10.2-5.1.0-BETA-359', + 'regex' => '/^([a-zA-Z0-9.\-_]+)$/', + ]); + + // Update Bungeecord Version Checking + DB::table('service_variables')->where([ + ['name', 'Bungeecord Version'], + ['env_variable', 'BUNGEE_VERSION'], + ['default_value', 'latest'], + ['regex', '/^(latest|[\d]{3,5})$/'], + ])->update([ + 'regex' => '/^(latest|[\d]{1,6})$/', + ]); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // do nothing + } +} diff --git a/database/migrations/2017_01_03_150436_fix_misnamed_option_tag.php b/database/migrations/2017_01_03_150436_fix_misnamed_option_tag.php new file mode 100644 index 000000000..a03584ca0 --- /dev/null +++ b/database/migrations/2017_01_03_150436_fix_misnamed_option_tag.php @@ -0,0 +1,40 @@ +where([ + ['name', 'Sponge (SpongeVanilla)'], + ['tag', 'spigot'], + ['docker_image', 'quay.io/pterodactyl/minecraft:sponge'], + ])->update([ + 'tag' => 'sponge', + ]); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + DB::table('service_options')->where([ + ['name', 'Sponge (SpongeVanilla)'], + ['tag', 'sponge'], + ['docker_image', 'quay.io/pterodactyl/minecraft:sponge'], + ])->update([ + 'tag' => 'spigot', + ]); + } +} diff --git a/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php b/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php new file mode 100644 index 000000000..905d28a46 --- /dev/null +++ b/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->char('token', 32); + $table->timestamp('expires_at'); + $table->integer('node')->unsigned(); + $table->foreign('node')->references('id')->on('nodes'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('node_configuration_tokens'); + } +} diff --git a/database/migrations/2017_01_12_135449_add_more_user_data.php b/database/migrations/2017_01_12_135449_add_more_user_data.php new file mode 100644 index 000000000..67bc3f59d --- /dev/null +++ b/database/migrations/2017_01_12_135449_add_more_user_data.php @@ -0,0 +1,50 @@ +string('name_first')->after('email')->nullable(); + $table->string('name_last')->after('name_first')->nullable(); + $table->string('username')->after('uuid'); + $table->boolean('gravatar')->after('totp_secret')->default(true); + }); + + DB::transaction(function () { + foreach (User::all() as &$user) { + $user->username = $user->email; + $user->save(); + } + }); + + Schema::table('users', function (Blueprint $table) { + $table->string('username')->unique()->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('name_first'); + $table->dropColumn('name_last'); + $table->dropColumn('username'); + $table->dropColumn('gravatar'); + }); + } +} diff --git a/database/seeds/MinecraftServiceTableSeeder.php b/database/seeds/MinecraftServiceTableSeeder.php index ff141abdb..28f61343e 100644 --- a/database/seeds/MinecraftServiceTableSeeder.php +++ b/database/seeds/MinecraftServiceTableSeeder.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Illuminate\Database\Seeder; - use Pterodactyl\Models; +use Illuminate\Database\Seeder; class MinecraftServiceTableSeeder extends Seeder { @@ -35,7 +34,7 @@ class MinecraftServiceTableSeeder extends Seeder protected $service; /** - * Stores all of the option objects + * Stores all of the option objects. * * @var array */ @@ -61,7 +60,7 @@ class MinecraftServiceTableSeeder extends Seeder 'description' => 'Minecraft - the classic game from Mojang. With support for Vanilla MC, Spigot, and many others!', 'file' => 'minecraft', 'executable' => 'java', - 'startup' => '-Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}' + 'startup' => '-Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}', ]); } @@ -74,7 +73,7 @@ class MinecraftServiceTableSeeder extends Seeder 'tag' => 'vanilla', 'docker_image' => 'quay.io/pterodactyl/minecraft', 'executable' => null, - 'startup' => null + 'startup' => null, ]); $this->option['spigot'] = Models\ServiceOptions::create([ @@ -84,17 +83,17 @@ class MinecraftServiceTableSeeder extends Seeder 'tag' => 'spigot', 'docker_image' => 'quay.io/pterodactyl/minecraft:spigot', 'executable' => null, - 'startup' => '-Xms128M -Xmx{{SERVER_MEMORY}}M -Djline.terminal=jline.UnsupportedTerminal -jar {{SERVER_JARFILE}}' + 'startup' => '-Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}', ]); $this->option['sponge'] = Models\ServiceOptions::create([ 'parent_service' => $this->service->id, 'name' => 'Sponge (SpongeVanilla)', 'description' => 'SpongeVanilla is the SpongeAPI implementation for Vanilla Minecraft.', - 'tag' => 'spigot', + 'tag' => 'sponge', 'docker_image' => 'quay.io/pterodactyl/minecraft:sponge', 'executable' => null, - 'startup' => null + 'startup' => null, ]); $this->option['bungeecord'] = Models\ServiceOptions::create([ @@ -104,7 +103,7 @@ class MinecraftServiceTableSeeder extends Seeder 'tag' => 'bungeecord', 'docker_image' => 'quay.io/pterodactyl/minecraft:bungeecord', 'executable' => null, - 'startup' => null + 'startup' => null, ]); } @@ -127,19 +126,19 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/' + 'regex' => '/^([\w\d._-]+)(\.jar)$/', ]); Models\ServiceVariables::create([ 'option_id' => $this->option['vanilla']->id, - 'name' => 'Server Jar File', + 'name' => 'Server Version', 'description' => 'The version of Minecraft Vanilla to install. Use "latest" to install the latest version.', 'env_variable' => 'VANILLA_VERSION', 'default_value' => 'latest', 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{5,6})$/' + 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{3,7})$/', ]); } @@ -154,7 +153,7 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/' + 'regex' => '/^([\w\d._-]+)(\.jar)$/', ]); Models\ServiceVariables::create([ @@ -166,7 +165,7 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{5,6})$/' + 'regex' => '/^(latest|[a-zA-Z0-9_\.-]{3,7})$/', ]); Models\ServiceVariables::create([ @@ -178,7 +177,7 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 0, 'user_editable' => 0, 'required' => 0, - 'regex' => '/^(.*)$/' + 'regex' => '/^(.*)$/', ]); } @@ -189,11 +188,11 @@ class MinecraftServiceTableSeeder extends Seeder 'name' => 'Sponge Version', 'description' => 'The version of SpongeVanilla to download and use.', 'env_variable' => 'SPONGE_VERSION', - 'default_value' => '1.8.9-4.2.0-BETA-351', + 'default_value' => '1.10.2-5.1.0-BETA-359', 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(.*)$/' + 'regex' => '/^([a-zA-Z0-9.\-_]+)$/', ]); Models\ServiceVariables::create([ @@ -205,7 +204,7 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/' + 'regex' => '/^([\w\d._-]+)(\.jar)$/', ]); } @@ -220,7 +219,7 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(latest|[\d]{3,5})$/' + 'regex' => '/^(latest|[\d]{1,6})$/', ]); Models\ServiceVariables::create([ @@ -232,7 +231,7 @@ class MinecraftServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([\w\d._-]+)(\.jar)$/' + 'regex' => '/^([\w\d._-]+)(\.jar)$/', ]); } } diff --git a/database/seeds/SourceServiceTableSeeder.php b/database/seeds/SourceServiceTableSeeder.php index 2c4b25d55..838814db8 100644 --- a/database/seeds/SourceServiceTableSeeder.php +++ b/database/seeds/SourceServiceTableSeeder.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Illuminate\Database\Seeder; - use Pterodactyl\Models; +use Illuminate\Database\Seeder; class SourceServiceTableSeeder extends Seeder { @@ -35,7 +34,7 @@ class SourceServiceTableSeeder extends Seeder protected $service; /** - * Stores all of the option objects + * Stores all of the option objects. * * @var array */ @@ -61,7 +60,7 @@ class SourceServiceTableSeeder extends Seeder 'description' => 'Includes support for most Source Dedicated Server games.', 'file' => 'srcds', 'executable' => './srcds_run', - 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} -strictportbind -norestart' + 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} -strictportbind -norestart', ]); } @@ -74,7 +73,7 @@ class SourceServiceTableSeeder extends Seeder 'tag' => 'srcds', 'docker_image' => 'quay.io/pterodactyl/srcds', 'executable' => null, - 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} -strictportbind -norestart' + 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} -strictportbind -norestart', ]); $this->option['tf2'] = Models\ServiceOptions::create([ @@ -84,7 +83,7 @@ class SourceServiceTableSeeder extends Seeder 'tag' => 'srcds', 'docker_image' => 'quay.io/pterodactyl/srcds', 'executable' => null, - 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} -strictportbind -norestart' + 'startup' => '-game {{SRCDS_GAME}} -console -port {{SERVER_PORT}} +map {{SRCDS_MAP}} -strictportbind -norestart', ]); $this->option['ark'] = Models\ServiceOptions::create([ @@ -94,7 +93,7 @@ class SourceServiceTableSeeder extends Seeder 'tag' => 'ark', 'docker_image' => 'quay.io/pterodactyl/srcds:ark', 'executable' => './ShooterGameServer', - 'startup' => 'TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}' + 'startup' => 'TheIsland?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}', ]); $this->option['custom'] = Models\ServiceOptions::create([ @@ -104,7 +103,7 @@ class SourceServiceTableSeeder extends Seeder 'tag' => 'srcds', 'docker_image' => 'quay.io/pterodactyl/srcds', 'executable' => null, - 'startup' => null + 'startup' => null, ]); } @@ -127,7 +126,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(17705)$/' + 'regex' => '/^(17705)$/', ]); Models\ServiceVariables::create([ @@ -139,7 +138,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(insurgency)$/' + 'regex' => '/^(insurgency)$/', ]); Models\ServiceVariables::create([ @@ -151,7 +150,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\w{1,20})$/' + 'regex' => '/^(\w{1,20})$/', ]); } @@ -166,7 +165,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(232250)$/' + 'regex' => '/^(232250)$/', ]); Models\ServiceVariables::create([ @@ -178,7 +177,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(tf)$/' + 'regex' => '/^(tf)$/', ]); Models\ServiceVariables::create([ @@ -190,7 +189,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\w{1,20})$/' + 'regex' => '/^(\w{1,20})$/', ]); } @@ -205,7 +204,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 0, - 'regex' => '/^(\w\.*)$/' + 'regex' => '/^(\w\.*)$/', ]); DB::table('service_variables')->insert([ @@ -217,7 +216,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 0, - 'regex' => '/^(\w\.*)$/' + 'regex' => '/^(\w\.*)$/', ]); DB::table('service_variables')->insert([ @@ -229,7 +228,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^(\d{1,4})$/' + 'regex' => '/^(\d{1,4})$/', ]); } @@ -244,7 +243,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(\d){1,6}$/' + 'regex' => '/^(\d){1,6}$/', ]); Models\ServiceVariables::create([ @@ -256,7 +255,7 @@ class SourceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(.*)$/' + 'regex' => '/^(.*)$/', ]); } } diff --git a/database/seeds/TerrariaServiceTableSeeder.php b/database/seeds/TerrariaServiceTableSeeder.php index 01c7376fe..bd3089ea2 100644 --- a/database/seeds/TerrariaServiceTableSeeder.php +++ b/database/seeds/TerrariaServiceTableSeeder.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Illuminate\Database\Seeder; - use Pterodactyl\Models; +use Illuminate\Database\Seeder; class TerrariaServiceTableSeeder extends Seeder { @@ -35,7 +34,7 @@ class TerrariaServiceTableSeeder extends Seeder protected $service; /** - * Stores all of the option objects + * Stores all of the option objects. * * @var array */ @@ -61,7 +60,7 @@ class TerrariaServiceTableSeeder extends Seeder 'description' => 'Terraria is a land of adventure! A land of mystery! A land that\'s yours to shape, defend, and enjoy. Your options in Terraria are limitless. Are you an action gamer with an itchy trigger finger? A master builder? A collector? An explorer? There\'s something for everyone.', 'file' => 'terraria', 'executable' => 'TerrariaServer.exe', - 'startup' => '-port {{SERVER_PORT}} -autocreate 2 -worldname World' + 'startup' => '-port {{SERVER_PORT}} -autocreate 2 -worldname World', ]); } @@ -74,7 +73,7 @@ class TerrariaServiceTableSeeder extends Seeder 'tag' => 'tshock', 'docker_image' => 'quay.io/pterodactyl/terraria:tshock', 'executable' => '', - 'startup' => '' + 'startup' => '', ]); } @@ -89,7 +88,7 @@ class TerrariaServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([0-9_\.-]{5,10})$/' + 'regex' => '/^([0-9_\.-]{5,10})$/', ]); Models\ServiceVariables::create([ @@ -101,7 +100,7 @@ class TerrariaServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(\d){1,3}$/' + 'regex' => '/^(\d){1,3}$/', ]); } } diff --git a/database/seeds/VoiceServiceTableSeeder.php b/database/seeds/VoiceServiceTableSeeder.php index 6756d0758..1fca3a475 100644 --- a/database/seeds/VoiceServiceTableSeeder.php +++ b/database/seeds/VoiceServiceTableSeeder.php @@ -1,7 +1,7 @@ + * Copyright (c) 2015 - 2017 Dane Everitt . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -use Illuminate\Database\Seeder; - use Pterodactyl\Models; +use Illuminate\Database\Seeder; class VoiceServiceTableSeeder extends Seeder { @@ -35,7 +34,7 @@ class VoiceServiceTableSeeder extends Seeder protected $service; /** - * Stores all of the option objects + * Stores all of the option objects. * * @var array */ @@ -61,7 +60,7 @@ class VoiceServiceTableSeeder extends Seeder 'description' => 'Voice servers such as Mumble and Teamspeak 3.', 'file' => 'voice', 'executable' => '', - 'startup' => '' + 'startup' => '', ]); } @@ -74,7 +73,7 @@ class VoiceServiceTableSeeder extends Seeder 'tag' => 'mumble', 'docker_image' => 'quay.io/pterodactyl/voice:mumble', 'executable' => './murmur.x86', - 'startup' => '-fg' + 'startup' => '-fg', ]); $this->option['ts3'] = Models\ServiceOptions::create([ @@ -84,7 +83,7 @@ class VoiceServiceTableSeeder extends Seeder 'tag' => 'ts3', 'docker_image' => 'quay.io/pterodactyl/voice:ts3', 'executable' => './ts3server_minimal_runscript.sh', - 'startup' => 'default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}}' + 'startup' => 'default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}}', ]); } @@ -99,7 +98,7 @@ class VoiceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 0, 'required' => 1, - 'regex' => '/^(\d){1,6}$/' + 'regex' => '/^(\d){1,6}$/', ]); Models\ServiceVariables::create([ @@ -111,7 +110,7 @@ class VoiceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([0-9_\.-]{5,8})$/' + 'regex' => '/^([0-9_\.-]{5,8})$/', ]); Models\ServiceVariables::create([ @@ -123,7 +122,7 @@ class VoiceServiceTableSeeder extends Seeder 'user_viewable' => 1, 'user_editable' => 1, 'required' => 1, - 'regex' => '/^([0-9_\.-]{5,10})$/' + 'regex' => '/^([0-9_\.-]{5,10})$/', ]); } } diff --git a/package.json b/package.json new file mode 100644 index 000000000..2a9697409 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "pterodactyl-panel", + "devDependencies": { + "babel-cli": "6.18.0", + "babel-plugin-transform-strict-mode": "^6.18.0", + "babel-preset-es2015": "6.18.0" + }, + "scripts": { + "build": "./node_modules/babel-cli/bin/babel.js public/themes/pterodactyl/js/frontend/files/src --source-maps --out-file public/themes/pterodactyl/js/frontend/files/filemanager.min.js" + } +} diff --git a/public/index.php b/public/index.php index c5820533b..f2bd8213e 100644 --- a/public/index.php +++ b/public/index.php @@ -1,9 +1,8 @@ */ @@ -19,7 +18,7 @@ | */ -require __DIR__.'/../bootstrap/autoload.php'; +require __DIR__ . '/../bootstrap/autoload.php'; /* |-------------------------------------------------------------------------- @@ -33,7 +32,7 @@ require __DIR__.'/../bootstrap/autoload.php'; | */ -$app = require_once __DIR__.'/../bootstrap/app.php'; +$app = require_once __DIR__ . '/../bootstrap/app.php'; /* |-------------------------------------------------------------------------- diff --git a/public/js/admin.min.js b/public/js/admin.min.js index b6ed01f4c..b012c35d0 100755 --- a/public/js/admin.min.js +++ b/public/js/admin.min.js @@ -1,6 +1,6 @@ /** * Pterodactyl - Panel - * Copyright (c) 2015 - 2016 Dane Everitt + * Copyright (c) 2015 - 2017 Dane Everitt * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,4 +46,24 @@ $(document).ready(function () { centerModal($(this)); }); $(window).on('resize', centerModal); + + // Idea code for multiplicators submitted by @Taronyuu on Github + // https://github.com/Pterodactyl/Panel/issues/154#issuecomment-257116078 + $('input[data-multiplicator="true"]').on('change', function () { + var value = $(this).val(); + if (!/^\d+$/.test(value)) { + var multiplicator = value.replace(/[0-9]/g, '').toLowerCase(); + value = value.replace(/\D/g, ''); + + if (multiplicator === 't') { + value = value * (1024 * 1024); + } + + if (multiplicator === 'g') { + value = value * 1024; + } + } + + $(this).val(value); + }); }); diff --git a/public/js/filemanager.min.js b/public/js/filemanager.min.js new file mode 100644 index 000000000..64a74e92d --- /dev/null +++ b/public/js/filemanager.min.js @@ -0,0 +1,5 @@ +'use strict';var _createClass=function(){function defineProperties(target,props){for(var i=0;i\n \n ';nameBlock.html(attachEditor);var inputField=nameBlock.find('input');var inputLoader=nameBlock.find('.input-loader');inputField.focus();inputField.on('blur keydown',function(e){if(e.type==='keydown'&&e.which===27||e.type==='blur'||e.type==='keydown'&&e.which===13&¤tName===inputField.val()){if(!_.isEmpty(currentLink)){nameBlock.html(currentLink)}else{nameBlock.html(currentName)}inputField.remove();ContextMenu.unbind().run();return}if(e.type==='keydown'&&e.which!==13)return;inputLoader.show();var currentPath=decodeURIComponent(nameBlock.data('path'));$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/server/file/rename',timeout:10000,data:JSON.stringify({from:''+currentPath+currentName,to:''+currentPath+inputField.val()})}).done(function(data){nameBlock.attr('data-name',inputField.val());if(!_.isEmpty(currentLink)){var newLink=currentLink.attr('href');if(nameBlock.parent().data('type')!=='folder'){newLink=newLink.substr(0,newLink.lastIndexOf('/'))+'/'+inputField.val()}currentLink.attr('href',newLink);nameBlock.html(currentLink.html(inputField.val()))}else{nameBlock.html(inputField.val())}inputField.remove()}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}nameBlock.addClass('has-error').delay(2000).queue(function(){nameBlock.removeClass('has-error').dequeue()});inputField.popover({animation:true,placement:'top',content:error,title:'Save Error'}).popover('show')}).always(function(){inputLoader.remove();ContextMenu.unbind().run()})})}},{key:'copy',value:function copy(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var currentName=decodeURIComponent(nameBlock.attr('data-name'));var currentPath=decodeURIComponent(nameBlock.data('path'));swal({type:'input',title:'Copy File',text:'Please enter the new path for the copied file below.',showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true,inputValue:''+currentPath+currentName},function(val){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/server/file/copy',timeout:10000,data:JSON.stringify({from:''+currentPath+currentName,to:''+val})}).done(function(data){swal({type:'success',title:'',text:'File successfully copied.'});Files.list()}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'',text:error})})})}},{key:'download',value:function download(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var fileName=decodeURIComponent(nameBlock.attr('data-name'));var filePath=decodeURIComponent(nameBlock.data('path'));window.location='/server/'+Pterodactyl.server.uuidShort+'/files/download/'+filePath+fileName}},{key:'delete',value:function _delete(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var delPath=decodeURIComponent(nameBlock.data('path'));var delName=decodeURIComponent(nameBlock.data('name'));swal({type:'warning',title:'',text:'Are you sure you want to delete '+delName+'? There is no reversing this action.',html:true,showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true},function(){$.ajax({type:'DELETE',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/server/file/f/'+delPath+delName,headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid}}).done(function(data){nameBlock.parent().addClass('warning').delay(200).fadeOut();swal({type:'success',title:'File Deleted'})}).fail(function(jqXHR){console.error(jqXHR);swal({type:'error',title:'Whoops!',html:true,text:'An error occured while attempting to delete this file. Please try again.'})})})}},{key:'decompress',value:function decompress(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var compPath=decodeURIComponent(nameBlock.data('path'));var compName=decodeURIComponent(nameBlock.data('name'));swal({title:' Decompressing...',text:'This might take a few seconds to complete.',html:true,allowOutsideClick:false,allowEscapeKey:false,showConfirmButton:false});$.ajax({type:'POST',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/server/file/decompress',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',data:JSON.stringify({files:''+compPath+compName})}).done(function(data){swal.close();Files.list(compPath)}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'Whoops!',html:true,text:error})})}},{key:'compress',value:function compress(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var compPath=decodeURIComponent(nameBlock.data('path'));var compName=decodeURIComponent(nameBlock.data('name'));$.ajax({type:'POST',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/server/file/compress',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',data:JSON.stringify({files:''+compPath+compName,to:compPath.toString()})}).done(function(data){Files.list(compPath,function(err){if(err)return;var fileListing=$('#file_listing').find('[data-name="'+data.saved_as+'"]').parent();fileListing.addClass('success pulsate').delay(3000).queue(function(){fileListing.removeClass('success pulsate').dequeue()})})}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'Whoops!',html:true,text:error})})}}]);return ActionsClass}(); +'use strict';var _createClass=function(){function defineProperties(target,props){for(var i=0;i New File
  • New Folder
  • '}if(Pterodactyl.permissions.downloadFiles||Pterodactyl.permissions.deleteFiles){buildMenu+='
  • '}if(Pterodactyl.permissions.downloadFiles){buildMenu+=''}if(Pterodactyl.permissions.deleteFiles){buildMenu+='
  • Delete
  • '}buildMenu+='';return buildMenu}},{key:'rightClick',value:function rightClick(){var _this=this;$('[data-action="toggleMenu"]').on('mousedown',function(){event.preventDefault();_this.showMenu(event)});$('#file_listing > tbody td').on('contextmenu',function(event){_this.showMenu(event)})}},{key:'showMenu',value:function showMenu(event){var _this2=this;var parent=$(event.target).closest('tr');var menu=$(this.makeMenu(parent));if(parent.data('type')==='disabled')return;event.preventDefault();$(menu).appendTo('body');$(menu).data('invokedOn',$(event.target)).show().css({position:'absolute',left:event.pageX-150,top:event.pageY});this.activeLine=parent;this.activeLine.addClass('active');var Actions=new ActionsClass(parent,menu);if(Pterodactyl.permissions.moveFiles){$(menu).find('li[data-action="move"]').unbind().on('click',function(e){e.preventDefault();Actions.move()});$(menu).find('li[data-action="rename"]').unbind().on('click',function(e){e.preventDefault();Actions.rename()})}if(Pterodactyl.permissions.copyFiles){$(menu).find('li[data-action="copy"]').unbind().on('click',function(e){e.preventDefault();Actions.copy()})}if(Pterodactyl.permissions.compressFiles){if(parent.data('type')==='folder'){$(menu).find('li[data-action="compress"]').removeClass('hidden')}$(menu).find('li[data-action="compress"]').unbind().on('click',function(e){e.preventDefault();Actions.compress()})}if(Pterodactyl.permissions.decompressFiles){if(_.without(['application/zip','application/gzip','application/x-gzip'],parent.data('mime')).length<3){$(menu).find('li[data-action="decompress"]').removeClass('hidden')}$(menu).find('li[data-action="decompress"]').unbind().on('click',function(e){e.preventDefault();Actions.decompress()})}if(Pterodactyl.permissions.createFiles){$(menu).find('li[data-action="folder"]').unbind().on('click',function(e){e.preventDefault();Actions.folder()})}if(Pterodactyl.permissions.downloadFiles){if(parent.data('type')==='file'){$(menu).find('li[data-action="download"]').removeClass('hidden')}$(menu).find('li[data-action="download"]').unbind().on('click',function(e){e.preventDefault();Actions.download()})}if(Pterodactyl.permissions.deleteFiles){$(menu).find('li[data-action="delete"]').unbind().on('click',function(e){e.preventDefault();Actions.delete()})}$(window).on('click',function(){$(menu).remove();if(!_.isNull(_this2.activeLine))_this2.activeLine.removeClass('active')})}},{key:'directoryClick',value:function directoryClick(){$('a[data-action="directory-view"]').on('click',function(event){event.preventDefault();var path=$(this).parent().data('path')||'';var name=$(this).parent().data('name')||'';window.location.hash=encodeURIComponent(path+name);Files.list()})}}]);return ContextMenuClass}();window.ContextMenu=new ContextMenuClass; +'use strict';var _createClass=function(){function defineProperties(target,props){for(var i=0;i\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ActionsClass {\n constructor(element, menu) {\n this.element = element;\n this.menu = menu;\n }\n\n destroy() {\n this.element = undefined;\n }\n\n folder() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n let inputValue = `${currentPath}${currentName}/`;\n if ($(this.element).data('type') === 'file') {\n inputValue = currentPath;\n }\n swal({\n type: 'input',\n title: 'Create Folder',\n text: 'Please enter the path and folder name below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: inputValue\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`,\n timeout: 10000,\n data: JSON.stringify({\n path: val,\n }),\n }).done(data => {\n swal.close();\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n move() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Move File',\n text: 'Please enter the new path for the file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal.close();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n\n }\n\n rename() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentLink = nameBlock.find('a');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const attachEditor = `\n \n \n `;\n\n nameBlock.html(attachEditor);\n const inputField = nameBlock.find('input');\n const inputLoader = nameBlock.find('.input-loader');\n\n inputField.focus();\n inputField.on('blur keydown', e => {\n // Save Field\n if (\n (e.type === 'keydown' && e.which === 27)\n || e.type === 'blur'\n || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val())\n ) {\n if (!_.isEmpty(currentLink)) {\n nameBlock.html(currentLink);\n } else {\n nameBlock.html(currentName);\n }\n inputField.remove();\n ContextMenu.unbind().run();\n return;\n }\n\n if (e.type === 'keydown' && e.which !== 13) return;\n\n inputLoader.show();\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${currentPath}${inputField.val()}`,\n }),\n }).done(data => {\n nameBlock.attr('data-name', inputField.val());\n if (!_.isEmpty(currentLink)) {\n let newLink = currentLink.attr('href');\n if (nameBlock.parent().data('type') !== 'folder') {\n newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val();\n }\n currentLink.attr('href', newLink);\n nameBlock.html(\n currentLink.html(inputField.val())\n );\n } else {\n nameBlock.html(inputField.val());\n }\n inputField.remove();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n nameBlock.addClass('has-error').delay(2000).queue(() => {\n nameBlock.removeClass('has-error').dequeue();\n });\n inputField.popover({\n animation: true,\n placement: 'top',\n content: error,\n title: 'Save Error'\n }).popover('show');\n }).always(() => {\n inputLoader.remove();\n ContextMenu.unbind().run();\n });\n });\n }\n\n copy() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n\n swal({\n type: 'input',\n title: 'Copy File',\n text: 'Please enter the new path for the copied file below.',\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n inputValue: `${currentPath}${currentName}`,\n }, (val) => {\n $.ajax({\n type: 'POST',\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`,\n timeout: 10000,\n data: JSON.stringify({\n from: `${currentPath}${currentName}`,\n to: `${val}`,\n }),\n }).done(data => {\n swal({\n type: 'success',\n title: '',\n text: 'File successfully copied.'\n });\n Files.list();\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: '',\n text: error,\n });\n });\n });\n }\n\n download() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const fileName = decodeURIComponent(nameBlock.attr('data-name'));\n const filePath = decodeURIComponent(nameBlock.data('path'));\n\n window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`;\n }\n\n delete() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const delPath = decodeURIComponent(nameBlock.data('path'));\n const delName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n type: 'warning',\n title: '',\n text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.',\n html: true,\n showCancelButton: true,\n showConfirmButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true\n }, () => {\n $.ajax({\n type: 'DELETE',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n }\n }).done(data => {\n nameBlock.parent().addClass('warning').delay(200).fadeOut();\n swal({\n type: 'success',\n title: 'File Deleted'\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: 'An error occured while attempting to delete this file. Please try again.',\n });\n });\n });\n }\n\n decompress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n swal({\n title: ' Decompressing...',\n text: 'This might take a few seconds to complete.',\n html: true,\n allowOutsideClick: false,\n allowEscapeKey: false,\n showConfirmButton: false,\n });\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`\n })\n }).done(data => {\n swal.close();\n Files.list(compPath);\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n\n compress() {\n const nameBlock = $(this.element).find('td[data-identifier=\"name\"]');\n const compPath = decodeURIComponent(nameBlock.data('path'));\n const compName = decodeURIComponent(nameBlock.data('name'));\n\n $.ajax({\n type: 'POST',\n url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`,\n headers: {\n 'X-Access-Token': Pterodactyl.server.daemonSecret,\n 'X-Access-Server': Pterodactyl.server.uuid,\n },\n contentType: 'application/json; charset=utf-8',\n data: JSON.stringify({\n files: `${compPath}${compName}`,\n to: compPath.toString()\n })\n }).done(data => {\n Files.list(compPath, err => {\n if (err) return;\n const fileListing = $('#file_listing').find(`[data-name=\"${data.saved_as}\"]`).parent();\n fileListing.addClass('success pulsate').delay(3000).queue(() => {\n fileListing.removeClass('success pulsate').dequeue();\n });\n });\n }).fail(jqXHR => {\n console.error(jqXHR);\n var error = 'An error occured while trying to process this request.';\n if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {\n error = jqXHR.responseJSON.error;\n }\n swal({\n type: 'error',\n title: 'Whoops!',\n html: true,\n text: error\n });\n });\n }\n}\n","\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass ContextMenuClass {\n constructor() {\n this.activeLine = null;\n }\n\n run() {\n this.directoryClick();\n this.rightClick();\n }\n\n makeMenu(parent) {\n $(document).find('#fileOptionMenu').remove();\n if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n\n let newFilePath = $('#headerTableRow').attr('data-currentDir');\n if (parent.data('type') === 'folder') {\n const nameBlock = parent.find('td[data-identifier=\"name\"]');\n const currentName = decodeURIComponent(nameBlock.attr('data-name'));\n const currentPath = decodeURIComponent(nameBlock.data('path'));\n newFilePath = `${currentPath}${currentName}`;\n }\n\n let buildMenu = '
      ';\n\n if (Pterodactyl.permissions.moveFiles) {\n buildMenu += '
    • Rename
    • \\\n
    • Move
    • ';\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n buildMenu += '
    • Copy
    • ';\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n buildMenu += '
    • Compress
    • ';\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n buildMenu += '
    • Decompress
    • ';\n }\n\n if (Pterodactyl.permissions.createFiles) {\n buildMenu += '
    • \\\n
    • New File
    • \\\n
    • New Folder
    • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles || Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
    • ';\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n buildMenu += '
    • Download
    • ';\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n buildMenu += '
    • Delete
    • ';\n }\n\n buildMenu += '
    ';\n return buildMenu;\n }\n\n rightClick() {\n $('[data-action=\"toggleMenu\"]').on('mousedown', () => {\n event.preventDefault();\n this.showMenu(event);\n });\n $('#file_listing > tbody td').on('contextmenu', event => {\n this.showMenu(event);\n });\n }\n\n showMenu(event) {\n const parent = $(event.target).closest('tr');\n const menu = $(this.makeMenu(parent));\n\n if (parent.data('type') === 'disabled') return;\n event.preventDefault();\n\n $(menu).appendTo('body');\n $(menu).data('invokedOn', $(event.target)).show().css({\n position: 'absolute',\n left: event.pageX - 150,\n top: event.pageY,\n });\n\n this.activeLine = parent;\n this.activeLine.addClass('active');\n\n // Handle Events\n const Actions = new ActionsClass(parent, menu);\n if (Pterodactyl.permissions.moveFiles) {\n $(menu).find('li[data-action=\"move\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.move();\n });\n $(menu).find('li[data-action=\"rename\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.rename();\n });\n }\n\n if (Pterodactyl.permissions.copyFiles) {\n $(menu).find('li[data-action=\"copy\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.copy();\n });\n }\n\n if (Pterodactyl.permissions.compressFiles) {\n if (parent.data('type') === 'folder') {\n $(menu).find('li[data-action=\"compress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"compress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.compress();\n });\n }\n\n if (Pterodactyl.permissions.decompressFiles) {\n if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) {\n $(menu).find('li[data-action=\"decompress\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"decompress\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.decompress();\n });\n }\n\n if (Pterodactyl.permissions.createFiles) {\n $(menu).find('li[data-action=\"folder\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.folder();\n });\n }\n\n if (Pterodactyl.permissions.downloadFiles) {\n if (parent.data('type') === 'file') {\n $(menu).find('li[data-action=\"download\"]').removeClass('hidden');\n }\n $(menu).find('li[data-action=\"download\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.download();\n });\n }\n\n if (Pterodactyl.permissions.deleteFiles) {\n $(menu).find('li[data-action=\"delete\"]').unbind().on('click', e => {\n e.preventDefault();\n Actions.delete();\n });\n }\n\n $(window).on('click', () => {\n $(menu).remove();\n if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active');\n });\n }\n\n directoryClick() {\n $('a[data-action=\"directory-view\"]').on('click', function (event) {\n event.preventDefault();\n\n const path = $(this).parent().data('path') || '';\n const name = $(this).parent().data('name') || '';\n\n window.location.hash = encodeURIComponent(path + name);\n Files.list();\n });\n }\n}\n\nwindow.ContextMenu = new ContextMenuClass;\n","\"use strict\";\n\n// Copyright (c) 2015 - 2017 Dane Everitt \n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\nclass FileManager {\n constructor() {\n this.list(this.decodeHash());\n }\n\n list(path, next) {\n if (_.isUndefined(path)) {\n path = this.decodeHash();\n }\n\n this.loader(true);\n $.ajax({\n type: 'POST',\n url: Pterodactyl.meta.directoryList,\n headers: {\n 'X-CSRF-Token': Pterodactyl.meta.csrftoken,\n },\n data: {\n directory: path,\n },\n }).done(data => {\n this.loader(false);\n $('#load_files').slideUp().html(data).slideDown(100, () => {\n ContextMenu.run();\n this.reloadFilesButton();\n if (_.isFunction(next)) {\n return next();\n }\n });\n $('#internal_alert').slideUp();\n }).fail(jqXHR => {\n this.loader(false);\n if (_.isFunction(next)) {\n return next(new Error('Failed to load file listing.'));\n }\n swal({\n type: 'error',\n title: 'File Error',\n text: 'An error occured while attempting to process this request. Please try again.',\n });\n console.log(jqXHR);\n });\n }\n\n loader(show) {\n if ($('#load_files').height() < 5) return;\n\n if (show === true){\n var height = $('#load_files').height();\n var width = $('.ajax_loading_box').width();\n var center_height = (height / 2) - 30;\n var center_width = (width / 2) - 30;\n\n $('#position_me').css({\n 'top': center_height,\n 'left': center_width,\n 'font-size': '60px'\n });\n\n $('.ajax_loading_box').css('height', (height + 5)).show();\n } else {\n $('.ajax_loading_box').hide();\n }\n }\n\n reloadFilesButton() {\n $('i[data-action=\"reload-files\"]').unbind().on('click', () => {\n $('i[data-action=\"reload-files\"]').addClass('fa-spin');\n this.list();\n });\n }\n\n decodeHash() {\n return decodeURIComponent(window.location.hash.substring(1));\n }\n\n}\n\nwindow.Files = new FileManager;\n"]} \ No newline at end of file diff --git a/public/js/files/actions.js b/public/js/files/actions.js new file mode 100644 index 000000000..f286f4c1f --- /dev/null +++ b/public/js/files/actions.js @@ -0,0 +1,394 @@ +"use strict"; + +// Copyright (c) 2015 - 2017 Dane Everitt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +class ActionsClass { + constructor(element, menu) { + this.element = element; + this.menu = menu; + } + + destroy() { + this.element = undefined; + } + + folder() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const currentName = decodeURIComponent(nameBlock.attr('data-name')); + const currentPath = decodeURIComponent(nameBlock.data('path')); + + let inputValue = `${currentPath}${currentName}/`; + if ($(this.element).data('type') === 'file') { + inputValue = currentPath; + } + swal({ + type: 'input', + title: 'Create Folder', + text: 'Please enter the path and folder name below.', + showCancelButton: true, + showConfirmButton: true, + closeOnConfirm: false, + showLoaderOnConfirm: true, + inputValue: inputValue + }, (val) => { + $.ajax({ + type: 'POST', + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + }, + contentType: 'application/json; charset=utf-8', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/folder`, + timeout: 10000, + data: JSON.stringify({ + path: val, + }), + }).done(data => { + swal.close(); + Files.list(); + }).fail(jqXHR => { + console.error(jqXHR); + var error = 'An error occured while trying to process this request.'; + if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { + error = jqXHR.responseJSON.error; + } + swal({ + type: 'error', + title: '', + text: error, + }); + }); + }); + } + + move() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const currentName = decodeURIComponent(nameBlock.attr('data-name')); + const currentPath = decodeURIComponent(nameBlock.data('path')); + + swal({ + type: 'input', + title: 'Move File', + text: 'Please enter the new path for the file below.', + showCancelButton: true, + showConfirmButton: true, + closeOnConfirm: false, + showLoaderOnConfirm: true, + inputValue: `${currentPath}${currentName}`, + }, (val) => { + $.ajax({ + type: 'POST', + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + }, + contentType: 'application/json; charset=utf-8', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/move`, + timeout: 10000, + data: JSON.stringify({ + from: `${currentPath}${currentName}`, + to: `${val}`, + }), + }).done(data => { + nameBlock.parent().addClass('warning').delay(200).fadeOut(); + swal.close(); + }).fail(jqXHR => { + console.error(jqXHR); + var error = 'An error occured while trying to process this request.'; + if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { + error = jqXHR.responseJSON.error; + } + swal({ + type: 'error', + title: '', + text: error, + }); + }); + }); + + } + + rename() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const currentLink = nameBlock.find('a'); + const currentName = decodeURIComponent(nameBlock.attr('data-name')); + const attachEditor = ` + + + `; + + nameBlock.html(attachEditor); + const inputField = nameBlock.find('input'); + const inputLoader = nameBlock.find('.input-loader'); + + inputField.focus(); + inputField.on('blur keydown', e => { + // Save Field + if ( + (e.type === 'keydown' && e.which === 27) + || e.type === 'blur' + || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val()) + ) { + if (!_.isEmpty(currentLink)) { + nameBlock.html(currentLink); + } else { + nameBlock.html(currentName); + } + inputField.remove(); + ContextMenu.unbind().run(); + return; + } + + if (e.type === 'keydown' && e.which !== 13) return; + + inputLoader.show(); + const currentPath = decodeURIComponent(nameBlock.data('path')); + + $.ajax({ + type: 'POST', + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + }, + contentType: 'application/json; charset=utf-8', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/rename`, + timeout: 10000, + data: JSON.stringify({ + from: `${currentPath}${currentName}`, + to: `${currentPath}${inputField.val()}`, + }), + }).done(data => { + nameBlock.attr('data-name', inputField.val()); + if (!_.isEmpty(currentLink)) { + let newLink = currentLink.attr('href'); + if (nameBlock.parent().data('type') !== 'folder') { + newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val(); + } + currentLink.attr('href', newLink); + nameBlock.html( + currentLink.html(inputField.val()) + ); + } else { + nameBlock.html(inputField.val()); + } + inputField.remove(); + }).fail(jqXHR => { + console.error(jqXHR); + var error = 'An error occured while trying to process this request.'; + if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { + error = jqXHR.responseJSON.error; + } + nameBlock.addClass('has-error').delay(2000).queue(() => { + nameBlock.removeClass('has-error').dequeue(); + }); + inputField.popover({ + animation: true, + placement: 'top', + content: error, + title: 'Save Error' + }).popover('show'); + }).always(() => { + inputLoader.remove(); + ContextMenu.unbind().run(); + }); + }); + } + + copy() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const currentName = decodeURIComponent(nameBlock.attr('data-name')); + const currentPath = decodeURIComponent(nameBlock.data('path')); + + swal({ + type: 'input', + title: 'Copy File', + text: 'Please enter the new path for the copied file below.', + showCancelButton: true, + showConfirmButton: true, + closeOnConfirm: false, + showLoaderOnConfirm: true, + inputValue: `${currentPath}${currentName}`, + }, (val) => { + $.ajax({ + type: 'POST', + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + }, + contentType: 'application/json; charset=utf-8', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/copy`, + timeout: 10000, + data: JSON.stringify({ + from: `${currentPath}${currentName}`, + to: `${val}`, + }), + }).done(data => { + swal({ + type: 'success', + title: '', + text: 'File successfully copied.' + }); + Files.list(); + }).fail(jqXHR => { + console.error(jqXHR); + var error = 'An error occured while trying to process this request.'; + if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { + error = jqXHR.responseJSON.error; + } + swal({ + type: 'error', + title: '', + text: error, + }); + }); + }); + } + + download() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const fileName = decodeURIComponent(nameBlock.attr('data-name')); + const filePath = decodeURIComponent(nameBlock.data('path')); + + window.location = `/server/${Pterodactyl.server.uuidShort}/files/download/${filePath}${fileName}`; + } + + delete() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const delPath = decodeURIComponent(nameBlock.data('path')); + const delName = decodeURIComponent(nameBlock.data('name')); + + swal({ + type: 'warning', + title: '', + text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.', + html: true, + showCancelButton: true, + showConfirmButton: true, + closeOnConfirm: false, + showLoaderOnConfirm: true + }, () => { + $.ajax({ + type: 'DELETE', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/f/${delPath}${delName}`, + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + } + }).done(data => { + nameBlock.parent().addClass('warning').delay(200).fadeOut(); + swal({ + type: 'success', + title: 'File Deleted' + }); + }).fail(jqXHR => { + console.error(jqXHR); + swal({ + type: 'error', + title: 'Whoops!', + html: true, + text: 'An error occured while attempting to delete this file. Please try again.', + }); + }); + }); + } + + decompress() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const compPath = decodeURIComponent(nameBlock.data('path')); + const compName = decodeURIComponent(nameBlock.data('name')); + + swal({ + title: ' Decompressing...', + text: 'This might take a few seconds to complete.', + html: true, + allowOutsideClick: false, + allowEscapeKey: false, + showConfirmButton: false, + }); + + $.ajax({ + type: 'POST', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/decompress`, + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + }, + contentType: 'application/json; charset=utf-8', + data: JSON.stringify({ + files: `${compPath}${compName}` + }) + }).done(data => { + swal.close(); + Files.list(compPath); + }).fail(jqXHR => { + console.error(jqXHR); + var error = 'An error occured while trying to process this request.'; + if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { + error = jqXHR.responseJSON.error; + } + swal({ + type: 'error', + title: 'Whoops!', + html: true, + text: error + }); + }); + } + + compress() { + const nameBlock = $(this.element).find('td[data-identifier="name"]'); + const compPath = decodeURIComponent(nameBlock.data('path')); + const compName = decodeURIComponent(nameBlock.data('name')); + + $.ajax({ + type: 'POST', + url: `${Pterodactyl.node.scheme}://${Pterodactyl.node.fqdn}:${Pterodactyl.node.daemonListen}/server/file/compress`, + headers: { + 'X-Access-Token': Pterodactyl.server.daemonSecret, + 'X-Access-Server': Pterodactyl.server.uuid, + }, + contentType: 'application/json; charset=utf-8', + data: JSON.stringify({ + files: `${compPath}${compName}`, + to: compPath.toString() + }) + }).done(data => { + Files.list(compPath, err => { + if (err) return; + const fileListing = $('#file_listing').find(`[data-name="${data.saved_as}"]`).parent(); + fileListing.addClass('success pulsate').delay(3000).queue(() => { + fileListing.removeClass('success pulsate').dequeue(); + }); + }); + }).fail(jqXHR => { + console.error(jqXHR); + var error = 'An error occured while trying to process this request.'; + if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { + error = jqXHR.responseJSON.error; + } + swal({ + type: 'error', + title: 'Whoops!', + html: true, + text: error + }); + }); + } +} diff --git a/public/js/files/contextmenu.js b/public/js/files/contextmenu.js new file mode 100644 index 000000000..7c91ac004 --- /dev/null +++ b/public/js/files/contextmenu.js @@ -0,0 +1,195 @@ +"use strict"; + +// Copyright (c) 2015 - 2017 Dane Everitt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +class ContextMenuClass { + constructor() { + this.activeLine = null; + } + + run() { + this.directoryClick(); + this.rightClick(); + } + + makeMenu(parent) { + $(document).find('#fileOptionMenu').remove(); + if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active'); + + let newFilePath = $('#headerTableRow').attr('data-currentDir'); + if (parent.data('type') === 'folder') { + const nameBlock = parent.find('td[data-identifier="name"]'); + const currentName = decodeURIComponent(nameBlock.attr('data-name')); + const currentPath = decodeURIComponent(nameBlock.data('path')); + newFilePath = `${currentPath}${currentName}`; + } + + let buildMenu = ''; + return buildMenu; + } + + rightClick() { + $('[data-action="toggleMenu"]').on('mousedown', () => { + event.preventDefault(); + this.showMenu(event); + }); + $('#file_listing > tbody td').on('contextmenu', event => { + this.showMenu(event); + }); + } + + showMenu(event) { + const parent = $(event.target).closest('tr'); + const menu = $(this.makeMenu(parent)); + + if (parent.data('type') === 'disabled') return; + event.preventDefault(); + + $(menu).appendTo('body'); + $(menu).data('invokedOn', $(event.target)).show().css({ + position: 'absolute', + left: event.pageX - 150, + top: event.pageY, + }); + + this.activeLine = parent; + this.activeLine.addClass('active'); + + // Handle Events + const Actions = new ActionsClass(parent, menu); + if (Pterodactyl.permissions.moveFiles) { + $(menu).find('li[data-action="move"]').unbind().on('click', e => { + e.preventDefault(); + Actions.move(); + }); + $(menu).find('li[data-action="rename"]').unbind().on('click', e => { + e.preventDefault(); + Actions.rename(); + }); + } + + if (Pterodactyl.permissions.copyFiles) { + $(menu).find('li[data-action="copy"]').unbind().on('click', e => { + e.preventDefault(); + Actions.copy(); + }); + } + + if (Pterodactyl.permissions.compressFiles) { + if (parent.data('type') === 'folder') { + $(menu).find('li[data-action="compress"]').removeClass('hidden'); + } + $(menu).find('li[data-action="compress"]').unbind().on('click', e => { + e.preventDefault(); + Actions.compress(); + }); + } + + if (Pterodactyl.permissions.decompressFiles) { + if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) { + $(menu).find('li[data-action="decompress"]').removeClass('hidden'); + } + $(menu).find('li[data-action="decompress"]').unbind().on('click', e => { + e.preventDefault(); + Actions.decompress(); + }); + } + + if (Pterodactyl.permissions.createFiles) { + $(menu).find('li[data-action="folder"]').unbind().on('click', e => { + e.preventDefault(); + Actions.folder(); + }); + } + + if (Pterodactyl.permissions.downloadFiles) { + if (parent.data('type') === 'file') { + $(menu).find('li[data-action="download"]').removeClass('hidden'); + } + $(menu).find('li[data-action="download"]').unbind().on('click', e => { + e.preventDefault(); + Actions.download(); + }); + } + + if (Pterodactyl.permissions.deleteFiles) { + $(menu).find('li[data-action="delete"]').unbind().on('click', e => { + e.preventDefault(); + Actions.delete(); + }); + } + + $(window).on('click', () => { + $(menu).remove(); + if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active'); + }); + } + + directoryClick() { + $('a[data-action="directory-view"]').on('click', function (event) { + event.preventDefault(); + + const path = $(this).parent().data('path') || ''; + const name = $(this).parent().data('name') || ''; + + window.location.hash = encodeURIComponent(path + name); + Files.list(); + }); + } +} + +window.ContextMenu = new ContextMenuClass; diff --git a/resources/views/server/js/filemanager/index.blade.php b/public/js/files/index.js similarity index 94% rename from resources/views/server/js/filemanager/index.blade.php rename to public/js/files/index.js index a89b4114f..f833ab2af 100644 --- a/resources/views/server/js/filemanager/index.blade.php +++ b/public/js/files/index.js @@ -1,6 +1,6 @@ "use strict"; -// Copyright (c) 2015 - 2016 Dane Everitt +// Copyright (c) 2015 - 2017 Dane Everitt // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,9 +32,9 @@ class FileManager { this.loader(true); $.ajax({ type: 'POST', - url: '{{ route('server.files.directory-list', $server->uuidShort) }}', + url: Pterodactyl.meta.directoryList, headers: { - 'X-CSRF-Token': '{{ csrf_token() }}', + 'X-CSRF-Token': Pterodactyl.meta.csrftoken, }, data: { directory: path, diff --git a/public/js/jquery.terminal-0.11.23.min.js b/public/js/jquery.terminal-0.11.23.min.js new file mode 100644 index 000000000..0fd1cd1fd --- /dev/null +++ b/public/js/jquery.terminal-0.11.23.min.js @@ -0,0 +1,38 @@ +/**@license + * __ _____ ________ __ + * / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / / + * __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ / + * / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__ + * \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/ + * \/ /____/ version 0.11.23 + * + * This file is part of jQuery Terminal. http://terminal.jcubic.pl + * + * Copyright (c) 2010-2016 Jakub Jankiewicz + * Released under the MIT license + * + * Contains: + * + * Storage plugin Distributed under the MIT License + * Copyright (c) 2010 Dave Schindler + * + * jQuery Timers licenced with the WTFPL + * + * + * Cross-Browser Split 1.1.1 + * Copyright 2007-2012 Steven Levithan + * Available under the MIT License + * + * jQuery Caret + * Copyright (c) 2009, Gideon Sireling + * 3 clause BSD License + * + * sprintf.js + * Copyright (c) 2007-2013 Alexandru Marasteanu + * licensed under 3 clause BSD license + * + * Date: Sat, 10 Dec 2016 10:56:53 +0000 + */ +(function(e){var n=function(){if(!n.cache.hasOwnProperty(arguments[0])){n.cache[arguments[0]]=n.parse(arguments[0])}return n.format.call(null,n.cache[arguments[0]],arguments)};n.format=function(e,t){var o=1,a=e.length,s="",l,f=[],c,u,h,p,m,g;for(c=0;c>>0;break;case"x":l=l.toString(16);break;case"X":l=l.toString(16).toUpperCase();break}l=/[def]/.test(h[8])&&h[3]&&l>=0?"+"+l:l;m=h[4]?h[4]=="0"?"0":h[4].charAt(1):" ";g=h[6]-String(l).length;p=h[6]?i(m,g):"";f.push(h[5]?l+p:p+l)}}return f.join("")};n.cache={};n.parse=function(e){var n=e,t=[],r=[],i=0;while(n){if((t=/^[^\x25]+/.exec(n))!==null){r.push(t[0])}else if((t=/^\x25{2}/.exec(n))!==null){r.push("%")}else if((t=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(n))!==null){if(t[2]){i|=1;var o=[],a=t[2],s=[];if((s=/^([a-z_][a-z_\d]*)/i.exec(a))!==null){o.push(s[1]);while((a=a.substring(s[0].length))!==""){if((s=/^\.([a-z_][a-z_\d]*)/i.exec(a))!==null){o.push(s[1])}else if((s=/^\[(\d+)\]/.exec(a))!==null){o.push(s[1])}else{throw"[sprintf] huh?"}}}else{throw"[sprintf] huh?"}t[2]=o}else{i|=2}if(i===3){throw"[sprintf] mixing positional and named placeholders is not (yet) supported"}r.push(t)}else{throw"[sprintf] huh?"}n=n.substring(t[0].length)}return r};var t=function(e,t,r){r=t.slice(0);r.splice(0,0,e);return n.apply(null,r)};function r(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}function i(e,n){for(var t=[];n>0;t[--n]=e){}return t.join("")}e.sprintf=n;e.vsprintf=t})(typeof global!="undefined"?global:window);(function(e,n){"use strict";e.omap=function(n,t){var r={};e.each(n,function(e,i){r[e]=t.call(n,e,i)});return r};var t={clone_object:function(n){var t={};if(typeof n=="object"){if(e.isArray(n)){return this.clone_array(n)}else if(n===null){return n}else{for(var r in n){if(e.isArray(n[r])){t[r]=this.clone_array(n[r])}else if(typeof n[r]=="object"){t[r]=this.clone_object(n[r])}else{t[r]=n[r]}}}}return t},clone_array:function(n){if(!e.isFunction(Array.prototype.map)){throw new Error("You'r browser don't support ES5 array map "+"use es5-shim")}return n.slice(0).map(function(e){if(typeof e=="object"){return this.clone_object(e)}else{return e}}.bind(this))}};var r=function(e){return t.clone_object(e)};var i=function(){var e="test",n=window.localStorage;try{n.setItem(e,"1");n.removeItem(e);return true}catch(t){return false}};var o=i();function a(e,n){var t;if(typeof e==="string"&&typeof n==="string"){localStorage[e]=n;return true}else if(typeof e==="object"&&typeof n==="undefined"){for(t in e){if(e.hasOwnProperty(t)){localStorage[t]=e[t]}}return true}return false}function s(e,n){var t,r,i;t=new Date;t.setTime(t.getTime()+31536e6);r="; expires="+t.toGMTString();if(typeof e==="string"&&typeof n==="string"){document.cookie=e+"="+n+r+"; path=/";return true}else if(typeof e==="object"&&typeof n==="undefined"){for(i in e){if(e.hasOwnProperty(i)){document.cookie=i+"="+e[i]+r+"; path=/"}}return true}return false}function l(e){return localStorage[e]}function f(e){var n,t,r,i;n=e+"=";t=document.cookie.split(";");for(r=0;ri&&i!==0||r.call(e,a)===false){h.timer.remove(e,t,r)}s.inProgress=false};s.$timerID=r.$timerID;if(!e.$timers[t][r.$timerID]){e.$timers[t][r.$timerID]=window.setInterval(s,n)}if(!this.global[t]){this.global[t]=[]}this.global[t].push(e)},remove:function(e,n,t){var r=e.$timers,i;if(r){if(!n){for(var o in r){if(r.hasOwnProperty(o)){this.remove(e,o,t)}}}else if(r[n]){if(t){if(t.$timerID){window.clearInterval(r[n][t.$timerID]);delete r[n][t.$timerID]}}else{for(var a in r[n]){if(r[n].hasOwnProperty(a)){window.clearInterval(r[n][a]);delete r[n][a]}}}for(i in r[n]){if(r[n].hasOwnProperty(i)){break}}if(!i){i=null;delete r[n]}}for(i in r){if(r.hasOwnProperty(i)){break}}if(!i){e.$timers=null}}}}});if(/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase())){h(window).one("unload",function(){var e=h.timer.global;for(var n in e){if(e.hasOwnProperty(n)){var t=e[n],r=t.length;while(--r){h.timer.remove(t[r],n)}}}})}(function(e){if(!String.prototype.split.toString().match(/\[native/)){return}var n=String.prototype.split,t=/()??/.exec("")[1]===e,r;r=function(r,i,o){if(Object.prototype.toString.call(i)!=="[object RegExp]"){return n.call(r,i,o)}var a=[],s=(i.ignoreCase?"i":"")+(i.multiline?"m":"")+(i.extended?"x":"")+(i.sticky?"y":""),l=0,f,c,u,h;i=new RegExp(i.source,s+"g");r+="";if(!t){f=new RegExp("^"+i.source+"$(?!\\s)",s)}o=o===e?-1>>>0:o>>>0;while(c=i.exec(r)){u=c.index+c[0].length;if(u>l){a.push(r.slice(l,c.index));if(!t&&c.length>1){c[0].replace(f,function(){for(var n=1;n1&&c.index=o){break}}if(i.lastIndex===c.index){i.lastIndex++}}if(l===r.length){if(h||!i.test("")){a.push("")}}else{a.push(r.slice(l))}return a.length>o?a.slice(0,o):a};String.prototype.split=function(e,n){return r(this,e,n)};return r})();e.fn.caret=function(e){var n=this[0];var t=n.contentEditable==="true";if(arguments.length==0){if(window.getSelection){if(t){n.focus();var r=window.getSelection().getRangeAt(0),i=r.cloneRange();i.selectNodeContents(n);i.setEnd(r.endContainer,r.endOffset);return i.toString().length}return n.selectionStart}if(document.selection){n.focus();if(t){var r=document.selection.createRange(),i=document.body.createTextRange();i.moveToElementText(n);i.setEndPoint("EndToEnd",r);return i.text.length}var e=0,o=n.createTextRange(),i=document.selection.createRange().duplicate(),a=i.getBookmark();o.moveToBookmark(a);while(o.moveStart("character",-1)!==0)e++;return e}return 0}if(e==-1)e=this[t?"text":"val"]().length;if(window.getSelection){if(t){n.focus();window.getSelection().collapse(n.firstChild,e)}else n.setSelectionRange(e,e)}else if(document.body.createTextRange){var o=document.body.createTextRange();o.moveToElementText(n);o.moveStart("character",e);o.collapse(true);o.select()}if(!t)n.focus();return e};function p(e,n){var t=[];var r=e.length;if(rt.length){if(n){break}e=0;n=true}}return t[e]}},append:function(e){t.push(e)}})}function g(n){var t=n instanceof Array?n:n?[n]:[];e.extend(this,{data:function(){return t},map:function(n){return e.map(t,n)},size:function(){return t.length},pop:function(){if(t.length===0){return null}else{var e=t[t.length-1];t=t.slice(0,t.length-1);return e}},push:function(e){t=t.concat([e]);return e},top:function(){return t.length>0?t[t.length-1]:null},clone:function(){return new g(t.slice(0))}})}function d(n,t,r){var i=true;var o="";if(typeof n==="string"&&n!==""){o=n+"_"}o+="commands";var a;if(r){a=[]}else{a=e.Storage.get(o);a=a?e.parseJSON(a):[]}var s=a.length-1;e.extend(this,{append:function(n){if(i){if(a[a.length-1]!==n){a.push(n);if(t&&a.length>t){a=a.slice(-t)}s=a.length-1;if(!r){e.Storage.set(o,JSON.stringify(a))}}}},data:function(){return a},reset:function(){s=a.length-1},last:function(){return a[a.length-1]},end:function(){return s===a.length-1},position:function(){return s},current:function(){return a[s]},next:function(){if(s0){--s}if(e!==-1){return a[s]}},clear:function(){a=[];this.purge()},enabled:function(){return i},enable:function(){i=true},purge:function(){if(!r){e.Storage.remove(o)}},disable:function(){i=false}})}var v=function(){var e=document.createElement("div");e.setAttribute("onpaste","return;");return typeof e.onpaste=="function"}();var y=true;e.fn.cmd=function(t){var r=this;var i=r.data("cmd");if(i){return i}r.addClass("cmd");r.append(''+' ');var o=e(" +

    @lang('base.api.new.allowed_ips.description')

    + + +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    @lang('base.api.new.base.title')
    +
    +
    +
    + +
    +
    +
    + @if(Auth::user()->isRootAdmin()) +
    +
    +
    @lang('base.api.new.user_management.title')
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    @lang('base.api.new.node_management.title')
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + @endif +
    +
    +
    +
    +
    @lang('base.api.new.server_management.title')
    +
    +
    +
    + +
    +
    + +
    + @if(Auth::user()->isRootAdmin()) +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + @endif +
    +
    + @if(Auth::user()->isRootAdmin()) +
    +
    +
    @lang('base.api.new.service_management.title')
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    @lang('base.api.new.location_management.title')
    +
    +
    +
    + +
    +
    +
    + @endif +
    + {!! csrf_field() !!} + + +@endsection diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php new file mode 100644 index 000000000..c6066c25a --- /dev/null +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -0,0 +1,89 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('base.index.header') +@endsection + +@section('content-header') +

    @lang('base.index.header')@lang('base.index.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('base.index.list')

    +
    +
    + +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + + @foreach($servers as $server) + + + + + + + + + + @endforeach + +
    @lang('strings.id')@lang('strings.name')@lang('strings.node')@lang('strings.connection')@lang('strings.status')
    {{ $server->uuidShort }}{{ $server->name }}{{ $server->nodeName }}@if(!is_null($server->ip_alias)){{ $server->ip_alias }}@else{{ $server->ip }}@endif:{{ $server->port }} + @if($server->suspended === 1) + @lang('strings.suspended') + @else + + @endif +
    +
    +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/serverlist.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/base/security.blade.php b/resources/themes/pterodactyl/base/security.blade.php new file mode 100644 index 000000000..666a790bc --- /dev/null +++ b/resources/themes/pterodactyl/base/security.blade.php @@ -0,0 +1,143 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('base.security.header') +@endsection + +@section('content-header') +

    @lang('base.security.header')@lang('base.security.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('base.security.sessions')

    +
    +
    + + + + + + + + + @foreach($sessions as $session) + + + + + + + @endforeach + +
    @lang('strings.id')@lang('strings.ip')@lang('strings.last_activity')
    {{ substr($session->id, 0, 6) }}{{ $session->ip_address }}{{ Carbon::createFromTimestamp($session->last_activity)->diffForHumans() }} + + + +
    +
    +
    +
    +
    +
    +
    +

    @lang('base.security.2fa_header')

    +
    + @if(Auth::user()->use_totp) +
    +
    +

    @lang('base.security.2fa_enabled')

    +
    + +
    + +

    @lang('base.security.2fa_token_help')

    +
    +
    +
    + +
    + @else +
    +
    + @lang('base.security.2fa_disabled') +
    + +
    + @endif +
    +
    +
    + +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/2fa-modal.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/errors/403.blade.php b/resources/themes/pterodactyl/errors/403.blade.php new file mode 100644 index 000000000..225852a15 --- /dev/null +++ b/resources/themes/pterodactyl/errors/403.blade.php @@ -0,0 +1,45 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.error') + +@section('title') + @lang('base.errors.403.header') +@endsection + +@section('content-header') +@endsection + +@section('content') + +
    +
    +
    +
    +

    403

    +

    @lang('base.errors.403.desc')

    +
    + +
    +
    +
    +@endsection diff --git a/resources/themes/pterodactyl/errors/404.blade.php b/resources/themes/pterodactyl/errors/404.blade.php new file mode 100644 index 000000000..39ace2669 --- /dev/null +++ b/resources/themes/pterodactyl/errors/404.blade.php @@ -0,0 +1,45 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.error') + +@section('title') + @lang('base.errors.404.header') +@endsection + +@section('content-header') +@endsection + +@section('content') + +
    +
    +
    +
    +

    404

    +

    @lang('base.errors.404.desc')

    +
    + +
    +
    +
    +@endsection diff --git a/resources/themes/pterodactyl/layouts/auth.blade.php b/resources/themes/pterodactyl/layouts/auth.blade.php new file mode 100644 index 000000000..58758f4fa --- /dev/null +++ b/resources/themes/pterodactyl/layouts/auth.blade.php @@ -0,0 +1,53 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} + + + + + + {{ Settings::get('company', 'Pterodactyl') }} - @yield('title') + + @section('scripts') + {!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!} + {!! Theme::css('vendor/adminlte/admin.min.css') !!} + {!! Theme::css('css/pterodactyl.css') !!} + + + + + @show + + + + {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} + {!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!} + + diff --git a/resources/themes/pterodactyl/layouts/error.blade.php b/resources/themes/pterodactyl/layouts/error.blade.php new file mode 100644 index 000000000..fd78fd81e --- /dev/null +++ b/resources/themes/pterodactyl/layouts/error.blade.php @@ -0,0 +1,74 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} + + + + + + {{ Settings::get('company', 'Pterodactyl') }} - @yield('title') + + + @section('scripts') + {!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!} + {!! Theme::css('vendor/adminlte/admin.min.css') !!} + {!! Theme::css('vendor/adminlte/colors/skin-blue.min.css') !!} + {!! Theme::css('vendor/sweetalert/sweetalert.min.css') !!} + {!! Theme::css('css/pterodactyl.css') !!} + + + + + @show + + +
    +
    + + +
    +
    +
    + @yield('content-header') +
    +
    + @yield('content') +
    +
    + +
    + @section('footer-scripts') + {!! Theme::js('js/laroute.js') !!} + {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} + {!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!} + {!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js') !!} + {!! Theme::js('vendor/adminlte/app.min.js') !!} + @show + + diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php new file mode 100644 index 000000000..19b03380f --- /dev/null +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -0,0 +1,286 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} + + + + + + {{ Settings::get('company', 'Pterodactyl') }} - @yield('title') + + + @section('scripts') + {!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!} + {!! Theme::css('vendor/adminlte/admin.min.css') !!} + {!! Theme::css('vendor/adminlte/colors/skin-blue.min.css') !!} + {!! Theme::css('vendor/sweetalert/sweetalert.min.css') !!} + {!! Theme::css('vendor/animate/animate.min.css') !!} + {!! Theme::css('css/pterodactyl.css') !!} + + + + + @show + + +
    +
    + + +
    + +
    +
    + @yield('content-header') +
    +
    +
    +
    + @if (count($errors) > 0) +
    + @lang('base.validation_error')

    +
      + @foreach ($errors->all() as $error) +
    • {{ $error }}
    • + @endforeach +
    +
    + @endif + @foreach (Alert::getMessages() as $type => $messages) + @foreach ($messages as $message) + + @endforeach + @endforeach +
    +
    + @yield('content') +
    +
    + + +
    +
    + @section('footer-scripts') + {!! Theme::js('js/laroute.js') !!} + {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} + {!! Theme::js('vendor/sweetalert/sweetalert.min.js') !!} + {!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!} + {!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js') !!} + {!! Theme::js('vendor/adminlte/app.min.js') !!} + {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} + {!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js') !!} + @show + + diff --git a/resources/themes/pterodactyl/server/files/add.blade.php b/resources/themes/pterodactyl/server/files/add.blade.php new file mode 100644 index 000000000..d605b8dd5 --- /dev/null +++ b/resources/themes/pterodactyl/server/files/add.blade.php @@ -0,0 +1,109 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.files.add.header') +@endsection + +@section('scripts') + {{-- This has to be loaded before the AdminLTE theme to avoid dropdown issues. --}} + {!! Theme::css('vendor/select2/select2.min.css') !!} + @parent +@endsection + +@section('content-header') +

    @lang('server.files.add.header')@lang('server.files.add.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +
    + /home/container/ + +
    +
    +
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('vendor/select2/select2.full.min.js') !!} + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/vendor/ace/ace.js') !!} + {!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + {!! Theme::js('js/vendor/lodash/lodash.js') !!} + {!! Theme::js('js/frontend/files/editor.js') !!} + +@endsection diff --git a/resources/themes/pterodactyl/server/files/edit.blade.php b/resources/themes/pterodactyl/server/files/edit.blade.php new file mode 100644 index 000000000..fece93d10 --- /dev/null +++ b/resources/themes/pterodactyl/server/files/edit.blade.php @@ -0,0 +1,63 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.files.edit.header') +@endsection + +@section('content-header') +

    @lang('server.files.edit.header')@lang('server.files.edit.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    + + +
    {{ $contents }}
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/vendor/ace/ace.js') !!} + {!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + {!! Theme::js('js/frontend/files/editor.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/server/files/index.blade.php b/resources/themes/pterodactyl/server/files/index.blade.php new file mode 100644 index 000000000..932176a9a --- /dev/null +++ b/resources/themes/pterodactyl/server/files/index.blade.php @@ -0,0 +1,66 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.files.header') +@endsection + +@section('content-header') +

    @lang('server.files.header')@lang('server.files.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +
    +
    @lang('server.files.loading')
    +
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/vendor/async/async.min.js') !!} + {!! Theme::js('js/vendor/lodash/lodash.js') !!} + {!! Theme::js('vendor/siofu/client.min.js') !!} + @if(App::environment('production')) + {!! Theme::js('js/frontend/files/filemanager.min.js') !!} + @else + {!! Theme::js('js/frontend/files/src/index.js') !!} + {!! Theme::js('js/frontend/files/src/contextmenu.js') !!} + {!! Theme::js('js/frontend/files/src/actions.js') !!} + @endif + {!! Theme::js('js/frontend/files/upload.js') !!} +@endsection diff --git a/resources/views/server/files/list.blade.php b/resources/themes/pterodactyl/server/files/list.blade.php similarity index 79% rename from resources/views/server/files/list.blade.php rename to resources/themes/pterodactyl/server/files/list.blade.php index 74f539efb..ab9d51703 100644 --- a/resources/views/server/files/list.blade.php +++ b/resources/themes/pterodactyl/server/files/list.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -20,18 +20,23 @@ - - - - + + + + + - @@ -42,7 +47,8 @@ - + + @endif @@ -52,32 +58,34 @@ - + + @endif @foreach ($folders as $folder) - - + + - - + + @endforeach @foreach ($files as $file) - - + - - + + @endforeach diff --git a/resources/themes/pterodactyl/server/index.blade.php b/resources/themes/pterodactyl/server/index.blade.php new file mode 100644 index 000000000..67e6c956c --- /dev/null +++ b/resources/themes/pterodactyl/server/index.blade.php @@ -0,0 +1,91 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + {{ trans('server.index.title', [ 'name' => $server->name]) }} +@endsection + +@section('scripts') + @parent + {!! Theme::css('css/jquery.terminal.css') !!} +@endsection + +@section('content-header') +

    @lang('server.index.header')@lang('server.index.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +

    Memory Usage

    +
    +
    + +
    +
    +
    +
    +
    +
    +

    CPU Usage

    +
    +
    + +
    +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/jquery.mousewheel-min.js') !!} + {!! Theme::js('js/jquery.terminal-0.11.23.min.js') !!} + {!! Theme::js('js/unix_formatting.js') !!} + {!! Theme::js('js/frontend/console.js') !!} + {!! Theme::js('js/vendor/chartjs/chart.min.js') !!} + {!! Theme::js('js/vendor/jquery/jquery-dateFormat.min.js') !!} + @if($server->a_serviceFile === 'minecraft') + {!! Theme::js('js/plugins/minecraft/eula.js') !!} + @endif +@endsection diff --git a/resources/themes/pterodactyl/server/settings/allocation.blade.php b/resources/themes/pterodactyl/server/settings/allocation.blade.php new file mode 100644 index 000000000..f2782a88c --- /dev/null +++ b/resources/themes/pterodactyl/server/settings/allocation.blade.php @@ -0,0 +1,129 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.config.allocation.header') +@endsection + +@section('content-header') +

    @lang('server.config.allocation.header')@lang('server.config.allocation.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.config.allocation.available')

    +
    +
    +
    File NameSizeLast Modified@lang('server.files.file_name') + +
    + /home/container{{ $directory['header'] }} - +
    ← {{ $directory['link_show'] }}
    {{ $folder['entry'] }} {{ $folder['size'] }} +
    +
    {{-- oh boy --}} @if(in_array($file['mime'], [ 'application/x-7z-compressed', @@ -138,17 +146,18 @@ {{ $file['entry'] }} @endif {{ $file['size'] }} +
    + + + + + + + + @foreach ($allocations as $allocation) + + + + + + + @endforeach + +
    @lang('strings.ip')@lang('strings.alias')@lang('strings.port')
    + {{ $allocation->ip }} + + @if(is_null($allocation->ip_alias)) + @lang('strings.none') + @else + {{ $allocation->ip_alias }} + @endif + {{ $allocation->port }} + @if($allocation->id === $server->allocation) + @lang('strings.primary') + @else + @lang('strings.make_primary') + @endif +
    +
    +
    + +
    +
    +
    +

    @lang('server.config.allocation.help')

    +
    +
    +

    @lang('server.config.allocation.help_text')

    +
    +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + +@endsection diff --git a/resources/themes/pterodactyl/server/settings/databases.blade.php b/resources/themes/pterodactyl/server/settings/databases.blade.php new file mode 100644 index 000000000..b69b0f36d --- /dev/null +++ b/resources/themes/pterodactyl/server/settings/databases.blade.php @@ -0,0 +1,123 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.config.database.header') +@endsection + +@section('content-header') +

    @lang('server.config.database.header')@lang('server.config.database.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.config.database.your_dbs')

    +
    + @if(count($databases) > 0) +
    + + + + + + + + + @foreach($databases as $database) + + + + + + + @endforeach + +
    @lang('strings.database')@lang('strings.username')@lang('strings.password')@lang('server.config.database.host')
    {{ $database->database }}{{ $database->username }}{{ Crypt::decrypt($database->password) }} + @can('reset-db-password', $server) + + @endcan + {{ $database->a_host }}:{{ $database->a_port }}
    +
    + @else +
    +
    + @lang('server.config.database.no_dbs') + @if(Auth::user()->root_admin === 1) + @lang('server.config.database.add_db') + @endif +
    +
    + @endif +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + +@endsection diff --git a/resources/themes/pterodactyl/server/settings/sftp.blade.php b/resources/themes/pterodactyl/server/settings/sftp.blade.php new file mode 100644 index 000000000..747b93412 --- /dev/null +++ b/resources/themes/pterodactyl/server/settings/sftp.blade.php @@ -0,0 +1,114 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.config.sftp.header') +@endsection + +@section('content-header') +

    @lang('server.config.sftp.header')@lang('server.config.sftp.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.config.sftp.change_pass')

    +
    + @can('reset-sftp', $server) +
    +
    +
    + +
    + +

    @lang('auth.password_requirements')

    +
    +
    +
    + +
    + @else +
    +
    +

    @lang('auth.not_authorized')

    +
    +
    + @endcan +
    +
    +
    +
    +
    +

    @lang('server.config.sftp.details')

    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    + +
    +
    + @can('view-sftp-password', $server) +
    + +
    + sftp_password))value="{{ Crypt::decrypt($server->sftp_password) }}"@endif /> +
    +
    + @endcan +
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/server/settings/startup.blade.php b/resources/themes/pterodactyl/server/settings/startup.blade.php new file mode 100644 index 000000000..745d0d3fd --- /dev/null +++ b/resources/themes/pterodactyl/server/settings/startup.blade.php @@ -0,0 +1,98 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.config.startup.header') +@endsection + +@section('content-header') +

    @lang('server.config.startup.header')@lang('server.config.startup.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.config.startup.command')

    +
    +
    +
    + {{ $service->executable }} + +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.config.startup.edit_params')

    +
    + @can('edit-startup', $server) +
    +
    + @foreach($variables as $item) +
    + +
    + user_editable === 1) + name="{{ $item->env_variable }}" + @else + readonly="readonly" + @endif + class="form-control" value="{{ old($item->env_variable, $item->a_serverValue) }}" data-action="matchRegex" data-regex="{{ $item->regex }}" /> +
    +

    {!! $item->description !!}

    +
    + @endforeach +
    + +
    + @else +
    +
    +

    @lang('auth.not_authorized')

    +
    +
    + @endcan +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/server/tasks/index.blade.php b/resources/themes/pterodactyl/server/tasks/index.blade.php new file mode 100644 index 000000000..cd0f529e3 --- /dev/null +++ b/resources/themes/pterodactyl/server/tasks/index.blade.php @@ -0,0 +1,99 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.tasks.header') +@endsection + +@section('content-header') +

    @lang('server.tasks.header')@lang('server.tasks.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.tasks.current')

    +
    +
    + + + + + + + + + + + + @foreach($tasks as $task) + active === 0)class="muted muted-hover"@endif> + + + + + + @can('delete-task', $server) + + @endcan + @can('toggle-task', $server) + + @endcan + + @endforeach + + +
    @lang('strings.action')@lang('strings.data')@lang('strings.queued')@lang('strings.last_run')@lang('strings.next_run')
    {{ $actions[$task->action] }}{{ $task->data }} + @if ($task->queued) + @lang('strings.yes') + @else + @lang('strings.no') + @endif + {{ Carbon::parse($task->last_run)->toDayDateTimeString() }}
    ({{ Carbon::parse($task->last_run)->diffForHumans() }})
    + @if($task->active !== 0) + {{ Carbon::parse($task->next_run)->toDayDateTimeString() }}
    ({{ Carbon::parse($task->next_run)->diffForHumans() }}) + @else + n/a + @endif +
    +
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/frontend/tasks.js') !!} +@endsection diff --git a/resources/views/server/tasks/new.blade.php b/resources/themes/pterodactyl/server/tasks/new.blade.php similarity index 52% rename from resources/views/server/tasks/new.blade.php rename to resources/themes/pterodactyl/server/tasks/new.blade.php index 230a8399f..045d2fe8d 100644 --- a/resources/views/server/tasks/new.blade.php +++ b/resources/themes/pterodactyl/server/tasks/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -20,34 +20,50 @@ @extends('layouts.master') @section('title') - Scheduled Tasks + @lang('server.tasks.new.header') +@endsection + +@section('scripts') + {{-- This has to be loaded before the AdminLTE theme to avoid dropdown issues. --}} + {!! Theme::css('vendor/select2/select2.min.css') !!} + @parent +@endsection + +@section('content-header') +

    @lang('server.tasks.new.header')@lang('server.tasks.new.header_sub')

    + @endsection @section('content') -
    -

    Create Scheduled Task
    Current System Time: {{ Carbon::now()->toDayDateTimeString() }}


    -
    -
    You may use either the dropdown selection boxes or enter custom cron variables into the fields below.
    -
    -
    -
    + +
    +
    +
    +
    +

    @lang('server.tasks.new.day_of_week')

    +
    +
    -
    - +
    @@ -55,11 +71,15 @@
    -
    -
    +
    +
    +
    +
    +

    @lang('server.tasks.new.day_of_month')

    +
    +
    -
    @@ -78,12 +98,14 @@
    -
    -
    -
    +
    +
    +
    +

    @lang('server.tasks.new.hour')

    +
    +
    -
    @@ -101,11 +123,15 @@
    -
    -
    +
    +
    +
    +
    +

    @lang('server.tasks.new.minute')

    +
    +
    -
    @@ -126,35 +152,46 @@
    -
    -
    - -
    - +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + + @lang('server.tasks.new.payload_help') +
    +
    +
    -
    -
    - -
    - -

    For example, if you selected Send Command enter the command here. If you selected Send Power Option put the power action here (e.g. restart).

    +
    -
    -
    - {!! csrf_field() !!} - -
    -
    - +
    - + @endsection diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php new file mode 100644 index 000000000..f44849758 --- /dev/null +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -0,0 +1,99 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.users.header') +@endsection + +@section('content-header') +

    @lang('server.users.header')@lang('server.users.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.users.list')

    +
    +
    + + + + + + + + + @can('view-subuser', $server)@endcan + @can('delete-subuser', $server)@endcan + + @foreach($subusers as $user) + + + + + + @can('view-subuser', $server) + + @endcan + @can('delete-subuser', $server) + + @endcan + + @endforeach + +
    @lang('strings.username')@lang('strings.email')@lang('strings.2fa')
    User Image{{ $user->username }} + {{ $user->email }} + @if($user->use_totp) + + @else + + @endif + + + + + + + + +
    +
    + @can('create-subuser', $server) + + @endcan +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/server/users/new.blade.php b/resources/themes/pterodactyl/server/users/new.blade.php new file mode 100644 index 000000000..5cbe5617f --- /dev/null +++ b/resources/themes/pterodactyl/server/users/new.blade.php @@ -0,0 +1,414 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.users.new.header') +@endsection + +@section('content-header') +

    @lang('server.users.new.header')@lang('server.users.new.header_sub')

    + +@endsection + +@section('content') + +
    +
    +
    +
    +
    +
    + +
    + {!! csrf_field() !!} + +

    @lang('server.users.new.email_help')

    +
    +
    +
    + +
    +
    +
    +
    +
    + {{-- Left Side --}} +
    +
    +
    +
    +

    @lang('server.users.new.power_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.subuser_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.server_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.sftp_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + {{-- Right Side --}} +
    +
    +
    +
    +

    @lang('server.users.new.file_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.task_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.db_header')

    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + +@endsection diff --git a/resources/themes/pterodactyl/server/users/view.blade.php b/resources/themes/pterodactyl/server/users/view.blade.php new file mode 100644 index 000000000..b697edc34 --- /dev/null +++ b/resources/themes/pterodactyl/server/users/view.blade.php @@ -0,0 +1,418 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.master') + +@section('title') + @lang('server.users.new.header') +@endsection + +@section('content-header') +

    @lang('server.users.edit.header')@lang('server.users.edit.header_sub')

    + +@endsection + +@section('content') +@can('edit-subuser', $server) +
    +@endcan +
    +
    +
    +
    +
    + +
    + {!! csrf_field() !!} + +
    +
    +
    + @can('edit-subuser', $server) + + @endcan +
    +
    +
    +
    +
    + {{-- Left Side --}} +
    +
    +
    +
    +

    @lang('server.users.new.power_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.subuser_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.server_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.sftp_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + {{-- Right Side --}} +
    +
    +
    +
    +

    @lang('server.users.new.file_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.task_header')

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.users.new.db_header')

    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +@can('edit-subuser', $server) +
    +@endcan +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + +@endsection diff --git a/resources/views/server/tasks/view.blade.php b/resources/themes/pterodactyl/vendor/.gitkeep similarity index 100% rename from resources/views/server/tasks/view.blade.php rename to resources/themes/pterodactyl/vendor/.gitkeep diff --git a/resources/themes/pterodactyl/vendor/notifications/email-plain.blade.php b/resources/themes/pterodactyl/vendor/notifications/email-plain.blade.php new file mode 100644 index 000000000..875095895 --- /dev/null +++ b/resources/themes/pterodactyl/vendor/notifications/email-plain.blade.php @@ -0,0 +1,22 @@ + + + + + + + + + + + 'margin: 0; padding: 0; width: 100%; background-color: #F2F4F6;', + 'email-wrapper' => 'width: 100%; margin: 0; padding: 0; background-color: #F2F4F6;', + + /* Masthead ----------------------- */ + + 'email-masthead' => 'padding: 25px 0; text-align: center;', + 'email-masthead_name' => 'font-size: 16px; font-weight: bold; color: #2F3133; text-decoration: none; text-shadow: 0 1px 0 white;', + + 'email-body' => 'width: 100%; margin: 0; padding: 0; border-top: 1px solid #EDEFF2; border-bottom: 1px solid #EDEFF2; background-color: #FFF;', + 'email-body_inner' => 'width: auto; max-width: 570px; margin: 0 auto; padding: 0;', + 'email-body_cell' => 'padding: 35px;', + + 'email-footer' => 'width: auto; max-width: 570px; margin: 0 auto; padding: 0; text-align: center;', + 'email-footer_cell' => 'color: #AEAEAE; padding: 35px; text-align: center;', + + /* Body ------------------------------ */ + + 'body_action' => 'width: 100%; margin: 30px auto; padding: 0; text-align: center;', + 'body_sub' => 'margin-top: 25px; padding-top: 25px; border-top: 1px solid #EDEFF2;', + + /* Type ------------------------------ */ + + 'anchor' => 'color: #3869D4;', + 'header-1' => 'margin-top: 0; color: #2F3133; font-size: 19px; font-weight: bold; text-align: left;', + 'paragraph' => 'margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;', + 'paragraph-sub' => 'margin-top: 0; color: #74787E; font-size: 12px; line-height: 1.5em;', + 'paragraph-center' => 'text-align: center;', + + /* Buttons ------------------------------ */ + + 'button' => 'display: block; display: inline-block; width: 200px; min-height: 20px; padding: 10px; + background-color: #3869D4; border-radius: 3px; color: #ffffff; font-size: 15px; line-height: 25px; + text-align: center; text-decoration: none; -webkit-text-size-adjust: none;', + + 'button--green' => 'background-color: #22BC66;', + 'button--red' => 'background-color: #dc4d2f;', + 'button--blue' => 'background-color: #3869D4;', +]; +?> + + + + + + + + +
    + + + + + + + + + + + + + + + +
    + + {{ Settings::get('company') }} + +
    + + + + +
    + +

    + @if (! empty($greeting)) + {{ $greeting }} + @else + @if ($level == 'error') + Whoops! + @else + Hello! + @endif + @endif +

    + + + @foreach ($introLines as $line) +

    + {{ $line }} +

    + @endforeach + + + @if (isset($actionText)) + + + + +
    + + + + {{ $actionText }} + +
    + @endif + + + @foreach ($outroLines as $line) +

    + {{ $line }} +

    + @endforeach + + +

    + Regards,
    {{ Settings::get('company') }} +

    + + + @if (isset($actionText)) + + + + +
    +

    + If you’re having trouble clicking the "{{ $actionText }}" button, + copy and paste the URL below into your web browser: +

    + +

    + + {{ $actionUrl }} + +

    +
    + @endif +
    +
    + + + + +
    +

    + © {{ date('Y') }} + {{ Settings::get('company') }}. + All rights reserved. +

    +
    +
    +
    + + diff --git a/resources/themes/pterodactyl/vendor/pagination/bootstrap-4.blade.php b/resources/themes/pterodactyl/vendor/pagination/bootstrap-4.blade.php new file mode 100644 index 000000000..9d80428cc --- /dev/null +++ b/resources/themes/pterodactyl/vendor/pagination/bootstrap-4.blade.php @@ -0,0 +1,36 @@ +@if ($paginator->count() > 1) +
      + + @if ($paginator->onFirstPage()) +
    • «
    • + @else +
    • + @endif + + + @foreach ($elements as $element) + + @if (is_string($element)) +
    • {{ $element }}
    • + @endif + + + @if (is_array($element)) + @foreach ($element as $page => $url) + @if ($page == $paginator->currentPage()) +
    • {{ $page }}
    • + @else +
    • {{ $page }}
    • + @endif + @endforeach + @endif + @endforeach + + + @if ($paginator->hasMorePages()) +
    • + @else +
    • »
    • + @endif +
    +@endif diff --git a/resources/themes/pterodactyl/vendor/pagination/default.blade.php b/resources/themes/pterodactyl/vendor/pagination/default.blade.php new file mode 100644 index 000000000..26e56994f --- /dev/null +++ b/resources/themes/pterodactyl/vendor/pagination/default.blade.php @@ -0,0 +1,36 @@ +@if ($paginator->lastPage() > 1) +
      + + @if ($paginator->onFirstPage()) + {{--
    • «
    • --}} + @else +
    • + @endif + + + @foreach ($elements as $element) + + @if (is_string($element)) +
    • {{ $element }}
    • + @endif + + + @if (is_array($element)) + @foreach ($element as $page => $url) + @if ($page == $paginator->currentPage()) +
    • {{ $page }}
    • + @else +
    • {{ $page }}
    • + @endif + @endforeach + @endif + @endforeach + + + @if ($paginator->hasMorePages()) +
    • + @else + {{--
    • »
    • --}} + @endif +
    +@endif diff --git a/resources/themes/pterodactyl/vendor/pagination/simple-bootstrap-4.blade.php b/resources/themes/pterodactyl/vendor/pagination/simple-bootstrap-4.blade.php new file mode 100644 index 000000000..4b14efeb5 --- /dev/null +++ b/resources/themes/pterodactyl/vendor/pagination/simple-bootstrap-4.blade.php @@ -0,0 +1,17 @@ +@if ($paginator->count() > 1) +
      + + @if ($paginator->onFirstPage()) +
    • «
    • + @else +
    • + @endif + + + @if ($paginator->hasMorePages()) +
    • + @else +
    • »
    • + @endif +
    +@endif diff --git a/resources/themes/pterodactyl/vendor/pagination/simple-default.blade.php b/resources/themes/pterodactyl/vendor/pagination/simple-default.blade.php new file mode 100644 index 000000000..a45097ee2 --- /dev/null +++ b/resources/themes/pterodactyl/vendor/pagination/simple-default.blade.php @@ -0,0 +1,17 @@ +@if ($paginator->count() > 1) +
      + + @if ($paginator->onFirstPage()) +
    • «
    • + @else +
    • + @endif + + + @if ($paginator->hasMorePages()) +
    • + @else +
    • »
    • + @endif +
    +@endif diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php index 00e176609..f45e70192 100644 --- a/resources/views/admin/databases/index.blade.php +++ b/resources/views/admin/databases/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -36,7 +36,7 @@
  • -
    +
    @@ -65,12 +65,12 @@
    - {{ $databases->render() }} + {{ $databases->appends('tab', 'tab_databases')->render() }}
    -
    +
    @@ -88,18 +88,18 @@ @foreach($dbh as $db) - {{ $db->name }} + {{ $db->name }} {{ $db->host }}:{{ $db->port }} {{ $db->username }} {{ $db->c_databases }} @if(is_null($db->a_linkedNode))unlinked@else{{ $db->a_linkedNode }}@endif - + @endforeach
    - {{ $dbh->render() }} + {{ $dbh->appends('tab', 'tab_dbservers')->render() }}
    diff --git a/resources/views/admin/databases/new.blade.php b/resources/views/admin/databases/new.blade.php index fa6d71a1b..24ff27007 100644 --- a/resources/views/admin/databases/new.blade.php +++ b/resources/views/admin/databases/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 27e8d52e9..b0758f27c 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -24,13 +24,31 @@ @endsection @section('content') -
    - -

    Pterodactyl Admin Control Panel


    -

    Welcome to the most advanced, lightweight, and user-friendly open source game server control panel.

    -

    You are running version {{ config('app.version') }}.

    +
    +
    + +

    Pterodactyl Admin Control Panel


    + @if (Version::isLatestPanel()) +
    You are running Pterodactyl Panel version {{ Version::getCurrentPanel() }}. Your panel is up-to-date!
    + @else +
    + Your panel is not up-to-date! The latest version is {{ Version::getPanel() }} and you are currently running version {{ Version::getCurrentPanel() }}. +
    + @endif +
    +
    + @endsection diff --git a/resources/views/admin/nodes/new.blade.php b/resources/views/admin/nodes/new.blade.php index 3278a006f..07227daa7 100644 --- a/resources/views/admin/nodes/new.blade.php +++ b/resources/views/admin/nodes/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -92,7 +92,7 @@
    - + MB
    @@ -117,7 +117,7 @@
    - + MB
    diff --git a/resources/views/admin/nodes/remote/deploy.blade.php b/resources/views/admin/nodes/remote/deploy.blade.php index 19b29c908..b7283fcfd 100644 --- a/resources/views/admin/nodes/remote/deploy.blade.php +++ b/resources/views/admin/nodes/remote/deploy.blade.php @@ -1,7 +1,7 @@ #!/bin/bash #### # Pterodactyl - Panel - # Copyright (c) 2015 - 2016 Dane Everitt + # Copyright (c) 2015 - 2017 Dane Everitt # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 010e0910a..a0ed696e7 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -69,6 +69,18 @@
    + + + + + + + + + + + + @@ -171,7 +183,7 @@
    - + MB
    @@ -185,7 +197,7 @@
    - + MB
    @@ -204,6 +216,19 @@
    +
    +
    +
    + +
    + + MB +
    +

    Enter the maximum size of files that can be uploaded through the web-based file manager.

    +
    +
    +
    +
    @@ -230,7 +255,7 @@
    - +
    Reset Daemon Master Key
    @@ -258,46 +283,14 @@
    -
    - Below is the configuration file for your daemon on this node. We recommend not simply copy and pasting the code below unless you know what you are doing. You should run the auto-installer or auto-updater to setup the daemon. +
    +

    To simplify the configuration of nodes it is possible to fetch the config from the panel. A token is required for this process. The button below will generate a token and provide you with the commands necessary for automatic configuration of the node. Be aware that these tokens are only valid for 5 minutes.

    +
    +
    +

    -
    {
    -    "web": {
    -        "listen": {{ $node->daemonListen }},
    -        "ssl": {
    -            "enabled": {{ $node->scheme === 'https' ? 'true' : 'false' }},
    -            "certificate": "/etc/letsencrypt/live/{{ $node->fqdn }}/fullchain.pem",
    -            "key": "/etc/letsencrypt/live/{{ $node->fqdn }}/privkey.pem"
    -        }
    -    },
    -    "docker": {
    -        "socket": "/var/run/docker.sock",
    -        "autoupdate_images": true
    -    },
    -    "sftp": {
    -        "path": "{{ $node->daemonBase }}",
    -        "port": {{ $node->daemonSFTP }},
    -        "container": "ptdl-sftp"
    -    },
    -    "logger": {
    -        "path": "logs/",
    -        "src": false,
    -        "level": "info",
    -        "period": "1d",
    -        "count": 3
    -    },
    -    "remote": {
    -        "download": "{{ route('remote.download') }}",
    -        "installed": "{{ route('remote.install') }}"
    -    },
    -    "uploads": {
    -        "maximumSize": 100000000
    -    },
    -    "keys": [
    -        "{{ $node->daemonSecret }}"
    -    ]
    -}
    +
    {{ $node->getConfigurationAsJson(true) }}
    @@ -505,6 +498,26 @@ $(document).ready(function () { }); }); + $('#configTokenBtn').on('click', function (event) { + $.getJSON('{{ route('admin.nodes.configuration-token', $node->id) }}') + .done(function (data) { + swal({ + type: 'success', + title: 'Token created.', + text: 'Your token will expire at ' + data.expires_at + '

    ' + + '

    To auto-configure your node run

    npm run configure -- --panel-url {{ config('app.url') }} --token '+data.token+'

    ', + html: true + }) + }) + .fail(function () { + swal({ + title: 'Error', + text: 'Something went wrong creating your token.', + type: 'error' + }); + }) + }) + $('.cloneElement').on('click', function (event) { event.preventDefault(); var rnd = randomKey(10); @@ -674,7 +687,7 @@ $(document).ready(function () { memoryData.push(parseInt(data.stats.memory / (1024 * 1024))); var m = new Date(); - timeLabels.push($.format.date(new Date(), 'HH:MM:ss')); + timeLabels.push($.format.date(new Date(), 'HH:mm:ss')); CPUChart.update(); MemoryChart.update(); @@ -777,6 +790,24 @@ $(document).ready(function () { element.parent().removeClass('has-error has-success'); } + (function getInformation() { + $.ajax({ + method: 'GET', + url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}', + timeout: 5000, + headers: { + 'X-Access-Token': '{{ $node->daemonSecret }}' + }, + }).done(function (data) { + $('[data-attr="info-version"]').html(data.version); + $('[data-attr="info-system"]').html(data.system.type + '(' + data.system.arch + ') ' + data.system.release + ''); + $('[data-attr="info-cpus"]').html(data.system.cpus); + }).fail(function (jqXHR) { + + }).always(function() { + setTimeout(getInformation, 10000); + }); + })(); }); @endsection diff --git a/resources/views/admin/servers/index.blade.php b/resources/views/admin/servers/index.blade.php index 67a913037..612d2905c 100644 --- a/resources/views/admin/servers/index.blade.php +++ b/resources/views/admin/servers/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php index 8aa499f4f..2c3d655a2 100644 --- a/resources/views/admin/servers/new.blade.php +++ b/resources/views/admin/servers/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -43,14 +43,14 @@
    -

    Character limits: a-zA-Z0-9_- and [Space] (max 35 characters)

    +

    Character limits: a-z A-Z 0-9 _ - . and [Space] (max 200 characters).

    {{-- Hacky workaround to prevent Safari and Chrome from trying to suggest emails here --}} - +
    @@ -118,14 +118,14 @@
    - + MB
    - + MB
    @@ -150,7 +150,7 @@
    - + MB
    @@ -171,7 +171,7 @@
    -

    If you do not want to limit CPU usage set the value to 0. To determine a value, take the number physical cores and multiply it by 100. For example, on a quad core system (4 * 100 = 400) there is 400% available. To limit a server to using half of a single core, you would set the value to 50. To allow a server to use up to two physical cores, set the value to 200. BlockIO should be a value between 10 and 1000. Please see this documentation for more information about it.

    +

    If you do not want to limit CPU usage set the value to 0. To determine a value, take the number physical cores and multiply it by 100. For example, on a quad core system (4 * 100 = 400) there is 400% available. To limit a server to using half of a single core, you would set the value to 50. To allow a server to use up to two physical cores, set the value to 200. BlockIO should be a value between 10 and 1000. Please see this documentation for more information about it.

    @@ -201,6 +201,15 @@

    Select the type of service that this server will be running.

    +
    @@ -392,6 +401,7 @@ $(document).ready(function () { handleLoader('#load_services', true); $('#serviceOptions').slideUp(); $('#getOption').html(''); + $('#getPack').html(''); $.ajax({ method: 'POST', @@ -423,10 +433,11 @@ $(document).ready(function () { handleLoader('#serviceOptions', true); $('#serverVariables').html(''); $('input[name="custom_image_name"]').val($(this).find(':selected').data('image')); + $('#getPack').html(''); $.ajax({ method: 'POST', - url: '/admin/servers/new/service-variables', + url: '/admin/servers/new/option-details', headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' }, @@ -436,6 +447,12 @@ $(document).ready(function () { }).done(function (data) { $('#startupExec').html(data.exec); $('input[name="startup"]').val(data.startup); + + $.each(data.packs, function (i, item) { + $('#getPack').append(''); + }); + $('#getPack').append('').parent().parent().removeClass('hidden'); + $.each(data.variables, function (i, item) { var isRequired = (item.required === 1) ? 'Required ' : ''; var dataAppend = ' \ diff --git a/resources/views/admin/servers/view.blade.php b/resources/views/admin/servers/view.blade.php index d6178d872..abad871d9 100644 --- a/resources/views/admin/servers/view.blade.php +++ b/resources/views/admin/servers/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -79,17 +79,25 @@ + + + + + + + + - + - + @@ -228,14 +236,14 @@
    - + MB
    - + MB

    Setting this to 0 will disable swap space on this server.

    @@ -373,7 +381,7 @@
    -
    {{ $server->uuidShort }}_
    +
    s{{ $server->id }}_
    @@ -553,6 +561,27 @@ $(document).ready(function () { $('[data-toggle="tooltip"]').tooltip(); $('#sidebar_links').find("a[href='/admin/servers']").addClass('active'); + (function checkServerInfo() { + $.ajax({ + type: 'GET', + headers: { + 'X-Access-Token': '{{ $server->daemonSecret }}', + 'X-Access-Server': '{{ $server->uuid }}' + }, + url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server', + dataType: 'json', + timeout: 5000, + }).done(function (data) { + $('td[data-attr="container-id"]').html('' + data.container.id + ''); + $('td[data-attr="container-user"]').html('' + data.user + ''); + }).fail(function (jqXHR) { + $('td[data-attr="container-id"]').html('error'); + $('td[data-attr="container-user"]').html('error'); + console.error(jqXHR); + }).always(function () { + setTimeout(checkServerInfo, 60000); + }) + })(); $('input[name="default"]').on('change', function (event) { $('select[name="remove_additional[]"]').find('option:disabled').prop('disabled', false); $('select[name="remove_additional[]"]').find('option[value="' + $(this).val() + '"]').prop('disabled', true).prop('selected', false); diff --git a/resources/views/admin/services/config.blade.php b/resources/views/admin/services/config.blade.php new file mode 100644 index 000000000..2aa814428 --- /dev/null +++ b/resources/views/admin/services/config.blade.php @@ -0,0 +1,180 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Manage Service Configuration +@endsection + +@section('content') +
    + +

    Service Configuration


    + +
    +
    +
    +
    +
    +
    +
    +
    {{ $contents['json'] }}
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    {{ $contents['index'] }}
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +{!! Theme::js('js/vendor/ace/ace.js') !!} +{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/resources/views/admin/services/index.blade.php b/resources/views/admin/services/index.blade.php index e55fce78e..453f1582f 100644 --- a/resources/views/admin/services/index.blade.php +++ b/resources/views/admin/services/index.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -33,9 +33,10 @@
    Daemon Version (Latest: {{ Version::getDaemon() }})
    System Information
    Total CPU Cores
    Total Servers {{ count($servers) }} UUID {{ $server->uuid }}
    Docker Container ID
    Docker User ID
    Owner {{ $server->a_ownerEmail }}
    Location{{ $server->a_locationName }}{{ $node->a_locationName }}
    Node{{ $server->a_nodeName }}{{ $node->name }}
    Service
    - + + @@ -44,9 +45,11 @@ + @endforeach + diff --git a/resources/views/admin/services/new.blade.php b/resources/views/admin/services/new.blade.php index cd421ef9c..1bb829e00 100644 --- a/resources/views/admin/services/new.blade.php +++ b/resources/views/admin/services/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -55,7 +55,7 @@ /index.js -

    This should be the name of the folder on the daemon that contains all of the service logic.

    +

    This should be a unique alpha-numeric (a-z) name used to identify the service.

    diff --git a/resources/views/admin/services/options/new.blade.php b/resources/views/admin/services/options/new.blade.php index 7749682dc..5585fad0f 100644 --- a/resources/views/admin/services/options/new.blade.php +++ b/resources/views/admin/services/options/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/admin/services/options/variable.blade.php b/resources/views/admin/services/options/variable.blade.php index 9cfceea60..2c8ff8957 100644 --- a/resources/views/admin/services/options/variable.blade.php +++ b/resources/views/admin/services/options/variable.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index d5de1a910..bffb2057e 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php new file mode 100644 index 000000000..23dbf2951 --- /dev/null +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -0,0 +1,90 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Service Packs for {{ $option->name }} +@endsection + +@section('content') +
    + +

    Service Packs


    +
    Service TypeService Type Description Servers
    {{ $service->name }} {!! $service->description !!} {{ $service->c_servers }}
    + + + + + + + + + + + @foreach ($packs as $pack) + + + + + + + + @endforeach + + + + +
    Pack NameVersionUUIDSelectableVisible
    {{ $pack->name }}{{ $pack->version }}{{ $pack->uuid }}@if($pack->selectable)@else@endif@if($pack->visible)@else@endif
    + + + + + + +
    +
    + +@endsection diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php new file mode 100644 index 000000000..8475de289 --- /dev/null +++ b/resources/views/admin/services/packs/byservice.blade.php @@ -0,0 +1,67 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Service Packs for {{ $service->name }} +@endsection + +@section('content') +
    + +

    Service Packs


    + + + + + + + + + @foreach ($options as $option) + + + + + @endforeach + + + + +
    Service OptionTotal Packs
    {{ $option->name }}{{ $option->p_count }}
    + + + + + + +
    +
    + +@endsection diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php new file mode 100644 index 000000000..dcb67d5df --- /dev/null +++ b/resources/views/admin/services/packs/edit.blade.php @@ -0,0 +1,160 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Add New Service Pack +@endsection + +@section('content') +
    + +

    Manage Service Pack


    +
    +
    +
    + +
    + +

    The name of the pack which will be seen in dropdown menus and to users.

    +
    +
    +
    + +
    + +

    The version of the program included in this pack.

    +
    +
    +
    + +
    + +

    Provide a description of the pack which will be shown to users.

    +
    +
    +
    +
    +
    + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    Package Archive
    +
    +
    +
    + @if(count($files) > 1) +
    Warning! Service packs should only contain a single pack archive in .tar.gz format. We've detected more than one file for this pack.
    + @endif + + + + + + + + + + + @foreach($files as &$file) + + + + + + + @endforeach + +
    FilenameFile SizeSHA1 HashLast Modified
    {{ basename($file) }}{{ Storage::size($file) }} Bytes{{ sha1_file(storage_path('app/' . $file)) }}{{ Carbon::createFromTimestamp(Storage::lastModified($file))->toDateTimeString() }}
    +

    If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as archive.tar.gz.

    +
    +
    +
    +
    +
    +
    +
    +
    +
    + {!! csrf_field() !!} + + + + +
    +
    + +
    +{!! Theme::js('js/vendor/ace/ace.js') !!} +{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/resources/views/admin/services/packs/index.blade.php b/resources/views/admin/services/packs/index.blade.php new file mode 100644 index 000000000..6456ca317 --- /dev/null +++ b/resources/views/admin/services/packs/index.blade.php @@ -0,0 +1,47 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Service Packs +@endsection + +@section('content') +
    + +

    Service Packs


    +
    + @foreach ($services as $service) + + @endforeach +
    +
    + +@endsection diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php new file mode 100644 index 000000000..82601bc62 --- /dev/null +++ b/resources/views/admin/services/packs/new.blade.php @@ -0,0 +1,135 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} +{{-- of this software and associated documentation files (the "Software"), to deal --}} +{{-- in the Software without restriction, including without limitation the rights --}} +{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} +{{-- copies of the Software, and to permit persons to whom the Software is --}} +{{-- furnished to do so, subject to the following conditions: --}} + +{{-- The above copyright notice and this permission notice shall be included in all --}} +{{-- copies or substantial portions of the Software. --}} + +{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} +{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} +{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} +{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} +{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} +{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} +{{-- SOFTWARE. --}} +@extends('layouts.admin') + +@section('title') + Add New Service Pack +@endsection + +@section('content') +
    + +

    New Service Pack


    +
    +
    +
    + +
    + +

    The name of the pack which will be seen in dropdown menus and to users.

    +
    +
    +
    + +
    + +

    The version of the program included in this pack.

    +
    +
    +
    + +
    + +

    Provide a description of the pack which will be shown to users.

    +
    +
    +
    +
    +
    + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    File Upload
    +
    +
    +
    + + +

    This package file must be a .tar.gz archive of files to use for either building or running this pack.

    If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. + This server is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

    +
    +
    +
    +
    +
    +
    +
    +
    +
    + {!! csrf_field() !!} + +
    +
    + +
    +{!! Theme::js('js/vendor/ace/ace.js') !!} +{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} + +@endsection diff --git a/resources/views/admin/services/packs/upload.blade.php b/resources/views/admin/services/packs/upload.blade.php new file mode 100644 index 000000000..e9ca020fa --- /dev/null +++ b/resources/views/admin/services/packs/upload.blade.php @@ -0,0 +1,45 @@ + diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php index e05d061fd..887478aca 100644 --- a/resources/views/admin/services/view.blade.php +++ b/resources/views/admin/services/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -106,6 +106,7 @@
    {!! csrf_field() !!} +
    diff --git a/resources/views/admin/settings.blade.php b/resources/views/admin/settings.blade.php index d24f512b6..09e66d6fc 100644 --- a/resources/views/admin/settings.blade.php +++ b/resources/views/admin/settings.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -44,7 +44,7 @@
    +
    + +
    +
    + - - - + + + @foreach ($users as $user) - - - - + + + + + + @endforeach diff --git a/resources/views/admin/users/new.blade.php b/resources/views/admin/users/new.blade.php index 39ad6ecab..8e0bf5f7a 100644 --- a/resources/views/admin/users/new.blade.php +++ b/resources/views/admin/users/new.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Some Modifications (c) 2015 Dylan Seidt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} @@ -34,15 +34,48 @@

    Create New Account


    -
    - -
    - +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +

    Setting this to 'Yes' gives a user full administrative access.

    +
    -
    +
    +

    Providing a user password is optional. New user emails prompt users to create a password the first time they login. If a password is provided here you will need to find a different method of providing it to the user.

    diff --git a/resources/views/admin/users/view.blade.php b/resources/views/admin/users/view.blade.php index 6ec648ef5..0a5d8230d 100644 --- a/resources/views/admin/users/view.blade.php +++ b/resources/views/admin/users/view.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Some Modifications (c) 2015 Dylan Seidt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} @@ -31,7 +31,9 @@
  • Accounts
  • {{ $user->email }}
  • -

    Viewing User: {{ $user->email }}


    +

    Viewing User: {{ $user->email }}

    +

    Registered {{ (new Carbon($user->created_at))->toRfc1123String() }}

    +
    @@ -43,19 +45,21 @@
    - +
    - +
    - +
    - -

    Setting this to 'Yes' gives a user full administrative access.

    + +
    +
    +
    + +
    +
    @@ -66,7 +70,6 @@
    -

    {{ trans('base.account.update_pass') }}


    @@ -74,16 +77,22 @@
    -
    - -
    - -
    -
    +
    +
    + +
    + +

    Setting this to 'Yes' gives a user full administrative access.

    +
    +
    +
    diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php deleted file mode 100644 index 2000dad22..000000000 --- a/resources/views/auth/login.blade.php +++ /dev/null @@ -1,145 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'Login') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('resp-alerts') -@endsection - -@section('resp-errors') -@endsection - -@section('content') -
    - @if (count($errors) > 0) -
    - - {{ trans('strings.whoops') }}! {{ trans('auth.errorencountered') }}

    -
      - @foreach ($errors->all() as $error) -
    • {{ $error }}
    • - @endforeach -
    -
    - @endif - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach -
    - {{ trans('strings.login') }} -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - -
    -
    -
    -
    - {!! csrf_field() !!} - - -
    -
    -
    - -
    - -
    - -@endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php deleted file mode 100644 index 064373a53..000000000 --- a/resources/views/auth/passwords/email.blade.php +++ /dev/null @@ -1,63 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'Reset Password') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('content') -
    -
    - {{ trans('auth.resetpassword') }} -
    - @if (session('status')) -
    - {{ trans('strings.success') }}! {{ trans('auth.emailsent') }} -
    - @endif -
    - -
    - - @if ($errors->has('email')) - - {{ $errors->first('email') }} - - @endif -
    -
    -
    -
    - {!! csrf_field() !!} - -
    -
    -
    - -
    -
    -@endsection diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php deleted file mode 100644 index 5151ce7a2..000000000 --- a/resources/views/auth/passwords/reset.blade.php +++ /dev/null @@ -1,82 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} -{{-- Some Modifications (c) 2015 Dylan Seidt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'Reset Password') - - -@section('right-nav') -@endsection - -@section('sidebar') -@endsection - -@section('content') -
    -
    - {{ trans('auth.resetpassword') }} -
    - -
    - -
    - - @if ($errors->has('email')) - - {{ $errors->first('email') }} - - @endif -
    -
    -
    - -
    - - @if ($errors->has('password')) - - {{ $errors->first('password') }} - - @endif -

    {{ trans('base.password_req') }}

    -
    -
    -
    - -
    - - @if ($errors->has('password_confirmation')) - - {{ $errors->first('password_confirmation') }} - - @endif -
    -
    -
    -
    - {!! csrf_field() !!} - -
    -
    -
    - -
    -
    -@endsection diff --git a/resources/views/base/account.blade.php b/resources/views/base/account.blade.php deleted file mode 100644 index 629d5885b..000000000 --- a/resources/views/base/account.blade.php +++ /dev/null @@ -1,90 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'Your Account') - -@section('sidebar-server') -@endsection - -@section('content') -
    -
    -
    -

    {{ trans('base.account.update_pass') }}


    -
    -
    - -
    - -
    -
    -
    - -
    - -

    {{ trans('base.password_req') }}

    -
    -
    -
    - -
    - -
    -
    -
    -
    - {!! csrf_field() !!} - -
    -
    - -
    -
    -

    {{ trans('base.account.update_email') }}


    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - {!! csrf_field() !!} - -
    -
    - -
    -
    -
    - -@endsection diff --git a/resources/views/base/api/index.blade.php b/resources/views/base/api/index.blade.php deleted file mode 100644 index 0fcc69a79..000000000 --- a/resources/views/base/api/index.blade.php +++ /dev/null @@ -1,109 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'API Access') - -@section('sidebar-server') -@endsection - -@section('scripts') - @parent - {!! Theme::css('css/vendor/sweetalert/sweetalert.min.css') !!} - {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} -@endsection - -@section('content') -
    -
    EmailAccount CreatedAccount UpdatedID + Email + Client NameUsername
    {{ $user->email }} @if($user->root_admin === 1)Administrator@endif{{ $user->created_at }}{{ $user->updated_at }}
    #{{ $user->id }}{{ $user->email }}{{ $user->name_last }}, {{ $user->name_first }}{{ $user->username }}
    - - - - - - - - - - - @foreach ($keys as $key) - - - - - - - - @endforeach - -
    Public KeyMemoCreatedExpires
    {{ $key->public }}{{ $key->memo }}{{ (new Carbon($key->created_at))->toDayDateTimeString() }} - @if(is_null($key->expires_at)) - Never - @else - {{ (new Carbon($key->expires_at))->toDayDateTimeString() }} - @endif -
    - -
    - -@endsection diff --git a/resources/views/base/api/new.blade.php b/resources/views/base/api/new.blade.php deleted file mode 100644 index 0fb75caac..000000000 --- a/resources/views/base/api/new.blade.php +++ /dev/null @@ -1,278 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'API Access') - -@section('sidebar-server') -@endsection - -@section('content') -
    -
    -
    -
      -
    • - 1Permissions - -
    • - @if(Auth::user()->root_admin === 1) -
    • - 2Admin - -
    • - @endif -
    • - @if(Auth::user()->root_admin === 1)3 @else 2 @endifSecurity - -
    • -
    -
    -
    - - -
    -
    -
    -
    -
    Any servers that you are a subuser for will be accessible through this API with the same permissions that you currently have.
    -
    -
    -

    Base Information


    -
    -
    -
    -
    -
    -
    -

    Server Management


    -
    -
    -
    -
    -
    -
    -
    - @if(Auth::user()->root_admin === 1) -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    User Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Server Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Node Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Service Management


    -
    -
    -
    -
    -

    Location Management


    -
    -
    -
    -
    -
    - @endif -
    -
    - -
    - -

    Enter a breif description of what this API key will be used for.

    -
    -
    -
    - -
    - -

    Enter a line delimitated list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.

    -
    -
    -
    -
    - {!! csrf_field() !!} -
    -
    -
    - -@endsection diff --git a/resources/views/base/index.blade.php b/resources/views/base/index.blade.php deleted file mode 100644 index 43392975f..000000000 --- a/resources/views/base/index.blade.php +++ /dev/null @@ -1,126 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'Your Servers') - -@section('sidebar-server') -@endsection - -@section('content') -
    - @if (Auth::user()->root_admin == 1) -
    {{ trans('base.view_as_admin') }}
    - @endif - @if (!$servers->isEmpty()) - - - - @if (Auth::user()->root_admin == 1) - - @endif - - - - - - - - - - - @foreach ($servers as $server) - - @if (Auth::user()->root_admin == 1) - - @endif - - - - - - - - - @endforeach - -
    {{ trans('base.server_name') }}{{ trans('strings.node') }}{{ trans('strings.connection') }}{{ trans('strings.players') }}{{ trans('strings.status') }}
    - @if ($server->owner === Auth::user()->id) - - @else - - @endif - {{ $server->name }}{{ $server->nodeName }}@if(!is_null($server->ip_alias)){{ $server->ip_alias }}@else{{ $server->ip }}@endif:{{ $server->port }}--@if($server->suspended === 1)Suspended@else--@endif
    -
    -
    {!! $servers->render() !!}
    -
    - @else -
    {{ trans('base.no_servers') }}
    - @endif -
    - -@endsection diff --git a/resources/views/base/security.blade.php b/resources/views/base/security.blade.php deleted file mode 100644 index 48b730555..000000000 --- a/resources/views/base/security.blade.php +++ /dev/null @@ -1,205 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title', 'Account Security') - -@section('sidebar-server') -@endsection - -@section('content') -
    - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach -

    Active Sessions


    - - - - - - - - - - - - @foreach($sessions as $session) - - payload)) ?> - - - - - - - @endforeach - -
    Session IDIP AddressUser AgentLast Activity
    {{ substr($session->id, 0, 8) }}{{ $session->ip_address }}{{ $session->user_agent }} - @if((time() - $session->last_activity < 10)) - just now - @else - {{ date('D, M j \a\t H:i:s', $session->last_activity) }} - @endif -
    - -

    {{ trans('base.account.totp_header') }} @if (Auth::user()->use_totp === 1){{ trans('strings.enabled') }}@else{{ trans('strings.disabled') }}@endif


    - @if (Auth::user()->use_totp === 1) -
    -
    {{ trans('base.account.totp_disable') }}
    -
    -

    {{ trans('base.account.totp_disable_help') }}

    -
    -
    -
    -
    - {{ trans('base.account.totp_token') }} - - - {!! csrf_field() !!} - {{ method_field('DELETE') }} - - -
    -
    -
    -
    -
    - @else -
    -
    -

    {{ trans('base.account.totp_header') }}

    -
    -
    -

    {{ trans('base.account.totp_enable_help') }}

    -
    {{ trans('base.account.totp_apps') }}
    -
    -
    -
    -
    -
    - {!! csrf_field() !!} - -
    -
    -
    - @endif - - -
    - -@endsection diff --git a/resources/views/emails/added-subuser.blade.php b/resources/views/emails/added-subuser.blade.php index a468eb298..c6d0d47d2 100644 --- a/resources/views/emails/added-subuser.blade.php +++ b/resources/views/emails/added-subuser.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/emails/new-account.blade.php b/resources/views/emails/new-account.blade.php index 093d626b1..1240cbc2c 100644 --- a/resources/views/emails/new-account.blade.php +++ b/resources/views/emails/new-account.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/emails/new_password.blade.php b/resources/views/emails/new_password.blade.php index 69b671baa..882cf2af3 100644 --- a/resources/views/emails/new_password.blade.php +++ b/resources/views/emails/new_password.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/errors/403.blade.php b/resources/views/errors/403.blade.php index aef80166e..bc83eb24a 100644 --- a/resources/views/errors/403.blade.php +++ b/resources/views/errors/403.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php index 6988e78a6..bdaec2cd4 100644 --- a/resources/views/errors/404.blade.php +++ b/resources/views/errors/404.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/errors/installing.blade.php b/resources/views/errors/installing.blade.php index c68ec61f3..8a8d5c292 100644 --- a/resources/views/errors/installing.blade.php +++ b/resources/views/errors/installing.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/errors/suspended.blade.php b/resources/views/errors/suspended.blade.php index 442f85ec0..f96f13d60 100644 --- a/resources/views/errors/suspended.blade.php +++ b/resources/views/errors/suspended.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php index 803c222a2..f21e1a0c7 100644 --- a/resources/views/layouts/admin.blade.php +++ b/resources/views/layouts/admin.blade.php @@ -1,4 +1,4 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} {{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} {{-- of this software and associated documentation files (the "Software"), to deal --}} @@ -35,6 +35,23 @@ {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} {!! Theme::js('js/vendor/fuelux/fuelux.min.js') !!} {!! Theme::js('js/admin.min.js') !!} + {!! Theme::js('js/bootstrap-notify.min.js') !!} + @show {{ Settings::get('company') }} - @yield('title') @@ -47,7 +64,7 @@ - {{ Settings::get('company') }} + {{ Settings::get('company', 'Pterodactyl Panel') }}
    diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php deleted file mode 100644 index 3df9634cb..000000000 --- a/resources/views/layouts/master.blade.php +++ /dev/null @@ -1,315 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} - - - - @section('scripts') - - - - {!! Theme::css('css/vendor/bootstrap/bootstrap.css') !!} - {!! Theme::css('css/pterodactyl.css') !!} - {!! Theme::css('css/animate.css') !!} - {!! Theme::css('css/vendor/fontawesome/font-awesome.min.css') !!} - {!! Theme::css('css/vendor/sweetalert/sweetalert.min.css') !!} - {!! Theme::css('css/vendor/fuelux/fuelux.min.css') !!} - {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} - {!! Theme::js('js/vendor/bootstrap/bootstrap.min.js') !!} - {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} - {!! Theme::js('js/vendor/sweetalert/sweetalert.min.js') !!} - {!! Theme::js('js/vendor/fuelux/fuelux.min.js') !!} - {!! Theme::js('js/admin.min.js') !!} - {!! Theme::js('js/bootstrap-notify.min.js') !!} - - @section('server-socket') - @if (isset($server->name) && isset($node->name)) - - @endif - @show - @show - {{ Settings::get('company') }} - @yield('title') - - -
    - -
    - -
    -
    -
    - @section('resp-errors') - @if (count($errors) > 0) -
    - - {{ trans('strings.whoops') }}! {{ trans('auth.errorencountered') }}

    -
      - @foreach ($errors->all() as $error) -
    • {{ $error }}
    • - @endforeach -
    -
    - @endif - @show - @section('resp-alerts') - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach - @show -
    -
    -
    - @yield('content') -
    -
    -
    - -
    - - - diff --git a/resources/views/server/files/add.blade.php b/resources/views/server/files/add.blade.php deleted file mode 100644 index 7019c0cdc..000000000 --- a/resources/views/server/files/add.blade.php +++ /dev/null @@ -1,270 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Add File to: {{ $server->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::js('js/vendor/upload/client.min.js') !!} - {!! Theme::js('js/vendor/lodash/lodash.js') !!} -@endsection - -@section('content') -
    - -
    -
    -
    -
    -
    - Save As: - -
    -

    All files are saved relative to /home/container. You can enter more of the path into the Save As field to save the file into a specific folder.

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    - @can('upload-files', $server) -
    -
    -
    -
    - Upload Directory: - -
    -

    All files are saved relative to /home/container. You can enter more of the path into the Save As field to save the file into a specific folder.

    -
    -
    - -
    Edit the path location above before you upload files. They will automatically be placed in the directory you specify above. You can change this each time you upload a new file without having to press anything else. The directory must exist before performing an upload.
    - - -
    -

    Drag and Drop File Here

    -
    - -
    - @endcan -
    -
    -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/server/files/edit.blade.php b/resources/views/server/files/edit.blade.php deleted file mode 100644 index ed6c38637..000000000 --- a/resources/views/server/files/edit.blade.php +++ /dev/null @@ -1,103 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Managing Files for: {{ $server->name }} -@endsection - -@section('content') -
    -

    Editing File: /home/container/{{ $file }}

    -
    -
    -
    {{ $contents }}
    -
    -
    - @can('save-files', $server) -
    -
    -
    - - - {{ trans('server.files.back') }} -
    -
    - @endcan -
    -{!! Theme::js('js/vendor/ace/ace.js') !!} -{!! Theme::js('js/vendor/ace/ext-modelist.js') !!} - -@endsection diff --git a/resources/views/server/files/index.blade.php b/resources/views/server/files/index.blade.php deleted file mode 100644 index c284faf60..000000000 --- a/resources/views/server/files/index.blade.php +++ /dev/null @@ -1,187 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Managing Files for: {{ $server->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::js('js/vendor/async/async.min.js') !!} - {!! Theme::js('js/vendor/lodash/lodash.js') !!} - {!! Theme::js('js/vendor/upload/client.min.js') !!} -@endsection - -@section('content') -
    -
    -
    -
    - {{ trans('server.files.loading') }} -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    File Path Information

    -
    -
    - When configuring any file paths in your server plugins or settings you should use /home/container as your base path. -
    -
    -
    -
    -
    - - - - -@endsection diff --git a/resources/views/server/index.blade.php b/resources/views/server/index.blade.php deleted file mode 100644 index 5cfec8a2c..000000000 --- a/resources/views/server/index.blade.php +++ /dev/null @@ -1,499 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Viewing Server: {{ $server->name }} -@endsection - -@section('scripts') - @parent - {!! Theme::css('css/jquery.terminal.css') !!} - {!! Theme::js('js/jquery.mousewheel-min.js') !!} - {!! Theme::js('js/jquery.terminal-0.11.6.min.js') !!} - {!! Theme::js('js/unix_formatting.js') !!} - {!! Theme::js('js/vendor/chartjs/chart.min.js') !!} - {!! Theme::js('js/vendor/jquery/jquery-dateFormat.min.js') !!} -@endsection - -@section('content') -
    - -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - @can('power-start', $server)@endcan - @can('power-restart', $server)@endcan - @can('power-stop', $server)@endcan - @can('power-kill', $server)@endcan - - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    - @can('view-allocation', $server) -
    -
    -
    -
    -
    Below is a listing of all avaliable IPs and Ports for your service. To change the default connection address for your server, simply click on the one you would like to make default below.
    - - - - - - - - @foreach ($allocations as $allocation) - - - - - - - @endforeach -
    IP AddressAliasPort
    - {{ $allocation->ip }} - ip_alias))class="muted"@endif> - @if(is_null($allocation->ip_alias)) - none - @else - {{ $allocation->ip_alias }} - @endif - {{ $allocation->port }} - @if($allocation->id === $server->allocation) - Primary - @else - Make Primary - @endif -
    -
    -
    -
    - @endcan -
    -
    - -@if($server->a_serviceFile === 'minecraft') - -@endif - -@endsection diff --git a/resources/views/server/js/filemanager/actions.blade.php b/resources/views/server/js/filemanager/actions.blade.php deleted file mode 100644 index 3e8ea2250..000000000 --- a/resources/views/server/js/filemanager/actions.blade.php +++ /dev/null @@ -1,408 +0,0 @@ -"use strict"; - -// Copyright (c) 2015 - 2016 Dane Everitt -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -class ActionsClass { - constructor(element, menu) { - this.element = element; - this.menu = menu; - } - - destroy() { - this.element = undefined; - } - - @can('create-files', $server) - folder() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const currentName = decodeURIComponent(nameBlock.attr('data-name')); - const currentPath = decodeURIComponent(nameBlock.data('path')); - - let inputValue = `${currentPath}${currentName}/`; - if ($(this.element).data('type') === 'file') { - inputValue = currentPath; - } - swal({ - type: 'input', - title: 'Create Folder', - text: 'Please enter the path and folder name below.', - showCancelButton: true, - showConfirmButton: true, - closeOnConfirm: false, - showLoaderOnConfirm: true, - inputValue: inputValue - }, (val) => { - $.ajax({ - type: 'POST', - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - }, - contentType: 'application/json; charset=utf-8', - url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/folder', - timeout: 10000, - data: JSON.stringify({ - path: val, - }), - }).done(data => { - swal.close(); - Files.list(); - }).fail(jqXHR => { - console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; - if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { - error = jqXHR.responseJSON.error; - } - swal({ - type: 'error', - title: '', - text: error, - }); - }); - }); - } - @endcan - - @can('move-files', $server) - move() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const currentName = decodeURIComponent(nameBlock.attr('data-name')); - const currentPath = decodeURIComponent(nameBlock.data('path')); - - swal({ - type: 'input', - title: 'Move File', - text: 'Please enter the new path for the file below.', - showCancelButton: true, - showConfirmButton: true, - closeOnConfirm: false, - showLoaderOnConfirm: true, - inputValue: `${currentPath}${currentName}`, - }, (val) => { - $.ajax({ - type: 'POST', - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - }, - contentType: 'application/json; charset=utf-8', - url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/move', - timeout: 10000, - data: JSON.stringify({ - from: `${currentPath}${currentName}`, - to: `${val}`, - }), - }).done(data => { - nameBlock.parent().addClass('warning').delay(200).fadeOut(); - swal.close(); - }).fail(jqXHR => { - console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; - if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { - error = jqXHR.responseJSON.error; - } - swal({ - type: 'error', - title: '', - text: error, - }); - }); - }); - - } - - rename() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const currentLink = nameBlock.find('a'); - const currentName = decodeURIComponent(nameBlock.attr('data-name')); - const attachEditor = ` - - - `; - - nameBlock.html(attachEditor); - const inputField = nameBlock.find('input'); - const inputLoader = nameBlock.find('.input-loader'); - - inputField.focus(); - inputField.on('blur keydown', e => { - // Save Field - if ( - (e.type === 'keydown' && e.which === 27) - || e.type === 'blur' - || (e.type === 'keydown' && e.which === 13 && currentName === inputField.val()) - ) { - if (!_.isEmpty(currentLink)) { - nameBlock.html(currentLink); - } else { - nameBlock.html(currentName); - } - inputField.remove(); - ContextMenu.unbind().run(); - return; - } - - if (e.type === 'keydown' && e.which !== 13) return; - - inputLoader.show(); - const currentPath = decodeURIComponent(nameBlock.data('path')); - - $.ajax({ - type: 'POST', - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - }, - contentType: 'application/json; charset=utf-8', - url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/rename', - timeout: 10000, - data: JSON.stringify({ - from: `${currentPath}${currentName}`, - to: `${currentPath}${inputField.val()}`, - }), - }).done(data => { - nameBlock.attr('data-name', inputField.val()); - if (!_.isEmpty(currentLink)) { - let newLink = currentLink.attr('href'); - if (nameBlock.parent().data('type') !== 'folder') { - newLink = newLink.substr(0, newLink.lastIndexOf('/')) + '/' + inputField.val(); - } - currentLink.attr('href', newLink); - nameBlock.html( - currentLink.html(inputField.val()) - ); - } else { - nameBlock.html(inputField.val()); - } - inputField.remove(); - }).fail(jqXHR => { - console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; - if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { - error = jqXHR.responseJSON.error; - } - nameBlock.addClass('has-error').delay(2000).queue(() => { - nameBlock.removeClass('has-error').dequeue(); - }); - inputField.popover({ - animation: true, - placement: 'top', - content: error, - title: 'Save Error' - }).popover('show'); - }).always(() => { - inputLoader.remove(); - ContextMenu.unbind().run(); - }); - }); - } - @endcan - - @can('copy-files', $server) - copy() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const currentName = decodeURIComponent(nameBlock.attr('data-name')); - const currentPath = decodeURIComponent(nameBlock.data('path')); - - swal({ - type: 'input', - title: 'Copy File', - text: 'Please enter the new path for the copied file below.', - showCancelButton: true, - showConfirmButton: true, - closeOnConfirm: false, - showLoaderOnConfirm: true, - inputValue: `${currentPath}${currentName}`, - }, (val) => { - $.ajax({ - type: 'POST', - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - }, - contentType: 'application/json; charset=utf-8', - url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/copy', - timeout: 10000, - data: JSON.stringify({ - from: `${currentPath}${currentName}`, - to: `${val}`, - }), - }).done(data => { - swal({ - type: 'success', - title: '', - text: 'File successfully copied.' - }); - Files.list(); - }).fail(jqXHR => { - console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; - if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { - error = jqXHR.responseJSON.error; - } - swal({ - type: 'error', - title: '', - text: error, - }); - }); - }); - } - @endcan - - @can('download-files', $server) - download() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const fileName = decodeURIComponent(nameBlock.attr('data-name')); - const filePath = decodeURIComponent(nameBlock.data('path')); - - window.location = `/server/{{ $server->uuidShort }}/files/download/${filePath}${fileName}`; - } - @endcan - - @can('delete-files', $server) - delete() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const delPath = decodeURIComponent(nameBlock.data('path')); - const delName = decodeURIComponent(nameBlock.data('name')); - - swal({ - type: 'warning', - title: '', - text: 'Are you sure you want to delete ' + delName + '? There is no reversing this action.', - html: true, - showCancelButton: true, - showConfirmButton: true, - closeOnConfirm: false, - showLoaderOnConfirm: true - }, () => { - $.ajax({ - type: 'DELETE', - url: `{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/f/${delPath}${delName}`, - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - } - }).done(data => { - nameBlock.parent().addClass('warning').delay(200).fadeOut(); - swal({ - type: 'success', - title: 'File Deleted' - }); - }).fail(jqXHR => { - console.error(jqXHR); - swal({ - type: 'error', - title: 'Whoops!', - html: true, - text: 'An error occured while attempting to delete this file. Please try again.', - }); - }); - }); - } - @endcan - - @can('decompress-files', $server) - decompress() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const compPath = decodeURIComponent(nameBlock.data('path')); - const compName = decodeURIComponent(nameBlock.data('name')); - - swal({ - title: ' Decompressing...', - text: 'This might take a few seconds to complete.', - html: true, - allowOutsideClick: false, - allowEscapeKey: false, - showConfirmButton: false, - }); - - $.ajax({ - type: 'POST', - url: `{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/decompress`, - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - }, - contentType: 'application/json; charset=utf-8', - data: JSON.stringify({ - files: `${compPath}${compName}` - }) - }).done(data => { - swal.close(); - Files.list(compPath); - }).fail(jqXHR => { - console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; - if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { - error = jqXHR.responseJSON.error; - } - swal({ - type: 'error', - title: 'Whoops!', - html: true, - text: error - }); - }); - } - @endcan - - @can('compress-files', $server) - compress() { - const nameBlock = $(this.element).find('td[data-identifier="name"]'); - const compPath = decodeURIComponent(nameBlock.data('path')); - const compName = decodeURIComponent(nameBlock.data('name')); - - $.ajax({ - type: 'POST', - url: `{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/file/compress`, - headers: { - 'X-Access-Token': '{{ $server->daemonSecret }}', - 'X-Access-Server': '{{ $server->uuid }}' - }, - contentType: 'application/json; charset=utf-8', - data: JSON.stringify({ - files: `${compPath}${compName}`, - to: compPath.toString() - }) - }).done(data => { - Files.list(compPath, err => { - if (err) return; - const fileListing = $('#file_listing').find(`[data-name="${data.saved_as}"]`).parent(); - fileListing.addClass('success pulsate').delay(3000).queue(() => { - fileListing.removeClass('success pulsate').dequeue(); - }); - }); - }).fail(jqXHR => { - console.error(jqXHR); - var error = 'An error occured while trying to process this request.'; - if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') { - error = jqXHR.responseJSON.error; - } - swal({ - type: 'error', - title: 'Whoops!', - html: true, - text: error - }); - }); - } - @endcan -} diff --git a/resources/views/server/js/filemanager/contextmenu.blade.php b/resources/views/server/js/filemanager/contextmenu.blade.php deleted file mode 100644 index a4111415c..000000000 --- a/resources/views/server/js/filemanager/contextmenu.blade.php +++ /dev/null @@ -1,171 +0,0 @@ -"use strict"; - -// Copyright (c) 2015 - 2016 Dane Everitt -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -class ContextMenuClass { - constructor() { - this.activeLine = null; - } - - run() { - this.directoryClick(); - this.rightClick(); - } - - makeMenu(parent) { - $(document).find('#fileOptionMenu').remove(); - if (!_.isNull(this.activeLine)) this.activeLine.removeClass('active'); - - let newFilePath = $('#headerTableRow').attr('data-currentDir'); - if (parent.data('type') === 'folder') { - const nameBlock = parent.find('td[data-identifier="name"]'); - const currentName = decodeURIComponent(nameBlock.attr('data-name')); - const currentPath = decodeURIComponent(nameBlock.data('path')); - newFilePath = `${currentPath}${currentName}`; - } - return ''; - } - - rightClick() { - $('#file_listing > tbody td').on('contextmenu', event => { - - const parent = $(event.target).closest('tr'); - const menu = $(this.makeMenu(parent)); - - if (parent.data('type') === 'disabled') return; - event.preventDefault(); - - $(menu).appendTo('body'); - $(menu).data('invokedOn', $(event.target)).show().css({ - position: 'absolute', - left: event.pageX, - top: event.pageY, - }); - - this.activeLine = parent; - this.activeLine.addClass('active'); - - @can('download-files', $server) - if (parent.data('type') === 'file') { - $(menu).find('li[data-action="download"]').removeClass('hidden'); - } - @endcan - - @can('compress-files', $server) - if (parent.data('type') === 'folder') { - $(menu).find('li[data-action="compress"]').removeClass('hidden'); - } - @endcan - - @can('decompress-files', $server) - if (_.without(['application/zip', 'application/gzip', 'application/x-gzip'], parent.data('mime')).length < 3) { - $(menu).find('li[data-action="decompress"]').removeClass('hidden'); - } - @endcan - - // Handle Events - const Actions = new ActionsClass(parent, menu); - @can('move-files', $server) - $(menu).find('li[data-action="move"]').unbind().on('click', e => { - e.preventDefault(); - Actions.move(); - }); - @endcan - - @can('copy-files', $server) - $(menu).find('li[data-action="copy"]').unbind().on('click', e => { - e.preventDefault(); - Actions.copy(); - }); - @endcan - - @can('move-files', $server) - $(menu).find('li[data-action="rename"]').unbind().on('click', e => { - e.preventDefault(); - Actions.rename(); - }); - @endcan - - @can('compress-files', $server) - $(menu).find('li[data-action="compress"]').unbind().on('click', e => { - e.preventDefault(); - Actions.compress(); - }); - @endcan - - @can('decompress-files', $server) - $(menu).find('li[data-action="decompress"]').unbind().on('click', e => { - e.preventDefault(); - Actions.decompress(); - }); - @endcan - - @can('create-files', $server) - $(menu).find('li[data-action="folder"]').unbind().on('click', e => { - e.preventDefault(); - Actions.folder(); - }); - @endcan - - @can('download-files', $server) - $(menu).find('li[data-action="download"]').unbind().on('click', e => { - e.preventDefault(); - Actions.download(); - }); - @endcan - - $(menu).find('li[data-action="delete"]').unbind().on('click', e => { - e.preventDefault(); - Actions.delete(); - }); - - $(window).on('click', () => { - $(menu).remove(); - if(!_.isNull(this.activeLine)) this.activeLine.removeClass('active'); - }); - }); - } - - directoryClick() { - $('a[data-action="directory-view"]').on('click', function (event) { - event.preventDefault(); - - const path = $(this).parent().data('path') || ''; - const name = $(this).parent().data('name') || ''; - - window.location.hash = encodeURIComponent(path + name); - Files.list(); - }); - } -} - -window.ContextMenu = new ContextMenuClass; diff --git a/resources/views/server/settings.blade.php b/resources/views/server/settings.blade.php deleted file mode 100644 index 4acead9e8..000000000 --- a/resources/views/server/settings.blade.php +++ /dev/null @@ -1,246 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Server Settings -@endsection - -@section('content') -
    -

    Server Settings


    - -
    - @can('view-sftp', $server) -
    -
    -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - -
    -
    - @can('reset-sftp', $server) -
    - -
    - - - {!! csrf_field() !!} - - -
    -

    Passwords must meet the following requirements: at least one uppercase character, one lowercase character, one digit, and be at least 8 characters in length. Click here to generate one to use.

    -
    - @endcan -
    -
    - @can('view-sftp-password', $server) - -
    - -
    - @endcan -
    -
    -
    -
    -
    - @endcan - @can('view-startup', $server) -
    -
    -
    -
    -
    -
    -
    - -
    - {{ $service->executable }} - -
    -
    -
    -
    - @can('edit-startup', $server) -
    -
    -
    - @foreach($variables as $item) -
    - -
    - user_editable === 1) - name="{{ $item->env_variable }}" - @else - readonly="readonly" - @endif - class="form-control" value="{{ old($item->env_variable, $item->a_serverValue) }}" data-action="matchRegex" data-regex="{{ $item->regex }}" /> -
    -

    {!! $item->description !!}

    -
    - @endforeach -
    -
    -
    -
    -
    -
    - {!! csrf_field() !!} - -
    -
    -
    - @endcan -
    -
    -
    - @endcan - @can('view-databases', $server) -
    -
    -
    -
    - @if(count($databases) > 0) - - - - - - - - - - - @foreach($databases as $database) - - - - - - - @endforeach - -
    DatabaseUsernamePasswordDB Server
    {{ $database->database }}{{ $database->username }}{{ Crypt::decrypt($database->password) }} @can('reset-db-password', $server)@endcan{{ $database->a_host }}:{{ $database->a_port }}
    - @else -
    - There are no databases configured for this server. - @if(Auth::user()->root_admin === 1) - Add a new database. - @endif -
    - @endif -
    -
    -
    - @endcan -
    -
    - -@endsection diff --git a/resources/views/server/tasks/index.blade.php b/resources/views/server/tasks/index.blade.php deleted file mode 100644 index 9c76dece8..000000000 --- a/resources/views/server/tasks/index.blade.php +++ /dev/null @@ -1,156 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Scheduled Tasks -@endsection - -@section('content') -
    -

    Manage Scheduled Tasks


    - - - - - - - - @can('delete-task', $server)@endcan - @can('toggle-task', $server)@endcan - - - - @foreach($tasks as $task) - active === 0)class="text-disabled"@endif> - {{-- --}} - - - - - @can('delete-task', $server) - - @endcan - @can('toggle-task', $server) - - @endcan - - - @endforeach - -
    ActionDataLast RunNext Run
    {{ $actions[$task->action] }}{{ $actions[$task->action] }}{{ $task->data }}{{ Carbon::parse($task->last_run)->toDayDateTimeString() }}

    ({{ Carbon::parse($task->last_run)->diffForHumans() }})

    - @if($task->active !== 0) - {{ Carbon::parse($task->next_run)->toDayDateTimeString() }}

    ({{ Carbon::parse($task->next_run)->diffForHumans() }})

    - @else - n/a - @endif -
    - @can('create-task', $server) - - @endcan -
    - -@endsection diff --git a/resources/views/server/users/index.blade.php b/resources/views/server/users/index.blade.php deleted file mode 100644 index 96a1d40ff..000000000 --- a/resources/views/server/users/index.blade.php +++ /dev/null @@ -1,107 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Viewing Subusers -@endsection - -@section('content') -
    -

    Manage Sub-Users


    - - - - - - @can('view-subuser', $server)@endcan - @can('delete-subuser', $server)@endcan - - - - @foreach($subusers as $user) - - - - @can('view-subuser', $server) - - @endcan - @can('delete-subuser', $server) - - @endcan - - @endforeach - -
    EmailCreated
    {{ $user->a_userEmail }}{{ $user->created_at }}
    - @can('create-subuser', $server) -
    -
    - -
    -
    - @endcan -
    - -@endsection diff --git a/resources/views/server/users/new.blade.php b/resources/views/server/users/new.blade.php deleted file mode 100644 index c954bcd4b..000000000 --- a/resources/views/server/users/new.blade.php +++ /dev/null @@ -1,301 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Create New Subuser -@endsection - -@section('content') -
    -

    Create New Subuser
    - @can('edit-subuser', $server) -
    - @endcan - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    -
    -

    Power Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    File Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Subuser Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Server Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Database Management


    -
    -
    -
    -
    -
    -
    -

    SFTP Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Task Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - @can('edit-subuser', $server) -
    -
    -
    - {!! csrf_field() !!} - -
    -
    -
    -
    - @endcan -

    - -@endsection diff --git a/resources/views/server/users/view.blade.php b/resources/views/server/users/view.blade.php deleted file mode 100644 index 6ac4dc9a8..000000000 --- a/resources/views/server/users/view.blade.php +++ /dev/null @@ -1,289 +0,0 @@ -{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} - -{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}} -{{-- of this software and associated documentation files (the "Software"), to deal --}} -{{-- in the Software without restriction, including without limitation the rights --}} -{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}} -{{-- copies of the Software, and to permit persons to whom the Software is --}} -{{-- furnished to do so, subject to the following conditions: --}} - -{{-- The above copyright notice and this permission notice shall be included in all --}} -{{-- copies or substantial portions of the Software. --}} - -{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}} -{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}} -{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}} -{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}} -{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}} -{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}} -{{-- SOFTWARE. --}} -@extends('layouts.master') - -@section('title') - Manage Subuser: {{ $subuser->a_userEmail }} -@endsection - -@section('content') -
    -

    Manage Subuser {{ $subuser->a_userEmail }}


    - @can('edit-subuser', $server) -
    - @endcan -
    -
    -

    Power Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    File Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Subuser Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Server Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Database Management


    -
    -
    -
    -
    -
    -
    -

    SFTP Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Task Management


    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - @can('edit-subuser', $server) -
    -
    -
    - {!! csrf_field() !!} - -
    -
    -
    - - @endcan -
    - -@endsection diff --git a/server.php b/server.php index f65c7c444..de038652f 100644 --- a/server.php +++ b/server.php @@ -1,12 +1,10 @@ */ - $uri = urldecode( parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ); @@ -14,8 +12,8 @@ $uri = urldecode( // This file allows us to emulate Apache's "mod_rewrite" functionality from the // built-in PHP web server. This provides a convenient way to test a Laravel // application without having installed a "real" web server software here. -if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { +if ($uri !== '/' && file_exists(__DIR__ . '/public' . $uri)) { return false; } -require_once __DIR__.'/public/index.php'; +require_once __DIR__ . '/public/index.php'; diff --git a/storage/app/.gitignore b/storage/app/.gitignore index c96a04f00..104980aa3 100755 --- a/storage/app/.gitignore +++ b/storage/app/.gitignore @@ -1,2 +1,6 @@ * -!.gitignore \ No newline at end of file +!.gitignore +!services/* +packs/**/* +services/.bak/* +!packs/.githold diff --git a/storage/app/packs/.githold b/storage/app/packs/.githold new file mode 100644 index 000000000..e69de29bb diff --git a/storage/app/services/.templates/index.js b/storage/app/services/.templates/index.js new file mode 100644 index 000000000..f6b6695d0 --- /dev/null +++ b/storage/app/services/.templates/index.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * Copyright (c) 2015 - 2017 Dane Everitt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +const rfr = require('rfr'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; diff --git a/storage/app/services/minecraft/index.js b/storage/app/services/minecraft/index.js new file mode 100644 index 000000000..b53364bec --- /dev/null +++ b/storage/app/services/minecraft/index.js @@ -0,0 +1,38 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * Copyright (c) 2015 - 2017 Dane Everitt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +const rfr = require('rfr'); +const _ = require('lodash'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core { + onConsole(data) { + // Hide the output spam from Bungeecord getting pinged. + if (_.endsWith(data, '<-> InitialHandler has connected')) return; + return super.onConsole(data); + } +} + +module.exports = Service; diff --git a/storage/app/services/minecraft/main.json b/storage/app/services/minecraft/main.json new file mode 100644 index 000000000..48a490cb3 --- /dev/null +++ b/storage/app/services/minecraft/main.json @@ -0,0 +1,74 @@ +{ + "vanilla": { + "startup": { + "done": ")! For help, type ", + "userInteraction": [ + "Go to eula.txt for more info." + ] + }, + "stop": "stop", + "configs": { + "server.properties": { + "parser": "properties", + "find": { + "server-ip": "0.0.0.0", + "enable-query": "true", + "server-port": "{{ server.build.default.port }}", + "query.port": "{{ server.build.default.port }}" + } + } + }, + "log": { + "custom": false, + "location": "logs/latest.log" + }, + "query": "minecraftping" + }, + "spigot": { + "symlink": "vanilla", + "configs": { + "spigot.yml": { + "parser": "yaml", + "find": { + "settings.restart-on-crash": "false" + } + } + } + }, + "bungeecord": { + "startup": { + "done": "Listening on ", + "userInteraction": [ + "Listening on /0.0.0.0:25577" + ] + }, + "stop": "end", + "configs": { + "config.yml": { + "parser": "yaml", + "find": { + "listeners[0].query_enabled": true, + "listeners[0].query_port": "{{ server.build.default.port }}", + "listeners[0].host": "0.0.0.0:{{ server.build.default.port }}", + "servers.*.address": { + "127.0.0.1": "{{ config.docker.interface }}", + "localhost": "{{ config.docker.interface }}" + } + } + } + }, + "log": { + "custom": false, + "location": "proxy.log.0" + }, + "query": "minecraftping" + }, + "sponge": { + "symlink": "vanilla", + "startup": { + "userInteraction": [ + "You need to agree to the EULA" + ] + } + } +} diff --git a/storage/app/services/srcds/index.js b/storage/app/services/srcds/index.js new file mode 100644 index 000000000..f6b6695d0 --- /dev/null +++ b/storage/app/services/srcds/index.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * Copyright (c) 2015 - 2017 Dane Everitt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +const rfr = require('rfr'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; diff --git a/storage/app/services/srcds/main.json b/storage/app/services/srcds/main.json new file mode 100644 index 000000000..989a67537 --- /dev/null +++ b/storage/app/services/srcds/main.json @@ -0,0 +1,23 @@ +{ + "srcds": { + "startup": { + "done": "Assigned anonymous gameserver Steam ID", + "userInteraction": [] + }, + "stop": "quit", + "configs": {}, + "log": { + "custom": true, + "location": "logs/latest.log" + }, + "query": "protocol-valve" + }, + "ark": { + "symlink": "srcds", + "startup": { + "done": "Setting breakpad minidump AppID" + }, + "stop": "^C", + "query": "none" + } +} diff --git a/storage/app/services/terraria/index.js b/storage/app/services/terraria/index.js new file mode 100644 index 000000000..f6b6695d0 --- /dev/null +++ b/storage/app/services/terraria/index.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * Copyright (c) 2015 - 2017 Dane Everitt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +const rfr = require('rfr'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; diff --git a/storage/app/services/terraria/main.json b/storage/app/services/terraria/main.json new file mode 100644 index 000000000..78f1b5bc0 --- /dev/null +++ b/storage/app/services/terraria/main.json @@ -0,0 +1,23 @@ +{ + "tshock": { + "startup": { + "done": "Type 'help' for a list of commands", + "userInteraction": [] + }, + "stop": "exit", + "configs": { + "tshock/config.json": { + "parser": "json", + "find": { + "ServerPort": "{{ server.build.default.port }}", + "MaxSlots": "{{ server.build.env.MAX_SLOTS }}" + } + } + }, + "log": { + "custom": false, + "location": "ServerLog.txt" + }, + "query": "none" + } +} diff --git a/storage/app/services/voice/index.js b/storage/app/services/voice/index.js new file mode 100644 index 000000000..f6b6695d0 --- /dev/null +++ b/storage/app/services/voice/index.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Pterodactyl - Daemon + * Copyright (c) 2015 - 2017 Dane Everitt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +const rfr = require('rfr'); + +const Core = rfr('src/services/index.js'); + +class Service extends Core {} + +module.exports = Service; diff --git a/storage/app/services/voice/main.json b/storage/app/services/voice/main.json new file mode 100644 index 000000000..bc7232f46 --- /dev/null +++ b/storage/app/services/voice/main.json @@ -0,0 +1,50 @@ +{ + "mumble": { + "startup": { + "done": "Server listening on", + "userInteraction": [ + "Generating new server certificate" + ] + }, + "stop": "^C", + "configs": { + "murmur.ini": { + "parser": "ini", + "find": { + "logfile": "murmur.log", + "port": "{{ server.build.default.port }}", + "host": "0.0.0.0", + "users": "{{ server.build.env.MAX_USERS }}" + } + } + }, + "log": { + "custom": true, + "location": "logs/murmur.log" + }, + "query": "mumbleping" + }, + "ts3": { + "startup": { + "done": "listening on 0.0.0.0:", + "userInteraction": [] + }, + "stop": "^C", + "configs": { + "ts3server.ini": { + "parser": "ini", + "find": { + "default_voice_port": "{{ server.build.default.port }}", + "voice_ip": "0.0.0.0", + "query_port": "{{ server.build.default.port }}", + "query_ip": "0.0.0.0" + } + } + }, + "log": { + "custom": true, + "location": "logs/ts3.log" + }, + "query": "none" + } +} diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php index 7e81d37aa..2c3a83c83 100644 --- a/tests/ExampleTest.php +++ b/tests/ExampleTest.php @@ -1,8 +1,5 @@ make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();