Welcome Guest, Not a member yet? Register   Sign In
Shield... no route found
#1

Hi everyone,
I am not sure, either my problem is very special or I am just dumb. At least I tried something with Shield, it worked all fine, had some testing and just after putting it online it broke...
So I managed to adjust Shield to accept UUID as field for login. It sends an email to this uuid (done by the Email activator. It's some magic, I'll leave this as blackbox here) and waits for a confirmation code, so far so good. The url for this is auth/a/show as expected. First thing I notice, once one tries to reload this, it gives a 404 error.
Next thing, once one enters the code it should redirect to auth/a/verify with the post request and the confirmation code. But it always gets a 404 error as well!
"php spark routes" shows everything fine and in order
PHP Code:
GET    | /                      »                  | \App\Controllers\Home::index                                      |                toolbar      |
GET    register                »                  | \CodeIgniter\Shield\Controllers\RegisterController::registerView  |                toolbar      |
GET    login                  »                  | \CodeIgniter\Shield\Controllers\LoginController::loginView        |                toolbar      |
GET    login/magic-link        magic-link        | \CodeIgniter\Shield\Controllers\MagicLinkController::loginView    |                toolbar      |
GET    login/verify-magic-link verify-magic-link  | \CodeIgniter\Shield\Controllers\MagicLinkController::verify        |                toolbar      |
GET    logout                  »                  | \CodeIgniter\Shield\Controllers\LoginController::logoutAction      |                toolbar      |
GET    auth/a/show            auth-action-show  | \CodeIgniter\Shield\Controllers\ActionController::show            |                toolbar      |
GET    about-us                »                  | \App\Controllers\Home::page/about-us                              |                toolbar      |
GET    links                  »                  | \App\Controllers\Home::page/links                                  |                toolbar      |
POST  register                »                  | \CodeIgniter\Shield\Controllers\RegisterController::registerAction |                toolbar      |
POST  login                  »                  | \CodeIgniter\Shield\Controllers\LoginController::loginAction      |                toolbar      |
POST  login/magic-link        »                  | \CodeIgniter\Shield\Controllers\MagicLinkController::loginAction  |                toolbar      |
POST  auth/a/handle          auth-action-handle | \CodeIgniter\Shield\Controllers\ActionController::handle          |                toolbar      |
POST  auth/a/verify          auth-action-verify | \CodeIgniter\Shield\Controllers\ActionController::verify          |                toolbar  
If anyone has any idea or how to help, I'll be very happy. If a demo url can help, I can provide one.
Reply
#2

Please show the code, not the demo URL.

If you customized Shield, that could be the cause of the bug.
Reply
#3

Alright, let me see what I've modified....

app/Actions/EmailActivator.php (copied the one from Shield and edited only show() )
PHP Code:
<?php

declare(strict_types=1);

/**
 * This file is part of CodeIgniter Shield.
 *
 * (c) CodeIgniter Foundation <[email protected]>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace CodeIgniter\Shield\Authentication\Actions;

use 
CodeIgniter\Exceptions\PageNotFoundException;
use 
CodeIgniter\HTTP\IncomingRequest;
use 
CodeIgniter\HTTP\RedirectResponse;
use 
CodeIgniter\HTTP\Response;
use 
CodeIgniter\I18n\Time;
use 
CodeIgniter\Shield\Authentication\Authenticators\Session;
use 
CodeIgniter\Shield\Entities\User;
use 
CodeIgniter\Shield\Entities\UserIdentity;
use 
CodeIgniter\Shield\Exceptions\LogicException;
use 
CodeIgniter\Shield\Exceptions\RuntimeException;
use 
CodeIgniter\Shield\Models\UserIdentityModel;
use 
CodeIgniter\Shield\Traits\Viewable;

class 
EmailActivator implements ActionInterface
{
    use Viewable;

    private string $type Session::ID_TYPE_EMAIL_ACTIVATE;

    /**
    * Shows the initial screen to the user telling them
    * that an email was just sent to them with a link
    * to confirm their email address.
    */
    public function show(): string
    
{
        /** @var Session $authenticator */
        $authenticator auth('session')->getAuthenticator();

        $user $authenticator->getPendingUser();
        if ($user === null) {
            throw new RuntimeException('Cannot get the pending login User.');
        }

        $userEmail $user->email;

        if ($userEmail === null) {
            throw new LogicException('Email Activation needs user email address. user_id: ' $user->id);
        }

        $code $this->createIdentity($user);



        /** @var IncomingRequest $request */
        $request service('request');

        $ipAddress $request->getIPAddress();
        $userAgent = (string)$request->getUserAgent();
        $date Time::now()->toDateTimeString();

        // Send the email
        helper('email');
        $email emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
        $email->setTo($userEmail);
        $email->setSubject('slponyplay');
        $email->setMessage('signup|'.$user->uuid '|' $code);

        if ($email->send(false) === false) {
            throw new RuntimeException('Cannot send email for user: ' $user->email "\n" $email->printDebugger(['headers']));
        }

        // Clear the email
        $email->clear();

        // force to reset password
        //$user->forcePasswordReset();  // did work at the beginning, lately gives error

        auth()->logout();

        // Display the info page
        return $this->view(setting('Auth.views')['action_email_activate_show'], ['user' => $user]);
    }

    /**
    * This method is unused.
    *
    * @return Response|string
    */
    public function handle(IncomingRequest $request)
    {
        throw new PageNotFoundException();
    }

    /**
    * Verifies the email address and code matches an
    * identity we have for that user.
    *
    * @return RedirectResponse|string
    */
    public function verify(IncomingRequest $request)
    {
        /** @var Session $authenticator */
        $authenticator auth('session')->getAuthenticator();

        $postedToken $request->getVar('token');

        $user $authenticator->getPendingUser();
        if ($user === null) {
            throw new RuntimeException('Cannot get the pending login User.');
        }

        $identity $this->getIdentity($user);

        // No match - let them try again.
        if (!$authenticator->checkAction($identity$postedToken)) {
            session()->setFlashdata('error'lang('Auth.invalidActivateToken'));

            return $this->view(setting('Auth.views')['action_email_activate_show']);
        }

        $user $authenticator->getUser();

        // Set the user active now
        $user->activate();

        // Success!
        return redirect()->to(config('Auth')->registerRedirect())
            ->with('message'lang('Auth.registerSuccess'));
    }

    /**
    * Creates an identity for the action of the user.
    *
    * @return string secret
    */
    public function createIdentity(User $user): string
    
{
        /** @var UserIdentityModel $identityModel */
        $identityModel model(UserIdentityModel::class);

        // Delete any previous identities for action
        $identityModel->deleteIdentitiesByType($user$this->type);

        $generator = static fn(): string => random_string('nozero'6);

        return $identityModel->createCodeIdentity(
            $user,
            [
                'type' => $this->type,
                'name' => 'register',
                'extra' => lang('Auth.needVerification'),
            ],
            $generator
        
);
    }

    /**
    * Returns an identity for the action of the user.
    */
    private function getIdentity(User $user): ?UserIdentity
    
{
        /** @var UserIdentityModel $identityModel */
        $identityModel model(UserIdentityModel::class);

        return $identityModel->getIdentityByType(
            $user,
            $this->type
        
);
    }

    /**
    * Returns the string type of the action class.
    */
    public function getType(): string
    
{
        return $this->type;
    }


config/Auth.php

PHP Code:
<?php

declare(strict_types=1);

/**
 * This file is part of CodeIgniter Shield.
 *
 * (c) CodeIgniter Foundation <[email protected]>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Config;

use 
CodeIgniter\Shield\Config\Auth as ShieldAuth;
use 
CodeIgniter\Shield\Authentication\Actions\ActionInterface;
use 
CodeIgniter\Shield\Authentication\AuthenticatorInterface;
use 
CodeIgniter\Shield\Authentication\Authenticators\AccessTokens;
use 
CodeIgniter\Shield\Authentication\Authenticators\HmacSha256;
use 
CodeIgniter\Shield\Authentication\Authenticators\JWT;
use 
CodeIgniter\Shield\Authentication\Authenticators\Session;
use 
CodeIgniter\Shield\Authentication\Passwords\CompositionValidator;
use 
CodeIgniter\Shield\Authentication\Passwords\DictionaryValidator;
use 
CodeIgniter\Shield\Authentication\Passwords\NothingPersonalValidator;
use 
CodeIgniter\Shield\Authentication\Passwords\PwnedValidator;
use 
CodeIgniter\Shield\Authentication\Passwords\ValidatorInterface;
use 
CodeIgniter\Shield\Models\UserModel;

class 
Auth extends ShieldAuth
{
    /**
    * ////////////////////////////////////////////////////////////////////
    * AUTHENTICATION
    * ////////////////////////////////////////////////////////////////////
    */

    // Constants for Record Login Attempts. Do not change.
    public const RECORD_LOGIN_ATTEMPT_NONE    0// Do not record at all
    public const RECORD_LOGIN_ATTEMPT_FAILURE 1// Record only failures
    public const RECORD_LOGIN_ATTEMPT_ALL    2// Record all login attempts

    /**
    * --------------------------------------------------------------------
    * View files
    * --------------------------------------------------------------------
    */
    public array $views = [
        'login'                      => 'App\Views\Shield\login',
        'register'                    => 'App\Views\Shield\register',
        'layout'                      => 'App\Views\templates\layout',
        'action_email_2fa'            => '\CodeIgniter\Shield\Views\email_2fa_show',
        'action_email_2fa_verify'    => '\CodeIgniter\Shield\Views\email_2fa_verify',
        'action_email_2fa_email'      => '\CodeIgniter\Shield\Views\Email\email_2fa_email',
        'action_email_activate_show'  => '\CodeIgniter\Shield\Views\email_activate_show',
        'action_email_activate_email' => '\CodeIgniter\Shield\Views\Email\email_activate_email',
        'magic-link-login'            => 'App\Views\Shield\magic_link_form',
        'magic-link-message'          => '\CodeIgniter\Shield\Views\magic_link_message',
        'magic-link-email'            => '\CodeIgniter\Shield\Views\Email\magic_link_email',
    ];

    /**
    * --------------------------------------------------------------------
    * Redirect URLs
    * --------------------------------------------------------------------
    * The default URL that a user will be redirected to after various auth
    * actions. This can be either of the following:
    *
    * 1. An absolute URL. E.g. http://example.com OR https://example.com
    * 2. A named route that can be accessed using `route_to()` or `url_to()`
    * 3. A URI path within the application. e.g 'admin', 'login', 'expath'
    *
    * If you need more flexibility you can override the `getUrl()` method
    * to apply any logic you may need.
    */
    public array $redirects = [
        'register'          => '/',
        'login'            => '/',
        'logout'            => '/',
        'force_reset'      => '/change-password',
        'permission_denied' => '/',
        'group_denied'      => '/',
    ];

    /**
    * --------------------------------------------------------------------
    * Authentication Actions
    * --------------------------------------------------------------------
    * Specifies the class that represents an action to take after
    * the user logs in or registers a new account at the site.
    *
    * You must register actions in the order of the actions to be performed.
    *
    * Available actions with Shield:
    * - register: \CodeIgniter\Shield\Authentication\Actions\EmailActivator::class
    * - login:    \CodeIgniter\Shield\Authentication\Actions\Email2FA::class
    *
    * @var array<string, class-string<ActionInterface>|null>
    */
    public array $actions = [
        'register' => \App\Actions\EmailActivator::class,
        'login'    => null,
    ];

    /**
    * --------------------------------------------------------------------
    * Authenticators
    * --------------------------------------------------------------------
    * The available authentication systems, listed
    * with alias and class name. These can be referenced
    * by alias in the auth helper:
    *      auth('tokens')->attempt($credentials);
    *
    * @var array<string, class-string<AuthenticatorInterface>>
    */
    public array $authenticators = [
        'tokens'  => AccessTokens::class,
        'session' => Session::class,
        'hmac'    => HmacSha256::class,
        // 'jwt'    => JWT::class,
    ];

    /**
    * --------------------------------------------------------------------
    * Default Authenticator
    * --------------------------------------------------------------------
    * The Authenticator to use when none is specified.
    * Uses the $key from the $authenticators array above.
    */
    public string $defaultAuthenticator 'session';

    /**
    * --------------------------------------------------------------------
    * Authentication Chain
    * --------------------------------------------------------------------
    * The Authenticators to test logged in status against
    * when using the 'chain' filter. Each Authenticator listed will be checked.
    * If no match is found, then the next in the chain will be checked.
    *
    * @var string[]
    * @phpstan-var list<string>
    */
    public array $authenticationChain = [
        'session',
        'tokens',
        'hmac',
        // 'jwt',
    ];

    /**
    * --------------------------------------------------------------------
    * Allow Registration
    * --------------------------------------------------------------------
    * Determines whether users can register for the site.
    */
    public bool $allowRegistration true;

    /**
    * --------------------------------------------------------------------
    * Record Last Active Date
    * --------------------------------------------------------------------
    * If true, will always update the `last_active` datetime for the
    * logged-in user on every page request.
    * This feature only works when session/tokens filter is active.
    *
    * @see https://codeigniter4.github.io/shield/quick_start_guide/using_session_auth/#protecting-pages for set filters.
    */
    public bool $recordActiveDate true;

    /**
    * --------------------------------------------------------------------
    * Allow Magic Link Logins
    * --------------------------------------------------------------------
    * If true, will allow the use of "magic links" sent via the email
    * as a way to log a user in without the need for a password.
    * By default, this is used in place of a password reset flow, but
    * could be modified as the only method of login once an account
    * has been set up.
    */
    public bool $allowMagicLinkLogins true;

    /**
    * --------------------------------------------------------------------
    * Magic Link Lifetime
    * --------------------------------------------------------------------
    * Specifies the amount of time, in seconds, that a magic link is valid.
    * You can use Time Constants or any desired number.
    */
    public int $magicLinkLifetime HOUR;

    /**
    * --------------------------------------------------------------------
    * Session Authenticator Configuration
    * --------------------------------------------------------------------
    * These settings only apply if you are using the Session Authenticator
    * for authentication.
    *
    * - field                  The name of the key the current user info is stored in session
    * - allowRemembering      Does the system allow use of "remember-me"
    * - rememberCookieName    The name of the cookie to use for "remember-me"
    * - rememberLength        The length of time, in seconds, to remember a user.
    *
    * @var array<string, bool|int|string>
    */
    public array $sessionConfig = [
        'field'              => 'user',
        'allowRemembering'  => true,
        'rememberCookieName' => 'remember',
        'rememberLength'    => 30 DAY,
    ];

    /**
    * --------------------------------------------------------------------
    * The validation rules for username
    * --------------------------------------------------------------------
    *
    * Do not use string rules like `required|valid_email`.
    *
    * @var array<string, array<int, string>|string>
    */
    public array $usernameValidationRules = [
        'label' => 'Auth.username',
        'rules' => [
            'required',
            'max_length[30]',
            'min_length[3]',
            'regex_match[/\A[a-zA-Z0-9\.]+\z/]',
        ],
    ];

    /**
    * --------------------------------------------------------------------
    * The validation rules for email
    * --------------------------------------------------------------------
    *
    * Do not use string rules like `required|valid_email`.
    *
    * @var array<string, array<int, string>|string>
    */
    public array $emailValidationRules = [
        'label' => 'Auth.email',
        'rules' => [
            'required',
            'max_length[254]',
            'valid_email',
        ],
    ];

    /**
    * --------------------------------------------------------------------
    * The validation rules for uuid
    * --------------------------------------------------------------------
    *
    * Do not use string rules like `required|valid_email`.
    *
    * @var array<string, array<int, string>|string>
    */
    public array $uuidValidationRules = [
        'label' => 'Auth.uuid',
        'rules' => [
            'required',
            'min_length[36]',
            'max_length[36]',
            'regex_match[/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/]',
        ],
    ];


    /**
    * --------------------------------------------------------------------
    * Minimum Password Length
    * --------------------------------------------------------------------
    * The minimum length that a password must be to be accepted.
    * Recommended minimum value by NIST = 8 characters.
    */
    public int $minimumPasswordLength 8;

    /**
    * --------------------------------------------------------------------
    * Password Check Helpers
    * --------------------------------------------------------------------
    * The PasswordValidator class runs the password through all of these
    * classes, each getting the opportunity to pass/fail the password.
    * You can add custom classes as long as they adhere to the
    * CodeIgniter\Shield\Authentication\Passwords\ValidatorInterface.
    *
    * @var class-string<ValidatorInterface>[]
    */
    public array $passwordValidators = [
        CompositionValidator::class,
        NothingPersonalValidator::class,
        DictionaryValidator::class,
        // PwnedValidator::class,
    ];

    /**
    * --------------------------------------------------------------------
    * Valid login fields
    * --------------------------------------------------------------------
    * Fields that are available to be used as credentials for login.
    */
    public array $validFields = [
        'uuid',
        'username',
    ];

    /**
    * --------------------------------------------------------------------
    * Additional Fields for "Nothing Personal"
    * --------------------------------------------------------------------
    * The NothingPersonalValidator prevents personal information from
    * being used in passwords. The email and username fields are always
    * considered by the validator. Do not enter those field names here.
    *
    * An extended User Entity might include other personal info such as
    * first and/or last names. $personalFields is where you can add
    * fields to be considered as "personal" by the NothingPersonalValidator.
    * For example:
    *    $personalFields = ['firstname', 'lastname'];
    */
    public array $personalFields = [];

    /**
    * --------------------------------------------------------------------
    * Password / Username Similarity
    * --------------------------------------------------------------------
    * Among other things, the NothingPersonalValidator checks the
    * amount of sameness between the password and username.
    * Passwords that are too much like the username are invalid.
    *
    * The value set for $maxSimilarity represents the maximum percentage
    * of similarity at which the password will be accepted. In other words, any
    * calculated similarity equal to, or greater than $maxSimilarity
    * is rejected.
    *
    * The accepted range is 0-100, with 0 (zero) meaning don't check similarity.
    * Using values at either extreme of the *working range* (1-100) is
    * not advised. The low end is too restrictive and the high end is too permissive.
    * The suggested value for $maxSimilarity is 50.
    *
    * You may be thinking that a value of 100 should have the effect of accepting
    * everything like a value of 0 does. That's logical and probably true,
    * but is unproven and untested. Besides, 0 skips the work involved
    * making the calculation unlike when using 100.
    *
    * The (admittedly limited) testing that's been done suggests a useful working range
    * of 50 to 60. You can set it lower than 50, but site users will probably start
    * to complain about the large number of proposed passwords getting rejected.
    * At around 60 or more it starts to see pairs like 'captain joe' and 'joe*captain' as
    * perfectly acceptable which clearly they are not.
    *
    * To disable similarity checking set the value to 0.
    *    public $maxSimilarity = 0;
    */
    public int $maxSimilarity 50;

    /**
    * --------------------------------------------------------------------
    * Hashing Algorithm to use
    * --------------------------------------------------------------------
    * Valid values are
    * - PASSWORD_DEFAULT (default)
    * - PASSWORD_BCRYPT
    * - PASSWORD_ARGON2I  - As of PHP 7.2 only if compiled with support for it
    * - PASSWORD_ARGON2ID - As of PHP 7.3 only if compiled with support for it
    */
    public string $hashAlgorithm PASSWORD_DEFAULT;

    /**
    * --------------------------------------------------------------------
    * ARGON2I/ARGON2ID Algorithm options
    * --------------------------------------------------------------------
    * The ARGON2I method of hashing allows you to define the "memory_cost",
    * the "time_cost" and the number of "threads", whenever a password hash is
    * created.
    */
    public int $hashMemoryCost 65536// PASSWORD_ARGON2_DEFAULT_MEMORY_COST;

    public int $hashTimeCost 4;  // PASSWORD_ARGON2_DEFAULT_TIME_COST;
    public int $hashThreads  1;  // PASSWORD_ARGON2_DEFAULT_THREADS;

    /**
    * --------------------------------------------------------------------
    * BCRYPT Algorithm options
    * --------------------------------------------------------------------
    * The BCRYPT method of hashing allows you to define the "cost"
    * or number of iterations made, whenever a password hash is created.
    * This defaults to a value of 12 which is an acceptable number.
    * However, depending on the security needs of your application
    * and the power of your hardware, you might want to increase the
    * cost. This makes the hashing process takes longer.
    *
    * Valid range is between 4 - 31.
    */
    public int $hashCost 12;

    /**
    * ////////////////////////////////////////////////////////////////////
    * OTHER SETTINGS
    * ////////////////////////////////////////////////////////////////////
    */

    /**
    * --------------------------------------------------------------------
    * Customize the DB group used for each model
    * --------------------------------------------------------------------
    */
    public ?string $DBGroup null;

    /**
    * --------------------------------------------------------------------
    * Customize Name of Shield Tables
    * --------------------------------------------------------------------
    * Only change if you want to rename the default Shield table names
    *
    * It may be necessary to change the names of the tables for
    * security reasons, to prevent the conflict of table names,
    * the internal policy of the companies or any other reason.
    *
    * - users                  Auth Users Table, the users info is stored.
    * - auth_identities        Auth Identities Table, Used for storage of passwords, access tokens, social login identities, etc.
    * - auth_logins            Auth Login Attempts, Table records login attempts.
    * - auth_token_logins      Auth Token Login Attempts Table, Records Bearer Token type login attempts.
    * - auth_remember_tokens  Auth Remember Tokens (remember-me) Table.
    * - auth_groups_users      Groups Users Table.
    * - auth_permissions_users Users Permissions Table.
    *
    * @var array<string, string>
    */
    public array $tables = [
        'users'            => 'users',
        'identities'        => 'auth_identities',
        'logins'            => 'auth_logins',
        'token_logins'      => 'auth_token_logins',
        'remember_tokens'  => 'auth_remember_tokens',
        'groups_users'      => 'auth_groups_users',
        'permissions_users' => 'auth_permissions_users',
    ];

    /**
    * --------------------------------------------------------------------
    * User Provider
    * --------------------------------------------------------------------
    * The name of the class that handles user persistence.
    * By default, this is the included UserModel, which
    * works with any of the database engines supported by CodeIgniter.
    * You can change it as long as they adhere to the
    * CodeIgniter\Shield\Models\UserModel.
    *
    * @var class-string<UserModel>
    */
//    public string $userProvider = UserModel::class;
    public string $userProvider = \App\Models\UserModel::class;

    /**
    * Returns the URL that a user should be redirected
    * to after a successful login.
    */
    public function loginRedirect(): string
    
{
        $session session();
        $url    $session->getTempdata('beforeLoginUrl') ?? setting('Auth.redirects')['login'];

        return $this->getUrl($url);
    }

    /**
    * Returns the URL that a user should be redirected
    * to after they are logged out.
    */
    public function logoutRedirect(): string
    
{
        $url setting('Auth.redirects')['logout'];

        return $this->getUrl($url);
    }

    /**
    * Returns the URL the user should be redirected to
    * after a successful registration.
    */
    public function registerRedirect(): string
    
{
        $url setting('Auth.redirects')['register'];

        return $this->getUrl($url);
    }

    /**
    * Returns the URL the user should be redirected to
    * if force_reset identity is set to true.
    */
    public function forcePasswordResetRedirect(): string
    
{
        $url setting('Auth.redirects')['force_reset'];

        return $this->getUrl($url);
    }

    /**
    * Returns the URL the user should be redirected to
    * if permission denied.
    */
    public function permissionDeniedRedirect(): string
    
{
        $url setting('Auth.redirects')['permission_denied'];

        return $this->getUrl($url);
    }

    /**
    * Returns the URL the user should be redirected to
    * if group denied.
    */
    public function groupDeniedRedirect(): string
    
{
        $url setting('Auth.redirects')['group_denied'];

        return $this->getUrl($url);
    }

    /**
    * Accepts a string which can be an absolute URL or
    * a named route or just a URI path, and returns the
    * full path.
    *
    * @param string $url an absolute URL or a named route or just URI path
    */
    protected function getUrl(string $url): string
    
{
        // To accommodate all url patterns
        $final_url '';

        switch (true) {
            case strpos($url'http://') === || strpos($url'https://') === 0// URL begins with 'http' or 'https'. E.g. http://example.com
                $final_url $url;
                break;

            case route_to($url) !== false// URL is a named-route
                $final_url rtrim(url_to($url), '/ ');
                break;

            default: // URL is a route (URI path)
                $final_url rtrim(site_url($url), '/ ');
                break;
        }

        return $final_url;
    }


config/Routes.php

PHP Code:
<?php

use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */
$routes->get('/''Home::index');

# Stables
$routes->get('stables''Stables::list');
$routes->get('stable/(:num)''Stables::view/$1');
$routes->get('stable/new''Stables::edit', ['filter' => 'session']);
$routes->get('stable/edit/(:num)''Stables::edit/$1', ['filter' => 'session']);
$routes->post('stable/save''Stables::save', ['filter' => 'session']);

# Profiles
$routes->get('profiles''Profiles::list');
$routes->get('u/(:segment)''Profiles::view/$1');
$routes->get('edit-profile''Profiles::edit', ['filter' => 'session']);
$routes->post('profile/save''Profiles::save', ['filter' => 'session']);
$routes->post('profile/delete''Profiles::delete', ['filter' => 'session']);

# Events
$routes->get('events''Events::list');
$routes->get('event/(:num)''Events::view/$1');
$routes->get('event/new''Events::edit', ['filter' => 'session']);
$routes->get('event/edit/(:num)''Events::edit/$1', ['filter' => 'session']);
$routes->post('event/save''Events::save', ['filter' => 'session']);

# Results
$routes->get('results''Results::list');
$routes->get('results/(:num)''Results::list/$1'); // for year filter
$routes->get('result/(:num)''Results::view/$1');
$routes->match(['get''post'], 'result/new''Results::edit', ['filter' => 'session']);
$routes->post('result/save''Results::save', ['filter' => 'session']);

# Forum
$routes->get('forum''Forums::show');
$routes->get('forum/(:num)''Forums::show/$1');
$routes->post('forum/save''Forums::save', ['filter' => 'session']);

# Insights
$routes->post('insights/save''Insights::save', ['filter' => 'session']);

# Shield, Login, Registration etc
$routes->post('login/magic-link''MagicLinkController::loginAction');
service('auth')->routes($routes);
$routes->match(['get''post'], 'change-password''Home::changePassword', ['filter' => 'session']);

# static pages
$routes->get('polo-league''Home::page/polo-league');
$routes->get('about-us''Home::page/about-us');
$routes->get('links''Home::page/links');

# API
$routes->post('api/signup/''API::signup');
$routes->post('api/events''API::events');
$routes->post('api/autocomplete''API::autocomplete', ['filter' => 'session']); 

and Controllers/MagicLinkController.php

PHP Code:
<?php

namespace App\Controllers;

use 
CodeIgniter\Shield\Controllers\MagicLinkController as ShieldMagicLinkController;
use 
CodeIgniter\HTTP\RedirectResponse;
use 
CodeIgniter\I18n\Time;
use 
CodeIgniter\Shield\Authentication\Authenticators\Session;
use 
CodeIgniter\Shield\Models\UserIdentityModel;

class 
MagicLinkController extends ShieldMagicLinkController
{
    public function loginAction(): string|RedirectResponse
    
{
        if (!setting('Auth.allowMagicLinkLogins')) {
            return redirect()->route('login')->with('error'lang('Auth.magicLinkDisabled'));
        }

        // Validate email format
        $rules $this->getValidationRules();
        if (!$this->validateData($this->request->getPost(), $rules, [], config('Auth')->DBGroup)) {
            return redirect()->route('magic-link')->with('errors'$this->validator->getErrors());
        }

        // Check if the user exists
        $uuid $this->request->getPost('uuid');
        $user $this->provider->findByCredentials(['uuid' => $uuid]);

        if ($user === null) {
            return redirect()->route('magic-link')->with('error'lang('Auth.invalidEmail'));
        }

        /** @var UserIdentityModel $identityModel */
        $identityModel model(UserIdentityModel::class);

        // Delete any previous magic-link identities
        $identityModel->deleteIdentitiesByType($userSession::ID_TYPE_MAGIC_LINK);

        // Generate the code and save it as an identity
        helper('text');
        $token random_string('crypto'20);

        $identityModel->insert([
            'user_id' => $user->id,
            'type' => Session::ID_TYPE_MAGIC_LINK,
            'secret' => $token,
            'expires' => Time::now()->addSeconds(setting('Auth.magicLinkLifetime'))->format('Y-m-d H:i:s'),
        ]);

        /** @var IncomingRequest $request */
        $request service('request');

        $ipAddress $request->getIPAddress();
        $userAgent = (string)$request->getUserAgent();
        $date Time::now()->toDateTimeString();

        $userEmail '[email protected]'// only for posting at forum

        // Send the user an email with the code
        helper('email');
        $email emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
        $email->setTo($userEmail);
        $email->setSubject('slponyplay');
        $email->setMessage('login|' $uuid '|' url_to('verify-magic-link') . '?token=' $token);

        if ($email->send(false) === false) {
            log_message('error'$email->printDebugger(['headers']));

            return redirect()->route('magic-link')->with('error'lang('Auth.unableSendEmailToUser', [$user->email]));
        }

        // Clear the email
        $email->clear();

        $user->forcePasswordReset();

        return $this->displayMessage();
    }

    protected function getValidationRules(): array
    {
        return [
            'uuid' => config('Auth')->uuidValidationRules,
        ];
    }


This should be all. I'd started it with Shield 1.0.0 when it came out and tested it the whole registration process and magic link thoroughly. And when the site was finished, it was broken. Updates for Shield has been done, tested it with Shield 1.0.0 again but no success.
Also it seems to revert to email still at times, when I enter a UUID the form responds it can't send an email to xyz (i only use fake emails on all users)
Reply




Theme © iAndrew 2016 - Forum software by © MyBB