LICENSE.md000064400000002063150251047330006151 0ustar00The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. auth-backend/RedirectsUsers.php000064400000000617150251047330012555 0ustar00redirectTo(); } return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home'; } } auth-backend/ResetsPasswords.php000064400000012367150251047330012767 0ustar00route()->parameter('token'); return view('auth.passwords.reset')->with( ['token' => $token, 'email' => $request->email] ); } /** * Reset the given user's password. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ public function reset(Request $request) { $request->validate($this->rules(), $this->validationErrorMessages()); // Here we will attempt to reset the user's password. If it is successful we // will update the password on an actual user model and persist it to the // database. Otherwise we will parse the error and return the response. $response = $this->broker()->reset( $this->credentials($request), function ($user, $password) { $this->resetPassword($user, $password); } ); // If the password was successfully reset, we will redirect the user back to // the application's home authenticated view. If there is an error we can // redirect them back to where they came from with their error message. return $response == Password::PASSWORD_RESET ? $this->sendResetResponse($request, $response) : $this->sendResetFailedResponse($request, $response); } /** * Get the password reset validation rules. * * @return array */ protected function rules() { return [ 'token' => 'required', 'email' => 'required|email', 'password' => ['required', 'confirmed', Rules\Password::defaults()], ]; } /** * Get the password reset validation error messages. * * @return array */ protected function validationErrorMessages() { return []; } /** * Get the password reset credentials from the request. * * @param \Illuminate\Http\Request $request * @return array */ protected function credentials(Request $request) { return $request->only( 'email', 'password', 'password_confirmation', 'token' ); } /** * Reset the given user's password. * * @param \Illuminate\Contracts\Auth\CanResetPassword $user * @param string $password * @return void */ protected function resetPassword($user, $password) { $this->setUserPassword($user, $password); $user->setRememberToken(Str::random(60)); $user->save(); event(new PasswordReset($user)); $this->guard()->login($user); } /** * Set the user's password. * * @param \Illuminate\Contracts\Auth\CanResetPassword $user * @param string $password * @return void */ protected function setUserPassword($user, $password) { $user->password = Hash::make($password); } /** * Get the response for a successful password reset. * * @param \Illuminate\Http\Request $request * @param string $response * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ protected function sendResetResponse(Request $request, $response) { if ($request->wantsJson()) { return new JsonResponse(['message' => trans($response)], 200); } return redirect($this->redirectPath()) ->with('status', trans($response)); } /** * Get the response for a failed password reset. * * @param \Illuminate\Http\Request $request * @param string $response * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ protected function sendResetFailedResponse(Request $request, $response) { if ($request->wantsJson()) { throw ValidationException::withMessages([ 'email' => [trans($response)], ]); } return redirect()->back() ->withInput($request->only('email')) ->withErrors(['email' => trans($response)]); } /** * Get the broker to be used during password reset. * * @return \Illuminate\Contracts\Auth\PasswordBroker */ public function broker() { return Password::broker(); } /** * Get the guard to be used during password reset. * * @return \Illuminate\Contracts\Auth\StatefulGuard */ protected function guard() { return Auth::guard(); } } auth-backend/ThrottlesLogins.php000064400000006124150251047330012752 0ustar00limiter()->tooManyAttempts( $this->throttleKey($request), $this->maxAttempts() ); } /** * Increment the login attempts for the user. * * @param \Illuminate\Http\Request $request * @return void */ protected function incrementLoginAttempts(Request $request) { $this->limiter()->hit( $this->throttleKey($request), $this->decayMinutes() * 60 ); } /** * Redirect the user after determining they are locked out. * * @param \Illuminate\Http\Request $request * @return \Symfony\Component\HttpFoundation\Response * * @throws \Illuminate\Validation\ValidationException */ protected function sendLockoutResponse(Request $request) { $seconds = $this->limiter()->availableIn( $this->throttleKey($request) ); throw ValidationException::withMessages([ $this->username() => [trans('auth.throttle', [ 'seconds' => $seconds, 'minutes' => ceil($seconds / 60), ])], ])->status(Response::HTTP_TOO_MANY_REQUESTS); } /** * Clear the login locks for the given user credentials. * * @param \Illuminate\Http\Request $request * @return void */ protected function clearLoginAttempts(Request $request) { $this->limiter()->clear($this->throttleKey($request)); } /** * Fire an event when a lockout occurs. * * @param \Illuminate\Http\Request $request * @return void */ protected function fireLockoutEvent(Request $request) { event(new Lockout($request)); } /** * Get the throttle key for the given request. * * @param \Illuminate\Http\Request $request * @return string */ protected function throttleKey(Request $request) { return Str::transliterate(Str::lower($request->input($this->username())).'|'.$request->ip()); } /** * Get the rate limiter instance. * * @return \Illuminate\Cache\RateLimiter */ protected function limiter() { return app(RateLimiter::class); } /** * Get the maximum number of attempts to allow. * * @return int */ public function maxAttempts() { return property_exists($this, 'maxAttempts') ? $this->maxAttempts : 5; } /** * Get the number of minutes to throttle for. * * @return int */ public function decayMinutes() { return property_exists($this, 'decayMinutes') ? $this->decayMinutes : 1; } } auth-backend/VerifiesEmails.php000064400000005342150251047330012516 0ustar00user()->hasVerifiedEmail() ? redirect($this->redirectPath()) : view('auth.verify'); } /** * Mark the authenticated user's email address as verified. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse * * @throws \Illuminate\Auth\Access\AuthorizationException */ public function verify(Request $request) { if (! hash_equals((string) $request->route('id'), (string) $request->user()->getKey())) { throw new AuthorizationException; } if (! hash_equals((string) $request->route('hash'), sha1($request->user()->getEmailForVerification()))) { throw new AuthorizationException; } if ($request->user()->hasVerifiedEmail()) { return $request->wantsJson() ? new JsonResponse([], 204) : redirect($this->redirectPath()); } if ($request->user()->markEmailAsVerified()) { event(new Verified($request->user())); } if ($response = $this->verified($request)) { return $response; } return $request->wantsJson() ? new JsonResponse([], 204) : redirect($this->redirectPath())->with('verified', true); } /** * The user has been verified. * * @param \Illuminate\Http\Request $request * @return mixed */ protected function verified(Request $request) { // } /** * Resend the email verification notification. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse */ public function resend(Request $request) { if ($request->user()->hasVerifiedEmail()) { return $request->wantsJson() ? new JsonResponse([], 204) : redirect($this->redirectPath()); } $request->user()->sendEmailVerificationNotification(); return $request->wantsJson() ? new JsonResponse([], 202) : back()->with('resent', true); } } auth-backend/AuthenticatesUsers.php000064400000012577150251047330013442 0ustar00validateLogin($request); // If the class is using the ThrottlesLogins trait, we can automatically throttle // the login attempts for this application. We'll key this by the username and // the IP address of the client making these requests into this application. if (method_exists($this, 'hasTooManyLoginAttempts') && $this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); return $this->sendLockoutResponse($request); } if ($this->attemptLogin($request)) { if ($request->hasSession()) { $request->session()->put('auth.password_confirmed_at', time()); } return $this->sendLoginResponse($request); } // If the login attempt was unsuccessful we will increment the number of attempts // to login and redirect the user back to the login form. Of course, when this // user surpasses their maximum number of attempts they will get locked out. $this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request); } /** * Validate the user login request. * * @param \Illuminate\Http\Request $request * @return void * * @throws \Illuminate\Validation\ValidationException */ protected function validateLogin(Request $request) { $request->validate([ $this->username() => 'required|string', 'password' => 'required|string', ]); } /** * Attempt to log the user into the application. * * @param \Illuminate\Http\Request $request * @return bool */ protected function attemptLogin(Request $request) { return $this->guard()->attempt( $this->credentials($request), $request->boolean('remember') ); } /** * Get the needed authorization credentials from the request. * * @param \Illuminate\Http\Request $request * @return array */ protected function credentials(Request $request) { return $request->only($this->username(), 'password'); } /** * Send the response after the user was authenticated. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ protected function sendLoginResponse(Request $request) { $request->session()->regenerate(); $this->clearLoginAttempts($request); if ($response = $this->authenticated($request, $this->guard()->user())) { return $response; } return $request->wantsJson() ? new JsonResponse([], 204) : redirect()->intended($this->redirectPath()); } /** * The user has been authenticated. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function authenticated(Request $request, $user) { // } /** * Get the failed login response instance. * * @param \Illuminate\Http\Request $request * @return \Symfony\Component\HttpFoundation\Response * * @throws \Illuminate\Validation\ValidationException */ protected function sendFailedLoginResponse(Request $request) { throw ValidationException::withMessages([ $this->username() => [trans('auth.failed')], ]); } /** * Get the login username to be used by the controller. * * @return string */ public function username() { return 'email'; } /** * Log the user out of the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ public function logout(Request $request) { $this->guard()->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); if ($response = $this->loggedOut($request)) { return $response; } return $request->wantsJson() ? new JsonResponse([], 204) : redirect('/'); } /** * The user has logged out of the application. * * @param \Illuminate\Http\Request $request * @return mixed */ protected function loggedOut(Request $request) { // } /** * Get the guard to be used during authentication. * * @return \Illuminate\Contracts\Auth\StatefulGuard */ protected function guard() { return Auth::guard(); } } auth-backend/SendsPasswordResetEmails.php000064400000006257150251047330014552 0ustar00validateEmail($request); // We will send the password reset link to this user. Once we have attempted // to send the link, we will examine the response then see the message we // need to show to the user. Finally, we'll send out a proper response. $response = $this->broker()->sendResetLink( $this->credentials($request) ); return $response == Password::RESET_LINK_SENT ? $this->sendResetLinkResponse($request, $response) : $this->sendResetLinkFailedResponse($request, $response); } /** * Validate the email for the given request. * * @param \Illuminate\Http\Request $request * @return void */ protected function validateEmail(Request $request) { $request->validate(['email' => 'required|email']); } /** * Get the needed authentication credentials from the request. * * @param \Illuminate\Http\Request $request * @return array */ protected function credentials(Request $request) { return $request->only('email'); } /** * Get the response for a successful password reset link. * * @param \Illuminate\Http\Request $request * @param string $response * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ protected function sendResetLinkResponse(Request $request, $response) { return $request->wantsJson() ? new JsonResponse(['message' => trans($response)], 200) : back()->with('status', trans($response)); } /** * Get the response for a failed password reset link. * * @param \Illuminate\Http\Request $request * @param string $response * @return \Illuminate\Http\RedirectResponse * * @throws \Illuminate\Validation\ValidationException */ protected function sendResetLinkFailedResponse(Request $request, $response) { if ($request->wantsJson()) { throw ValidationException::withMessages([ 'email' => [trans($response)], ]); } return back() ->withInput($request->only('email')) ->withErrors(['email' => trans($response)]); } /** * Get the broker to be used during password reset. * * @return \Illuminate\Contracts\Auth\PasswordBroker */ public function broker() { return Password::broker(); } } auth-backend/RegistersUsers.php000064400000003034150251047330012574 0ustar00validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); $this->guard()->login($user); if ($response = $this->registered($request, $user)) { return $response; } return $request->wantsJson() ? new JsonResponse([], 201) : redirect($this->redirectPath()); } /** * Get the guard to be used during registration. * * @return \Illuminate\Contracts\Auth\StatefulGuard */ protected function guard() { return Auth::guard(); } /** * The user has been registered. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function registered(Request $request, $user) { // } } auth-backend/ConfirmsPasswords.php000064400000003136150251047330013274 0ustar00validate($this->rules(), $this->validationErrorMessages()); $this->resetPasswordConfirmationTimeout($request); return $request->wantsJson() ? new JsonResponse([], 204) : redirect()->intended($this->redirectPath()); } /** * Reset the password confirmation timeout. * * @param \Illuminate\Http\Request $request * @return void */ protected function resetPasswordConfirmationTimeout(Request $request) { $request->session()->put('auth.password_confirmed_at', time()); } /** * Get the password confirmation validation rules. * * @return array */ protected function rules() { return [ 'password' => 'required|current_password:web', ]; } /** * Get the password confirmation validation error messages. * * @return array */ protected function validationErrorMessages() { return []; } } composer.json000064400000002074150251047330007271 0ustar00{ "name": "laravel/ui", "description": "Laravel UI utilities and presets.", "keywords": ["laravel", "ui"], "license": "MIT", "authors": [ { "name": "Taylor Otwell", "email": "taylor@laravel.com" } ], "require": { "php": "^8.0", "illuminate/console": "^9.21|^10.0", "illuminate/filesystem": "^9.21|^10.0", "illuminate/support": "^9.21|^10.0", "illuminate/validation": "^9.21|^10.0" }, "require-dev": { "orchestra/testbench": "^7.0|^8.0", "phpunit/phpunit": "^9.3" }, "autoload": { "psr-4": { "Laravel\\Ui\\": "src/", "Illuminate\\Foundation\\Auth\\": "auth-backend/" } }, "config": { "sort-packages": true }, "extra": { "branch-alias": { "dev-master": "4.x-dev" }, "laravel": { "providers": [ "Laravel\\Ui\\UiServiceProvider" ] } }, "minimum-stability": "dev", "prefer-stable": true } src/AuthCommand.php000064400000011065150251047330010247 0ustar00 'auth/login.blade.php', 'auth/passwords/confirm.stub' => 'auth/passwords/confirm.blade.php', 'auth/passwords/email.stub' => 'auth/passwords/email.blade.php', 'auth/passwords/reset.stub' => 'auth/passwords/reset.blade.php', 'auth/register.stub' => 'auth/register.blade.php', 'auth/verify.stub' => 'auth/verify.blade.php', 'home.stub' => 'home.blade.php', 'layouts/app.stub' => 'layouts/app.blade.php', ]; /** * Execute the console command. * * @return void * * @throws \InvalidArgumentException */ public function handle() { if (static::hasMacro($this->argument('type'))) { return call_user_func(static::$macros[$this->argument('type')], $this); } if (! in_array($this->argument('type'), ['bootstrap'])) { throw new InvalidArgumentException('Invalid preset.'); } $this->ensureDirectoriesExist(); $this->exportViews(); if (! $this->option('views')) { $this->exportBackend(); } $this->components->info('Authentication scaffolding generated successfully.'); } /** * Create the directories for the files. * * @return void */ protected function ensureDirectoriesExist() { if (! is_dir($directory = $this->getViewPath('layouts'))) { mkdir($directory, 0755, true); } if (! is_dir($directory = $this->getViewPath('auth/passwords'))) { mkdir($directory, 0755, true); } } /** * Export the authentication views. * * @return void */ protected function exportViews() { foreach ($this->views as $key => $value) { if (file_exists($view = $this->getViewPath($value)) && ! $this->option('force')) { if (! $this->components->confirm("The [$value] view already exists. Do you want to replace it?")) { continue; } } copy( __DIR__.'/Auth/'.$this->argument('type').'-stubs/'.$key, $view ); } } /** * Export the authentication backend. * * @return void */ protected function exportBackend() { $this->callSilent('ui:controllers'); $controller = app_path('Http/Controllers/HomeController.php'); if (file_exists($controller) && ! $this->option('force')) { if ($this->components->confirm("The [HomeController.php] file already exists. Do you want to replace it?")) { file_put_contents($controller, $this->compileControllerStub()); } } else { file_put_contents($controller, $this->compileControllerStub()); } file_put_contents( base_path('routes/web.php'), file_get_contents(__DIR__.'/Auth/stubs/routes.stub'), FILE_APPEND ); copy( __DIR__.'/../stubs/migrations/2014_10_12_100000_create_password_resets_table.php', base_path('database/migrations/2014_10_12_100000_create_password_resets_table.php') ); } /** * Compiles the "HomeController" stub. * * @return string */ protected function compileControllerStub() { return str_replace( '{{namespace}}', $this->laravel->getNamespace(), file_get_contents(__DIR__.'/Auth/stubs/controllers/HomeController.stub') ); } /** * Get full view path relative to the application's configured view path. * * @param string $path * @return string */ protected function getViewPath($path) { return implode(DIRECTORY_SEPARATOR, [ config('view.paths')[0] ?? resource_path('views'), $path, ]); } } src/UiServiceProvider.php000064400000001236150251047330011457 0ustar00app->runningInConsole()) { $this->commands([ AuthCommand::class, ControllersCommand::class, UiCommand::class, ]); } } /** * Bootstrap any application services. * * @return void */ public function boot() { Route::mixin(new AuthRouteMethods); } } src/UiCommand.php000064400000004463150251047330007727 0ustar00argument('type'))) { return call_user_func(static::$macros[$this->argument('type')], $this); } if (! in_array($this->argument('type'), ['bootstrap', 'vue', 'react'])) { throw new InvalidArgumentException('Invalid preset.'); } if ($this->option('auth')) { $this->call('ui:auth'); } $this->{$this->argument('type')}(); } /** * Install the "bootstrap" preset. * * @return void */ protected function bootstrap() { Presets\Bootstrap::install(); $this->components->info('Bootstrap scaffolding installed successfully.'); $this->components->warn('Please run [npm install && npm run dev] to compile your fresh scaffolding.'); } /** * Install the "vue" preset. * * @return void */ protected function vue() { Presets\Bootstrap::install(); Presets\Vue::install(); $this->components->info('Vue scaffolding installed successfully.'); $this->components->warn('Please run [npm install && npm run dev] to compile your fresh scaffolding.'); } /** * Install the "react" preset. * * @return void */ protected function react() { Presets\Bootstrap::install(); Presets\React::install(); $this->components->info('React scaffolding installed successfully.'); $this->components->warn('Please run [npm install && npm run dev] to compile your fresh scaffolding.'); } } src/Presets/Vue.php000064400000003320150251047330010226 0ustar00 '^4.0.0', 'vue' => '^3.2.37', ] + Arr::except($packages, [ '@vitejs/plugin-react', 'react', 'react-dom', ]); } /** * Update the Vite configuration. * * @return void */ protected static function updateViteConfiguration() { copy(__DIR__.'/vue-stubs/vite.config.js', base_path('vite.config.js')); } /** * Update the example component. * * @return void */ protected static function updateComponent() { (new Filesystem)->delete( resource_path('js/components/Example.js') ); copy( __DIR__.'/vue-stubs/ExampleComponent.vue', resource_path('js/components/ExampleComponent.vue') ); } /** * Update the bootstrapping files. * * @return void */ protected static function updateBootstrapping() { copy(__DIR__.'/vue-stubs/app.js', resource_path('js/app.js')); } } src/Presets/Preset.php000064400000003137150251047330010737 0ustar00isDirectory($directory = resource_path('js/components'))) { $filesystem->makeDirectory($directory, 0755, true); } } /** * Update the "package.json" file. * * @param bool $dev * @return void */ protected static function updatePackages($dev = true) { if (! file_exists(base_path('package.json'))) { return; } $configurationKey = $dev ? 'devDependencies' : 'dependencies'; $packages = json_decode(file_get_contents(base_path('package.json')), true); $packages[$configurationKey] = static::updatePackageArray( array_key_exists($configurationKey, $packages) ? $packages[$configurationKey] : [], $configurationKey ); ksort($packages[$configurationKey]); file_put_contents( base_path('package.json'), json_encode($packages, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL ); } /** * Remove the installed Node modules. * * @return void */ protected static function removeNodeModules() { tap(new Filesystem, function ($files) { $files->deleteDirectory(base_path('node_modules')); $files->delete(base_path('yarn.lock')); }); } } src/Presets/react-stubs/Example.jsx000064400000001420150251047330013332 0ustar00import React from 'react'; import ReactDOM from 'react-dom/client'; function Example() { return (
Example Component
I'm an example component!
); } export default Example; if (document.getElementById('example')) { const Index = ReactDOM.createRoot(document.getElementById("example")); Index.render( ) } src/Presets/react-stubs/vite.config.js000064400000000563150251047330013771 0ustar00import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [ laravel({ input: [ 'resources/sass/app.scss', 'resources/js/app.js', ], refresh: true, }), react(), ], }); src/Presets/react-stubs/app.js000064400000000764150251047330012341 0ustar00/** * First we will load all of this project's JavaScript dependencies which * includes React and other helpers. It's a great starting point while * building robust, powerful web applications using React + Laravel. */ import './bootstrap'; /** * Next, we will create a fresh React component instance and attach it to * the page. Then, you may begin adding components to this application * or customize the JavaScript scaffolding to fit your unique needs. */ import './components/Example'; src/Presets/Bootstrap.php000064400000003143150251047330011447 0ustar00 '^5.2.3', '@popperjs/core' => '^2.11.6', 'sass' => '^1.56.1', ] + $packages; } /** * Update the Vite configuration. * * @return void */ protected static function updateViteConfiguration() { copy(__DIR__.'/bootstrap-stubs/vite.config.js', base_path('vite.config.js')); } /** * Update the Sass files for the application. * * @return void */ protected static function updateSass() { (new Filesystem)->ensureDirectoryExists(resource_path('sass')); copy(__DIR__.'/bootstrap-stubs/_variables.scss', resource_path('sass/_variables.scss')); copy(__DIR__.'/bootstrap-stubs/app.scss', resource_path('sass/app.scss')); } /** * Update the bootstrapping files. * * @return void */ protected static function updateBootstrapping() { copy(__DIR__.'/bootstrap-stubs/bootstrap.js', resource_path('js/bootstrap.js')); } } src/Presets/React.php000064400000005040150251047330010526 0ustar00 '^2.2.0', 'react' => '^18.2.0', 'react-dom' => '^18.2.0', ] + Arr::except($packages, [ '@vitejs/plugin-vue', 'vue' ]); } /** * Update the Vite configuration. * * @return void */ protected static function updateViteConfiguration() { copy(__DIR__.'/react-stubs/vite.config.js', base_path('vite.config.js')); } /** * Update the example component. * * @return void */ protected static function updateComponent() { (new Filesystem)->delete( resource_path('js/components/ExampleComponent.vue') ); copy( __DIR__.'/react-stubs/Example.jsx', resource_path('js/components/Example.jsx') ); } /** * Update the bootstrapping files. * * @return void */ protected static function updateBootstrapping() { copy(__DIR__.'/react-stubs/app.js', resource_path('js/app.js')); } /** * Add Vite's React Refresh Runtime * * @return void */ protected static function addViteReactRefreshDirective() { $view = static::getViewPath('layouts/app.blade.php'); if (! file_exists($view)) { return; } file_put_contents( $view, str_replace('@vite(', '@viteReactRefresh'.PHP_EOL.' @vite(', file_get_contents($view)) ); } /** * Get full view path relative to the application's configured view path. * * @param string $path * @return string */ protected static function getViewPath($path) { return implode(DIRECTORY_SEPARATOR, [ config('view.paths')[0] ?? resource_path('views'), $path, ]); } } src/Presets/bootstrap-stubs/_variables.scss000064400000000212150251047330015132 0ustar00// Body $body-bg: #f8fafc; // Typography $font-family-sans-serif: 'Nunito', sans-serif; $font-size-base: 0.9rem; $line-height-base: 1.6; src/Presets/bootstrap-stubs/app.scss000064400000000230150251047330013603 0ustar00// Fonts @import url('https://fonts.bunny.net/css?family=Nunito'); // Variables @import 'variables'; // Bootstrap @import 'bootstrap/scss/bootstrap'; src/Presets/bootstrap-stubs/bootstrap.js000064400000002221150251047330014503 0ustar00import 'bootstrap'; /** * We'll load the axios HTTP library which allows us to easily issue requests * to our Laravel back-end. This library automatically handles sending the * CSRF token as a header based on the value of the "XSRF" token cookie. */ import axios from 'axios'; window.axios = axios; window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; /** * Echo exposes an expressive API for subscribing to channels and listening * for events that are broadcast by Laravel. Echo and event broadcasting * allows your team to easily build robust real-time web applications. */ // import Echo from 'laravel-echo'; // import Pusher from 'pusher-js'; // window.Pusher = Pusher; // window.Echo = new Echo({ // broadcaster: 'pusher', // key: import.meta.env.VITE_PUSHER_APP_KEY, // wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, // wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, // wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, // forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', // enabledTransports: ['ws', 'wss'], // }); src/Presets/bootstrap-stubs/vite.config.js000064400000000470150251047330014705 0ustar00import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; export default defineConfig({ plugins: [ laravel({ input: [ 'resources/sass/app.scss', 'resources/js/app.js', ], refresh: true, }), ], }); src/Presets/vue-stubs/ExampleComponent.vue000064400000001050150251047330014710 0ustar00 src/Presets/vue-stubs/vite.config.js000064400000001206150251047330013465 0ustar00import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [ laravel({ input: [ 'resources/sass/app.scss', 'resources/js/app.js', ], refresh: true, }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false, }, }, }), ], resolve: { alias: { vue: 'vue/dist/vue.esm-bundler.js', }, }, }); src/Presets/vue-stubs/app.js000064400000002601150251047330012032 0ustar00/** * First we will load all of this project's JavaScript dependencies which * includes Vue and other libraries. It is a great starting point when * building robust, powerful web applications using Vue and Laravel. */ import './bootstrap'; import { createApp } from 'vue'; /** * Next, we will create a fresh Vue application instance. You may then begin * registering components with the application instance so they are ready * to use in your application's views. An example is included for you. */ const app = createApp({}); import ExampleComponent from './components/ExampleComponent.vue'; app.component('example-component', ExampleComponent); /** * The following block of code may be used to automatically register your * Vue components. It will recursively scan this directory for the Vue * components and automatically register them with their "basename". * * Eg. ./components/ExampleComponent.vue -> */ // Object.entries(import.meta.glob('./**/*.vue', { eager: true })).forEach(([path, definition]) => { // app.component(path.split('/').pop().replace(/\.\w+$/, ''), definition.default); // }); /** * Finally, we will attach the application instance to a HTML element with * an "id" attribute of "app". This element is included with the "auth" * scaffolding. Otherwise, you will need to add an element yourself. */ app.mount('#app'); src/AuthRouteMethods.php000064400000006657150251047330011326 0ustar00prependGroupNamespace('Auth\LoginController')) ? null : 'App\Http\Controllers'; $this->group(['namespace' => $namespace], function() use($options) { // Login Routes... if ($options['login'] ?? true) { $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); $this->post('login', 'Auth\LoginController@login'); } // Logout Routes... if ($options['logout'] ?? true) { $this->post('logout', 'Auth\LoginController@logout')->name('logout'); } // Registration Routes... if ($options['register'] ?? true) { $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); $this->post('register', 'Auth\RegisterController@register'); } // Password Reset Routes... if ($options['reset'] ?? true) { $this->resetPassword(); } // Password Confirmation Routes... if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) { $this->confirmPassword(); } // Email Verification Routes... if ($options['verify'] ?? false) { $this->emailVerification(); } }); }; } /** * Register the typical reset password routes for an application. * * @return callable */ public function resetPassword() { return function () { $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); }; } /** * Register the typical confirm password routes for an application. * * @return callable */ public function confirmPassword() { return function () { $this->get('password/confirm', 'Auth\ConfirmPasswordController@showConfirmForm')->name('password.confirm'); $this->post('password/confirm', 'Auth\ConfirmPasswordController@confirm'); }; } /** * Register the typical email verification routes for an application. * * @return callable */ public function emailVerification() { return function () { $this->get('email/verify', 'Auth\VerificationController@show')->name('verification.notice'); $this->get('email/verify/{id}/{hash}', 'Auth\VerificationController@verify')->name('verification.verify'); $this->post('email/resend', 'Auth\VerificationController@resend')->name('verification.resend'); }; } } src/ControllersCommand.php000064400000002332150251047330011651 0ustar00allFiles(__DIR__.'/../stubs/Auth')) ->each(function (SplFileInfo $file) use ($filesystem) { $filesystem->copy( $file->getPathname(), app_path('Http/Controllers/Auth/'.Str::replaceLast('.stub', '.php', $file->getFilename())) ); }); $this->components->info('Authentication scaffolding generated successfully.'); } } src/Auth/stubs/routes.stub000064400000000154150251047330011614 0ustar00 Auth::routes(); Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); src/Auth/stubs/controllers/HomeController.stub000064400000000734150251047330015601 0ustar00middleware('auth'); } /** * Show the application dashboard. * * @return \Illuminate\Contracts\Support\Renderable */ public function index() { return view('home'); } } src/Auth/bootstrap-stubs/auth/register.stub000064400000007054150251047330015101 0ustar00@extends('layouts.app') @section('content')
{{ __('Register') }}
@csrf
@error('name') {{ $message }} @enderror
@error('email') {{ $message }} @enderror
@error('password') {{ $message }} @enderror
@endsection src/Auth/bootstrap-stubs/auth/passwords/reset.stub000064400000005650150251047330016424 0ustar00@extends('layouts.app') @section('content')
{{ __('Reset Password') }}
@csrf
@error('email') {{ $message }} @enderror
@error('password') {{ $message }} @enderror
@endsection src/Auth/bootstrap-stubs/auth/passwords/email.stub000064400000003546150251047330016373 0ustar00@extends('layouts.app') @section('content')
{{ __('Reset Password') }}
@if (session('status')) @endif
@csrf
@error('email') {{ $message }} @enderror
@endsection src/Auth/bootstrap-stubs/auth/passwords/confirm.stub000064400000004010150251047330016724 0ustar00@extends('layouts.app') @section('content')
{{ __('Confirm Password') }}
{{ __('Please confirm your password before continuing.') }}
@csrf
@error('password') {{ $message }} @enderror
@if (Route::has('password.request')) {{ __('Forgot Your Password?') }} @endif
@endsection src/Auth/bootstrap-stubs/auth/verify.stub000064400000002156150251047330014557 0ustar00@extends('layouts.app') @section('content')
{{ __('Verify Your Email Address') }}
@if (session('resent')) @endif {{ __('Before proceeding, please check your email for a verification link.') }} {{ __('If you did not receive the email') }},
@csrf .
@endsection src/Auth/bootstrap-stubs/auth/login.stub000064400000006420150251047330014361 0ustar00@extends('layouts.app') @section('content')
{{ __('Login') }}
@csrf
@error('email') {{ $message }} @enderror
@error('password') {{ $message }} @enderror
@if (Route::has('password.request')) {{ __('Forgot Your Password?') }} @endif
@endsection src/Auth/bootstrap-stubs/layouts/app.stub000064400000006666150251047330014604 0ustar00 {{ config('app.name', 'Laravel') }} @vite(['resources/sass/app.scss', 'resources/js/app.js'])
@yield('content')
src/Auth/bootstrap-stubs/home.stub000064400000001212150251047330013232 0ustar00@extends('layouts.app') @section('content')
{{ __('Dashboard') }}
@if (session('status')) @endif {{ __('You are logged in!') }}
@endsection tests/AuthBackend/RegistersUsersTest.php000064400000005553150251047330014431 0ustar00loadLaravelMigrations(); } /** @test */ public function it_can_register_a_user() { $request = Request::create('/register', 'POST', [ 'name' => 'Taylor Otwell', 'email' => 'taylor@laravel.com', 'password' => 'secret-password', 'password_confirmation' => 'secret-password', ], [], [], [ 'HTTP_ACCEPT' => 'application/json', ]); $response = $this->handleRequestUsing($request, function ($request) { return $this->register($request); })->assertCreated(); $this->assertDatabaseHas('users', [ 'name' => 'Taylor Otwell', 'email' => 'taylor@laravel.com', ]); } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return \App\Models\User */ protected function create(array $data) { $user = (new User())->forceFill([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); $user->save(); return $user; } /** * Handle Request using the following pipeline. * * @param \Illuminate\Http\Request $request * @param callable $callback * @return \Illuminate\Testing\TestResponse */ protected function handleRequestUsing(Request $request, callable $callback) { return new TestResponse( (new Pipeline($this->app)) ->send($request) ->through([ \Illuminate\Session\Middleware\StartSession::class, ]) ->then($callback) ); } } tests/AuthBackend/AuthenticatesUsersTest.php000064400000011463150251047330015260 0ustar00loadLaravelMigrations(); } /** @test */ public function it_can_authenticate_a_user() { Event::fake(); $user = UserFactory::new()->create(); $request = Request::create('/login', 'POST', [ 'email' => $user->email, 'password' => 'password', ], [], [], [ 'HTTP_ACCEPT' => 'application/json', ]); $response = $this->handleRequestUsing($request, function ($request) { return $this->login($request); })->assertStatus(204); Event::assertDispatched(function (Attempting $event) { return $event->remember === false; }); } /** @test */ public function it_can_authenticate_a_user_with_remember_as_false() { Event::fake(); $user = UserFactory::new()->create(); $request = Request::create('/login', 'POST', [ 'email' => $user->email, 'password' => 'password', 'remember' => false, ], [], [], [ 'HTTP_ACCEPT' => 'application/json', ]); $response = $this->handleRequestUsing($request, function ($request) { return $this->login($request); })->assertStatus(204); Event::assertDispatched(function (Attempting $event) { return $event->remember === false; }); } /** @test */ public function it_can_authenticate_a_user_with_remember_as_true() { Event::fake(); $user = UserFactory::new()->create(); $request = Request::create('/login', 'POST', [ 'email' => $user->email, 'password' => 'password', 'remember' => true, ], [], [], [ 'HTTP_ACCEPT' => 'application/json', ]); $response = $this->handleRequestUsing($request, function ($request) { return $this->login($request); })->assertStatus(204); Event::assertDispatched(function (Attempting $event) { return $event->remember === true; }); } /** @test */ public function it_cant_authenticate_a_user_with_invalid_password() { $user = UserFactory::new()->create(); $request = Request::create('/login', 'POST', [ 'email' => $user->email, 'password' => 'invalid-password', ], [], [], [ 'HTTP_ACCEPT' => 'application/json', ]); $response = $this->handleRequestUsing($request, function ($request) { return $this->login($request); })->assertUnprocessable(); $this->assertInstanceOf(ValidationException::class, $response->exception); $this->assertSame([ 'email' => [ 'These credentials do not match our records.', ], ], $response->exception->errors()); } /** @test */ public function it_cant_authenticate_unknown_credential() { $request = Request::create('/login', 'POST', [ 'email' => 'taylor@laravel.com', 'password' => 'password', ], [], [], [ 'HTTP_ACCEPT' => 'application/json', ]); $response = $this->handleRequestUsing($request, function ($request) { return $this->login($request); })->assertUnprocessable(); $this->assertInstanceOf(ValidationException::class, $response->exception); $this->assertSame([ 'email' => [ 'These credentials do not match our records.', ], ], $response->exception->errors()); } /** * Handle Request using the following pipeline. * * @param \Illuminate\Http\Request $request * @param callable $callback * @return \Illuminate\Testing\TestResponse */ protected function handleRequestUsing(Request $request, callable $callback) { return new TestResponse( (new Pipeline($this->app)) ->send($request) ->through([ \Illuminate\Session\Middleware\StartSession::class, ]) ->then($callback) ); } } tests/AuthBackend/ThrottleLoginsTest.php000064400000002735150251047330014420 0ustar00getMockForTrait(ThrottlesLogins::class, [], '', true, true, true, ['username']); $throttle->method('username')->willReturn('email'); $reflection = new \ReflectionClass($throttle); $method = $reflection->getMethod('throttleKey'); $method->setAccessible(true); $request = $this->mock(Request::class); $request->expects('input')->with('email')->andReturn($email); $request->expects('ip')->andReturn('192.168.0.1'); $this->assertSame($expectedEmail . '|192.168.0.1', $method->invoke($throttle, $request)); } public function emailProvider(): array { return [ 'lowercase special characters' => ['ⓣⓔⓢⓣ@ⓛⓐⓡⓐⓥⓔⓛ.ⓒⓞⓜ', 'test@laravel.com'], 'uppercase special characters' => ['ⓉⒺⓈⓉ@ⓁⒶⓇⒶⓋⒺⓁ.ⒸⓄⓂ', 'test@laravel.com'], 'special character numbers' =>['test⑩⓸③@laravel.com', 'test1043@laravel.com'], 'default email' => ['test@laravel.com', 'test@laravel.com'], ]; } } README.md000064400000022450150251047330006026 0ustar00# Laravel UI Total Downloads Latest Stable Version License ## Introduction While Laravel does not dictate which JavaScript or CSS pre-processors you use, it does provide a basic starting point using [Bootstrap](https://getbootstrap.com/), [React](https://reactjs.org/), and / or [Vue](https://vuejs.org/) that will be helpful for many applications. By default, Laravel uses [NPM](https://www.npmjs.org/) to install both of these frontend packages. > This legacy package is a very simple authentication scaffolding built on the Bootstrap CSS framework. While it continues to work with the latest version of Laravel, you should consider using [Laravel Breeze](https://github.com/laravel/breeze) for new projects. Or, for something more robust, consider [Laravel Jetstream](https://github.com/laravel/jetstream). ## Official Documentation ### Supported Versions Only the latest major version of Laravel UI receives bug fixes. The table below lists compatible Laravel versions: | Version | Laravel Version | |---- |----| | [1.x](https://github.com/laravel/ui/tree/1.x) | 5.8, 6.x | | [2.x](https://github.com/laravel/ui/tree/2.x) | 7.x | | [3.x](https://github.com/laravel/ui/tree/3.x) | 8.x | | [4.x](https://github.com/laravel/ui/tree/4.x) | 9.x, 10.x | ### Installation The Bootstrap and Vue scaffolding provided by Laravel is located in the `laravel/ui` Composer package, which may be installed using Composer: ```bash composer require laravel/ui ``` Once the `laravel/ui` package has been installed, you may install the frontend scaffolding using the `ui` Artisan command: ```bash // Generate basic scaffolding... php artisan ui bootstrap php artisan ui vue php artisan ui react // Generate login / registration scaffolding... php artisan ui bootstrap --auth php artisan ui vue --auth php artisan ui react --auth ``` #### CSS Laravel officially supports [Vite](https://laravel.com/docs/vite), a modern frontend build tool that provides an extremely fast development environment and bundles your code for production. Vite supports a variety of CSS preprocessor languages, including SASS and Less, which are extensions of plain CSS that add variables, mixins, and other powerful features that make working with CSS much more enjoyable. In this document, we will briefly discuss CSS compilation in general; however, you should consult the full [Vite documentation](https://laravel.com/docs/vite#working-with-stylesheets) for more information on compiling SASS or Less. #### JavaScript Laravel does not require you to use a specific JavaScript framework or library to build your applications. In fact, you don't have to use JavaScript at all. However, Laravel does include some basic scaffolding to make it easier to get started writing modern JavaScript using the [Vue](https://vuejs.org) library. Vue provides an expressive API for building robust JavaScript applications using components. As with CSS, we may use Vite to easily compile JavaScript components into a single, browser-ready JavaScript file. ### Writing CSS After installing the `laravel/ui` Composer package and [generating the frontend scaffolding](#introduction), Laravel's `package.json` file will include the `bootstrap` package to help you get started prototyping your application's frontend using Bootstrap. However, feel free to add or remove packages from the `package.json` file as needed for your own application. You are not required to use the Bootstrap framework to build your Laravel application - it is provided as a good starting point for those who choose to use it. Before compiling your CSS, install your project's frontend dependencies using the [Node package manager (NPM)](https://www.npmjs.org): ```bash npm install ``` Once the dependencies have been installed using `npm install`, you can compile your SASS files to plain CSS using [Vite](https://laravel.com/docs/vite#working-with-stylesheets). The `npm run dev` command will process the instructions in your `vite.config.js` file. Typically, your compiled CSS will be placed in the `public/build/assets` directory: ```bash npm run dev ``` The `vite.config.js` file included with Laravel's frontend scaffolding will compile the `resources/sass/app.scss` SASS file. This `app.scss` file imports a file of SASS variables and loads Bootstrap, which provides a good starting point for most applications. Feel free to customize the `app.scss` file however you wish or even use an entirely different pre-processor by [configuring Vite](https://laravel.com/docs/vite#working-with-stylesheets). ### Writing JavaScript All of the JavaScript dependencies required by your application can be found in the `package.json` file in the project's root directory. This file is similar to a `composer.json` file except it specifies JavaScript dependencies instead of PHP dependencies. You can install these dependencies using the [Node package manager (NPM)](https://www.npmjs.org): ```bash npm install ``` > By default, the Laravel `package.json` file includes a few packages such as `lodash` and `axios` to help you get started building your JavaScript application. Feel free to add or remove from the `package.json` file as needed for your own application. Once the packages are installed, you can use the `npm run dev` command to [compile your assets](https://laravel.com/docs/vite). Vite is a module bundler for modern JavaScript applications. When you run the `npm run dev` command, Vite will execute the instructions in your `vite.config.js` file: ```bash npm run dev ``` By default, the Laravel `vite.config.js` file compiles your SASS and the `resources/js/app.js` file. Within the `app.js` file you may register your Vue components or, if you prefer a different framework, configure your own JavaScript application. Your compiled JavaScript will typically be placed in the `public/build/assets` directory. > The `app.js` file will load the `resources/js/bootstrap.js` file which bootstraps and configures Vue, Axios, jQuery, and all other JavaScript dependencies. If you have additional JavaScript dependencies to configure, you may do so in this file. #### Writing Vue Components When using the `laravel/ui` package to scaffold your frontend, an `ExampleComponent.vue` Vue component will be placed in the `resources/js/components` directory. The `ExampleComponent.vue` file is an example of a [single file Vue component](https://vuejs.org/guide/single-file-components) which defines its JavaScript and HTML template in the same file. Single file components provide a very convenient approach to building JavaScript driven applications. The example component is registered in your `app.js` file: ```javascript import ExampleComponent from './components/ExampleComponent.vue'; Vue.component('example-component', ExampleComponent); ``` To use the component in your application, you may drop it into one of your HTML templates. For example, after running the `php artisan ui vue --auth` Artisan command to scaffold your application's authentication and registration screens, you could drop the component into the `home.blade.php` Blade template: ```blade @extends('layouts.app') @section('content') @endsection ``` > Remember, you should run the `npm run dev` command each time you change a Vue component. Or, you may run the `npm run watch` command to monitor and automatically recompile your components each time they are modified. If you are interested in learning more about writing Vue components, you should read the [Vue documentation](https://vuejs.org/guide/), which provides a thorough, easy-to-read overview of the entire Vue framework. #### Using React If you prefer to use React to build your JavaScript application, Laravel makes it a cinch to swap the Vue scaffolding with React scaffolding: ```bash composer require laravel/ui // Generate basic scaffolding... php artisan ui react // Generate login / registration scaffolding... php artisan ui react --auth ```` ### Adding Presets Presets are "macroable", which allows you to add additional methods to the `UiCommand` class at runtime. For example, the following code adds a `nextjs` method to the `UiCommand` class. Typically, you should declare preset macros in a [service provider](https://laravel.com/docs/providers): ```php use Laravel\Ui\UiCommand; UiCommand::macro('nextjs', function (UiCommand $command) { // Scaffold your frontend... }); ``` Then, you may call the new preset via the `ui` command: ```bash php artisan ui nextjs ``` ## Contributing Thank you for considering contributing to UI! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). ## Code of Conduct In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). ## Security Vulnerabilities Please review [our security policy](https://github.com/laravel/ui/security/policy) on how to report security vulnerabilities. ## License Laravel UI is open-sourced software licensed under the [MIT license](LICENSE.md). stubs/migrations/2014_10_12_100000_create_password_resets_table.php000064400000001235150251047330020563 0ustar00string('email')->index(); $table->string('token'); $table->timestamp('created_at')->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('password_resets'); } }; stubs/Auth/RegisterController.stub000064400000003654150251047330013344 0ustar00middleware('guest'); } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return \App\Models\User */ protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); } } stubs/Auth/ResetPasswordController.stub000064400000001514150251047330014356 0ustar00middleware('auth'); $this->middleware('signed')->only('verify'); $this->middleware('throttle:6,1')->only('verify', 'resend'); } } stubs/Auth/LoginController.stub000064400000001752150251047330012625 0ustar00middleware('guest')->except('logout'); } } stubs/Auth/ConfirmPasswordController.stub000064400000002000150251047330014660 0ustar00middleware('auth'); } }