/ src / views / elements / SecurityElement.php
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Sreenidhi Muralidharan
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\views\elements;

use seekquarry\yioop as B;
use seekquarry\yioop\configs as C;

/**
 * Element used to handle configurations of Yioop related to authentication,
 * captchas, and recovery of missing passwords
 *
 * @author Sreenidhi Muralidharan/Chris Pollett
 */
class SecurityElement extends Element
{
    /**
     * Method that draws forms to to select either among a text or a
     * graphical captcha
     *
     * @param array $data holds data on the profile elements which have been
     *     filled in as well as data about which form fields to display
     */
    public function render($data)
    {
        $admin_url = htmlentities(B\controllerUrl('admin', true));
        $localize_url = $admin_url .C\p('CSRF_TOKEN')."=".
            $data[C\p('CSRF_TOKEN')] .
            "&a=manageLocales&arg=editstrings&selectlocale=" .
            $data['LOCALE_TAG'];
        ?>
        <div class = "current-activity">
        <h2><?= tl('security_element_session_captcha') ?></h2>
        <form class="top-margin" method="post">
            <input type="hidden" name="c" value="admin" >
            <input type="hidden" name="a" value="security" >
            <input type="hidden" name="<?= C\p('CSRF_TOKEN') ?>" value="<?=
                $data[C\p('CSRF_TOKEN')] ?>" >
            <input type="hidden" name="arg" value="updatetypes" >
            <div class="top-margin">
            <fieldset>
                <legend><b><?=
                tl('security_element_session').
                "&nbsp;" . $this->view->helper("helpbutton")->render(
                    "Session Parameters", $data[C\p('CSRF_TOKEN')])
                ?>
                </b></legend>
                <div class="top-margin"><b><label for="timezone"><?=
                    tl('security_element_site_timezone') ?></label></b>
                <input type="text" id="timezone"
                    name="TIMEZONE" class="extra-wide-field" value='<?=
                    $data["TIMEZONE"] ?>' ></div>
                <div class="top-margin"><b><label for="token-name"><?=
                    tl('security_element_token_name') ?></label></b>
                <input type="text" id="token-name"
                    name="CSRF_TOKEN" class="extra-wide-field" value='<?=
                    $data["CSRF_TOKEN"] ?>' ></div>
                <div class="top-margin"><b><label for="cookie-name"><?=
                    tl('security_element_session_name') ?></label></b>
                <input type="text" id="cookie-name"
                    name="SESSION_NAME" class="extra-wide-field" value='<?=
                    $data["SESSION_NAME"] ?>' ></div>
                <div class="top-margin"><b><label for="autologout"><?=
                    tl('security_element_autologout')?></label></b>
                <?php
                    $this->view->helper("options")->render(
                    "autologout", "AUTOLOGOUT",  $data['AUTOLOGOUT_TIMES'],
                     $data['AUTOLOGOUT']);?></div>
                <div class="top-margin"><b><label for="consent-expires"><?=
                    tl('security_element_consent_expires')?></label></b>
                <?php
                    $this->view->helper("options")->render(
                    "consent-expires", "COOKIE_LIFETIME",
                    $data['COOKIE_LIFETIMES'], $data['COOKIE_LIFETIME']);
                    ?></div>
            </fieldset>
            </div>
            <div class="top-margin">
            <fieldset>
                <legend><b><label
                for="privacy-mode"><?=tl('security_element_privacy') ?>
                </label>
                <?= tl($this->view->helper("helpbutton")->render(
                    "Privacy", $data[C\p('CSRF_TOKEN')]))
                ?></b>
                </legend>
                <table>
                <tr><td>
                <label><b><?=
                    tl('security_element_differential_privacy')?></b></label>
                </td><td>
                <?php
                if (empty($data['DIFFERENTIAL_PRIVACY'])) {
                    $data['DIFFERENTIAL_PRIVACY'] = 0;
                }
                $this->view->helper("options")->render("privacy-mode",
                    "DIFFERENTIAL_PRIVACY", $data['PRIVACY_MODES'],
                    $data['DIFFERENTIAL_PRIVACY']);
                ?>
                </td></tr><tr><td>
                <label for="group-analytics-mode"><b><?php
                e(tl('security_element_group_analytics'));
                ?></b>
                </label>
                </td><td>
                <?php
                if (empty($data['GROUP_ANALYTICS_MODE'])) {
                    $data['GROUP_ANALYTICS_MODE'] = 0;
                }
                $this->view->helper("options")->render("group-analytics-mode",
                    "GROUP_ANALYTICS_MODE", $data['GROUP_ANALYTICS_MODES'],
                    $data['GROUP_ANALYTICS_MODE']);
                ?>
                </td></tr><tr><td>
                <label
                for="search-analytics-mode"><b><?php
                e(tl('security_element_search_analytics'));
                ?></b>
                </label>
                </td><td>
                <?php
                if (empty($data['SEARCH_ANALYTICS_MODE'])) {
                    $data['SEARCH_ANALYTICS_MODE'] = 0;
                }
                $this->view->helper("options")->render("search-analytics-mode",
                    "SEARCH_ANALYTICS_MODE", $data['SEARCH_ANALYTICS_MODES'],
                    $data['SEARCH_ANALYTICS_MODE']);
                ?>
                </td></tr></table>
            </fieldset>
            </div>
            <div class="top-margin">
            <fieldset>
                <legend><b><?=tl('security_element_authentication')
                ?>&nbsp;<?=$this->view->helper("helpbutton")->render(
                    "Authentication", $data[C\p('CSRF_TOKEN')])
                ?></b>
                </legend>
                <div class="top-margin"><b><label for="auth-method"><?=
                    tl('security_element_auth_method') ?></label></b>
                <?php
                $this->view->helper("options")->render("auth-method",
                    "AUTH_METHOD", $data['AUTH_METHODS'],
                    $data['AUTH_METHOD'],
                    'toggleClass("local-auth-section", "none");' .
                    'toggleClass("ldap-section", "none");' .
                    'elt("recovery-mode").disabled = ' .
                    '(this.value == ' . C\LDAP_AUTHENTICATION . ');' .
                    'elt("recovery-mode-off").disabled = ' .
                    '(this.value != ' . C\LDAP_AUTHENTICATION . ');' .
                    'if (this.value == ' . C\LDAP_AUTHENTICATION . ') {' .
                    'elt("recovery-mode").value = ' . C\NO_RECOVERY . ';}');
                ?></div>
                <div id="local-auth-section"<?=
                    ($data['AUTH_METHOD'] == C\LDAP_AUTHENTICATION) ?
                    ' class="none"' : '' ?>>
                <div class="top-margin"><b><?=
                    tl('security_element_password_rules') ?></b></div>
                <div><input type="checkbox" id="password-require-lowercase"
                    name="PASSWORD_REQUIRE_LOWERCASE" value="true" <?=
                    !empty($data['PASSWORD_REQUIRE_LOWERCASE']) ?
                    "checked='checked'" : "" ?> ><label
                    for="password-require-lowercase"><?=
                    tl('security_element_require_lowercase') ?></label></div>
                <div><input type="checkbox" id="password-require-uppercase"
                    name="PASSWORD_REQUIRE_UPPERCASE" value="true" <?=
                    !empty($data['PASSWORD_REQUIRE_UPPERCASE']) ?
                    "checked='checked'" : "" ?> ><label
                    for="password-require-uppercase"><?=
                    tl('security_element_require_uppercase') ?></label></div>
                <div><input type="checkbox" id="password-require-digit"
                    name="PASSWORD_REQUIRE_DIGIT" value="true" <?=
                    !empty($data['PASSWORD_REQUIRE_DIGIT']) ?
                    "checked='checked'" : "" ?> ><label
                    for="password-require-digit"><?=
                    tl('security_element_require_digit') ?></label></div>
                <div><input type="checkbox" id="password-require-symbol"
                    name="PASSWORD_REQUIRE_SYMBOL" value="true" <?=
                    !empty($data['PASSWORD_REQUIRE_SYMBOL']) ?
                    "checked='checked'" : "" ?> ><label
                    for="password-require-symbol"><?=
                    tl('security_element_require_symbol') ?></label></div>
                <div class="top-margin"><b><label for="password-min-len"><?=
                    tl('security_element_password_min_len') ?></label></b>
                <input type="text" id="password-min-len"
                    name="PASSWORD_MIN_LEN" class="very-narrow-field" value='<?=
                    $data['PASSWORD_MIN_LEN'] ?>' ></div>
                </div>
                <div id="ldap-section"<?=
                    ($data['AUTH_METHOD'] == C\LDAP_AUTHENTICATION) ?
                    '' : ' class="none"' ?>>
                <?php $auth_missing = $data['AUTHENTICATION_MISSING'] ?? []; ?>
                <div class="top-margin"><b><label
                    for="ldap-controller-add"><?=
                    tl('security_element_ldap_controllers')
                    ?></label></b>
                    <?php
                    $controller_csv = trim((string)
                        ($data['LDAP_CONTROLLERS'] ?? ''));
                    $controller_entries = ($controller_csv === '') ? [] :
                        array_filter(array_map('trim',
                        explode(',', $controller_csv)));
                    ?>
                    <ul class="mail-domain-list" id="ldap-controller-list"
                        ><?php
                        foreach ($controller_entries as $controller) {
                            ?><li class="mail-domain-item managed-csv-item"
                                ><span class="mail-domain-text managed-csv-text"
                                ><?= $controller
                                ?></span><button type="button"
                                class="managed-csv-remove mail-domain-remove"
                                title="<?= tl(
                                'security_element_ldap_controller_remove'
                                ) ?>">&times;</button></li><?php
                        }
                        ?></ul>
                    <div class="mail-domain-add-row">
                        <input type="text" id="ldap-controller-add"
                            class="wide-field" >
                        <button type="button" id="ldap-controller-add-button"
                            class="button-box" data-remove-label="<?= tl(
                            'security_element_ldap_controller_remove'
                            ) ?>"><?= tl(
                            'security_element_ldap_controller_add'
                            ) ?></button><?php
                            if (in_array('LDAP_CONTROLLERS', $auth_missing)) {
                                ?><span class="required-star<?=
                                (!empty($controller_entries)) ? ' none' : ''
                                ?>" id="ldap-controllers-star">*</span><?php
                            } ?>
                    </div>
                    <input type="hidden" id="ldap-controllers"
                        name="LDAP_CONTROLLERS"
                        value="<?= $controller_csv ?>" >
                </div>
                <div class="top-margin"><b><label
                    for="ldap-account-suffix"><?=
                    tl('security_element_ldap_account_suffix')
                    ?></label></b>
                    <input type="text" id="ldap-account-suffix"
                        name="LDAP_ACCOUNT_SUFFIX" class="wide-field"
                        value="<?= $data['LDAP_ACCOUNT_SUFFIX'] ?? '' ?>"
                        ><?php e(in_array('LDAP_ACCOUNT_SUFFIX', $auth_missing)
                        ? '<span class="required-star">*</span>' : ''); ?>
                </div>
                <div class="top-margin"><b><label for="ldap-base-dn"><?=
                    tl('security_element_ldap_base_dn')
                    ?></label></b>
                    <input type="text" id="ldap-base-dn"
                        name="LDAP_BASE_DN" class="wide-field"
                        value="<?= $data['LDAP_BASE_DN'] ?? '' ?>"
                        ><?php e(in_array('LDAP_BASE_DN', $auth_missing)
                        ? '<span class="required-star">*</span>' : ''); ?>
                </div>
                <div class="top-margin"><?=
                    tl('security_element_ldap_root_intro') ?></div>
                <div class="top-margin"><b><label for="ldap-root-name"><?=
                    tl('security_element_ldap_root_name')
                    ?></label></b>
                    <input type="text" id="ldap-root-name"
                        name="LDAP_ROOT_NAME" class="wide-field" value=""
                        autocomplete="off" ><?php
                        e(in_array('LDAP_ROOT_NAME', $auth_missing)
                        ? '<span class="required-star">*</span>' : ''); ?>
                </div>
                <div class="top-margin"><b><label
                    for="ldap-root-password"><?=
                    tl('security_element_ldap_root_password')
                    ?></label></b>
                    <input type="password" id="ldap-root-password"
                        name="LDAP_ROOT_PASSWORD" class="wide-field" value=""
                        autocomplete="off" ><?php
                        e(in_array('LDAP_ROOT_PASSWORD', $auth_missing)
                        ? '<span class="required-star">*</span>' : ''); ?>
                </div>
                <?php if (!empty($data['LDAP_PROBLEMS'])) {
                    $problem_messages = [
                        'no_servers' =>
                            tl('security_element_ldap_problem_no_servers'),
                        'no_suffix' =>
                            tl('security_element_ldap_problem_no_suffix'),
                        'no_base_dn' =>
                            tl('security_element_ldap_problem_no_base_dn'),
                        'email_conflicts' => tl(
                            'security_element_ldap_problem_email_conflicts'),
                        'root_no_email' => tl(
                            'security_element_ldap_problem_root_no_email'),
                    ];
                    ?>
                <div class="top-margin red">
                    <?= tl('security_element_ldap_problem_intro') ?>
                    <ul><?php
                    foreach ($data['LDAP_PROBLEMS'] as $problem) {
                        $problem_text = $problem_messages[$problem] ?? '';
                        if ($problem_text === '') {
                            continue;
                        }
                        ?><li><?= $problem_text ?><?php
                        if ($problem == 'email_conflicts') {
                            ?> <a href="<?= $admin_url .
                                C\p('CSRF_TOKEN') . "=" .
                                $data[C\p('CSRF_TOKEN')] . "&a=security" .
                                "&arg=downloadconflicts" ?>"><?=
                                tl('security_element_ldap_download_conflicts')
                                ?></a><?php
                        }
                        ?></li><?php
                    }
                    ?></ul>
                </div>
                <?php } ?>
                </div>
                <div class="top-margin"><b><label for="recovery-mode"><?=
                    tl('security_element_account_recovery') ?></label></b>
                <?php
                $recovery_is_ldap =
                    $data['AUTH_METHOD'] == C\LDAP_AUTHENTICATION;
                $recovery_selected = ($recovery_is_ldap) ? C\NO_RECOVERY :
                    $data['RECOVERY_MODE'];
                $recovery_attributes = ($recovery_is_ldap) ?
                    ['disabled' => 'disabled'] : [];
                $this->view->helper("options")->render("recovery-mode",
                    "RECOVERY_MODE", $data['RECOVERY_MODES'],
                    $recovery_selected, false, $recovery_attributes);
                /* A disabled select submits nothing, so under LDAP this
                   hidden field carries the off value in its place; when
                   the method is not LDAP it is disabled and the select
                   submits instead, so exactly one sends RECOVERY_MODE. */
                ?><input type="hidden" id="recovery-mode-off"
                    name="RECOVERY_MODE" value="<?= C\NO_RECOVERY ?>"<?=
                    ($recovery_is_ldap) ? '' : ' disabled="disabled"'
                    ?> ></div>
            </fieldset>
            </div>
            <div class="top-margin center"><button
                class="button-box" type="submit"><?=tl('security_element_save')
                ?></button>
            </div>
        </form>
        <script>
        window.onload = function()
        {
            initManagedCsvList("ldap-controller-list", "ldap-controller-add",
                "ldap-controller-add-button", "ldap-controllers",
                function(count) {
                    setClass("ldap-controllers-star", count > 0, "none");
                });
        }
        </script>
        </div>
        <?php
    }
}
X