Merge branch 'develop' into v2

This commit is contained in:
Matthew Penner 2021-10-23 13:26:25 -06:00
commit b966069946
No known key found for this signature in database
GPG key ID: BAB67850901908A8
12 changed files with 164 additions and 78 deletions

View file

@ -30,7 +30,7 @@ else
fi
echo "Checking if https is required."
if [ -f /etc/nginx/conf.d/default.conf ]; then
if [ -f /etc/nginx/http.d/panel.conf ]; then
echo "Using nginx config already in place."
if [ $LE_EMAIL ]; then
echo "Checking for cert update"
@ -42,15 +42,17 @@ else
echo "Checking if letsencrypt email is set."
if [ -z $LE_EMAIL ]; then
echo "No letsencrypt email is set using http config."
cp .github/docker/default.conf /etc/nginx/conf.d/default.conf
cp .github/docker/default.conf /etc/nginx/http.d/panel.conf
else
echo "writing ssl config"
cp .github/docker/default_ssl.conf /etc/nginx/conf.d/default.conf
cp .github/docker/default_ssl.conf /etc/nginx/http.d/panel.conf
echo "updating ssl config for domain"
sed -i "s|<domain>|$(echo $APP_URL | sed 's~http[s]*://~~g')|g" /etc/nginx/conf.d/default.conf
sed -i "s|<domain>|$(echo $APP_URL | sed 's~http[s]*://~~g')|g" /etc/nginx/http.d/panel.conf
echo "generating certs"
certbot certonly -d $(echo $APP_URL | sed 's~http[s]*://~~g') --standalone -m $LE_EMAIL --agree-tos -n
fi
echo "Removing the default nginx config"
rm -rf /etc/nginx/http.d/default.conf
fi
## check for DB up before starting the panel

View file

@ -32,7 +32,7 @@ I would like to extend my sincere thanks to the following sponsors for helping f
| [**Spill Hosting**](https://spillhosting.no/) | Spill Hosting is a Norwegian hosting service, which aims for inexpensive services on quality servers. Premium i9-9900K processors will run your game like a dream. |
| [**DeinServerHost**](https://deinserverhost.de/) | DeinServerHost offers Dedicated, vps and Gameservers for many popular Games like Minecraft and Rust in Germany since 2013. |
| [**HostBend**](https://hostbend.com/) | HostBend offers a variety of solutions for developers, students, and others who have a tight budget but don't want to compromise quality and support. |
| [**Capitol Hosting Solutions**](https://capitolsolutions.cloud/) | CHS is *the* budget friendly hosting company for Australian and American gamers, offering a variety of plans from Web Hosting to Game Servers; Custom Solutions too! |
| [**Capitol Hosting Solutions**](https://chs.gg/) | CHS is *the* budget friendly hosting company for Australian and American gamers, offering a variety of plans from Web Hosting to Game Servers; Custom Solutions too! |
| [**ByteAnia**](https://byteania.com/?utm_source=pterodactyl) | ByteAnia offers the best performing and most affordable **Ryzen 5000 Series hosting** on the market for *unbeatable prices*! |
| [**Aussie Server Hosts**](https://aussieserverhosts.com/) | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand. |
| [**VibeGAMES**](https://vibegames.net/) | VibeGAMES is a game server provider that specializes in DDOS protection for the games we offer. We have multiple locations in the US, Brazil, France, Germany, Singapore, Australia and South Africa.|

View file

@ -5,14 +5,9 @@ The following versions of Pterodactyl are receiving active support and maintenan
| Panel | Daemon | Supported |
| ----- | ------------ | ------------------ |
| 1.4.x | wings@1.4.x | :white_check_mark: |
| 1.3.x | wings@1.3.x | :x: |
| 1.2.x | wings@1.2.x | :x: |
| 1.1.x | wings@1.1.x | :x: |
| 1.0.x | wings@1.0.x | :x: |
| 1.6.x | wings@1.5.x | :white_check_mark: |
| 0.7.x | daemon@0.6.x | :x: |
| 0.6.x | daemon@0.5.x | :x: |
| 0.5.x | daemon@0.4.x | :x: |
## Reporting a Vulnerability

View file

@ -57,7 +57,7 @@ class UpgradeCommand extends Command
$userDetails = posix_getpwuid(fileowner('public'));
$user = $userDetails['name'] ?? 'www-data';
if (!$this->confirm("Your webserver user has been detected as [{$user}]: is this correct?", true)) {
if (!$this->confirm("Your webserver user has been detected as <fg=blue>[{$user}]:</> is this correct?", true)) {
$user = $this->anticipate(
'Please enter the name of the user running your webserver process. This varies from system to system, but is generally "www-data", "nginx", or "apache".',
[
@ -73,7 +73,7 @@ class UpgradeCommand extends Command
$groupDetails = posix_getgrgid(filegroup('public'));
$group = $groupDetails['name'] ?? 'www-data';
if (!$this->confirm("Your webserver group has been detected as [{$group}]: is this correct?", true)) {
if (!$this->confirm("Your webserver group has been detected as <fg=blue>[{$group}]:</> is this correct?", true)) {
$group = $this->anticipate(
'Please enter the name of the group running your webserver process. Normally this is the same as your user.',
[
@ -86,6 +86,7 @@ class UpgradeCommand extends Command
}
if (!$this->confirm('Are you sure you want to run the upgrade process for your Panel?')) {
$this->warn('Upgrade process terminated by user.');
return;
}
}
@ -173,8 +174,8 @@ class UpgradeCommand extends Command
$this->call('up');
});
$this->newLine();
$this->info('Finished running upgrade.');
$this->newLine(2);
$this->info('Panel has been successfully upgraded. Please ensure you also update any Wings instances: https://pterodactyl.io/wings/1.0/upgrading.html');
}
protected function withProgress(ProgressBar $bar, Closure $callback)

View file

@ -109,5 +109,7 @@ class Kernel extends HttpKernel
'bindings' => SubstituteBindings::class,
'recaptcha' => VerifyReCaptcha::class,
'node.maintenance' => MaintenanceMiddleware::class,
// API Specific Middleware
'api..key' => AuthenticateKey::class,
];
}

View file

@ -2,6 +2,7 @@
namespace Pterodactyl\Providers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
@ -19,44 +20,87 @@ class RouteServiceProvider extends ServiceProvider
protected $namespace = 'Pterodactyl\Http\Controllers';
/**
* Define the routes for the application.
* Define your route model bindings, pattern filters, etc.
*/
public function map()
public function boot()
{
Route::middleware(['web', 'auth', 'csrf'])
->namespace($this->namespace . '\Base')
->group(base_path('routes/base.php'));
$this->configureRateLimiting();
Route::middleware(['web', 'auth', 'admin', 'csrf'])->prefix('/admin')
->namespace($this->namespace . '\Admin')
->group(base_path('routes/admin.php'));
$this->routes(function () {
Route::middleware(['web', 'auth', 'csrf'])
->namespace("$this->namespace\\Base")
->group(base_path('routes/base.php'));
Route::middleware(['web', 'csrf'])->prefix('/auth')
->namespace($this->namespace . '\Auth')
->group(base_path('routes/auth.php'));
Route::middleware(['web', 'auth', 'admin', 'csrf'])->prefix('/admin')
->namespace("$this->namespace\\Admin")
->group(base_path('routes/admin.php'));
Route::middleware(['web', 'csrf', 'auth', 'server', 'node.maintenance'])
->prefix('/api/server/{server}')
->namespace($this->namespace . '\Server')
->group(base_path('routes/server.php'));
Route::middleware(['web', 'csrf'])->prefix('/auth')
->namespace("$this->namespace\\Auth")
->group(base_path('routes/auth.php'));
Route::middleware([
sprintf('throttle:%s,%s', config('http.rate_limit.application'), config('http.rate_limit.application_period')),
'api',
])->prefix('/api/application')
->namespace($this->namespace . '\Api\Application')
->group(base_path('routes/api-application.php'));
Route::middleware(['web', 'csrf', 'auth', 'server', 'node.maintenance'])
->prefix('/api/server/{server}')
->namespace("$this->namespace\\Server")
->group(base_path('routes/server.php'));
Route::middleware([
//sprintf('throttle:%s,%s', config('http.rate_limit.client'), config('http.rate_limit.client_period')),
'client-api',
])->prefix('/api/client')
->namespace($this->namespace . '\Api\Client')
->group(base_path('routes/api-client.php'));
Route::middleware(['api', 'throttle:api.application'])
->prefix('/api/application')
->namespace("$this->namespace\\Api\\Application")
->group(base_path('routes/api-application.php'));
Route::middleware(['daemon'])->prefix('/api/remote')
->namespace($this->namespace . '\Api\Remote')
->group(base_path('routes/api-remote.php'));
Route::middleware(['client-api', 'throttle:api.client'])
->prefix('/api/client')
->namespace("$this->namespace\\Api\\Client")
->group(base_path('routes/api-client.php'));
Route::middleware(['daemon'])->prefix('/api/remote')
->namespace("$this->namespace\\Api\\Remote")
->group(base_path('routes/api-remote.php'));
});
}
/**
* Configure the rate limiters for the application.
*/
protected function configureRateLimiting()
{
// Authentication rate limiting. For login and checkpoint endpoints we'll apply
// a limit of 10 requests per minute, for the forgot password endpoint apply a
// limit of two per minute for the requester so that there is less ability to
// trigger email spam.
RateLimiter::for('authentication', function (Request $request) {
if ($request->route()->named('auth.post.forgot-password')) {
return Limit::perMinute(2)->by($request->ip());
}
return Limit::perMinute(10);
});
// Configure the throttles for both the application and client APIs below.
// This is configurable per-instance in "config/http.php". By default this
// limiter will be tied to the specific request user, and falls back to the
// request IP if there is no request user present for the key.
//
// This means that an authenticated API user cannot use IP switching to get
// around the limits.
RateLimiter::for('api.client', function (Request $request) {
$key = optional($request->user())->uuid ?: $request->ip();
return Limit::perMinutes(
config('http.rate_limit.client_period'),
config('http.rate_limit.client')
)->by($key);
});
RateLimiter::for('api.application', function (Request $request) {
$key = optional($request->user())->uuid ?: $request->ip();
return Limit::perMinutes(
config('http.rate_limit.application_period'),
config('http.rate_limit.application')
)->by($key);
});
RateLimiter::for('pull', function () {
return Limit::perMinute(10);

View file

@ -58,15 +58,20 @@ class SuspensionService
throw new ConflictHttpException('Cannot toggle suspension status on a server that is currently being transferred.');
}
$this->connection->transaction(function () use ($action, $server, $isSuspending) {
$server->update([
'status' => $isSuspending ? Server::STATUS_SUSPENDED : null,
]);
// Update the server's suspension status.
$server->update([
'status' => $isSuspending ? Server::STATUS_SUSPENDED : null,
]);
// Only trigger a Wings server sync if it is not currently being transferred.
if (is_null($server->transfer)) {
$this->daemonServerRepository->setServer($server)->sync();
}
});
try {
// Tell wings to re-sync the server state.
$this->daemonServerRepository->setServer($server)->sync();
} catch (\Exception $exception) {
// Rollback the server's suspension status if wings fails to sync the server.
$server->update([
'status' => $isSuspending ? null : Server::STATUS_SUSPENDED,
]);
throw $exception;
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,7 @@
"version": "PTDL_v1",
"update_url": null
},
"exported_at": "2021-05-29T19:02:43-04:00",
"exported_at": "2021-09-15T17:07:50-04:00",
"name": "Rust",
"author": "support@pterodactyl.io",
"description": "The only aim in Rust is to survive. To do this you will need to overcome struggles such as hunger, thirst and cold. Build a fire. Build a shelter. Kill animals for meat. Protect yourself from other players, and kill them for meat. Create alliances with other players and form a town. Do whatever it takes to survive.",
@ -13,11 +13,11 @@
"quay.io\/pterodactyl\/core:rust"
],
"file_denylist": [],
"startup": ".\/RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.identity \"rust\" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \\\"{{HOSTNAME}}\\\" +server.level \\\"{{LEVEL}}\\\" +server.description \\\"{{DESCRIPTION}}\\\" +server.url \\\"{{SERVER_URL}}\\\" +server.headerimage \\\"{{SERVER_IMG}}\\\" +server.logoimage \\\"{{SERVER_LOGO}}\\\" +server.worldsize \\\"{{WORLD_SIZE}}\\\" +server.seed \\\"{{WORLD_SEED}}\\\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \\\"{{RCON_PASS}}\\\" +server.saveinterval {{SAVEINTERVAL}} +app.port {{APP_PORT}} {{ADDITIONAL_ARGS}}",
"startup": ".\/RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.identity \"rust\" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \\\"{{HOSTNAME}}\\\" +server.level \\\"{{LEVEL}}\\\" +server.description \\\"{{DESCRIPTION}}\\\" +server.url \\\"{{SERVER_URL}}\\\" +server.headerimage \\\"{{SERVER_IMG}}\\\" +server.logoimage \\\"{{SERVER_LOGO}}\\\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \\\"{{RCON_PASS}}\\\" +server.saveinterval {{SAVEINTERVAL}} +app.port {{APP_PORT}} $( [ -z ${MAP_URL} ] && printf %s \"+server.worldsize \\\"{{WORLD_SIZE}}\\\" +server.seed \\\"{{WORLD_SEED}}\\\"\" || printf %s \"+server.levelurl {{MAP_URL}}\" ) {{ADDITIONAL_ARGS}}",
"config": {
"files": "{}",
"startup": "{\r\n \"done\": \"Server startup complete\",\r\n \"userInteraction\": []\r\n}",
"logs": "{\r\n \"custom\": false,\r\n \"location\": \"latest.log\"\r\n}",
"startup": "{\r\n \"done\": \"Server startup complete\"\r\n}",
"logs": "{}",
"stop": "quit"
},
"scripts": {
@ -162,6 +162,15 @@
"user_viewable": true,
"user_editable": true,
"rules": "nullable|url"
},
{
"name": "Custom Map URL",
"description": "Overwrites the map with the one from the direct download URL. Invalid URLs will cause the server to crash.",
"env_variable": "MAP_URL",
"default_value": "",
"user_viewable": true,
"user_editable": true,
"rules": "nullable|url"
}
]
}
}

View file

@ -7,14 +7,16 @@ import TitledGreyBox from '@/components/elements/TitledGreyBox';
import { ServerContext } from '@/state/server';
import CopyOnClick from '@/components/elements/CopyOnClick';
import { SocketEvent, SocketRequest } from '@/components/server/events';
import UptimeDuration from '@/components/server/UptimeDuration';
interface Stats {
memory: number;
cpu: number;
disk: number;
uptime: number;
}
function statusToColor (status: string|null, installing: boolean): TwStyle {
function statusToColor (status: string | null, installing: boolean): TwStyle {
if (installing) {
status = '';
}
@ -30,7 +32,7 @@ function statusToColor (status: string|null, installing: boolean): TwStyle {
}
const ServerDetailsBlock = () => {
const [ stats, setStats ] = useState<Stats>({ memory: 0, cpu: 0, disk: 0 });
const [ stats, setStats ] = useState<Stats>({ memory: 0, cpu: 0, disk: 0, uptime: 0 });
const status = ServerContext.useStoreState(state => state.status.value);
const connected = ServerContext.useStoreState(state => state.socket.connected);
@ -48,6 +50,7 @@ const ServerDetailsBlock = () => {
memory: stats.memory_bytes,
cpu: stats.cpu_absolute,
disk: stats.disk_bytes,
uptime: stats.uptime || 0,
});
};
@ -69,7 +72,7 @@ const ServerDetailsBlock = () => {
const isTransferring = ServerContext.useStoreState(state => state.server.data!.isTransferring);
const limits = ServerContext.useStoreState(state => state.server.data!.limits);
const primaryAllocation = ServerContext.useStoreState(state => state.server.data!.allocations.filter(alloc => alloc.isDefault).map(
allocation => (allocation.alias || allocation.ip) + ':' + allocation.port
allocation => (allocation.alias || allocation.ip) + ':' + allocation.port,
)).toString();
const diskLimit = limits.disk ? megabytesToHuman(limits.disk) : 'Unlimited';
@ -88,6 +91,11 @@ const ServerDetailsBlock = () => {
]}
/>
&nbsp;{!status ? 'Connecting...' : (isInstalling ? 'Installing' : (isTransferring) ? 'Transferring' : status)}
{stats.uptime > 0 &&
<span css={tw`ml-2`}>
(<UptimeDuration uptime={stats.uptime / 1000}/>)
</span>
}
</p>
<CopyOnClick text={primaryAllocation}>
<p css={tw`text-xs mt-2`}>

View file

@ -0,0 +1,14 @@
import React from 'react';
export default ({ uptime }: { uptime: number }) => {
const hours = Math.floor(Math.floor(uptime) / 60 / 60);
const remainder = Math.floor(uptime - (hours * 60 * 60));
const minutes = Math.floor(remainder / 60);
const seconds = remainder % 60;
return (
<>
{hours.toString().padStart(2, '0')}:{minutes.toString().padStart(2, '0')}:{seconds.toString().padStart(2, '0')}
</>
);
};

View file

@ -1,7 +1,5 @@
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Authentication Routes
@ -17,14 +15,22 @@ Route::group(['middleware' => 'guest'], function () {
Route::get('/password', 'LoginController@index')->name('auth.forgot-password');
Route::get('/password/reset/{token}', 'LoginController@index')->name('auth.reset');
// Login endpoints.
Route::post('/login', 'LoginController@login')->middleware('recaptcha');
Route::post('/login/checkpoint', 'LoginCheckpointController')->name('auth.checkpoint');
Route::post('/login/checkpoint/key', 'WebauthnController@auth')->name('auth.checkpoint.key');
// Apply a throttle to authentication action endpoints, in addition to the
// recaptcha endpoints to slow down manual attack spammers even more. 🤷‍
//
// @see \Pterodactyl\Providers\RouteServiceProvider
Route::middleware(['throttle:authentication'])->group(function () {
// Login endpoints.
Route::post('/login', 'LoginController@login')->middleware('recaptcha');
Route::post('/login/checkpoint', 'LoginCheckpointController')->name('auth.login-checkpoint');
Route::post('/login/checkpoint/key', 'WebauthnController@auth')->name('auth.login-checkpoint-key');
// Forgot password route. A post to this endpoint will trigger an
// email to be sent containing a reset token.
Route::post('/password', 'ForgotPasswordController@sendResetLinkEmail')->middleware('recaptcha');
// Forgot password route. A post to this endpoint will trigger an
// email to be sent containing a reset token.
Route::post('/password', 'ForgotPasswordController@sendResetLinkEmail')
->name('auth.post.forgot-password')
->middleware('recaptcha');
});
// Password reset routes. This endpoint is hit after going through
// the forgot password routes to acquire a token (or after an account