Cut over-engineering found by a repo-wide audit
- Config: auth, services, logging, queue and database only repeated the
framework's own files and are gone; the others keep only the keys that
differ (app version, cache serializable_classes, session cookie name,
Markdown mail theme, the shares disk, three Octane values, Livewire's
pagination theme and payload guards).
- Email verification is removed: User never implemented MustVerifyEmail,
so it was never enforced, and SealShare has a single admin and no
registration. CreateNewUser goes with it.
- FileEncryptionService::encryptFile() and generateSalt() were only used
by tests; tests build files with encryptTestFile() in tests/Pest.php.
- The expiration options are defined once, as Share::EXPIRATIONS. "30 Days"
now lasts 30 days instead of a calendar month, and Admin settings only
save a default expiration that is one of the options.
- One-caller helpers are inlined, the uploader reads chunk responses with
XHR's responseType, and starter-kit leftovers are removed.
- Docker: PHP reads the PHP_* limits from the environment itself
(${VAR:-default} in uploads.ini); both entrypoints stop writing the ini.
docker-compose.yml shares the app and scheduler variables through one
anchor. The dev image installs gd for the screenshot publisher and fake
test images.
- Development runs in Docker only: the composer dev script, concurrently,
laravel/pail, laravel/sail, autoprefixer and the shell-quote override
are gone.
- phpunit.xml forces the test environment with <server> entries, so tests
run in the dev container no longer use its real database.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a62edbcefb
commit
4530298398
@@ -51,6 +51,23 @@ test('admin can save settings', function () {
|
||||
expect(Setting::get('default_expiration'))->toBe('7d');
|
||||
});
|
||||
|
||||
test('the default expiration only accepts the offered options', function () {
|
||||
$admin = User::query()->where('is_admin', true)->first();
|
||||
|
||||
$component = Livewire::actingAs($admin)
|
||||
->test(AdminSettings::class)
|
||||
->set('defaultExpiration', '99y')
|
||||
->call('saveSettings')
|
||||
->assertHasErrors(['defaultExpiration' => 'in']);
|
||||
|
||||
expect(Setting::get('default_expiration'))->toBeNull();
|
||||
|
||||
$component
|
||||
->set('defaultExpiration', '')
|
||||
->call('saveSettings')
|
||||
->assertHasNoErrors();
|
||||
});
|
||||
|
||||
test('admin can set system password', function () {
|
||||
$admin = User::query()->where('is_admin', true)->first();
|
||||
Livewire::actingAs($admin)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
test('email verification screen can be rendered', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get(route('verification.notice'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('email can be verified', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$response = $this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertDispatched(Verified::class);
|
||||
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
|
||||
$response->assertRedirect(route('admin.dashboard', absolute: false).'?verified=1');
|
||||
});
|
||||
|
||||
test('email is not verified with invalid hash', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1('wrong-email')]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
|
||||
});
|
||||
|
||||
test('already verified user visiting verification link is redirected without firing event again', function () {
|
||||
$user = User::factory()->create([
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl)
|
||||
->assertRedirect(route('admin.dashboard', absolute: false).'?verified=1');
|
||||
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
|
||||
Event::assertNotDispatched(Verified::class);
|
||||
});
|
||||
@@ -249,6 +249,21 @@ test('file upload with expiration sets expires_at', function () {
|
||||
expect($share->expires_at)->not->toBeNull();
|
||||
});
|
||||
|
||||
test('a 30 day expiration lasts 30 days, not a calendar month', function () {
|
||||
Storage::fake('shares');
|
||||
$this->travelTo(new DateTimeImmutable('2026-02-01 12:00:00'));
|
||||
|
||||
$component = Livewire::test(FileUploader::class);
|
||||
uploadThroughPage($component, ['file.txt' => 'content']);
|
||||
|
||||
$component
|
||||
->set('expiration', '30d')
|
||||
->call('createShare')
|
||||
->assertRedirectContains('/share/');
|
||||
|
||||
expect(Share::query()->first()->expires_at->toDateTimeString())->toBe('2026-03-03 12:00:00');
|
||||
});
|
||||
|
||||
test('file upload with max downloads sets limit', function () {
|
||||
Storage::fake('shares');
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ test('every page is one page template, one h1 and the same width', function (Clo
|
||||
|
||||
return $test->get(route('system-password'));
|
||||
}],
|
||||
'verify email' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->unverified()->create())->get(route('verification.notice'))],
|
||||
'confirm password' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->create())->get(route('password.confirm'))],
|
||||
'profile' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->create())->get(route('profile.edit'))],
|
||||
'password' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->create())->get(route('user-password.edit'))],
|
||||
|
||||
@@ -27,10 +27,9 @@ test('profile information can be updated', function () {
|
||||
|
||||
expect($user->name)->toEqual('Test User');
|
||||
expect($user->email)->toEqual('test@example.com');
|
||||
expect($user->email_verified_at)->toBeNull();
|
||||
});
|
||||
|
||||
test('email verification status is unchanged when email address is unchanged', function () {
|
||||
test('the profile saves with its own unchanged email address', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
@@ -42,7 +41,7 @@ test('email verification status is unchanged when email address is unchanged', f
|
||||
|
||||
$response->assertHasNoErrors();
|
||||
|
||||
expect($user->refresh()->email_verified_at)->not->toBeNull();
|
||||
expect($user->refresh()->name)->toEqual('Test User');
|
||||
});
|
||||
|
||||
test('user can delete their account', function () {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use App\Livewire\ShareDownload;
|
||||
use App\Models\Share;
|
||||
use App\Models\ShareFile;
|
||||
use App\Services\FileEncryptionService;
|
||||
use App\Services\ShareService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@@ -280,7 +279,7 @@ test('a password share created before key wrapping still unlocks and downloads',
|
||||
$source = tempnam(sys_get_temp_dir(), 'old');
|
||||
file_put_contents($source, 'old content');
|
||||
Storage::disk('shares')->makeDirectory($share->token);
|
||||
app(FileEncryptionService::class)->encryptFile($source, Storage::disk('shares')->path($share->token.'/old.enc'), bin2hex(hash_pbkdf2('sha256', 'old-password', hex2bin($salt), 100000, 32, true)), 1024);
|
||||
encryptTestFile($source, Storage::disk('shares')->path($share->token.'/old.enc'), bin2hex(hash_pbkdf2('sha256', 'old-password', hex2bin($salt), 100000, 32, true)), 1024);
|
||||
unlink($source);
|
||||
|
||||
Livewire::test(ShareDownload::class, ['share' => $share])
|
||||
|
||||
Reference in New Issue
Block a user