302 lines
10 KiB
PHP
302 lines
10 KiB
PHP
<?php
|
|
|
|
require getenv('LARAVEL_INSTALLER_AUTOLOADER') ?: __DIR__.'/vendor/autoload.php';
|
|
|
|
use Laravel\Chisel\Chisel;
|
|
use Laravel\Chisel\Question;
|
|
use Laravel\Prompts\Support\Logger;
|
|
use Symfony\Component\Process\Process;
|
|
|
|
use function Laravel\Prompts\task;
|
|
|
|
function chiselRun(array $command, string $label): void
|
|
{
|
|
$process = task(
|
|
label: $label,
|
|
keepSummary: true,
|
|
callback: function (Logger $logger) use ($command) {
|
|
$process = new Process($command);
|
|
$process->run(function ($type, $line) use ($logger) {
|
|
$logger->line($line);
|
|
});
|
|
|
|
if ($process->isSuccessful()) {
|
|
$logger->success(implode(' ', $command));
|
|
|
|
return $process;
|
|
}
|
|
|
|
$logger->error(implode(' ', $command));
|
|
$logger->error('Error output: '.trim($process->getErrorOutput()));
|
|
$logger->error('Chisel: Your project may be in a partially-modified state — review the output above before continuing.');
|
|
|
|
return $process;
|
|
},
|
|
);
|
|
|
|
if (! $process->isSuccessful()) {
|
|
exit($process->getExitCode());
|
|
}
|
|
}
|
|
|
|
function chiselSkipsNode(): bool
|
|
{
|
|
return filter_var(
|
|
$_ENV['LARAVEL_INSTALLER_NO_NODE']
|
|
?? $_SERVER['LARAVEL_INSTALLER_NO_NODE']
|
|
?? getenv('LARAVEL_INSTALLER_NO_NODE'),
|
|
FILTER_VALIDATE_BOOL,
|
|
);
|
|
}
|
|
|
|
function chiselRemoveNpmPackages(Chisel $c, string ...$packages): void
|
|
{
|
|
if (! chiselSkipsNode()) {
|
|
$c->npm()->remove(...$packages);
|
|
|
|
return;
|
|
}
|
|
|
|
foreach ($packages as $package) {
|
|
$c->file('package.json')->removeLinesContaining('"'.$package.'":');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Framework-specific filenames are supplied by the sibling chisel-paths.php
|
|
* that ships with each Inertia kit (React/Svelte/Vue). After build both files
|
|
* land in the project root.
|
|
*
|
|
* @var array{
|
|
* login: string,
|
|
* register: string,
|
|
* welcome: string,
|
|
* profile: string,
|
|
* security: string,
|
|
* verify_email: string,
|
|
* two_factor_challenge: string,
|
|
* confirm_password: string,
|
|
* auth_types: string,
|
|
* two_factor_files: list<string>,
|
|
* two_factor_otp_package: ?string,
|
|
* passkey_files: list<string>,
|
|
* } $paths
|
|
*/
|
|
$paths = require __DIR__.'/chisel-paths.php';
|
|
|
|
return Chisel::script(__DIR__)
|
|
->questions([
|
|
Question::multiselect(
|
|
name: 'auth_features',
|
|
label: 'Which authentication features would you like to enable?',
|
|
options: [
|
|
'email-verification' => 'Email verification',
|
|
'registration' => 'Registration',
|
|
'2fa' => 'Two-factor authentication',
|
|
'passkeys' => 'Passkeys',
|
|
'password-confirmation' => 'Password confirmation',
|
|
],
|
|
default: ['email-verification', 'registration', '2fa', 'passkeys', 'password-confirmation'],
|
|
hint: 'Use space to select, enter to confirm.',
|
|
),
|
|
])
|
|
->selected(
|
|
'auth_features',
|
|
'registration',
|
|
then: function (Chisel $c) use ($paths) {
|
|
$c->files(
|
|
'config/fortify.php',
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
$paths['login'],
|
|
$paths['welcome'],
|
|
)->removeSectionMarkers('registration');
|
|
},
|
|
else: function (Chisel $c) use ($paths) {
|
|
$c->file('config/fortify.php')->removeSection('registration');
|
|
|
|
$c->files(
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
$paths['login'],
|
|
$paths['welcome'],
|
|
)->removeSection('registration');
|
|
|
|
$c->files(
|
|
'app/Actions/Fortify/CreateNewUser.php',
|
|
'app/Http/Responses/RegisterResponse.php',
|
|
$paths['register'],
|
|
'tests/Feature/Auth/RegistrationTest.php',
|
|
)->delete();
|
|
},
|
|
)
|
|
->selected(
|
|
'auth_features',
|
|
'email-verification',
|
|
then: function (Chisel $c) use ($paths) {
|
|
$c->files(
|
|
'config/fortify.php',
|
|
$paths['profile'],
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
)->removeSectionMarkers('email-verification');
|
|
},
|
|
else: function (Chisel $c) use ($paths) {
|
|
$c->php('app/Models/User.php')
|
|
->removeImport('Illuminate\Contracts\Auth\MustVerifyEmail')
|
|
->removeInterface('MustVerifyEmail');
|
|
|
|
$c->files(
|
|
'config/fortify.php',
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
$paths['profile'],
|
|
)->removeSection('email-verification');
|
|
|
|
$c->files(
|
|
'app/Http/Responses/VerifyEmailResponse.php',
|
|
$paths['verify_email'],
|
|
'tests/Feature/Auth/EmailVerificationTest.php',
|
|
'tests/Feature/Auth/VerificationNotificationTest.php',
|
|
)->delete();
|
|
},
|
|
)
|
|
->selected(
|
|
'auth_features',
|
|
'2fa',
|
|
then: function (Chisel $c) use ($paths) {
|
|
$c->files(
|
|
'app/Models/User.php',
|
|
'database/factories/UserFactory.php',
|
|
$paths['security'],
|
|
$paths['auth_types'],
|
|
'config/fortify.php',
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
'app/Http/Controllers/Settings/SecurityController.php',
|
|
)->removeSectionMarkers('2fa');
|
|
},
|
|
else: function (Chisel $c) use ($paths) {
|
|
$c->php('app/Models/User.php')
|
|
->removeImport('Laravel\Fortify\TwoFactorAuthenticatable')
|
|
->removeTrait('TwoFactorAuthenticatable');
|
|
|
|
$c->files(
|
|
'app/Models/User.php',
|
|
'database/factories/UserFactory.php',
|
|
'config/fortify.php',
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
'app/Http/Controllers/Settings/SecurityController.php',
|
|
$paths['security'],
|
|
$paths['auth_types'],
|
|
)->removeSection('2fa');
|
|
|
|
if ($paths['two_factor_otp_package'] !== null) {
|
|
chiselRemoveNpmPackages($c, $paths['two_factor_otp_package']);
|
|
}
|
|
|
|
$c->files(...[
|
|
$paths['two_factor_challenge'],
|
|
...$paths['two_factor_files'],
|
|
'database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php',
|
|
'tests/Feature/Auth/TwoFactorChallengeTest.php',
|
|
])->delete();
|
|
},
|
|
)
|
|
->selected(
|
|
'auth_features',
|
|
'passkeys',
|
|
then: function (Chisel $c) use ($paths) {
|
|
$c->files(
|
|
'config/fortify.php',
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
'app/Http/Controllers/Settings/SecurityController.php',
|
|
'routes/settings.php',
|
|
'tests/Feature/Auth/AuthenticationTest.php',
|
|
'tests/Feature/Settings/SecurityTest.php',
|
|
$paths['auth_types'],
|
|
$paths['security'],
|
|
$paths['login'],
|
|
$paths['confirm_password'],
|
|
)->removeSectionMarkers('passkeys');
|
|
},
|
|
else: function (Chisel $c) use ($paths) {
|
|
$c->php('app/Models/User.php')
|
|
->removeImport('Laravel\Fortify\PasskeyAuthenticatable')
|
|
->removeImport('Laravel\Fortify\Contracts\PasskeyUser')
|
|
->removeTrait('PasskeyAuthenticatable')
|
|
->removeInterface('PasskeyUser');
|
|
|
|
$c->files(
|
|
'config/fortify.php',
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
'app/Http/Controllers/Settings/SecurityController.php',
|
|
'routes/settings.php',
|
|
'tests/Feature/Auth/AuthenticationTest.php',
|
|
'tests/Feature/Settings/SecurityTest.php',
|
|
$paths['auth_types'],
|
|
$paths['security'],
|
|
$paths['login'],
|
|
$paths['confirm_password'],
|
|
)->removeSection('passkeys');
|
|
|
|
chiselRemoveNpmPackages($c, '@laravel/passkeys');
|
|
|
|
$c->files(...[
|
|
...$paths['passkey_files'],
|
|
'app/Http/Responses/PasskeyLoginResponse.php',
|
|
'database/migrations/2024_01_01_000000_create_passkeys_table.php',
|
|
])->delete();
|
|
},
|
|
)
|
|
->selectedAny(
|
|
'auth_features',
|
|
['2fa', 'passkeys'],
|
|
then: function (Chisel $c) use ($paths) {
|
|
$c->file($paths['security'])
|
|
->removeSectionMarkers('2fa-or-passkeys');
|
|
},
|
|
else: function (Chisel $c) use ($paths) {
|
|
$c->file($paths['security'])
|
|
->removeSection('2fa-or-passkeys');
|
|
},
|
|
)
|
|
->selected(
|
|
'auth_features',
|
|
'password-confirmation',
|
|
then: function (Chisel $c) {
|
|
$c->files(
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
'routes/settings.php',
|
|
'tests/Feature/Settings/SecurityTest.php',
|
|
)->removeSectionMarkers('password-confirmation');
|
|
},
|
|
else: function (Chisel $c) use ($paths) {
|
|
$c->file('config/fortify.php')
|
|
->replace("'confirmPassword' => true,", "'confirmPassword' => false,");
|
|
|
|
$c->files(
|
|
'app/Providers/FortifyServiceProvider.php',
|
|
'routes/settings.php',
|
|
'tests/Feature/Settings/SecurityTest.php',
|
|
)->removeSection('password-confirmation');
|
|
|
|
$c->files(
|
|
$paths['confirm_password'],
|
|
'tests/Feature/Auth/PasswordConfirmationTest.php',
|
|
)->delete();
|
|
},
|
|
)
|
|
->apply(function (Chisel $c): void {
|
|
$c->file('composer.json')
|
|
->removeLinesContaining('"@php artisan install:features --ansi"');
|
|
|
|
chiselRun(['composer', 'lint'], 'Composer Lint');
|
|
chiselRun(['php', 'artisan', 'wayfinder:generate', '--with-form', '--no-interaction'], 'Generate Wayfinder Resources');
|
|
|
|
if (! chiselSkipsNode()) {
|
|
$c->npm()->run('check:fix');
|
|
}
|
|
|
|
$c->files(
|
|
'app/Console/Commands/InstallFeaturesCommand.php',
|
|
'chisel.php',
|
|
'chisel-paths.php',
|
|
)->delete();
|
|
});
|