<commit_before><?php

namespace Backend\Modules\Users\Installer;

/*
 * This file is part of Fork CMS.
 *
 * For the full copyright and license information, please view the license
 * file that was distributed with this source code.
 */

use Symfony\Component\Filesystem\Filesystem;
use Backend\Core\Installer\ModuleInstaller;
use Backend\Modules\Groups\Engine\Model as BackendGroupsModel;
use Backend\Modules\Profiles\Engine\Model as BackendProfilesModel;
use Backend\Modules\Users\Engine\Model as BackendUsersModel;

/**
 * Installer for the users module
 */
class Installer extends ModuleInstaller
{
    public function install(): void
    {
        $this->addModule('Users');
        $this->importSQL(__DIR__ . '/Data/install.sql');
        $this->importLocale(__DIR__ . '/Data/locale.xml');
        $this->configureSettings();
        $this->configureBackendNavigation();
        $this->configureBackendRights();
        $this->loadGodUser();
    }

    private function configureBackendNavigation(): void
    {
        // Set navigation for "Settings"
        $navigationSettingsId = $this->setNavigation(null, 'Settings');
        $this->setNavigation(
            $navigationSettingsId,
            'Users',
            'users/index',
            [
                'users/add',
                'users/edit',
            ],
            4
        );
    }

    private function configureBackendRights(): void
    {
        $this->setModuleRights(1, $this->getModule());

        $this->setActionRights(1, $this->getModule(), 'Add');
        $this->setActionRights(1, $this->getModule(), 'Delete');
        $this->setActionRights(1, $this->getModule(), 'Edit');
        $this->setActionRights(1, $this->getModule(), 'Index');
        $this->setActionRights(1, $this->getModule(), 'UndoDelete');
    }

    private function configureSettings(): void
    {
        $this->setSetting($this->getModule(), 'date_formats', ['j/n/Y', 'd/m/Y', 'j F Y', 'F j, Y']);
        $this->setSetting($this->getModule(), 'default_group', 1);
        $this->setSetting($this->getModule(), 'time_formats', ['H:i', 'H:i:s', 'g:i a', 'g:i A']);
    }

    public function getPasswordStrength(): string
    {
        // init vars
        $password = $this->getVariable('password');
        $score = 0;
        $uniqueChars = [];

        // less then 4 chars is just a weak password
        if (mb_strlen($password) <= 4) {
            return 'weak';
        }

        // loop chars and add unique chars
        $passwordChars = str_split($password);
        foreach ($passwordChars as $char) {
            $uniqueChars[$char] = $char;
        }

        // less then 3 unique chars is just weak
        if (count($uniqueChars) < 3) {
            return 'weak';
        }

        // more then 6 chars is good
        if (mb_strlen($password) >= 6) {
            ++$score;
        }

        // more then 8 is better
        if (mb_strlen($password) >= 8) {
            ++$score;
        }

        // @todo
        // upper and lowercase?
        if (preg_match('/[a-z]/', $password) && preg_match('/[A-Z]/', $password)) {
            $score += 2;
        }

        // number?
        if (preg_match('/\d+/', $password)) {
            ++$score;
        }

        // special char?
        if (preg_match('/.[!,@,#,$,%,^,&,*,?,_,~,-,(,)]/', $password)) {
            ++$score;
        }

        // strong password
        if ($score >= 4) {
            return 'strong';
        }

        // average
        if ($score >= 2) {
            return 'average';
        }

        // fallback
        return 'weak';
    }

    private function hasExistingGodUser(): bool
    {
        // @todo: Replace by UserRepository method when it exists.
        return (bool) $this->getDB()->getVar(
            'SELECT 1
             FROM users
             WHERE is_god = ? AND deleted = ? AND active = ?
             LIMIT 1',
            ['Y', 'N', 'Y']
        );
    }

    /**
     * @todo: Move this code to a DataFixture and use User entity when it exists.
     */
    private function loadGodUser(): void
    {
        if (!$this->hasExistingGodUser()) {
            $this->loadGodUserAvatar();

            // build settings
            $settings = [];
            $settings['nickname'] = serialize('Fork CMS');
            $settings['name'] = serialize('Fork');
            $settings['surname'] = serialize('CMS');
            $settings['interface_language'] = serialize($this->getVariable('default_interface_language'));
            $settings['date_format'] = serialize('j F Y');
            $settings['time_format'] = serialize('H:i');
            $settings['datetime_format'] = serialize(
                unserialize($settings['date_format']) . ' ' . unserialize($settings['time_format'])
            );
            $settings['number_format'] = serialize('dot_nothing');
            $settings['password_key'] = serialize(uniqid('', true));
            $settings['password_strength'] = serialize($this->getPasswordStrength());
            $settings['current_password_change'] = serialize(time());
            $settings['avatar'] = serialize('god.jpg');

            // build user
            $user = [];
            $user['email'] = $this->getVariable('email');
            $user['password'] = BackendProfilesModel::encryptPassword($this->getVariable('password'));
            $user['active'] = 'Y';
            $user['deleted'] = 'N';
            $user['is_god'] = 'Y';

            // insert user
            $user['id'] = BackendUsersModel::insert($user, $settings);

            // build groups
            $groups = [$this->getSetting('Users', 'default_group')];

            // insert group
            BackendGroupsModel::insertMultipleGroups($user['id'], $groups);
        }
    }

    private function loadGodUserAvatar(): void
    {
        // secret files
        $avatar124x124 = '/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAYEBAQFBAYFBQYJBgUGCQsIBgYICwwKCgsKCgwQDAwMDAwMEAwODxAPDgwTExQUExMcGxsbHCAgICAgICAgICD/2wBDAQcHBw0MDRgQEBgaFREVGiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICD/wAARCAB8AHwDAREAAhEBAxEB/8QAHQAAAgIDAQ<KEY>';
        $avatar64x64 = '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';
        $avatar32x32 = <KEY>';

        $filesystem = new Filesystem();

        // store files
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/source/god.jpg',
            base64_decode($avatar124x124)
        );
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/128x128/god.jpg',
            base64_decode($avatar124x124)
        );
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/64x64/god.jpg',
            base64_decode($avatar64x64)
        );
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/32x32/god.jpg',
            base64_decode($avatar32x32)
        );
    }
}
<commit_msg>fix the double serialising of the user settings<commit_after><?php

namespace Backend\Modules\Users\Installer;

/*
 * This file is part of Fork CMS.
 *
 * For the full copyright and license information, please view the license
 * file that was distributed with this source code.
 */

use Symfony\Component\Filesystem\Filesystem;
use Backend\Core\Installer\ModuleInstaller;
use Backend\Modules\Groups\Engine\Model as BackendGroupsModel;
use Backend\Modules\Profiles\Engine\Model as BackendProfilesModel;
use Backend\Modules\Users\Engine\Model as BackendUsersModel;

/**
 * Installer for the users module
 */
class Installer extends ModuleInstaller
{
    public function install(): void
    {
        $this->addModule('Users');
        $this->importSQL(__DIR__ . '/Data/install.sql');
        $this->importLocale(__DIR__ . '/Data/locale.xml');
        $this->configureSettings();
        $this->configureBackendNavigation();
        $this->configureBackendRights();
        $this->loadGodUser();
    }

    private function configureBackendNavigation(): void
    {
        // Set navigation for "Settings"
        $navigationSettingsId = $this->setNavigation(null, 'Settings');
        $this->setNavigation(
            $navigationSettingsId,
            'Users',
            'users/index',
            [
                'users/add',
                'users/edit',
            ],
            4
        );
    }

    private function configureBackendRights(): void
    {
        $this->setModuleRights(1, $this->getModule());

        $this->setActionRights(1, $this->getModule(), 'Add');
        $this->setActionRights(1, $this->getModule(), 'Delete');
        $this->setActionRights(1, $this->getModule(), 'Edit');
        $this->setActionRights(1, $this->getModule(), 'Index');
        $this->setActionRights(1, $this->getModule(), 'UndoDelete');
    }

    private function configureSettings(): void
    {
        $this->setSetting($this->getModule(), 'date_formats', ['j/n/Y', 'd/m/Y', 'j F Y', 'F j, Y']);
        $this->setSetting($this->getModule(), 'default_group', 1);
        $this->setSetting($this->getModule(), 'time_formats', ['H:i', 'H:i:s', 'g:i a', 'g:i A']);
    }

    public function getPasswordStrength(): string
    {
        // init vars
        $password = $this->getVariable('password');
        $score = 0;
        $uniqueChars = [];

        // less then 4 chars is just a weak password
        if (mb_strlen($password) <= 4) {
            return 'weak';
        }

        // loop chars and add unique chars
        $passwordChars = str_split($password);
        foreach ($passwordChars as $char) {
            $uniqueChars[$char] = $char;
        }

        // less then 3 unique chars is just weak
        if (count($uniqueChars) < 3) {
            return 'weak';
        }

        // more then 6 chars is good
        if (mb_strlen($password) >= 6) {
            ++$score;
        }

        // more then 8 is better
        if (mb_strlen($password) >= 8) {
            ++$score;
        }

        // @todo
        // upper and lowercase?
        if (preg_match('/[a-z]/', $password) && preg_match('/[A-Z]/', $password)) {
            $score += 2;
        }

        // number?
        if (preg_match('/\d+/', $password)) {
            ++$score;
        }

        // special char?
        if (preg_match('/.[!,@,#,$,%,^,&,*,?,_,~,-,(,)]/', $password)) {
            ++$score;
        }

        // strong password
        if ($score >= 4) {
            return 'strong';
        }

        // average
        if ($score >= 2) {
            return 'average';
        }

        // fallback
        return 'weak';
    }

    private function hasExistingGodUser(): bool
    {
        // @todo: Replace by UserRepository method when it exists.
        return (bool) $this->getDB()->getVar(
            'SELECT 1
             FROM users
             WHERE is_god = ? AND deleted = ? AND active = ?
             LIMIT 1',
            ['Y', 'N', 'Y']
        );
    }

    /**
     * @todo: Move this code to a DataFixture and use User entity when it exists.
     */
    private function loadGodUser(): void
    {
        if (!$this->hasExistingGodUser()) {
            $this->loadGodUserAvatar();

            // build settings
            $settings = [];
            $settings['nickname'] = 'Fork CMS';
            $settings['name'] = 'Fork';
            $settings['surname'] = 'CMS';
            $settings['interface_language'] = $this->getVariable('default_interface_language');
            $settings['date_format'] = 'j F Y';
            $settings['time_format'] = 'H:i';
            $settings['datetime_format'] = $settings['date_format'] . ' ' . $settings['time_format'];
            $settings['number_format'] = 'dot_nothing';
            $settings['password_key'] = uniqid('', true);
            $settings['password_strength'] = $this->getPasswordStrength();
            $settings['current_password_change'] = time();
            $settings['avatar'] = 'god.jpg';

            // build user
            $user = [];
            $user['email'] = $this->getVariable('email');
            $user['password'] = BackendProfilesModel::encryptPassword($this->getVariable('password'));
            $user['active'] = 'Y';
            $user['deleted'] = 'N';
            $user['is_god'] = 'Y';

            // insert user
            $user['id'] = BackendUsersModel::insert($user, $settings);

            // build groups
            $groups = [$this->getSetting('Users', 'default_group')];

            // insert group
            BackendGroupsModel::insertMultipleGroups($user['id'], $groups);
        }
    }

    private function loadGodUserAvatar(): void
    {
        // secret files
        $avatar124x124 = '/9j/<KEY>';
        $avatar64x64 = <KEY>';
        $avatar32x32 = <KEY>WB4bkomO+XSiNkIX//2Q==';

        $filesystem = new Filesystem();

        // store files
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/source/god.jpg',
            base64_decode($avatar124x124)
        );
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/128x128/god.jpg',
            base64_decode($avatar124x124)
        );
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/64x64/god.jpg',
            base64_decode($avatar64x64)
        );
        $filesystem->dumpFile(
            PATH_WWW . '/src/Frontend/Files/backend_users/avatars/32x32/god.jpg',
            base64_decode($avatar32x32)
        );
    }
}

{'fraction_non_alphanumeric': 0.12869399428026693, 'fraction_numerical': 0.03574833174451859, 'mean_word_length': 2.7525150905432594, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 98, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3742650', 'n_tokens_mistral': 6769, 'n_tokens_neox': 6282, 'n_words': 774}