Initial Commit of Files
PufferPanel v0.9 (Laravel) is now Pterodactyl 1.0
This commit is contained in:
commit
1489f7a694
154 changed files with 10159 additions and 0 deletions
83
app/Http/Controllers/API/UserController.php
Normal file
83
app/Http/Controllers/API/UserController.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\API;
|
||||
|
||||
use Gate;
|
||||
use Log;
|
||||
use Debugbar;
|
||||
use Pterodactyl\Models\API;
|
||||
use Pterodactyl\Models\User;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('api');
|
||||
}
|
||||
|
||||
public function getAllUsers(Request $request)
|
||||
{
|
||||
|
||||
// Policies don't work if the user isn't logged in for whatever reason in Laravel...
|
||||
if(!API::checkPermission($request->header('X-Authorization'), 'get-users')) {
|
||||
return API::noPermissionError();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'users' => User::all()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON response about a user given their ID.
|
||||
* If fields are provided only those fields are returned.
|
||||
*
|
||||
* Does not return protected fields (i.e. password & totp_secret)
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @param string $fields
|
||||
* @return Response
|
||||
*/
|
||||
public function getUser(Request $request, $id, $fields = null)
|
||||
{
|
||||
|
||||
// Policies don't work if the user isn't logged in for whatever reason in Laravel...
|
||||
if(!API::checkPermission($request->header('X-Authorization'), 'get-users')) {
|
||||
return API::noPermissionError();
|
||||
}
|
||||
|
||||
if (is_null($fields)) {
|
||||
return response()->json(User::find($id));
|
||||
}
|
||||
|
||||
$query = User::where('id', $id);
|
||||
$explode = explode(',', $fields);
|
||||
|
||||
foreach($explode as &$exploded) {
|
||||
if(!empty($exploded)) {
|
||||
$query->addSelect($exploded);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return response()->json($query->get());
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof \Illuminate\Database\QueryException) {
|
||||
return response()->json([
|
||||
'error' => 'One of the fields provided in your argument list is invalid.'
|
||||
], 500);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
43
app/Http/Controllers/Admin/AccountsController.php
Normal file
43
app/Http/Controllers/Admin/AccountsController.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Debugbar;
|
||||
use Pterodactyl\Models\User;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AccountsController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Controller Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// All routes in this controller are protected by the authentication middleware.
|
||||
$this->middleware('auth');
|
||||
$this->middleware('admin');
|
||||
|
||||
}
|
||||
|
||||
public function getIndex(Request $request)
|
||||
{
|
||||
return view('admin.accounts.index', [
|
||||
'users' => User::paginate(20)
|
||||
]);
|
||||
}
|
||||
|
||||
public function getNew(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function getView(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
30
app/Http/Controllers/Admin/BaseController.php
Normal file
30
app/Http/Controllers/Admin/BaseController.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Debugbar;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Controller Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// All routes in this controller are protected by the authentication middleware.
|
||||
$this->middleware('auth');
|
||||
$this->middleware('admin');
|
||||
|
||||
}
|
||||
|
||||
public function getIndex(Request $request)
|
||||
{
|
||||
return view('admin.index');
|
||||
}
|
||||
|
||||
}
|
47
app/Http/Controllers/Admin/ServersController.php
Normal file
47
app/Http/Controllers/Admin/ServersController.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Debugbar;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Node;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServersController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Controller Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// All routes in this controller are protected by the authentication middleware.
|
||||
$this->middleware('auth');
|
||||
$this->middleware('admin');
|
||||
|
||||
}
|
||||
|
||||
public function getIndex(Request $request)
|
||||
{
|
||||
return view('admin.servers.index', [
|
||||
'servers' => Server::select('servers.*', 'nodes.name as a_nodeName', 'users.email as a_ownerEmail')
|
||||
->join('nodes', 'servers.node', '=', 'nodes.id')
|
||||
->join('users', 'servers.owner', '=', 'users.id')
|
||||
->paginate(20),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getNew(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function getView(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
97
app/Http/Controllers/Auth/AuthController.php
Normal file
97
app/Http/Controllers/Auth/AuthController.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Auth;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
|
||||
use Validator;
|
||||
use Auth;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Registration & Login Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles the registration of new users, as well as the
|
||||
| authentication of existing users. By default, this controller uses
|
||||
| a simple trait to add these behaviors. Why don't you explore it?
|
||||
|
|
||||
*/
|
||||
|
||||
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
|
||||
|
||||
/**
|
||||
* Post-Authentication redirect location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectPath = '/';
|
||||
|
||||
/**
|
||||
* Failed post-authentication redirect location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $loginPath = '/auth/login';
|
||||
|
||||
/**
|
||||
* Lockout time for failed login requests.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $lockoutTime = 120;
|
||||
|
||||
/**
|
||||
* After how many attempts should logins be throttled and locked.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $maxLoginAttempts = 5;
|
||||
|
||||
/**
|
||||
* Create a new authentication controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest', ['except' => 'getLogout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'email' => 'required|email|max:255|unique:users',
|
||||
'password' => 'required|confirmed|min:8',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
* @return User
|
||||
*/
|
||||
protected function create(array $data)
|
||||
{
|
||||
return User::create([
|
||||
'name' => $data['name'],
|
||||
'email' => $data['email'],
|
||||
'password' => password_hash($data['password']),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
32
app/Http/Controllers/Auth/PasswordController.php
Normal file
32
app/Http/Controllers/Auth/PasswordController.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Auth;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
|
||||
class PasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset requests
|
||||
| and uses a simple trait to include this behavior. You're free to
|
||||
| explore this trait and override any methods you wish to tweak.
|
||||
|
|
||||
*/
|
||||
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Create a new password controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
}
|
222
app/Http/Controllers/Base/IndexController.php
Normal file
222
app/Http/Controllers/Base/IndexController.php
Normal file
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Base;
|
||||
|
||||
use Auth;
|
||||
use Debugbar;
|
||||
use Google2FA;
|
||||
use Log;
|
||||
use Alert;
|
||||
use Pterodactyl\Exceptions\AccountNotFoundException;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class IndexController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Controller Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// All routes in this controller are protected by the authentication middleware.
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns listing of user's servers.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getIndex(Request $request)
|
||||
{
|
||||
return view('base.index', [
|
||||
'servers' => Server::getUserServers(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TOTP Management Page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getAccountTotp(Request $request)
|
||||
{
|
||||
return view('base.totp');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates TOTP Secret and returns popup data for user to verify
|
||||
* that they can generate a valid response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function putAccountTotp(Request $request)
|
||||
{
|
||||
|
||||
try {
|
||||
$totpSecret = User::setTotpSecret(Auth::user()->id);
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof AccountNotFoundException) {
|
||||
return response($e->getMessage(), 500);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'qrImage' => Google2FA::getQRCodeGoogleUrl(
|
||||
'Pterodactyl',
|
||||
Auth::user()->email,
|
||||
$totpSecret
|
||||
),
|
||||
'secret' => $totpSecret
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that 2FA token recieved is valid and will work on the account.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function postAccountTotp(Request $request)
|
||||
{
|
||||
|
||||
if (!$request->has('token')) {
|
||||
return response('No input \'token\' defined.', 500);
|
||||
}
|
||||
|
||||
try {
|
||||
if(User::toggleTotp(Auth::user()->id, $request->input('token'))) {
|
||||
return response('true');
|
||||
}
|
||||
return response('false');
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof AccountNotFoundException) {
|
||||
return response($e->getMessage(), 500);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables TOTP on an account.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function deleteAccountTotp(Request $request)
|
||||
{
|
||||
|
||||
if (!$request->has('token')) {
|
||||
Alert::danger('Missing required `token` field in request.')->flash();
|
||||
return redirect()->route('account.totp');
|
||||
}
|
||||
|
||||
try {
|
||||
if(User::toggleTotp(Auth::user()->id, $request->input('token'))) {
|
||||
return redirect()->route('account.totp');
|
||||
}
|
||||
|
||||
Alert::danger('Unable to disable TOTP on this account, was the token correct?')->flash();
|
||||
return redirect()->route('account.totp');
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof AccountNotFoundException) {
|
||||
Alert::danger('An error occured while attempting to perform this action.')->flash();
|
||||
return redirect()->route('account.totp');
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display base account information page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getAccount(Request $request)
|
||||
{
|
||||
return view('base.account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an account email.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function postAccountEmail(Request $request)
|
||||
{
|
||||
|
||||
$this->validate($request, [
|
||||
'new_email' => 'required|email',
|
||||
'password' => 'required'
|
||||
]);
|
||||
|
||||
if (!password_verify($request->input('password'), Auth::user()->password)) {
|
||||
Alert::danger('The password provided was not valid for this account.')->flash();
|
||||
return redirect()->route('account');
|
||||
}
|
||||
|
||||
// Met Validation, lets roll out.
|
||||
try {
|
||||
User::setEmail(Auth::user()->id, $request->input('new_email'));
|
||||
Alert::success('Your email address has successfully been updated.')->flash();
|
||||
return redirect()->route('account');
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof AccountNotFoundException || $e instanceof DisplayException) {
|
||||
Alert::danger($e->getMessage())->flash();
|
||||
return redirect()->route('account');
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an account password.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function postAccountPassword(Request $request)
|
||||
{
|
||||
|
||||
$this->validate($request, [
|
||||
'current_password' => 'required',
|
||||
'new_password' => 'required|confirmed|different:current_password|regex:((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})',
|
||||
'new_password_confirmation' => 'required'
|
||||
]);
|
||||
|
||||
if (!password_verify($request->input('current_password'), Auth::user()->password)) {
|
||||
Alert::danger('The password provided was not valid for this account.')->flash();
|
||||
return redirect()->route('account');
|
||||
}
|
||||
|
||||
// Met Validation, lets roll out.
|
||||
try {
|
||||
User::setPassword(Auth::user()->id, $request->input('new_password'));
|
||||
Alert::success('Your password has successfully been updated.')->flash();
|
||||
return redirect()->route('account');
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof AccountNotFoundException || $e instanceof DisplayException) {
|
||||
Alert::danger($e->getMessage())->flash();
|
||||
return redirect()->route('account');
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
13
app/Http/Controllers/Controller.php
Normal file
13
app/Http/Controllers/Controller.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
|
||||
abstract class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
}
|
193
app/Http/Controllers/Scales/FileController.php
Normal file
193
app/Http/Controllers/Scales/FileController.php
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Scales;
|
||||
|
||||
use \Exception;
|
||||
use Log;
|
||||
use Debugbar;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Node;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Helpers;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
class FileController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* The Eloquent Model associated with the requested server.
|
||||
*
|
||||
* @var \Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* The Eloquent Model for the node corresponding with the requested server.
|
||||
*
|
||||
* @var \Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
protected $node;
|
||||
|
||||
/**
|
||||
* The Guzzle Client associated with the requested server and node.
|
||||
*
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* The Guzzle Client headers associated with the requested server and node.
|
||||
* (non-administrative headers)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $headers;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a requested file for the server.
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public function returnFileContents($file)
|
||||
{
|
||||
|
||||
if (empty($file)) {
|
||||
throw new Exception('Not all parameters were properly passed to the function.');
|
||||
}
|
||||
|
||||
$file = (object) pathinfo($file);
|
||||
if (!in_array($file->extension, Helpers::editableFiles())) {
|
||||
throw new DisplayException('You do not have permission to edit this type of file.');
|
||||
}
|
||||
|
||||
$file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/';
|
||||
|
||||
$res = $this->client->request('GET', '/server/file/' . rawurlencode($file->dirname.$file->basename), [
|
||||
'headers' => $this->headers
|
||||
]);
|
||||
|
||||
$json = json_decode($res->getBody());
|
||||
if($res->getStatusCode() !== 200 || !isset($json->contents)) {
|
||||
throw new DisplayException('Scales provided a non-200 error code: HTTP\\' . $res->getStatusCode());
|
||||
}
|
||||
|
||||
return $json;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the contents of a requested file on the Scales instance.
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $content
|
||||
* @return boolean
|
||||
*/
|
||||
public function saveFileContents($file, $content)
|
||||
{
|
||||
|
||||
if (empty($file)) {
|
||||
throw new Exception('A valid file and path must be specified to save a file.');
|
||||
}
|
||||
|
||||
$file = (object) pathinfo($file);
|
||||
|
||||
if(!in_array($file->extension, Helpers::editableFiles())) {
|
||||
throw new DisplayException('You do not have permission to edit this type of file.');
|
||||
}
|
||||
|
||||
$file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/';
|
||||
|
||||
$res = $this->client->request('PUT', '/server/file/' . rawurlencode($file->dirname.$file->basename), [
|
||||
'headers' => $this->headers,
|
||||
'form_params' => [
|
||||
'contents' => $content
|
||||
]
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() !== 204) {
|
||||
throw new DisplayException('An error occured while attempting to save this file. Scales said: ' . $res->getBody());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a listing of all files and folders within a specified Scales directory.
|
||||
*
|
||||
* @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/' . $directory, [
|
||||
'headers' => $this->headers
|
||||
]);
|
||||
|
||||
$json = json_decode($res->getBody());
|
||||
if($res->getStatusCode() !== 200) {
|
||||
throw new DisplayException('An error occured while attempting to save this file. Scales said: ' . $res->getBody());
|
||||
}
|
||||
|
||||
// Iterate through results
|
||||
$files = [];
|
||||
$folders = [];
|
||||
foreach($json as &$value) {
|
||||
|
||||
if ($value->file !== true) {
|
||||
|
||||
// @TODO Handle Symlinks
|
||||
$folders = array_merge($folders, [[
|
||||
'entry' => $value->name,
|
||||
'directory' => trim($directory, '/'),
|
||||
'size' => null,
|
||||
'date' => strtotime($value->modified)
|
||||
]]);
|
||||
|
||||
} else {
|
||||
|
||||
$files = array_merge($files, [[
|
||||
'entry' => $value->name,
|
||||
'directory' => trim($directory, '/'),
|
||||
'extension' => pathinfo($value->name, PATHINFO_EXTENSION),
|
||||
'size' => Helpers::bytesToHuman($value->size),
|
||||
'date' => strtotime($value->modified)
|
||||
]]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'files' => $files,
|
||||
'folders' => $folders,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
}
|
182
app/Http/Controllers/Server/AjaxController.php
Normal file
182
app/Http/Controllers/Server/AjaxController.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Server;
|
||||
|
||||
use Log;
|
||||
use Debugbar;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Http\Helpers;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Scales\FileController;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
class AjaxController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $files = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $folders = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $directory;
|
||||
|
||||
/**
|
||||
* Controller Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// All routes in this controller are protected by the authentication middleware.
|
||||
$this->middleware('auth');
|
||||
|
||||
// Routes in this file are also checked aganist the server middleware. If the user
|
||||
// does not have permission to view the server it will not load.
|
||||
$this->middleware('server');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false depending on the power status of the requested server.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $uuid
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getStatus(Request $request, $uuid)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($uuid);
|
||||
$client = Node::guzzleRequest($server->node);
|
||||
|
||||
try {
|
||||
|
||||
$res = $client->request('GET', '/server', [
|
||||
'headers' => Server::getGuzzleHeaders($uuid)
|
||||
]);
|
||||
|
||||
if($res->getStatusCode() === 200) {
|
||||
|
||||
$json = json_decode($res->getBody());
|
||||
|
||||
if (isset($json->status) && $json->status === 1) {
|
||||
return 'true';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (RequestException $e) {
|
||||
Debugbar::error($e->getMessage());
|
||||
Log::notice('An exception was raised while attempting to contact a Scales instance to get server status information.', [
|
||||
'exception' => $e->getMessage(),
|
||||
'path' => $request->path()
|
||||
]);
|
||||
}
|
||||
|
||||
return 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a listing of files in a given directory for a server.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $uuid`
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function postDirectoryList(Request $request, $uuid)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($uuid);
|
||||
$this->directory = '/' . trim(urldecode($request->input('directory', '/')), '/');
|
||||
$this->authorize('list-files', $server);
|
||||
|
||||
$prevDir = [
|
||||
'header' => ($this->directory !== '/') ? $this->directory : ''
|
||||
];
|
||||
if ($this->directory !== '/') {
|
||||
$prevDir['first'] = true;
|
||||
}
|
||||
|
||||
// Determine if we should show back links in the file browser.
|
||||
// This code is strange, and could probably be rewritten much better.
|
||||
$goBack = explode('/', rtrim($this->directory, '/'));
|
||||
if (isset($goBack[2]) && !empty($goBack[2])) {
|
||||
$prevDir['show'] = true;
|
||||
$prevDir['link'] = '/' . trim(str_replace(end($goBack), '', $this->directory), '/');
|
||||
$prevDir['link_show'] = trim($prevDir['link'], '/');
|
||||
}
|
||||
|
||||
$controller = new FileController($uuid);
|
||||
|
||||
try {
|
||||
$directoryContents = $controller->returnDirectoryListing($this->directory);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
Debugbar::addException($e);
|
||||
$exception = 'An error occured while attempting to load the requested directory, please try again.';
|
||||
|
||||
if ($e instanceof DisplayException) {
|
||||
$exception = $e->getMessage();
|
||||
}
|
||||
|
||||
return response($exception, 500);
|
||||
|
||||
}
|
||||
|
||||
return view('server.files.list', [
|
||||
'server' => $server,
|
||||
'files' => $directoryContents->files,
|
||||
'folders' => $directoryContents->folders,
|
||||
'extensions' => Helpers::editableFiles(),
|
||||
'directory' => $prevDir
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a POST request to save a file.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $uuid
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function postSaveFile(Request $request, $uuid)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($uuid);
|
||||
$this->authorize('save-files', $server);
|
||||
|
||||
$controller = new FileController($uuid);
|
||||
|
||||
try {
|
||||
$controller->saveFileContents($request->input('file'), $request->input('contents'));
|
||||
return response(null, 204);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
Debugbar::addException($e);
|
||||
$exception = 'An error occured while attempting to save that file, please try again.';
|
||||
|
||||
if ($e instanceof DisplayException) {
|
||||
$exception = $e->getMessage();
|
||||
}
|
||||
|
||||
return response($exception, 500);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
162
app/Http/Controllers/Server/ServerController.php
Normal file
162
app/Http/Controllers/Server/ServerController.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Server;
|
||||
|
||||
use Auth;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Models\Download;
|
||||
use Debugbar;
|
||||
use Uuid;
|
||||
use Alert;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Scales\FileController;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Controller Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// All routes in this controller are protected by the authentication middleware.
|
||||
$this->middleware('auth');
|
||||
|
||||
// Routes in this file are also checked aganist the server middleware. If the user
|
||||
// does not have permission to view the server it will not load.
|
||||
$this->middleware('server');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders server index page for specified server.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getIndex(Request $request)
|
||||
{
|
||||
$server = Server::getByUUID($request->route()->server);
|
||||
return view('server.index', [
|
||||
'server' => $server,
|
||||
'node' => Node::find($server->node)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders file overview page.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getFiles(Request $request)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($request->route()->server);
|
||||
$this->authorize('list-files', $server);
|
||||
|
||||
return view('server.files.index', [
|
||||
'server' => $server,
|
||||
'node' => Node::find($server->node)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders add file page.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getAddFile(Request $request)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($request->route()->server);
|
||||
$this->authorize('add-files', $server);
|
||||
|
||||
return view('server.files.add', [
|
||||
'server' => $server,
|
||||
'node' => Node::find($server->node),
|
||||
'directory' => (in_array($request->get('dir'), [null, '/', ''])) ? '' : trim($request->get('dir'), '/') . '/'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders edit file page for a given file.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $uuid
|
||||
* @param string $file
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getEditFile(Request $request, $uuid, $file)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($uuid);
|
||||
$this->authorize('edit-files', $server);
|
||||
|
||||
$fileInfo = (object) pathinfo($file);
|
||||
$controller = new FileController($uuid);
|
||||
|
||||
try {
|
||||
$fileContent = $controller->returnFileContents($file);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
Debugbar::addException($e);
|
||||
$exception = 'An error occured while attempting to load the requested file for editing, please try again.';
|
||||
|
||||
if ($e instanceof DisplayException) {
|
||||
$exception = $e->getMessage();
|
||||
}
|
||||
|
||||
Alert::danger($exception)->flash();
|
||||
return redirect()->route('files.index', $uuid);
|
||||
|
||||
}
|
||||
|
||||
return view('server.files.edit', [
|
||||
'server' => $server,
|
||||
'node' => Node::find($server->node),
|
||||
'file' => $file,
|
||||
'contents' => $fileContent->contents,
|
||||
'directory' => (in_array($fileInfo->dirname, ['.', './', '/'])) ? '/' : trim($fileInfo->dirname, '/') . '/',
|
||||
'extension' => $fileInfo->extension
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles downloading a file for the user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $uuid
|
||||
* @param string $file
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getDownloadFile(Request $request, $uuid, $file)
|
||||
{
|
||||
|
||||
$server = Server::getByUUID($uuid);
|
||||
$node = Node::find($server->node);
|
||||
|
||||
$this->authorize('download-files', $server);
|
||||
|
||||
$download = new Download;
|
||||
|
||||
$download->token = Uuid::generate(4);
|
||||
$download->server = $server->id;
|
||||
$download->path = str_replace('../', '', $file);
|
||||
|
||||
$download->save();
|
||||
|
||||
return redirect('https://' . $node->fqdn . ':' . $node->daemonListen . '/server/download/' . $download->token);
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue