mirror of
https://github.com/manualdousuario/marreta.git
synced 2026-10-19 07:23:34 +00:00
fixes and cleanup
This commit is contained in:
parent
65ff1bd88f
commit
a2fda5cfa7
15 changed files with 78 additions and 72 deletions
11
.dockerignore
Normal file
11
.dockerignore
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
.git
|
||||
.github
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
storage/app/*
|
||||
storage/logs/*
|
||||
storage/framework/cache/data/*
|
||||
storage/framework/sessions/*
|
||||
storage/framework/views/*
|
||||
node_modules
|
||||
|
|
@ -6,14 +6,10 @@ APP_DEBUG=false
|
|||
APP_URL=http://localhost
|
||||
APP_LOCALE=pt-br
|
||||
|
||||
DNS_SERVERS=1.1.1.1,8.8.8.8
|
||||
|
||||
BROWSER_WS_ENDPOINT=ws://marreta_browser:9222
|
||||
BROWSER_TIMEOUT_MS=30000
|
||||
|
||||
DISABLE_CACHE=false
|
||||
CLEANUP_DAYS=7
|
||||
LOG_DAYS_TO_KEEP=7
|
||||
|
||||
# Proxy (optional)
|
||||
# PROXY_URL=
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -22,5 +22,3 @@
|
|||
Homestead.json
|
||||
Homestead.yaml
|
||||
Thumbs.db
|
||||
/cache
|
||||
/database
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ WORKDIR /var/www/html
|
|||
COPY . .
|
||||
|
||||
RUN composer install --no-interaction --optimize-autoloader --no-dev \
|
||||
&& php artisan config:cache \
|
||||
&& php artisan route:cache \
|
||||
&& php artisan view:cache
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ Agora modifique com suas preferencias:
|
|||
|
||||
- `APP_NAME`: Nome do seu Marreta
|
||||
- `APP_DESCRIPTION`: Conta pra que serve
|
||||
- `APP_URL`: Onde vai rodar, endereço completo com `https://`. Se você alterar a porta no docker-compose (ex: 8080:80), você também deve incluir a porta no SITE_URL (ex: https://seusite:8080)
|
||||
- `APP_LANGUAGE`: pt-br (Português Brasil), en (Inglês), es (Espanhol) ou de-de (Alemão), ru-ru (Russo)
|
||||
- `APP_URL`: Onde vai rodar, endereço completo com `https://`. Se você alterar a porta no docker-compose (ex: 8080:80), você também deve incluir a porta no APP_URL (ex: https://seusite:8080)
|
||||
- `APP_LOCALE`: pt-br (Português Brasil), en (Inglês), es (Espanhol) ou de-de (Alemão), ru-ru (Russo)
|
||||
- `ADMIN_EMAIL`: admin@marreta.local
|
||||
- `ADMIN_PASSWORD`: password
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enums\MarretaError;
|
||||
use App\Exceptions\MarretaException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\ProxyService;
|
||||
use App\Services\UrlNormalizer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
final class ProxyController extends Controller
|
||||
|
|
@ -19,19 +19,17 @@ final class ProxyController extends Controller
|
|||
private readonly UrlNormalizer $urlNormalizer,
|
||||
) {}
|
||||
|
||||
public function __invoke(Request $request, string $url): JsonResponse|RedirectResponse
|
||||
public function __invoke(Request $request, string $url): JsonResponse
|
||||
{
|
||||
$processed = $this->urlNormalizer->processRouteUrl($url, $request->query->all());
|
||||
|
||||
if (! $processed['valid']) {
|
||||
return redirect('/?message=INVALID_URL');
|
||||
}
|
||||
|
||||
if ($processed['needs_redirect']) {
|
||||
return redirect(config('marreta.site_url').'/api/'.$processed['url']);
|
||||
}
|
||||
$headers = ['Access-Control-Allow-Origin' => '*'];
|
||||
|
||||
try {
|
||||
$processed = $this->urlNormalizer->processRouteUrl($url, $request->query->all());
|
||||
|
||||
if (! $processed['valid']) {
|
||||
throw new MarretaException(MarretaError::InvalidUrl);
|
||||
}
|
||||
|
||||
$this->proxyService->analyze($processed['url']);
|
||||
|
||||
$displayUrl = preg_replace('#^https?://#', '', $processed['url']);
|
||||
|
|
@ -39,15 +37,9 @@ final class ProxyController extends Controller
|
|||
return response()->json([
|
||||
'status' => 200,
|
||||
'url' => config('marreta.site_url').'/p/'.$displayUrl,
|
||||
], 200, [
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Methods' => 'GET',
|
||||
]);
|
||||
], 200, $headers + ['Access-Control-Allow-Methods' => 'GET']);
|
||||
} catch (MarretaException $e) {
|
||||
$headers = [
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'X-Error-Type' => $e->errorType(),
|
||||
];
|
||||
$headers['X-Error-Type'] = $e->errorType();
|
||||
|
||||
if ($e->additionalInfo()) {
|
||||
$headers['X-Error-Info'] = $e->additionalInfo();
|
||||
|
|
@ -56,7 +48,7 @@ final class ProxyController extends Controller
|
|||
return response()->json([
|
||||
'status' => $e->error()->httpCode(),
|
||||
'error' => [
|
||||
'type' => $e->errorType(),
|
||||
'code' => $e->errorType(),
|
||||
'message' => $e->getMessage(),
|
||||
'details' => $e->additionalInfo() ?: null,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\MarretaCacheService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class HomeController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request, MarretaCacheService $cache): View|RedirectResponse
|
||||
public function __invoke(Request $request): View|RedirectResponse
|
||||
{
|
||||
app()->setLocale(config('marreta.language'));
|
||||
|
||||
|
|
@ -47,7 +46,6 @@ final class HomeController extends Controller
|
|||
'message' => $message,
|
||||
'message_type' => $messageType,
|
||||
'url' => $url,
|
||||
'cache_count' => $cache->getCacheFileCount(),
|
||||
'site_name' => config('marreta.site_name'),
|
||||
'site_description' => config('marreta.site_description'),
|
||||
'site_url' => config('marreta.site_url'),
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ final class ProxyService
|
|||
*/
|
||||
public function analyze(string $url): string
|
||||
{
|
||||
if (! preg_match('#^https?://#', $url)) {
|
||||
$url = 'https://'.$url;
|
||||
}
|
||||
|
||||
$host = parse_url($url, PHP_URL_HOST);
|
||||
if (! $host) {
|
||||
throw new MarretaException(MarretaError::InvalidUrl);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ final class UrlNormalizer
|
|||
$url = preg_replace('#/+#', '/', $url);
|
||||
$url = 'https://'.$url;
|
||||
|
||||
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
|
||||
if (! $this->isValidUrl($url)) {
|
||||
return ['valid' => false, 'url' => '', 'needs_redirect' => false];
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ final class UrlNormalizer
|
|||
{
|
||||
$url = trim($url);
|
||||
|
||||
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
|
||||
if (! $this->isValidUrl($url)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
@ -85,8 +85,21 @@ final class UrlNormalizer
|
|||
$cleaned .= isset($parts['query']) ? '?'.$parts['query'] : '';
|
||||
$cleaned .= isset($parts['fragment']) ? '#'.$parts['fragment'] : '';
|
||||
|
||||
$cleaned = preg_replace('/[\x00-\x1F\x7F]/', '', $cleaned);
|
||||
return preg_replace('/[\x00-\x1F\x7F]/', '', $cleaned);
|
||||
}
|
||||
|
||||
return (string) filter_var($cleaned, FILTER_SANITIZE_URL);
|
||||
/**
|
||||
* Validate a URL, tolerating non-ASCII characters that FILTER_VALIDATE_URL rejects
|
||||
* (e.g. accented letters in Wikipedia-style paths) by percent-encoding them first.
|
||||
*/
|
||||
private function isValidUrl(string $url): bool
|
||||
{
|
||||
$ascii = preg_replace_callback(
|
||||
'/[^\x21-\x7E]/',
|
||||
fn (array $m): string => rawurlencode($m[0]),
|
||||
$url,
|
||||
);
|
||||
|
||||
return filter_var($ascii, FILTER_VALIDATE_URL) !== false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,13 +41,11 @@
|
|||
"composer install",
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
|
||||
"@php artisan key:generate",
|
||||
"@php artisan migrate --force",
|
||||
"npm install",
|
||||
"npm run build"
|
||||
"@php artisan migrate --force"
|
||||
],
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --timeout=0\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --timeout=0\" \"php artisan pail --timeout=0\" --names=server,queue,logs --kill-others"
|
||||
],
|
||||
"test": [
|
||||
"@php artisan config:clear --ansi",
|
||||
|
|
|
|||
26
composer.lock
generated
26
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": "43bc61ffbf39fedb6f934290bc5fadf6",
|
||||
"content-hash": "4b8ce4c8ae1ef4c82a90d5d4ea094c21",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
|
|
@ -2211,16 +2211,16 @@
|
|||
},
|
||||
{
|
||||
"name": "kirschbaum-development/eloquent-power-joins",
|
||||
"version": "4.3.2",
|
||||
"version": "4.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kirschbaum-development/eloquent-power-joins.git",
|
||||
"reference": "33c189bd51a510c1ceba67222395ead08a29863a"
|
||||
"reference": "c609dbbe4ad2051b667e937f1ab554067519d64b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/33c189bd51a510c1ceba67222395ead08a29863a",
|
||||
"reference": "33c189bd51a510c1ceba67222395ead08a29863a",
|
||||
"url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/c609dbbe4ad2051b667e937f1ab554067519d64b",
|
||||
"reference": "c609dbbe4ad2051b667e937f1ab554067519d64b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2268,22 +2268,22 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/kirschbaum-development/eloquent-power-joins/issues",
|
||||
"source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.3.2"
|
||||
"source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.3.3"
|
||||
},
|
||||
"time": "2026-05-28T20:35:55+00:00"
|
||||
"time": "2026-07-23T11:41:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v13.21.1",
|
||||
"version": "v13.22.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "303b5f8dc899f89e8c38c350b639b8fbd193ed16"
|
||||
"reference": "d354afa45334cdac523fbc015f203a78d7e2f5c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/303b5f8dc899f89e8c38c350b639b8fbd193ed16",
|
||||
"reference": "303b5f8dc899f89e8c38c350b639b8fbd193ed16",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/d354afa45334cdac523fbc015f203a78d7e2f5c6",
|
||||
"reference": "d354afa45334cdac523fbc015f203a78d7e2f5c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2497,7 +2497,7 @@
|
|||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2026-07-21T14:27:35+00:00"
|
||||
"time": "2026-07-24T20:38:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
|
|
@ -10518,7 +10518,7 @@
|
|||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.3"
|
||||
"php": "^8.4"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.9.0"
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ return [
|
|||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'url' => env('DB_URL'),
|
||||
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||
'database' => env('DB_DATABASE', storage_path('app/database.sqlite')),
|
||||
'prefix' => '',
|
||||
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||
'busy_timeout' => null,
|
||||
|
|
|
|||
|
|
@ -28,21 +28,18 @@ return [
|
|||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
'dns_servers' => array_values(array_filter(explode(',', (string) env('DNS_SERVERS', '1.1.1.1,8.8.8.8')))),
|
||||
|
||||
'proxy_url' => env('PROXY_URL'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Browser engine (Lightpanda via CDP)
|
||||
| BROWSER_WS_ENDPOINT takes precedence; legacy SELENIUM_HOST is honoured
|
||||
| as a deprecated fallback (translated into a ws:// endpoint).
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
'browser' => [
|
||||
'ws_endpoint' => env('BROWSER_WS_ENDPOINT')
|
||||
?: (env('SELENIUM_HOST') ? 'ws://'.preg_replace('#^https?://#', '', (string) env('SELENIUM_HOST')) : 'ws://localhost:9222'),
|
||||
// A trailing path is required: the underlying WebSocket client rejects a URI with no path.
|
||||
// Left null when unset — the browser fetch strategy is skipped in that case.
|
||||
'ws_endpoint' => env('BROWSER_WS_ENDPOINT') ? rtrim((string) env('BROWSER_WS_ENDPOINT'), '/').'/' : null,
|
||||
'timeout_ms' => (int) env('BROWSER_TIMEOUT_MS', 30000),
|
||||
],
|
||||
|
||||
|
|
@ -54,18 +51,10 @@ return [
|
|||
|
||||
'cache' => [
|
||||
'disabled' => (bool) env('DISABLE_CACHE', false),
|
||||
'directory' => env('CACHE_DIR', base_path('cache')),
|
||||
'directory' => storage_path('app/marreta-cache'),
|
||||
'compress_level' => 3,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maintenance
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
'cleanup_days' => (int) env('CLEANUP_DAYS', 0),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Admin (Filament)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@
|
|||
colors="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory>tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Feature">
|
||||
<directory>tests/Feature</directory>
|
||||
</testsuite>
|
||||
|
|
|
|||
11
resources/views/filament/pages/global-rules.blade.php
Normal file
11
resources/views/filament/pages/global-rules.blade.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<x-filament-panels::page>
|
||||
<form wire:submit="save">
|
||||
{{ $this->form }}
|
||||
|
||||
<div class="mt-6">
|
||||
<x-filament::button type="submit">
|
||||
{{ __('admin.save') }}
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</form>
|
||||
</x-filament-panels::page>
|
||||
Loading…
Add table
Add a link
Reference in a new issue