status: completed

input:
const patch = "*** Begin Patch\n*** Delete File: /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/register.blade.php\n*** Add File: /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/register.blade.php\n+
\n+
Join us
\n+
Create your account
\n+    <form wire:submit=\"register\" class=\"mt-8 space-y-5\">\n+
\n+
First name<input id=\"first-name\" autocomplete=\"given-name\" wire:model=\"firstName\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">
\n+
Last name<input id=\"last-name\" autocomplete=\"family-name\" wire:model=\"lastName\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">
\n+
\n+
Email<input id=\"register-email\" type=\"email\" autocomplete=\"email\" wire:model=\"email\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">
\n+
Password<input id=\"register-password\" type=\"password\" autocomplete=\"new-password\" wire:model=\"password\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">
\n+
Confirm password<input id=\"register-password-confirmation\" type=\"password\" autocomplete=\"new-password\" wire:model=\"passwordConfirmation\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">
\n+        <input type=\"checkbox\" wire:model=\"marketingOptIn\" class=\"mt-1\">Send me occasional product updates and offers.\n+        @error('*')
{{ $message }}
@enderror\n+        <button class=\"w-full rounded-full bg-blue-600 px-5 py-3 font-semibold text-white\">Create account</button>\n+    </form>\n+
\n*** End Patch";
text(await tools.apply_patch(patch));


type: FileChange

type: add

content:
Join us

Create your account

    <form wire:submit="register" class="mt-8 space-y-5">

First name<input id="first-name" autocomplete="given-name" wire:model="firstName" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">

Last name<input id="last-name" autocomplete="family-name" wire:model="lastName" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">

Email<input id="register-email" type="email" autocomplete="email" wire:model="email" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">

Password<input id="register-password" type="password" autocomplete="new-password" wire:model="password" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">

Confirm password<input id="register-password-confirmation" type="password" autocomplete="new-password" wire:model="passwordConfirmation" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">

        <input type="checkbox" wire:model="marketingOptIn" class="mt-1">Send me occasional product updates and offers.
        @error('*')
{{ $message }}
@enderror
        <button class="w-full rounded-full bg-blue-600 px-5 py-3 font-semibold text-white">Create account</button>
    </form>

status: completed

stdout:
Success. Updated the following files:
A /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/register.blade.php
D /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/register.blade.php


text:
Script completed
Wall time 0.0 seconds
Output:


exec

status: completed

input:
const patch = "*** Begin Patch\n*** Delete File: /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/login.blade.php\n*** Add File: /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/login.blade.php\n+
\n+
Welcome back
\n+
Log in
\n+    <form wire:submit=\"login\" class=\"mt-8 space-y-5\">\n+
Email<input id=\"email\" type=\"email\" autocomplete=\"email\" wire:model=\"email\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">@error('email')
{{ $message }}
@enderror
\n+
Password<input id=\"password\" type=\"password\" autocomplete=\"current-password\" wire:model=\"password\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900\">@error('password')
{{ $message }}
@enderror
\n+        <input type=\"checkbox\" wire:model=\"remember\"> Remember me\n+        <button class=\"w-full rounded-full bg-blue-600 px-5 py-3 font-semibold text-white\">Log in</button>\n+    </form>\n+
New here? Create an account
\n+    Forgot password?\n+
\n*** Delete File: /Users/wesner/Herd/shop/resources/views/livewire/admin/auth/login.blade.php\n*** Add File: /Users/wesner/Herd/shop/resources/views/livewire/admin/auth/login.blade.php\n+
\n+
Acme Fashion
\n+
Sign in
\n+
Admin access
\n+    <form wire:submit=\"login\" class=\"mt-8 space-y-5\">\n+
Email<input id=\"admin-email\" type=\"email\" autocomplete=\"email\" wire:model=\"email\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3\">@error('email')
{{ $message }}
@enderror
\n+
Password<input id=\"admin-password\" type=\"password\" autocomplete=\"current-password\" wire:model=\"password\" class=\"mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3\">@error('password')
{{ $message }}
@enderror
\n+        <input type=\"checkbox\" wire:model=\"remember\"> Remember me\n+        <button class=\"w-full rounded-full bg-zinc-900 px-5 py-3 font-semibold text-white\">Sign in</button>\n+    </form>\n+    Forgot password?\n+
\n*** End Patch";
text(await tools.apply_patch(patch));


content:
Acme Fashion

Sign in

Admin access

    <form wire:submit="login" class="mt-8 space-y-5">

Email<input id="admin-email" type="email" autocomplete="email" wire:model="email" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3">@error('email')
{{ $message }}
@enderror

Password<input id="admin-password" type="password" autocomplete="current-password" wire:model="password" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3">@error('password')
{{ $message }}
@enderror

        <input type="checkbox" wire:model="remember"> Remember me
        <button class="w-full rounded-full bg-zinc-900 px-5 py-3 font-semibold text-white">Sign in</button>
    </form>
    Forgot password?

content:
Welcome back

Log in

    <form wire:submit="login" class="mt-8 space-y-5">

Email<input id="email" type="email" autocomplete="email" wire:model="email" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">@error('email')
{{ $message }}
@enderror

Password<input id="password" type="password" autocomplete="current-password" wire:model="password" class="mt-2 w-full rounded-lg border border-zinc-300 px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">@error('password')
{{ $message }}
@enderror

        <input type="checkbox" wire:model="remember"> Remember me
        <button class="w-full rounded-full bg-blue-600 px-5 py-3 font-semibold text-white">Log in</button>
    </form>

New here? Create an account

    Forgot password?

stdout:
Success. Updated the following files:
A /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/login.blade.php
A /Users/wesner/Herd/shop/resources/views/livewire/admin/auth/login.blade.php
D /Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/login.blade.php
D /Users/wesner/Herd/shop/resources/views/livewire/admin/auth/login.blade.php


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const r = await tools.exec_command({cmd:"sed -n '1,180p' app/Livewire/Storefront/Account/Auth/ForgotPassword.php; sed -n '1,180p' app/Livewire/Storefront/Account/Auth/ResetPassword.php; sed -n '1,160p' app/Livewire/Admin/Auth/ForgotPassword.php; sed -n '1,160p' app/Livewire/Admin/Auth/ResetPassword.php; sed -n '1,220p' app/Providers/FortifyServiceProvider.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":16000});
text(r.output);


type: CommandExecution

command: sed -n '1,180p' app/Livewire/Storefront/Account/Auth/ForgotPassword.php; sed -n '1,180p' app/Livewire/Storefront/Account/Auth/ResetPassword.php; sed -n '1,160p' app/Livewire/Admin/Auth/ForgotPassword.php; sed -n '1,160p' app/Livewire/Admin/Auth/ResetPassword.php; sed -n '1,220p' app/Providers/FortifyServiceProvider.php

ForgotPassword.php

type: read

FortifyServiceProvider.php

stdout:
<?php

namespace App\Livewire\Storefront\Account\Auth;

use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ForgotPassword extends Component
{
    public string $email = '';

    public string $message = '';

    public function sendResetLink(): void
    {
        $this->validate(['email' => ['required', 'email']]);
        Password::broker('customers')->sendResetLink(['email' => $this->email]);
        $this->message = 'If an account exists for that email, a reset link has been sent.';
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.forgot-password')->layout('layouts.storefront');
    }
}
<?php

namespace App\Livewire\Storefront\Account\Auth;

use App\Models\Customer;
use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ResetPassword extends Component
{
    public string $token;

    public string $email = '';

    public string $password = '';

    public string $passwordConfirmation = '';

    public function mount(string $token): void
    {
        $this->token = $token;
        $this->email = request()->string('email')->toString();
    }

    public function resetPassword(): void
    {
        $data = $this->validate(['email' => ['required', 'email'], 'password' => ['required', 'min:8', 'same:passwordConfirmation']]);
        $status = Password::broker('customers')->reset(['email' => $data['email'], 'password' => $data['password'], 'password_confirmation' => $this->passwordConfirmation, 'token' => $this->token], function (Customer $customer, string $password): void {
            $customer->password_hash = $password;
            $customer->save();
        });

        if ($status !== Password::PASSWORD_RESET) {
            $this->addError('email', __($status));

            return;
        }

        $this->redirect(route('account.login'), navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.reset-password')->layout('layouts.storefront');
    }
}
<?php

namespace App\Livewire\Admin\Auth;

use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ForgotPassword extends Component
{
    public string $email = '';

    public string $message = '';

    public function sendResetLink(): void
    {
        $this->validate(['email' => ['required', 'email']]);
        Password::broker('users')->sendResetLink(['email' => $this->email]);
        $this->message = 'If an account exists for that email, a reset link has been sent.';
    }

    public function render(): mixed
    {
        return view('livewire.admin.auth.forgot-password')->layout('layouts.auth');
    }
}
<?php

namespace App\Livewire\Admin\Auth;

use App\Models\User;
use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ResetPassword extends Component
{
    public string $token;

    public string $email = '';

    public string $password = '';

    public string $passwordConfirmation = '';

    public function mount(string $token): void
    {
        $this->token = $token;
        $this->email = request()->string('email')->toString();
    }

    public function resetPassword(): void
    {
        $data = $this->validate(['email' => ['required', 'email'], 'password' => ['required', 'min:8', 'same:passwordConfirmation']]);
        $status = Password::broker('users')->reset(['email' => $data['email'], 'password' => $data['password'], 'password_confirmation' => $this->passwordConfirmation, 'token' => $this->token], function (User $user, string $password): void {
            $user->password = $password;
            $user->save();
        });

        if ($status !== Password::PASSWORD_RESET) {
            $this->addError('email', __($status));

            return;
        }

        $this->redirect(route('admin.login'), navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.admin.auth.reset-password')->layout('layouts.auth');
    }
}
<?php

namespace App\Providers;

use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;

class FortifyServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $this->configureActions();
        $this->configureViews();
        $this->configureRateLimiting();
    }

    /**
     * Configure Fortify actions.
     */
    private function configureActions(): void
    {
        Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
        Fortify::createUsersUsing(CreateNewUser::class);
    }

    /**
     * Configure Fortify views.
     */
    private function configureViews(): void
    {
        Fortify::loginView(fn () => view('livewire.auth.login'));
        Fortify::verifyEmailView(fn () => view('livewire.auth.verify-email'));
        Fortify::twoFactorChallengeView(fn () => view('livewire.auth.two-factor-challenge'));
        Fortify::confirmPasswordView(fn () => view('livewire.auth.confirm-password'));
        Fortify::registerView(fn () => view('livewire.auth.register'));
        Fortify::resetPasswordView(fn () => view('livewire.auth.reset-password'));
        Fortify::requestPasswordResetLinkView(fn () => view('livewire.auth.forgot-password'));
    }

    /**
     * Configure rate limiting.
     */
    private function configureRateLimiting(): void
    {
        RateLimiter::for('two-factor', function (Request $request) {
            return Limit::perMinute(5)->by($request->session()->get('login.id'));
        });

        RateLimiter::for('login', function (Request $request) {
            $throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());

            return Limit::perMinute(5)->by($throttleKey);
        });
    }
}


text:
Script completed
Wall time 0.1 seconds
Output:

text:
<?php

namespace App\Livewire\Storefront\Account\Auth;

use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ForgotPassword extends Component
{
    public string $email = '';

    public string $message = '';

    public function sendResetLink(): void
    {
        $this->validate(['email' => ['required', 'email']]);
        Password::broker('customers')->sendResetLink(['email' => $this->email]);
        $this->message = 'If an account exists for that email, a reset link has been sent.';
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.forgot-password')->layout('layouts.storefront');
    }
}
<?php

namespace App\Livewire\Storefront\Account\Auth;

use App\Models\Customer;
use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ResetPassword extends Component
{
    public string $token;

    public string $email = '';

    public string $password = '';

    public string $passwordConfirmation = '';

    public function mount(string $token): void
    {
        $this->token = $token;
        $this->email = request()->string('email')->toString();
    }

    public function resetPassword(): void
    {
        $data = $this->validate(['email' => ['required', 'email'], 'password' => ['required', 'min:8', 'same:passwordConfirmation']]);
        $status = Password::broker('customers')->reset(['email' => $data['email'], 'password' => $data['password'], 'password_confirmation' => $this->passwordConfirmation, 'token' => $this->token], function (Customer $customer, string $password): void {
            $customer->password_hash = $password;
            $customer->save();
        });

        if ($status !== Password::PASSWORD_RESET) {
            $this->addError('email', __($status));

            return;
        }

        $this->redirect(route('account.login'), navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.reset-password')->layout('layouts.storefront');
    }
}
<?php

namespace App\Livewire\Admin\Auth;

use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ForgotPassword extends Component
{
    public string $email = '';

    public string $message = '';

    public function sendResetLink(): void
    {
        $this->validate(['email' => ['required', 'email']]);
        Password::broker('users')->sendResetLink(['email' => $this->email]);
        $this->message = 'If an account exists for that email, a reset link has been sent.';
    }

    public function render(): mixed
    {
        return view('livewire.admin.auth.forgot-password')->layout('layouts.auth');
    }
}
<?php

namespace App\Livewire\Admin\Auth;

use App\Models\User;
use Illuminate\Support\Facades\Password;
use Livewire\Component;

class ResetPassword extends Component
{
    public string $token;

    public string $email = '';

    public string $password = '';

    public string $passwordConfirmation = '';

    public function mount(string $token): void
    {
        $this->token = $token;
        $this->email = request()->string('email')->toString();
    }

    public function resetPassword(): void
    {
        $data = $this->validate(['email' => ['required', 'email'], 'password' => ['required', 'min:8', 'same:passwordConfirmation']]);
        $status = Password::broker('users')->reset(['email' => $data['email'], 'password' => $data['password'], 'password_confirmation' => $this->passwordConfirmation, 'token' => $this->token], function (User $user, string $password): void {
            $user->password = $password;
            $user->save();
        });

        if ($status !== Password::PASSWORD_RESET) {
            $this->addError('email', __($status));

            return;
        }

        $this->redirect(route('admin.login'), navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.admin.auth.reset-password')->layout('layouts.auth');
    }
}
<?php

namespace App\Providers;

use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;

class FortifyServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $this->configureActions();
        $this->configureViews();
        $this->configureRateLimiting();
    }

    /**
     * Configure Fortify actions.
     */
    private function configureActions(): void
    {
        Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
        Fortify::createUsersUsing(CreateNewUser::class);
    }

    /**
     * Configure Fortify views.
     */
    private function configureViews(): void
    {
        Fortify::loginView(fn () => view('livewire.auth.login'));
        Fortify::verifyEmailView(fn () => view('livewire.auth.verify-email'));
        Fortify::twoFactorChallengeView(fn () => view('livewire.auth.two-factor-challenge'));
        Fortify::confirmPasswordView(fn () => view('livewire.auth.confirm-password'));
        Fortify::registerView(fn () => view('livewire.auth.register'));
        Fortify::resetPasswordView(fn () => view('livewire.auth.reset-password'));
        Fortify::requestPasswordResetLinkView(fn () => view('livewire.auth.forgot-password'));
    }

    /**
     * Configure rate limiting.
     */
    private function configureRateLimiting(): void
    {
        RateLimiter::for('two-factor', function (Request $request) {
            return Limit::perMinute(5)->by($request->session()->get('login.id'));
        });

        RateLimiter::for('login', function (Request $request) {
            $throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());

            return Limit::perMinute(5)->by($throttleKey);
        });
    }
}


exec

status: completed

input:
const r = await tools.exec_command({cmd:"sed -n '1,260p' vendor/laravel/framework/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php; sed -n '1,180p' vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php; sed -n '1,180p' vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":22000});
text(r.output);


command: sed -n '1,260p' vendor/laravel/framework/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php; sed -n '1,180p' vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php; sed -n '1,180p' vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php

PasswordBrokerManager.php

stdout:
<?php

namespace Illuminate\Auth\Passwords;

use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

class DatabaseTokenRepository implements TokenRepositoryInterface
{
    /**
     * Create a new token repository instance.
     *
     * @param  int  $expires  The number of seconds a token should remain valid.
     * @param  int  $throttle  Minimum number of seconds before the user can generate new password reset tokens.
     */
    public function __construct(
        protected ConnectionInterface $connection,
        protected HasherContract $hasher,
        protected string $table,
        protected string $hashKey,
        protected int $expires = 3600,
        protected int $throttle = 60,
    ) {
    }

    /**
     * Create a new token record.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return string
     */
    public function create(CanResetPasswordContract $user)
    {
        $email = $user->getEmailForPasswordReset();

        $this->deleteExisting($user);

        // We will create a new, random token for the user so that we can e-mail them
        // a safe link to the password reset form. Then we will insert a record in
        // the database so that we can verify the token within the actual reset.
        $token = $this->createNewToken();

        $this->getTable()->insert($this->getPayload($email, $token));

        return $token;
    }

    /**
     * Delete all existing reset tokens from the database.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return int
     */
    protected function deleteExisting(CanResetPasswordContract $user)
    {
        return $this->getTable()->where('email', $user->getEmailForPasswordReset())->delete();
    }

    /**
     * Build the record payload for the table.
     *
     * @param  string  $email
     * @param  string  $token
     * @return array
     */
    protected function getPayload($email, #[\SensitiveParameter] $token)
    {
        return ['email' => $email, 'token' => $this->hasher->make($token), 'created_at' => new Carbon];
    }

    /**
     * Determine if a token record exists and is valid.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @param  string  $token
     * @return bool
     */
    public function exists(CanResetPasswordContract $user, #[\SensitiveParameter] $token)
    {
        $record = (array) $this->getTable()->where(
            'email', $user->getEmailForPasswordReset()
        )->first();

        return $record &&
               ! $this->tokenExpired($record['created_at']) &&
                 $this->hasher->check($token, $record['token']);
    }

    /**
     * Determine if the token has expired.
     *
     * @param  string  $createdAt
     * @return bool
     */
    protected function tokenExpired($createdAt)
    {
        return Carbon::parse($createdAt)->addSeconds($this->expires)->isPast();
    }

    /**
     * Determine if the given user recently created a password reset token.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return bool
     */
    public function recentlyCreatedToken(CanResetPasswordContract $user)
    {
        $record = (array) $this->getTable()->where(
            'email', $user->getEmailForPasswordReset()
        )->first();

        return $record && $this->tokenRecentlyCreated($record['created_at']);
    }

    /**
     * Determine if the token was recently created.
     *
     * @param  string  $createdAt
     * @return bool
     */
    protected function tokenRecentlyCreated($createdAt)
    {
        if ($this->throttle <= 0) {
            return false;
        }

        return Carbon::parse($createdAt)->addSeconds(
            $this->throttle
        )->isFuture();
    }

    /**
     * Delete a token record by user.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return void
     */
    public function delete(CanResetPasswordContract $user)
    {
        $this->deleteExisting($user);
    }

    /**
     * Delete expired tokens.
     *
     * @return void
     */
    public function deleteExpired()
    {
        $expiredAt = Carbon::now()->subSeconds($this->expires);

        $this->getTable()->where('created_at', '<', $expiredAt)->delete();
    }

    /**
     * Create a new token for the user.
     *
     * @return string
     */
    public function createNewToken()
    {
        return hash_hmac('sha256', Str::random(40), $this->hashKey);
    }

    /**
     * Get the database connection instance.
     *
     * @return \Illuminate\Database\ConnectionInterface
     */
    public function getConnection()
    {
        return $this->connection;
    }

    /**
     * Begin a new database query against the table.
     *
     * @return \Illuminate\Database\Query\Builder
     */
    protected function getTable()
    {
        return $this->connection->table($this->table);
    }

    /**
     * Get the hasher instance.
     *
     * @return \Illuminate\Contracts\Hashing\Hasher
     */
    public function getHasher()
    {
        return $this->hasher;
    }
}
<?php

namespace Illuminate\Auth\Passwords;

use Closure;
use Illuminate\Auth\Events\PasswordResetLinkSent;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
use Illuminate\Support\Timebox;
use UnexpectedValueException;

class PasswordBroker implements PasswordBrokerContract
{
    /**
     * The password token repository.
     *
     * @var \Illuminate\Auth\Passwords\TokenRepositoryInterface
     */
    protected $tokens;

    /**
     * The user provider implementation.
     *
     * @var \Illuminate\Contracts\Auth\UserProvider
     */
    protected $users;

    /**
     * The event dispatcher instance.
     *
     * @var \Illuminate\Contracts\Events\Dispatcher|null
     */
    protected $events;

    /**
     * The timebox instance.
     *
     * @var \Illuminate\Support\Timebox
     */
    protected $timebox;

    /**
     * The number of microseconds that the timebox should wait for.
     *
     * @var int
     */
    protected $timeboxDuration;

    /**
     * Create a new password broker instance.
     *
     * @param  \Illuminate\Auth\Passwords\TokenRepositoryInterface  $tokens
     * @param  \Illuminate\Contracts\Auth\UserProvider  $users
     * @param  \Illuminate\Contracts\Events\Dispatcher|null  $dispatcher
     * @param  \Illuminate\Support\Timebox|null  $timebox
     * @param  int  $timeboxDuration
     */
    public function __construct(
        #[\SensitiveParameter] TokenRepositoryInterface $tokens,
        UserProvider $users,
        ?Dispatcher $dispatcher = null,
        ?Timebox $timebox = null,
        int $timeboxDuration = 200000,
    ) {
        $this->users = $users;
        $this->tokens = $tokens;
        $this->events = $dispatcher;
        $this->timebox = $timebox ?: new Timebox;
        $this->timeboxDuration = $timeboxDuration;
    }

    /**
     * Send a password reset link to a user.
     *
     * @param  array  $credentials
     * @param  \Closure|null  $callback
     * @return string
     */
    public function sendResetLink(#[\SensitiveParameter] array $credentials, ?Closure $callback = null)
    {
        return $this->timebox->call(function () use ($credentials, $callback) {
            // First we will check to see if we found a user at the given credentials and
            // if we did not we will redirect back to this current URI with a piece of
            // "flash" data in the session to indicate to the developers the errors.
            $user = $this->getUser($credentials);

            if (is_null($user)) {
                return static::INVALID_USER;
            }

            if ($this->tokens->recentlyCreatedToken($user)) {
                return static::RESET_THROTTLED;
            }

            $token = $this->tokens->create($user);

            if ($callback) {
                return $callback($user, $token) ?? static::RESET_LINK_SENT;
            }

            // Once we have the reset token, we are ready to send the message out to this
            // user with a link to reset their password. We will then redirect back to
            // the current URI having nothing set in the session to indicate errors.
            $user->sendPasswordResetNotification($token);

            $this->events?->dispatch(new PasswordResetLinkSent($user));

            return static::RESET_LINK_SENT;
        }, $this->timeboxDuration);
    }

    /**
     * Reset the password for the given token.
     *
     * @param  array  $credentials
     * @param  \Closure  $callback
     * @return string
     */
    public function reset(#[\SensitiveParameter] array $credentials, Closure $callback)
    {
        return $this->timebox->call(function ($timebox) use ($credentials, $callback) {
            $user = $this->validateReset($credentials);

            // If the responses from the validate method is not a user instance, we will
            // assume that it is a redirect and simply return it from this method and
            // the user is properly redirected having an error message on the post.
            if (! $user instanceof CanResetPasswordContract) {
                return $user;
            }

            $password = $credentials['password'];

            // Once the reset has been validated, we'll call the given callback with the
            // new password. This gives the user an opportunity to store the password
            // in their persistent storage. Then we'll delete the token and return.
            $callback($user, $password);

            $this->tokens->delete($user);

            $timebox->returnEarly();

            return static::PASSWORD_RESET;
        }, $this->timeboxDuration);
    }

    /**
     * Validate a password reset for the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\CanResetPassword|string
     */
    protected function validateReset(#[\SensitiveParameter] array $credentials)
    {
        if (is_null($user = $this->getUser($credentials))) {
            return static::INVALID_USER;
        }

        if (! $this->tokens->exists($user, $credentials['token'])) {
            return static::INVALID_TOKEN;
        }

        return $user;
    }

    /**
     * Get the user for the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\CanResetPassword|null
     *
     * @throws \UnexpectedValueException
     */
    public function getUser(#[\SensitiveParameter] array $credentials)
    {
        $credentials = Arr::except($credentials, ['token']);

        $user = $this->users->retrieveByCredentials($credentials);
<?php

namespace Illuminate\Auth\Passwords;

use Illuminate\Contracts\Auth\PasswordBrokerFactory as FactoryContract;
use InvalidArgumentException;

/**
 * @mixin \Illuminate\Contracts\Auth\PasswordBroker
 */
class PasswordBrokerManager implements FactoryContract
{
    /**
     * The application instance.
     *
     * @var \Illuminate\Contracts\Foundation\Application
     */
    protected $app;

    /**
     * The array of created "drivers".
     *
     * @var array
     */
    protected $brokers = [];

    /**
     * Create a new PasswordBroker manager instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     */
    public function __construct($app)
    {
        $this->app = $app;
    }

    /**
     * Attempt to get the broker from the local cache.
     *
     * @param  string|null  $name
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     */
    public function broker($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

        return $this->brokers[$name] ?? ($this->brokers[$name] = $this->resolve($name));
    }

    /**
     * Resolve the given broker.
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     *
     * @throws \InvalidArgumentException
     */
    protected function resolve($name)
    {
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Password resetter [{$name}] is not defined.");
        }

        // The password broker uses a token repository to validate tokens and send user
        // password e-mails, as well as validating that password reset process as an
        // aggregate service of sorts providing a convenient interface for resets.
        return new PasswordBroker(
            $this->createTokenRepository($config),
            $this->app['auth']->createUserProvider($config['provider'] ?? null),
            $this->app['events'] ?? null,
            timeboxDuration: $this->app['config']->get('auth.timebox_duration', 200000),
        );
    }

    /**
     * Create a token repository instance based on the given configuration.
     *
     * @param  array  $config
     * @return \Illuminate\Auth\Passwords\TokenRepositoryInterface
     */
    protected function createTokenRepository(array $config)
    {
        $key = $this->app['config']['app.key'];

        if (str_starts_with($key, 'base64:')) {
            $key = base64_decode(substr($key, 7));
        }

        if (isset($config['driver']) && $config['driver'] === 'cache') {
            return new CacheTokenRepository(
                $this->app['cache']->store($config['store'] ?? null),
                $this->app['hash'],
                $key,
                ($config['expire'] ?? 60) * 60,
                $config['throttle'] ?? 0,
            );
        }

        return new DatabaseTokenRepository(
            $this->app['db']->connection($config['connection'] ?? null),
            $this->app['hash'],
            $config['table'],
            $key,
            ($config['expire'] ?? 60) * 60,
            $config['throttle'] ?? 0,
        );
    }

    /**
     * Get the password broker configuration.
     *
     * @param  string  $name
     * @return array|null
     */
    protected function getConfig($name)
    {
        return $this->app['config']["auth.passwords.{$name}"];
    }

    /**
     * Get the default password broker name.
     *
     * @return string
     */
    public function getDefaultDriver()
    {
        return $this->app['config']['auth.defaults.passwords'];
    }

    /**
     * Set the default password broker name.
     *
     * @param  string  $name
     * @return void
     */
    public function setDefaultDriver($name)
    {
        $this->app['config']['auth.defaults.passwords'] = $name;
    }

    /**
     * Dynamically call the default driver instance.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        return $this->broker()->{$method}(...$parameters);
    }
}


text:
Script completed
Wall time 0.1 seconds
Output:

text:
<?php

namespace Illuminate\Auth\Passwords;

use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

class DatabaseTokenRepository implements TokenRepositoryInterface
{
    /**
     * Create a new token repository instance.
     *
     * @param  int  $expires  The number of seconds a token should remain valid.
     * @param  int  $throttle  Minimum number of seconds before the user can generate new password reset tokens.
     */
    public function __construct(
        protected ConnectionInterface $connection,
        protected HasherContract $hasher,
        protected string $table,
        protected string $hashKey,
        protected int $expires = 3600,
        protected int $throttle = 60,
    ) {
    }

    /**
     * Create a new token record.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return string
     */
    public function create(CanResetPasswordContract $user)
    {
        $email = $user->getEmailForPasswordReset();

        $this->deleteExisting($user);

        // We will create a new, random token for the user so that we can e-mail them
        // a safe link to the password reset form. Then we will insert a record in
        // the database so that we can verify the token within the actual reset.
        $token = $this->createNewToken();

        $this->getTable()->insert($this->getPayload($email, $token));

        return $token;
    }

    /**
     * Delete all existing reset tokens from the database.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return int
     */
    protected function deleteExisting(CanResetPasswordContract $user)
    {
        return $this->getTable()->where('email', $user->getEmailForPasswordReset())->delete();
    }

    /**
     * Build the record payload for the table.
     *
     * @param  string  $email
     * @param  string  $token
     * @return array
     */
    protected function getPayload($email, #[\SensitiveParameter] $token)
    {
        return ['email' => $email, 'token' => $this->hasher->make($token), 'created_at' => new Carbon];
    }

    /**
     * Determine if a token record exists and is valid.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @param  string  $token
     * @return bool
     */
    public function exists(CanResetPasswordContract $user, #[\SensitiveParameter] $token)
    {
        $record = (array) $this->getTable()->where(
            'email', $user->getEmailForPasswordReset()
        )->first();

        return $record &&
               ! $this->tokenExpired($record['created_at']) &&
                 $this->hasher->check($token, $record['token']);
    }

    /**
     * Determine if the token has expired.
     *
     * @param  string  $createdAt
     * @return bool
     */
    protected function tokenExpired($createdAt)
    {
        return Carbon::parse($createdAt)->addSeconds($this->expires)->isPast();
    }

    /**
     * Determine if the given user recently created a password reset token.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return bool
     */
    public function recentlyCreatedToken(CanResetPasswordContract $user)
    {
        $record = (array) $this->getTable()->where(
            'email', $user->getEmailForPasswordReset()
        )->first();

        return $record && $this->tokenRecentlyCreated($record['created_at']);
    }

    /**
     * Determine if the token was recently created.
     *
     * @param  string  $createdAt
     * @return bool
     */
    protected function tokenRecentlyCreated($createdAt)
    {
        if ($this->throttle <= 0) {
            return false;
        }

        return Carbon::parse($createdAt)->addSeconds(
            $this->throttle
        )->isFuture();
    }

    /**
     * Delete a token record by user.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return void
     */
    public function delete(CanResetPasswordContract $user)
    {
        $this->deleteExisting($user);
    }

    /**
     * Delete expired tokens.
     *
     * @return void
     */
    public function deleteExpired()
    {
        $expiredAt = Carbon::now()->subSeconds($this->expires);

        $this->getTable()->where('created_at', '<', $expiredAt)->delete();
    }

    /**
     * Create a new token for the user.
     *
     * @return string
     */
    public function createNewToken()
    {
        return hash_hmac('sha256', Str::random(40), $this->hashKey);
    }

    /**
     * Get the database connection instance.
     *
     * @return \Illuminate\Database\ConnectionInterface
     */
    public function getConnection()
    {
        return $this->connection;
    }

    /**
     * Begin a new database query against the table.
     *
     * @return \Illuminate\Database\Query\Builder
     */
    protected function getTable()
    {
        return $this->connection->table($this->table);
    }

    /**
     * Get the hasher instance.
     *
     * @return \Illuminate\Contracts\Hashing\Hasher
     */
    public function getHasher()
    {
        return $this->hasher;
    }
}
<?php

namespace Illuminate\Auth\Passwords;

use Closure;
use Illuminate\Auth\Events\PasswordResetLinkSent;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
use Illuminate\Support\Timebox;
use UnexpectedValueException;

class PasswordBroker implements PasswordBrokerContract
{
    /**
     * The password token repository.
     *
     * @var \Illuminate\Auth\Passwords\TokenRepositoryInterface
     */
    protected $tokens;

    /**
     * The user provider implementation.
     *
     * @var \Illuminate\Contracts\Auth\UserProvider
     */
    protected $users;

    /**
     * The event dispatcher instance.
     *
     * @var \Illuminate\Contracts\Events\Dispatcher|null
     */
    protected $events;

    /**
     * The timebox instance.
     *
     * @var \Illuminate\Support\Timebox
     */
    protected $timebox;

    /**
     * The number of microseconds that the timebox should wait for.
     *
     * @var int
     */
    protected $timeboxDuration;

    /**
     * Create a new password broker instance.
     *
     * @param  \Illuminate\Auth\Passwords\TokenRepositoryInterface  $tokens
     * @param  \Illuminate\Contracts\Auth\UserProvider  $users
     * @param  \Illuminate\Contracts\Events\Dispatcher|null  $dispatcher
     * @param  \Illuminate\Support\Timebox|null  $timebox
     * @param  int  $timeboxDuration
     */
    public function __construct(
        #[\SensitiveParameter] TokenRepositoryInterface $tokens,
        UserProvider $users,
        ?Dispatcher $dispatcher = null,
        ?Timebox $timebox = null,
        int $timeboxDuration = 200000,
    ) {
        $this->users = $users;
        $this->tokens = $tokens;
        $this->events = $dispatcher;
        $this->timebox = $timebox ?: new Timebox;
        $this->timeboxDuration = $timeboxDuration;
    }

    /**
     * Send a password reset link to a user.
     *
     * @param  array  $credentials
     * @param  \Closure|null  $callback
     * @return string
     */
    public function sendResetLink(#[\SensitiveParameter] array $credentials, ?Closure $callback = null)
    {
        return $this->timebox->call(function () use ($credentials, $callback) {
            // First we will check to see if we found a user at the given credentials and
            // if we did not we will redirect back to this current URI with a piece of
            // "flash" data in the session to indicate to the developers the errors.
            $user = $this->getUser($credentials);

            if (is_null($user)) {
                return static::INVALID_USER;
            }

            if ($this->tokens->recentlyCreatedToken($user)) {
                return static::RESET_THROTTLED;
            }

            $token = $this->tokens->create($user);

            if ($callback) {
                return $callback($user, $token) ?? static::RESET_LINK_SENT;
            }

            // Once we have the reset token, we are ready to send the message out to this
            // user with a link to reset their password. We will then redirect back to
            // the current URI having nothing set in the session to indicate errors.
            $user->sendPasswordResetNotification($token);

            $this->events?->dispatch(new PasswordResetLinkSent($user));

            return static::RESET_LINK_SENT;
        }, $this->timeboxDuration);
    }

    /**
     * Reset the password for the given token.
     *
     * @param  array  $credentials
     * @param  \Closure  $callback
     * @return string
     */
    public function reset(#[\SensitiveParameter] array $credentials, Closure $callback)
    {
        return $this->timebox->call(function ($timebox) use ($credentials, $callback) {
            $user = $this->validateReset($credentials);

            // If the responses from the validate method is not a user instance, we will
            // assume that it is a redirect and simply return it from this method and
            // the user is properly redirected having an error message on the post.
            if (! $user instanceof CanResetPasswordContract) {
                return $user;
            }

            $password = $credentials['password'];

            // Once the reset has been validated, we'll call the given callback with the
            // new password. This gives the user an opportunity to store the password
            // in their persistent storage. Then we'll delete the token and return.
            $callback($user, $password);

            $this->tokens->delete($user);

            $timebox->returnEarly();

            return static::PASSWORD_RESET;
        }, $this->timeboxDuration);
    }

    /**
     * Validate a password reset for the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\CanResetPassword|string
     */
    protected function validateReset(#[\SensitiveParameter] array $credentials)
    {
        if (is_null($user = $this->getUser($credentials))) {
            return static::INVALID_USER;
        }

        if (! $this->tokens->exists($user, $credentials['token'])) {
            return static::INVALID_TOKEN;
        }

        return $user;
    }

    /**
     * Get the user for the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\CanResetPassword|null
     *
     * @throws \UnexpectedValueException
     */
    public function getUser(#[\SensitiveParameter] array $credentials)
    {
        $credentials = Arr::except($credentials, ['token']);

        $user = $this->users->retrieveByCredentials($credentials);
<?php

namespace Illuminate\Auth\Passwords;

use Illuminate\Contracts\Auth\PasswordBrokerFactory as FactoryContract;
use InvalidArgumentException;

/**
 * @mixin \Illuminate\Contracts\Auth\PasswordBroker
 */
class PasswordBrokerManager implements FactoryContract
{
    /**
     * The application instance.
     *
     * @var \Illuminate\Contracts\Foundation\Application
     */
    protected $app;

    /**
     * The array of created "drivers".
     *
     * @var array
     */
    protected $brokers = [];

    /**
     * Create a new PasswordBroker manager instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     */
    public function __construct($app)
    {
        $this->app = $app;
    }

    /**
     * Attempt to get the broker from the local cache.
     *
     * @param  string|null  $name
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     */
    public function broker($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

        return $this->brokers[$name] ?? ($this->brokers[$name] = $this->resolve($name));
    }

    /**
     * Resolve the given broker.
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     *
     * @throws \InvalidArgumentException
     */
    protected function resolve($name)
    {
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Password resetter [{$name}] is not defined.");
        }

        // The password broker uses a token repository to validate tokens and send user
        // password e-mails, as well as validating that password reset process as an
        // aggregate service of sorts providing a convenient interface for resets.
        return new PasswordBroker(
            $this->createTokenRepository($config),
            $this->app['auth']->createUserProvider($config['provider'] ?? null),
            $this->app['events'] ?? null,
            timeboxDuration: $this->app['config']->get('auth.timebox_duration', 200000),
        );
    }

    /**
     * Create a token repository instance based on the given configuration.
     *
     * @param  array  $config
     * @return \Illuminate\Auth\Passwords\TokenRepositoryInterface
     */
    protected function createTokenRepository(array $config)
    {
        $key = $this->app['config']['app.key'];

        if (str_starts_with($key, 'base64:')) {
            $key = base64_decode(substr($key, 7));
        }

        if (isset($config['driver']) && $config['driver'] === 'cache') {
            return new CacheTokenRepository(
                $this->app['cache']->store($config['store'] ?? null),
                $this->app['hash'],
                $key,
                ($config['expire'] ?? 60) * 60,
                $config['throttle'] ?? 0,
            );
        }

        return new DatabaseTokenRepository(
            $this->app['db']->connection($config['connection'] ?? null),
            $this->app['hash'],
            $config['table'],
            $key,
            ($config['expire'] ?? 60) * 60,
            $config['throttle'] ?? 0,
        );
    }

    /**
     * Get the password broker configuration.
     *
     * @param  string  $name
     * @return array|null
     */
    protected function getConfig($name)
    {
        return $this->app['config']["auth.passwords.{$name}"];
    }

    /**
     * Get the default password broker name.
     *
     * @return string
     */
    public function getDefaultDriver()
    {
        return $this->app['config']['auth.defaults.passwords'];
    }

    /**
     * Set the default password broker name.
     *
     * @param  string  $name
     * @return void
     */
    public function setDefaultDriver($name)
    {
        $this->app['config']['auth.defaults.passwords'] = $name;
    }

    /**
     * Dynamically call the default driver instance.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        return $this->broker()->{$method}(...$parameters);
    }
}


exec

status: completed

input:
const r = await tools.exec_command({cmd:"rg -n \"function extend|extend\\(\" vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php vendor/laravel/framework/src/Illuminate/Auth | head -40; sed -n '1,180p' vendor/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":8000});
text(r.output);


command: rg -n "function extend|extend\(" vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php vendor/laravel/framework/src/Illuminate/Auth | head -40; sed -n '1,180p' vendor/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php

type: search

cmd: rg -n "function extend|extend\\(" vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php vendor/laravel/framework/src/Illuminate/Auth

query: function extend|extend\(

AuthServiceProvider.php

stdout:
vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php:230:        return $this->extend($driver, function () use ($callback) {
vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php:269:    public function extend($driver, Closure $callback)
<?php

namespace Illuminate\Auth;

use Illuminate\Auth\Access\Gate;
use Illuminate\Auth\Middleware\RequirePassword;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Contracts\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->registerAuthenticator();
        $this->registerUserResolver();
        $this->registerAccessGate();
        $this->registerRequirePassword();
        $this->registerRequestRebindHandler();
        $this->registerEventRebindHandler();
    }

    /**
     * Register the authenticator services.
     *
     * @return void
     */
    protected function registerAuthenticator()
    {
        $this->app->singleton('auth', fn ($app) => new AuthManager($app));

        $this->app->singleton('auth.driver', fn ($app) => $app['auth']->guard());
    }

    /**
     * Register a resolver for the authenticated user.
     *
     * @return void
     */
    protected function registerUserResolver()
    {
        $this->app->bind(AuthenticatableContract::class, fn ($app) => call_user_func($app['auth']->userResolver()));
    }

    /**
     * Register the access gate service.
     *
     * @return void
     */
    protected function registerAccessGate()
    {
        $this->app->singleton(GateContract::class, function ($app) {
            return new Gate($app, fn () => call_user_func($app['auth']->userResolver()));
        });
    }

    /**
     * Register a resolver for the authenticated user.
     *
     * @return void
     */
    protected function registerRequirePassword()
    {
        $this->app->bind(RequirePassword::class, function ($app) {
            return new RequirePassword(
                $app[ResponseFactory::class],
                $app[UrlGenerator::class],
                $app['config']->get('auth.password_timeout')
            );
        });
    }

    /**
     * Handle the re-binding of the request binding.
     *
     * @return void
     */
    protected function registerRequestRebindHandler()
    {
        $this->app->rebinding('request', function ($app, $request) {
            $request->setUserResolver(function ($guard = null) use ($app) {
                return call_user_func($app['auth']->userResolver(), $guard);
            });
        });
    }

    /**
     * Handle the re-binding of the event dispatcher binding.
     *
     * @return void
     */
    protected function registerEventRebindHandler()
    {
        $this->app->rebinding('events', function ($app, $dispatcher) {
            if (! $app->resolved('auth') ||
                $app['auth']->hasResolvedGuards() === false) {
                return;
            }

            if (method_exists($guard = $app['auth']->guard(), 'setDispatcher')) {
                $guard->setDispatcher($dispatcher);
            }
        });
    }
}


text:
Script completed
Wall time 0.1 seconds
Output:

text:
vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php:230:        return $this->extend($driver, function () use ($callback) {
vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php:269:    public function extend($driver, Closure $callback)
<?php

namespace Illuminate\Auth;

use Illuminate\Auth\Access\Gate;
use Illuminate\Auth\Middleware\RequirePassword;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Contracts\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->registerAuthenticator();
        $this->registerUserResolver();
        $this->registerAccessGate();
        $this->registerRequirePassword();
        $this->registerRequestRebindHandler();
        $this->registerEventRebindHandler();
    }

    /**
     * Register the authenticator services.
     *
     * @return void
     */
    protected function registerAuthenticator()
    {
        $this->app->singleton('auth', fn ($app) => new AuthManager($app));

        $this->app->singleton('auth.driver', fn ($app) => $app['auth']->guard());
    }

    /**
     * Register a resolver for the authenticated user.
     *
     * @return void
     */
    protected function registerUserResolver()
    {
        $this->app->bind(AuthenticatableContract::class, fn ($app) => call_user_func($app['auth']->userResolver()));
    }

    /**
     * Register the access gate service.
     *
     * @return void
     */
    protected function registerAccessGate()
    {
        $this->app->singleton(GateContract::class, function ($app) {
            return new Gate($app, fn () => call_user_func($app['auth']->userResolver()));
        });
    }

    /**
     * Register a resolver for the authenticated user.
     *
     * @return void
     */
    protected function registerRequirePassword()
    {
        $this->app->bind(RequirePassword::class, function ($app) {
            return new RequirePassword(
                $app[ResponseFactory::class],
                $app[UrlGenerator::class],
                $app['config']->get('auth.password_timeout')
            );
        });
    }

    /**
     * Handle the re-binding of the request binding.
     *
     * @return void
     */
    protected function registerRequestRebindHandler()
    {
        $this->app->rebinding('request', function ($app, $request) {
            $request->setUserResolver(function ($guard = null) use ($app) {
                return call_user_func($app['auth']->userResolver(), $guard);
            });
        });
    }

    /**
     * Handle the re-binding of the event dispatcher binding.
     *
     * @return void
     */
    protected function registerEventRebindHandler()
    {
        $this->app->rebinding('events', function ($app, $dispatcher) {
            if (! $app->resolved('auth') ||
                $app['auth']->hasResolvedGuards() === false) {
                return;
            }

            if (method_exists($guard = $app['auth']->guard(), 'setDispatcher')) {
                $guard->setDispatcher($dispatcher);
            }
        });
    }
}


exec

status: completed

input:
const r = await tools.exec_command({cmd:"rg -n \"auth.password|PasswordBrokerManager\" vendor/laravel/framework/src/Illuminate/ -g'*.php' | head -40; rg -n \"sendPasswordResetNotification|CanResetPassword\" vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php | tail -20","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":6000});
text(r.output);


command: rg -n "auth.password|PasswordBrokerManager" vendor/laravel/framework/src/Illuminate/ -g'*.php' | head -40; rg -n "sendPasswordResetNotification|CanResetPassword" vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php | tail -20

type: search

cmd: rg -n 'auth.password|PasswordBrokerManager' vendor/laravel/framework/src/Illuminate/ '-g*.php'

query: auth.password|PasswordBrokerManager

path: Illuminate

type: search

query: sendPasswordResetNotification|CanResetPassword

stdout:
vendor/laravel/framework/src/Illuminate/Session/Store.php:835:        $this->put('auth.password_confirmed_at', Date::now()->unix());
vendor/laravel/framework/src/Illuminate/Support/Facades/Password.php:20: * @see \Illuminate\Auth\Passwords\PasswordBrokerManager
vendor/laravel/framework/src/Illuminate/Support/Facades/Password.php:73:        return 'auth.password';
vendor/laravel/framework/src/Illuminate/Auth/Console/ClearResetsCommand.php:32:        $this->laravel['auth.password']->broker($this->argument('name'))->getRepository()->deleteExpired();
vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php:80:            ->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:27:        $this->app->singleton('auth.password', function ($app) {
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:28:            return new PasswordBrokerManager($app);
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:31:        $this->app->bind('auth.password.broker', function ($app) {
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:32:            return $app->make('auth.password')->broker();
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:43:        return ['auth.password', 'auth.password.broker'];
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php:11:class PasswordBrokerManager implements FactoryContract
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php:119:        return $this->app['config']["auth.passwords.{$name}"];
vendor/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php:75:                $app['config']->get('auth.password_timeout')
vendor/laravel/framework/src/Illuminate/Auth/Middleware/RequirePassword.php:96:        $confirmedAt = Date::now()->unix() - $request->session()->get('auth.password_confirmed_at', 0);
vendor/laravel/framework/src/Illuminate/Foundation/Application.php:1642:            'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
vendor/laravel/framework/src/Illuminate/Foundation/Application.php:1643:            'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
7:use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
107:            $user->sendPasswordResetNotification($token);
130:            if (! $user instanceof CanResetPasswordContract) {
153:     * @return \Illuminate\Contracts\Auth\CanResetPassword|string
172:     * @return \Illuminate\Contracts\Auth\CanResetPassword|null
182:        if ($user && ! $user instanceof CanResetPasswordContract) {
183:            throw new UnexpectedValueException('User must implement CanResetPassword interface.');
192:     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
195:    public function createToken(CanResetPasswordContract $user)
203:     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
206:    public function deleteToken(CanResetPasswordContract $user)
214:     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
218:    public function tokenExists(CanResetPasswordContract $user, #[\SensitiveParameter] $token)


text:
Script completed
Wall time 0.1 seconds
Output:

text:
vendor/laravel/framework/src/Illuminate/Session/Store.php:835:        $this->put('auth.password_confirmed_at', Date::now()->unix());
vendor/laravel/framework/src/Illuminate/Support/Facades/Password.php:20: * @see \Illuminate\Auth\Passwords\PasswordBrokerManager
vendor/laravel/framework/src/Illuminate/Support/Facades/Password.php:73:        return 'auth.password';
vendor/laravel/framework/src/Illuminate/Auth/Console/ClearResetsCommand.php:32:        $this->laravel['auth.password']->broker($this->argument('name'))->getRepository()->deleteExpired();
vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php:80:            ->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:27:        $this->app->singleton('auth.password', function ($app) {
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:28:            return new PasswordBrokerManager($app);
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:31:        $this->app->bind('auth.password.broker', function ($app) {
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:32:            return $app->make('auth.password')->broker();
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordResetServiceProvider.php:43:        return ['auth.password', 'auth.password.broker'];
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php:11:class PasswordBrokerManager implements FactoryContract
vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php:119:        return $this->app['config']["auth.passwords.{$name}"];
vendor/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php:75:                $app['config']->get('auth.password_timeout')
vendor/laravel/framework/src/Illuminate/Auth/Middleware/RequirePassword.php:96:        $confirmedAt = Date::now()->unix() - $request->session()->get('auth.password_confirmed_at', 0);
vendor/laravel/framework/src/Illuminate/Foundation/Application.php:1642:            'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
vendor/laravel/framework/src/Illuminate/Foundation/Application.php:1643:            'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
7:use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
107:            $user->sendPasswordResetNotification($token);
130:            if (! $user instanceof CanResetPasswordContract) {
153:     * @return \Illuminate\Contracts\Auth\CanResetPassword|string
172:     * @return \Illuminate\Contracts\Auth\CanResetPassword|null
182:        if ($user && ! $user instanceof CanResetPasswordContract) {
183:            throw new UnexpectedValueException('User must implement CanResetPassword interface.');
192:     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
195:    public function createToken(CanResetPasswordContract $user)
203:     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
206:    public function deleteToken(CanResetPasswordContract $user)
214:     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
218:    public function tokenExists(CanResetPasswordContract $user, #[\SensitiveParameter] $token)


status: completed

input:
const r = await tools.exec_command({cmd:"php artisan make:class Auth/StoreScopedTokenRepository --no-interaction && php artisan make:class Auth/StoreScopedPasswordBrokerManager --no-interaction","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":5000});
text(r.output);


command: php artisan make:class Auth/StoreScopedTokenRepository --no-interaction && php artisan make:class Auth/StoreScopedPasswordBrokerManager --no-interaction

type: unknown

stdout: INFO  Class [app/Auth/StoreScopedPasswordBrokerManager.php] created successfully.


text:
Script completed
Wall time 0.2 seconds
Output:

text:
   INFO  Class [app/Auth/StoreScopedTokenRepository.php] created successfully.

   INFO  Class [app/Auth/StoreScopedPasswordBrokerManager.php] created successfully.


status: completed

input:
const patch = "*** Begin Patch\n*** Update File: /Users/wesner/Herd/shop/app/Auth/StoreScopedTokenRepository.php\n@@\n namespace App\\Auth;\n \n+use Illuminate\\Auth\\Passwords\\DatabaseTokenRepository;\n+use Illuminate\\Contracts\\Auth\\CanResetPassword as CanResetPasswordContract;\n+use Illuminate\\Support\\Carbon;\n+\n class StoreScopedTokenRepository\n {\n-    /**\n-     * Create a new class instance.\n-     */\n-    public function __construct()\n+    public function __construct()\n     {\n-        //\n     }\n }\n*** End Patch";
text(await tools.apply_patch(patch));


type: update

unified_diff:
@@ -4,10 +4,10 @@

+use Illuminate\Auth\Passwords\DatabaseTokenRepository;
+use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
+use Illuminate\Support\Carbon;
+
 class StoreScopedTokenRepository
 {
-    /**
-     * Create a new class instance.
-     */
     public function __construct()
     {
-        //
     }

stdout:
Success. Updated the following files:
M /Users/wesner/Herd/shop/app/Auth/StoreScopedTokenRepository.php


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const patch = "*** Begin Patch\n*** Update File: /Users/wesner/Herd/shop/app/Auth/StoreScopedTokenRepository.php\n@@\n-class StoreScopedTokenRepository\n+class StoreScopedTokenRepository extends DatabaseTokenRepository\n {\n-    public function __construct()\n+    public function create(CanResetPasswordContract $user): string\n     {\n+        $email = $user->getEmailForPasswordReset();\n+        $this->deleteExisting($user);\n+        $token = $this->createNewToken();\n+        $this->getTable()->insert($this->getPayload($email, $token));\n+\n+        return $token;\n+    }\n+\n+    public function exists(CanResetPasswordContract $user, string $token): bool\n+    {\n+        $record = (array) $this->scopedTable()->where('email', $user->getEmailForPasswordReset())->first();\n+\n+        return $record !== []\n+            && ! $this->tokenExpired($record['created_at'])\n+            && $this->getHasher()->check($token, $record['token']);\n+    }\n+\n+    public function recentlyCreatedToken(CanResetPasswordContract $user): bool\n+    {\n+        $record = (array) $this->scopedTable()->where('email', $user->getEmailForPasswordReset())->first();\n+\n+        return $record !== [] && $this->tokenRecentlyCreated($record['created_at']);\n+    }\n+\n+    public function delete(CanResetPasswordContract $user): void\n+    {\n+        $this->deleteExisting($user);\n+    }\n+\n+    public function deleteExpired(): void\n+    {\n+        $expiredAt = Carbon::now()->subSeconds($this->expires);\n+        $query = $this->scopedTable();\n+        $query->where('created_at', '<', $expiredAt)->delete();\n+    }\n+\n+    protected function deleteExisting(CanResetPasswordContract $user): int\n+    {\n+        return $this->scopedTable()->where('email', $user->getEmailForPasswordReset())->delete();\n+    }\n+\n+    protected function getPayload($email, #[\\SensitiveParameter] $token): array\n+    {\n+        return array_merge(parent::getPayload($email, $token), ['store_id' => $this->currentStoreId()]);\n+    }\n+\n+    private function scopedTable(): \\Illuminate\\Database\\Query\\Builder\n+    {\n+        $query = $this->getTable();\n+\n+        if ($this->currentStoreId() === null) {\n+            return $query->whereNull('store_id');\n+        }\n+\n+        return $query->where('store_id', $this->currentStoreId());\n+    }\n+\n+    private function currentStoreId(): ?int\n+    {\n+        return app()->bound('current_store') ? (int) app('current_store')->getKey() : null;\n     }\n }\n*** End Patch";
text(await tools.apply_patch(patch));


unified_diff:
@@ -8,6 +8,66 @@

-class StoreScopedTokenRepository
+class StoreScopedTokenRepository extends DatabaseTokenRepository
 {
-    public function __construct()
+    public function create(CanResetPasswordContract $user): string
+    {
+        $email = $user->getEmailForPasswordReset();
+        $this->deleteExisting($user);
+        $token = $this->createNewToken();
+        $this->getTable()->insert($this->getPayload($email, $token));
+
+        return $token;
+    }
+
+    public function exists(CanResetPasswordContract $user, string $token): bool
+    {
+        $record = (array) $this->scopedTable()->where('email', $user->getEmailForPasswordReset())->first();
+
+        return $record !== []
+            && ! $this->tokenExpired($record['created_at'])
+            && $this->getHasher()->check($token, $record['token']);
+    }
+
+    public function recentlyCreatedToken(CanResetPasswordContract $user): bool
+    {
+        $record = (array) $this->scopedTable()->where('email', $user->getEmailForPasswordReset())->first();
+
+        return $record !== [] && $this->tokenRecentlyCreated($record['created_at']);
+    }
+
+    public function delete(CanResetPasswordContract $user): void
+    {
+        $this->deleteExisting($user);
+    }
+
+    public function deleteExpired(): void
+    {
+        $expiredAt = Carbon::now()->subSeconds($this->expires);
+        $query = $this->scopedTable();
+        $query->where('created_at', '<', $expiredAt)->delete();
+    }
+
+    protected function deleteExisting(CanResetPasswordContract $user): int
+    {
+        return $this->scopedTable()->where('email', $user->getEmailForPasswordReset())->delete();
+    }
+
+    protected function getPayload($email, #[\SensitiveParameter] $token): array
+    {
+        return array_merge(parent::getPayload($email, $token), ['store_id' => $this->currentStoreId()]);
+    }
+
+    private function scopedTable(): \Illuminate\Database\Query\Builder
+    {
+        $query = $this->getTable();
+
+        if ($this->currentStoreId() === null) {
+            return $query->whereNull('store_id');
+        }
+
+        return $query->where('store_id', $this->currentStoreId());
+    }
+
+    private function currentStoreId(): ?int
     {
+        return app()->bound('current_store') ? (int) app('current_store')->getKey() : null;
     }


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const patch = "*** Begin Patch\n*** Update File: /Users/wesner/Herd/shop/app/Auth/StoreScopedPasswordBrokerManager.php\n@@\n namespace App\\Auth;\n \n+use Illuminate\\Auth\\Passwords\\DatabaseTokenRepository;\n+use Illuminate\\Auth\\Passwords\\PasswordBrokerManager;\n+use Illuminate\\Contracts\\Auth\\PasswordBrokerFactory;\n+\n-class StoreScopedPasswordBrokerManager\n+class StoreScopedPasswordBrokerManager extends PasswordBrokerManager implements PasswordBrokerFactory\n {\n-    /**\n-     * Create a new class instance.\n-     */\n-    public function __construct()\n+    protected function createTokenRepository(array $config)\n     {\n-        //\n+        $key = $this->app['config']['app.key'];\n+\n+        if (str_starts_with($key, 'base64:')) {\n+            $key = base64_decode(substr($key, 7));\n+        }\n+\n+        if (($config['table'] ?? null) === 'customer_password_reset_tokens') {\n+            return new StoreScopedTokenRepository(\n+                $this->app['db']->connection($config['connection'] ?? null),\n+                $this->app['hash'],\n+                $config['table'],\n+                $key,\n+                ($config['expire'] ?? 60) * 60,\n+                $config['throttle'] ?? 0,\n+            );\n+        }\n+\n+        return new DatabaseTokenRepository(\n+            $this->app['db']->connection($config['connection'] ?? null),\n+            $this->app['hash'],\n+            $config['table'],\n+            $key,\n+            ($config['expire'] ?? 60) * 60,\n+            $config['throttle'] ?? 0,\n+        );\n     }\n }\n*** End Patch";
text(await tools.apply_patch(patch));


unified_diff:
@@ -4,10 +4,35 @@

-class StoreScopedPasswordBrokerManager
+use Illuminate\Auth\Passwords\DatabaseTokenRepository;
+use Illuminate\Auth\Passwords\PasswordBrokerManager;
+use Illuminate\Contracts\Auth\PasswordBrokerFactory;
+
+class StoreScopedPasswordBrokerManager extends PasswordBrokerManager implements PasswordBrokerFactory
 {
-    /**
-     * Create a new class instance.
-     */
-    public function __construct()
+    protected function createTokenRepository(array $config)
     {
-        //
+        $key = $this->app['config']['app.key'];
+
+        if (str_starts_with($key, 'base64:')) {
+            $key = base64_decode(substr($key, 7));
+        }
+
+        if (($config['table'] ?? null) === 'customer_password_reset_tokens') {
+            return new StoreScopedTokenRepository(
+                $this->app['db']->connection($config['connection'] ?? null),
+                $this->app['hash'],
+                $config['table'],
+                $key,
+                ($config['expire'] ?? 60) * 60,
+                $config['throttle'] ?? 0,
+            );
+        }
+
+        return new DatabaseTokenRepository(
+            $this->app['db']->connection($config['connection'] ?? null),
+            $this->app['hash'],
+            $config['table'],
+            $key,
+            ($config['expire'] ?? 60) * 60,
+            $config['throttle'] ?? 0,
+        );
     }

stdout:
Success. Updated the following files:
M /Users/wesner/Herd/shop/app/Auth/StoreScopedPasswordBrokerManager.php


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const patch = "*** Begin Patch\n*** Update File: /Users/wesner/Herd/shop/app/Providers/AppServiceProvider.php\n@@\n use App\\Auth\\CustomerUserProvider;\n+use App\\Auth\\StoreScopedPasswordBrokerManager;\n@@\n         $this->app->bind(PaymentProviderContract::class, MockPaymentProvider::class);\n         Auth::provider('customer', fn ($app, array $config): CustomerUserProvider => new CustomerUserProvider($app['hash'], $config['model']));\n+        $this->app->extend('auth.password', fn ($manager, $app): StoreScopedPasswordBrokerManager => new StoreScopedPasswordBrokerManager($app));\n*** End Patch";
text(await tools.apply_patch(patch));


unified_diff:
@@ -5,2 +5,3 @@
 use App\Auth\CustomerUserProvider;
+use App\Auth\StoreScopedPasswordBrokerManager;
 use App\Contracts\PaymentProvider as PaymentProviderContract;
@@ -32,2 +33,3 @@
         Auth::provider('customer', fn ($app, array $config): CustomerUserProvider => new CustomerUserProvider($app['hash'], $config['model']));
+        $this->app->extend('auth.password', fn ($manager, $app): StoreScopedPasswordBrokerManager => new StoreScopedPasswordBrokerManager($app));
     }

stdout:
Success. Updated the following files:
M /Users/wesner/Herd/shop/app/Providers/AppServiceProvider.php


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const patch = "*** Begin Patch\n*** Update File: /Users/wesner/Herd/shop/app/Models/Customer.php\n@@\n use Illuminate\\Auth\\Authenticatable as AuthenticatableTrait;\n+use Illuminate\\Auth\\Passwords\\CanResetPassword;\n use Illuminate\\Contracts\\Auth\\Authenticatable;\n+use Illuminate\\Contracts\\Auth\\CanResetPassword as CanResetPasswordContract;\n@@\n-class Customer extends Model implements Authenticatable\n+class Customer extends Model implements Authenticatable, CanResetPasswordContract\n {\n-    use AuthenticatableTrait, BelongsToStore, HasFactory, Notifiable;\n+    use AuthenticatableTrait, BelongsToStore, CanResetPassword, HasFactory, Notifiable;\n*** End Patch";
text(await tools.apply_patch(patch));


unified_diff:
@@ -6,3 +6,5 @@
 use Illuminate\Auth\Authenticatable as AuthenticatableTrait;
+use Illuminate\Auth\Passwords\CanResetPassword;
 use Illuminate\Contracts\Auth\Authenticatable;
+use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -12,5 +14,5 @@

-class Customer extends Model implements Authenticatable
+class Customer extends Model implements Authenticatable, CanResetPasswordContract
 {
-    use AuthenticatableTrait, BelongsToStore, HasFactory, Notifiable;
+    use AuthenticatableTrait, BelongsToStore, CanResetPassword, HasFactory, Notifiable;

stdout:
Success. Updated the following files:
M /Users/wesner/Herd/shop/app/Models/Customer.php


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const r = await tools.exec_command({cmd:"php artisan test --compact tests/Feature/Auth tests/Feature/CustomerAuthTest.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":12000});
text(r.output);
if (r.session_id) text((await tools.write_stdin({session_id:r.session_id, chars:"", yield_time_ms:1000, max_output_tokens:12000})).output);


command: php artisan test --compact tests/Feature/Auth tests/Feature/CustomerAuthTest.php

status: failed


text:
Script completed
Wall time 0.2 seconds
Output:

text: INFO  Test file "tests/Feature/CustomerAuthTest.php" not found.


status: completed

input:
const r = await tools.exec_command({cmd:"rg --files tests/Feature | sort | sed -n '1,100p'; php artisan test --compact tests/Feature/Auth","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":12000});
text(r.output);
if (r.session_id) text((await tools.write_stdin({session_id:r.session_id, chars:"", yield_time_ms:1000, max_output_tokens:12000})).output);


command: rg --files tests/Feature | sort | sed -n '1,100p'; php artisan test --compact tests/Feature/Auth

stdout:
  ..................

  Tests:    18 passed (41 assertions)
  Duration: 0.99s


text:
Script completed
Wall time 1.2 seconds
Output:

text:
tests/Feature/AdminApiTest.php
tests/Feature/ApiTokenTest.php
tests/Feature/Auth/AuthenticationTest.php
tests/Feature/Auth/EmailVerificationTest.php
tests/Feature/Auth/PasswordConfirmationTest.php
tests/Feature/Auth/PasswordResetTest.php
tests/Feature/Auth/RegistrationTest.php
tests/Feature/Auth/TwoFactorChallengeTest.php
tests/Feature/CommerceFlowTest.php
tests/Feature/DashboardTest.php
tests/Feature/ExampleTest.php
tests/Feature/SearchAnalyticsWebhookTest.php
tests/Feature/SeedDataTest.php
tests/Feature/Settings/PasswordUpdateTest.php
tests/Feature/Settings/ProfileUpdateTest.php
tests/Feature/Settings/TwoFactorAuthenticationTest.php
tests/Feature/Storefront/CustomerAuthenticationTest.php
tests/Feature/Tenancy/ResolveStoreTest.php

  ..................

  Tests:    18 passed (41 assertions)
  Duration: 0.99s


status: completed

input:
const r = await tools.exec_command({cmd:"php artisan test --compact tests/Feature/Storefront/CustomerAuthenticationTest.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":12000});
text(r.output);
if (r.session_id) text((await tools.write_stdin({session_id:r.session_id, chars:"", yield_time_ms:1000, max_output_tokens:12000})).output);


command: php artisan test --compact tests/Feature/Storefront/CustomerAuthenticationTest.php

stdout:
  ..

  Tests:    2 passed (6 assertions)
  Duration: 0.18s


text:
Script completed
Wall time 0.4 seconds
Output:

text:
  ..

  Tests:    2 passed (6 assertions)
  Duration: 0.18s


status: completed

input:
const r = await tools.exec_command({cmd:"sed -n '1,220p' routes/web.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":1000,"max_output_tokens":18000});
text(r.output);


command:
/bin/zsh
-lc
sed -n '1,220p' routes/web.php

web.php

cmd: sed -n '1,220p' routes/web.php

stdout:
<?php

use App\Livewire\Admin\Analytics\Index as AdminAnalyticsIndex;
use App\Livewire\Admin\Apps\Index as AdminAppsIndex;
use App\Livewire\Admin\Apps\Show as AdminAppsShow;
use App\Livewire\Admin\Auth\ForgotPassword as AdminForgotPassword;
use App\Livewire\Admin\Auth\Login as AdminLogin;
use App\Livewire\Admin\Auth\ResetPassword as AdminResetPassword;
use App\Livewire\Admin\Collections\Create as AdminCollectionsCreate;
use App\Livewire\Admin\Collections\Edit as AdminCollectionsEdit;
use App\Livewire\Admin\Collections\Index as AdminCollectionsIndex;
use App\Livewire\Admin\Customers\Index as AdminCustomersIndex;
use App\Livewire\Admin\Customers\Show as AdminCustomersShow;
use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Livewire\Admin\Developers\Index as AdminDevelopersIndex;
use App\Livewire\Admin\Discounts\Form as AdminDiscountForm;
use App\Livewire\Admin\Discounts\Index as AdminDiscountsIndex;
use App\Livewire\Admin\Inventory\Index as AdminInventoryIndex;
use App\Livewire\Admin\Navigation\Index as AdminNavigationIndex;
use App\Livewire\Admin\Orders\Index as AdminOrdersIndex;
use App\Livewire\Admin\Orders\Show as AdminOrdersShow;
use App\Livewire\Admin\Pages\Create as AdminPagesCreate;
use App\Livewire\Admin\Pages\Edit as AdminPagesEdit;
use App\Livewire\Admin\Pages\Index as AdminPagesIndex;
use App\Livewire\Admin\Products\Form as AdminProductForm;
use App\Livewire\Admin\Products\Index as AdminProductsIndex;
use App\Livewire\Admin\Search\Settings as AdminSearchSettings;
use App\Livewire\Admin\Settings\General as AdminSettingsGeneral;
use App\Livewire\Admin\Settings\Shipping as AdminSettingsShipping;
use App\Livewire\Admin\Settings\Taxes as AdminSettingsTaxes;
use App\Livewire\Admin\Themes\Editor as AdminThemesEditor;
use App\Livewire\Admin\Themes\Index as AdminThemesIndex;
use App\Livewire\Storefront\Account\Addresses\Index as AccountAddresses;
use App\Livewire\Storefront\Account\Auth\ForgotPassword as CustomerForgotPassword;
use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Livewire\Storefront\Account\Auth\ResetPassword as CustomerResetPassword;
use App\Livewire\Storefront\Account\Dashboard as AccountDashboard;
use App\Livewire\Storefront\Account\Orders\Index as AccountOrders;
use App\Livewire\Storefront\Account\Orders\Show as AccountOrderShow;
use App\Livewire\Storefront\Cart\Show as CartShow;
use App\Livewire\Storefront\Checkout\Confirmation as CheckoutConfirmation;
use App\Livewire\Storefront\Checkout\Show as CheckoutShow;
use App\Livewire\Storefront\Collections\Index as CollectionsIndex;
use App\Livewire\Storefront\Collections\Show as CollectionShow;
use App\Livewire\Storefront\Home;
use App\Livewire\Storefront\Pages\Show as PageShow;
use App\Livewire\Storefront\Products\Show as ProductShow;
use App\Livewire\Storefront\Search\Index as SearchIndex;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;

Route::view('dashboard', 'dashboard')
    ->middleware(['auth', 'verified'])
    ->name('dashboard');

require __DIR__.'/settings.php';

Route::get('/favicon.ico', fn (): \Symfony\Component\HttpFoundation\Response => response('', 204))->name('favicon');

Route::middleware('store.resolve')->group(function (): void {
    Route::livewire('/', Home::class)->name('home');
    Route::livewire('/collections', CollectionsIndex::class)->name('collections.index');
    Route::livewire('/collections/{handle}', CollectionShow::class)->name('collection.show');
    Route::livewire('/products/{handle}', ProductShow::class)->name('product.show');
    Route::livewire('/cart', CartShow::class)->name('cart.show');
    Route::livewire('/search', SearchIndex::class)->name('search');
    Route::livewire('/pages/{handle}', PageShow::class)->name('page.show');
    Route::livewire('/checkout/{checkoutId}', CheckoutShow::class)->name('checkout.show');
    Route::livewire('/checkout/{checkoutId}/confirmation', CheckoutConfirmation::class)->name('checkout.confirmation');
    Route::livewire('/account/login', CustomerLogin::class)->middleware('throttle:login')->name('account.login');
    Route::livewire('/account/register', CustomerRegister::class)->name('account.register');
    Route::livewire('/forgot-password', CustomerForgotPassword::class)->name('password.request');
    Route::livewire('/reset-password/{token}', CustomerResetPassword::class)->name('password.reset');
    Route::post('/account/logout', function (): \Illuminate\Http\RedirectResponse {
        Auth::guard('customer')->logout();
        request()->session()->invalidate();
        request()->session()->regenerateToken();

        return redirect()->route('home');
    })->name('account.logout');

    Route::middleware('auth:customer')->group(function (): void {
        Route::livewire('/account', AccountDashboard::class)->name('account.dashboard');
        Route::livewire('/account/orders', AccountOrders::class)->name('account.orders');
        Route::livewire('/account/orders/{orderNumber}', AccountOrderShow::class)->name('account.order.show');
        Route::livewire('/account/addresses', AccountAddresses::class)->name('account.addresses');
    });
});

Route::livewire('/admin/login', AdminLogin::class)->middleware('throttle:login')->name('admin.login');
Route::livewire('/admin/forgot-password', AdminForgotPassword::class)->middleware('throttle:login')->name('admin.password.request');
Route::livewire('/admin/reset-password/{token}', AdminResetPassword::class)->name('admin.password.reset');
Route::post('/admin/logout', function (): \Illuminate\Http\RedirectResponse {
    Auth::guard('web')->logout();
    request()->session()->invalidate();
    request()->session()->regenerateToken();

    return redirect()->route('admin.login');
})->name('admin.logout');

Route::prefix('admin')->middleware(['auth', 'verified', 'store.resolve', 'role.check:owner,admin,staff,support'])->group(function (): void {
    Route::livewire('/', AdminDashboard::class)->name('admin.dashboard');
    Route::livewire('/products', AdminProductsIndex::class)->name('admin.products.index');
    Route::livewire('/products/create', AdminProductForm::class)->middleware('role.check:owner,admin,staff')->name('admin.products.create');
    Route::livewire('/products/{product}/edit', AdminProductForm::class)->middleware('role.check:owner,admin,staff')->name('admin.products.edit');
    Route::livewire('/orders', AdminOrdersIndex::class)->name('admin.orders.index');
    Route::livewire('/orders/{order}', AdminOrdersShow::class)->name('admin.orders.show');
    Route::livewire('/customers', AdminCustomersIndex::class)->name('admin.customers.index');
    Route::livewire('/customers/{customer}', AdminCustomersShow::class)->name('admin.customers.show');
    Route::livewire('/discounts', AdminDiscountsIndex::class)->name('admin.discounts.index');
    Route::livewire('/discounts/create', AdminDiscountForm::class)->middleware('role.check:owner,admin,staff')->name('admin.discounts.create');
    Route::livewire('/discounts/{discount}/edit', AdminDiscountForm::class)->middleware('role.check:owner,admin,staff')->name('admin.discounts.edit');
    Route::livewire('/settings', AdminSettingsGeneral::class)->middleware('role.check:owner,admin')->name('admin.settings');
    Route::livewire('/settings/shipping', AdminSettingsShipping::class)->middleware('role.check:owner,admin')->name('admin.settings.shipping');
    Route::livewire('/settings/taxes', AdminSettingsTaxes::class)->middleware('role.check:owner,admin')->name('admin.settings.taxes');
    Route::livewire('/inventory', AdminInventoryIndex::class)->name('admin.inventory');
    Route::livewire('/collections', AdminCollectionsIndex::class)->name('admin.collections');
    Route::livewire('/collections/create', AdminCollectionsCreate::class)->middleware('role.check:owner,admin,staff')->name('admin.collections.create');
    Route::livewire('/collections/{collection}/edit', AdminCollectionsEdit::class)->middleware('role.check:owner,admin,staff')->name('admin.collections.edit');
    Route::livewire('/themes', AdminThemesIndex::class)->name('admin.themes');
    Route::livewire('/themes/{theme}/editor', AdminThemesEditor::class)->name('admin.themes.editor');
    Route::livewire('/pages', AdminPagesIndex::class)->name('admin.pages');
    Route::livewire('/pages/create', AdminPagesCreate::class)->middleware('role.check:owner,admin')->name('admin.pages.create');
    Route::livewire('/pages/{page}/edit', AdminPagesEdit::class)->middleware('role.check:owner,admin')->name('admin.pages.edit');
    Route::livewire('/navigation', AdminNavigationIndex::class)->name('admin.navigation');
    Route::livewire('/apps', AdminAppsIndex::class)->name('admin.apps');
    Route::livewire('/apps/{installation}', AdminAppsShow::class)->name('admin.apps.show');
    Route::livewire('/developers', AdminDevelopersIndex::class)->name('admin.developers');
    Route::livewire('/analytics', AdminAnalyticsIndex::class)->name('admin.analytics');
    Route::livewire('/search/settings', AdminSearchSettings::class)->name('admin.search.settings');
});