output_content($response, $input['http_headers']); } else { return $this->output_content($response, array()); } } protected function output_headers($headers) { foreach ($headers as $name => $value) { Hm_Functions::header($name . ': ' . $value); } } protected function output_content($content, $headers = array()) { $this->output_headers($headers); return $content; } } class Tiki_Hm_Custom_Session extends Hm_Session { /** * check for an active session or an attempt to start one * @param object $request request object * @return bool */ public function check($request) { $this->active = session_status() == PHP_SESSION_ACTIVE; return $this->is_active(); } /** * Start the session. This could be an existing session or a new login * @param object $request request details * @return void */ public function start($request, $existing_session = false) { // Tiki handles this return; } /** * Call the configured authentication method to check user credentials * @param string $user username * @param string $pass password * @return bool true if the authentication was successful */ public function auth($user, $pass) { $userlib = TikiLib::lib('user'); list($isvalid, $user) = $userlib->validate_user($user, $pass); return $isvalid; } /** * Return a session value, or a user settings value stored in the session * @param string $name session value name to return * @param mixed $default value to return if $name is not found * @return mixed the value if found, otherwise $defaultHm_Auth */ public function get($name, $default = false, $user = false) { if ($user) { return array_key_exists($this->session_prefix(), $_SESSION) && array_key_exists('user_data', $_SESSION[$this->session_prefix()]) && array_key_exists($name, $_SESSION[$this->session_prefix()]['user_data']) ? $_SESSION[$this->session_prefix()]['user_data'][$name] : $default; } else { return array_key_exists($this->session_prefix(), $_SESSION) && array_key_exists($name, $_SESSION[$this->session_prefix()]) ? $_SESSION[$this->session_prefix()][$name] : $default; } } /** * Save a value in the session * @param string $name the name to save * @param string $value the value to save * @return void */ public function set($name, $value, $user = false) { if ($user) { $_SESSION[$this->session_prefix()]['user_data'][$name] = $value; } else { $_SESSION[$this->session_prefix()][$name] = $value; } } /** * Delete a value from the session * @param string $name name of value to delete * @return void */ public function del($name) { if (array_key_exists($this->session_prefix(), $_SESSION) && array_key_exists($name, $_SESSION[$this->session_prefix()])) { unset($_SESSION[$this->session_prefix()][$name]); } } /** * End a session after a page request is complete. This only closes the session and * does not destroy it * @return void */ public function end() { $this->active = false; return true; } /** * Destroy a session for good * @param object $request request details * @return void */ public function destroy($request) { if (function_exists('delete_uploaded_files')) { delete_uploaded_files($this); } unset($_SESSION[$this->session_prefix()]); $this->active = false; } /** * Dump current session contents * @return array */ public function dump() { if (array_key_exists($this->session_prefix(), $_SESSION)) { return $_SESSION[$this->session_prefix()]; } else { return []; } } public function close_early() { // noop; } /** * When Cypht runs in a wiki page as a wiki plugin and SEFURL is off * replace all Cypht links to include the page_id of the wiki page * so tiki-index can load the correct wiki page. Cypht reuses page param * for its internal uses. */ public function dedup_page_links($output) { global $prefs; if ($prefs['feature_sefurl'] === 'y') { return $output; } if (! $this->get('page_id')) { return $output; } $output = str_replace("?page=", "?page_id=" . $this->get('page_id') . "&page=", $output); $output = str_replace('get('page_id') . '\\">set('session_type', 'custom'); $this->set('session_class', 'Tiki_Hm_Custom_Session'); $this->set('session_prefix', $session_prefix); $this->set('auth_type', 'custom'); $this->set('output_class', 'Tiki_Hm_Output_HTTP'); $this->set('cookie_path', ini_get('session.cookie_path')); if ($user && (empty($_SESSION[$session_prefix]['user_data']) || count($_SESSION[$session_prefix]['user_data']) == 2)) { $user_config = new Tiki_Hm_User_Config($this); $user_config->load($user); $_SESSION[$session_prefix]['user_data'] = $user_config->dump(); } $this->settings_per_page = $settings_per_page; $output_modules = $this->get('output_modules'); $handler_modules = $this->get('handler_modules'); foreach ($output_modules as $page => $_) { unset($output_modules[$page]['header_start']); unset($output_modules[$page]['header_content']); unset($output_modules[$page]['header_end']); unset($output_modules[$page]['content_start']); unset($output_modules[$page]['content_end']); if (isset($output_modules[$page]['header_css'])) { unset($output_modules[$page]['header_css']); $headerlib->add_cssfile('lib/cypht/site.css'); $headerlib->add_cssfile('lib/cypht/modules/tiki/site.css'); } if (isset($output_modules[$page]['page_js'])) { unset($output_modules[$page]['page_js']); $headerlib->add_jsfile('lib/cypht/jquery.touch.js', true); $headerlib->add_jsfile('lib/cypht/site.js', true); } } // cleanup side menu unset($output_modules['ajax_hm_folders']['logout_menu_item']); unset($output_modules['ajax_hm_folders']['contacts_page_link']); unset($output_modules['ajax_hm_folders']['settings_save_link']); // show links according to permissions if (! Perms::get()->admin_personal_webmail && ! Perms::get()->admin_group_webmail) { unset($output_modules['ajax_hm_folders']['settings_servers_link']); unset($output_modules['ajax_hm_folders']['folders_page_link']); unset($output_modules['home']['welcome_dialog']); unset($handler_modules['ajax_imap_folder_expand']['add_folder_manage_link']); } foreach ($handler_modules as $page => $modules) { foreach ($modules as $module => $opts) { if ($module == 'http_headers') { $handler_modules[$page]['http_headers_tiki'] = ['tiki', true]; } } } $this->set('output_modules', $output_modules); $this->set('handler_modules', $handler_modules); if (empty($_SESSION[$session_prefix]['user_data']['timezone_setting'])) { $this->user_defaults['timezone_setting'] = TikiLib::lib('tiki')->get_display_timezone(); if (isset($_SESSION[$session_prefix]['user_data'])) { $_SESSION[$session_prefix]['user_data']['timezone_setting'] = $this->user_defaults['timezone_setting']; } } if (isset($_SESSION[$session_prefix]['user_data']['allow_external_images_setting'])) { $this->set('allow_external_image_sources', $_SESSION[$session_prefix]['user_data']['allow_external_images_setting']); } // handle oauth2 config $oauth2 = array( 'gmail' => array( 'client_id' => '', 'client_secret' => '', 'client_uri' => '', 'auth_uri' => '', 'token_uri' => '', 'refresh_uri' => '', ), 'outlook' => array( 'client_id' => '', 'client_secret' => '', 'client_uri' => '', 'auth_uri' => '', 'token_uri' => '', 'refresh_uri' => '', ),); if (isset($_SESSION[$session_prefix]['user_data']['tiki_enable_oauth2_over_imap_setting'])) { $this->set('tiki_enable_oauth2_over_imap', $_SESSION[$session_prefix]['user_data']['tiki_enable_oauth2_over_imap_setting']); } if (isset($_SESSION[$session_prefix]['user_data']['tiki_enable_gmail_contacts_module_setting'])) { $this->set('tiki_enable_gmail_contacts_module', $_SESSION[$session_prefix]['user_data']['tiki_enable_gmail_contacts_module_setting']); } if (isset($_SESSION[$session_prefix]['user_data']['gmail_client_id_setting'])) { $oauth2['gmail']['client_id'] = $_SESSION[$session_prefix]['user_data']['gmail_client_id_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['gmail_client_secret_setting'])) { $oauth2['gmail']['client_secret'] = $_SESSION[$session_prefix]['user_data']['gmail_client_secret_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['gmail_client_uri_setting'])) { $oauth2['gmail']['client_uri'] = $_SESSION[$session_prefix]['user_data']['gmail_client_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['gmail_auth_uri_setting'])) { $oauth2['gmail']['auth_uri'] = $_SESSION[$session_prefix]['user_data']['gmail_auth_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['gmail_token_uri_setting'])) { $oauth2['gmail']['token_uri'] = $_SESSION[$session_prefix]['user_data']['gmail_token_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['gmail_refresh_uri_setting'])) { $oauth2['gmail']['refresh_uri'] = $_SESSION[$session_prefix]['user_data']['gmail_refresh_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['outlook_client_id_setting'])) { $oauth2['outlook']['client_id'] = $_SESSION[$session_prefix]['user_data']['outlook_client_id_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['outlook_client_secret_setting'])) { $oauth2['outlook']['client_secret'] = $_SESSION[$session_prefix]['user_data']['outlook_client_secret_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['outlook_client_uri_setting'])) { $oauth2['outlook']['client_uri'] = $_SESSION[$session_prefix]['user_data']['outlook_client_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['outlook_auth_uri_setting'])) { $oauth2['outlook']['auth_uri'] = $_SESSION[$session_prefix]['user_data']['outlook_auth_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['outlook_token_uri_setting'])) { $oauth2['outlook']['token_uri'] = $_SESSION[$session_prefix]['user_data']['outlook_token_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['outlook_refresh_uri_setting'])) { $oauth2['outlook']['refresh_uri'] = $_SESSION[$session_prefix]['user_data']['outlook_refresh_uri_setting']; } if (isset($_SESSION[$session_prefix]['user_data']['tiki_enable_oauth2_over_imap_setting']) && $_SESSION[$session_prefix]['user_data']['tiki_enable_oauth2_over_imap_setting'] == 1) { $this->set('oauth2.ini', $oauth2); if (isset($_SESSION[$session_prefix]['user_data']['tiki_enable_gmail_contacts_module_setting']) && $_SESSION[$session_prefix]['user_data']['tiki_enable_gmail_contacts_module_setting'] == 1) { array_push($this->config['modules'], 'gmail_contacts'); $gmail_contact = array( 'load_gmail_contacts' => array( '0' => 'gmail_contacts', '1' => 1 ) ); array_push($this->config['handler_modules']['contacts'], $gmail_contact); } else { unset($this->config['modules']['gmail_contacts']); unset($this->config['handler_modules']['contacts']['load_gmail_contacts']); } } else { if (isset($this->config['oauth2.ini'])) { $this->del('oauth2.ini'); } } } } /** * Override user config handling in Cypht. * Store settings in Tiki user preferences and load them from there. * Ignore encryption and decryption of the settings due to missing password key when loading. */ class Tiki_Hm_User_Config extends Hm_Config { /* username */ private $username; private $site_config; /** * Load site configuration * @param object $config site config */ public function __construct($config) { $this->config = array_merge($this->config, $config->user_defaults); $this->site_config = $config; } /** * Load the settings for a user * @param string $username username * @param string $key key to decrypt the user data (not used) * @return void */ public function load($username, $key = null) { $this->username = $username; $session_prefix = $this->site_config->get('session_prefix'); if ($this->site_config->settings_per_page) { $data = $_SESSION[$session_prefix]['plugin_data'] ?? TikiLib::lib('tiki')->get_user_preference('%', $_SESSION[$session_prefix]['preference_name']); } else { $data = TikiLib::lib('tiki')->get_user_preference($username, $_SESSION[$session_prefix]['preference_name']); } if ($data) { $data = $this->decode($data); $this->config = array_merge($this->config, $data); $this->set_tz(); } // merge imap/smtp servers config with session as plugin cypht might be overriding these foreach (['imap_servers', 'smtp_servers'] as $key) { if (! empty($_SESSION[$session_prefix]['user_data'][$key])) { if (empty($this->config[$key])) { $this->config[$key] = []; } foreach ($_SESSION[$session_prefix]['user_data'][$key] as $server) { $found = false; foreach ($this->config[$key] as $cserver) { if ($server['server'] == $cserver['server'] && $server['tls'] == $cserver['tls'] && $server['port'] == $cserver['port'] && $server['user'] == $cserver['user']) { $found = true; break; } } if (! $found) { do { $id = uniqid(); } while (isset($this->config[$key][$id])); $this->config[$key][$id] = $server; } } } } } /** * Reload from outside input - done upon load_user_data handler executed in Cypht. * This loads user confirm from session but also saves to persistent storage * as Tiki-Cypht does not warn user about unsaved settings when logging out... * @param array $data new user data * @param string $username * @return void */ public function reload($data, $username = false) { $this->username = $username; $this->config = $data; $this->set_tz(); if ($username) { $temp_config = new Tiki_Hm_User_Config($this->site_config); $temp_config->load($username); $existing = $temp_config->dump(); ksort($existing); ksort($data); if (json_encode($existing) != json_encode($data)) { $this->save($username); } } } /** * Save user settings into Tiki * @param string $username username * @param string $key encryption key (not used) * @return void */ public function save($username = null, $key = null) { if ($this->get('skip_saving_on_set', false)) { return; } if (empty($username)) { $username = $this->username; } $this->shuffle(); $removed = $this->filter_servers(); ksort($this->config); $data = json_encode($this->config); if ($this->site_config->settings_per_page) { $original_plugin_data = $_SESSION[$this->site_config->get('session_prefix')]['plugin_data'] ?? ''; if ($original_plugin_data != $data) { $util = new Services_Edit_Utilities(); $util->replacePlugin(new JitFilter([ 'page' => $this->site_config->settings_per_page, 'message' => "Auto-saving Cypht settings.", 'type' => 'cypht', 'content' => $data, 'index' => 1 ]), false); } } else { TikiLib::lib('tiki')->set_user_preference($username, $_SESSION[$this->site_config->get('session_prefix')]['preference_name'], $data); } $this->restore_servers($removed); } /** * Set a config value * @param string $name config value name * @param string $value config value * @return void */ public function set($name, $value) { $this->config[$name] = $value; $this->save($this->username); } /** * Clear state variables in server list like 'object' and 'connected'. * Pass the rest of the cleanup to parent. */ public function filter_servers() { foreach ($this->config as $key => $vals) { if (in_array($key, ['pop3_servers', 'imap_servers', 'smtp_servers'])) { foreach ($vals as $index => $server) { $this->config[$key][$index]['object'] = false; $this->config[$key][$index]['connected'] = false; } } } return parent::filter_servers(); } }