forked from Alex/Pterodactyl-Panel
Merge branch 'develop' into workflows/releases
This commit is contained in:
commit
cf2d17014a
@ -8,6 +8,7 @@ APP_DELETE_MINUTES=10
|
|||||||
APP_ENVIRONMENT_ONLY=true
|
APP_ENVIRONMENT_ONLY=true
|
||||||
LOG_CHANNEL=daily
|
LOG_CHANNEL=daily
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
|
APP_URL=http://panel.example.com
|
||||||
|
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
@ -30,7 +31,7 @@ MAILGUN_ENDPOINT=api.mailgun.net
|
|||||||
# mail servers such as Gmail to reject your mail.
|
# mail servers such as Gmail to reject your mail.
|
||||||
#
|
#
|
||||||
# @see: https://github.com/pterodactyl/panel/pull/3110
|
# @see: https://github.com/pterodactyl/panel/pull/3110
|
||||||
# SERVER_NAME=panel.yourdomain.com
|
# SERVER_NAME=panel.example.com
|
||||||
|
|
||||||
QUEUE_HIGH=high
|
QUEUE_HIGH=high
|
||||||
QUEUE_STANDARD=standard
|
QUEUE_STANDARD=standard
|
||||||
|
2
.github/docker/entrypoint.sh
vendored
2
.github/docker/entrypoint.sh
vendored
@ -57,7 +57,7 @@ fi
|
|||||||
|
|
||||||
## check for DB up before starting the panel
|
## check for DB up before starting the panel
|
||||||
echo "Checking database status."
|
echo "Checking database status."
|
||||||
until nc -z -v -w30 $DB_HOST 3306
|
until nc -z -v -w30 $DB_HOST $DB_PORT
|
||||||
do
|
do
|
||||||
echo "Waiting for database connection..."
|
echo "Waiting for database connection..."
|
||||||
# wait for 1 seconds before check again
|
# wait for 1 seconds before check again
|
||||||
|
@ -3,6 +3,13 @@ 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.
|
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||||
|
|
||||||
|
## v1.6.6
|
||||||
|
### Fixed
|
||||||
|
* **[security]** Fixes a CSRF vulnerability for both the administrative test email endpoint and node auto-deployment token generation endpoint. [GHSA-wwgq-9jhf-qgw6](https://github.com/pterodactyl/panel/security/advisories/GHSA-wwgq-9jhf-qgw6)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Updates Minecraft eggs to include latest Java 17 yolk by default.
|
||||||
|
|
||||||
## v1.6.5
|
## v1.6.5
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fixes broken application API endpoints due to changes introduced with session management in 1.6.4.
|
* Fixes broken application API endpoints due to changes introduced with session management in 1.6.4.
|
||||||
|
@ -75,6 +75,7 @@ class Kernel extends HttpKernel
|
|||||||
ApiSubstituteBindings::class,
|
ApiSubstituteBindings::class,
|
||||||
'api..key:' . ApiKey::TYPE_APPLICATION,
|
'api..key:' . ApiKey::TYPE_APPLICATION,
|
||||||
AuthenticateApplicationUser::class,
|
AuthenticateApplicationUser::class,
|
||||||
|
VerifyCsrfToken::class,
|
||||||
AuthenticateIPAccess::class,
|
AuthenticateIPAccess::class,
|
||||||
],
|
],
|
||||||
'client-api' => [
|
'client-api' => [
|
||||||
@ -85,6 +86,7 @@ class Kernel extends HttpKernel
|
|||||||
SubstituteClientApiBindings::class,
|
SubstituteClientApiBindings::class,
|
||||||
'api..key:' . ApiKey::TYPE_ACCOUNT,
|
'api..key:' . ApiKey::TYPE_ACCOUNT,
|
||||||
AuthenticateIPAccess::class,
|
AuthenticateIPAccess::class,
|
||||||
|
VerifyCsrfToken::class,
|
||||||
// This is perhaps a little backwards with the Client API, but logically you'd be unable
|
// This is perhaps a little backwards with the Client API, but logically you'd be unable
|
||||||
// to create/get an API key without first enabling 2FA on the account, so I suppose in the
|
// to create/get an API key without first enabling 2FA on the account, so I suppose in the
|
||||||
// end it makes sense.
|
// end it makes sense.
|
||||||
|
@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
|||||||
use Pterodactyl\Models\User;
|
use Pterodactyl\Models\User;
|
||||||
use Pterodactyl\Models\ApiKey;
|
use Pterodactyl\Models\ApiKey;
|
||||||
use Illuminate\Auth\AuthManager;
|
use Illuminate\Auth\AuthManager;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Contracts\Encryption\Encrypter;
|
use Illuminate\Contracts\Encryption\Encrypter;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||||
@ -55,7 +56,7 @@ class AuthenticateKey
|
|||||||
public function handle(Request $request, Closure $next, int $keyType)
|
public function handle(Request $request, Closure $next, int $keyType)
|
||||||
{
|
{
|
||||||
if (is_null($request->bearerToken()) && is_null($request->user())) {
|
if (is_null($request->bearerToken()) && is_null($request->user())) {
|
||||||
throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']);
|
throw new HttpException(401, 'A bearer token or valid user session cookie must be provided to access this endpoint.', null, ['WWW-Authenticate' => 'Bearer']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a request coming through using cookies, we have an authenticated user
|
// This is a request coming through using cookies, we have an authenticated user
|
||||||
|
@ -2,18 +2,45 @@
|
|||||||
|
|
||||||
namespace Pterodactyl\Http\Middleware;
|
namespace Pterodactyl\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Pterodactyl\Models\ApiKey;
|
||||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
|
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
|
||||||
|
|
||||||
class VerifyCsrfToken extends BaseVerifier
|
class VerifyCsrfToken extends BaseVerifier
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The URIs that should be excluded from CSRF verification.
|
* The URIs that should be excluded from CSRF verification. These are
|
||||||
|
* never hit by the front-end, and require specific token validation
|
||||||
|
* to work.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
protected $except = [
|
protected $except = ['remote/*', 'daemon/*'];
|
||||||
'remote/*',
|
|
||||||
'daemon/*',
|
/**
|
||||||
'api/*',
|
* Manually apply CSRF protection to routes depending on the authentication
|
||||||
];
|
* mechanism being used. If the API request is using an API key that exists
|
||||||
|
* in the database we can safely ignore CSRF protections, since that would be
|
||||||
|
* a manually initiated request by a user or server.
|
||||||
|
*
|
||||||
|
* All other requests should go through the standard CSRF protections that
|
||||||
|
* Laravel affords us. This code will be removed in v2 since we have switched
|
||||||
|
* to using Sanctum for the API endpoints, which handles that for us automatically.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Session\TokenMismatchException
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
$key = $request->attributes->get('api_key');
|
||||||
|
|
||||||
|
if ($key instanceof ApiKey && $key->exists) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::handle($request, $next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"version": "PTDL_v1",
|
"version": "PTDL_v1",
|
||||||
"update_url": null
|
"update_url": null
|
||||||
},
|
},
|
||||||
"exported_at": "2021-11-14T19:22:27+00:00",
|
"exported_at": "2021-12-02T16:19:36+00:00",
|
||||||
"name": "Forge Minecraft",
|
"name": "Forge Minecraft",
|
||||||
"author": "support@pterodactyl.io",
|
"author": "support@pterodactyl.io",
|
||||||
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
|
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
|
||||||
@ -13,10 +13,10 @@
|
|||||||
"java_version"
|
"java_version"
|
||||||
],
|
],
|
||||||
"images": [
|
"images": [
|
||||||
"ghcr.io\/pterodactyl\/yolks:java_8",
|
"ghcr.io\/pterodactyl\/yolks:java_17",
|
||||||
"ghcr.io\/pterodactyl\/yolks:java_11",
|
|
||||||
"ghcr.io\/pterodactyl\/yolks:java_16",
|
"ghcr.io\/pterodactyl\/yolks:java_16",
|
||||||
"ghcr.io\/pterodactyl\/yolks:java_17"
|
"ghcr.io\/pterodactyl\/yolks:java_11",
|
||||||
|
"ghcr.io\/pterodactyl\/yolks:java_8"
|
||||||
],
|
],
|
||||||
"file_denylist": [],
|
"file_denylist": [],
|
||||||
"startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true $( [ ! -f unix_args.txt ] && printf %s \"-jar {{SERVER_JARFILE}}\" || printf %s \"@unix_args.txt\" )",
|
"startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true $( [ ! -f unix_args.txt ] && printf %s \"-jar {{SERVER_JARFILE}}\" || printf %s \"@unix_args.txt\" )",
|
||||||
|
@ -7,10 +7,21 @@ const http: AxiosInstance = axios.create({
|
|||||||
'X-Requested-With': 'XMLHttpRequest',
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-CSRF-Token': (window as any).X_CSRF_TOKEN as string || '',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
http.interceptors.request.use(req => {
|
||||||
|
const cookies = document.cookie.split(';').reduce((obj, val) => {
|
||||||
|
const [ key, value ] = val.trim().split('=').map(decodeURIComponent);
|
||||||
|
|
||||||
|
return { ...obj, [key]: value };
|
||||||
|
}, {} as Record<string, string>);
|
||||||
|
|
||||||
|
req.headers['X-XSRF-TOKEN'] = cookies['XSRF-TOKEN'] || 'nil';
|
||||||
|
|
||||||
|
return req;
|
||||||
|
});
|
||||||
|
|
||||||
http.interceptors.request.use(req => {
|
http.interceptors.request.use(req => {
|
||||||
if (!req.url?.endsWith('/resources') && (req.url?.indexOf('_debugbar') || -1) < 0) {
|
if (!req.url?.endsWith('/resources') && (req.url?.indexOf('_debugbar') || -1) < 0) {
|
||||||
store.getActions().progress.startContinuous();
|
store.getActions().progress.startContinuous();
|
||||||
|
@ -76,7 +76,7 @@ export default ({ database, className }: Props) => {
|
|||||||
<FlashMessageRender byKey={'database:delete'} css={tw`mb-6`}/>
|
<FlashMessageRender byKey={'database:delete'} css={tw`mb-6`}/>
|
||||||
<h2 css={tw`text-2xl mb-6`}>Confirm database deletion</h2>
|
<h2 css={tw`text-2xl mb-6`}>Confirm database deletion</h2>
|
||||||
<p css={tw`text-sm`}>
|
<p css={tw`text-sm`}>
|
||||||
Deleting a database is a permanent action, it cannot be undone. This will permanetly
|
Deleting a database is a permanent action, it cannot be undone. This will permanently
|
||||||
delete the <strong>{database.name}</strong> database and remove all associated data.
|
delete the <strong>{database.name}</strong> database and remove all associated data.
|
||||||
</p>
|
</p>
|
||||||
<Form css={tw`m-0 mt-6`}>
|
<Form css={tw`m-0 mt-6`}>
|
||||||
|
@ -70,7 +70,11 @@
|
|||||||
@parent
|
@parent
|
||||||
<script>
|
<script>
|
||||||
$('#configTokenBtn').on('click', function (event) {
|
$('#configTokenBtn').on('click', function (event) {
|
||||||
$.getJSON('{{ route('admin.nodes.view.configuration.token', $node->id) }}').done(function (data) {
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: '{{ route('admin.nodes.view.configuration.token', $node->id) }}',
|
||||||
|
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
|
||||||
|
}).done(function (data) {
|
||||||
swal({
|
swal({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Token created.',
|
title: 'Token created.',
|
||||||
|
@ -145,9 +145,9 @@
|
|||||||
showLoaderOnConfirm: true
|
showLoaderOnConfirm: true
|
||||||
}, function () {
|
}, function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method: 'GET',
|
method: 'POST',
|
||||||
url: '/admin/settings/mail/test',
|
url: '/admin/settings/mail/test',
|
||||||
headers: { 'X-CSRF-Token': $('input[name="_token"]').val() }
|
headers: { 'X-CSRF-TOKEN': $('input[name="_token"]').val() }
|
||||||
}).fail(function (jqXHR) {
|
}).fail(function (jqXHR) {
|
||||||
showErrorDialog(jqXHR, 'test');
|
showErrorDialog(jqXHR, 'test');
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
|
@ -66,8 +66,8 @@ Route::group(['prefix' => 'databases'], function () {
|
|||||||
Route::group(['prefix' => 'settings'], function () {
|
Route::group(['prefix' => 'settings'], function () {
|
||||||
Route::get('/', 'Settings\IndexController@index')->name('admin.settings');
|
Route::get('/', 'Settings\IndexController@index')->name('admin.settings');
|
||||||
Route::get('/mail', 'Settings\MailController@index')->name('admin.settings.mail');
|
Route::get('/mail', 'Settings\MailController@index')->name('admin.settings.mail');
|
||||||
Route::get('/mail/test', 'Settings\MailController@test')->name('admin.settings.mail.test');
|
|
||||||
Route::get('/advanced', 'Settings\AdvancedController@index')->name('admin.settings.advanced');
|
Route::get('/advanced', 'Settings\AdvancedController@index')->name('admin.settings.advanced');
|
||||||
|
Route::post('/mail/test', 'Settings\MailController@test')->name('admin.settings.mail.test');
|
||||||
|
|
||||||
Route::patch('/', 'Settings\IndexController@update');
|
Route::patch('/', 'Settings\IndexController@update');
|
||||||
Route::patch('/mail', 'Settings\MailController@update');
|
Route::patch('/mail', 'Settings\MailController@update');
|
||||||
@ -153,12 +153,12 @@ Route::group(['prefix' => 'nodes'], function () {
|
|||||||
Route::get('/view/{node}/allocation', 'Nodes\NodeViewController@allocations')->name('admin.nodes.view.allocation');
|
Route::get('/view/{node}/allocation', 'Nodes\NodeViewController@allocations')->name('admin.nodes.view.allocation');
|
||||||
Route::get('/view/{node}/servers', 'Nodes\NodeViewController@servers')->name('admin.nodes.view.servers');
|
Route::get('/view/{node}/servers', 'Nodes\NodeViewController@servers')->name('admin.nodes.view.servers');
|
||||||
Route::get('/view/{node}/system-information', 'Nodes\SystemInformationController');
|
Route::get('/view/{node}/system-information', 'Nodes\SystemInformationController');
|
||||||
Route::get('/view/{node}/settings/token', 'NodeAutoDeployController')->name('admin.nodes.view.configuration.token');
|
|
||||||
|
|
||||||
Route::post('/new', 'NodesController@store');
|
Route::post('/new', 'NodesController@store');
|
||||||
Route::post('/view/{node}/allocation', 'NodesController@createAllocation');
|
Route::post('/view/{node}/allocation', 'NodesController@createAllocation');
|
||||||
Route::post('/view/{node}/allocation/remove', 'NodesController@allocationRemoveBlock')->name('admin.nodes.view.allocation.removeBlock');
|
Route::post('/view/{node}/allocation/remove', 'NodesController@allocationRemoveBlock')->name('admin.nodes.view.allocation.removeBlock');
|
||||||
Route::post('/view/{node}/allocation/alias', 'NodesController@allocationSetAlias')->name('admin.nodes.view.allocation.setAlias');
|
Route::post('/view/{node}/allocation/alias', 'NodesController@allocationSetAlias')->name('admin.nodes.view.allocation.setAlias');
|
||||||
|
Route::post('/view/{node}/settings/token', 'NodeAutoDeployController')->name('admin.nodes.view.configuration.token');
|
||||||
|
|
||||||
Route::patch('/view/{node}/settings', 'NodesController@updateSettings');
|
Route::patch('/view/{node}/settings', 'NodesController@updateSettings');
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class EggControllerTest extends ApplicationApiIntegrationTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that all of the eggs belonging to a given nest can be returned.
|
* Test that all the eggs belonging to a given nest can be returned.
|
||||||
*/
|
*/
|
||||||
public function testListAllEggsInNest()
|
public function testListAllEggsInNest()
|
||||||
{
|
{
|
||||||
@ -47,7 +47,7 @@ class EggControllerTest extends ApplicationApiIntegrationTestCase
|
|||||||
'files' => [],
|
'files' => [],
|
||||||
'startup' => ['done'],
|
'startup' => ['done'],
|
||||||
'stop',
|
'stop',
|
||||||
'logs' => ['custom', 'location'],
|
'logs' => [],
|
||||||
'extends',
|
'extends',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user