mirror of
https://github.com/pelican-dev/panel.git
synced 2025-09-08 12:48:45 +02:00
Merge branch 'main' into filament-v4
This commit is contained in:
commit
582b9bc0ac
@ -63,7 +63,7 @@ FROM --platform=$TARGETOS/$TARGETARCH localhost:5000/base-php:$TARGETARCH AS fin
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Install additional required libraries
|
||||
RUN apk update && apk add --no-cache \
|
||||
RUN apk add --no-cache \
|
||||
caddy ca-certificates supervisor supercronic
|
||||
|
||||
COPY --chown=root:www-data --chmod=640 --from=composerbuild /build .
|
||||
@ -93,10 +93,11 @@ COPY docker/Caddyfile /etc/caddy/Caddyfile
|
||||
# Add Laravel scheduler to crontab
|
||||
COPY docker/crontab /etc/supercronic/crontab
|
||||
|
||||
COPY docker/entrypoint.sh ./docker/entrypoint.sh
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
COPY docker/healthcheck.sh /healthcheck.sh
|
||||
|
||||
HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/up || exit 1
|
||||
CMD /bin/ash /healthcheck.sh
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
@ -104,5 +105,5 @@ VOLUME /pelican-data
|
||||
|
||||
USER www-data
|
||||
|
||||
ENTRYPOINT [ "/bin/ash", "docker/entrypoint.sh" ]
|
||||
ENTRYPOINT [ "/bin/ash", "/entrypoint.sh" ]
|
||||
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]
|
||||
|
@ -67,8 +67,8 @@ FROM --platform=$TARGETOS/$TARGETARCH base AS final
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Install additional required libraries
|
||||
RUN apk update && apk add --no-cache \
|
||||
caddy ca-certificates supervisor supercronic
|
||||
RUN apk add --no-cache \
|
||||
caddy ca-certificates supervisor supercronic coreutils
|
||||
|
||||
COPY --chown=root:www-data --chmod=640 --from=composerbuild /build .
|
||||
COPY --chown=root:www-data --chmod=640 --from=yarnbuild /build/public ./public
|
||||
@ -97,10 +97,11 @@ COPY docker/Caddyfile /etc/caddy/Caddyfile
|
||||
# Add Laravel scheduler to crontab
|
||||
COPY docker/crontab /etc/supercronic/crontab
|
||||
|
||||
COPY docker/entrypoint.sh ./docker/entrypoint.sh
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
COPY docker/healthcheck.sh /healthcheck.sh
|
||||
|
||||
HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/up || exit 1
|
||||
CMD /bin/ash /healthcheck.sh
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
@ -108,5 +109,5 @@ VOLUME /pelican-data
|
||||
|
||||
USER www-data
|
||||
|
||||
ENTRYPOINT [ "/bin/ash", "docker/entrypoint.sh" ]
|
||||
ENTRYPOINT [ "/bin/ash", "/entrypoint.sh" ]
|
||||
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]
|
||||
|
@ -32,4 +32,6 @@ interface OAuthSchemaInterface
|
||||
public function getHexColor(): ?string;
|
||||
|
||||
public function isEnabled(): bool;
|
||||
|
||||
public function shouldCreateMissingUsers(): bool;
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ namespace App\Extensions\OAuth\Schemas;
|
||||
|
||||
use App\Extensions\OAuth\OAuthSchemaInterface;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Schemas\Components\Utilities\Set;
|
||||
use Filament\Schemas\Components\Wizard\Step;
|
||||
use Filament\Schemas\Components\Component;
|
||||
use Illuminate\Support\Str;
|
||||
@ -53,6 +55,17 @@ abstract class OAuthSchema implements OAuthSchemaInterface
|
||||
->revealable()
|
||||
->autocomplete(false)
|
||||
->default(env("OAUTH_{$id}_CLIENT_SECRET")),
|
||||
Toggle::make("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS")
|
||||
->label(trans('admin/setting.oauth.create_missing_users'))
|
||||
->columnSpanFull()
|
||||
->inline(false)
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
->onColor('success')
|
||||
->offColor('danger')
|
||||
->formatStateUsing(fn ($state): bool => (bool) $state)
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS", (bool) $state))
|
||||
->default(env("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS")),
|
||||
];
|
||||
}
|
||||
|
||||
@ -96,4 +109,11 @@ abstract class OAuthSchema implements OAuthSchemaInterface
|
||||
|
||||
return env("OAUTH_{$id}_ENABLED", false);
|
||||
}
|
||||
|
||||
public function shouldCreateMissingUsers(): bool
|
||||
{
|
||||
$id = Str::upper($this->getId());
|
||||
|
||||
return env("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS", false);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Remote;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use App\Models\Node;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Remote\Servers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Enums\ContainerStatus;
|
||||
use App\Http\Requests\Api\Remote\ServerRequest;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
@ -12,11 +13,11 @@ class ServerContainersController extends Controller
|
||||
/**
|
||||
* Updates the server container's status on the Panel
|
||||
*/
|
||||
public function status(Server $server, Request $request): JsonResponse
|
||||
public function status(ServerRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
$status = fluent($request->json()->all())->get('data.new_state');
|
||||
$status = ContainerStatus::tryFrom($request->json('data.new_state')) ?? ContainerStatus::Missing;
|
||||
|
||||
cache()->put("servers.$server->uuid.container.status", $status, now()->addHour());
|
||||
cache()->put("servers.$server->uuid.status", $status, now()->addHour());
|
||||
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use App\Models\Node;
|
||||
use Throwable;
|
||||
use App\Models\ActivityLog;
|
||||
use App\Enums\ServerState;
|
||||
use App\Http\Requests\Api\Remote\ServerRequest;
|
||||
use App\Models\Backup;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Server;
|
||||
@ -32,7 +33,7 @@ class ServerDetailsController extends Controller
|
||||
* Returns details about the server that allows daemon to self-recover and ensure
|
||||
* that the state of the server matches the Panel at all times.
|
||||
*/
|
||||
public function __invoke(Server $server): JsonResponse
|
||||
public function __invoke(ServerRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
return new JsonResponse([
|
||||
'settings' => $this->configurationStructureService->handle($server),
|
||||
|
@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Remote\Servers;
|
||||
|
||||
use App\Exceptions\Model\DataValidationException;
|
||||
use App\Enums\ServerState;
|
||||
use App\Http\Requests\Api\Remote\ServerRequest;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@ -16,14 +17,12 @@ class ServerInstallController extends Controller
|
||||
/**
|
||||
* Returns installation information for a server.
|
||||
*/
|
||||
public function index(Server $server): JsonResponse
|
||||
public function index(ServerRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
$egg = $server->egg;
|
||||
|
||||
return new JsonResponse([
|
||||
'container_image' => $egg->copy_script_container,
|
||||
'entrypoint' => $egg->copy_script_entry,
|
||||
'script' => $egg->copy_script_install,
|
||||
'container_image' => $server->egg->copy_script_container,
|
||||
'entrypoint' => $server->egg->copy_script_entry,
|
||||
'script' => $server->egg->copy_script_install,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Remote\Servers;
|
||||
|
||||
use Throwable;
|
||||
use App\Http\Requests\Api\Remote\ServerRequest;
|
||||
use App\Models\Server;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\ServerTransfer;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
|
||||
@ -29,14 +28,23 @@ class ServerTransferController extends Controller
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function failure(Server $server): JsonResponse
|
||||
public function failure(ServerRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
$transfer = $server->transfer;
|
||||
if (is_null($transfer)) {
|
||||
throw new ConflictHttpException('Server is not being transferred.');
|
||||
}
|
||||
|
||||
return $this->processFailedTransfer($transfer);
|
||||
$this->connection->transaction(function () use ($transfer) {
|
||||
$transfer->forceFill(['successful' => false])->saveOrFail();
|
||||
|
||||
if ($transfer->new_allocation || $transfer->new_additional_allocations) {
|
||||
$allocations = array_merge([$transfer->new_allocation], $transfer->new_additional_allocations);
|
||||
Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]);
|
||||
}
|
||||
});
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,16 +52,17 @@ class ServerTransferController extends Controller
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function success(Server $server): JsonResponse
|
||||
public function success(ServerRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
$transfer = $server->transfer;
|
||||
if (is_null($transfer)) {
|
||||
throw new ConflictHttpException('Server is not being transferred.');
|
||||
}
|
||||
|
||||
$data = [];
|
||||
/** @var Server $server */
|
||||
$server = $this->connection->transaction(function () use ($server, $transfer, $data) {
|
||||
$server = $this->connection->transaction(function () use ($server, $transfer) {
|
||||
$data = [];
|
||||
|
||||
if ($transfer->old_allocation || $transfer->old_additional_allocations) {
|
||||
$allocations = array_merge([$transfer->old_allocation], $transfer->old_additional_allocations);
|
||||
// Remove the old allocations for the server and re-assign the server to the new
|
||||
@ -61,6 +70,7 @@ class ServerTransferController extends Controller
|
||||
Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]);
|
||||
$data['allocation_id'] = $transfer->new_allocation;
|
||||
}
|
||||
|
||||
$data['node_id'] = $transfer->new_node;
|
||||
$server->update($data);
|
||||
|
||||
@ -83,24 +93,4 @@ class ServerTransferController extends Controller
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all the reserved allocations for this transfer and mark it as failed in
|
||||
* the database.
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected function processFailedTransfer(ServerTransfer $transfer): JsonResponse
|
||||
{
|
||||
$this->connection->transaction(function () use (&$transfer) {
|
||||
$transfer->forceFill(['successful' => false])->saveOrFail();
|
||||
|
||||
if ($transfer->new_allocation || $transfer->new_additional_allocations) {
|
||||
$allocations = array_merge([$transfer->new_allocation], $transfer->new_additional_allocations);
|
||||
Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]);
|
||||
}
|
||||
});
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ use App\Extensions\OAuth\OAuthService;
|
||||
use App\Filament\Pages\Auth\EditProfile;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Services\Users\UserCreationService;
|
||||
use App\Services\Users\UserUpdateService;
|
||||
use Exception;
|
||||
use Filament\Notifications\Notification;
|
||||
use Illuminate\Auth\AuthManager;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@ -18,8 +18,9 @@ class OAuthController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AuthManager $auth,
|
||||
private UserCreationService $userCreation,
|
||||
private readonly UserUpdateService $updateService,
|
||||
private readonly OAuthService $oauthService
|
||||
private readonly OAuthService $oauthService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -40,8 +41,10 @@ class OAuthController extends Controller
|
||||
*/
|
||||
public function callback(Request $request, string $driver): RedirectResponse
|
||||
{
|
||||
// Driver is disabled - redirect to normal login
|
||||
if (!$this->oauthService->get($driver)?->isEnabled()) {
|
||||
$driver = $this->oauthService->get($driver);
|
||||
|
||||
// Unknown driver or driver is disabled - redirect to normal login
|
||||
if (!$driver || !$driver->isEnabled()) {
|
||||
return redirect()->route('auth.login');
|
||||
}
|
||||
|
||||
@ -59,33 +62,57 @@ class OAuthController extends Controller
|
||||
return redirect()->route('auth.login');
|
||||
}
|
||||
|
||||
$oauthUser = Socialite::driver($driver)->user();
|
||||
$oauthUser = Socialite::driver($driver->getId())->user();
|
||||
|
||||
// User is already logged in and wants to link a new OAuth Provider
|
||||
if ($request->user()) {
|
||||
$oauth = $request->user()->oauth;
|
||||
$oauth[$driver] = $oauthUser->getId();
|
||||
$oauth[$driver->getId()] = $oauthUser->getId();
|
||||
|
||||
$this->updateService->handle($request->user(), ['oauth' => $oauth]);
|
||||
|
||||
return redirect(EditProfile::getUrl(['tab' => '-oauth-tab'], panel: 'app'));
|
||||
}
|
||||
|
||||
try {
|
||||
$user = User::query()->whereJsonContains('oauth->'. $driver, $oauthUser->getId())->firstOrFail();
|
||||
$user = User::whereJsonContains('oauth->'. $driver->getId(), $oauthUser->getId())->first();
|
||||
|
||||
$this->auth->guard()->login($user, true);
|
||||
} catch (Exception) {
|
||||
// No user found - redirect to normal login
|
||||
Notification::make()
|
||||
->title('No linked User found')
|
||||
->danger()
|
||||
->persistent()
|
||||
->send();
|
||||
if (!$user) {
|
||||
// No user found and auto creation is disabled - redirect to normal login
|
||||
if (!$driver->shouldCreateMissingUsers()) {
|
||||
Notification::make()
|
||||
->title('No linked User found')
|
||||
->danger()
|
||||
->persistent()
|
||||
->send();
|
||||
|
||||
return redirect()->route('auth.login');
|
||||
return redirect()->route('auth.login');
|
||||
}
|
||||
|
||||
$username = $oauthUser->getNickname();
|
||||
$email = $oauthUser->getEmail();
|
||||
|
||||
// Incomplete data, can't create user - redirect to normal login
|
||||
if (!$email) {
|
||||
Notification::make()
|
||||
->title('No linked User found')
|
||||
->danger()
|
||||
->persistent()
|
||||
->send();
|
||||
|
||||
return redirect()->route('auth.login');
|
||||
}
|
||||
|
||||
$user = $this->userCreation->handle([
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'oauth' => [
|
||||
$driver->getId() => $oauthUser->getId(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->auth->guard()->login($user, true);
|
||||
|
||||
return redirect('/');
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,8 @@
|
||||
|
||||
namespace App\Http\Requests\Api\Remote;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class InstallationDataRequest extends FormRequest
|
||||
class InstallationDataRequest extends ServerRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string|string[]>
|
||||
*/
|
||||
|
21
app/Http/Requests/Api/Remote/ServerRequest.php
Normal file
21
app/Http/Requests/Api/Remote/ServerRequest.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api\Remote;
|
||||
|
||||
use App\Models\Node;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ServerRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
/** @var Node $node */
|
||||
$node = $this->attributes->get('node');
|
||||
|
||||
/** @var ?Server $server */
|
||||
$server = $this->route()->parameter('server');
|
||||
|
||||
return $server && $server->node_id === $node->id;
|
||||
}
|
||||
}
|
@ -2,16 +2,16 @@
|
||||
|
||||
namespace App\Services\Nodes;
|
||||
|
||||
use App\Extensions\Lcobucci\JWT\Encoding\TimestampDates;
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTimeImmutable;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Node;
|
||||
use App\Models\User;
|
||||
use Lcobucci\JWT\Token\Plain;
|
||||
use Lcobucci\JWT\Configuration;
|
||||
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||
use Lcobucci\JWT\Signer\Key\InMemory;
|
||||
use App\Extensions\Lcobucci\JWT\Encoding\TimestampDates;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
|
||||
class NodeJWTService
|
||||
{
|
||||
@ -64,7 +64,7 @@ class NodeJWTService
|
||||
/**
|
||||
* Generate a new JWT for a given node.
|
||||
*/
|
||||
public function handle(Node $node, ?string $identifiedBy, string $algo = 'md5'): Plain
|
||||
public function handle(Node $node, ?string $identifiedBy, string $algo = 'sha256'): UnencryptedToken
|
||||
{
|
||||
$identifier = hash($algo, $identifiedBy);
|
||||
$config = Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($node->daemon_token));
|
||||
@ -80,7 +80,9 @@ class NodeJWTService
|
||||
$builder = $builder->expiresAt($this->expiresAt);
|
||||
|
||||
if (!empty($this->subject)) {
|
||||
$builder = $builder->relatedTo($this->subject)->withHeader('sub', $this->subject);
|
||||
$builder = $builder
|
||||
->relatedTo($this->subject)
|
||||
->withHeader('sub', $this->subject);
|
||||
}
|
||||
|
||||
foreach ($this->claims as $key => $value) {
|
||||
@ -88,14 +90,7 @@ class NodeJWTService
|
||||
}
|
||||
|
||||
if (!is_null($this->user)) {
|
||||
$builder = $builder
|
||||
->withClaim('user_uuid', $this->user->uuid)
|
||||
// The "user_id" claim is deprecated and should not be referenced — it remains
|
||||
// here solely to ensure older versions of daemon are unaffected when the Panel
|
||||
// is updated.
|
||||
//
|
||||
// This claim will be removed in Panel@1.11 or later.
|
||||
->withClaim('user_id', $this->user->id);
|
||||
$builder = $builder->withClaim('user_uuid', $this->user->uuid);
|
||||
}
|
||||
|
||||
return $builder
|
||||
|
@ -44,15 +44,7 @@ class ServerCreationService
|
||||
* as possible given the input data. For example, if an allocation_id is passed with
|
||||
* no node_id the node_is will be picked from the allocation.
|
||||
*
|
||||
* @param array{
|
||||
* node_id?: int,
|
||||
* oom_killer?: bool,
|
||||
* oom_disabled?: bool,
|
||||
* egg_id?: int,
|
||||
* image?: ?string,
|
||||
* startup?: ?string,
|
||||
* start_on_completion?: ?bool,
|
||||
* } $data
|
||||
* @param array<mixed, mixed> $data
|
||||
*
|
||||
* @throws Throwable
|
||||
* @throws DisplayException
|
||||
@ -99,6 +91,8 @@ class ServerCreationService
|
||||
if (empty($data['node_id'])) {
|
||||
$data['node_id'] = $nodes->first();
|
||||
}
|
||||
} else {
|
||||
$data['node_id'] = Allocation::find($data['allocation_id'])?->node_id;
|
||||
}
|
||||
|
||||
Assert::false(empty($data['node_id']), 'Expected a non-empty node_id in server creation data.');
|
||||
|
@ -11,7 +11,7 @@ use App\Services\Nodes\NodeJWTService;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Lcobucci\JWT\Token\Plain;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
|
||||
class TransferServerService
|
||||
{
|
||||
@ -23,7 +23,7 @@ class TransferServerService
|
||||
private NodeJWTService $nodeJWTService,
|
||||
) {}
|
||||
|
||||
private function notify(ServerTransfer $transfer, Plain $token): void
|
||||
private function notify(ServerTransfer $transfer, UnencryptedToken $token): void
|
||||
{
|
||||
Http::daemon($transfer->oldNode)->post("/api/servers/{$transfer->server->uuid}/transfer", [
|
||||
'url' => $transfer->newNode->getConnectionAddress() . '/api/transfers',
|
||||
|
@ -6,7 +6,6 @@ use App\Exceptions\Model\DataValidationException;
|
||||
use Throwable;
|
||||
use App\Events\Server\SubUserAdded;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Server;
|
||||
use App\Models\Subuser;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
@ -42,14 +41,8 @@ class SubuserCreationService
|
||||
return $this->connection->transaction(function () use ($server, $email, $permissions) {
|
||||
$user = User::withoutGlobalScopes()->where('email', $email)->first();
|
||||
if (!$user) {
|
||||
// Just cap the username generated at 64 characters at most and then append a random string
|
||||
// to the end to make it "unique"...
|
||||
[$beforeDomain] = explode('@', $email, 1);
|
||||
$username = substr(preg_replace('/([^\w.-]+)/', '', $beforeDomain), 0, 64) . Str::random(3);
|
||||
|
||||
$user = $this->userCreationService->handle([
|
||||
'email' => $email,
|
||||
'username' => $username,
|
||||
'root_admin' => false,
|
||||
]);
|
||||
} else {
|
||||
|
@ -5,6 +5,7 @@ namespace App\Services\Users;
|
||||
use Exception;
|
||||
use App\Exceptions\Model\DataValidationException;
|
||||
use App\Models\Role;
|
||||
use Illuminate\Support\Str;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
@ -44,6 +45,16 @@ class UserCreationService
|
||||
$isRootAdmin = array_key_exists('root_admin', $data) && $data['root_admin'];
|
||||
unset($data['root_admin']);
|
||||
|
||||
if (empty($data['username'])) {
|
||||
$data['username'] = str($data['email'])->before('@')->toString() . Str::random(3);
|
||||
}
|
||||
|
||||
$data['username'] = str($data['username'])
|
||||
->replace(['.', '-'], '')
|
||||
->ascii()
|
||||
->substr(0, 64)
|
||||
->toString();
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::query()->forceCreate(array_merge($data, [
|
||||
'uuid' => Uuid::uuid4()->toString(),
|
||||
|
@ -45,6 +45,7 @@ services:
|
||||
<<: [*panel-environment, *mail-environment]
|
||||
XDG_DATA_HOME: /pelican-data
|
||||
# SKIP_CADDY: true # enable when not using caddy.
|
||||
TRUSTED_PROXIES:
|
||||
|
||||
volumes:
|
||||
pelican-data:
|
||||
|
@ -13,15 +13,15 @@
|
||||
"calebporzio/sushi": "^2.5",
|
||||
"dedoc/scramble": "^0.12.10",
|
||||
"doctrine/dbal": "~3.6.0",
|
||||
"filament/filament": "4.0.0-beta22",
|
||||
"filament/filament": "4.0.0-beta25",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"laravel/framework": "^12.21",
|
||||
"laravel/framework": "^12.22",
|
||||
"laravel/helpers": "^1.7",
|
||||
"laravel/sanctum": "^4.1",
|
||||
"laravel/socialite": "^5.21",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"laravel/ui": "^4.6",
|
||||
"lcobucci/jwt": "~4.3.0",
|
||||
"lcobucci/jwt": "^5.5",
|
||||
"league/flysystem-aws-s3-v3": "^3.29",
|
||||
"league/flysystem-memory": "^3.29",
|
||||
"phpseclib/phpseclib": "~3.0.18",
|
||||
|
433
composer.lock
generated
433
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": "6bf532c77a50b48ff70400ca649c8de9",
|
||||
"content-hash": "be2f0e0bdd59e886fd0a64dda84fa95d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "amphp/amp",
|
||||
@ -936,16 +936,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.351.3",
|
||||
"version": "3.352.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "7c58f4a8acd2230daad1ef23bceb9972e62bdf94"
|
||||
"reference": "06d8e8c85f91e957f48480ce41e9c8a6d9fa253f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7c58f4a8acd2230daad1ef23bceb9972e62bdf94",
|
||||
"reference": "7c58f4a8acd2230daad1ef23bceb9972e62bdf94",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/06d8e8c85f91e957f48480ce41e9c8a6d9fa253f",
|
||||
"reference": "06d8e8c85f91e957f48480ce41e9c8a6d9fa253f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1027,9 +1027,9 @@
|
||||
"support": {
|
||||
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.351.3"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.352.6"
|
||||
},
|
||||
"time": "2025-07-21T18:04:02+00:00"
|
||||
"time": "2025-08-11T18:04:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "blade-ui-kit/blade-heroicons",
|
||||
@ -1674,16 +1674,16 @@
|
||||
},
|
||||
{
|
||||
"name": "dedoc/scramble",
|
||||
"version": "v0.12.23",
|
||||
"version": "v0.12.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dedoc/scramble.git",
|
||||
"reference": "5b650167c81c59138e844c2ae550c14dc1a249d0"
|
||||
"reference": "f06a98d1fd6678544428df7077d73194e2d28de3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dedoc/scramble/zipball/5b650167c81c59138e844c2ae550c14dc1a249d0",
|
||||
"reference": "5b650167c81c59138e844c2ae550c14dc1a249d0",
|
||||
"url": "https://api.github.com/repos/dedoc/scramble/zipball/f06a98d1fd6678544428df7077d73194e2d28de3",
|
||||
"reference": "f06a98d1fd6678544428df7077d73194e2d28de3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1742,7 +1742,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dedoc/scramble/issues",
|
||||
"source": "https://github.com/dedoc/scramble/tree/v0.12.23"
|
||||
"source": "https://github.com/dedoc/scramble/tree/v0.12.28"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1750,7 +1750,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-15T09:04:49+00:00"
|
||||
"time": "2025-08-04T12:20:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dflydev/dot-access-data",
|
||||
@ -2174,33 +2174,32 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
"version": "2.0.10",
|
||||
"version": "2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/inflector.git",
|
||||
"reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc"
|
||||
"reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc",
|
||||
"reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc",
|
||||
"url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b",
|
||||
"reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^11.0",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.3",
|
||||
"phpunit/phpunit": "^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.25 || ^5.4"
|
||||
"doctrine/coding-standard": "^12.0 || ^13.0",
|
||||
"phpstan/phpstan": "^1.12 || ^2.0",
|
||||
"phpstan/phpstan-phpunit": "^1.4 || ^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.6 || ^2.0",
|
||||
"phpunit/phpunit": "^8.5 || ^12.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
|
||||
"Doctrine\\Inflector\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@ -2245,7 +2244,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/inflector/issues",
|
||||
"source": "https://github.com/doctrine/inflector/tree/2.0.10"
|
||||
"source": "https://github.com/doctrine/inflector/tree/2.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2261,7 +2260,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-18T20:23:39+00:00"
|
||||
"time": "2025-08-10T19:31:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
@ -2474,16 +2473,16 @@
|
||||
},
|
||||
{
|
||||
"name": "filament/actions",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/actions.git",
|
||||
"reference": "97fec740f57241c2537c8ddf6a8c22ad34cf96de"
|
||||
"reference": "8b8eef43e31f86681d7c8f1a8d8400afa9172442"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/actions/zipball/97fec740f57241c2537c8ddf6a8c22ad34cf96de",
|
||||
"reference": "97fec740f57241c2537c8ddf6a8c22ad34cf96de",
|
||||
"url": "https://api.github.com/repos/filamentphp/actions/zipball/8b8eef43e31f86681d7c8f1a8d8400afa9172442",
|
||||
"reference": "8b8eef43e31f86681d7c8f1a8d8400afa9172442",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2519,20 +2518,20 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-05T09:46:29+00:00"
|
||||
"time": "2025-08-11T19:29:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/filament",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/panels.git",
|
||||
"reference": "ada74566525dbcf2e9dcae03f493ac5948216fb7"
|
||||
"reference": "dc8306c984d0d52b0b8365b5e66bb7c43b81784b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/panels/zipball/ada74566525dbcf2e9dcae03f493ac5948216fb7",
|
||||
"reference": "ada74566525dbcf2e9dcae03f493ac5948216fb7",
|
||||
"url": "https://api.github.com/repos/filamentphp/panels/zipball/dc8306c984d0d52b0b8365b5e66bb7c43b81784b",
|
||||
"reference": "dc8306c984d0d52b0b8365b5e66bb7c43b81784b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2576,20 +2575,20 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-04T10:36:20+00:00"
|
||||
"time": "2025-08-11T19:28:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/forms",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/forms.git",
|
||||
"reference": "c1b3e830850d276669a0a8eeb2a43bf8d1b4d330"
|
||||
"reference": "cb06cbd7855a178fd9c1db88ad5f3ecad7d993a1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/forms/zipball/c1b3e830850d276669a0a8eeb2a43bf8d1b4d330",
|
||||
"reference": "c1b3e830850d276669a0a8eeb2a43bf8d1b4d330",
|
||||
"url": "https://api.github.com/repos/filamentphp/forms/zipball/cb06cbd7855a178fd9c1db88ad5f3ecad7d993a1",
|
||||
"reference": "cb06cbd7855a178fd9c1db88ad5f3ecad7d993a1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2626,20 +2625,20 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-04T10:36:15+00:00"
|
||||
"time": "2025-08-11T19:29:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/infolists",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/infolists.git",
|
||||
"reference": "0371df3b6423c9bd85a49d947cb1836eb2f2324a"
|
||||
"reference": "749e080d195fc94dcaa3b1bc1545e0e4b95d4703"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/infolists/zipball/0371df3b6423c9bd85a49d947cb1836eb2f2324a",
|
||||
"reference": "0371df3b6423c9bd85a49d947cb1836eb2f2324a",
|
||||
"url": "https://api.github.com/repos/filamentphp/infolists/zipball/749e080d195fc94dcaa3b1bc1545e0e4b95d4703",
|
||||
"reference": "749e080d195fc94dcaa3b1bc1545e0e4b95d4703",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2671,11 +2670,11 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-05T09:46:25+00:00"
|
||||
"time": "2025-08-11T19:29:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/notifications",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/notifications.git",
|
||||
@ -2722,16 +2721,16 @@
|
||||
},
|
||||
{
|
||||
"name": "filament/schemas",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/schemas.git",
|
||||
"reference": "b4175cca16f6f09f0c409f6dfc0abb446dc31675"
|
||||
"reference": "407e656aab02840781161648ea4a3f4c96de6570"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/schemas/zipball/b4175cca16f6f09f0c409f6dfc0abb446dc31675",
|
||||
"reference": "b4175cca16f6f09f0c409f6dfc0abb446dc31675",
|
||||
"url": "https://api.github.com/repos/filamentphp/schemas/zipball/407e656aab02840781161648ea4a3f4c96de6570",
|
||||
"reference": "407e656aab02840781161648ea4a3f4c96de6570",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2763,20 +2762,20 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-05T09:46:35+00:00"
|
||||
"time": "2025-08-11T19:28:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/support",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/support.git",
|
||||
"reference": "89463a9f6bebc72cb91f41634dae9275664d2687"
|
||||
"reference": "1c6ed2b3697600f5213bee6760e0f709a746a968"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/support/zipball/89463a9f6bebc72cb91f41634dae9275664d2687",
|
||||
"reference": "89463a9f6bebc72cb91f41634dae9275664d2687",
|
||||
"url": "https://api.github.com/repos/filamentphp/support/zipball/1c6ed2b3697600f5213bee6760e0f709a746a968",
|
||||
"reference": "1c6ed2b3697600f5213bee6760e0f709a746a968",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2821,20 +2820,20 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-04T10:36:21+00:00"
|
||||
"time": "2025-08-10T20:27:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/tables",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/tables.git",
|
||||
"reference": "9b2441ee99e6e95d28df394588827a5bbb71c7fe"
|
||||
"reference": "a2d45bc8741044a0409e8e9fd81abcc3999e24ef"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/tables/zipball/9b2441ee99e6e95d28df394588827a5bbb71c7fe",
|
||||
"reference": "9b2441ee99e6e95d28df394588827a5bbb71c7fe",
|
||||
"url": "https://api.github.com/repos/filamentphp/tables/zipball/a2d45bc8741044a0409e8e9fd81abcc3999e24ef",
|
||||
"reference": "a2d45bc8741044a0409e8e9fd81abcc3999e24ef",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2866,20 +2865,20 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-05T09:46:36+00:00"
|
||||
"time": "2025-08-11T19:29:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "filament/widgets",
|
||||
"version": "v4.0.0-beta22",
|
||||
"version": "v4.0.0-beta25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filamentphp/widgets.git",
|
||||
"reference": "03bb26c9c072f4f26dcd0c9b2b0bd8232e91abcc"
|
||||
"reference": "ec65855e6b572900eefbb514608fb2ce92abb8d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filamentphp/widgets/zipball/03bb26c9c072f4f26dcd0c9b2b0bd8232e91abcc",
|
||||
"reference": "03bb26c9c072f4f26dcd0c9b2b0bd8232e91abcc",
|
||||
"url": "https://api.github.com/repos/filamentphp/widgets/zipball/ec65855e6b572900eefbb514608fb2ce92abb8d0",
|
||||
"reference": "ec65855e6b572900eefbb514608fb2ce92abb8d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2910,7 +2909,7 @@
|
||||
"issues": "https://github.com/filamentphp/filament/issues",
|
||||
"source": "https://github.com/filamentphp/filament"
|
||||
},
|
||||
"time": "2025-08-05T09:46:27+00:00"
|
||||
"time": "2025-08-10T20:27:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "firebase/php-jwt",
|
||||
@ -3642,16 +3641,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v12.21.0",
|
||||
"version": "v12.22.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "ac8c4e73bf1b5387b709f7736d41427e6af1c93b"
|
||||
"reference": "d33ee45184126f32f593d4b809a846ed88a1dc43"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/ac8c4e73bf1b5387b709f7736d41427e6af1c93b",
|
||||
"reference": "ac8c4e73bf1b5387b709f7736d41427e6af1c93b",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/d33ee45184126f32f593d4b809a846ed88a1dc43",
|
||||
"reference": "d33ee45184126f32f593d4b809a846ed88a1dc43",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3853,7 +3852,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2025-07-22T15:41:55+00:00"
|
||||
"time": "2025-08-08T13:58:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/helpers",
|
||||
@ -4098,16 +4097,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/socialite",
|
||||
"version": "v5.22.0",
|
||||
"version": "v5.23.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/socialite.git",
|
||||
"reference": "99d0fe750a7c68e5b60d8b1850de2554f3ea4072"
|
||||
"reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/99d0fe750a7c68e5b60d8b1850de2554f3ea4072",
|
||||
"reference": "99d0fe750a7c68e5b60d8b1850de2554f3ea4072",
|
||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5",
|
||||
"reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4166,7 +4165,7 @@
|
||||
"issues": "https://github.com/laravel/socialite/issues",
|
||||
"source": "https://github.com/laravel/socialite"
|
||||
},
|
||||
"time": "2025-07-08T22:07:57+00:00"
|
||||
"time": "2025-07-23T14:16:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/tinker",
|
||||
@ -4297,105 +4296,40 @@
|
||||
},
|
||||
"time": "2025-01-28T15:15:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/clock",
|
||||
"version": "3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/clock.git",
|
||||
"reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/clock/zipball/db3713a61addfffd615b79bf0bc22f0ccc61b86b",
|
||||
"reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.2.0 || ~8.3.0 || ~8.4.0",
|
||||
"psr/clock": "^1.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/clock-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.29",
|
||||
"lcobucci/coding-standard": "^11.1.0",
|
||||
"phpstan/extension-installer": "^1.3.1",
|
||||
"phpstan/phpstan": "^1.10.25",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1.3",
|
||||
"phpstan/phpstan-phpunit": "^1.3.13",
|
||||
"phpstan/phpstan-strict-rules": "^1.5.1",
|
||||
"phpunit/phpunit": "^11.3.6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lcobucci\\Clock\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Luís Cobucci",
|
||||
"email": "lcobucci@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Yet another clock abstraction",
|
||||
"support": {
|
||||
"issues": "https://github.com/lcobucci/clock/issues",
|
||||
"source": "https://github.com/lcobucci/clock/tree/3.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/lcobucci",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/lcobucci",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-24T20:45:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "4.3.0",
|
||||
"version": "5.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/jwt.git",
|
||||
"reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4"
|
||||
"reference": "a835af59b030d3f2967725697cf88300f579088e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/4d7de2fe0d51a96418c0d04004986e410e87f6b4",
|
||||
"reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e",
|
||||
"reference": "a835af59b030d3f2967725697cf88300f579088e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-hash": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-sodium": "*",
|
||||
"lcobucci/clock": "^2.0 || ^3.0",
|
||||
"php": "^7.4 || ^8.0"
|
||||
"php": "~8.2.0 || ~8.3.0 || ~8.4.0",
|
||||
"psr/clock": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.21",
|
||||
"lcobucci/coding-standard": "^6.0",
|
||||
"mikey179/vfsstream": "^1.6.7",
|
||||
"infection/infection": "^0.29",
|
||||
"lcobucci/clock": "^3.2",
|
||||
"lcobucci/coding-standard": "^11.0",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/php-invoker": "^3.1",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.10.7",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1.3",
|
||||
"phpstan/phpstan-phpunit": "^1.3.10",
|
||||
"phpstan/phpstan-strict-rules": "^1.5.0",
|
||||
"phpunit/phpunit": "^11.1"
|
||||
},
|
||||
"suggest": {
|
||||
"lcobucci/clock": ">= 3.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -4421,7 +4355,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/lcobucci/jwt/issues",
|
||||
"source": "https://github.com/lcobucci/jwt/tree/4.3.0"
|
||||
"source": "https://github.com/lcobucci/jwt/tree/5.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4433,7 +4367,7 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-02T13:28:00+00:00"
|
||||
"time": "2025-01-26T21:29:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
@ -5722,16 +5656,16 @@
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.13.3",
|
||||
"version": "1.13.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
|
||||
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
|
||||
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -5770,7 +5704,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -5778,7 +5712,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-05T12:25:42+00:00"
|
||||
"time": "2025-08-01T08:46:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
@ -6025,12 +5959,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "34f1ba0f5576d7433a7c60fad946ec0667d44620"
|
||||
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/34f1ba0f5576d7433a7c60fad946ec0667d44620",
|
||||
"reference": "34f1ba0f5576d7433a7c60fad946ec0667d44620",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
|
||||
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6106,20 +6040,20 @@
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.8"
|
||||
},
|
||||
"time": "2025-08-01T02:17:40+00:00"
|
||||
"time": "2025-08-06T21:43:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.5.0",
|
||||
"version": "v5.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
|
||||
"reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
|
||||
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56",
|
||||
"reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6162,9 +6096,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0"
|
||||
},
|
||||
"time": "2025-05-31T08:24:38+00:00"
|
||||
"time": "2025-07-27T20:03:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/termwind",
|
||||
@ -7586,16 +7520,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.12.9",
|
||||
"version": "v0.12.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "1b801844becfe648985372cb4b12ad6840245ace"
|
||||
"reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/1b801844becfe648985372cb4b12ad6840245ace",
|
||||
"reference": "1b801844becfe648985372cb4b12ad6840245ace",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/6e80abe6f2257121f1eb9a4c55bf29d921025b22",
|
||||
"reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -7645,12 +7579,11 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Justin Hileman",
|
||||
"email": "justin@justinhileman.info",
|
||||
"homepage": "http://justinhileman.com"
|
||||
"email": "justin@justinhileman.info"
|
||||
}
|
||||
],
|
||||
"description": "An interactive shell for modern PHP.",
|
||||
"homepage": "http://psysh.org",
|
||||
"homepage": "https://psysh.org",
|
||||
"keywords": [
|
||||
"REPL",
|
||||
"console",
|
||||
@ -7659,9 +7592,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.9"
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.10"
|
||||
},
|
||||
"time": "2025-06-23T02:35:06+00:00"
|
||||
"time": "2025-08-04T12:39:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
@ -8790,16 +8723,16 @@
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-health",
|
||||
"version": "1.34.4",
|
||||
"version": "1.34.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-health.git",
|
||||
"reference": "ac04fb0b82b4c89ab88c18897f9eda4e559d624b"
|
||||
"reference": "8487a3a43551f3d24e73546362f93da2684a0a3a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-health/zipball/ac04fb0b82b4c89ab88c18897f9eda4e559d624b",
|
||||
"reference": "ac04fb0b82b4c89ab88c18897f9eda4e559d624b",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-health/zipball/8487a3a43551f3d24e73546362f93da2684a0a3a",
|
||||
"reference": "8487a3a43551f3d24e73546362f93da2684a0a3a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8871,7 +8804,7 @@
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/spatie/laravel-health/tree/1.34.4"
|
||||
"source": "https://github.com/spatie/laravel-health/tree/1.34.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -8879,7 +8812,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-22T08:06:42+00:00"
|
||||
"time": "2025-07-25T07:00:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
@ -8944,16 +8877,16 @@
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-permission",
|
||||
"version": "6.20.0",
|
||||
"version": "6.21.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-permission.git",
|
||||
"reference": "31c05679102c73f3b0d05790d2400182745a5615"
|
||||
"reference": "6a118e8855dfffcd90403aab77bbf35a03db51b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/31c05679102c73f3b0d05790d2400182745a5615",
|
||||
"reference": "31c05679102c73f3b0d05790d2400182745a5615",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/6a118e8855dfffcd90403aab77bbf35a03db51b3",
|
||||
"reference": "6a118e8855dfffcd90403aab77bbf35a03db51b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -9015,7 +8948,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-permission/issues",
|
||||
"source": "https://github.com/spatie/laravel-permission/tree/6.20.0"
|
||||
"source": "https://github.com/spatie/laravel-permission/tree/6.21.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -9023,20 +8956,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-05T07:33:07+00:00"
|
||||
"time": "2025-07-23T16:08:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-query-builder",
|
||||
"version": "6.3.3",
|
||||
"version": "6.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-query-builder.git",
|
||||
"reference": "0d80323d2b2ffc410f06bf73c2e3a6ad763e4b8d"
|
||||
"reference": "ee3c98235616f88c11e75d3df5ea48dc7b20dd93"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-query-builder/zipball/0d80323d2b2ffc410f06bf73c2e3a6ad763e4b8d",
|
||||
"reference": "0d80323d2b2ffc410f06bf73c2e3a6ad763e4b8d",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-query-builder/zipball/ee3c98235616f88c11e75d3df5ea48dc7b20dd93",
|
||||
"reference": "ee3c98235616f88c11e75d3df5ea48dc7b20dd93",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -9097,7 +9030,7 @@
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-14T08:31:42+00:00"
|
||||
"time": "2025-08-04T07:36:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/php-structure-discoverer",
|
||||
@ -10051,16 +9984,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.3.1",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "4403d87a2c16f33345dca93407a8714ee8c05a64"
|
||||
"reference": "1c064a0c67749923483216b081066642751cc2c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/4403d87a2c16f33345dca93407a8714ee8c05a64",
|
||||
"reference": "4403d87a2c16f33345dca93407a8714ee8c05a64",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7",
|
||||
"reference": "1c064a0c67749923483216b081066642751cc2c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -10126,7 +10059,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.3.1"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -10137,12 +10070,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-28T07:58:39+00:00"
|
||||
"time": "2025-07-15T11:36:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@ -12032,16 +11969,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v7.3.1",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "0c3555045a46ab3cd4cc5a69d161225195230edb"
|
||||
"reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/0c3555045a46ab3cd4cc5a69d161225195230edb",
|
||||
"reference": "0c3555045a46ab3cd4cc5a69d161225195230edb",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/b8d7d868da9eb0919e99c8830431ea087d6aae30",
|
||||
"reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -12084,7 +12021,7 @@
|
||||
"description": "Loads and dumps YAML files",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/yaml/tree/v7.3.1"
|
||||
"source": "https://github.com/symfony/yaml/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -12095,12 +12032,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-03T06:57:57+00:00"
|
||||
"time": "2025-07-10T08:47:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tijsverkoyen/css-to-inline-styles",
|
||||
@ -12961,16 +12902,16 @@
|
||||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.18.3",
|
||||
"version": "2.18.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "59a123a3d459c5a23055802237cb317f609867e5"
|
||||
"reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5",
|
||||
"reference": "59a123a3d459c5a23055802237cb317f609867e5",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d",
|
||||
"reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -13020,7 +12961,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/filp/whoops/issues",
|
||||
"source": "https://github.com/filp/whoops/tree/2.18.3"
|
||||
"source": "https://github.com/filp/whoops/tree/2.18.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -13028,7 +12969,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-16T00:02:10+00:00"
|
||||
"time": "2025-08-08T12:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
@ -14903,16 +14844,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "6.3.1",
|
||||
"version": "6.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959"
|
||||
"reference": "85c77556683e6eee4323e4c5468641ca0237e2e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959",
|
||||
"reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8",
|
||||
"reference": "85c77556683e6eee4323e4c5468641ca0237e2e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -14971,15 +14912,27 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1"
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-07T06:57:01+00:00"
|
||||
"time": "2025-08-10T08:07:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
@ -15560,16 +15513,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/type",
|
||||
"version": "5.1.2",
|
||||
"version": "5.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/type.git",
|
||||
"reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e"
|
||||
"reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e",
|
||||
"reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449",
|
||||
"reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -15605,15 +15558,27 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/type/issues",
|
||||
"security": "https://github.com/sebastianbergmann/type/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/type/tree/5.1.2"
|
||||
"source": "https://github.com/sebastianbergmann/type/tree/5.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/sebastian/type",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-18T13:35:50+00:00"
|
||||
"time": "2025-08-09T06:55:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
|
@ -1,12 +1,17 @@
|
||||
{
|
||||
admin off
|
||||
email {$ADMIN_EMAIL}
|
||||
servers {
|
||||
## docs https://caddyserver.com/docs/caddyfile/options#trusted-proxies
|
||||
{$CADDY_TRUSTED_PROXIES}
|
||||
{$CADDY_STRICT_PROXIES}
|
||||
}
|
||||
admin off
|
||||
auto_https off
|
||||
email {$ADMIN_EMAIL}
|
||||
}
|
||||
|
||||
{$APP_URL} {
|
||||
root * /var/www/html/public
|
||||
encode gzip
|
||||
root * /var/www/html/public
|
||||
encode gzip
|
||||
|
||||
php_fastcgi 127.0.0.1:9000
|
||||
file_server
|
||||
php_fastcgi 127.0.0.1:9000
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#!/bin/ash -e
|
||||
|
||||
## check for .env file or symlink and generate app keys if missing
|
||||
if [ -f /var/www/html/.env ]; then
|
||||
echo "external vars exist."
|
||||
@ -23,6 +22,8 @@ else
|
||||
echo -e "APP_INSTALLED=false" >> /pelican-data/.env
|
||||
fi
|
||||
|
||||
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = ${UPLOAD_LIMIT}M/" /usr/local/etc/php/php.ini-production
|
||||
|
||||
mkdir -p /pelican-data/database /pelican-data/storage/avatars /pelican-data/storage/fonts /var/www/html/storage/logs/supervisord 2>/dev/null
|
||||
|
||||
if ! grep -q "APP_KEY=" .env || grep -q "APP_KEY=$" .env; then
|
||||
@ -39,6 +40,7 @@ php artisan migrate --force
|
||||
echo -e "Optimizing Filament"
|
||||
php artisan filament:optimize
|
||||
|
||||
# default to caddy not starting
|
||||
export SUPERVISORD_CADDY=false
|
||||
|
||||
## disable caddy if SKIP_CADDY is set
|
||||
@ -46,7 +48,14 @@ if [[ "${SKIP_CADDY:-}" == "true" ]]; then
|
||||
echo "Starting PHP-FPM only"
|
||||
else
|
||||
echo "Starting PHP-FPM and Caddy"
|
||||
# enable caddy
|
||||
export SUPERVISORD_CADDY=true
|
||||
|
||||
# handle trusted proxies for caddy
|
||||
if [[ ! -z ${TRUSTED_PROXIES} ]]; then
|
||||
export CADDY_TRUSTED_PROXIES=$(echo "trusted_proxies static ${TRUSTED_PROXIES}" | sed 's/,/ /g')
|
||||
export CADDY_STRICT_PROXIES="trusted_proxies_strict"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Starting Supervisord"
|
||||
|
9
docker/healthcheck.sh
Normal file
9
docker/healthcheck.sh
Normal file
@ -0,0 +1,9 @@
|
||||
#!/bin/ash -e
|
||||
|
||||
if [ ${SKIP_CADDY} ! "true" ]; then
|
||||
curl -f http://localhost/up || exit 1
|
||||
fi
|
||||
|
||||
cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 2
|
||||
|
||||
exit 0
|
@ -97,6 +97,7 @@ return [
|
||||
'base_url' => 'Base URL',
|
||||
'display_name' => 'Display Name',
|
||||
'auth_url' => 'Authorization callback URL',
|
||||
'create_missing_users' => 'Auto Create Missing Users?',
|
||||
],
|
||||
'misc' => [
|
||||
'auto_allocation' => [
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
function o({name:i,recordKey:s,state:a}){return{error:void 0,isLoading:!1,state:a,init(){Livewire.hook("commit",({component:e,commit:r,succeed:n,fail:h,respond:u})=>{n(({snapshot:f,effect:d})=>{this.$nextTick(()=>{if(this.isLoading||e.id!==this.$root.closest("[wire\\:id]").attributes["wire:id"].value)return;let t=this.getServerState();t===void 0||Alpine.raw(this.state)===t||(this.state=t)})})}),this.$watch("state",async()=>{let e=this.getServerState();if(e===void 0||Alpine.raw(this.state)===e)return;this.isLoading=!0;let r=await this.$wire.updateTableColumnState(i,s,this.state);this.error=r?.error??void 0,!this.error&&this.$refs.serverState&&(this.$refs.serverState.value=this.state?"1":"0"),this.isLoading=!1})},getServerState(){if(this.$refs.serverState)return[1,"1"].includes(this.$refs.serverState.value)}}}export{o as default};
|
||||
function o({name:i,recordKey:s,state:a}){return{error:void 0,isLoading:!1,state:a,init(){Livewire.hook("commit",({component:e,commit:r,succeed:n,fail:h,respond:u})=>{n(({snapshot:f,effect:d})=>{this.$nextTick(()=>{if(this.isLoading||e.id!==this.$root.closest("[wire\\:id]")?.attributes["wire:id"].value)return;let t=this.getServerState();t===void 0||Alpine.raw(this.state)===t||(this.state=t)})})}),this.$watch("state",async()=>{let e=this.getServerState();if(e===void 0||Alpine.raw(this.state)===e)return;this.isLoading=!0;let r=await this.$wire.updateTableColumnState(i,s,this.state);this.error=r?.error??void 0,!this.error&&this.$refs.serverState&&(this.$refs.serverState.value=this.state?"1":"0"),this.isLoading=!1})},getServerState(){if(this.$refs.serverState)return[1,"1"].includes(this.$refs.serverState.value)}}}export{o as default};
|
||||
|
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
function o({name:i,recordKey:s,state:a}){return{error:void 0,isLoading:!1,state:a,init(){Livewire.hook("commit",({component:e,commit:r,succeed:n,fail:d,respond:u})=>{n(({snapshot:f,effect:h})=>{this.$nextTick(()=>{if(this.isLoading||e.id!==this.$root.closest("[wire\\:id]").attributes["wire:id"].value)return;let t=this.getServerState();t===void 0||this.getNormalizedState()===t||(this.state=t)})})}),this.$watch("state",async()=>{let e=this.getServerState();if(e===void 0||this.getNormalizedState()===e)return;this.isLoading=!0;let r=await this.$wire.updateTableColumnState(i,s,this.state);this.error=r?.error??void 0,!this.error&&this.$refs.serverState&&(this.$refs.serverState.value=this.getNormalizedState()),this.isLoading=!1})},getServerState(){if(this.$refs.serverState)return[null,void 0].includes(this.$refs.serverState.value)?"":this.$refs.serverState.value.replaceAll('\\"','"')},getNormalizedState(){let e=Alpine.raw(this.state);return[null,void 0].includes(e)?"":e}}}export{o as default};
|
||||
function o({name:i,recordKey:s,state:a}){return{error:void 0,isLoading:!1,state:a,init(){Livewire.hook("commit",({component:e,commit:r,succeed:n,fail:d,respond:u})=>{n(({snapshot:f,effect:h})=>{this.$nextTick(()=>{if(this.isLoading||e.id!==this.$root.closest("[wire\\:id]")?.attributes["wire:id"].value)return;let t=this.getServerState();t===void 0||this.getNormalizedState()===t||(this.state=t)})})}),this.$watch("state",async()=>{let e=this.getServerState();if(e===void 0||this.getNormalizedState()===e)return;this.isLoading=!0;let r=await this.$wire.updateTableColumnState(i,s,this.state);this.error=r?.error??void 0,!this.error&&this.$refs.serverState&&(this.$refs.serverState.value=this.getNormalizedState()),this.isLoading=!1})},getServerState(){if(this.$refs.serverState)return[null,void 0].includes(this.$refs.serverState.value)?"":this.$refs.serverState.value.replaceAll('\\"','"')},getNormalizedState(){let e=Alpine.raw(this.state);return[null,void 0].includes(e)?"":e}}}export{o as default};
|
||||
|
@ -1 +1 @@
|
||||
function o({name:i,recordKey:s,state:a}){return{error:void 0,isLoading:!1,state:a,init(){Livewire.hook("commit",({component:e,commit:r,succeed:n,fail:h,respond:u})=>{n(({snapshot:f,effect:d})=>{this.$nextTick(()=>{if(this.isLoading||e.id!==this.$root.closest("[wire\\:id]").attributes["wire:id"].value)return;let t=this.getServerState();t===void 0||Alpine.raw(this.state)===t||(this.state=t)})})}),this.$watch("state",async()=>{let e=this.getServerState();if(e===void 0||Alpine.raw(this.state)===e)return;this.isLoading=!0;let r=await this.$wire.updateTableColumnState(i,s,this.state);this.error=r?.error??void 0,!this.error&&this.$refs.serverState&&(this.$refs.serverState.value=this.state?"1":"0"),this.isLoading=!1})},getServerState(){if(this.$refs.serverState)return[1,"1"].includes(this.$refs.serverState.value)}}}export{o as default};
|
||||
function o({name:i,recordKey:s,state:a}){return{error:void 0,isLoading:!1,state:a,init(){Livewire.hook("commit",({component:e,commit:r,succeed:n,fail:h,respond:u})=>{n(({snapshot:f,effect:d})=>{this.$nextTick(()=>{if(this.isLoading||e.id!==this.$root.closest("[wire\\:id]")?.attributes["wire:id"].value)return;let t=this.getServerState();t===void 0||Alpine.raw(this.state)===t||(this.state=t)})})}),this.$watch("state",async()=>{let e=this.getServerState();if(e===void 0||Alpine.raw(this.state)===e)return;this.isLoading=!0;let r=await this.$wire.updateTableColumnState(i,s,this.state);this.error=r?.error??void 0,!this.error&&this.$refs.serverState&&(this.$refs.serverState.value=this.state?"1":"0"),this.isLoading=!1})},getServerState(){if(this.$refs.serverState)return[1,"1"].includes(this.$refs.serverState.value)}}}export{o as default};
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,15 +8,12 @@ use Lcobucci\JWT\Configuration;
|
||||
use App\Models\Permission;
|
||||
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||
use Lcobucci\JWT\Signer\Key\InMemory;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use Lcobucci\JWT\Validation\Constraint\SignedWith;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
|
||||
class WebsocketControllerTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that a subuser attempting to connect to the websocket receives an error if they
|
||||
* do not explicitly have the permission.
|
||||
*/
|
||||
public function test_subuser_without_websocket_permission_receives_error(): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount([Permission::ACTION_CONTROL_RESTART]);
|
||||
@ -59,41 +56,34 @@ class WebsocketControllerTest extends ClientApiIntegrationTestCase
|
||||
$response->assertJsonStructure(['data' => ['token', 'socket']]);
|
||||
|
||||
$connection = $response->json('data.socket');
|
||||
$this->assertStringStartsWith('wss://', $connection, 'Failed asserting that websocket connection address has expected "wss://" prefix.');
|
||||
$this->assertStringEndsWith("/api/servers/$server->uuid/ws", $connection, 'Failed asserting that websocket connection address uses expected Daemon endpoint.');
|
||||
$this->assertStringStartsWith('wss://', $connection);
|
||||
$this->assertStringEndsWith("/api/servers/$server->uuid/ws", $connection);
|
||||
|
||||
$key = InMemory::plainText($server->node->daemon_token);
|
||||
$config = Configuration::forSymmetricSigner(new Sha256(), $key);
|
||||
|
||||
$config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->daemon_token));
|
||||
$config->setValidationConstraints(new SignedWith(new Sha256(), $key));
|
||||
/** @var \Lcobucci\JWT\Token\Plain $token */
|
||||
$token = $config->parser()->parse($response->json('data.token'));
|
||||
$this->assertInstanceOf(UnencryptedToken::class, $token);
|
||||
|
||||
$constraints = [new SignedWith(new Sha256(), $key)];
|
||||
$this->assertTrue(
|
||||
$config->validator()->validate($token, ...$config->validationConstraints()),
|
||||
$config->validator()->validate($token, ...$constraints),
|
||||
'Failed to validate that the JWT data returned was signed using the Node\'s secret key.'
|
||||
);
|
||||
|
||||
// The way we generate times for the JWT will truncate the microseconds from the
|
||||
// time, but CarbonImmutable::now() will include them, thus causing test failures.
|
||||
//
|
||||
// This little chunk of logic just strips those out by generating a new CarbonImmutable
|
||||
// instance from the current timestamp, which is how the JWT works. We also need to
|
||||
// switch to UTC here for consistency.
|
||||
$expect = CarbonImmutable::createFromTimestamp(CarbonImmutable::now()->getTimestamp())->timezone('UTC');
|
||||
$expect = CarbonImmutable::createFromTimestamp(CarbonImmutable::now()->getTimestamp())->timezone('UTC')->setMicroseconds(0);
|
||||
|
||||
// Check that the claims are generated correctly.
|
||||
$this->assertTrue($token->hasBeenIssuedBy(config('app.url')));
|
||||
$this->assertTrue($token->isPermittedFor($server->node->getConnectionAddress()));
|
||||
$this->assertEquals($expect, $token->claims()->get('iat'));
|
||||
$this->assertEquals($expect->subMinutes(5), $token->claims()->get('nbf'));
|
||||
$this->assertEquals($expect->addMinutes(10), $token->claims()->get('exp'));
|
||||
$this->assertSame($user->id, $token->claims()->get('user_id'));
|
||||
$this->assertSame($server->uuid, $token->claims()->get('server_uuid'));
|
||||
$this->assertSame(['*'], $token->claims()->get('permissions'));
|
||||
$claims = $token->claims();
|
||||
$this->assertSame(config('app.url'), $claims->get('iss'));
|
||||
$this->assertSame($server->node->getConnectionAddress(), $claims->get('aud')[0] ?? null);
|
||||
$this->assertEquals($expect, CarbonImmutable::instance($claims->get('iat'))->setMicroseconds(0));
|
||||
$this->assertEquals($expect->subMinutes(5), CarbonImmutable::instance($claims->get('nbf'))->setMicroseconds(0));
|
||||
$this->assertEquals($expect->addMinutes(10), CarbonImmutable::instance($claims->get('exp'))->setMicroseconds(0));
|
||||
$this->assertSame($user->uuid, $claims->get('user_uuid'));
|
||||
$this->assertSame($server->uuid, $claims->get('server_uuid'));
|
||||
$this->assertSame(['*'], $claims->get('permissions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the subuser's permissions are passed along correctly in the generated JWT.
|
||||
*/
|
||||
public function test_jwt_is_configured_correctly_for_server_subuser(): void
|
||||
{
|
||||
$permissions = [Permission::ACTION_WEBSOCKET_CONNECT, Permission::ACTION_CONTROL_CONSOLE];
|
||||
@ -107,17 +97,18 @@ class WebsocketControllerTest extends ClientApiIntegrationTestCase
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure(['data' => ['token', 'socket']]);
|
||||
|
||||
$config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->daemon_token));
|
||||
$config->setValidationConstraints(new SignedWith(new Sha256(), $key));
|
||||
/** @var \Lcobucci\JWT\Token\Plain $token */
|
||||
$token = $config->parser()->parse($response->json('data.token'));
|
||||
$key = InMemory::plainText($server->node->daemon_token);
|
||||
$config = Configuration::forSymmetricSigner(new Sha256(), $key);
|
||||
|
||||
$token = $config->parser()->parse($response->json('data.token'));
|
||||
$this->assertInstanceOf(UnencryptedToken::class, $token);
|
||||
|
||||
$constraints = [new SignedWith(new Sha256(), $key)];
|
||||
$this->assertTrue(
|
||||
$config->validator()->validate($token, ...$config->validationConstraints()),
|
||||
$config->validator()->validate($token, ...$constraints),
|
||||
'Failed to validate that the JWT data returned was signed using the Node\'s secret key.'
|
||||
);
|
||||
|
||||
// Check that the claims are generated correctly.
|
||||
$this->assertSame($permissions, $token->claims()->get('permissions'));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user