diff --git a/app/Http/Controllers/Admin/AccountsController.php b/app/Http/Controllers/Admin/AccountsController.php
index 55af688aa..a4b071fa6 100644
--- a/app/Http/Controllers/Admin/AccountsController.php
+++ b/app/Http/Controllers/Admin/AccountsController.php
@@ -3,11 +3,9 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Alert;
-use Debugbar;
-use Hash;
-use Uuid;
-
use Pterodactyl\Models\User;
+use Pterodactyl\Repositories\UserRepository;
+
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Http\Request;
@@ -52,18 +50,19 @@ class AccountsController extends Controller
'password_confirmation' => 'required'
]);
- //@TODO: re-generate UUID if conflict
- $user = new User;
- $user->uuid = Uuid::generate(4);
+ try {
- $user->username = $request->input('username');
- $user->email = $request->input('email');
- $user->password = Hash::make($request->input('password'));
+ $user = new UserRepository;
+ $userid = $user->create($request->input('username'), $request->input('email'), $request->input('password'));
- $user->save();
+ Alert::success('Account has been successfully created.')->flash();
+ return redirect()->route('admin.accounts.view', ['id' => $userid]);
+
+ } catch (\Exception $e) {
+ Alert::danger('An error occured while attempting to add a new user. Please check the logs or try again.')->flash();
+ return redirect()->route('admin.accounts.new');
+ }
- Alert::success('Account has been successfully created.')->flash();
- return redirect()->route('admin.accounts.view', ['id' => $user->id]);
}
}
diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php
index 00dd918f4..c307f0f3d 100644
--- a/app/Http/Controllers/Admin/ServersController.php
+++ b/app/Http/Controllers/Admin/ServersController.php
@@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Debugbar;
+use Pterodactyl\Repositories\ServerRepository;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Location;
@@ -56,7 +57,8 @@ class ServersController extends Controller
{
try {
- $resp = Server::addServer($request->all());
+ $server = new ServerRepository;
+ $resp = $server->create($request->all());
echo $resp . '
';
} catch (\Exception $e) {
Debugbar::addException($e);
diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php
index b8599c517..d62af98cd 100644
--- a/app/Http/Controllers/Base/IndexController.php
+++ b/app/Http/Controllers/Base/IndexController.php
@@ -3,14 +3,12 @@
namespace Pterodactyl\Http\Controllers\Base;
use Auth;
-use Debugbar;
+use Hash;
use Google2FA;
-use Log;
use Alert;
-use Pterodactyl\Exceptions\AccountNotFoundException;
-use Pterodactyl\Exceptions\DisplayException;
-use Pterodactyl\Models\User;
+
use Pterodactyl\Models\Server;
+use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Http\Request;
@@ -74,22 +72,18 @@ class IndexController extends Controller
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;
- }
+ $user = $request->user();
+
+ $user->totp_secret = Google2FA::generateSecretKey();
+ $user->save();
return response()->json([
'qrImage' => Google2FA::getQRCodeGoogleUrl(
'Pterodactyl',
- Auth::user()->email,
- $totpSecret
+ $user->email,
+ $user->totp_secret
),
- 'secret' => $totpSecret
+ 'secret' => $user->totp_secret
]);
}
@@ -104,21 +98,16 @@ class IndexController extends Controller
{
if (!$request->has('token')) {
- return response('No input \'token\' defined.', 500);
+ return response(null, 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;
+ $user = $request->user();
+ if($user->toggleTotp($request->input('token'))) {
+ return response('true');
}
+ return response('false');
+
}
/**
@@ -135,21 +124,14 @@ class IndexController extends Controller
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();
+ $user = $request->user();
+ if($user->toggleTotp($request->input('token'))) {
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;
}
+ Alert::danger('The TOTP token provided was invalid.')->flash();
+ return redirect()->route('account.totp');
+
}
/**
@@ -177,23 +159,19 @@ class IndexController extends Controller
'password' => 'required'
]);
- if (!password_verify($request->input('password'), Auth::user()->password)) {
+ $user = $request->user();
+
+ if (!password_verify($request->input('password'), $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;
- }
+ $user->email = $request->input('new_email');
+ $user->save();
+
+ Alert::success('Your email address has successfully been updated.')->flash();
+ return redirect()->route('account');
+
}
/**
@@ -211,24 +189,22 @@ class IndexController extends Controller
'new_password_confirmation' => 'required'
]);
- if (!password_verify($request->input('current_password'), Auth::user()->password)) {
+ $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');
}
- // Met Validation, lets roll out.
try {
- User::setPassword(Auth::user()->id, $request->input('new_password'));
+ $user->setPassword($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;
+ } catch (DisplayException $e) {
+ Alert::danger($e->getMessage())->flash();
}
+ return redirect()->route('account');
+
}
}
diff --git a/app/Models/Server.php b/app/Models/Server.php
index 3b0313e63..2fa7bb735 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -3,16 +3,8 @@
namespace Pterodactyl\Models;
use Auth;
-use DB;
-use Debugbar;
-use Validator;
-
-use Pterodactyl\Exceptions\DisplayException;
-use Pterodactyl\Exceptions\AccountNotFoundException;
-use Pterodactyl\Exceptions\DisplayValidationException;
-
-use Pterodactyl\Models;
+use Pterodactyl\Models\Subuser;
use Illuminate\Database\Eloquent\Model;
class Server extends Model
@@ -50,18 +42,6 @@ class Server extends Model
self::$user = Auth::user();
}
- protected static function generateSFTPUsername($name)
- {
-
- $name = preg_replace('/\s+/', '', $name);
- if (strlen($name) > 6) {
- return strtolower('ptdl-' . substr($name, 0, 6) . '_' . str_random(5));
- }
-
- return strtolower('ptdl-' . $name . '_' . str_random((11 - strlen($name))));
-
- }
-
/**
* Determine if we need to change the server's daemonSecret value to
* match that of the user if they are a subuser.
@@ -76,7 +56,7 @@ class Server extends Model
return $server->daemonSecret;
}
- $subuser = Models\Subuser::where('server_id', $server->id)->where('user_id', self::$user->id)->first();
+ $subuser = Subuser::where('server_id', $server->id)->where('user_id', self::$user->id)->first();
if (is_null($subuser)) {
return null;
@@ -101,7 +81,7 @@ class Server extends Model
->where('active', 1);
if (self::$user->root_admin !== 1) {
- $query->whereIn('servers.id', Models\Subuser::accessServers());
+ $query->whereIn('servers.id', Subuser::accessServers());
}
return $query->get();
@@ -124,7 +104,7 @@ class Server extends Model
$query = self::where('uuidShort', $uuid)->where('active', 1);
if (self::$user->root_admin !== 1) {
- $query->whereIn('servers.id', Models\Subuser::accessServers());
+ $query->whereIn('servers.id', Subuser::accessServers());
}
$result = $query->first();
@@ -158,84 +138,4 @@ class Server extends Model
}
- /**
- * 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.
- */
- public static function addServer(array $data)
- {
-
- // Validate Fields
- $validator = Validator::make($data, [
- 'owner' => 'required|email|exists:users,email',
- 'node' => 'required|numeric|min:1|exists:nodes,id',
- 'name' => 'required|regex:([\w -]{4,35})',
- 'memory' => 'required|numeric|min:1',
- 'disk' => 'required|numeric|min:1',
- 'cpu' => 'required|numeric|min:0',
- 'io' => 'required|numeric|min:10|max:1000',
- 'ip' => 'required|ip',
- 'port' => 'required|numeric|min:1|max:65535',
- 'service' => 'required|numeric|min:1|exists:services,id',
- 'option' => 'required|numeric|min:1|exists:service_options,id',
- 'custom_image_name' => 'required_if:use_custom_image,on',
- ]);
-
- // Run validator, throw catchable and displayable exception if it fails.
- // Exception includes a JSON result of failed validation rules.
- if ($validator->fails()) {
- throw new DisplayValidationException(json_encode($validator->errors()->all()));
- }
-
- // Get the User ID; user exists since we passed the 'exists:users,email' part of the validation
- $user = Models\User::select('id')->where('email', $data['owner'])->first();
-
- // 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
- $node = Models\Node::find($data['node']);
- $allocation = Models\Allocation::where('ip', $data['ip'])->where('port', $data['port'])->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) {
- throw new DisplayException('The selected IP/Port combination (' . $data['ip'] . ':' . $data['port'] . ') is either already in use, or unavaliable for this node.');
- }
-
- // Validate those Service Option Variables
- // We know the service and option exists because of the validation.
- // 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) {
- throw new DisplayException('The requested service option does not exist for the specified service.');
- }
-
- // Check those Variables
- $variables = Models\ServiceVariables::where('option_id', $data['option'])->get();
- if ($variables) {
- foreach($variables as $variable) {
-
- // Is the variable required?
- if (!$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.');
- }
-
- $data['env_' . $variable->env_variable] = $variable->default_value;
- continue;
- }
-
- // Check aganist Regex Pattern
- 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 . ').');
- }
-
- continue;
-
- }
- }
-
- return self::generateSFTPUsername($data['name']);
-
- }
-
}
diff --git a/app/Models/User.php b/app/Models/User.php
index 2b9dc9f4e..df2aa8afe 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -2,6 +2,7 @@
namespace Pterodactyl\Models;
+use Hash;
use Google2FA;
use Pterodactyl\Exceptions\AccountNotFoundException;
use Pterodactyl\Exceptions\DisplayException;
@@ -47,51 +48,21 @@ class User extends Model implements AuthenticatableContract,
return $this->hasMany(Permission::class);
}
- /**
- * Sets the TOTP secret for an account.
- *
- * @param int $id Account ID for which we want to generate a TOTP secret
- * @return string
- */
- public static function setTotpSecret($id)
- {
-
- $totpSecretKey = Google2FA::generateSecretKey();
-
- $user = User::find($id);
-
- if (!$user) {
- throw new AccountNotFoundException('An account with that ID (' . $id . ') does not exist in the system.');
- }
-
- $user->totp_secret = $totpSecretKey;
- $user->save();
-
- return $totpSecretKey;
-
- }
-
/**
* Enables or disables TOTP on an account if the token is valid.
*
- * @param int $id Account ID for which we want to generate a TOTP secret
+ * @param int $token The token that we want to verify.
* @return boolean
*/
- public static function toggleTotp($id, $token)
+ public function toggleTotp($token)
{
- $user = User::find($id);
-
- if (!$user) {
- throw new AccountNotFoundException('An account with that ID (' . $id . ') does not exist in the system.');
- }
-
- if (!Google2FA::verifyKey($user->totp_secret, $token)) {
+ if (!Google2FA::verifyKey($this->totp_secret, $token)) {
return false;
}
- $user->use_totp = ($user->use_totp === 1) ? 0 : 1;
- $user->save();
+ $this->use_totp = !$this->use_totp;
+ $this->save();
return true;
@@ -104,51 +75,19 @@ class User extends Model implements AuthenticatableContract,
* - at least one lowercase character
* - at least one number
*
- * @param int $id The ID of the account to update the password on.
* @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,})'.
* @return void
*/
- public static function setPassword($id, $password, $regex = '((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})')
+ public function setPassword($password, $regex = '((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})')
{
- $user = User::find($id);
- if (!$user) {
- throw new AccountNotFoundException('An account with that ID (' . $id . ') does not exist in the system.');
- }
-
if (!preg_match($regex, $password)) {
throw new DisplayException('The password passed did not meet the minimum password requirements.');
}
- $user->password = password_hash($password, PASSWORD_BCRYPT);
- $user->save();
-
- return;
-
- }
-
- /**
- * Updates the email address for an account.
- *
- * @param int $id
- * @param string $email
- * @return void
- */
- public static function setEmail($id, $email)
- {
-
- $user = User::find($id);
- if (!$user) {
- throw new AccountNotFoundException('An account with that ID (' . $id . ') does not exist in the system.');
- }
-
- if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
- throw new DisplayException('The email provided (' . $email . ') was not valid.');
- }
-
- $user->email = $email;
- $user->save();
+ $this->password = Hash::make($password);
+ $this->save();
return;
diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php
new file mode 100644
index 000000000..d0a00f793
--- /dev/null
+++ b/app/Repositories/ServerRepository.php
@@ -0,0 +1,122 @@
+ 6) {
+ return strtolower('ptdl-' . substr($name, 0, 6) . '_' . str_random(5));
+ }
+
+ return strtolower('ptdl-' . $name . '_' . str_random((11 - strlen($name))));
+
+ }
+
+ /**
+ * 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.
+ */
+ public function create(array $data)
+ {
+
+ // Validate Fields
+ $validator = Validator::make($data, [
+ 'owner' => 'required|email|exists:users,email',
+ 'node' => 'required|numeric|min:1|exists:nodes,id',
+ 'name' => 'required|regex:([\w -]{4,35})',
+ 'memory' => 'required|numeric|min:1',
+ 'disk' => 'required|numeric|min:1',
+ 'cpu' => 'required|numeric|min:0',
+ 'io' => 'required|numeric|min:10|max:1000',
+ 'ip' => 'required|ip',
+ 'port' => 'required|numeric|min:1|max:65535',
+ 'service' => 'required|numeric|min:1|exists:services,id',
+ 'option' => 'required|numeric|min:1|exists:service_options,id',
+ 'custom_image_name' => 'required_if:use_custom_image,on',
+ ]);
+
+ // Run validator, throw catchable and displayable exception if it fails.
+ // Exception includes a JSON result of failed validation rules.
+ if ($validator->fails()) {
+ throw new DisplayValidationException(json_encode($validator->errors()->all()));
+ }
+
+ // Get the User ID; user exists since we passed the 'exists:users,email' part of the validation
+ $user = Models\User::select('id')->where('email', $data['owner'])->first();
+
+ // 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
+ $node = Models\Node::find($data['node']);
+ $allocation = Models\Allocation::where('ip', $data['ip'])->where('port', $data['port'])->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) {
+ throw new DisplayException('The selected IP/Port combination (' . $data['ip'] . ':' . $data['port'] . ') is either already in use, or unavaliable for this node.');
+ }
+
+ // Validate those Service Option Variables
+ // We know the service and option exists because of the validation.
+ // 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) {
+ throw new DisplayException('The requested service option does not exist for the specified service.');
+ }
+
+ // Check those Variables
+ $variables = Models\ServiceVariables::where('option_id', $data['option'])->get();
+ if ($variables) {
+ foreach($variables as $variable) {
+
+ // Is the variable required?
+ if (!$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.');
+ }
+
+ $data['env_' . $variable->env_variable] = $variable->default_value;
+ continue;
+ }
+
+ // Check aganist Regex Pattern
+ 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 . ').');
+ }
+
+ continue;
+
+ }
+ }
+
+ return (new UuidService)->generateShort();
+ //return $this->generateSFTPUsername($data['name']);
+
+ }
+
+}
diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php
new file mode 100644
index 000000000..bd3d48ce9
--- /dev/null
+++ b/app/Repositories/UserRepository.php
@@ -0,0 +1,44 @@
+uuid = $uuid->table('users')->generate();
+
+ $user->username = $username;
+ $user->email = $email;
+ $user->password = Hash::make($password);
+
+ $user->save();
+
+ return $user->id;
+
+ }
+
+}
diff --git a/app/Services/UuidService.php b/app/Services/UuidService.php
new file mode 100644
index 000000000..e9ecf7f76
--- /dev/null
+++ b/app/Services/UuidService.php
@@ -0,0 +1,101 @@
+table = $table;
+ return $this;
+ }
+
+ /**
+ * Set the field in the given table that we want to check for a unique UUID.
+ *
+ * @param string $field
+ * @return void
+ */
+ public function field($field)
+ {
+ $this->field = $field;
+ return $this;
+ }
+
+ /**
+ * Generate a unique UUID validating against specified table and column.
+ * Defaults to `users.uuid`
+ *
+ * @param integer $type The type of UUID to generate.
+ * @return string
+ */
+ public function generate($type = 4)
+ {
+
+ $return = false;
+ do {
+
+ $uuid = LaravelUUID::generate($type);
+ if (!DB::table($this->table)->where($this->field, $uuid)->exists()) {
+ $return = $uuid;
+ }
+
+ } while (!$return);
+
+ return $return;
+
+ }
+
+ /**
+ * Generates a ShortUUID code which is 8 characters long and is used for identifying servers in the system.
+ *
+ * @param string $table
+ * @param string $field
+ * @return string
+ */
+ public function generateShort($table = 'servers', $field = 'uuidShort')
+ {
+
+ $return = false;
+ do {
+
+ $short = substr(Uuid::generate(4), 0, 8);
+ if (!DB::table($table)->where($field, $short)->exists()) {
+ $return = $short;
+ }
+
+ } while (!$return);
+
+ return $return;
+
+ }
+
+}