/** * Adds a new database to a given database server. * @param int $server Id of the server to add a database for. * @param array $options Array of options for creating that database. * @return void */ public function create($server, $options) { $server = Models\Server::findOrFail($server); $validator = Validator::make($options, ['db_server' => 'required|exists:database_servers,id', 'database' => 'required|regex:/^\\w{1,100}$/', 'remote' => 'required|regex:/^[0-9%.]{1,15}$/']); if ($validator->fails()) { throw new DisplayValidationException($validator->errors()); } DB::beginTransaction(); try { $db = new Models\Database(); $db->fill(['server_id' => $server->id, 'db_server' => $options['db_server'], 'database' => $server->uuidShort . '_' . $options['database'], 'username' => $server->uuidShort . '_' . str_random(7), 'remote' => $options['remote'], 'password' => Crypt::encrypt(str_random(20))]); $db->save(); // Contact Remote $dbr = Models\DatabaseServer::findOrFail($options['db_server']); $capsule = new Capsule(); $capsule->addConnection(['driver' => 'mysql', 'host' => $dbr->host, 'port' => $dbr->port, 'database' => 'mysql', 'username' => $dbr->username, 'password' => Crypt::decrypt($dbr->password), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', '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; } }
/** * 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); }
/** * Create a new scheduled task for a given server. * @param int $id * @param array $data * * @throws DisplayException * @throws DisplayValidationException * @return void */ public function create($id, $data) { $server = Models\Server::findOrFail($id); $validator = Validator::make($data, ['action' => 'string|required', 'data' => 'string|required', 'year' => 'string|sometimes', 'day_of_week' => 'string|sometimes', 'month' => 'string|sometimes', 'day_of_month' => 'string|sometimes', 'hour' => 'string|sometimes', 'minute' => 'string|sometimes']); if ($validator->fails()) { throw new DisplayValidationException(json_encode($validator->errors())); } 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] !== '') { $cron[$setting] = $data[$setting]; } } // Check that is this a valid Cron Entry try { $buildCron = Cron::factory(sprintf('%s %s %s %s %s %s', $cron['minute'], $cron['hour'], $cron['day_of_month'], $cron['month'], $cron['day_of_week'], $cron['year'])); } catch (\Exception $ex) { throw $ex; } $task = new Models\Task(); $task->fill(['server' => $server->id, 'active' => 1, 'action' => $data['action'], 'data' => $data['data'], 'queued' => 0, 'year' => $cron['year'], 'day_of_week' => $cron['day_of_week'], 'month' => $cron['month'], 'day_of_month' => $cron['day_of_month'], 'hour' => $cron['hour'], 'minute' => $cron['minute'], 'last_run' => null, 'next_run' => $buildCron->getNextRunDate()]); return $task->save(); }
/** * Returns an array of each server ID that the user has access to. * * @return array */ 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; }
/** * Execute the console command. * * @return mixed */ public function handle() { $tasks = Models\Task::where('queued', 0)->where('active', 1)->where('next_run', '<=', Carbon::now()->toAtomString())->get(); $this->info(sprintf('Preparing to queue %d tasks.', count($tasks))); $bar = $this->output->createProgressBar(count($tasks)); foreach ($tasks as &$task) { $bar->advance(); $this->dispatch(new SendScheduledTask(Models\Server::findOrFail($task->server), $task)); } $bar->finish(); $this->info("\nFinished queuing tasks for running."); }
/** * Run the migrations. * * @return void */ public function up() { Schema::table('servers', function (Blueprint $table) { $table->string('image')->after('daemonSecret'); }); // Populate the column $servers = Server::select('servers.id', 'service_options.docker_image as s_optionImage')->join('service_options', 'service_options.id', '=', 'servers.option')->get(); foreach ($servers as $server) { $server->image = $server->s_optionImage; $server->save(); } }
public function postInstall(Request $request) { $server = Models\Server::where('uuid', $request->input('server'))->first(); if (!$server) { return response()->json(['error' => 'No server by that ID was found on the system.'], 422); } $node = Models\Node::findOrFail($server->node); $hmac = $request->input('signed'); $status = $request->input('installed'); if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { return response()->json(['error' => 'Signed HMAC was invalid.'], 403); } $server->installed = $status === 'installed' ? 1 : 2; $server->save(); return response()->json(['message' => 'Recieved!'], 200); }
/** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if (!Auth::user()) { return redirect()->guest('auth/login'); } $server = Server::getByUUID($request->route()->server); if (!$server) { return response()->view('errors.404', [], 404); } if ($server->suspended === 1) { return response()->view('errors.suspended', [], 403); } if ($server->installed !== 1) { return response()->view('errors.installing', [], 403); } return $next($request); }
public function delete($id) { $option = Models\ServiceOptions::findOrFail($id); $servers = Models\Server::where('option', $option->id)->get(); if (count($servers) !== 0) { throw new DisplayException('You cannot delete an option that has servers attached to it currently.'); } DB::beginTransaction(); try { Models\ServiceVariables::where('option_id', $option->id)->delete(); $option->delete(); DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } }
public function delete($id) { $service = Models\Service::findOrFail($id); $servers = Models\Server::where('service', $service->id)->get(); $options = Models\ServiceOptions::select('id')->where('parent_service', $service->id); if (count($servers) !== 0) { throw new DisplayException('You cannot delete a service that has servers associated with it.'); } DB::beginTransaction(); try { Models\ServiceVariables::whereIn('option_id', $options->get()->toArray())->delete(); $options->delete(); $service->delete(); DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } }
public function getView(Request $request, $id) { return view('admin.users.view', ['user' => User::findOrFail($id), 'servers' => Server::select('servers.*', 'nodes.name as nodeName', 'locations.long as location')->join('nodes', 'servers.node', '=', 'nodes.id')->join('locations', 'nodes.location', '=', 'locations.id')->where('owner', $id)->get()]); }
public function toggleTask(Request $request, $uuid, $id) { $server = Models\Server::getByUUID($uuid); $this->authorize('toggle-task', $server); $task = Models\Task::findOrFail($id); if (!$task || $server->id !== $task->server) { return response()->json(['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]); } catch (\Exception $ex) { Log::error($ex); return response()->json(['error' => 'A server error occured while attempting to toggle this task.'], 503); } }
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, 'variables' => Models\ServiceVariables::where('option_id', $option)->get(), 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail')->join('users', 'users.id', '=', 'servers.owner')->where('option', $option)->paginate(10)]); }
public function deleteSubuser(Request $request, $uuid, $id) { $server = Models\Server::getByUUID($uuid); $this->authorize('delete-subuser', $server); try { $subuser = Models\Subuser::select('id')->where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); 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()], 422); } catch (\Exception $ex) { Log::error($ex); response()->json(['error' => 'An unknown error occured while attempting to delete this subuser.'], 503); } }
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']); } $node->delete(); Alert::success('Node successfully deleted.')->flash(); return redirect()->route('admin.nodes'); }
public function postSettingsStartup(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); $this->authorize('edit-startup', $server); try { $repo = new ServerRepository(); $repo->updateStartup($server->id, $request->except(['_token'])); Alert::success('Server startup variables were successfully updated.')->flash(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } 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']); }
public function __construct($server) { $this->server = $server instanceof Models\Server ? $server : Models\Server::findOrFail($server); $this->node = Models\Node::getByID($this->server->node); $this->client = Models\Node::guzzleRequest($this->server->node); }
public function postResetDatabasePassword(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); $database = Models\Database::where('id', $request->input('database'))->where('server_id', $server->id)->firstOrFail(); $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) { Log::error($ex); return response()->json(['error' => 'An unhandled error occured while attempting to modify this database\'s password.'], 503); } }
public function updateSFTPPassword($id, $password) { $server = Models\Server::findOrFail($id); $node = Models\Node::findOrFail($server->node); $validator = Validator::make(['password' => $password], ['password' => 'required|regex:/^((?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,})$/']); if ($validator->fails()) { throw new DisplayValidationException(json_encode($validator->errors())); } DB::beginTransaction(); $server->sftp_password = Crypt::encrypt($password); try { $server->save(); $client = Models\Node::guzzleRequest($server->node); $client->request('POST', '/server/password', ['headers' => ['X-Access-Token' => $node->daemonSecret, 'X-Access-Server' => $server->uuid], 'json' => ['password' => $password]]); DB::commit(); return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); throw new DisplayException('There was an error while attmping to contact the remote service to change the password.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } }
/** * 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' => Models\Server::getUserServers(10)]); }
/** * Update Server Build Configuration * * Updates server build information on panel and on node. * * @Patch("/servers/{id}/build") * @Versions({"v1"}) * @Transaction({ * @Request({ * "default": "192.168.0.1:25565", * "add_additional": [ * "192.168.0.1:25566", * "192.168.0.1:25567", * "192.168.0.1:25568" * ], * "remove_additional": [], * "memory": 1024, * "swap": 0, * "io": 500, * "cpu": 0, * "disk": 1024 * }, headers={"Authorization": "Bearer <token>"}), * @Response(200, body={"name": "New Name"}), * @Response(422) * }) * @Parameters({ * @Parameter("id", type="integer", required=true, description="The ID of the server to modify.") * }) */ 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)); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); } catch (\Exception $ex) { throw new ServiceUnavailableHttpException('Unable to update server on system due to an error.'); } }
public function postUpdateServerToggleBuild(Request $request, $id) { $server = Models\Server::findOrFail($id); $node = Models\Node::findOrFail($server->node); $client = Models\Node::guzzleRequest($server->node); try { $res = $client->request('POST', '/server/rebuild', ['headers' => ['X-Access-Server' => $server->uuid, '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) { Log::warning($ex); Alert::danger('An error occured while attempting to toggle a rebuild.')->flash(); } return redirect()->route('admin.servers.view', ['id' => $id, 'tab' => 'tab_manage']); }
/** * Deletes a user on the panel, returns the number of records deleted. * * @param integer $id * @return integer */ public function delete($id) { if (Models\Server::where('owner', $id)->count() > 0) { throw new DisplayException('Cannot delete a user with active servers attached to thier account.'); } DB::beginTransaction(); try { Models\Permission::where('user_id', $id)->delete(); Models\Subuser::where('user_id', $id)->delete(); Models\User::destroy($id); DB::commit(); return true; } catch (\Exception $ex) { DB::rollBack(); throw $ex; } }
/** * Updates permissions for a given subuser. * @param integer $id The ID of the subuser row in MySQL. (Not the user ID) * @param array $data * @throws DisplayValidationException * @throws DisplayException * @return void */ public function update($id, array $data) { $validator = Validator::make($data, ['permissions' => 'required|array', 'user' => 'required|exists:users,id', 'server' => 'required|exists:servers,id']); if ($validator->fails()) { throw new DisplayValidationException(json_encode($validator->all())); } $subuser = Models\Subuser::findOrFail($id); $server = Models\Server::findOrFail($data['server']); DB::beginTransaction(); try { Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); $daemonPermissions = $this->coreDaemonPermissions; 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])) { array_push($daemonPermissions, $this->permissions[$permission]); } $model = new Models\Permission(); $model->fill(['user_id' => $data['user'], 'server_id' => $data['server'], 'permission' => $permission]); $model->save(); } } // Contact Daemon // We contact even if they don't have any daemon permissions to overwrite // if they did have them previously. $node = Models\Node::getByID($server->node); $client = Models\Node::guzzleRequest($server->node); $res = $client->request('PATCH', '/server', ['headers' => ['X-Access-Server' => $server->uuid, 'X-Access-Token' => $node->daemonSecret], 'json' => ['keys' => [$subuser->daemonSecret => $daemonPermissions]]]); DB::commit(); return true; } catch (\GuzzleHttp\Exception\TransferException $ex) { DB::rollBack(); throw new DisplayException('There was an error attempting to connect to the daemon to update permissions.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } return false; }