mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-05 09:54:05 +00:00
add DisallowSqliteAttach feature
This commit is contained in:
parent
613ab5bbc8
commit
9bb06afc57
10 changed files with 275 additions and 1 deletions
100
tests/Features/NoAttachTest.php
Normal file
100
tests/Features/NoAttachTest.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Stancl\JobPipeline\JobPipeline;
|
||||
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Events\TenancyEnded;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\Events\TenantCreated;
|
||||
use Stancl\Tenancy\Features\DisallowSqliteAttach;
|
||||
use Stancl\Tenancy\Jobs\CreateDatabase;
|
||||
use Stancl\Tenancy\Jobs\MigrateDatabase;
|
||||
use Stancl\Tenancy\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Listeners\RevertToCentralContext;
|
||||
use Stancl\Tenancy\Middleware\InitializeTenancyByPath;
|
||||
use Stancl\Tenancy\Tests\Etc\Tenant;
|
||||
|
||||
test('sqlite ATTACH statements can be blocked', function (bool $disallow) {
|
||||
try {
|
||||
readlink(base_path('vendor'));
|
||||
} catch (\Throwable) {
|
||||
symlink(base_path('vendor'), '/var/www/html/vendor');
|
||||
}
|
||||
|
||||
DisallowSqliteAttach::$extensionPath = '/var/www/html/extensions/lib/arm/noattach.so';
|
||||
|
||||
if ($disallow) config(['tenancy.features' => [DisallowSqliteAttach::class]]);
|
||||
|
||||
config(['tenancy.bootstrappers' => [DatabaseTenancyBootstrapper::class]]);
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([
|
||||
CreateDatabase::class,
|
||||
MigrateDatabase::class,
|
||||
])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
$tempdb1 = tempnam(sys_get_temp_dir(), 'tenancy_attach_test');
|
||||
$tempdb2 = tempnam(sys_get_temp_dir(), 'tenancy_attach_test');
|
||||
register_shutdown_function(fn () => @unlink($tempdb1));
|
||||
register_shutdown_function(fn () => @unlink($tempdb2));
|
||||
|
||||
config(['database.connections.foo' => ['driver' => 'sqlite', 'database' => $tempdb1]]);
|
||||
config(['database.connections.bar' => ['driver' => 'sqlite', 'database' => $tempdb2]]);
|
||||
|
||||
DB::connection('bar')->statement('CREATE TABLE secrets (key, value)');
|
||||
DB::connection('bar')->statement('INSERT INTO secrets (key, value) VALUES ("secret_foo", "secret_bar")');
|
||||
|
||||
Route::post('/central-sqli', function () {
|
||||
DB::connection('foo')->select(request('q1'));
|
||||
return json_encode(DB::connection('foo')->select(request('q2')));
|
||||
});
|
||||
|
||||
Route::middleware(InitializeTenancyByPath::class)->post('/{tenant}/tenant-sqli', function () {
|
||||
DB::select(request('q1'));
|
||||
return json_encode(DB::select(request('q2')));
|
||||
});
|
||||
|
||||
tenancy(); // trigger features: todo@samuel remove after feature refactor
|
||||
|
||||
if ($disallow) {
|
||||
expect(fn () => pest()->post('/central-sqli', [
|
||||
'q1' => 'ATTACH DATABASE "' . $tempdb2 . '" as bar',
|
||||
'q2' => 'SELECT * from bar.secrets',
|
||||
])->json())->toThrow(QueryException::class, 'not authorized');
|
||||
} else {
|
||||
expect(pest()->post('/central-sqli', [
|
||||
'q1' => 'ATTACH DATABASE "' . $tempdb2 . '" as bar',
|
||||
'q2' => 'SELECT * from bar.secrets',
|
||||
])->json()[0])->toBe([
|
||||
'key' => 'secret_foo',
|
||||
'value' => 'secret_bar',
|
||||
]);
|
||||
}
|
||||
|
||||
$tenant = Tenant::create([
|
||||
'tenancy_db_connection' => 'sqlite',
|
||||
]);
|
||||
|
||||
if ($disallow) {
|
||||
expect(fn () => pest()->post($tenant->id . '/tenant-sqli', [
|
||||
'q1' => 'ATTACH DATABASE "' . $tempdb2 . '" as baz',
|
||||
'q2' => 'SELECT * from bar.secrets',
|
||||
])->json())->toThrow(QueryException::class);
|
||||
} else {
|
||||
expect(pest()->post($tenant->id . '/tenant-sqli', [
|
||||
'q1' => 'ATTACH DATABASE "' . $tempdb2 . '" as baz',
|
||||
'q2' => 'SELECT * from baz.secrets',
|
||||
])->json()[0])->toBe([
|
||||
'key' => 'secret_foo',
|
||||
'value' => 'secret_bar',
|
||||
]);
|
||||
}
|
||||
})->with([true, false]);
|
||||
Loading…
Add table
Add a link
Reference in a new issue