Pechente / kirby-password-guard

Protect your frontend with a simple password
MIT License
27 stars 1 forks source link

Additional function: array with multiple passwords #4

Open gbdesign2023 opened 2 weeks ago

gbdesign2023 commented 2 weeks ago

I added the function to your script that allows me to use different passwords. This can be useful if a password changes monthly, and you want to create a list in advance.

config.php

'pechente.kirby-password-guard' => [
    'enabled' => true,
    'passwords' => [
        'password',
        'password2',
        'password3'
    ],
    'pattern' => '(:all)',
],

index.php

<?php

use Kirby\Cms\Page;

Kirby::plugin('pechente/kirby-password-guard', [
    'templates' => [
        'password-guard' => __DIR__ . '/templates/password-guard.php',
    ],
    'snippets' => [
        'panel-icon' => __DIR__ . '/snippets/panel-icon.php',
    ],
    'routes' => [
        [
            'pattern' => 'password-guard',
            'language' => '*',
            'method' => 'POST',
            'action' => function () {
                $password = get('password');
                $hashedPassword = password_hash($password, PASSWORD_BCRYPT);

                $session = kirby()->session();
                $session->set('kirby-password-guard.password-hash', $hashedPassword);

                $redirect = get('redirect');

                kirby()->response()->redirect($redirect);
            }
        ],
        [
            'pattern' => option('pechente.kirby-password-guard.pattern', '(:all)'),
            'method' => 'GET',
            'action' => function (string $uid) {
                if (
                    option('pechente.kirby-password-guard.enabled') === false ||
                    !option('pechente.kirby-password-guard.passwords') || // Adjustment here: Check for an array of passwords
                    kirby()->user()
                ) {
                    $this->next();
                }
                $passwordIncorrect = false;

                // Retrieve the session and stored hash
                $session = kirby()->session();
                $hash = $session->get('kirby-password-guard.password-hash');
                $passwords = option('pechente.kirby-password-guard.passwords'); // Load the array of passwords

                // Check if any of the passwords are correct
                if ($hash) {
                    foreach ($passwords as $password) {
                        if (password_verify($password, $hash)) {
                            $this->next(); // Redirect if the password is correct
                        }
                    }
                    // If no password was correct, mark the password as incorrect
                    $passwordIncorrect = true;
                    kirby()->session()->remove('kirby-password-guard.password-hash');
                }

                // Render the password page if the password is incorrect
                $passwordPage = new Page([
                    'slug' => 'password-guard',
                    'template' => 'password-guard',
                    'content' => [
                        'title' => 'Password Guard',
                        'redirect' => url($uid),
                        'passwordIncorrect' => $passwordIncorrect
                    ]
                ]);

                return $passwordPage->render();
            }
        ]
    ],
]);
Pechente commented 2 weeks ago

That's pretty cool! Feel free to submit a pull request. One note though: It would be great if it was still compatible with the old config pattern. I.e if 'password' is filled in the config, just add it to the array of passwords. That way existing configs will not break.

gbdesign2023 commented 2 weeks ago

And with this addition, it is possible to de-/activate the plugin in the panel:

site.yml

fields:
  passwordGuardEnabled:
    label:
      en: 'Enable "Password Guard"?'
      de: '"Password Guard" aktivieren?'
    type: toggle
    text:
      -
        en: not activated
        de: nicht aktiviert
      -
        en: activated
        de: aktiviert
    default: false
    icon: lock
    help:
      en: The website is only protected for users who are logged out.
      de: Die Website wird nur für ausgeloggte User geschützt.
<?php

use Kirby\Cms\Page;

Kirby::plugin('pechente/kirby-password-guard', [
    'templates' => [
        'password-guard' => __DIR__ . '/templates/password-guard.php',
    ],
    'snippets' => [
        'panel-icon' => __DIR__ . '/snippets/panel-icon.php',
    ],
    'routes' => [
        [
            'pattern' => 'password-guard',
            'language' => '*',
            'method' => 'POST',
            'action' => function () {
                $password = get('password');
                $hashedPassword = password_hash($password, PASSWORD_BCRYPT);

                $session = kirby()->session();
                $session->set('kirby-password-guard.password-hash', $hashedPassword);

                $redirect = get('redirect');

                kirby()->response()->redirect($redirect);
            }
        ],
        [
            'pattern' => option('pechente.kirby-password-guard.pattern', '(:all)'),
            'method' => 'GET',
            'action' => function (string $uid) {
                // Check if the password guard is enabled using the value from the Panel field
                if (
                    site()->passwordGuardEnabled()->toBool() === false || // Use the value from the site field
                    !option('pechente.kirby-password-guard.passwords') || // Check for an array of passwords
                    kirby()->user()
                ) {
                    $this->next();
                }
                $passwordIncorrect = false;

                // Retrieve the session and stored hash
                $session = kirby()->session();
                $hash = $session->get('kirby-password-guard.password-hash');
                $passwords = option('pechente.kirby-password-guard.passwords'); // Load the array of passwords

                // Check if any of the passwords are correct
                if ($hash) {
                    foreach ($passwords as $password) {
                        if (password_verify($password, $hash)) {
                            $this->next(); // Redirect if the password is correct
                        }
                    }
                    // If no password was correct, mark the password as incorrect
                    $passwordIncorrect = true;
                    kirby()->session()->remove('kirby-password-guard.password-hash');
                }

                // Render the password page if the password is incorrect
                $passwordPage = new Page([
                    'slug' => 'password-guard',
                    'template' => 'password-guard',
                    'content' => [
                        'title' => 'Password Guard',
                        'redirect' => url($uid),
                        'passwordIncorrect' => $passwordIncorrect
                    ]
                ]);

                return $passwordPage->render();
            }
        ]
    ],
]);
gbdesign2023 commented 2 weeks ago

@Pechente I have to admit that I have never created a pull request... With the addition in the site.yml blueprint, it would also be better to create a snippet in the plugin.

gbdesign2023 commented 2 weeks ago

@Pechente It is also possible to create a list of passwords in the panel. These are then stored in plain text in site.txt. This is, of course, not as secure as hardcoding them in config.php. Would this option still be of interest to you?