mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-20 00:34:44 +02:00
Merge branch 'pelican-dev:main' into replace/encrypt-decrypt
This commit is contained in:
commit
b1928e89b4
@ -17,9 +17,6 @@ CACHE_STORE=file
|
||||
QUEUE_CONNECTION=database
|
||||
SESSION_DRIVER=file
|
||||
|
||||
HASHIDS_SALT=
|
||||
HASHIDS_LENGTH=8
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=smtp.example.com
|
||||
MAIL_PORT=25
|
||||
|
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -34,7 +34,6 @@ jobs:
|
||||
MAIL_MAILER: array
|
||||
SESSION_DRIVER: array
|
||||
QUEUE_CONNECTION: sync
|
||||
HASHIDS_SALT: alittlebitofsalt1234
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_DATABASE: testing
|
||||
@ -97,7 +96,6 @@ jobs:
|
||||
MAIL_MAILER: array
|
||||
SESSION_DRIVER: array
|
||||
QUEUE_CONNECTION: sync
|
||||
HASHIDS_SALT: alittlebitofsalt1234
|
||||
DB_CONNECTION: sqlite
|
||||
DB_DATABASE: testing.sqlite
|
||||
steps:
|
||||
|
@ -32,7 +32,6 @@ class AppSettingsCommand extends Command
|
||||
protected $description = 'Configure basic environment settings for the Panel.';
|
||||
|
||||
protected $signature = 'p:environment:setup
|
||||
{--new-salt : Whether or not to generate a new salt for Hashids.}
|
||||
{--url= : The URL that this Panel is running on.}
|
||||
{--cache= : The cache driver backend to use.}
|
||||
{--session= : The session driver backend to use.}
|
||||
@ -61,10 +60,6 @@ class AppSettingsCommand extends Command
|
||||
{
|
||||
$this->variables['APP_TIMEZONE'] = 'UTC';
|
||||
|
||||
if (empty(config('hashids.salt')) || $this->option('new-salt')) {
|
||||
$this->variables['HASHIDS_SALT'] = str_random(20);
|
||||
}
|
||||
|
||||
$this->output->comment(__('commands.appsettings.comment.url'));
|
||||
$this->variables['APP_URL'] = $this->option('url') ?? $this->ask(
|
||||
'Application URL',
|
||||
|
@ -62,7 +62,7 @@ class ProcessRunnableCommand extends Command
|
||||
|
||||
$this->line(trans('command/messages.schedule.output_line', [
|
||||
'schedule' => $schedule->name,
|
||||
'hash' => $schedule->hashid,
|
||||
'id' => $schedule->id,
|
||||
]));
|
||||
} catch (\Throwable|\Exception $exception) {
|
||||
logger()->error($exception, ['schedule_id' => $schedule->id]);
|
||||
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts\Extensions;
|
||||
|
||||
use Hashids\HashidsInterface as VendorHashidsInterface;
|
||||
|
||||
interface HashidsInterface extends VendorHashidsInterface
|
||||
{
|
||||
/**
|
||||
* Decode an encoded hashid and return the first result.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function decodeFirst(string $encoded, string $default = null): mixed;
|
||||
}
|
@ -48,7 +48,7 @@ class DisplayException extends PanelException implements HttpExceptionInterface
|
||||
*/
|
||||
public function render(Request $request)
|
||||
{
|
||||
if (str($request->url())->contains('livewire')) {
|
||||
if ($request->is('livewire/update')) {
|
||||
Notification::make()
|
||||
->title(static::class)
|
||||
->body($this->getMessage())
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Extensions;
|
||||
|
||||
use Hashids\Hashids as VendorHashids;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
class Hashids extends VendorHashids implements HashidsInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function decodeFirst(string $encoded, string $default = null): mixed
|
||||
{
|
||||
$result = $this->decode($encoded);
|
||||
if (!is_array($result)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return array_first($result, null, $default);
|
||||
}
|
||||
}
|
@ -337,6 +337,7 @@ class CreateNode extends CreateRecord
|
||||
->suffix('%')
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
->default(0)
|
||||
->minValue(0),
|
||||
Forms\Components\TextInput::make('cpu_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
@ -346,6 +347,7 @@ class CreateNode extends CreateRecord
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
->default(0)
|
||||
->minValue(-1)
|
||||
->maxValue(100)
|
||||
->suffix('%'),
|
||||
|
@ -6,9 +6,11 @@ use App\Filament\Resources\NodeResource;
|
||||
use App\Filament\Resources\NodeResource\Widgets\NodeMemoryChart;
|
||||
use App\Filament\Resources\NodeResource\Widgets\NodeStorageChart;
|
||||
use App\Models\Node;
|
||||
use App\Services\Nodes\NodeUpdateService;
|
||||
use Filament\Actions;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Components\Tabs;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Illuminate\Support\HtmlString;
|
||||
use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
|
||||
@ -374,6 +376,18 @@ class EditNode extends EditRecord
|
||||
->rows(19)
|
||||
->hintAction(CopyAction::make())
|
||||
->columnSpanFull(),
|
||||
Forms\Components\Actions::make([
|
||||
Forms\Components\Actions\Action::make('resetKey')
|
||||
->label('Reset Daemon Token')
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Reset Daemon Token?')
|
||||
->modalDescription('Resetting the daemon token will void any request coming from the old token. This token is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this token regularly for security.')
|
||||
->action(fn (NodeUpdateService $nodeUpdateService, Node $node) => $nodeUpdateService->handle($node, [], true)
|
||||
&& Notification::make()->success()->title('Daemon Key Reset')->send()
|
||||
&& $this->fillForm()
|
||||
),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
|
@ -24,8 +24,8 @@ class NodeDeploymentController extends ApplicationApiController
|
||||
$data = $request->validated();
|
||||
|
||||
$nodes = $this->viableNodesService->handle(
|
||||
$data['disk'] ?? 0,
|
||||
$data['memory'] ?? 0,
|
||||
$data['disk'] ?? 0,
|
||||
$data['cpu'] ?? 0,
|
||||
$data['tags'] ?? $data['location_ids'] ?? [],
|
||||
);
|
||||
|
@ -56,11 +56,10 @@ class StoreServerRequest extends ApplicationApiRequest
|
||||
// Automatic deployment rules
|
||||
'deploy' => 'sometimes|required|array',
|
||||
'deploy.locations' => 'array',
|
||||
'deploy.locations.*' => 'integer|min:1',
|
||||
'deploy.locations.*' => 'required_with:deploy.locations,integer|min:1',
|
||||
'deploy.dedicated_ip' => 'required_with:deploy,boolean',
|
||||
'deploy.port_range' => 'array',
|
||||
'deploy.port_range.*' => 'string',
|
||||
|
||||
'start_on_completion' => 'sometimes|boolean',
|
||||
];
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @property bool $has_alias
|
||||
* @property \App\Models\Server|null $server
|
||||
* @property \App\Models\Node $node
|
||||
* @property string $hashid
|
||||
*
|
||||
* @method static \Database\Factories\AllocationFactory factory(...$parameters)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Allocation newModelQuery()
|
||||
@ -88,14 +87,6 @@ class Allocation extends Model
|
||||
return $this->getKeyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashid encoded string to represent the ID of the allocation.
|
||||
*/
|
||||
public function getHashidAttribute(): string
|
||||
{
|
||||
return app()->make('hashids')->encode($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor to automatically provide the IP alias if defined.
|
||||
*/
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
@ -73,26 +71,6 @@ class Database extends Model
|
||||
return $this->getKeyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the database using the ID by checking if the value provided is a HashID
|
||||
* string value, or just the ID to the database itself.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function resolveRouteBinding($value, $field = null): ?\Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
if (is_scalar($value) && ($field ?? $this->getRouteKeyName()) === 'id') {
|
||||
$value = ctype_digit((string) $value)
|
||||
? $value
|
||||
: Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value);
|
||||
}
|
||||
|
||||
return $this->where($field ?? $this->getRouteKeyName(), $value)->firstOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the host database server associated with a database.
|
||||
*/
|
||||
|
@ -63,10 +63,6 @@ class Node extends Model
|
||||
*/
|
||||
protected $hidden = ['daemon_token_id', 'daemon_token'];
|
||||
|
||||
public int $sum_memory;
|
||||
public int $sum_disk;
|
||||
public int $sum_cpu;
|
||||
|
||||
/**
|
||||
* Fields that are mass assignable.
|
||||
*/
|
||||
@ -241,11 +237,28 @@ class Node extends Model
|
||||
*/
|
||||
public function isViable(int $memory, int $disk, int $cpu): bool
|
||||
{
|
||||
$memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100));
|
||||
$diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100));
|
||||
$cpuLimit = $this->cpu * (1 + ($this->cpu_overallocate / 100));
|
||||
if ($this->memory_overallocate >= 0) {
|
||||
$memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100));
|
||||
if ($this->servers_sum_memory + $memory > $memoryLimit) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit && ($this->sum_cpu + $cpu) <= $cpuLimit;
|
||||
if ($this->disk_overallocate >= 0) {
|
||||
$diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100));
|
||||
if ($this->servers_sum_disk + $disk > $diskLimit) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->cpu_overallocate >= 0) {
|
||||
$cpuLimit = $this->cpu * (1 + ($this->cpu_overallocate / 100));
|
||||
if ($this->servers_sum_cpu + $cpu > $cpuLimit) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getForServerCreation()
|
||||
|
@ -4,10 +4,8 @@ namespace App\Models;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@ -25,7 +23,6 @@ use App\Contracts\Extensions\HashidsInterface;
|
||||
* @property \Carbon\Carbon|null $next_run_at
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $hashid
|
||||
* @property \App\Models\Server $server
|
||||
* @property \App\Models\Task[]|\Illuminate\Support\Collection $tasks
|
||||
*/
|
||||
@ -124,14 +121,6 @@ class Schedule extends Model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashid encoded string to represent the ID of the schedule.
|
||||
*/
|
||||
public function getHashidAttribute(): string
|
||||
{
|
||||
return Container::getInstance()->make(HashidsInterface::class)->encode($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return tasks belonging to a schedule.
|
||||
*/
|
||||
|
@ -52,14 +52,6 @@ class Subuser extends Model
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashid encoded string to represent the ID of the subuser.
|
||||
*/
|
||||
public function getHashidAttribute(): string
|
||||
{
|
||||
return app()->make('hashids')->encode($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server associated with a subuser.
|
||||
*/
|
||||
|
@ -2,10 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@ -18,7 +16,6 @@ use App\Contracts\Extensions\HashidsInterface;
|
||||
* @property bool $continue_on_failure
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $hashid
|
||||
* @property \App\Models\Schedule $schedule
|
||||
* @property \App\Models\Server $server
|
||||
*/
|
||||
@ -96,14 +93,6 @@ class Task extends Model
|
||||
return $this->getKeyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashid encoded string to represent the ID of the task.
|
||||
*/
|
||||
public function getHashidAttribute(): string
|
||||
{
|
||||
return Container::getInstance()->make(HashidsInterface::class)->encode($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schedule that a task belongs to.
|
||||
*/
|
||||
|
@ -35,11 +35,13 @@ class AdminPanelProvider extends PanelProvider
|
||||
->default()
|
||||
->id('admin')
|
||||
->path('admin')
|
||||
->topNavigation(config('panel.filament.top-navigation', false))
|
||||
->topNavigation(config('panel.filament.top-navigation', true))
|
||||
->login()
|
||||
->homeUrl('/')
|
||||
->favicon('/pelican.ico')
|
||||
->brandName('Pelican')
|
||||
->favicon(config('app.favicon', '/pelican.ico'))
|
||||
->brandName(config('app.name', 'Pelican'))
|
||||
->brandLogo(config('app.logo'))
|
||||
->brandLogoHeight('2rem')
|
||||
->profile(EditProfile::class, false)
|
||||
->colors([
|
||||
'danger' => Color::Red,
|
||||
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Extensions\Hashids;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
class HashidsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register the ability to use Hashids.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->singleton(HashidsInterface::class, function () {
|
||||
return new Hashids(
|
||||
config('hashids.salt', ''),
|
||||
config('hashids.length', 0),
|
||||
config('hashids.alphabet', 'abcdefghijkmlnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890')
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->alias(HashidsInterface::class, 'hashids');
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Database;
|
||||
use Illuminate\Foundation\Http\Middleware\TrimStrings;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
@ -29,11 +28,6 @@ class RouteServiceProvider extends ServiceProvider
|
||||
return preg_match(self::FILE_PATH_REGEX, $request->getPathInfo()) === 1;
|
||||
});
|
||||
|
||||
// This is needed to make use of the "resolveRouteBinding" functionality in the
|
||||
// model. Without it you'll never trigger that logic flow thus resulting in a 404
|
||||
// error because we request databases with a HashID, and not with a normal ID.
|
||||
Route::model('database', Database::class);
|
||||
|
||||
$this->routes(function () {
|
||||
Route::middleware('web')->group(function () {
|
||||
Route::middleware(['auth.session', RequireTwoFactorAuthentication::class])
|
||||
|
@ -17,19 +17,17 @@ class FindViableNodesService
|
||||
* are tossed out, as are any nodes marked as non-public, meaning automatic
|
||||
* deployments should not be done against them.
|
||||
*/
|
||||
public function handle(int $disk = 0, int $memory = 0, int $cpu = 0, $tags = []): Collection
|
||||
public function handle(int $memory = 0, int $disk = 0, int $cpu = 0, $tags = []): Collection
|
||||
{
|
||||
$nodes = Node::query()
|
||||
->withSum('servers', 'disk')
|
||||
->withSum('servers', 'memory')
|
||||
->withSum('servers', 'disk')
|
||||
->withSum('servers', 'cpu')
|
||||
->where('public', true)
|
||||
->get();
|
||||
|
||||
return $nodes
|
||||
->filter(fn (Node $node) => !$tags || collect($node->tags)->intersect($tags))
|
||||
->filter(fn (Node $node) => $node->servers_sum_disk + $disk <= $node->disk * (1 + $node->disk_overallocate / 100))
|
||||
->filter(fn (Node $node) => $node->servers_sum_memory + $memory <= $node->memory * (1 + $node->memory_overallocate / 100))
|
||||
->filter(fn (Node $node) => $node->servers_sum_cpu + $cpu <= $node->cpu * (1 + $node->cpu_overallocate / 100));
|
||||
->filter(fn (Node $node) => $node->isViable($memory, $disk, $cpu));
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ class NodeUpdateService
|
||||
|
||||
[$updated, $exception] = $this->connection->transaction(function () use ($data, $node) {
|
||||
/** @var \App\Models\Node $updated */
|
||||
$updated = $node->replicate()->forceFill($data)->save();
|
||||
|
||||
$updated = $node->replicate();
|
||||
$updated->forceFill($data)->save();
|
||||
try {
|
||||
// If we're changing the FQDN for the node, use the newly provided FQDN for the connection
|
||||
// address. This should alleviate issues where the node gets pointed to a "valid" FQDN that
|
||||
|
@ -109,8 +109,8 @@ class ServerCreationService
|
||||
{
|
||||
/** @var Collection<\App\Models\Node> $nodes */
|
||||
$nodes = $this->findViableNodesService->handle(
|
||||
Arr::get($data, 'disk', 0),
|
||||
Arr::get($data, 'memory', 0),
|
||||
Arr::get($data, 'disk', 0),
|
||||
Arr::get($data, 'cpu', 0),
|
||||
Arr::get($data, 'tags', []),
|
||||
);
|
||||
|
@ -58,7 +58,9 @@ class TransferServerService
|
||||
// Check if the node is viable for the transfer.
|
||||
$node = Node::query()
|
||||
->select(['nodes.id', 'nodes.fqdn', 'nodes.scheme', 'nodes.daemon_token', 'nodes.daemon_listen', 'nodes.memory', 'nodes.disk', 'nodes.cpu', 'nodes.memory_overallocate', 'nodes.disk_overallocate', 'nodes.cpu_overallocate'])
|
||||
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk, IFNULL(SUM(servers.cpu), 0) as sum_cpu')
|
||||
->withSum('servers', 'disk')
|
||||
->withSum('servers', 'memory')
|
||||
->withSum('servers', 'cpu')
|
||||
->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')
|
||||
->where('nodes.id', $node_id)
|
||||
->first();
|
||||
|
@ -55,7 +55,7 @@ class ActivityLogTransformer extends BaseClientTransformer
|
||||
|
||||
$properties = $model->properties
|
||||
->mapWithKeys(function ($value, $key) use ($model) {
|
||||
if ($key === 'ip' && !$model->actor->is($this->request->user())) {
|
||||
if ($key === 'ip' && $model->actor && !$model->actor->is($this->request->user())) {
|
||||
return [$key => '[hidden]'];
|
||||
}
|
||||
|
||||
|
@ -6,22 +6,11 @@ use App\Models\Database;
|
||||
use League\Fractal\Resource\Item;
|
||||
use App\Models\Permission;
|
||||
use League\Fractal\Resource\NullResource;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
class DatabaseTransformer extends BaseClientTransformer
|
||||
{
|
||||
protected array $availableIncludes = ['password'];
|
||||
|
||||
private HashidsInterface $hashids;
|
||||
|
||||
/**
|
||||
* Handle dependency injection.
|
||||
*/
|
||||
public function handle(HashidsInterface $hashids)
|
||||
{
|
||||
$this->hashids = $hashids;
|
||||
}
|
||||
|
||||
public function getResourceName(): string
|
||||
{
|
||||
return Database::RESOURCE_NAME;
|
||||
@ -32,7 +21,7 @@ class DatabaseTransformer extends BaseClientTransformer
|
||||
$model->loadMissing('host');
|
||||
|
||||
return [
|
||||
'id' => $this->hashids->encode($model->id),
|
||||
'id' => $model->id,
|
||||
'host' => [
|
||||
'address' => $model->getRelation('host')->host,
|
||||
'port' => $model->getRelation('host')->port,
|
||||
|
@ -6,7 +6,6 @@ return [
|
||||
App\Providers\BackupsServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\Filament\AdminPanelProvider::class,
|
||||
App\Providers\HashidsServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
App\Providers\ViewComposerServiceProvider::class,
|
||||
];
|
||||
|
@ -16,7 +16,6 @@
|
||||
"doctrine/dbal": "~3.6.0",
|
||||
"filament/filament": "^3.2",
|
||||
"guzzlehttp/guzzle": "^7.8.1",
|
||||
"hashids/hashids": "~5.0.0",
|
||||
"laracasts/utilities": "~3.2.2",
|
||||
"laravel/framework": "^11.7",
|
||||
"laravel/helpers": "^1.7",
|
||||
@ -34,7 +33,8 @@
|
||||
"s1lentium/iptools": "~1.2.0",
|
||||
"spatie/laravel-fractal": "^6.2",
|
||||
"spatie/laravel-query-builder": "^5.8.1",
|
||||
"symfony/mailgun-mailer": "^7.0.7",
|
||||
"symfony/http-client": "^7.1",
|
||||
"symfony/mailgun-mailer": "^7.1",
|
||||
"symfony/postmark-mailer": "^7.0.7",
|
||||
"symfony/yaml": "^7.0.7",
|
||||
"webbingbrasil/filament-copyactions": "^3.0.1",
|
||||
|
257
composer.lock
generated
257
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dc1c1e5ee766f2e31e84c50670fa0c98",
|
||||
"content-hash": "328bdd29cb83793ec0a99b2210941740",
|
||||
"packages": [
|
||||
{
|
||||
"name": "abdelhamiderrahmouni/filament-monaco-editor",
|
||||
@ -2613,75 +2613,6 @@
|
||||
],
|
||||
"time": "2023-12-03T19:50:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hashids/hashids",
|
||||
"version": "5.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vinkla/hashids.git",
|
||||
"reference": "197171016b77ddf14e259e186559152eb3f8cf33"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vinkla/hashids/zipball/197171016b77ddf14e259e186559152eb3f8cf33",
|
||||
"reference": "197171016b77ddf14e259e186559152eb3f8cf33",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Required to use BC Math arbitrary precision mathematics (*).",
|
||||
"ext-gmp": "Required to use GNU multiple precision mathematics (*)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Hashids\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ivan Akimov",
|
||||
"email": "ivan@barreleye.com"
|
||||
},
|
||||
{
|
||||
"name": "Vincent Klaiber",
|
||||
"email": "hello@doubledip.se"
|
||||
}
|
||||
],
|
||||
"description": "Generate short, unique, non-sequential ids (like YouTube and Bitly) from numbers",
|
||||
"homepage": "https://hashids.org/php",
|
||||
"keywords": [
|
||||
"bitly",
|
||||
"decode",
|
||||
"encode",
|
||||
"hash",
|
||||
"hashid",
|
||||
"hashids",
|
||||
"ids",
|
||||
"obfuscate",
|
||||
"youtube"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/vinkla/hashids/issues",
|
||||
"source": "https://github.com/vinkla/hashids/tree/5.0.2"
|
||||
},
|
||||
"time": "2023-02-23T15:00:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "kirschbaum-development/eloquent-power-joins",
|
||||
"version": "3.5.6",
|
||||
@ -7722,6 +7653,178 @@
|
||||
],
|
||||
"time": "2024-04-18T09:29:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "2266f9813ed7d8c84e04627edead7b7fd249d6e9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/2266f9813ed7d8c84e04627edead7b7fd249d6e9",
|
||||
"reference": "2266f9813ed7d8c84e04627edead7b7fd249d6e9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/http-client-contracts": "^3.4.1",
|
||||
"symfony/service-contracts": "^2.5|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"php-http/discovery": "<1.15",
|
||||
"symfony/http-foundation": "<6.4"
|
||||
},
|
||||
"provide": {
|
||||
"php-http/async-client-implementation": "*",
|
||||
"php-http/client-implementation": "*",
|
||||
"psr/http-client-implementation": "1.0",
|
||||
"symfony/http-client-implementation": "3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/amp": "^2.5",
|
||||
"amphp/http-client": "^4.2.1",
|
||||
"amphp/http-tunnel": "^1.0",
|
||||
"amphp/socket": "^1.1",
|
||||
"guzzlehttp/promises": "^1.4|^2.0",
|
||||
"nyholm/psr7": "^1.0",
|
||||
"php-http/httplug": "^1.0|^2.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0",
|
||||
"symfony/messenger": "^6.4|^7.0",
|
||||
"symfony/process": "^6.4|^7.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0",
|
||||
"symfony/stopwatch": "^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\HttpClient\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-13T15:35:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client-contracts.git",
|
||||
"reference": "20414d96f391677bf80078aa55baece78b82647d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d",
|
||||
"reference": "20414d96f391677bf80078aa55baece78b82647d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
"url": "https://github.com/symfony/contracts"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Contracts\\HttpClient\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Test/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Generic abstractions related to HTTP clients",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"abstractions",
|
||||
"contracts",
|
||||
"decoupling",
|
||||
"interfaces",
|
||||
"interoperability",
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.0.7",
|
||||
@ -7994,16 +8097,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailgun-mailer",
|
||||
"version": "v7.0.7",
|
||||
"version": "v7.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mailgun-mailer.git",
|
||||
"reference": "e9bb8fdbdd79334a8a88bdd233204315abd992c5"
|
||||
"reference": "aa5afbe846bbc8bde6afe2602f0427834b872f55"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/e9bb8fdbdd79334a8a88bdd233204315abd992c5",
|
||||
"reference": "e9bb8fdbdd79334a8a88bdd233204315abd992c5",
|
||||
"url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/aa5afbe846bbc8bde6afe2602f0427834b872f55",
|
||||
"reference": "aa5afbe846bbc8bde6afe2602f0427834b872f55",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8043,7 +8146,7 @@
|
||||
"description": "Symfony Mailgun Mailer Bridge",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mailgun-mailer/tree/v7.0.7"
|
||||
"source": "https://github.com/symfony/mailgun-mailer/tree/v7.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -8059,7 +8162,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:29:19+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
@ -13061,5 +13164,5 @@
|
||||
"ext-zip": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Hashids Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here are the settings that control the Hashids setup and usage in the panel.
|
||||
|
|
||||
*/
|
||||
'salt' => env('HASHIDS_SALT'),
|
||||
'length' => env('HASHIDS_LENGTH', 8),
|
||||
'alphabet' => env('HASHIDS_ALPHABET', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'),
|
||||
];
|
@ -23,7 +23,7 @@ return [
|
||||
'2fa_disabled' => '2-Factor authentication has been disabled for :email.',
|
||||
],
|
||||
'schedule' => [
|
||||
'output_line' => 'Dispatching job for first task in `:schedule` (:hash).',
|
||||
'output_line' => 'Dispatching job for first task in `:schedule` (:id).',
|
||||
],
|
||||
'maintenance' => [
|
||||
'deleting_service_backup' => 'Deleting service backup file :file.',
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
# Pelican Panel
|
||||
|
||||
&color=rgba(255%2C%20255%2C%20255%2C%201))
|
||||
&color=rgba(255%2C%20255%2C%20255%2C%201))
|
||||
|
||||
|
||||
Pelican Panel is an open-source, web-based application designed for easy management of game servers.
|
||||
It offers a user-friendly interface for deploying, configuring, and managing servers, with features like real-time resource monitoring, Docker container isolation, and extensive customization options.
|
||||
Ideal for both individual gamers and hosting companies, it simplifies server administration without requiring deep technical knowledge.
|
||||
|
@ -5,7 +5,6 @@ namespace App\Tests\Integration\Api\Client\Server\Database;
|
||||
use App\Models\Subuser;
|
||||
use App\Models\Database;
|
||||
use App\Models\DatabaseHost;
|
||||
use App\Contracts\Extensions\HashidsInterface;
|
||||
use App\Services\Databases\DatabasePasswordService;
|
||||
use App\Services\Databases\DatabaseManagementService;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
@ -39,23 +38,22 @@ class DatabaseAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
->expects($method === 'POST' ? 'handle' : 'delete')
|
||||
->andReturn($method === 'POST' ? 'foo' : null);
|
||||
|
||||
$hashids = $this->app->make(HashidsInterface::class);
|
||||
// This is the only valid call for this test, accessing the database for the same
|
||||
// server that the API user is the owner of.
|
||||
$this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $hashids->encode($database1->id) . $endpoint))
|
||||
$this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $database1->id . $endpoint))
|
||||
->assertStatus($method === 'DELETE' ? 204 : 200);
|
||||
|
||||
// This request fails because the database is valid for that server but the user
|
||||
// making the request is not authorized to perform that action.
|
||||
$this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $hashids->encode($database2->id) . $endpoint))->assertForbidden();
|
||||
$this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $database2->id . $endpoint))->assertForbidden();
|
||||
|
||||
// Both of these should report a 404 error due to the database being linked to
|
||||
// servers that are not the same as the server in the request, or are assigned
|
||||
// to a server for which the user making the request has no access to.
|
||||
$this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $hashids->encode($database2->id) . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $hashids->encode($database3->id) . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $hashids->encode($database3->id) . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server3, '/databases/' . $hashids->encode($database3->id) . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $database2->id . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $database3->id . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $database3->id . $endpoint))->assertNotFound();
|
||||
$this->actingAs($user)->json($method, $this->link($server3, '/databases/' . $database3->id . $endpoint))->assertNotFound();
|
||||
}
|
||||
|
||||
public static function methodDataProvider(): array
|
||||
|
Loading…
x
Reference in New Issue
Block a user