1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8//this script may only be included - so its better to die if called directly. 9if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) { 10 header('location: index.php'); 11 exit; 12} 13 14/** 15 * Lib for user administration, groups and permissions. 16 */ 17 18// some definitions for helping with authentication 19define('USER_VALID', 2); 20 21define('SERVER_ERROR', -1); 22define('PASSWORD_INCORRECT', -3); 23define('USER_NOT_FOUND', -5); 24define('ACCOUNT_DISABLED', -6); 25define('ACCOUNT_WAITING_USER', -9); 26define('USER_AMBIGOUS', -7); 27define('USER_NOT_VALIDATED', -8); 28define('USER_PREVIOUSLY_VALIDATED', -10); 29define('USER_ALREADY_LOGGED', -11); 30define('EMAIL_AMBIGUOUS', -12); 31define('TWO_FA_INCORRECT', -13); 32 33//added for Auth v1.3 support 34define('AUTH_LOGIN_OK', 0); 35 36use PragmaRX\Google2FA\Google2FA; 37use Symfony\Component\Yaml\Yaml; 38use Symfony\Component\Yaml\Exception\ParseException; 39use Zend\Ldap\Exception\LdapException; 40use OneLogin\Saml2; 41 42class UsersLib extends TikiLib 43{ 44 // change this to an email address to receive debug emails from the LDAP code 45 public $debug = false; 46 47 public $usergroups_cache; 48 public $groupperm_cache; 49 public $groupinclude_cache; 50 public $userobjectperm_cache; // used to cache queries in object_has_one_permission() 51 public $get_object_permissions_for_user_cache; 52 static $cas_initialized = false; 53 static $userexists_cache = []; 54 55 56 57 58 function __construct() 59 { 60 parent::__construct(); 61 62 // Initialize caches 63 $this->usergroups_cache = []; 64 $this->groupperm_cache = [[]]; 65 $this->groupinclude_cache = []; 66 $this->get_object_permissions_for_user_cache = []; 67 } 68 69 70 function assign_object_permission($groupName, $objectId, $objectType, $permName) 71 { 72 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 73 74 $query = 'delete from `users_objectpermissions` where `objectId` = ? and `objectType`=?'; 75 $bindvars = [$objectId, $objectType]; 76 if (! empty($groupName)) { 77 $query .= ' and `groupName` = ?'; 78 $bindvars[] = $groupName; 79 } 80 if (! empty($permName)) { 81 $query .= ' and `permName` = ?'; 82 $bindvars[] = $permName; 83 } 84 $result = $this->query($query, $bindvars); 85 86 if (! empty($permName) && ! empty($groupName)) { 87 $query = 'insert into `users_objectpermissions`' . 88 ' (`groupName`, `objectId`, `objectType`, `permName`)' . 89 ' values(?, ?, ?, ?)'; 90 91 $result = $this->query($query, [$groupName, $objectId, $objectType, $permName]); 92 } 93 94 if ($objectType == 'file gallery') { 95 $cachelib = TikiLib::lib('cache'); 96 $cachelib->empty_type_cache('fgals_perms_' . $objectId . '_'); 97 } 98 return true; 99 } 100 101 function object_has_permission($user, $objectId, $objectType, $permName) 102 { 103 $groups = $this->get_user_groups($user); 104 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 105 $mid = implode(',', array_fill(0, count($groups), '?')); 106 $query = "select count(*) from `users_objectpermissions` where `groupName` in ($mid) and `objectId` = ? and `objectType` = ? and `permName` = ?"; 107 $bindvars = array_merge($groups, [$objectId, $objectType, $permName]); 108 $result = $this->getOne($query, $bindvars); 109 if ($result > 0) { 110 return true; 111 } else { 112 return false; 113 } 114 } 115 116 function remove_object_permission($groupName, $objectId, $objectType, $permName) 117 { 118 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 119 120 $query = 'delete from `users_objectpermissions`' . 121 ' where`objectId` = ? and `objectType` = ?'; 122 $bindvars = [$objectId, $objectType]; 123 if (! empty($groupName)) { 124 $query .= ' and `groupName` = ? '; 125 $bindvars[] = $groupName; 126 } 127 if (! empty($permName)) { 128 $query .= ' and `permName` = ? '; 129 $bindvars[] = $permName; 130 } 131 132 $result = $this->query($query, $bindvars); 133 134 if ($objectType == 'file gallery') { 135 $cachelib = TikiLib::lib('cache'); 136 $cachelib->empty_type_cache('fgals_perms_' . $objectId . '_'); 137 } 138 139 return true; 140 } 141 142 function copy_object_permissions($objectId, $destinationObjectId, $objectType) 143 { 144 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 145 146 $query = "select `permName`, `groupName` 147 from `users_objectpermissions` 148 where `objectId` =? and 149 `objectType` = ?"; 150 $bindvars = [$objectId, $objectType]; 151 $result = $this->query($query, $bindvars); 152 while ($res = $result->fetchRow()) { 153 $this->assign_object_permission($res["groupName"], $destinationObjectId, $objectType, $res["permName"]); 154 } 155 return true; 156 } 157 158 function get_object_permissions($objectId, $objectType, $group = '', $perm = '') 159 { 160 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 161 162 $query = "select `groupName`, `permName` 163 from `users_objectpermissions` 164 where `objectId` = ? and 165 `objectType` = ?"; 166 $bindvars = [$objectId, $objectType]; 167 if (! empty($group)) { 168 $query .= ' and `groupName`=?'; 169 $bindvars[] = $group; 170 } 171 if (! empty($perm)) { 172 $query .= ' and `permName`=?'; 173 $bindvars[] = $perm; 174 } 175 return $this->fetchAll($query, $bindvars); 176 } 177 178 function get_object_permissions_for_user($objectId, $objectType, $user) 179 { 180 $params = md5($objectId . $objectType . $user); 181 //Check the cache for these parameters 182 if (array_key_exists($params, $this->get_object_permissions_for_user_cache)) { 183 return $this->get_object_permissions_for_user_cache[$params]; 184 } 185 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 186 $bindvars = [$objectId, $objectType]; 187 $groups = $this->get_user_groups($user); 188 $bindvars = array_merge($bindvars, $groups); 189 190 $query = 'select `permName` ' . 191 ' from `users_objectpermissions`' . 192 ' where `objectId` = ? and `objectType` = ?' . 193 ' and `groupName` in (' . implode(',', array_fill(0, count($groups), '?')) . ')'; 194 195 $result = $this->query($query, $bindvars); 196 $ret = []; 197 198 while ($res = $result->fetchRow()) { 199 $ret[] = $res['permName']; 200 } 201 202 //Cache the result for this set of parameters 203 $this->get_object_permissions_for_user_cache[$params] = $ret; 204 return $ret; 205 } 206 207 function object_has_one_permission($objectId, $objectType) 208 { 209 $objectId = md5($objectType . TikiLib::strtolower($objectId)); 210 211 if (! isset($this->userobjectperm_cache) || ! is_array($this->userobjectperm_cache) 212 || ! isset($this->userobjectperm_cache[$objectId])) { 213 // i think, we really dont need the "and `objectType`=?" because the objectId should be unique due to the md5() 214 $query = 'select count(*) from `users_objectpermissions` where `objectId`=? and `objectType`=?'; 215 $this->userobjectperm_cache[$objectId] = $this->getOne($query, [$objectId, $objectType]); 216 } 217 218 return $this->userobjectperm_cache[$objectId]; 219 } 220 221 function user_exists($user) 222 { 223 if (! isset($userexists_cache[$user])) { 224 $query = 'select count(*) from `users_users` where upper(`login`) = ?'; 225 $result = $this->getOne($query, [TikiLib::strtoupper($user)]); 226 $userexists_cache[$user] = $result; 227 } 228 return $userexists_cache[$user]; 229 } 230 function user_exists_by_email($email) 231 { 232 if (! isset($userexists_cache[$email])) { 233 $query = 'select count(*) from `users_users` where upper(`email`) = ?'; 234 $result = $this->getOne($query, [TikiLib::strtoupper($email)]); 235 $userexists_cache[$email] = $result; 236 } 237 return $userexists_cache[$email]; 238 } 239 function get_user_real_case($user) 240 { 241 $query = 'select `login` from `users_users` where upper(`login`) = ?'; 242 return $this->getOne($query, [TikiLib::strtoupper($user)]); 243 } 244 245 function group_exists($group) 246 { 247 return in_array($group, $this->list_all_groups()); 248 } 249 250 /** 251 * @param string $user : username 252 * @param bool $remote_logout : logged out remotely (so do not redirect) 253 * @param string $redir : url to redirect to. Uses home page according to prefs if empty 254 * @return void : redirects to suitable homepage or redir param if not remote 255 */ 256 function user_logout($user, $remote_logout = false, $redir = '') 257 { 258 global $prefs, $user_cookie_site; 259 260 $logslib = TikiLib::lib('logs'); 261 $logslib->add_log('login', 'logged out'); 262 263 $userInfo = $this->get_user_info($user); 264 if ($prefs['login_multiple_forbidden'] === 'y') { 265 $this->delete_user_cookie($userInfo['userId']); 266 } else { 267 $secret = explode('.', $_COOKIE[$user_cookie_site]); 268 $this->delete_user_cookie($userInfo['userId'], $secret[0]); 269 } 270 271 if ($prefs['feature_intertiki'] == 'y' and $prefs['feature_intertiki_sharedcookie'] == 'y' and ! empty($prefs['feature_intertiki_mymaster'])) { 272 $remote = $prefs['interlist'][$prefs['feature_intertiki_mymaster']]; 273 $remote['path'] = preg_replace('/^\/?/', '/', $remote['path']); 274 $client = new XML_RPC_Client($remote['path'], $remote['host'], $remote['port']); 275 $client->setDebug(0); 276 $msg = new XML_RPC_Message( 277 'intertiki.logout', 278 [ 279 new XML_RPC_Value($prefs['tiki_key'], 'string'), 280 new XML_RPC_Value($user, 'string') 281 ] 282 ); 283 $client->send($msg); 284 } 285 286 // more local cleanup originally from tiki-logout.php 287 288 // go offline in Live Support 289 if ($prefs['feature_live_support'] == 'y') { 290 $access = TikiLib::lib('access'); 291 global $lslib; 292 include_once('lib/live_support/lslib.php'); 293 if ($lslib->get_operator_status($user) != 'offline') { 294 $lslib->set_operator_status($user, 'offline'); 295 } 296 } 297 298 if ($prefs['auth_method'] === 'saml' && $prefs['saml_options_slo'] == 'y') { 299 $saml_instance = $this->get_saml_auth(); 300 if (isset($saml_instance)) { 301 $nameId = null; 302 $sessionIndex = null; 303 if (isset($_SESSION['saml_nameid'])) { 304 $nameId = $_SESSION['saml_nameid']; 305 } 306 if (isset($_SESSION['saml_sessionindex'])) { 307 $sessionIndex = $_SESSION['saml_sessionindex']; 308 } 309 $saml_instance->logout(null, [], $nameId, $sessionIndex); 310 } 311 } 312 313 setcookie($user_cookie_site, '', -3600, $prefs['feature_intertiki_sharedcookie'] == 'y' ? '/' : $prefs['cookie_path'], $prefs['cookie_domain']); 314 315 /* change group home page or deactivate if no page is set */ 316 if (! empty($redir)) { 317 $url = $redir; 318 } elseif (($groupHome = $this->get_group_home('Anonymous')) != '') { 319 $url = (preg_match('/^(\/|https?:)/', $groupHome)) ? $groupHome : 'tiki-index.php?page=' . $groupHome; 320 } else { 321 $url = $prefs['site_tikiIndex']; 322 } 323 // RFC 2616 defines that the 'Location' HTTP headerconsists of an absolute URI 324 if (! preg_match('/^https?\:/i', $url)) { 325 global $url_scheme, $url_host, $url_port, $base_url; 326 $url = (preg_match('#^/#', $url) ? $url_scheme . '://' . $url_host . (($url_port != '') ? ":$url_port" : '') : $base_url) . $url; 327 } 328 if (SID) { 329 $url .= '?' . SID; 330 } 331 332 if ($prefs['auth_method'] === 'cas' && $user !== 'admin' && $user !== '' && $prefs['cas_force_logout'] === 'y') { 333 phpCAS::logoutWithRedirectService($url); 334 } 335 unset($_SESSION['cas_validation_time']); 336 unset($_SESSION[$user_cookie_site]); 337 session_unset(); 338 session_destroy(); 339 340 if ($remote_logout) { 341 return; 342 } 343 344 if ($prefs['auth_method'] === 'ws') { 345 header('Location: ' . str_replace('//', '//admin:@', $url)); // simulate a fake login to logout the user 346 } else { 347 header('Location: ' . $url); 348 } 349 350 return; 351 } 352 353 /** 354 * @see TikiLib::genPass() 355 * TODO: Merge with the above 356 */ 357 static function genPass() 358 { 359 // AWC: enable mixed case and digits, don't return too short password 360 global $prefs; 361 362 $vocales = 'AaEeIiOoUu13580'; 363 $consonantes = 'BbCcDdFfGgHhJjKkLlMmNnPpQqRrSsTtVvWwXxYyZz24679'; 364 $r = ''; 365 $passlen = ($prefs['min_pass_length'] > 5) ? $prefs['min_pass_length'] : 5; 366 367 for ($i = 0; $i < $passlen; $i++) { 368 if ($i % 2) { 369 $r .= $vocales{rand(0, strlen($vocales) - 1)}; 370 } else { 371 $r .= $consonantes{rand(0, strlen($consonantes) - 1)}; 372 } 373 } 374 375 return $r; 376 } 377 378 /** 379 * Force a logout for the specified user 380 * @param $user 381 */ 382 function force_logout($user) 383 { 384 if (! empty($user)) { 385 // Clear the timestamp for the existing session, 386 // which will force a logout next time the user accesses the session 387 $this->query('delete from `tiki_sessions` where `user`=?', [$user]); 388 389 // Add a log entry 390 $logslib = TikiLib::lib('logs'); 391 $logslib->add_log("login", "logged out", $user, '', '', $this->now); 392 } 393 } 394 395 // For each auth method, validate user in auth, if valid, verify tiki user exists and create if necessary (as configured) 396 // Once complete, update_lastlogin and return result, username and login message. 397 function validate_user($user, $pass, $validate_phase = false, $twoFactorCode = null) 398 { 399 global $prefs; 400 401 $user = str_replace(chr(0), '', $user); 402 $pass = str_replace(chr(0), '', $pass); 403 404 if ($user != 'admin' && $prefs['feature_intertiki'] == 'y' && ! empty($prefs['feature_intertiki_mymaster'])) { 405 // slave intertiki sites should never check passwords locally, just for admin 406 return false; 407 } 408 409 // these will help us keep tabs of what is going on 410 $userTiki = false; 411 $userTikiPresent = false; 412 $userLdap = false; 413 $userLdapPresent = false; 414 415 // read basic pam options 416 $auth_pam = ($prefs['auth_method'] == 'pam'); 417 $pam_create_tiki = ($prefs['pam_create_user_tiki'] == 'y'); 418 $pam_skip_admin = ($prefs['pam_skip_admin'] == 'y'); 419 420 // read basic LDAP options 421 $auth_ldap = ($prefs['auth_method'] == 'ldap'); 422 $ldap_create_tiki = ($prefs['ldap_create_user_tiki'] == 'y'); 423 $create_auth = ($prefs['ldap_create_user_ldap'] == 'y'); 424 $skip_admin = ($prefs['ldap_skip_admin'] == 'y'); 425 426 // read basic cas options 427 $auth_cas = ($prefs['auth_method'] == 'cas'); 428 $cas_create_tiki = ($prefs['cas_create_user_tiki'] == 'y'); 429 $cas_skip_admin = ($prefs['cas_skip_admin'] == 'y'); 430 431 // read basic phpbb options 432 $auth_phpbb = ($prefs['auth_method'] == 'phpbb'); 433 $phpbb_create_tiki = ($prefs['auth_phpbb_create_tiki'] == 'y'); 434 $phpbb_skip_admin = ($prefs['auth_phpbb_skip_admin'] == 'y'); 435 $phpbb_disable_tikionly = ($prefs['auth_phpbb_disable_tikionly'] == 'y'); 436 437 // see if we are to use Shibboleth 438 $auth_shib = ($prefs['auth_method'] == 'shib'); 439 $shib_create_tiki = ($prefs['shib_create_user_tiki'] == 'y'); 440 $shib_skip_admin = ($prefs['shib_skip_admin'] == 'y'); 441 442 // see if we are to use SAML 443 $auth_saml = ($prefs['auth_method'] == 'saml'); 444 $saml_create_tiki = (isset($prefs['saml_options_autocreates']) && $prefs['saml_options_autocreates'] == 'y'); 445 $saml_skip_admin = (isset($prefs['saml_options_skip_admin']) && $prefs['saml_options_skip_admin'] == 'y'); 446 447 // first attempt a login via the standard Tiki system 448 // 449 if (! ($auth_shib || $auth_cas || $auth_saml) || $user == 'admin') { //redflo: does this mean, that users in cas and shib are not replicated to tiki tables? Does this work well? 450 list($result, $user) = $this->validate_user_tiki($user, $pass, $validate_phase); 451 } else { 452 $result = null; 453 } 454 455 // If preference login_multiple_forbidden is set, don't let user login if already logged in 456 if ($result == USER_VALID && $prefs['login_multiple_forbidden'] == 'y' && $user != 'admin') { 457 $tikilib = TikiLib::lib('tiki'); 458 $grabSessionOnAlreadyLoggedIn = ! empty($prefs['login_grab_session']) ? $prefs['login_grab_session'] : 'n'; 459 if ($grabSessionOnAlreadyLoggedIn === 'y') { 460 // Log out first, then proceed to log in again 461 $this->force_logout($user); 462 } else { 463 $tikilib->update_session(); 464 if ($tikilib->is_user_online($user)) { 465 $result = USER_ALREADY_LOGGED; 466 } 467 } 468 } 469 470 switch ($result) { 471 case USER_VALID: 472 $userTiki = true; 473 $userTikiPresent = true; 474 break; 475 476 case USER_ALREADY_LOGGED: 477 $userTikiPresent = true; 478 break; 479 480 case PASSWORD_INCORRECT: 481 $userTikiPresent = true; 482 break; 483 } 484 485 // if we aren't using LDAP this will be quick 486 // if we are using tiki auth or if we're using an alternative auth except for admin 487 488 // todo: bad hack. better search for a more general solution here 489 if ((! $auth_ldap && ! $auth_pam && ! $auth_cas && ! $auth_shib&& ! $auth_saml && ! $auth_phpbb) 490 || ( 491 ( ($auth_ldap && $skip_admin) 492 || ($auth_shib && $shib_skip_admin) 493 || ($auth_saml && $saml_skip_admin) 494 || ($auth_pam && $pam_skip_admin) 495 || ($auth_cas && $cas_skip_admin) 496 || ($auth_phpbb && $phpbb_skip_admin) 497 ) 498 && $user == 'admin') 499 || ($auth_ldap && ($prefs['auth_ldap_permit_tiki_users'] == 'y' && $userTiki)) 500 ) { 501 // if the user verified ok, log them in 502 if ($userTiki) {//user validated in tiki, update lastlogin and be done 503 if ($auth_ldap) { 504 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result, 'tiki']; 505 } 506 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 507 // if the user password was incorrect but the account was there, give an error 508 } elseif ($userTikiPresent) { //user ixists in tiki but bad password 509 return [false, $user, $result]; 510 } // if the user was not found, give an error 511 // this could be for future uses 512 else { 513 return [false, $user, $result]; 514 } 515 516 // For the alternate auth methods, attempt to validate user 517 // return back one of two conditions 518 // Valid User or Bad password 519 // next see if we need to check PAM 520 } elseif ($auth_pam) { 521 $result = $this->validate_user_pam($user, $pass); 522 switch ($result) { 523 case USER_VALID: 524 $userPAM = true; 525 break; 526 527 case PASSWORD_INCORRECT: 528 $userPAM = false; 529 break; 530 } 531 532 // start off easy 533 // if the user verified in Tiki and PAM, log in 534 if ($userPAM && $userTiki) { 535 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 536 } elseif (! $userTikiPresent && ! $userPAM) { // if the user wasn't found in either system, just fail 537 return [false, $user, $result]; 538 } elseif ($userPAM && ! $userTikiPresent) { // if the user was logged into PAM but not found in Tiki 539 // see if we can create a new account 540 if ($pam_create_tiki) { 541 // need to make this better! ********************************************************* 542 $result = $this->add_user($user, $pass, ''); 543 544 // if it worked ok, just log in 545 if ($result == USER_VALID) { 546 // before we log in, update the login counter 547 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 548 // if the server didn't work, do something! 549 } elseif ($result == SERVER_ERROR) { 550 // check the notification status for this type of error 551 return [false, $user, $result]; 552 } else { 553 // otherwise don't log in. 554 return [false, $user, $result]; 555 } 556 } else { 557 // otherwise 558 // just say no! 559 return [false, $user, $result]; 560 } 561 } // if the user was logged into PAM and found in Tiki (no password in Tiki user table necessary) 562 elseif ($userPAM && $userTikiPresent) { 563 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 564 } 565 } elseif ($auth_cas) { 566 // next see if we need to check CAS 567 $result = $this->validate_user_cas($user); 568 569 switch ($result) { 570 case USER_VALID: 571 $userCAS = true; 572 break; 573 574 case PASSWORD_INCORRECT: 575 $userCAS = false; 576 break; 577 } 578 579 if ($this->user_exists($user)) { 580 $userTikiPresent = true; 581 } else { 582 $userTikiPresent = false; 583 } 584 585 // start off easy 586 // if the user verified in Tiki and by CAS, log in 587 if ($userCAS && $userTikiPresent) { 588 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 589 } elseif (! $userCAS) { 590 // if the user wasn't authenticated through CAS, just fail 591 return [false, $user, $result]; 592 } elseif ($userCAS && ! $userTikiPresent) { 593 // if the user was authenticated by CAS but not found in Tiki 594 595 // see if we can create a new account 596 if ($cas_create_tiki) { 597 // need to make this better! ********************************************************* 598 $randompass = $this->genPass(); 599 // in case CAS auth is turned off accidentally; 600 // we don't want ppl to be able to login as any user with blank passwords 601 $result = $this->add_user($user, $randompass, ''); 602 603 // if it worked ok, just log in 604 if ($result == USER_VALID) { 605 // before we log in, update the login counter 606 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 607 // if the server didn't work, do something! 608 } elseif ($result == SERVER_ERROR) { 609 // check the notification status for this type of error 610 return [false, $user, $result]; 611 } else { 612 // otherwise don't log in. 613 return [false, $user, $result]; 614 } 615 } else { 616 // otherwise 617 // just say no! 618 return [false, $user, $result]; 619 } 620 } // if the user was authenticated by CAS and found in Tiki (no password in Tiki user table necessary) 621 elseif ($userCAS && $userTikiPresent) { 622 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 623 } 624 } elseif ($auth_shib) { 625 // next see if we need to check Shibboleth 626 627 if ($this->user_exists($user)) { 628 $userTikiPresent = true; 629 } else { 630 $userTikiPresent = false; 631 } 632 633 // Shibboleth login was not successful 634 if (! isset($_SERVER['HTTP_SHIB_IDENTITY_PROVIDER'])) { 635 return false; 636 } 637 638 // Collect the shibboleth related attributes. 639 $shibmail = $_SERVER['HTTP_MAIL']; 640 $shibaffiliation = $_SERVER['HTTP_SHIB_EP_UNSCOPEDAFFILIATION']; 641 $shibproviderid = $_SERVER['HTTP_SHIB_IDENTITY_PROVIDER']; 642 643 // Get the affiliation information to log in 644 $shibaffiliarray = preg_split('/;/', TikiLib::strtoupper($shibaffiliation)); 645 $validaffiliarray = preg_split('/,/', TikiLib::strtoupper($prefs['shib_affiliation'])); 646 $validafil = false; 647 648 foreach ($shibaffiliarray as $affil) { 649 if (in_array($affil, $validaffiliarray)) { 650 $validafil = true; 651 } 652 } 653 654 // start off easy 655 // if the user verified in Tiki and by Shibboleth, log in 656 if ($userTikiPresent && $validafil) { 657 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, USER_VALID]; 658 } else { 659 $smarty = TikiLib::lib('smarty'); 660 // see if we can create a new account 661 if ($shib_create_tiki) { 662 if (! (strlen($user) > 0 and strlen($shibmail) > 0 and strlen($shibaffiliation) > 0)) { 663 $errmsg = 'User registration error: You do not have the required shibboleth attributes ('; 664 665 if (strlen($user) == 0) { 666 $errmsg = $errmsg . 'User '; 667 } 668 669 if (strlen($shibmail) == 0) { 670 $errmsg = $errmsg . 'Mail '; 671 } 672 673 if (strlen($shibaffiliation) == 0) { 674 $errmsg = $errmsg . 'Affiliation '; 675 } 676 677 $errmsg = $errmsg . '). For further information on this error goto the ((ShibReg)) Page'; 678 679 $smarty->assign('msg', $errmsg); 680 $smarty->display('error.tpl'); 681 exit; 682 } else { 683 if ($validafil) { 684 // Create the user 685 // need to make this better! ********************************************************* 686 $randompass = $this->genPass(); 687 // in case Shibboleth auth is turned off accidentally; 688 // we don't want ppl to be able to login as any user with blank passwords 689 690 $result = $this->add_user($user, $randompass, $shibmail); 691 692 // if it worked ok, just log in 693 if ($result == USER_VALID) { 694 // Add to the default Group 695 if ($prefs['shib_usegroup'] == 'y') { 696 $result = $this->assign_user_to_group($user, $prefs['shib_group']); 697 } 698 699 // before we log in, update the login counter 700 return [$this->_ldap_sync_and_update_lastlogin($user, $randompass), $user, $result]; 701 } elseif ($result == SERVER_ERROR) { 702 // if the server didn't work, do something! 703 704 // check the notification status for this type of error 705 return [false, $user, $result]; 706 } else { 707 // otherwise don't log in. 708 return [false, $user, $result]; 709 } 710 } else { 711 $vaffils = ''; 712 foreach ($validaffiliarray as $vaffil) { 713 $vaffils = $vaffils . $vaffil . ", "; 714 } 715 $vaffils = rtrim($vaffils, ", "); 716 $errmsg = '<H1 style="text-align: center;">User login error</H1>' . 717 '<BR/><BR/>You must have one of the following affiliations to get into this wiki.<BR/><BR/>' . 718 '<B>' . $vaffils . '</B><BR><BR/><BR/>' . 719 'For further information on this error goto the <a href="./tiki-index.php?page=ShibReg">Shibreg</a> Page'; 720 721 $smarty->assign('msg', $errmsg); 722 $smarty->display('error.tpl'); 723 exit; 724 } 725 } 726 } else { 727 $smarty->assign('msg', 'The user [ ' . $user . ' ] is not registered with this wiki.'); 728 $smarty->display('error.tpl'); 729 exit; 730 } 731 } 732 } elseif ($auth_saml) { 733 // next see if we need to check SAML 734 if (isset($_SESSION['samlUserdata']) && ! empty($_SESSION['samlUserdata']) || 735 isset($_SESSION['samlNameId']) && ! empty($_SESSION['samlNameId']) 736 ) { 737 $saml_username = $saml_email = ''; 738 $saml_groups = []; 739 740 if (empty($_SESSION['samlUserdata'])) { 741 $saml_username = $_SESSION['samlNameId']; 742 $saml_email = $saml_username; 743 } else { 744 $usernameMapping = isset($prefs['saml_attrmap_username']) ? $prefs['saml_attrmap_username'] : ''; 745 $emailMapping = isset($prefs['saml_attrmap_mail']) ? $prefs['saml_attrmap_mail'] : ''; 746 $groupMapping = isset($prefs['saml_attrmap_group']) ? $prefs['saml_attrmap_group'] : ''; 747 748 if (! empty($usernameMapping) && isset($_SESSION['samlUserdata'][$usernameMapping]) && ! empty($_SESSION['samlUserdata'][$usernameMapping][0])) { 749 $saml_username = $_SESSION['samlUserdata'][$usernameMapping][0]; 750 } 751 752 if (! empty($emailMapping) && isset($_SESSION['samlUserdata'][$emailMapping]) && ! empty($_SESSION['samlUserdata'][$usernameMapping][0])) { 753 $saml_email = $_SESSION['samlUserdata'][$emailMapping][0]; 754 } 755 756 if (! empty($groupMapping) && isset($_SESSION['samlUserdata'][$groupMapping]) && ! empty($_SESSION['samlUserdata'][$groupMapping])) { 757 $group_values = $_SESSION['samlUserdata'][$groupMapping]; 758 759 foreach ($group_values as $group_value) { 760 if (isset($prefs['saml_groupmap_admins']) && ! empty($prefs['saml_groupmap_admins'])) { 761 if (strcasecmp($prefs['saml_groupmap_admins'], $group_value) == 0) { 762 $saml_groups[] = "Admins"; 763 } 764 } 765 if (isset($prefs['saml_groupmap_registered']) && ! empty($prefs['saml_groupmap_registered'])) { 766 if (strcasecmp($prefs['saml_groupmap_registered'], $group_value) == 0) { 767 $saml_groups[] = "Registered"; 768 } 769 } 770 } 771 } 772 773 // Code SAML Custom role here 774 } 775 776 $matcher = isset($prefs['saml_option_account_matcher']) ? $prefs['saml_option_account_matcher'] : 'email'; 777 778 if ($matcher == 'email') { 779 if (empty($saml_email)) { 780 Feedback::error(tra("The email could not be retrieved from the IdP and is required")); 781 return [false, $username, SERVER_ERROR]; 782 } else { 783 $username = $this->get_user_by_email($saml_email); 784 if ($this->user_exists($username)) { 785 $userTikiPresent = true; 786 } else { 787 $userTikiPresent = false; 788 if (! isset($prefs['saml_options_autocreate']) || $prefs['saml_options_autocreate'] != 'y') { 789 Feedback::error(tr('The user [ %0 ] is not registered with this wiki and autocreate is disabled.', $saml_email)); 790 return [false, $username, USER_NOT_FOUND]; 791 } 792 } 793 } 794 } else { 795 if (empty($saml_username)) { 796 Feedback::error(tra("The username could not be retrieved from the IdP and is required")); 797 return [false, $username, SERVER_ERROR]; 798 } else { 799 $username = $saml_username; 800 if ($this->user_exists($saml_username)) { 801 $userTikiPresent = true; 802 } else { 803 $userTikiPresent = false; 804 805 if (! isset($prefs['saml_options_autocreate']) || $prefs['saml_options_autocreate'] != 'y') { 806 Feedback::error(tr('The user [ %0 ] is not registered with this wiki and autocreate is disabled.', $saml_username)); 807 return [false, $username, USER_NOT_FOUND]; 808 } 809 } 810 } 811 } 812 813 if (empty($username)) { 814 $username = $saml_username; 815 } 816 817 $cookie_site = preg_replace("/[^a-zA-Z0-9]/", "", $prefs['cookie_name']); 818 $user_cookie_site = 'tiki-user-' . $cookie_site; 819 $_SESSION["$user_cookie_site"] = $username; 820 821 $randompass = $this->genPass(); 822 if (! $userTikiPresent) { 823 // Create user 824 if (empty($saml_groups)) { 825 if (isset($prefs['saml_option_default_group']) && ! empty($prefs['saml_option_default_group'])) { 826 $saml_groups[] = $prefs['saml_option_default_group']; 827 } 828 } 829 830 $result = $this->add_user($username, $randompass, $saml_email, '', false, null, null, null, $saml_groups); 831 832 if (! $result) { 833 Feedback::error(tr('The user [ %0|%1 ] is not registered with this wiki and the creation process failed.', $username, $saml_email)); 834 return [false, $username, SERVER_ERROR]; 835 } 836 837 // if it worked ok, just log in 838 if ($result == USER_VALID) { 839 // before we log in, update the login counter 840 return [$this->update_lastlogin($username), $username, $result]; 841 } elseif ($result == SERVER_ERROR) { 842 // check the notification status for this type of error 843 return [false, $username, $result]; 844 } else { 845 // otherwise don't log in. 846 return [false, $username, $result]; 847 } 848 } else { 849 // Update user 850 if ($username != 'admin') { // Prevent change groups of the admin account 851 if (isset($prefs['saml_options_sync_group']) && $prefs['saml_options_sync_group'] == 'y') { 852 if (! empty($saml_groups)) { 853 $this->assign_user_to_groups($username, $saml_groups); 854 } 855 } 856 } 857 return [$this->update_lastlogin($username), $username, USER_VALID]; 858 } 859 } 860 } elseif ($auth_ldap) { 861 // next see if we need to check LDAP 862 // check the user account 863 $result = $this->validate_user_ldap($user, $pass); 864 865 switch ($result) { 866 case USER_VALID: 867 $userLdap = true; 868 $userLdapPresent = true; 869 break; 870 871 case PASSWORD_INCORRECT: 872 $userLdapPresent = true; 873 break; 874 } 875 876 // start off easy 877 // if the user is in Tiki and password is verified in LDAP, log in 878 if ($userLdap && $userTikiPresent) { 879 if ($userLdapPresent) { 880 # Sync again user attributes from LDAP (such as the RealName, mail and country) with user data in Tiki to prevent un-sync'ing them in a later stage 881 $this->init_ldap($user, $pass); 882 $this->ldap_sync_user_data($user, $this->ldap->get_user_attributes()); 883 } 884 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 885 } elseif (! $userTikiPresent && ! $userLdapPresent) { 886 // if the user wasn't found in either system, just fail 887 888 return [false, $user, $result]; 889 } elseif ($userTiki && ! $userLdapPresent) { 890 // if the user was logged into Tiki but not found in LDAP 891 892 // see if we can create a new account 893 if ($create_auth) { 894 // need to make this better! ********************************************************* 895 $result = $this->create_user_ldap($user, $pass); 896 897 // if it worked ok, just log in 898 if ($result == USER_VALID) { 899 // before we log in, update the login counter 900 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 901 } // if the server didn't work, do something! 902 elseif ($result == SERVER_ERROR) { 903 // check the notification status for this type of error 904 return [false, $user, $result]; 905 } // otherwise don't log in. 906 else { 907 return [false, $user, $result]; 908 } 909 } else { 910 // otherwise 911 // just say no! 912 return [false, $user, $result]; 913 } 914 } elseif ($userLdap && ! $userTikiPresent) { 915 // if the user was logged into Auth but not found in Tiki 916 // see if we are allowed to create a new account 917 if ($ldap_create_tiki) { 918 $ldap_user_attr = $this->ldap->get_user_attributes(); 919 // Get user attributes such as the real name, email and country from the data received by the ldap auth 920 $this->ldap_sync_user_data($user, $ldap_user_attr); 921 // Use what was configured in ldap admin config, otherwise assume the attribute name is "mail" as is usual 922 $email = $ldap_user_attr[empty($prefs['auth_ldap_emailattr']) ? 'mail' : $prefs['auth_ldap_emailattr']]; 923 $result = $this->add_user($user, $pass, $email); 924 $this->disable_tiki_auth($user); //disable that user's password in tiki - since we use ldap 925 926 // if it worked ok, just log in 927 if ($result == $user) { 928 // before we log in, update the login counter 929 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 930 } elseif ($result == SERVER_ERROR) { 931 // if the server didn't work, do something! 932 // check the notification status for this type of error 933 return [false, $user, $result]; 934 } else { // otherwise don't log in. 935 return [false, $user, $result]; 936 } 937 } else { // otherwise 938 // just say no! 939 return [false, $user, $result]; 940 } 941 } // if the user was logged into Auth and found in Tiki (no password in Tiki user table necessary) 942 elseif ($userLdap && $userTikiPresent) { 943 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 944 } 945 } elseif ($auth_phpbb) { 946 $result = $this->validate_user_phpbb($user, $pass); 947 948 switch ($result) { 949 case USER_VALID: 950 $userPhpbb = true; 951 break; 952 953 case PASSWORD_INCORRECT: 954 $userPhpbb = false; 955 break; 956 } 957 958 // start off easy 959 // if the user verified in Tiki and phpBB, log in 960 if ($userPhpbb && $userTiki) { 961 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 962 } elseif (! $userTikiPresent && ! $userPhpbb) { 963 // if the user wasn't found in either system, just fail 964 return [false, $user, USER_UNKNOWN]; 965 } elseif ($userPhpbb && ! $userTikiPresent) { 966 // if the user was logged into phpBB but not found in Tiki 967 968 // see if we can create a new account 969 if ($phpbb_create_tiki) { 970 // get the user email and then add the user to Tiki 971 $the_email = $this->phpbbauth->grabEmail($user); 972 $result = $this->add_user($user, $pass, $the_email); 973 974 // if it worked ok, just log in 975 if ($result == USER_VALID) { 976 // before we log in, update the login counter 977 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 978 } // if the server didn't work, do something! 979 elseif ($result == SERVER_ERROR) { 980 // check the notification status for this type of error 981 return [false, $user, $result]; 982 } // otherwise don't log in. 983 else { 984 return [false, $user, $result]; 985 } 986 } else { // otherwise 987 // just say no! 988 return [false, $user, $result]; 989 } 990 } elseif ($userTikiPresent && ! $userPhpbb) { 991 // if the user was found in Tiki, but not found in phpBB, we should probably disable the user 992 if ($phpbb_disable_tikionly) { 993 // would probably be better do flag the user as not active? How do you do that? 994 // and it also would be better to check if the user is active first.. :) 995 $this->invalidate_account($user); 996 $logslib = TikiLib::lib('logs'); 997 $logslib->add_log('auth_phpbb', 'NOTICE: Invalidated user ' . $user . ' due to missing phpBB account.'); 998 } 999 return [false, $user, ACCOUNT_DISABLED]; 1000 } // if the user was logged into phpBB and found in Tiki (no password in Tiki user table necessary) 1001 elseif ($userPhpbb && $userTikiPresent) { 1002 return [$this->_ldap_sync_and_update_lastlogin($user, $pass), $user, $result]; 1003 } 1004 } 1005 1006 // we will never get here 1007 return [false, $user, $result]; 1008 } 1009 1010 // validate the user through PAM 1011 function validate_user_pam($user, $pass) 1012 { 1013 global $prefs; 1014 $tikilib = TikiLib::lib('tiki'); 1015 1016 // just make sure we're supposed to be here 1017 if ($prefs['auth_method'] != 'pam') { 1018 return false; 1019 } 1020 1021 // Read page AuthPAM at tw.o, it says about a php module required. 1022 // maybe and if extension line could be added here... module requires $error 1023 // as reference. 1024 $error = ''; 1025 if (pam_auth($user, $pass, $error)) { 1026 return USER_VALID; 1027 } else { 1028 // Uncomment the following to see errors on that 1029 // error_log("TIKI ERROR PAM: $error User: $user Pass: $pass"); 1030 return PASSWORD_INCORRECT; 1031 } 1032 } 1033 1034 function check_cas_authentication($user_cookie_site) 1035 { 1036 global $prefs, $webdav_access; 1037 $tikilib = TikiLib::lib('tiki'); 1038 1039 // Avoid CAS authentication check if the client is not able to handle HTTP redirects to another domain. This includes: 1040 // - WebDAV requests 1041 // - Javascript/AJAX requests 1042 // 1043 if (( isset($webdav_access) && $webdav_access === true ) 1044 || ( isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) 1045 ) { 1046 return true; 1047 } 1048 1049 // just make sure we're supposed to be here 1050 if (! $this->_init_cas_client()) { 1051 return false; 1052 } 1053 1054 if (! empty($_SESSION['phpCAS']['user'])) { 1055 $_SESSION[$user_cookie_site] = strtolower($_SESSION['phpCAS']['user']); 1056 } 1057 1058 if (isset($_REQUEST['ticket']) && empty($_SESSION[$user_cookie_site])) { 1059 $cas_user = ''; 1060 $_SESSION['cas_is_validating'] = false; 1061 $this->validate_user_cas($cas_user, true); 1062 die(); 1063 } 1064 1065 // Check for CAS (re-)validation 1066 // Only if : 1067 // - using CAS auth method 1068 // - not calling tiki-login.php nor tiki-logout.php 1069 // - not using 'admin' user 1070 // - the request is not a POST ( which does not keep its params with CAS redirections ) 1071 // - either the CAS validation timed out or the validation process has not ended within 5 seconds which often means that the redirection to the CAS server failed 1072 // 1073 if (php_sapi_name() !== 'cli' 1074 && (isset($_SESSION[$user_cookie_site]) || $prefs['cas_autologin'] == 'y') 1075 && basename($_SERVER['SCRIPT_NAME']) != 'tiki-login.php' 1076 && basename($_SERVER['SCRIPT_NAME']) != 'tiki-logout.php' 1077 && (! isset($_SESSION[$user_cookie_site]) || $_SESSION[$user_cookie_site] != 'admin' ) 1078 && empty($_POST) 1079 && ( ( $prefs['cas_authentication_timeout'] && $tikilib->now - $_SESSION['cas_validation_time'] > $prefs['cas_authentication_timeout'] ) 1080 || ( isset($_SESSION['cas_is_validating']) && $_SESSION['cas_is_validating'] === true && $tikilib->now - $_SESSION['cas_validation_time'] > 5 ) ) 1081 ) { 1082 unset($_SESSION["$user_cookie_site"]); 1083 unset($_SESSION['phpCAS']['user']); 1084 1085 $_SESSION['cas_validation_time'] = $tikilib->now; 1086 $_SESSION['cas_is_validating'] = true; 1087 $cas_user = ''; 1088 1089 // phpCAS will always redirect to CAS validate URL 1090 $this->validate_user_cas($cas_user, true); 1091 1092 die(); 1093 } 1094 } 1095 1096 function _init_cas_client() 1097 { 1098 global $prefs; 1099 1100 // just make sure we're supposed to be here 1101 if ($prefs['auth_method'] != 'cas') { 1102 return false; 1103 } 1104 if (self::$cas_initialized === false) { 1105 // initialize phpCAS 1106 phpCAS::client($prefs['cas_version'], '' . $prefs['cas_hostname'], (int) $prefs['cas_port'], '' . $prefs['cas_path'], false); 1107 self::$cas_initialized = true; 1108 } 1109 1110 return true; 1111 } 1112 1113 // validate the user through CAS 1114 function validate_user_cas(&$user, $checkOnly = false) 1115 { 1116 global $prefs, $base_url; 1117 $tikilib = TikiLib::lib('tiki'); 1118 1119 // just make sure we're supposed to be here 1120 if (! $this->_init_cas_client()) { 1121 return false; 1122 } 1123 1124 // Redirect to this URL after authentication 1125 if (! empty($prefs['cas_extra_param']) && basename($_SERVER['SCRIPT_NAME']) == 'tiki-login.php') { 1126 phpCAS::setFixedServiceURL($base_url . 'tiki-login.php?cas=y&' . $prefs['cas_extra_param']); 1127 } 1128 1129 // check CAS authentication 1130 phpCAS::setNoCasServerValidation(); 1131 if ($checkOnly) { 1132 unset($_SESSION['phpCAS']['auth_checked']); 1133 $auth = phpCAS::checkAuthentication(); 1134 } else { 1135 $auth = phpCAS::forceAuthentication(); 1136 } 1137 $_SESSION['cas_validation_time'] = $tikilib->now; 1138 1139 // at this step, the user has been authenticated by the CAS server 1140 // and the user's login name can be read with phpCAS::getUser(). 1141 if ($auth && ($user = strtolower(phpCAS::getUser()))) { 1142 return USER_VALID; 1143 } else { 1144 $user = null; 1145 return PASSWORD_INCORRECT; 1146 } 1147 } 1148 1149 /** 1150 * Get php-saml auth object 1151 */ 1152 function check_saml_authentication($user_cookie_site) 1153 { 1154 global $prefs, $base_url; 1155 1156 if ($prefs['auth_method'] != 'saml'||! class_exists('\OneLogin\Saml2\Auth')) { 1157 return; 1158 } 1159 1160 $clicked_on_saml_link = false; 1161 1162 // Check endpoints 1163 if (array_key_exists('auth', $_REQUEST) && $_REQUEST['auth'] == 'saml') { 1164 $saml_instance = $this->get_saml_auth(); 1165 $saml_instance->login(); 1166 } elseif (array_key_exists('saml_metadata', $_REQUEST)) { 1167 $samlSettingsInfo = $this->get_saml_settings(); 1168 $saml_settings = new OneLogin_Saml2_Settings($samlSettingsInfo, true); 1169 $metadata = $saml_settings->getSPMetadata(); 1170 $errors = $saml_settings->validateMetadata($metadata); 1171 if (empty($errors)) { 1172 header('Content-Type: text/xml'); 1173 echo $metadata; 1174 exit(); 1175 } else { 1176 throw new OneLogin_Saml2_Error( 1177 'Invalid SP metadata: ' . implode(', ', $errors), 1178 OneLogin_Saml2_Error::METADATA_SP_INVALID 1179 ); 1180 } 1181 } elseif (array_key_exists('saml_acs', $_REQUEST)) { 1182 $clicked_on_saml_link = true; 1183 $saml_instance = $this->get_saml_auth(); 1184 try { 1185 $saml_instance->processResponse(); 1186 } catch (Exception $e) { 1187 Feedback::error($e->getMessage()); 1188 return; 1189 } 1190 $errors = $saml_instance->getErrors(); 1191 if (! empty($errors)) { 1192 Feedback::error(implode(', ', $errors)); 1193 return; 1194 } 1195 if (! $saml_instance->isAuthenticated()) { 1196 Feedback::error(tra("SAML Login failed. User not authenticated")); 1197 return; 1198 } 1199 1200 $_SESSION['samlUserdata'] = $saml_instance->getAttributes(); 1201 $_SESSION['samlNameId'] = $saml_instance->getNameId(); 1202 $_SESSION['samlSessionIndex'] = $saml_instance->getSessionIndex(); 1203/* 1204 if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) { 1205 $saml_instance->redirectTo($_POST['RelayState']); 1206 } 1207*/ 1208 } elseif (array_key_exists('saml_sls', $_REQUEST)) { 1209 $saml_instance = $this->get_saml_auth(); 1210 1211 try { 1212 $saml_instance->processSLO(false); 1213 } catch (Exception $e) { 1214 Feedback::error($e->getMessage()); 1215 return; 1216 } 1217 $errors = $saml_instance->getErrors(); 1218 if (! empty($errors)) { 1219 Feedback::error(implode(', ', $errors)); 1220 return; 1221 } else { 1222 unset($_SESSION['samlUserdata']); 1223 unset($_SESSION['samlNameId']); 1224 unset($_SESSION['samlSessionIndex']); 1225 } 1226 } 1227 1228 $already_logged_as_admin = isset($_SESSION["$user_cookie_site"]) && $_SESSION["$user_cookie_site"] == 'admin'; 1229 $force_saml_login = ! (isset($prefs['saml_options_skip_admin']) && $prefs['saml_options_skip_admin'] == 'y'); 1230 1231 if ($clicked_on_saml_link || ($force_saml_login && ! $already_logged_as_admin)) { 1232 $this->validate_user("", "", "", ""); 1233 } 1234 } 1235 1236 /** 1237 * Get php-saml auth object 1238 */ 1239 function get_saml_auth() 1240 { 1241 $samlSettingsInfo = $this->get_saml_settings(); 1242 1243 if (! class_exists('\OneLogin\Saml2\Auth')) { 1244 return; 1245 } 1246 1247 try { 1248 $auth = new Saml2\Auth($samlSettingsInfo); 1249 } catch (Exception $e) { 1250 print_r("There is a problem with the SAML settings, review them: " . $e->getMessage()); 1251 exit(); 1252 } 1253 1254 return $auth; 1255 } 1256 1257 /** 1258 * Build a settingsInfo array based on SAML settings store at Tiki 1259 */ 1260 function get_saml_settings() 1261 { 1262 global $prefs; 1263 global $base_url; 1264 1265 $samlSettingsInfo = [ 1266 'strict' => isset($prefs['saml_advanced_strict']) && $prefs['saml_advanced_strict'] == 'y' ? true : false, 1267 'debug' => isset($prefs['saml_advanced_debug']) && $prefs['saml_advanced_debug'] == 'y' ? true : false, 1268 'sp' => [ 1269 'entityId' => (! empty($prefs['saml_advanced_sp_entity_id']) ? $prefs['saml_advanced_sp_entity_id'] : 'php-saml'), 1270 'assertionConsumerService' => [ 1271 'url' => $base_url . 'tiki-login.php?saml_acs' 1272 ], 1273 'singleLogoutService' => [ 1274 'url' => $base_url . 'tiki-login.php?saml_sls' 1275 ], 1276 'NameIDFormat' => (! empty($prefs['saml_advanced_nameidformat']) ? $prefs['saml_advanced_nameidformat'] : 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified'), 1277 'x509cert' => isset($prefs['saml_advanced_sp_x509cert']) ? $prefs['saml_advanced_sp_x509cert'] : '', 1278 'privateKey' => isset($prefs['saml_advanced_sp_privatekey']) ? $prefs['saml_advanced_sp_privatekey'] : '', 1279 ], 1280 'idp' => [ 1281 'entityId' => isset($prefs['saml_idp_entityid']) ? $prefs['saml_idp_entityid'] : '', 1282 'singleSignOnService' => [ 1283 'url' => isset($prefs['saml_idp_sso']) ? $prefs['saml_idp_sso'] : '', 1284 ], 1285 'singleLogoutService' => [ 1286 'url' => isset($prefs['saml_idp_slo']) ? $prefs['saml_idp_slo'] : '', 1287 ], 1288 'x509cert' => isset($prefs['saml_idp_x509cert']) ? $prefs['saml_idp_x509cert'] : '', 1289 'lowercaseUrlencoding' => isset($prefs['saml_advanced_idp_lowercase_url_encoding']) && $prefs['saml_advanced_idp_lowercase_url_encoding'] == 'y' ? true : false, 1290 ], 1291 'security' => [ 1292 'signMetadata' => isset($prefs['saml_advanced_metadata_signed']) && $prefs['saml_advanced_metadata_signed'] == 'y' ? true : false, 1293 'nameIdEncrypted' => isset($prefs['saml_advanced_nameid_encrypted']) && $prefs['saml_advanced_nameid_encrypted'] == 'y' ? true : false, 1294 'authnRequestsSigned' => isset($prefs['saml_advanced_authn_request_signed']) && $prefs['saml_advanced_authn_request_signed'] == 'y' ? true : false, 1295 'logoutRequestSigned' => isset($prefs['saml_advanced_logout_request_signed']) && $prefs['saml_advanced_logout_request_signed'] == 'y' ? true : false, 1296 'logoutResponseSigned' => isset($prefs['saml_advanced_logout_response_signed']) && $prefs['saml_advanced_logout_response_signed'] == 'y' ? true : false, 1297 'wantMessagesSigned' => isset($prefs['saml_advanced_want_message_signed']) && $prefs['saml_advanced_want_message_signed'] == 'y' ? true : false, 1298 'wantAssertionsSigned' => isset($prefs['saml_advanced_want_assertion_signed']) && $prefs['saml_advanced_want_assertion_signed'] == 'y' ? true : false, 1299 'wantAssertionsEncrypted' => isset($prefs['saml_advanced_want_assertion_encrypted']) && $prefs['saml_advanced_want_assertion_encrypted'] == 'y' ? true : false, 1300 'requestedAuthnContext' => isset($prefs['saml_advanced_requestedauthncontext']) && $prefs['saml_advanced_requestedauthncontext'], 1301 'signatureAlgorithm' => isset($prefs['saml_advanced_sign_algorithm']) ? $prefs['saml_advanced_sign_algorithm'] : 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 1302 ] 1303 ]; 1304 return $samlSettingsInfo; 1305 } 1306 1307 1308 /** 1309 * Initiates the Tiki LDAP library. 1310 * 1311 * Passes it a set of options according to Tiki's preferences. 1312 * FIXME: a similar piece of code can be found at two other places in this file. 1313 */ 1314 function init_ldap($user, $pass) 1315 { 1316 global $prefs; 1317 if (! isset($this->ldap)) { 1318 require_once('auth/ldap.php'); 1319 $ldap_options = [ 1320 'host' => $prefs['auth_ldap_host'], 1321 'port' => $prefs['auth_ldap_port'], 1322 'useStartTls' => $prefs['auth_ldap_starttls'], 1323 'useSsl' => $prefs['auth_ldap_ssl'], 1324 'baseDn' => $prefs['auth_ldap_basedn'], 1325 'scope' => $prefs['auth_ldap_scope'], 1326 'bind_type' => $prefs['auth_ldap_type'], 1327 'username' => $user, 1328 'password' => $pass, 1329 'userdn' => $prefs['auth_ldap_userdn'], 1330 'useroc' => $prefs['auth_ldap_useroc'], 1331 'userattr' => $prefs['auth_ldap_userattr'], 1332 'fullnameattr' => $prefs['auth_ldap_nameattr'], 1333 'emailattr' => $prefs['auth_ldap_emailattr'], 1334 'countryattr' => $prefs['auth_ldap_countryattr'], 1335 'groupdn' => $prefs['auth_ldap_groupdn'], 1336 'groupattr' => $prefs['auth_ldap_groupattr'], 1337 'groupoc' => $prefs['auth_ldap_groupoc'], 1338 'groupnameattr' => $prefs['auth_ldap_groupnameatr'], 1339 'groupdescattr' => $prefs['auth_ldap_groupdescatr'], 1340 'groupmemberattr' => $prefs['auth_ldap_memberattr'], 1341 'groupmemberisdn' => $prefs['auth_ldap_memberisdn'], 1342 'usergroupattr' => $prefs['auth_ldap_usergroupattr'], 1343 'groupgroupattr' => $prefs['auth_ldap_groupgroupattr'], 1344 'debug' => $prefs['auth_ldap_debug'] 1345 ]; 1346 // print_r($ldap_options); 1347 $this->ldap = new TikiLdapLib($ldap_options); 1348 } 1349 } 1350 1351 /** 1352 * Validates the user via LDAP and gets a LDAP connection 1353 * 1354 * @param user: username 1355 * @param pass: password 1356 */ 1357 function validate_user_ldap($user, $pass) 1358 { 1359 if (! $pass) { // An LDAP password cannot be empty. Treat specially so that Tiki does *NOT* unintentionally request an unauthenticated bind. 1360 return PASSWORD_INCORRECT; 1361 } 1362 1363 global $prefs; 1364 $logslib = TikiLib::lib('logs'); 1365 1366 if ($prefs['auth_ldap_debug'] == 'y') { 1367 $logslib->add_log('ldap', 'UserLib::validate_user_ldap()'); 1368 } 1369 1370 // First connection on the ldap server in anonymous, now we can search the real name of the $user 1371 // It's required to pass in param the username & password because the username is used to determine the realname (dn) 1372 $this->init_ldap($user, $pass); 1373 1374 $err = $this->ldap->bind(); 1375 1376 // Change the default bind_type to use the full, call get_user_attributes function to use the realname (dn) in the credentials test 1377 $this->ldap->setOption('bind_type', 'full'); 1378 $this->ldap->get_user_attributes(); 1379 1380 // Credentials test! To test it we force the reconnection. 1381 $err = $this->ldap->bind(true); 1382 1383 switch ($err) { 1384 case LdapException::LDAP_INVALID_CREDENTIALS: 1385 return PASSWORD_INCORRECT; 1386 1387 case LdapException::LDAP_INVALID_SYNTAX: 1388 case LdapException::LDAP_NO_SUCH_OBJECT: 1389 case LdapException::LDAP_INVALID_DN_SYNTAX: 1390 return USER_NOT_FOUND; 1391 1392 case LdapException::LDAP_SUCCESS: 1393 if ($prefs['auth_ldap_debug'] == 'y') { 1394 $logslib->add_log('ldap', 'Bind successful.'); 1395 } 1396 return USER_VALID; 1397 1398 default: 1399 return SERVER_ERROR; 1400 } 1401 1402 // this should never happen 1403 die('Assertion failed ' . __FILE__ . ':' . __LINE__); 1404 } 1405 1406 // validate the user from a phpBB database 1407 function validate_user_phpbb($user, $pass) 1408 { 1409 require_once('auth/phpbb.php'); 1410 $this->phpbbauth = new TikiPhpBBLib(); 1411 1412 switch ($this->phpbbauth->check($user, $pass)) { 1413 case PHPBB_INVALID_CREDENTIALS: 1414 return PASSWORD_INCORRECT; 1415 break; 1416 1417 case PHPBB_INVALID_SYNTAX: 1418 case PHPBB_NO_SUCH_USER: 1419 return USER_NOT_FOUND; 1420 break; 1421 1422 case PHPBB_SUCCESS: 1423 //$logslib->add_log('phpbb','PhpBB user validation successful.'); 1424 return USER_VALID; 1425 break; 1426 1427 default: 1428 return SERVER_ERROR; 1429 } 1430 // this should never happen 1431 die('Assertion failed ' . __FILE__ . ':' . __LINE__); 1432 } 1433 1434 /** 1435 * Help function to disable a user's password. 1436 * 1437 * Used, whenever the user password shall not be 1438 * hold in the tiki db but in LDAP or somewhere else. 1439 */ 1440 function disable_tiki_auth($user) 1441 { 1442 global $tiki, $prefs; 1443 1444 if ($prefs['auth_ldap_debug'] == 'y') { 1445 TikiLib::lib('logs')->add_log('ldap', 'UserLib::disable_tiki_auth()'); 1446 } 1447 $query = 'update `users_users` set `hash`=? where binary `login` = ?'; 1448 $result = $this->query($query, ['', $user]); 1449 } 1450 1451 /** 1452 * Synchronizes all existing Tiki users to what is in the LDAP directory. 1453 * 1454 * Retrieves all users info from LDAP. 1455 * Creates the corresponding Tiki users from this data. 1456 */ 1457 public function ldap_sync_all_users() 1458 { 1459 global $prefs; 1460 $logslib = TikiLib::lib('logs'); 1461 1462 if ($prefs['syncUsersWithDirectory'] != 'y') { 1463 return false; 1464 } 1465 1466 require_once('auth/ldap.php'); 1467 if ($prefs['auth_ldap_debug'] == 'y') { 1468 $logslib->add_log('ldap', 'UsersLib::ldap_sync_all_users(): Syncing all Tiki users to LDAP'); 1469 } 1470 1471 $bind_type = 'default'; 1472 1473 switch ($prefs['auth_ldap_type']) { // Must be anonymous or admin 1474 case 'default': 1475 break; 1476 1477 default: 1478 if (! empty($prefs['auth_ldap_adminuser'])) { 1479 $bind_type = 'explicit'; 1480 break; 1481 } 1482 return false; 1483 break; 1484 } 1485 1486 // FIXME: Similar to the contents of the init_ldap method: 1487 $ldap_options = [ 1488 'host' => $prefs['auth_ldap_host'], 1489 'port' => $prefs['auth_ldap_port'], 1490 'useStartTls' => $prefs['auth_ldap_starttls'], 1491 'useSsl' => $prefs['auth_ldap_ssl'], 1492 'baseDn' => $prefs['auth_ldap_basedn'], 1493 'scope' => $prefs['auth_ldap_scope'], 1494 'bind_type' => $bind_type, 1495 'binddn' => $prefs['auth_ldap_adminuser'], 1496 'bindpw' => $prefs['auth_ldap_adminpass'], 1497 'userdn' => $prefs['auth_ldap_userdn'], 1498 'useroc' => $prefs['auth_ldap_useroc'], 1499 'userattr' => $prefs['auth_ldap_userattr'], 1500 'fullnameattr' => $prefs['auth_ldap_nameattr'], 1501 'emailattr' => $prefs['auth_ldap_emailattr'], 1502 'countryattr' => $prefs['auth_ldap_countryattr'], 1503 'groupdn' => $prefs['auth_ldap_groupdn'], 1504 'groupattr' => $prefs['auth_ldap_groupattr'], 1505 'groupoc' => $prefs['auth_ldap_groupoc'], 1506 'groupnameattr' => $prefs['auth_ldap_groupnameatr'], 1507 'groupdescattr' => $prefs['auth_ldap_groupdescatr'], 1508 'groupmemberattr' => $prefs['auth_ldap_memberattr'], 1509 'groupmemberisdn' => $prefs['auth_ldap_memberisdn'], 1510 'usergroupattr' => $prefs['auth_ldap_usergroupattr'], 1511 'groupgroupattr' => $prefs['auth_ldap_groupgroupattr'], 1512 'debug' => $prefs['auth_ldap_debug'] 1513 ]; 1514 1515 $user_ldap = new TikiLdapLib($ldap_options); 1516 1517 // Retrieve all users from LDAP: 1518 if (! ($users_attributes = $user_ldap->get_all_users_attributes())) { 1519 return false; 1520 } 1521 1522 foreach ($users_attributes as $user_attributes) { 1523 $user = $user_attributes[$prefs['auth_ldap_userattr']]; 1524 $this->add_user($user, '', $user); 1525 1526 if ($prefs['auth_method'] == 'ldap') { 1527 $this->disable_tiki_auth($user); 1528 } 1529 1530 $this->ldap_sync_user_data($user, $user_attributes); 1531 } 1532 } 1533 1534 /** 1535 * Synchronize all groups with LDAP directory 1536 * 1537 * For each user, makes sure that user is member of the same groups as specified in their LDAP entry. 1538 */ 1539 public function ldap_sync_all_groups() 1540 { 1541 global $prefs; 1542 if ($prefs['auth_ldap_debug'] == 'y') { 1543 TikiLib::lib('logs')->add_log('ldap', 'UsersLib::ldap_sync_all_groups()'); 1544 } 1545 1546 if ($prefs['syncGroupsWithDirectory'] != 'y') { 1547 return false; 1548 } 1549 1550 $users = $this->list_all_users(); 1551 1552 foreach ($users as $user) { 1553 $this->_ldap_sync_groups($user, null); 1554 } 1555 } 1556 1557 /** 1558 * Updates the info about the current Tiki user with the info found in the LDAP directory. 1559 * 1560 * @see \UsersLib::disable_tiki_auth() 1561 * @see \UsersLib::ldap_sync_user_data() 1562 */ 1563 function ldap_sync_user($user, $pass) 1564 { 1565 if ($user == 'admin') { 1566 return true; 1567 } 1568 1569 global $prefs; 1570 $logslib = TikiLib::lib('logs'); 1571 $ret = true; 1572 $this->init_ldap($user, $pass); 1573 1574 if ($prefs['auth_ldap_debug'] == 'y') { 1575 $logslib->add_log('ldap', 'Syncing user with ldap'); 1576 } 1577 1578 // sync user information 1579 if ($prefs['auth_method'] == 'ldap') { 1580 $this->disable_tiki_auth($user); 1581 } 1582 1583 if ($prefs['syncUsersWithDirectory'] == 'y') { 1584 $this->ldap_sync_user_data($user, $this->ldap->get_user_attributes()); 1585 } 1586 1587 return $ret; 1588 } 1589 1590 /** 1591 * Sets Tiki user fields with the values found about a given user in LDAP. 1592 * 1593 * (name, email, country) 1594 * 1595 * @param user: username 1596 * @param attributes: Name and value for each LDAP attribute of the user. 1597 */ 1598 function ldap_sync_user_data($user, $attributes) 1599 { 1600 global $prefs; 1601 1602 if ($prefs['auth_ldap_debug'] == 'y') { 1603 TikiLib::lib('logs')->add_log('ldap', 'UsersLib::ldap_sync_user_data()'); 1604 } 1605 $u = ['login' => $user]; 1606 1607 $userPreferenceToLdapPreferenceMap = [ 1608 'realName' => 'auth_ldap_nameattr', 1609 'email' => 'auth_ldap_emailattr', 1610 'country' => 'auth_ldap_countryattr', 1611 ]; 1612 1613 foreach ($userPreferenceToLdapPreferenceMap as $preference => $ldapPreference) { 1614 if ($preference == 'email') { 1615 $userPreferenceValue = $this->get_user_email($user); 1616 } else { 1617 $userPreferenceValue = $this->get_user_preference($user, $preference); 1618 } 1619 $isSetLdapPreferenceValue = isset($attributes[$prefs[$ldapPreference]]); 1620 $ldapPreferenceValue = $isSetLdapPreferenceValue ? $attributes[$prefs[$ldapPreference]] : ''; 1621 1622 if ($userPreferenceValue && empty($ldapPreferenceValue)) { 1623 $u[$preference] = ''; 1624 } else { 1625 if ($isSetLdapPreferenceValue) { 1626 // Ldap attributes can (by default) have multiple values, check if the current user preference is one of 1627 // the values of the attribute, in that case keep the same value 1628 if (is_array($ldapPreferenceValue) 1629 && $userPreferenceValue 1630 && in_array($userPreferenceValue, $ldapPreferenceValue) 1631 ) { 1632 $u[$preference] = $userPreferenceValue; 1633 continue; 1634 } 1635 if (is_array($ldapPreferenceValue)) { 1636 // Ldap attributes can (by default) have multiple values 1637 // so we always take the first from the list in case of a multi value field 1638 $ldapPreferenceValue = reset($ldapPreferenceValue); 1639 } 1640 if ($isSetLdapPreferenceValue) { 1641 $u[$preference] = $ldapPreferenceValue; 1642 } 1643 } 1644 } 1645 } 1646 1647 if (count($u) > 1) { 1648 $this->set_user_fields($u); 1649 } 1650 } 1651 1652 /** 1653 * For a given user, makes sure this user is member of all the groups they should be, 1654 * according to their entry in the LDAP directory. 1655 * 1656 * @param user: username 1657 * @param pass: password (might be null) 1658 */ 1659 private function _ldap_sync_groups($user, $pass) 1660 { 1661 if ($user == 'admin') { 1662 return true; 1663 } 1664 1665 global $prefs; 1666 $logslib = TikiLib::lib('logs'); 1667 static $ldap_group_options = []; 1668 static $ext_dir = null; 1669 $ret = true; 1670 1671 $this->init_ldap($user, $pass); 1672 $this->ldap->setOption('username', $user); 1673 $this->ldap->setOption('password', $pass); 1674 1675 if ($prefs['auth_ldap_debug'] == 'y') { 1676 $logslib->add_log('ldap', 'UsersLib::_ldap_sync_groups(): Syncing group with ldap'); 1677 } 1678 $userattributes = $this->ldap->get_user_attributes(true); 1679 1680 if ($prefs['syncGroupsWithDirectory'] == 'y' && $userattributes[$prefs['auth_ldap_group_corr_userattr']] != null) { 1681 // sync external group information of user 1682 $ldapgroups = []; 1683 1684 if ($prefs['auth_ldap_group_external'] == 'y') { 1685 // External directory for groups 1686 if (! isset($ext_dir)) { 1687 $ldap_group_options = [ 1688 'host' => $prefs['auth_ldap_group_host'], 1689 'port' => $prefs['auth_ldap_group_port'], 1690 'useStartTls' => $prefs['auth_ldap_group_starttls'], 1691 'useSsl' => $prefs['auth_ldap_group_ssl'], 1692 'baseDn' => $prefs['auth_ldap_group_basedn'], 1693 'scope' => $prefs['auth_ldap_group_scope'], 1694 'userdn' => $prefs['auth_ldap_group_userdn'], 1695 'useroc' => $prefs['auth_ldap_group_useroc'], 1696 'userattr' => $prefs['auth_ldap_group_userattr'], 1697 'username' => $userattributes[$prefs['auth_ldap_group_corr_userattr']], 1698 'groupdn' => $prefs['auth_ldap_groupdn'], 1699 'groupattr' => $prefs['auth_ldap_groupattr'], 1700 'groupoc' => $prefs['auth_ldap_groupoc'], 1701 'groupnameattr' => $prefs['auth_ldap_groupnameatr'], 1702 'groupdescattr' => $prefs['auth_ldap_groupdescatr'], 1703 'groupmemberattr' => $prefs['auth_ldap_memberattr'], 1704 'groupmemberisdn' => $prefs['auth_ldap_memberisdn'], 1705 'usergroupattr' => $prefs['auth_ldap_usergroupattr'], 1706 'groupgroupattr' => $prefs['auth_ldap_groupgroupattr'], 1707 'debug' => $prefs['auth_ldap_group_debug'] 1708 ]; 1709 1710 if (empty($prefs['auth_ldap_group_adminuser'])) { 1711 // Anonymous 1712 $ldap_group_options['bind_type'] = 'default'; 1713 } else { 1714 // Explicit 1715 $ldap_group_options['bind_type'] = 'explicit'; 1716 $ldap_group_options['binddn'] = $prefs['auth_ldap_group_adminuser']; 1717 $ldap_group_options['bindpw'] = $prefs['auth_ldap_group_adminpass']; 1718 } 1719 1720 $ext_dir = new TikiLdapLib($ldap_group_options); 1721 } 1722 1723 $ext_dir->setOption('username', $userattributes[$prefs['auth_ldap_group_corr_userattr']]); 1724 $ldapgroups = $ext_dir->get_groups(true); 1725 } else { 1726 if (! empty($prefs['auth_ldap_adminuser'])) { 1727 $this->ldap->setOption('bind_type', 'explicit'); 1728 $this->ldap->setOption('binddn', $prefs['auth_ldap_adminuser']); 1729 $this->ldap->setOption('bindpw', $prefs['auth_ldap_adminpass']); 1730 $this->ldap->bind(true); 1731 } 1732 1733 $ldapgroups = $this->ldap->get_groups(true); 1734 1735 if (! empty($prefs['auth_ldap_adminuser'])) { 1736 $this->ldap->setOption('bind_type', $prefs['auth_ldap_type']); 1737 $this->ldap->bind(true); 1738 } 1739 } 1740 1741 $this->_ldap_sync_group_data($user, $ldapgroups); 1742 } 1743 1744 return $ret; 1745 } 1746 1747 /** 1748 * Sync Tiki groups with LDAP groups data 1749 * 1750 * For each group, assigns the user to it if it is not already a member of it. 1751 * 1752 * Called from \UsersLib::_ldap_sync_groups() 1753 * 1754 * @param user: username 1755 * @param ldapgroups: list of LDAP group names 1756 */ 1757 private function _ldap_sync_group_data($user, $ldapgroups) 1758 { 1759 global $prefs; 1760 $logslib = TikiLib::lib('logs'); 1761 1762 if (! count($ldapgroups)) { 1763 return; 1764 } 1765 1766 $ldapgroups_simple = []; 1767 $tikigroups = $this->get_user_groups($user); 1768 foreach ($ldapgroups as $group) { 1769 $gname = $group[$prefs['auth_ldap_groupattr']]; 1770 $ldapgroups_simple[] = $gname; // needed later 1771 if ($this->group_exists($gname) && ! $this->group_is_external($gname)) { // group exists 1772 //check if we need to sync group information 1773 if (isset($group[$prefs['auth_ldap_groupdescattr']])) { 1774 $ginfo = $this->get_group_info($gname); 1775 if ($group[$prefs['auth_ldap_groupdescattr']] != $ginfo['groupDesc']) { 1776 $this->set_group_description($gname, $group[$prefs['auth_ldap_groupdescattr']]); 1777 } 1778 } 1779 } elseif (! $this->group_exists($gname)) { // create group 1780 if (isset($group[$prefs['auth_ldap_groupdescattr']])) { 1781 $gdesc = $group[$prefs['auth_ldap_groupdescattr']]; 1782 } else { 1783 $gdesc = ''; 1784 } 1785 $logslib->add_log('ldap', 'Creating external group ' . $gname); 1786 $this->add_group($gname, $gdesc, '', 0, 0, '', '', 0, '', 0, 0, 'y'); 1787 } 1788 1789 // add user 1790 if (! in_array($gname, $tikigroups)) { 1791 $logslib->add_log('ldap', 'Adding user ' . $user . ' to external group ' . $gname); 1792 $this->assign_user_to_group($user, $gname); 1793 } 1794 } 1795 1796 // now clean up group membership if user has been unassigned from a group in ldap 1797 $extgroups = $this->get_user_external_groups($user); 1798 foreach ($extgroups as $eg) { 1799 if (! in_array($eg, $ldapgroups_simple)) { 1800 $logslib->add_log('ldap', 'Removing user ' . $user . ' from external group ' . $eg); 1801 $this->remove_user_from_group($user, $eg); 1802 } 1803 } 1804 } 1805 1806 /** 1807 * Update infos for a user, and which groups it is in, reading from LDAP. 1808 * 1809 * Called after a user has been created or logged from LDAP. 1810 * 1811 * @param user: username 1812 * @param pass: password 1813 * @see \UserLib::_ldap_sync_user() 1814 * @see \UserLib::_ldap_sync_groups() 1815 */ 1816 function _ldap_sync_user_and_groups($user, $pass) 1817 { 1818 global $prefs; 1819 1820 if ($prefs['auth_ldap_debug'] == 'y') { 1821 TikiLib::lib('logs')->add_log('ldap', 'UsersLib::_ldap_sync_user_and_groups()'); 1822 } 1823 1824 $ret = true; 1825 $ret &= $this->ldap_sync_user($user, $pass); 1826 $ret &= $this->_ldap_sync_groups($user, $pass); 1827 1828 // Invalidate cache 1829 $cachelib = TikiLib::lib('cache'); 1830 $cacheKey = 'user_details_' . $user; 1831 $cachelib->invalidate($cacheKey); 1832 1833 return($ret); 1834 } 1835 1836 function set_group_description($group, $description) 1837 { 1838 $query = 'update `users_groups` set `groupDesc`=? where `groupName`=?'; 1839 $result = $this->query($query, [$description, $group]); 1840 } 1841 1842 function group_is_external($group) 1843 { 1844 $gi = $this->get_group_info($group); 1845 if ($gi['isExternal'] == 'y') { 1846 return true; 1847 } 1848 return false; 1849 } 1850 1851 // simple function - no group inclusion or intertiki 1852 function get_user_external_groups($user) 1853 { 1854 $userid = $this->get_user_id($user); 1855 $query = 'select u.`groupName`' . 1856 ' from `users_usergroups` u, `users_groups` g' . 1857 ' where u.`groupName`=g.`groupName` and u.`userId`=? and g.`isExternal`=?'; 1858 1859 $result = $this->query($query, [(int) $userid, 'y']); 1860 $ret = []; 1861 1862 while ($res = $result->fetchRow()) { 1863 $ret[] = $res['groupName']; 1864 } 1865 1866 return $ret; 1867 } 1868 1869 /** 1870 * Validate the user in the Tiki database 1871 1872 * @param user: username 1873 * @param pass: password 1874 */ 1875 function validate_user_tiki($user, $pass, $validate_phase = false) 1876 { 1877 global $prefs; 1878 1879 $userUpper = TikiLib::strtoupper($user); 1880 // first verify that the user exists 1881 $query = 'select `userId`,`login`,`waiting`, `hash`, `email`,`valid` from `users_users` where upper(`login`) = ?'; 1882 $result = $this->query($query, [$userUpper]); 1883 1884 1885 switch ($result->numRows()) { 1886 case 0: 1887 if ($prefs['login_allow_email'] == 'y') { //if no users found, check check if email is being used to login 1888 $query = 'select `userId`,`login`,`waiting`, `hash`, `email`,`valid` from `users_users` where upper(`email`) = ?'; 1889 $result = $this->query($query, [$userUpper]); 1890 if ($result->numRows() > 1) { 1891 return [EMAIL_AMBIGUOUS, $user]; // if there is more than one user with that email 1892 } elseif ($result->numRows() == 1) { 1893 break; // if there is only one user, exit switch 1894 } 1895 } 1896 return [USER_NOT_FOUND, $user]; 1897 1898 case 1: 1899 break; 1900 1901 default: 1902 return [USER_AMBIGOUS, $user]; 1903 } 1904 1905 1906 1907 $res = $result->fetchRow(); 1908 $user = $res['login']; 1909 1910 // check for account flags 1911 if ($res['waiting'] === 'u') { // if account is in validation mode. 1912 if (!empty($pass) && $pass === $res['valid']) { // if user successfully provides code from email 1913 return [USER_VALID, $user]; 1914 } else { 1915 return [ACCOUNT_WAITING_USER, $user]; // if code validation fails, (or user tries to log in before verifying) 1916 } 1917 } elseif ($res['waiting'] === 'a') { // if account needs administrator validation 1918 if (!empty($res['valid']) && $pass === $res['valid']) { // if admin successfully validates account 1919 return [USER_VALID, $user]; 1920 } else { 1921 return [ACCOUNT_DISABLED, $user]; 1922 } 1923 } 1924 1925 if ($validate_phase) { 1926 return [USER_PREVIOUSLY_VALIDATED, $user]; // if email verification code is used an a validated account, deny. 1927 } 1928 1929 1930 // next verify the password with every hashes methods 1931 1932 1933 if ($res['hash'][0] == '$') { // if password was created by crypt (old tiki hash) or password_hash (current tiki hash) 1934 if (password_verify($pass, $res['hash'])) { 1935 if (password_needs_rehash($res['hash'], PASSWORD_DEFAULT)) { 1936 $this->set_user_password($res['userId'], $pass); //if its a old hash style, rehash it in a more secure way 1937 } 1938 return [USER_VALID, $user]; 1939 } else { 1940 return [PASSWORD_INCORRECT, $user]; // if the password was incorrect, dont give the md5's a spin 1941 } 1942 } 1943 1944 if (! empty($pass) && $res['hash'] === md5($pass)) { // very method md5(pass), for compatibility 1945 $this->set_user_password($res['userId'], $pass); 1946 return [USER_VALID, $user]; 1947 } 1948 if (! empty($pass) && $res['hash'] === md5($user . $pass)) { // ancient method md5(user.pass), for compatibility 1949 $this->set_user_password($res['userId'], $pass); 1950 return [USER_VALID, $user]; 1951 } 1952 if (! empty($pass) && $res['hash'] === md5($user . $pass . trim($res['email']))) { // very ancient method md5(user.pass.email), for compatibility 1953 $this->set_user_password($res['userId'], $pass); 1954 return [USER_VALID, $user]; 1955 } 1956 1957 return [PASSWORD_INCORRECT, $user]; 1958 } 1959 1960 1961 /** 1962 * Stores a users password in the database 1963 * 1964 * @param userId: the id of the user. 1965 * @param pass: the clear text password to be hashed and stored 1966 */ 1967 private function set_user_password($userId, $pass) 1968 { 1969 1970 $hash = password_hash($pass, PASSWORD_DEFAULT); 1971 $query = 'update `users_users` set `hash`=? where `userId`=?'; 1972 $result = $this->query($query, [$hash, $userId]); 1973 1974 //todo: a little error checking would be nice. 1975 } 1976 1977 /** 1978 * Synchronizes Tiki user and group info from LDAP. 1979 * 1980 * @param user: User name. 1981 * @param pass: Password. 1982 */ 1983 private function _ldap_sync_and_update_lastlogin($user, $pass) 1984 { 1985 global $prefs; 1986 global $tikilib; 1987 1988 if ($prefs['auth_ldap_debug'] == 'y') { 1989 TikiLib::lib('logs')->add_log('ldap', 'UsersLib::_ldap_sync_and_update_lastlogin()'); 1990 } 1991 1992 $ret = $this->update_lastlogin($user); 1993 1994 if (empty($current)) { 1995 // First time 1996 $current = 0; 1997 } 1998 1999 if ($prefs['auth_method'] === 'ldap' && ($prefs['syncGroupsWithDirectory'] == 'y' || $prefs['syncUsersWithDirectory'] == 'y' )) { 2000 $ret &= $this->_ldap_sync_user_and_groups($user, $pass); 2001 } 2002 2003 return $ret; 2004 } 2005 2006 /** 2007 * Updates date and time of current and last (previous) login. 2008 * 2009 * Called when the user logs in. 2010 * The updated fields are: currentLogin and lastLogin. 2011 * Resets unsuccessful_logins field. 2012 * 2013 * @param user: Username 2014 */ 2015 public function update_lastlogin($user) 2016 { 2017 $previous = $this->getOne('select `currentLogin` from `users_users` where `login`= ?', [$user]); 2018 if (is_null($previous)) { 2019 // First login 2020 $previous = $this->now; // TODO: Should we really set lastLogin on the first login? 2021 } 2022 2023 $query = 'update `users_users` set `lastLogin`=?, `currentLogin`=?, `unsuccessful_logins`=? where `login`=? and (`waiting` <> \'a\' OR `waiting` IS NULL)'; // don't update last login if waiting for admin 2024 $this->query( 2025 $query, 2026 [ 2027 (int)$previous, 2028 (int)$this->now, 2029 0, 2030 $user 2031 ] 2032 ); 2033 2034 return true; 2035 } 2036 2037 /** 2038 * Creates a new user in the LDAP directory 2039 * 2040 * @param user: username 2041 * @param pass: password 2042 */ 2043 function create_user_ldap($user, $pass) 2044 { 2045 // todo: no more pear::auth! all in pear::ldap2 2046 global $prefs; 2047 $tikilib = TikiLib::lib('tiki'); 2048 2049 $options = []; 2050 $options['url'] = $prefs['auth_ldap_url']; 2051 $options['host'] = $prefs['auth_ldap_host']; 2052 $options['port'] = $prefs['auth_ldap_port']; 2053 $options['scope'] = $prefs['auth_ldap_scope']; 2054 $options['baseDn'] = $prefs['auth_ldap_basedn']; 2055 $options['userdn'] = $prefs['auth_ldap_userdn']; 2056 $options['userattr'] = $prefs['auth_ldap_userattr']; 2057 $options['useroc'] = $prefs['auth_ldap_useroc']; 2058 $options['groupdn'] = $prefs['auth_ldap_groupdn']; 2059 $options['groupattr'] = $prefs['auth_ldap_groupattr']; 2060 $options['groupoc'] = $prefs['auth_ldap_groupoc']; 2061 $options['memberattr'] = $prefs['auth_ldap_memberattr']; 2062 $options['memberisdn'] = ($prefs['auth_ldap_memberisdn'] == 'y'); 2063 $options['binduser'] = $prefs['auth_ldap_adminuser']; 2064 $options['bindpw'] = $prefs['auth_ldap_adminpass']; 2065 2066 // set additional attributes here 2067 $userattr = []; 2068 $userattr['email'] = ( $prefs['login_is_email'] == 'y' ) 2069 ? $user 2070 : $this->getOne('select `email` from `users_users` where `login`=?', [$user]); 2071 2072 2073 // set the Auth options 2074 $a = new Auth('LDAP', $options); 2075 2076 // check if the login correct 2077 if ($a->addUser($user, $pass, $userattr) === true) { 2078 $status = USER_VALID; 2079 } else { 2080 // otherwise use the error status given back 2081 $status = $a->getStatus(); 2082 } 2083 2084 return $status; 2085 } 2086 2087 2088 /** 2089 * This is a lighter version of get_users_names designed for AJAX checking of userrealnames 2090 */ 2091 function get_users_light($offset = 0, $maxRecords = -1, $sort_mode = 'login_asc', $find = '', $group = '') 2092 { 2093 global $prefs, $tiki_p_list_users, $tiki_p_admin; 2094 2095 if ($tiki_p_list_users !== 'y' && $tiki_p_admin != 'y') { 2096 return []; 2097 } 2098 2099 $mid = ''; 2100 $bindvars = []; 2101 if (! empty($group)) { 2102 if (! is_array($group)) { 2103 $group = [$group]; 2104 } 2105 $mid = ', `users_usergroups` uug where uu.`userId`=uug.`userId` and uug.`groupName` in (' . 2106 implode(',', array_fill(0, count($group), '?')) . ')'; 2107 2108 $bindvars = $group; 2109 } 2110 if (! empty($find)) { 2111 $findesc = '%' . $find . '%'; 2112 if (empty($mid)) { 2113 $mid .= ' where uu.`login` like ?'; 2114 } else { 2115 $mid .= ' and uu.`login` like ?'; 2116 } 2117 $bindvars[] = $findesc; 2118 } 2119 2120 $query = "select uu.`login` from `users_users` uu $mid order by " . $this->convertSortMode($sort_mode); 2121 $result = $this->fetchAll($query, $bindvars, $maxRecords, $offset); 2122 2123 $ret = []; 2124 2125 foreach ($result as $res) { 2126 $ret[$res['login']] = $this->clean_user($res['login']); 2127 } 2128 2129 if (! empty($findesc) && $prefs['user_show_realnames'] == 'y') { 2130 $query = "select `user` from `tiki_user_preferences` where `prefName` = 'realName' and `value` like ?"; 2131 $result = $this->fetchAll($query, [$findesc], $maxRecords, $offset); 2132 foreach ($result as $res) { 2133 if (! isset($ret[$res['user']])) { 2134 $ret[$res['user']] = $this->clean_user($res['user']); 2135 } 2136 } 2137 } 2138 asort($ret); 2139 return($ret); 2140 } 2141 2142 function get_users_names($offset = 0, $maxRecords = -1, $sort_mode = 'login_asc', $find = '') 2143 { 2144 global $tiki_p_list_users, $tiki_p_admin; 2145 2146 if ($tiki_p_list_users !== 'y' && $tiki_p_admin != 'y') { 2147 return []; 2148 } 2149 2150 // This function gets an array of user login names. 2151 if (! empty($find)) { 2152 $findesc = '%' . $find . '%'; 2153 $mid = ' where `login` like ?'; 2154 $bindvars = [$findesc]; 2155 } else { 2156 $mid = ''; 2157 $bindvars = []; 2158 } 2159 2160 $query = "select `login` from `users_users` $mid order by " . $this->convertSortMode($sort_mode); 2161 $result = $this->query($query, $bindvars, $maxRecords, $offset); 2162 $ret = []; 2163 2164 while ($res = $result->fetchRow()) { 2165 $ret[] = $res['login']; 2166 } 2167 2168 return ($ret); 2169 } 2170 2171 function get_members($group) 2172 { 2173 $group_results = true; 2174 if (! is_array($group)) { 2175 $group = [$group]; 2176 $group_results = false; 2177 } elseif (count($group) == 0) { 2178 return []; 2179 } 2180 $users = $this->fetchAll('SELECT ug.groupName, u.login FROM `users_usergroups` ug INNER JOIN `users_users` u ON u.userId = ug.userId WHERE ug.groupName IN (' 2181 . implode(',', array_fill(0, count($group), '?')) . ')', $group); 2182 2183 if (! $group_results) { 2184 return array_map(function ($row) { 2185 return $row['login']; 2186 }, $users); 2187 } else { 2188 $grouped = []; 2189 foreach ($users as $row) { 2190 $grouped[$row['groupName']][] = $row['login']; 2191 } 2192 return $grouped; 2193 } 2194 } 2195 2196 function get_users( 2197 $offset = 0, 2198 $maxRecords = -1, 2199 $sort_mode = 'login_asc', 2200 $find = '', 2201 $initial = '', 2202 $inclusion = false, 2203 $group = '', 2204 $email = '', 2205 $notconfirmed = false, 2206 $notvalidated = false, 2207 $neverloggedin = false 2208 ) { 2209 2210 $hasPermission = function ($group) { 2211 $perms = Perms::get(['type' => 'group', 'object' => $group]); 2212 if (! $perms->group_view_members && ! $perms->list_users && ! $perms->admin_users) { 2213 return false; 2214 } 2215 2216 return true; 2217 }; 2218 2219 if (is_array($group)) { 2220 $group = array_filter($group, $hasPermission); 2221 2222 if (empty($group)) { 2223 return []; 2224 } 2225 } elseif (! $hasPermission($group)) { 2226 return []; 2227 } 2228 2229 $mid = ''; 2230 $bindvars = []; 2231 $mmid = ''; 2232 $mbindvars = []; 2233 // Return an array of users indicating name, email, last changed pages, versions, lastLogin 2234 2235 //TODO : recurse included groups 2236 if (! empty($group)) { 2237 if (! is_array($group)) { 2238 $group = [$group]; 2239 } 2240 $mid = ', `users_usergroups` uug where uu.`userId`=uug.`userId` and uug.`groupName` in (' . implode(',', array_fill(0, count($group), '?')) . ')'; 2241 $mmid = $mid; 2242 $bindvars = $group; 2243 $mbindvars = $bindvars; 2244 } 2245 if (! empty($email)) { 2246 $mid .= $mid == '' ? ' where' : ' and'; 2247 $mid .= ' uu.`email` like ?'; 2248 $mmid = $mid; 2249 $bindvars[] = '%' . $email . '%'; 2250 $mbindvars[] = '%' . $email . '%'; 2251 } 2252 2253 if (! empty($find)) { 2254 $mid .= $mid == '' ? ' where' : ' and'; 2255 $mid .= ' uu.`login` like ?'; 2256 $mmid = $mid; 2257 $bindvars[] = '%' . $find . '%'; 2258 $mbindvars[] = '%' . $find . '%'; 2259 } 2260 2261 if (! empty($initial)) { 2262 $mid = ' where `login` like ?'; 2263 $mmid = $mid; 2264 $bindvars = [$initial . '%']; 2265 $mbindvars = $bindvars; 2266 } 2267 2268 if ($notconfirmed && $notvalidated) { 2269 $mid .= $mid == '' ? ' where' : ' and'; 2270 $mid .= ' (uu.`waiting` = \'u\' or uu.`waiting` = \'a\')'; 2271 $mmid = $mid; 2272 } else { 2273 if ($notconfirmed) { 2274 $mid .= $mid == '' ? ' where' : ' and'; 2275 $mid .= ' uu.`waiting` = \'u\''; 2276 $mmid = $mid; 2277 } 2278 2279 if ($notvalidated) { 2280 $mid .= $mid == '' ? ' where' : ' and'; 2281 $mid .= ' uu.`waiting` = \'a\''; 2282 $mmid = $mid; 2283 } 2284 } 2285 2286 if ($neverloggedin) { 2287 $mid .= $mid == '' ? ' where' : ' and'; 2288 $mid .= ' (uu.`lastLogin` is null or uu.`lastLogin` = 0)'; 2289 $mmid = $mid; 2290 } 2291 $query = "select uu.* from `users_users` uu $mid order by " . $this->convertSortMode($sort_mode); 2292 $query_cant = "select count(*) from `users_users` uu $mmid"; 2293 $ret = $this->fetchAll($query, $bindvars, $maxRecords, $offset); 2294 $cant = $this->getOne($query_cant, $mbindvars); 2295 2296 foreach ($ret as &$res) { 2297 if (! $perms->admin_users) { 2298 // Filter out sensitive data 2299 unset($res['email']); 2300 unset($res['hash']); 2301 unset($res['provpass']); 2302 } 2303 2304 $res['user'] = $res['login']; 2305 $user = $res['user']; 2306 2307 if ($inclusion) { 2308 $groups = $this->get_user_groups_inclusion($user); 2309 } else { 2310 $groups = $this->get_user_groups($user); 2311 } 2312 2313 $res['groups'] = $groups; 2314 $res['age'] = $this->now - $res['registrationDate']; 2315 $res['user_information'] = $this->get_user_preference($user, 'user_information', 'public'); 2316 $res['editable'] = $this->user_can_be_edited($user); 2317 } 2318 2319 $retval = []; 2320 $retval['data'] = $ret; 2321 $retval['cant'] = $cant; 2322 return $retval; 2323 } 2324 2325 /** 2326 * @param string $edited_user : username (login) of the user that might be edited 2327 * @param string $editing_user : username of user doing the editing (or logged-in user if omitted) 2328 * @return bool : true if $editing_user can edit $edited_user 2329 */ 2330 function user_can_be_edited($edited_user, $editing_user = '') 2331 { 2332 global $user; 2333 2334 if (empty($editing_user)) { 2335 $editing_user = $user; 2336 } 2337 2338 $editable = false; 2339 if ($this->user_has_permission($editing_user, 'tiki_p_admin')) { 2340 $editable = true; 2341 } elseif ($this->user_has_permission($editing_user, 'tiki_p_admin_users') && ! $this->user_has_permission($edited_user, 'tiki_p_admin')) { 2342 $editable = true; 2343 } 2344 return $editable; 2345 } 2346 2347 function group_inclusion($group, $include) 2348 { 2349 $query = 'insert into `tiki_group_inclusion`(`groupName`,`includeGroup`) values(?,?)'; 2350 $result = $this->query($query, [$group, $include]); 2351 } 2352 2353 function get_included_container_groups($group, $recur = true) 2354 { 2355 $includedGroups = $this->get_included_groups($group, $recur); 2356 $groups = $this->get_group_info($includedGroups); 2357 return array_filter($groups, function ($item) { 2358 return $item["isTplGroup"] == "y"; 2359 }); 2360 } 2361 2362 2363 function get_included_groups($group, $recur = true) 2364 { 2365 $engroup = urlencode($group); 2366 if (! $recur || ! isset($this->groupinclude_cache[$engroup])) { 2367 $query = 'select `includeGroup` from `tiki_group_inclusion` where `groupName`=?'; 2368 $result = $this->query($query, [$group]); 2369 $ret = []; 2370 2371 while ($res = $result->fetchRow()) { 2372 $ret[] = $res['includeGroup']; 2373 if ($recur) { 2374 $ret2 = $this->get_included_groups($res['includeGroup']); 2375 $ret = array_merge($ret, $ret2); 2376 } 2377 } 2378 2379 $back = array_unique($ret); 2380 2381 if ($recur) { 2382 $this->groupinclude_cache[$engroup] = $back; 2383 } 2384 return $back; 2385 } else { 2386 return $this->groupinclude_cache[$engroup]; 2387 } 2388 } 2389 function get_including_groups($group, $recur = 'n') 2390 { 2391 $query = 'select `groupName` from `tiki_group_inclusion` where `includeGroup`=? order by `groupName`'; 2392 $result = $this->query($query, [$group]); 2393 $ret = []; 2394 while ($res = $result->fetchRow()) { 2395 $ret[] = $res['groupName']; 2396 if ($recur == 'y') { 2397 $ret = array_merge($ret, $this->get_including_groups($res['groupName'])); 2398 } 2399 } 2400 if ($recur == 'y') { 2401 sort($ret); 2402 } 2403 return $ret; 2404 } 2405 function user_is_in_group($user, $group) 2406 { 2407 $user_groups = $this->get_user_groups($user); 2408 if (in_array($group, $user_groups)) { 2409 return true; 2410 } else { 2411 return false; 2412 } 2413 } 2414 2415 function remove_user_from_group($user, $group, $bulk = false) 2416 { 2417 global $prefs; 2418 2419 $tikilib = TikiLib::lib('tiki'); 2420 $cachelib = TikiLib::lib('cache'); 2421 2422 $cachelib->invalidate('user_details_' . $user); 2423 $tikilib->invalidate_usergroups_cache($user); 2424 $this->invalidate_usergroups_cache($user); // this is needed as cache is present in this instance too 2425 2426 $userid = $this->get_user_id($user); 2427 2428 $query = 'delete from `users_usergroups` where `userId` = ? and `groupName` = ?'; 2429 $result = $this->query($query, [$userid, $group]); 2430 2431 $query = 'update `users_users` set `default_group`=? where `login`=? and `default_group`=?'; 2432 $this->query($query, ['Registered', $user, $group]); 2433 2434 TikiLib::events()->trigger('tiki.user.groupleave', [ 2435 'type' => 'user', 2436 'object' => $user, 2437 'group' => $group, 2438 'bulk_import' => $bulk, 2439 ]); 2440 2441 $_SESSION['u_info']['group'] = 'Registered'; 2442 } 2443 2444 function remove_user_from_all_groups($user) 2445 { 2446 global $prefs; 2447 $userid = $this->get_user_id($user); 2448 $query = 'delete from `users_usergroups` where `userId` = ?'; 2449 $result = $this->query($query, [$userid]); 2450 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 2451 } 2452 2453 function get_groups_userchoice() 2454 { 2455 $ret = []; 2456 $groups = $this->get_groups(0, -1, '', '', '', 'n', '', 'y'); 2457 foreach ($groups['data'] as $g) { 2458 $ret[] = $g['groupName']; 2459 } 2460 return $ret; 2461 } 2462 2463 function get_groups_for_permissions() 2464 { 2465 $query = "SELECT * from users_groups 2466 where isTplGroup <> 'y' and groupName not in (select groupName 2467 from tiki_group_inclusion where includeGroup in (SELECT groupName 2468 from users_groups where isTplGroup = 'y')) order by id asc;"; 2469 $ret = $this->fetchAll($query); 2470 $retval = []; 2471 $retval['data'] = $ret; 2472 $retval['cant'] = count($ret); 2473 return $retval; 2474 } 2475 2476 function get_template_groups_containers() 2477 { 2478 $query = "SELECT * from users_groups 2479 where isTplGroup = 'y' order by id asc;"; 2480 $ret = $this->fetchAll($query); 2481 $retval = []; 2482 $retval['data'] = $ret; 2483 $retval['cant'] = count($ret); 2484 return $retval; 2485 } 2486 2487 function get_group_children($groupName) 2488 { 2489 $query = "SELECT DISTINCT * from users_groups as ug 2490 where ug.groupName in (select groupName from tiki_group_inclusion where includeGroup = ?) order by id asc;"; 2491 $ret = $this->fetchAll($query, [$groupName]); 2492 $retval = []; 2493 $retval['data'] = $ret; 2494 $retval['cant'] = count($ret); 2495 return $retval; 2496 } 2497 2498 function get_group_children_with_permissions($groupName) 2499 { 2500 $query = "SELECT DISTINCT ug.* from users_groups as ug join users_grouppermissions as up on ug.groupName = up.groupName 2501 where ug.groupName in (select groupName from tiki_group_inclusion where includeGroup = ?) order by id asc;"; 2502 $ret = $this->fetchAll($query, [$groupName]); 2503 $retval = []; 2504 $retval['data'] = $ret; 2505 $retval['cant'] = count($ret); 2506 return $retval; 2507 } 2508 2509 function get_groups($offset = 0, $maxRecords = -1, $sort_mode = 'groupName_asc', $find = '', $initial = '', $details = "y", $inGroups = '', $userChoice = '') 2510 { 2511 $mid = ''; 2512 $bindvars = []; 2513 if ($find) { 2514 $mid = ' where `groupName` like ?'; 2515 $bindvars[] = '%' . $find . '%'; 2516 } 2517 2518 if ($initial) { 2519 $mid = ' where `groupName` like ?'; 2520 $bindvars = [$initial . '%']; 2521 } 2522 2523 if ($inGroups) { 2524 $mid .= $mid ? ' and ' : ' where '; 2525 $mid .= '`groupName` in ('; 2526 $cpt = 0; 2527 foreach ($inGroups as $grp => $value) { 2528 if ($cpt++) { 2529 $mid .= ','; 2530 } 2531 $mid .= '?'; 2532 $bindvars[] = $grp; 2533 } 2534 $mid .= ')'; 2535 } 2536 2537 if ($userChoice) { 2538 $mid .= $mid ? ' and ' : ' where '; 2539 $mid .= "`userChoice` = 'y'"; 2540 } 2541 2542 $query = "select * from `users_groups` $mid order by " . $this->convertSortMode($sort_mode); 2543 $query_cant = "select count(*) from `users_groups` $mid"; 2544 $ret = $this->fetchAll($query, $bindvars, $maxRecords, $offset); 2545 $cant = $this->getOne($query_cant, $bindvars); 2546 2547 foreach ($ret as &$res) { 2548 if ($details == 'y') { 2549 $perms = $this->get_group_permissions($res['groupName']); 2550 $res['perms'] = $perms; 2551 $res['permcant'] = count($perms); 2552 $groups = $this->get_included_groups($res['groupName']); 2553 $res['included'] = $groups; 2554 $res['included_direct'] = $this->get_included_groups($res['groupName'], false); 2555 } 2556 } 2557 2558 $retval = []; 2559 $retval['data'] = $ret; 2560 $retval['cant'] = $cant; 2561 return $retval; 2562 } 2563 2564 function list_all_users() 2565 { 2566 global $tiki_p_list_users, $tiki_p_admin; 2567 $cachelib = TikiLib::lib('cache'); 2568 2569 if ($tiki_p_list_users !== 'y' && $tiki_p_admin != 'y') { 2570 return []; 2571 } 2572 2573 if (! $users = $cachelib->getSerialized('userslist')) { 2574 $users = []; 2575 $result = $this->query('select `login`,`userId` from `users_users` order by `login`', []); 2576 while ($res = $result->fetchRow()) { 2577 $users["{$res['userId']}"] = $res['login']; 2578 } 2579 $cachelib->cacheItem('userslist', serialize($users)); 2580 } 2581 2582 return $users; 2583 } 2584 2585 function list_regular_groups() 2586 { 2587 2588 $groups = []; 2589 $result = $this->query('select `id`, `groupName` from `users_groups` where isRole <> ? order by `groupName`', ['y']); 2590 while ($res = $result->fetchRow()) { 2591 $groups[] = ["groupName" => $res['groupName'], "id" => $res['id']]; 2592 } 2593 2594 return $groups; 2595 } 2596 2597 function list_role_groups() 2598 { 2599 return $this->fetchAll(" 2600 SELECT ug.id, ug.groupName FROM `users_groups` ug 2601 WHERE 2602 ug.isRole = 'y' 2603 group by ug.id, ug.GroupName"); 2604 } 2605 2606 2607 function list_all_groups() 2608 { 2609 $cachelib = TikiLib::lib('cache'); 2610 2611 if (! $groups = $cachelib->getSerialized('grouplist')) { 2612 $groups = []; 2613 $result = $this->query('select `groupName` from `users_groups` order by `groupName`', []); 2614 while ($res = $result->fetchRow()) { 2615 $groups[] = $res['groupName']; 2616 } 2617 $cachelib->cacheItem('grouplist', serialize($groups)); 2618 } 2619 2620 return $groups; 2621 } 2622 2623 function list_all_groupIds() 2624 { 2625 $cachelib = TikiLib::lib('cache'); 2626 2627 if (! $groups = $cachelib->getSerialized('groupIdlist')) { 2628 $groups = $this->fetchAll('select `id`, `groupName`, isRole from `users_groups` order by `groupName`', []); 2629 $cachelib->cacheItem('groupIdlist', serialize($groups)); 2630 } 2631 2632 return $groups; 2633 } 2634 2635 function list_can_include_groups($group) 2636 { 2637 $list = []; 2638 $query = 'select `groupName` from `users_groups`'; 2639 $result = $this->query($query); 2640 while ($res = $result->fetchRow()) { 2641 if ($res['groupName'] != $group) { 2642 $includedGroups = $this->get_included_groups($res['groupName']); 2643 if (! in_array($group, $includedGroups)) { 2644 $list[] = $res['groupName']; 2645 } 2646 } 2647 } 2648 return $list; 2649 } 2650 2651 function list_all_groups_with_permission() 2652 { 2653 $groups = array_map(function ($g) { 2654 return ['groupName' => $g]; 2655 }, $this->list_all_groups()); 2656 2657 $filtered = Perms::filter( 2658 ['type' => 'group'], 2659 'object', 2660 $groups, 2661 ['object' => 'groupName'], 2662 'group_view' 2663 ); 2664 2665 return array_map(function ($g) { 2666 return $g['groupName']; 2667 }, $filtered); 2668 } 2669 2670 2671 function remove_user($user) 2672 { 2673 $cachelib = TikiLib::lib('cache'); 2674 2675 if ($user == 'admin') { 2676 return false; 2677 } 2678 2679 $userexists_cache[$user] = null; 2680 2681 $userId = $this->getOne('select `userId` from `users_users` where `login` = ?', [$user]); 2682 2683 $groupTracker = $this->get_tracker_usergroup($user); 2684 if ($groupTracker && $groupTracker['usersTrackerId']) { 2685 $trklib = TikiLib::lib('trk'); 2686 2687 $itemId = $trklib->get_item_id($groupTracker['usersTrackerId'], $groupTracker['usersFieldId'], $user); 2688 if ($itemId) { 2689 $trklib->remove_tracker_item($itemId); 2690 } 2691 } 2692 2693 $tracker = $this->get_usertracker($userId); 2694 if ($tracker && $tracker['usersTrackerId']) { 2695 $trklib = TikiLib::lib('trk'); 2696 2697 $itemId = $trklib->get_item_id($tracker['usersTrackerId'], $tracker['usersFieldId'], $user); 2698 if ($itemId) { 2699 $trklib->remove_tracker_item($itemId); 2700 } 2701 } 2702 2703 $query = 'delete from `users_users` where binary `login` = ?'; 2704 $result = $this->query($query, [ $user ]); 2705 $query = 'delete from `users_usergroups` where `userId`=?'; 2706 $result = $this->query($query, [ $userId ]); 2707 $query = 'delete from `tiki_user_login_cookies` where `userId`=?'; 2708 $result = $this->query($query, [ $userId ]); 2709 $query = 'delete from `tiki_user_watches` where binary `user`=?'; 2710 $result = $this->query($query, [$user]); 2711 $query = 'delete from `tiki_user_preferences` where binary `user`=?'; 2712 $result = $this->query($query, [$user]); 2713 $query = 'delete from `tiki_newsletter_subscriptions` where binary `email`=? and `isUser`=?'; 2714 $result = $this->query($query, [$user, 'y']); 2715 $this->query('delete from `tiki_user_reports` where `user` = ?', [$user]); 2716 $this->query('delete from `tiki_user_reports_cache` where `user` = ?', [$user]); 2717 $this->query('delete from `tiki_user_mailin_struct` where `username` = ?', [$user]); 2718 2719 $cachelib->invalidate('userslist'); 2720 2721 TikiLib::events()->trigger('tiki.user.delete', ['type' => 'user', 'object' => $user]); 2722 2723 return true; 2724 } 2725 2726 function change_login($from, $to) 2727 { 2728 global $user; 2729 $cachelib = TikiLib::lib('cache'); 2730 2731 if ($from == 'admin') { 2732 return false; 2733 } 2734 2735 $userexists_cache[$user] = null; 2736 2737 $userId = $this->getOne('select `userId` from `users_users` where `login` = ?', [$from]); 2738 2739 if ($userId) { 2740 $this->query('update `users_users` set `login`=? where `userId` = ?', [$to, (int)$userId]); 2741 $this->query('update `tiki_wiki_attachments` set `user`=? where `user`=?', [$to, $from]); 2742 $this->query('update `tiki_webmail_contacts` set `user`=? where `user`=?', [$to, $from]); 2743 $this->query('update `tiki_webmail_contacts_fields` set `user`=? where `user`=?', [$to, $from]); 2744 $this->query('update `tiki_userpoints` set `user`=? where `user`=?', [$to, $from]); 2745 $this->query('update `tiki_userfiles` set `user`=? where `user`=?', [$to, $from]); 2746 $this->query('update `tiki_user_watches` set `user`=? where `user`=?', [$to, $from]); 2747 $this->query('update `tiki_user_votings` set `user`=? where `user`=?', [$to, $from]); 2748 $this->query('update `tiki_user_tasks` set `user`=? where `user`=?', [$to, $from]); 2749 $this->query('update `tiki_user_tasks` set `creator`=? where `creator`=?', [$to, $from]); 2750 $this->query('update `tiki_user_tasks_history` set `lasteditor`=? where `lasteditor`=?', [$to, $from]); 2751 $this->query('update `tiki_user_taken_quizzes` set `user`=? where `user`=?', [$to, $from]); 2752 $this->query('update `tiki_user_quizzes` set `user`=? where `user`=?', [$to, $from]); 2753 $this->query('update `tiki_user_preferences` set `user`=? where `user`=?', [$to, $from]); 2754 $this->query('update `tiki_user_postings` set `user`=? where `user`=?', [$to, $from]); 2755 $this->query('update `tiki_user_notes` set `user`=? where `user`=?', [$to, $from]); 2756 $this->query('update `tiki_user_menus` set `user`=? where `user`=?', [$to, $from]); 2757 $this->query('update `tiki_user_bookmarks_urls` set `user`=? where `user`=?', [$to, $from]); 2758 $this->query('update `tiki_user_bookmarks_folders` set `user`=? where `user`=?', [$to, $from]); 2759 $this->query('update `tiki_user_assigned_modules` set `user`=? where `user`=?', [$to, $from]); 2760 $this->query('update `tiki_tags` set `user`=? where `user`=?', [$to, $from]); 2761 $this->query('update `tiki_suggested_faq_questions` set `user`=? where `user`=?', [$to, $from]); 2762 $this->query('update `tiki_submissions` set `author`=? where `author`=?', [$to, $from]); 2763 $this->query('update `tiki_shoutbox` set `user`=? where `user`=?', [$to, $from]); 2764 $this->query('update `tiki_sessions` set `user`=? where `user`=?', [$to, $from]); 2765 $this->query('update `tiki_semaphores` set `user`=? where `user`=?', [$to, $from]); 2766 $this->query('update `tiki_received_pages` set `receivedFromUser`=? where `receivedFromUser`=?', [$to, $from]); 2767 $this->query('update `tiki_received_articles` set `author`=? where `author`=?', [$to, $from]); 2768 $this->query('update `tiki_private_messages` set `poster`=? where `poster`=?', [$to, $from]); 2769 $this->query('update `tiki_private_messages` set `toNickname`=? where `toNickname`=?', [$to, $from]); 2770 $this->query('update `tiki_pages` set `user`=? where `user`=?', [$to, $from]); 2771 $this->query('update `tiki_pages` set `creator`=? where `creator`=?', [$to, $from]); 2772 $this->query('update `tiki_page_footnotes` set `user`=? where `user`=?', [$to, $from]); 2773 $this->query('update `tiki_newsletters` set `author`=? where `author`=?', [$to, $from]); 2774 $this->query('update `tiki_minical_events` set `user`=? where `user`=?', [$to, $from]); 2775 $this->query('update `tiki_minical_topics` set `user`=? where `user`=?', [$to, $from]); 2776 $this->query('update `tiki_mailin_accounts` set `user`=? where `user`=?', [$to, $from]); 2777 $this->query('update `tiki_live_support_requests` set `operator`=? where `operator`=?', [$to, $from]); 2778 $this->query('update `tiki_live_support_requests` set `tiki_user`=? where `tiki_user`=?', [$to, $from]); 2779 $this->query('update `tiki_live_support_requests` set `user`=? where `user`=?', [$to, $from]); 2780 $this->query('update `tiki_live_support_operators` set `user`=? where `user`=?', [$to, $from]); 2781 $this->query('update `tiki_live_support_messages` set `user`=? where `user`=?', [$to, $from]); 2782 $this->query('update `tiki_live_support_messages` set `username`=? where `username`=?', [$to, $from]); 2783 $this->query('update `tiki_images` set `user`=? where `user`=?', [$to, $from]); 2784 $this->query('update `tiki_history` set `user`=? where `user`=?', [$to, $from]); 2785 $this->query('update `tiki_galleries` set `user`=? where `user`=?', [$to, $from]); 2786 $this->query('update `tiki_forums_reported` set `user`=? where `user`=?', [$to, $from]); 2787 $this->query('update `tiki_forums_queue` set `user`=? where `user`=?', [$to, $from]); 2788 $this->query('update `tiki_forums` set `moderator`=? where `moderator`=?', [$to, $from]); 2789 $this->query('update `tiki_forum_reads` set `user`=? where `user`=?', [$to, $from]); 2790 $this->query('update `tiki_files` set `user`=? where `user`=?', [$to, $from]); 2791 $this->query('update `tiki_files` set `lastModifUser`=? where `lastModifUser`=?', [$to, $from]); 2792 $this->query('update `tiki_files` set `lockedby`=? where `lockedby`=?', [$to, $from]); 2793 $this->query('update `tiki_file_galleries` set `user`=? where `user`=?', [$to, $from]); 2794 $this->query('update `tiki_file_drafts` set `user`=? where `user`=?', [$to, $from]); 2795 $this->query('update `tiki_copyrights` set `userName`=? where `userName`=?', [$to, $from]); 2796 $this->query('update `tiki_comments` set `userName`=? where `userName`=?', [$to, $from]); 2797 $this->query('update `tiki_chat_users` set `nickname`=? where `nickname`=?', [$to, $from]); 2798 $this->query('update `tiki_chat_messages` set `poster`=? where `poster`=?', [$to, $from]); 2799 $this->query('update `tiki_chat_channels` set `moderator`=? where `moderator`=?', [$to, $from]); 2800 $this->query('update `tiki_calendars` set `user`=? where `user`=?', [$to, $from]); 2801 $this->query('update `tiki_calendar_roles` set `username`=? where `username`=?', [$to, $from]); 2802 $this->query('update `tiki_calendar_items` set `user`=? where `user`=?', [$to, $from]); 2803 $this->query('update `tiki_blogs` set `user`=? where `user`=?', [$to, $from]); 2804 $this->query('update `tiki_blog_posts` set `user`=? where `user`=?', [$to, $from]); 2805 $this->query('update `tiki_banning` set `user`=? where `user`=?', [$to, $from]); 2806 $this->query('update `tiki_banners` set `client`=? where `client`=?', [$to, $from]); 2807 $this->query('update `tiki_articles` set `author`=? where `author`=?', [$to, $from]); 2808 $this->query('update `tiki_actionlog` set `user`=? where `user`=?', [$to, $from]); 2809 $this->query('update `messu_messages` set `user`=? where `user`=?', [$to, $from]); 2810 $this->query('update `messu_messages` set `user_from`=? where `user_from`=?', [$to, $from]); 2811 $this->query('update `tiki_newsletter_subscriptions` set `email`=? where `email`=? and `isUser`=?', [$to, $from, 'y']); 2812 $this->query('update `tiki_object_relations` set `source_itemId`=? where source_type="user" and `source_itemId`=?', [$to, $from]); 2813 $this->query('update `tiki_object_relations` set `target_itemId`=? where target_type="user" and `target_itemId`=?', [$to, $from]); 2814 $this->query('update `tiki_freetagged_objects` set `user`=? where `user`=?', [$to, $from]); 2815 2816 $this->query( 2817 'update `tiki_tracker_item_fields`ttif' . 2818 ' left join `tiki_tracker_fields` ttf on (ttif.`fieldId`=ttf.`fieldId`)' . 2819 ' set `value`=? where ttif.`value`=? and ttf.`type`=?', 2820 [$to, $from, 'u'] 2821 ); 2822 $this->query('update `tiki_tracker_items` set `createdBy`=? where `createdBy`=?', [$to, $from]); 2823 $this->query('update `tiki_tracker_items` set `lastModifBy`=? where `lastModifBy`=?', [$to, $from]); 2824 2825 $result = $this->query("select `fieldId`, `itemChoices` from `tiki_tracker_fields` where `type`='u'"); 2826 2827 while ($res = $result->fetchRow()) { 2828 $this->query('update `tiki_tracker_item_fields` set `value`=? where `value`=? and `fieldId`=?', [$to, $from, $res['fieldId']]); 2829 2830 $u = ($res['itemChoices'] != '' ) ? unserialize($res['itemChoices']) : []; 2831 2832 if ($value = array_search($from, $u)) { 2833 $u[$value] = $to; 2834 $u = serialize($u); 2835 $this->query('update `tiki_tracker_fields` set `itemChoices`=? where `fieldId`=?', [$u, $res['fieldId']]); 2836 } 2837 } 2838 $cachelib->invalidate('userslist'); 2839 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $from]); 2840 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $to]); 2841 return true; 2842 } else { 2843 return false; 2844 } 2845 } 2846 2847 function remove_group($group) 2848 { 2849 if ($group == 'Anonymous' || $group == 'Registered') { 2850 return false; 2851 } 2852 $info = $this->get_group_info($group); 2853 2854 $query = 'delete from `tiki_group_inclusion` where `groupName` = ? or `includeGroup` = ?'; 2855 $result = $this->query($query, [$group, $group]); 2856 2857 $query = []; 2858 $query[] = 'delete from `users_groups` where `groupName` = ?'; 2859 $query[] = 'delete from `users_usergroups` where `groupName` = ?'; 2860 $query[] = 'delete from `users_grouppermissions` where `groupName` = ?'; 2861 $query[] = 'delete from `users_objectpermissions` where `groupName` = ?'; 2862 $query[] = 'delete from `tiki_newsletter_groups` where `groupName` = ?'; 2863 $query[] = 'delete from `tiki_group_watches` where `group` = ?'; 2864 2865 foreach ($query as $q) { 2866 $this->query($q, [$group]); 2867 } 2868 2869 $this->query('update `users_users` set `default_group`=? where `default_group`=?', ['Registered', $group]); 2870 2871 if (isset($info['id'])) { 2872 TikiLib::lib('categ')->detach_managed_category($info['id']); 2873 2874 TikiLib::lib('attribute')->delete_objects_with( 'tiki.category.templatedgroupid', $info['id']); 2875 TikiLib::lib('attribute')->delete_objects_with( 'tiki.menu.templatedgroupid', $info['id']); 2876 } 2877 2878 TikiLib::events()->trigger('tiki.group.delete', [ 2879 'type' => 'group', 2880 'object' => $group, 2881 ]); 2882 2883 $cachelib = TikiLib::lib('cache'); 2884 $cachelib->invalidate('grouplist'); 2885 $cachelib->invalidate('group_theme_' . $group); 2886 2887 return $result; 2888 } 2889 2890 function get_user_default_group($user) 2891 { 2892 if (! isset($user)) { 2893 return 'Anonymous'; 2894 } 2895 if (isset($_SESSION['u_info']) && $user == $_SESSION['u_info']['login']) { 2896 if (isset($_SESSION['u_info']['group']) && is_string($_SESSION['u_info']['group'])) { 2897 return $_SESSION['u_info']['group']; 2898 } elseif (isset($_SESSION['u_info']['group']['groupName']) && is_string($_SESSION['u_info']['group']['groupName'])) { 2899 return $_SESSION['u_info']['group']['groupName']; 2900 } 2901 } 2902 $query = 'select `default_group` from `users_users` where `login` = ?'; 2903 $result = $this->getOne($query, [$user]); 2904 $ret = ''; 2905 if (! is_null($result) && $result != '') { 2906 $ret = $result; 2907 } else { 2908 $groups = $this->get_user_groups($user); 2909 foreach ($groups as $gr) { 2910 if ($gr != 'Anonymous' and $gr != 'Registered' and $gr != '') { 2911 $ret = $gr; 2912 break; 2913 } 2914 } 2915 if (! $ret) { 2916 $ret = 'Registered'; 2917 } 2918 } 2919 return $ret; 2920 } 2921 2922 /** 2923 * Returns the wiki page name for the current user and checks for useGroupHome pref 2924 * 2925 * @param string $user current logged in user 2926 * @return string page name 2927 */ 2928 function get_user_default_homepage($user) 2929 { 2930 global $prefs; 2931 2932 if ($prefs['useGroupHome'] !== 'y') { 2933 return $prefs['wikiHomePage']; 2934 } 2935 2936 $home = ''; 2937 $group = $this->get_user_default_group($user); 2938 2939 if ($group) { 2940 $home = $this->get_group_home($group); 2941 } 2942 if (! $home) { // work through the other groups this user is a member of 2943 $query = "select g.`groupHome`, g.`groupName`" . 2944 " from `users_usergroups` as gu, `users_users` as u, `users_groups`as g" . 2945 " where gu.`userId`= u.`userId` and u.`login`=? and gu.`groupName`= g.`groupName` and g.`groupHome` != '' and g.`groupHome` is not null"; 2946 2947 $result = $this->query($query, [$user]); 2948 2949 while ($res = $result->fetchRow()) { 2950 if ($home != '') { 2951 $groups = $this->get_included_groups($res['groupName']); 2952 if (in_array($group, $groups)) { 2953 $home = $res['groupHome']; 2954 $group = $res['groupName']; 2955 } 2956 } else { 2957 $home = $res['groupHome']; 2958 $group = $res['groupName']; 2959 } 2960 } 2961 } 2962 $home = $this->best_multilingual_page($home); 2963 2964 $validHome = substr($home, 0, 1) === '/' 2965 || preg_match(',^https?://,', $home) 2966 || TikiLib::lib('tiki')->page_exists($home); 2967 2968 if (! $validHome && $prefs['tikiIndex'] === 'tiki-index.php') { 2969 $home = $prefs['wikiHomePage']; 2970 } 2971 2972 return $home; 2973 } 2974 2975 function best_multilingual_page($page) 2976 { 2977 global $prefs; 2978 2979 if ($prefs['feature_multilingual'] != 'y') { 2980 return ($page); 2981 } 2982 2983 $info = $this->get_page_info($page); 2984 $multilinguallib = TikiLib::lib('multilingual'); 2985 $bestLangPageId = $multilinguallib->selectLangObj('wiki page', $info['page_id'], $prefs['language']); 2986 2987 if ($info['page_id'] == $bestLangPageId) { 2988 return $page; 2989 } 2990 2991 return $this->get_page_name_from_id($bestLangPageId); 2992 } 2993 2994 /* Returns a theme/style for this ithe default group of the current user. */ 2995 function get_user_group_theme() 2996 { 2997 global $user; 2998 $group = $this->get_user_default_group($user); 2999 3000 $cachelib = TikiLib::lib('cache'); 3001 $k = 'group_theme_' . $group; 3002 3003 if ($data = $cachelib->getCached($k)) { 3004 $return = $data; 3005 } elseif (! empty($group)) { 3006 $query = 'select `groupTheme` from `users_groups` where `groupName` = ?'; 3007 $return = $this->getOne($query, [$group]); 3008 $cachelib->cacheItem($k, $return); 3009 } 3010 return $return; 3011 } 3012 3013 /* Returns a default category for user's default_group 3014 */ 3015 function get_user_group_default_category($user) 3016 { 3017 $query = 'select `groupDefCat` from `users_groups` ug, `users_users` uu where `login` = ? and ug.`groupName` = uu.`default_group`'; 3018 $result = $this->getOne($query, [$user]); 3019 3020 return $result; 3021 } 3022 3023 //modified get_user_groups() to know if the user is part of the group directly or through groups inclusion 3024 function get_user_groups_inclusion($user) 3025 { 3026 $userid = $this->get_user_id($user); 3027 3028 $query = 'select `groupName` from `users_usergroups` where `userId`=?'; 3029 $result = $this->query($query, [(int)$userid]); 3030 $real = []; //really assigned groups (not (only) included) 3031 $ret = []; 3032 3033 while ($res = $result->fetchRow()) { 3034 $real[] = $res['groupName']; 3035 foreach ($this->get_included_groups($res['groupName']) as $group) { 3036 $ret[$group] = 'included'; 3037 } 3038 } 3039 3040 foreach ($real as $group) { 3041 $ret[$group] = 'real'; 3042 } 3043 3044 return $ret; 3045 } 3046 3047 function get_group_home($group) 3048 { 3049 $query = 'select `groupHome` from `users_groups` where `groupName`=?'; 3050 $result = $this->getOne($query, [$group]); 3051 $ret = ''; 3052 3053 if (! is_null($result)) { 3054 $ret = $result; 3055 } 3056 3057 return $ret; 3058 } 3059 3060 /** 3061 * Return information about users that belong to a 3062 * specific group 3063 * 3064 * @param string $group group name 3065 * @param int $offset 3066 * @param int $max 3067 * @param string $what which user fields to retrieve 3068 * @param string $sort_mode 3069 * @return array list of users 3070 */ 3071 function get_group_users($group, $offset = 0, $max = -1, $what = 'login', $sort_mode = 'login_asc') 3072 { 3073 if (empty($group)) { 3074 return []; 3075 } 3076 3077 $w = $what == '*' ? 'uu.*, ug.`created`, ug.`expire` ' : "uu.`$what`"; 3078 3079 if (strpos($sort_mode, 'created_') !== false) { 3080 $sort_mode = 'ug.' . $sort_mode; // avoid ambiguity of created column 3081 } 3082 $query = "select $w from `users_users` uu, `users_usergroups` ug where uu.`userId`=ug.`userId` and `groupName`=? order by " . 3083 $this->convertSortMode($sort_mode); 3084 3085 $result = $this->fetchAll($query, $group, $max, $offset); 3086 $ret = []; 3087 3088 foreach ($result as $res) { 3089 $ret[] = ($what == '*') ? $res : $res[$what]; 3090 } 3091 3092 return $ret; 3093 } 3094 3095 function get_recur_group_users($group, $recur = 0, $what = 'login') 3096 { 3097 $users = $this->get_group_users($group, 0, -1, $what); 3098 if ($recur > 0) { 3099 $includings = $this->get_including_groups($group, 'n'); 3100 --$recur; 3101 foreach ($includings as $including) { 3102 $users = array_merge($users, $this->get_recur_group_users($including, $recur, $what)); 3103 } 3104 } 3105 return $users; 3106 } 3107 3108 function get_user_info($user, $inclusion = false, $field = 'login') 3109 { 3110 global $prefs; 3111 if ($field == 'userId') { 3112 $user = (int)$user; 3113 } elseif ($field != 'login') { 3114 return false; 3115 } 3116 3117 $result = $this->query("select * from `users_users` where `$field`=?", [$user]); 3118 if ($res = $result->fetchRow()) { 3119 $res['groups'] = ( $inclusion ) ? $this->get_user_groups_inclusion($res['login']) : $this->get_user_groups($res['login']); 3120 $res['age'] = ( ! isset($res['registrationDate']) ) ? 0 : $this->now - $res['registrationDate']; 3121 3122 if ($prefs['login_is_email'] == 'y' && isset($res['login']) && $res['login'] != 'admin') { 3123 $res['email'] = $res['login']; 3124 } 3125 3126 $res['editable'] = $this->user_can_be_edited($res['login']); 3127 3128 return $res; 3129 } 3130 } 3131 3132 function get_userid_info($user, $inclusion = false) 3133 { 3134 return $this->get_user_info($user, $inclusion, 'userId'); 3135 } 3136 3137 /** 3138 * Helps recognize nicknames which anonymous users have chosen 3139 * A leading tab is for recognizing anonymous entries. Real usernames don't start with a tab 3140 * @param string $username user nickname or name 3141 * @return string string which should be displayed 3142 */ 3143 function distinguish_anonymous_users($username = "") 3144 { 3145 if (empty($username)) { 3146 return ""; 3147 } 3148 if ($username[0] == "\t") { 3149 $username = $username . ' (' . tra('unverified') . ')'; 3150 } 3151 return $username; 3152 } 3153 3154 3155 /** 3156 * Creates DOM tag for user info with popup or not depending on prefs etc 3157 * @param string $auser user to find info for (current user if empty) 3158 * @param string $body content of the anchor tag (user name if empty) 3159 * @param string $class add a class to the a tag (default userlink) 3160 * @return string HTML anchor tag 3161 */ 3162 function build_userinfo_tag($auser = '', $body = '', $class = 'userlink', $show_popup = 'y', $elementId = '') 3163 { 3164 global $user, $prefs; 3165 3166 if (! $auser) { 3167 $auser = $user; 3168 } 3169 $realn = $this->clean_user($auser); 3170 3171 if (! $body) { 3172 $body = $realn; 3173 } 3174 3175 if ($elementId) { 3176 $idStr = " id=\"$elementId\""; 3177 } else { 3178 $idStr = ''; 3179 } 3180 3181 $isSelf = ($auser === $user) ? true : false; 3182 // Only process if feature_friends enabled, user_information public or we query ourselfs 3183 if (($this->get_user_preference($auser, 'user_information', 'public') != 'public') && ($prefs['feature_friends'] != 'y') && ! $isSelf) { 3184 return "<span{$idStr}>$body</span>"; 3185 } 3186 3187 3188 $id = $this->get_user_id($auser); 3189 if ($id == -1) { 3190 return $body; 3191 } 3192 3193 $extra = ''; 3194 if ($show_popup == "n") { 3195 //do nothing for adding a tip 3196 $title = ''; 3197 } elseif ($prefs['feature_community_mouseover'] == 'y' && ($this->get_user_preference($auser, 'show_mouseover_user_info', 'y') == 'y' || $prefs['feature_friends'] == 'y')) { 3198 $data = TikiLib::lib('service')->getUrl([ 3199 'controller' => 'user', 3200 'action' => 'info', 3201 'username' => $auser, 3202 ]); 3203 $extra .= ' data-ajaxtips="' . htmlspecialchars($data, ENT_QUOTES) . '"'; 3204 $class .= ' ajaxtips'; 3205 3206 if ($auser === $user) { 3207 $title = tra('Your Information'); 3208 } else { 3209 $title = tra('User Information'); 3210 } 3211 } elseif ($prefs['user_show_realnames'] == 'y') { 3212 $class .= ' tips'; 3213 $title = tr('User') . ':' . $realn; 3214 } else { 3215 $class .= ' tips'; 3216 $title = tr('User') . ':' . $auser; 3217 } 3218 3219 if (empty($prefs['urlOnUsername'])) { 3220 $url = 'tiki-user_information.php?userId=' . $id; 3221 if ($prefs['feature_sefurl'] == 'y') { 3222 include_once('tiki-sefurl.php'); 3223 $url = filter_out_sefurl($url); 3224 } 3225 } else { 3226 $url = preg_replace( 3227 ['/%userId%/', '/%user%/'], 3228 [$id, $auser], 3229 $prefs['urlOnUsername'] 3230 ); 3231 } 3232 3233 $lat = $this->get_user_preference($auser, 'lat'); 3234 $lon = $this->get_user_preference($auser, 'lon'); 3235 $zoom = $this->get_user_preference($auser, 'zoom'); 3236 3237 if (! ($lat == 0 && $lon == 0)) { 3238 $class .= ' geolocated'; 3239 $extra .= ' data-geo-lat="' . $lat . '" data-geo-lon="' . $lon . '"'; 3240 3241 if ($zoom) { 3242 $extra .= ' data-geo-zoom="' . $zoom . '"'; 3243 } 3244 } 3245 3246 if ($title) { 3247 $titleStr = ' title="' . htmlspecialchars($title, ENT_QUOTES) . '"'; 3248 } else { 3249 $titleStr = ''; 3250 } 3251 3252 $body = "<a{$idStr}{$titleStr} href=\"$url\" class=\"$class\"$extra>" . $body . '</a>'; 3253 3254 return $body; 3255 } 3256 3257 3258 3259 // UNRELIABLE. In particular, lastLogin and currentLogin aren't properly maintained due to missing user_details_ cache invalidation 3260 // refactoring to use new cachelib instead of global var in memory - batawata 2006-02-07 3261 function get_user_details($login, $useCache = true) 3262 { 3263 $cachelib = TikiLib::lib('cache'); 3264 3265 $cacheKey = 'user_details_' . $login; 3266 3267 if (! $useCache || ! $user_details = $cachelib->getSerialized($cacheKey)) { 3268 $user_details = []; 3269 3270 $query = 'SELECT `userId`, `login`, `email`, `lastLogin`, `currentLogin`,' . 3271 ' `registrationDate`, `created`, `avatarName`, `avatarSize`,' . 3272 ' `avatarFileType`, `avatarLibName`, `avatarType`' . 3273 ' FROM `users_users` WHERE `login` = ?'; 3274 3275 $result = $this->query($query, [$login]); 3276 3277 $user_details['info'] = $result->fetchRow(); 3278 3279 $query = 'SELECT `prefName` , `value` FROM `tiki_user_preferences` WHERE `user` = ?'; 3280 $result = $this->query($query, [$login]); 3281 3282 $user_details['preferences'] = []; 3283 $aUserPrefs = ['realName', 'homePage', 'country']; 3284 3285 while ($row = $result->fetchRow()) { 3286 $user_details['preferences'][$row['prefName']] = $row['value']; 3287 3288 // atention: this is redundant, for intertiki slave mode 3289 // we insert, delete and insert again this information, 3290 // because of nature of user information as being preferences 3291 if (in_array($row['prefName'], $aUserPrefs)) { 3292 $user_details['info'][$row['prefName']] = $row['value']; 3293 } 3294 } 3295 3296 $user_details['groups'] = $this->get_user_groups($login); 3297 3298 $cachelib->cacheItem($cacheKey, serialize($user_details)); 3299 3300 global $user_preferences; 3301 $user_preferences[$login] = $user_details['preferences']; 3302 } 3303 3304 return $user_details; 3305 } 3306 3307 function set_default_group($user, $group) 3308 { 3309 // if user is not in group, assign user to group before setting default group 3310 $user_groups = $this->get_user_groups($user); 3311 if (! in_array($group, $user_groups) && ! empty($group)) { 3312 $this->assign_user_to_group($user, $group); 3313 } 3314 $query = 'update `users_users` set `default_group` = ? where `login` = ?'; 3315 $this->query($query, [$group, $user]); 3316 3317 if ($user == $_SESSION['u_info']['login']) { 3318 $_SESSION['u_info']['group'] = $group; 3319 } 3320 } 3321 3322 function set_email_group($user, $email) 3323 { 3324 $query = 'select `id`, `groupName`, `emailPattern` from `users_groups` where `emailPattern`!=?'; 3325 $groups = $this->fetchAll($query, ['']); 3326 $nb = 0; 3327 3328 if (empty($groups)) { 3329 return 0; 3330 } 3331 3332 $userGroups = $this->get_user_groups_inclusion($user); 3333 foreach ($groups as $group) { 3334 if (! isset($userGroups[$group['groupName']]) && preg_match($group['emailPattern'], $email)) { 3335 $this->assign_user_to_group($user, $group['groupName']); 3336 $this->set_default_group($user, $group['groupName']); 3337 ++$nb; 3338 } 3339 } 3340 return $nb; 3341 } 3342 3343 function refresh_set_email_group() 3344 { 3345 $users = $this->list_users(); 3346 $nb = 0; 3347 foreach ($users['data'] as $user) { 3348 $nb += $this->set_email_group($user['login'], $user['email']); 3349 } 3350 return $nb; 3351 } 3352 3353 function change_permission_level($perm, $level) 3354 { 3355 $query = 'update `users_permissions` set `level` = ? where `permName` = ?'; 3356 $this->query($query, [$level, $perm]); 3357 3358 $cachelib = TikiLib::lib('cache'); 3359 $cachelib->empty_type_cache('fgals_perms'); 3360 3361 $menulib = TikiLib::lib('menu'); 3362 $menulib->empty_menu_cache(); 3363 } 3364 3365 function assign_level_permissions($group, $level) 3366 { 3367 $query = 'select `permName` from `users_permissions` where `level` = ?'; 3368 $result = $this->query($query, [$level]); 3369 3370 while ($res = $result->fetchRow()) { 3371 $this->assign_permission_to_group($res['permName'], $group); 3372 } 3373 3374 $cachelib = TikiLib::lib('cache'); 3375 $cachelib->empty_type_cache('fgals_perms'); 3376 $cachelib->invalidate("groupperms_$group"); 3377 3378 $menulib = TikiLib::lib('menu'); 3379 $menulib->empty_menu_cache(); 3380 } 3381 3382 function remove_level_permissions($group, $level) 3383 { 3384 $query = 'select `permName` from `users_permissions` where `level` = ?'; 3385 $result = $this->query($query, [$level]); 3386 3387 while ($res = $result->fetchRow()) { 3388 $this->remove_permission_from_group($res['permName'], $group); 3389 } 3390 3391 $cachelib = TikiLib::lib('cache'); 3392 $cachelib->empty_type_cache('fgals_perms'); 3393 $cachelib->invalidate("groupperms_$group"); 3394 3395 $menulib = TikiLib::lib('menu'); 3396 $menulib->empty_menu_cache(); 3397 } 3398 3399 function create_dummy_level($level) 3400 { 3401 $query = 'delete from `users_permissions` where `permName` = ?'; 3402 $result = $this->query($query, ['']); 3403 $query = "insert into `users_permissions`(`permName`, `level`) values('', ?)"; 3404 $this->query($query, [$level]); 3405 3406 $cachelib = TikiLib::lib('cache'); 3407 $cachelib->empty_type_cache('fgals_perms'); 3408 3409 $menulib = TikiLib::lib('menu'); 3410 $menulib->empty_menu_cache(); 3411 } 3412 3413 function get_permission_levels() 3414 { 3415 $query = 'select distinct(`level`) from `users_permissions`'; 3416 3417 $result = $this->query($query); 3418 $ret = []; 3419 3420 while ($res = $result->fetchRow()) { 3421 $ret[] = $res['level']; 3422 } 3423 3424 return $ret; 3425 } 3426 3427 function get_tracker_usergroup($user) 3428 { 3429 $lastRes = ''; 3430 $group = $this->get_user_default_group($user); 3431 if (! empty($group)) { 3432 $lastRes = $this->get_usertrackerid($group); 3433 } 3434 if (! $lastRes) { 3435 $groups = $this->get_user_groups($user); 3436 $query = 'select `groupName`, `usersTrackerId`, `usersFieldId`' . 3437 ' from `users_groups`' . 3438 ' where `groupName` in ( ' . implode(' , ', array_fill(0, count($groups), '?')) . 3439 ' ) and `groupName` != ? and `usersTrackerId` > 0'; 3440 3441 $groups[] = 'Anonymous'; 3442 $result = $this->query($query, $groups); 3443 3444 while ($res = $result->fetchRow()) { 3445 $lastRes = $res; 3446 if ($res['groupName'] != 'Registered') { 3447 return $res ; 3448 } 3449 } 3450 } 3451 3452 return $lastRes; 3453 } 3454 3455 function get_grouptrackerid($group) 3456 { 3457 $res = $this->query('select `groupTrackerId`,`groupFieldId` from `users_groups` where `groupName`=?', [$group]); 3458 $ret = $res->fetchRow(); 3459 3460 if (! $ret['groupTrackerId'] or ! $ret['groupFieldId']) { 3461 $groups = $this->get_included_groups($group); 3462 foreach ($groups as $gr) { 3463 $res = $this->query('select `groupTrackerId`,`groupFieldId` from `users_groups` where `groupName`=?', [$gr]); 3464 $ret = $res->fetchRow(); 3465 if ($ret['groupTrackerId'] and $ret['groupFieldId']) { 3466 return $ret; 3467 } 3468 } 3469 } else { 3470 return $ret; 3471 } 3472 return false; 3473 } 3474 3475 /** 3476 * @param $group 3477 * @param $include_groups 3478 * @throws Exception 3479 */ 3480 public function manage_group($group, $include_groups): void 3481 { 3482 $oldIncluded = $this->get_included_groups($group, false); 3483 $this->remove_all_inclusions($group); 3484 $info = $this->get_group_info($group); 3485 3486 if (isset($include_groups) and is_array($include_groups)) { 3487 $oldIncludes = array_diff($oldIncluded, $include_groups); 3488 $oldGroups = $this->get_group_info(array_values($oldIncludes)); 3489 $parentGroupsIds = array_map(function ($item) { 3490 return $item["id"]; 3491 }, array_filter($oldGroups, function ($item) { 3492 return $item["isTplGroup"] == "y"; 3493 })); 3494 if (!empty($parentGroupsIds)) { 3495 TikiLib::lib('categ')->detach_managed_category($info["id"], $parentGroupsIds); 3496 } 3497 3498 foreach ($include_groups as $include) { 3499 if ($include && $group != $include) { 3500 $this->group_inclusion($group, $include); 3501 } 3502 } 3503 3504 $groups = $this->get_group_info($include_groups); 3505 $templateGroups = array_filter($groups, function ($item) { 3506 return $item["isTplGroup"] == "y"; 3507 }); 3508 foreach ($templateGroups as $templateGroup) { 3509 $categories = TikiLib::lib('categ')->get_managed_categories($templateGroup["id"]); 3510 $managedIds = array_unique(array_map(function ($item) { 3511 return $item["categId"]; 3512 }, $categories)); 3513 3514 foreach ($managedIds as $managedId) { 3515 TikiLib::lib('categ')->manage_sub_categories($managedId); 3516 } 3517 } 3518 } 3519 } 3520 3521 function get_usertrackerid($group) 3522 { 3523 $res = $this->query('select `usersTrackerId`,`usersFieldId` from `users_groups` where `groupName`=?', [$group]); 3524 $ret = $res->fetchRow(); 3525 3526 if (! $ret['usersTrackerId'] or ! $ret['usersFieldId']) { 3527 $groups = $this->get_included_groups($group); 3528 foreach ($groups as $gr) { 3529 $res = $this->query('select `usersTrackerId`,`usersFieldId` from `users_groups` where `groupName`=?', [$gr]); 3530 $ret = $res->fetchRow(); 3531 if ($ret['usersTrackerId'] and $ret['usersFieldId']) { 3532 return $ret; 3533 } 3534 } 3535 } else { 3536 return $ret; 3537 } 3538 return false; 3539 } 3540 3541 3542 function get_usertracker($uid) 3543 { 3544 if ($utr = $this->get_userid_info($uid)) { 3545 $utr['usersTrackerId'] = ''; 3546 foreach ($utr['groups'] as $gr) { 3547 $utrid = $this->get_usertrackerid($gr); 3548 if (! empty($utrid['usersTrackerId']) && ! empty($utrid['usersFieldId'])) { 3549 $utrid['group'] = $gr; 3550 $utrid['user'] = $utr['login']; 3551 $utr = $utrid; 3552 break; 3553 } 3554 } 3555 return $utr; 3556 } 3557 } 3558 3559 function get_enabled_permissions() 3560 { 3561 global $prefs; 3562 3563 $raw = $this->get_raw_permissions(); 3564 $out = []; 3565 3566 foreach ($raw as $permission) { 3567 $valid = empty($permission['prefs']); 3568 3569 if (! $valid) { 3570 foreach ($permission['prefs'] as $name) { 3571 if (isset($prefs[$name]) && $prefs[$name] == 'y') { 3572 $valid = true; 3573 break; 3574 } 3575 } 3576 } 3577 3578 if ($valid) { 3579 $out[$permission['name']] = $permission; 3580 } 3581 } 3582 3583 return $out; 3584 } 3585 3586 function get_permission_names_for($type) 3587 { 3588 // Compatibility hack without which no article results are returned by mysql full-text searches (basic search) 3589 if ($type == "cms") { 3590 $type = "articles"; 3591 } 3592 $raw = $this->get_permissions(0, -1, 'permName_asc', '', $type); 3593 $out = []; 3594 3595 foreach ($raw['data'] as $permission) { 3596 $out[] = $permission['name']; 3597 } 3598 3599 return $out; 3600 } 3601 3602 /** 3603 * Function for sorting permission in tiki-objectpermissions.php 3604 * @param $permissions 3605 * @return array $permissions 3606 */ 3607 private function getSortingPermissions($permissions) 3608 { 3609 3610 $file = 'db/config/tiki-objectpermissions_order.yml'; 3611 3612 if (! file_exists($file)) { 3613 return $permissions; 3614 } 3615 3616 $content = file_get_contents($file); 3617 3618 try { 3619 $order = Yaml::parse($content); 3620 } catch (ParseException $e) { 3621 $logslib = TikiLib::lib('logs'); 3622 $logslib->add_log('System', $file . ' - ' . $e->getMessage()); 3623 3624 return $permissions; 3625 } 3626 3627 $step = 100; 3628 $maxTypes = 0; 3629 $typeWeights = []; 3630 $permissionWeights = []; 3631 $checkYaml = []; 3632 3633 foreach ($permissions as $perCheck) { 3634 $checkYaml[$perCheck['type']][$perCheck['name']] = ['result' => 1]; 3635 } 3636 3637 foreach ($order as $key => $permissionList) { 3638 if (! isset($typeWeights[$key])) { 3639 $typeWeights[$key] = ['weight' => $maxTypes, 'next' => 0]; 3640 $maxTypes += $step; 3641 } 3642 $weight = $typeWeights[$key]['weight']; 3643 $next = $typeWeights[$key]['next']; 3644 foreach ($permissionList as $permission) { 3645 if (! array_key_exists('tiki_p_' . $permission, $checkYaml[$key])) { 3646 continue; 3647 } 3648 3649 if ($checkYaml[$key]['tiki_p_' . $permission]['result'] == 1) { 3650 $permissionWeights['tiki_p_' . $permission] = $weight + $next++; 3651 } 3652 } 3653 $typeWeights[$key]['next'] = $next; 3654 } 3655 3656 foreach ($permissions as $permission) { 3657 if (isset($permissionWeights[$permission['name']])) { 3658 continue; 3659 } 3660 if (! isset($typeWeights[$permission['type']])) { 3661 $typeWeights[$permission['type']] = ['weight' => $maxTypes, 'next' => 0]; 3662 $maxTypes += $step; 3663 } 3664 $permissionWeights[$permission['name']] = $typeWeights[$permission['type']]['weight'] + $typeWeights[$permission['type']]['next']++; 3665 } 3666 3667 usort($permissions, function ($a, $b) use ($permissionWeights) { 3668 $result = $permissionWeights[$a['name']] - $permissionWeights[$b['name']]; 3669 return $result; 3670 }); 3671 3672 return $permissions; 3673 } 3674 3675 private function get_raw_permissions() 3676 { 3677 static $permissions; 3678 3679 // Avoid multiple unserialize per page 3680 if ($permissions) { 3681 return $permissions; 3682 } 3683 3684 global $prefs; 3685 $cachelib = TikiLib::lib('cache'); 3686 3687 if ($permissions = $cachelib->getSerialized('rawpermissions' . $prefs['language'])) { 3688 return $permissions; 3689 } 3690 3691 /** 3692 * Define master permissions array 3693 * 3694 * NOTE: This is the order they appear in tiki-objectpermissions.php 3695 * and it's important to keep them grouped by 'type' 3696 * 3697 */ 3698 3699 $permissions = [ 3700 [ 3701 'name' => 'tiki_p_acct_create_book', 3702 'description' => tra('Can create/close a book'), 3703 'level' => 'admin', 3704 'type' => 'accounting', 3705 'admin' => false, 3706 'prefs' => ['feature_accounting'], 3707 'scope' => 'global', 3708 ], 3709 [ 3710 'name' => 'tiki_p_acct_manage_accounts', 3711 'description' => tra('Can create/edit/lock accounts'), 3712 'level' => 'admin', 3713 'type' => 'accounting', 3714 'admin' => true, 3715 'prefs' => ['feature_accounting' ], 3716 'scope' => 'global', 3717 ], 3718 [ 3719 'name' => 'tiki_p_acct_book', 3720 'description' => tra('Create a new transaction'), 3721 'level' => 'editors', 3722 'type' => 'accounting', 3723 'admin' => false, 3724 'prefs' => ['feature_accounting'], 3725 'scope' => 'global', 3726 ], 3727 [ 3728 'name' => 'tiki_p_acct_view', 3729 'description' => tra('Permission to view the journal'), 3730 'level' => 'registered', 3731 'type' => 'accounting', 3732 'admin' => false, 3733 'prefs' => ['feature_accounting' ], 3734 'scope' => 'global', 3735 ], 3736 [ 3737 'name' => 'tiki_p_acct_book_stack', 3738 'description' => tra('Can book into the stack where statements can be changed'), 3739 'level' => 'editors', 3740 'type' => 'accounting', 3741 'admin' => false, 3742 'prefs' => ['feature_accounting'], 3743 'scope' => 'global', 3744 ], 3745 [ 3746 'name' => 'tiki_p_acct_book_import', 3747 'description' => tra('Can import statements from external accounts'), 3748 'level' => 'editors', 3749 'type' => 'accounting', 3750 'admin' => false, 3751 'prefs' => ['feature_accounting' ], 3752 'scope' => 'global', 3753 ], 3754 [ 3755 'name' => 'tiki_p_acct_manage_template', 3756 'description' => tra('Can manage templates for recurring transactions'), 3757 'level' => 'editors', 3758 'type' => 'accounting', 3759 'admin' => false, 3760 'prefs' => ['feature_accounting'], 3761 'scope' => 'global', 3762 ], 3763 [ 3764 'name' => 'tiki_p_admin_cms', 3765 'description' => tra('Can admin the articles'), 3766 'level' => 'admin', 3767 'type' => 'articles', 3768 'admin' => true, 3769 'prefs' => ['feature_articles'], 3770 'scope' => 'object', 3771 ], 3772 [ 3773 'name' => 'tiki_p_approve_submission', 3774 'description' => tra('Can approve submissions'), 3775 'level' => 'editors', 3776 'type' => 'articles', 3777 'admin' => false, 3778 'prefs' => ['feature_articles'], 3779 'scope' => 'object', 3780 ], 3781 [ 3782 'name' => 'tiki_p_articles_admin_topics', 3783 'description' => tra('Can admin article topics'), 3784 'level' => 'editors', 3785 'type' => 'articles', 3786 'admin' => false, 3787 'prefs' => ['feature_articles'], 3788 'scope' => 'global', 3789 ], 3790 [ 3791 'name' => 'tiki_p_articles_admin_types', 3792 'description' => tra('Can admin article types'), 3793 'level' => 'editors', 3794 'type' => 'articles', 3795 'admin' => false, 3796 'prefs' => ['feature_articles'], 3797 'scope' => 'global', 3798 ], 3799 [ 3800 'name' => 'tiki_p_articles_read_heading', 3801 'description' => tra('Can read article headings'), 3802 'level' => 'basic', 3803 'type' => 'articles', 3804 'admin' => false, 3805 'prefs' => ['feature_articles'], 3806 'scope' => 'object', 3807 ], 3808 [ 3809 'name' => 'tiki_p_autoapprove_submission', 3810 'description' => tra('Submitted articles are automatically approved'), 3811 'level' => 'editors', 3812 'type' => 'articles', 3813 'admin' => false, 3814 'prefs' => ['feature_articles'], 3815 'scope' => 'global', 3816 ], 3817 [ 3818 'name' => 'tiki_p_edit_article', 3819 'description' => tra('Can edit articles'), 3820 'level' => 'editors', 3821 'type' => 'articles', 3822 'admin' => false, 3823 'prefs' => ['feature_articles'], 3824 'scope' => 'object', 3825 ], 3826 [ 3827 'name' => 'tiki_p_edit_article_user', 3828 'description' => tra('Can edit the user (owner) of articles'), 3829 'level' => 'editors', 3830 'type' => 'articles', 3831 'admin' => false, 3832 'prefs' => ['feature_articles'], 3833 'scope' => 'object', 3834 ], 3835 [ 3836 'name' => 'tiki_p_edit_submission', 3837 'description' => tra('Can edit submissions'), 3838 'level' => 'editors', 3839 'type' => 'articles', 3840 'admin' => false, 3841 'prefs' => ['feature_articles'], 3842 'scope' => 'object', 3843 ], 3844 [ 3845 'name' => 'tiki_p_read_article', 3846 'description' => tra('Can read articles (applies to article or topic level)'), 3847 'level' => 'basic', 3848 'type' => 'articles', 3849 'admin' => false, 3850 'prefs' => ['feature_articles'], 3851 'scope' => 'object', 3852 ], 3853 [ 3854 'name' => 'tiki_p_remove_article', 3855 'description' => tra('Can remove articles'), 3856 'level' => 'editors', 3857 'type' => 'articles', 3858 'admin' => false, 3859 'prefs' => ['feature_articles'], 3860 'scope' => 'object', 3861 ], 3862 [ 3863 'name' => 'tiki_p_remove_submission', 3864 'description' => tra('Can remove submissions'), 3865 'level' => 'editors', 3866 'type' => 'articles', 3867 'admin' => false, 3868 'prefs' => ['feature_articles'], 3869 'scope' => 'object', 3870 ], 3871 [ 3872 'name' => 'tiki_p_submit_article', 3873 'description' => tra('Can submit articles'), 3874 'level' => 'basic', 3875 'type' => 'articles', 3876 'admin' => false, 3877 'prefs' => ['feature_articles'], 3878 'scope' => 'global', 3879 ], 3880 [ 3881 'name' => 'tiki_p_rate_article', 3882 'description' => tra('Can rate articles'), 3883 'level' => 'basic', 3884 'type' => 'articles', 3885 'admin' => false, 3886 'prefs' => ['feature_articles'], 3887 'scope' => 'object', 3888 ], 3889 [ 3890 'name' => 'tiki_p_bigbluebutton_view_rec', 3891 'description' => tra('Can view recordings from past meetings'), 3892 'level' => 'basic', 3893 'type' => 'bigbluebutton', 3894 'admin' => false, 3895 'prefs' => ['bigbluebutton_feature'], 3896 'scope' => 'object', 3897 ], 3898 [ 3899 'name' => 'tiki_p_bigbluebutton_join', 3900 'description' => tra('Can join a meeting'), 3901 'level' => 'basic', 3902 'type' => 'bigbluebutton', 3903 'admin' => false, 3904 'prefs' => ['bigbluebutton_feature'], 3905 'scope' => 'object', 3906 ], 3907 [ 3908 'name' => 'tiki_p_bigbluebutton_moderate', 3909 'description' => tra('Can moderate a meeting'), 3910 'level' => 'admin', 3911 'type' => 'bigbluebutton', 3912 'admin' => false, 3913 'prefs' => ['bigbluebutton_feature'], 3914 'scope' => 'object', 3915 ], 3916 [ 3917 'name' => 'tiki_p_bigbluebutton_create', 3918 'description' => tra('Can create a meeting'), 3919 'level' => 'admin', 3920 'type' => 'bigbluebutton', 3921 'admin' => false, 3922 'prefs' => ['bigbluebutton_feature'], 3923 'scope' => 'object', 3924 ], 3925 [ 3926 'name' => 'tiki_p_xmpp_chat', 3927 'description' => tra('Can use XMPP chat'), 3928 'level' => 'admin', 3929 'type' => 'xmpp', 3930 'admin' => false, 3931 'prefs' => ['xmpp_feature'], 3932 'scope' => 'global', 3933 ], 3934 [ 3935 'name' => 'tiki_p_blog_admin', 3936 'description' => tra('Can admin blogs'), 3937 'level' => 'editors', 3938 'type' => 'blogs', 3939 'admin' => true, 3940 'prefs' => ['feature_blogs'], 3941 'scope' => 'object', 3942 ], 3943 [ 3944 'name' => 'tiki_p_assign_perm_blog', 3945 'description' => tra('Can assign perms to blog'), 3946 'level' => 'admin', 3947 'type' => 'blogs', 3948 'admin' => false, 3949 'prefs' => ['feature_blogs'], 3950 'scope' => 'object', 3951 ], 3952 [ 3953 'name' => 'tiki_p_blog_post', 3954 'description' => tra('Can post to a blog'), 3955 'level' => 'registered', 3956 'type' => 'blogs', 3957 'admin' => false, 3958 'prefs' => ['feature_blogs'], 3959 'scope' => 'object', 3960 ], 3961 [ 3962 'name' => 'tiki_p_create_blogs', 3963 'description' => tra('Can create a blog'), 3964 'level' => 'editors', 3965 'type' => 'blogs', 3966 'admin' => false, 3967 'prefs' => ['feature_blogs'], 3968 'scope' => 'global', 3969 ], 3970 [ 3971 'name' => 'tiki_p_read_blog', 3972 'description' => tra('Can read blogs'), 3973 'level' => 'basic', 3974 'type' => 'blogs', 3975 'admin' => false, 3976 'prefs' => ['feature_blogs'], 3977 'scope' => 'object', 3978 ], 3979 [ 3980 'name' => 'tiki_p_blog_post_view_ref', 3981 'description' => tra('Can view in module and feed the blog posts'), 3982 'level' => 'basic', 3983 'type' => 'blogs', 3984 'admin' => false, 3985 'prefs' => ['feature_blogs'], 3986 'scope' => 'object', 3987 ], 3988 [ 3989 'name' => 'tiki_p_blog_view_ref', 3990 'description' => tra('Can view in module and feed the blog'), 3991 'level' => 'basic', 3992 'type' => 'blogs', 3993 'admin' => false, 3994 'prefs' => ['feature_blogs'], 3995 'scope' => 'object', 3996 ], 3997 [ 3998 'name' => 'tiki_p_admin_calendar', 3999 'description' => tr('Can create/admin calendars'), 4000 'level' => 'admin', 4001 'type' => 'calendar', 4002 'admin' => true, 4003 'prefs' => ['feature_calendar'], 4004 'scope' => 'object', 4005 ], 4006 [ 4007 'name' => 'tiki_p_add_events', 4008 'description' => tra('Can add events in the calendar'), 4009 'level' => 'registered', 4010 'type' => 'calendar', 4011 'admin' => false, 4012 'prefs' => ['feature_calendar'], 4013 'scope' => 'object', 4014 ], 4015 [ 4016 'name' => 'tiki_p_change_events', 4017 'description' => tra('Can edit events in the calendar'), 4018 'level' => 'registered', 4019 'type' => 'calendar', 4020 'admin' => false, 4021 'prefs' => ['feature_calendar'], 4022 'scope' => 'object', 4023 ], 4024 [ 4025 'name' => 'tiki_p_view_calendar', 4026 'description' => tra('Can browse the calendar'), 4027 'level' => 'basic', 4028 'type' => 'calendar', 4029 'admin' => false, 4030 'prefs' => ['feature_calendar'], 4031 'scope' => 'object', 4032 ], 4033 [ 4034 'name' => 'tiki_p_view_events', 4035 'description' => tra('Can view event details'), 4036 'level' => 'registered', 4037 'type' => 'calendar', 4038 'admin' => false, 4039 'prefs' => ['feature_calendar'], 4040 'scope' => 'object', 4041 ], 4042 [ 4043 'name' => 'tiki_p_calendar_add_my_particip', 4044 'description' => tra('Can add himself or herself to the participants'), 4045 'level' => 'registered', 4046 'type' => 'calendar', 4047 'admin' => false, 4048 'prefs' => ['feature_calendar'], 4049 'scope' => 'object', 4050 ], 4051 [ 4052 'name' => 'tiki_p_calendar_add_guest_particip', 4053 'description' => tra('Can add guest to the participants'), 4054 'level' => 'registered', 4055 'type' => 'calendar', 4056 'admin' => false, 4057 'prefs' => ['feature_calendar'], 4058 'scope' => 'object', 4059 ], 4060 [ 4061 'name' => 'tiki_p_view_tiki_calendar', 4062 'description' => tra('Can view Tiki tools calendar'), 4063 'level' => 'basic', 4064 'type' => 'calendar', 4065 'admin' => false, 4066 'prefs' => ['feature_action_calendar'], 4067 'scope' => 'global', 4068 ], 4069 [ 4070 'name' => 'tiki_p_admin_categories', 4071 'description' => tra('Can admin categories'), 4072 'level' => 'admin', 4073 'type' => 'category', 4074 'admin' => true, 4075 'prefs' => ['feature_categories'], 4076 'scope' => 'object', 4077 ], 4078 [ 4079 'name' => 'tiki_p_view_category', 4080 'description' => tra('Can see the category in a listing'), 4081 'level' => 'basic', 4082 'type' => 'category', 4083 'admin' => false, 4084 'prefs' => ['feature_categories'], 4085 'scope' => 'object', 4086 ], 4087 [ 4088 'name' => 'tiki_p_add_object', 4089 'description' => tra('Can add objects to the category (tiki_p_modify_object_categories permission required)'), 4090 'level' => 'editors', 4091 'type' => 'category', 4092 'admin' => false, 4093 'prefs' => ['feature_categories'], 4094 'scope' => 'object', 4095 ], 4096 [ 4097 'name' => 'tiki_p_remove_object', 4098 'description' => tra('Can remove objects from the category (tiki_p_modify_object_categories permission required)'), 4099 'level' => 'editors', 4100 'type' => 'category', 4101 'admin' => false, 4102 'prefs' => ['feature_categories'], 4103 'scope' => 'object', 4104 ], 4105 [ 4106 'name' => 'tiki_p_assign_perm_category', 4107 'description' => tra('Can assign perms to category'), 4108 'level' => 'admin', 4109 'type' => 'category', 4110 'admin' => false, 4111 'prefs' => ['feature_categories'], 4112 'scope' => 'object', 4113 ], 4114 //array( 4115 // 'name' => 'tiki_p_create_category', 4116 // 'description' => tra('Can create new categories'), 4117 // 'level' => 'admin', 4118 // 'type' => 'category', 4119 // 'admin' => false, 4120 // 'prefs' => array('feature_categories'), 4121 // 'scope' => 'global', 4122 //), 4123 [ 4124 'name' => 'tiki_p_admin_chat', 4125 'description' => tra('Administrator can create channels, remove channels, etc'), 4126 'level' => 'editors', 4127 'type' => 'chat', 4128 'admin' => true, 4129 'prefs' => ['feature_minichat', 'feature_live_support'], 4130 'scope' => 'global', 4131 ], 4132 [ 4133 'name' => 'tiki_p_chat', 4134 'description' => tra('Can use the chat system'), 4135 'level' => 'registered', 4136 'type' => 'chat', 4137 'admin' => false, 4138 'prefs' => ['feature_minichat', 'feature_live_support'], 4139 'scope' => 'global', 4140 ], 4141 [ 4142 'name' => 'tiki_p_admin_received_articles', 4143 'description' => tra('Can admin received articles'), 4144 'level' => 'editors', 4145 'type' => 'comm', 4146 'admin' => false, 4147 'prefs' => ['feature_comm'], 4148 'scope' => 'global', 4149 ], 4150 [ 4151 'name' => 'tiki_p_admin_received_pages', 4152 'description' => tra('Can admin received pages'), 4153 'level' => 'editors', 4154 'type' => 'comm', 4155 'admin' => false, 4156 'prefs' => ['feature_comm'], 4157 'scope' => 'global', 4158 ], 4159 [ 4160 'name' => 'tiki_p_send_articles', 4161 'description' => tra('Can send articles to other sites'), 4162 'level' => 'editors', 4163 'type' => 'comm', 4164 'admin' => false, 4165 'prefs' => ['feature_comm'], 4166 'scope' => 'global', 4167 ], 4168 [ 4169 'name' => 'tiki_p_sendme_articles', 4170 'description' => tra('Can send articles to this site'), 4171 'level' => 'registered', 4172 'type' => 'comm', 4173 'admin' => false, 4174 'prefs' => ['feature_comm'], 4175 'scope' => 'global', 4176 ], 4177 [ 4178 'name' => 'tiki_p_sendme_pages', 4179 'description' => tra('Can send pages to this site'), 4180 'level' => 'registered', 4181 'type' => 'comm', 4182 'admin' => false, 4183 'prefs' => ['feature_comm'], 4184 'scope' => 'global', 4185 ], 4186 [ 4187 'name' => 'tiki_p_send_pages', 4188 'description' => tra('Can send pages to other sites'), 4189 'level' => 'registered', 4190 'type' => 'comm', 4191 'admin' => false, 4192 'prefs' => ['feature_comm'], 4193 'scope' => 'global', 4194 ], 4195 [ 4196 'name' => 'tiki_p_post_comments', 4197 'description' => tra('Can post new comments'), 4198 'level' => 'registered', 4199 'type' => 'comments', 4200 'admin' => false, 4201 'prefs' => [ 4202 'feature_wiki_comments', 4203 'feature_blogposts_comments', 4204 'feature_file_galleries_comments', 4205 'feature_image_galleries_comments', 4206 'feature_article_comments', 4207 'feature_faq_comments', 4208 'feature_poll_comments', 4209 'map_comments' 4210 ], 4211 'scope' => 'object', 4212 'apply_to' => ['wiki', 'trackers', 'articles', 'blogs'], 4213 ], 4214 [ 4215 'name' => 'tiki_p_read_comments', 4216 'description' => tra('Can read comments'), 4217 'level' => 'basic', 4218 'type' => 'comments', 4219 'admin' => false, 4220 'prefs' => [ 4221 'feature_wiki_comments', 4222 'feature_blogposts_comments', 4223 'feature_file_galleries_comments', 4224 'feature_image_galleries_comments', 4225 'feature_article_comments', 4226 'feature_faq_comments', 4227 'feature_poll_comments', 4228 'map_comments' 4229 ], 4230 'scope' => 'object', 4231 'apply_to' => ['wiki', 'trackers', 'articles', 'blogs'], 4232 ], 4233 [ 4234 'name' => 'tiki_p_admin_comments', 4235 'description' => tra('Can admin comments'), 4236 'level' => 'admin', 4237 'type' => 'comments', 4238 'admin' => true, 4239 'prefs' => [ 4240 'feature_wiki_comments', 4241 'feature_blogposts_comments', 4242 'feature_file_galleries_comments', 4243 'feature_image_galleries_comments', 4244 'feature_article_comments', 4245 'feature_faq_comments', 4246 'feature_poll_comments', 4247 'map_comments' 4248 ], 4249 'scope' => 'object', 4250 'apply_to' => ['wiki', 'trackers', 'articles', 'blogs'], 4251 ], 4252 [ 4253 'name' => 'tiki_p_edit_comments', 4254 'description' => tra('Can edit all comments'), 4255 'level' => 'editors', 4256 'type' => 'comments', 4257 'admin' => false, 4258 'prefs' => [' 4259 feature_wiki_comments', 4260 'feature_blogposts_comments', 4261 'feature_file_galleries_comments', 4262 'feature_image_galleries_comments', 4263 'feature_article_comments', 4264 'feature_faq_comments', 4265 'feature_poll_comments', 4266 'map_comments' 4267 ], 4268 'scope' => 'object', 4269 'apply_to' => ['wiki', 'trackers', 'articles', 'blogs'], 4270 ], 4271 [ 4272 'name' => 'tiki_p_remove_comments', 4273 'description' => tra('Can delete comments'), 4274 'level' => 'editors', 4275 'type' => 'comments', 4276 'admin' => false, 4277 'prefs' => [ 4278 'feature_wiki_comments', 4279 'feature_blogposts_comments', 4280 'feature_file_galleries_comments', 4281 'feature_image_galleries_comments', 4282 'feature_article_comments', 4283 'feature_faq_comments', 4284 'feature_poll_comments', 4285 'map_comments' 4286 ], 4287 'scope' => 'object', 4288 'apply_to' => ['wiki', 'trackers', 'articles', 'blogs'], 4289 ], 4290 [ 4291 'name' => 'tiki_p_vote_comments', 4292 'description' => tra('Can vote on comments'), 4293 'level' => 'registered', 4294 'type' => 'comments', 4295 'admin' => false, 4296 'prefs' => ['comments_vote'], 4297 'scope' => 'object', 4298 'apply_to' => ['wiki', 'trackers', 'articles', 'blogs'], 4299 ], 4300 [ 4301 'name' => 'tiki_p_admin_content_templates', 4302 'description' => tra('Can admin content templates'), 4303 'level' => 'admin', 4304 'type' => 'content templates', 4305 'admin' => true, 4306 'prefs' => ['feature_wiki_templates', 'feature_cms_templates'], 4307 'scope' => 'object', 4308 ], 4309 [ 4310 'name' => 'tiki_p_edit_content_templates', 4311 'description' => tra('Can edit content templates'), 4312 'level' => 'editors', 4313 'type' => 'content templates', 4314 'admin' => false, 4315 'prefs' => ['feature_wiki_templates', 'feature_cms_templates', 'feature_file_galleries_templates'], 4316 'scope' => 'object', 4317 ], 4318 [ 4319 'name' => 'tiki_p_lock_content_templates', 4320 'description' => tra('Can lock content templates'), 4321 'level' => 'editors', 4322 'type' => 'content templates', 4323 'admin' => false, 4324 'prefs' => ['feature_wiki_templates', 'feature_cms_templates', 'lock_content_templates'], 4325 'scope' => 'object', 4326 ], 4327 [ 4328 'name' => 'tiki_p_use_content_templates', 4329 'description' => tra('Can use content templates'), 4330 'level' => 'registered', 4331 'type' => 'content templates', 4332 'admin' => false, 4333 'prefs' => ['feature_wiki_templates', 'feature_cms_templates'], 4334 'scope' => 'object', 4335 ], 4336 [ 4337 'name' => 'tiki_p_admin_contribution', 4338 'description' => tra('Can admin contributions'), 4339 'level' => 'admin', 4340 'type' => 'contribution', 4341 'admin' => true, 4342 'prefs' => ['feature_contribution'], 4343 'scope' => 'global', 4344 ], 4345 [ 4346 'name' => 'tiki_p_admin_directory', 4347 'description' => tra('Can admin the directory'), 4348 'level' => 'editors', 4349 'type' => 'directory', 4350 'admin' => true, 4351 'prefs' => ['feature_directory'], 4352 'scope' => 'global', 4353 ], 4354 [ 4355 'name' => 'tiki_p_admin_directory_cats', 4356 'description' => tra('Can admin directory categories'), 4357 'level' => 'editors', 4358 'type' => 'directory', 4359 'admin' => false, 4360 'prefs' => ['feature_directory'], 4361 'scope' => 'global', 4362 ], 4363 [ 4364 'name' => 'tiki_p_admin_directory_sites', 4365 'description' => tra('Can admin directory sites'), 4366 'level' => 'editors', 4367 'type' => 'directory', 4368 'admin' => false, 4369 'prefs' => ['feature_directory'], 4370 'scope' => 'global', 4371 ], 4372 [ 4373 'name' => 'tiki_p_autosubmit_link', 4374 'description' => tra('Submitted links are valid'), 4375 'level' => 'editors', 4376 'type' => 'directory', 4377 'admin' => false, 4378 'prefs' => ['feature_directory'], 4379 'scope' => 'global', 4380 ], 4381 [ 4382 'name' => 'tiki_p_submit_link', 4383 'description' => tra('Can submit sites to the directory'), 4384 'level' => 'basic', 4385 'type' => 'directory', 4386 'admin' => false, 4387 'prefs' => ['feature_directory'], 4388 'scope' => 'global', 4389 ], 4390 [ 4391 'name' => 'tiki_p_validate_links', 4392 'description' => tra('Can validate submitted links'), 4393 'level' => 'editors', 4394 'type' => 'directory', 4395 'admin' => false, 4396 'prefs' => ['feature_directory'], 4397 'scope' => 'global', 4398 ], 4399 [ 4400 'name' => 'tiki_p_view_directory', 4401 'description' => tra('Can use the directory'), 4402 'level' => 'basic', 4403 'type' => 'directory', 4404 'admin' => false, 4405 'prefs' => ['feature_directory'], 4406 'scope' => 'global', 4407 ], 4408 [ 4409 'name' => 'tiki_p_dsn_query', 4410 'description' => tra('Can execute arbitrary queries on a given DSN'), 4411 'level' => 'admin', 4412 'type' => 'dsn', 4413 'admin' => false, 4414 'prefs' => [], 4415 'scope' => 'object', 4416 ], 4417 [ 4418 'name' => 'tiki_p_admin_faqs', 4419 'description' => tra('Can admin FAQs'), 4420 'level' => 'editors', 4421 'type' => 'faqs', 4422 'admin' => true, 4423 'prefs' => ['feature_faqs'], 4424 'scope' => 'object', 4425 ], 4426 [ 4427 'name' => 'tiki_p_suggest_faq', 4428 'description' => tra('Can suggest FAQ questions'), 4429 'level' => 'basic', 4430 'type' => 'faqs', 4431 'admin' => false, 4432 'prefs' => ['feature_faqs'], 4433 'scope' => 'object', 4434 ], 4435 [ 4436 'name' => 'tiki_p_view_faqs', 4437 'description' => tra('Can view FAQs'), 4438 'level' => 'basic', 4439 'type' => 'faqs', 4440 'admin' => false, 4441 'prefs' => ['feature_faqs'], 4442 'scope' => 'object', 4443 ], 4444 [ 4445 'name' => 'tiki_p_download_files', 4446 'description' => tra('Can download files'), 4447 'level' => 'basic', 4448 'type' => 'file galleries', 4449 'admin' => false, 4450 'prefs' => ['feature_file_galleries'], 4451 'scope' => 'object', 4452 ], 4453 [ 4454 'name' => 'tiki_p_upload_files', 4455 'description' => tra('Can upload files'), 4456 'level' => 'registered', 4457 'type' => 'file galleries', 4458 'admin' => false, 4459 'prefs' => ['feature_file_galleries'], 4460 'scope' => 'object', 4461 ], 4462 [ 4463 'name' => 'tiki_p_list_file_galleries', 4464 'description' => tra('Can list file galleries'), 4465 'level' => 'basic', 4466 'type' => 'file galleries', 4467 'admin' => false, 4468 'prefs' => ['feature_file_galleries'], 4469 'scope' => 'object', 4470 ], 4471 [ 4472 'name' => 'tiki_p_view_file_gallery', 4473 'description' => tra('Can view file galleries'), 4474 'level' => 'basic', 4475 'type' => 'file galleries', 4476 'admin' => false, 4477 'prefs' => ['feature_file_galleries'], 4478 'scope' => 'object', 4479 ], 4480 [ 4481 'name' => 'tiki_p_admin_file_galleries', 4482 'description' => tra('Can admin file galleries'), 4483 'level' => 'admin', 4484 'type' => 'file galleries', 4485 'admin' => true, 4486 'prefs' => ['feature_file_galleries'], 4487 'scope' => 'object', 4488 ], 4489 [ 4490 'name' => 'tiki_p_assign_perm_file_gallery', 4491 'description' => tra('Can assign permissions to file galleries'), 4492 'level' => 'admin', 4493 'type' => 'file galleries', 4494 'admin' => false, 4495 'prefs' => ['feature_file_galleries'], 4496 'scope' => 'object', 4497 ], 4498 [ 4499 'name' => 'tiki_p_batch_upload_file_dir', 4500 'description' => tra('Can use Directory Batch Load'), 4501 'level' => 'editors', 4502 'type' => 'file galleries', 4503 'admin' => false, 4504 'prefs' => ['feature_file_galleries_batch'], 4505 'scope' => 'object', 4506 ], 4507 [ 4508 'name' => 'tiki_p_batch_upload_files', 4509 'description' => tra('Can upload .zip file packages'), 4510 'level' => 'editors', 4511 'type' => 'file galleries', 4512 'admin' => false, 4513 'prefs' => ['feature_file_galleries'], 4514 'scope' => 'object', 4515 ], 4516 [ 4517 'name' => 'tiki_p_create_file_galleries', 4518 'description' => tra('Can create file galleries'), 4519 'level' => 'editors', 4520 'type' => 'file galleries', 4521 'admin' => false, 4522 'prefs' => ['feature_file_galleries'], 4523 'scope' => 'object', 4524 ], 4525 [ 4526 'name' => 'tiki_p_edit_gallery_file', 4527 'description' => tra('Can edit a gallery file'), 4528 'level' => 'editors', 4529 'type' => 'file galleries', 4530 'admin' => false, 4531 'prefs' => ['feature_file_galleries'], 4532 'scope' => 'object', 4533 ], 4534 [ 4535 'name' => 'tiki_p_remove_files', 4536 'description' => tra('Can remove files'), 4537 'level' => 'registered', 4538 'type' => 'file galleries', 4539 'admin' => false, 4540 'prefs' => ['feature_file_galleries'], 4541 'scope' => 'object', 4542 ], 4543 [ 4544 'name' => 'tiki_p_view_fgal_explorer', 4545 'description' => tra('Can view file galleries explorer'), 4546 'level' => 'basic', 4547 'type' => 'file galleries', 4548 'admin' => false, 4549 'prefs' => ['fgal_show_explorer'], 4550 'scope' => 'object', 4551 ], 4552 [ 4553 'name' => 'tiki_p_view_fgal_path', 4554 'description' => tra('Can view file galleries path'), 4555 'level' => 'basic', 4556 'type' => 'file galleries', 4557 'admin' => false, 4558 'prefs' => ['fgal_show_path'], 4559 'scope' => 'object', 4560 ], 4561 [ 4562 'name' => 'tiki_p_upload_javascript', 4563 'description' => tra('Can upload files containing JavaScript'), 4564 'level' => 'admin', 4565 'type' => 'file galleries', 4566 'admin' => false, 4567 'prefs' => ['feature_file_galleries'], 4568 'scope' => 'object', 4569 ], 4570 [ 4571 'name' => 'tiki_p_upload_svg', 4572 'description' => tra('Can upload SVG files'), 4573 'level' => 'admin', 4574 'type' => 'file galleries', 4575 'admin' => false, 4576 'prefs' => ['fgal_allow_svg'], 4577 'scope' => 'object', 4578 ], 4579 [ 4580 'name' => 'tiki_p_admin_forum', 4581 'description' => tra('Can admin forums'), 4582 'level' => 'admin', 4583 'type' => 'forums', 4584 'admin' => true, 4585 'prefs' => ['feature_forums'], 4586 'scope' => 'object', 4587 ], 4588 [ 4589 'name' => 'tiki_p_forum_attach', 4590 'description' => tra('Can attach files to forum posts'), 4591 'level' => 'registered', 4592 'type' => 'forums', 4593 'admin' => false, 4594 'prefs' => ['feature_forums'], 4595 'scope' => 'object', 4596 ], 4597 [ 4598 'name' => 'tiki_p_forum_autoapp', 4599 'description' => tra('Auto approve forum posts'), 4600 'level' => 'editors', 4601 'type' => 'forums', 4602 'admin' => false, 4603 'prefs' => ['feature_forums'], 4604 'scope' => 'object', 4605 ], 4606 [ 4607 'name' => 'tiki_p_forum_edit_own_posts', 4608 'description' => tra("Can edit one's own forum posts"), 4609 'level' => 'registered', 4610 'type' => 'forums', 4611 'admin' => false, 4612 'prefs' => ['feature_forums'], 4613 'scope' => 'object', 4614 ], 4615 [ 4616 'name' => 'tiki_p_forum_post', 4617 'description' => tra('Can post in forums'), 4618 'level' => 'registered', 4619 'type' => 'forums', 4620 'admin' => false, 4621 'prefs' => ['feature_forums'], 4622 'scope' => 'object', 4623 ], 4624 [ 4625 'name' => 'tiki_p_forum_post_topic', 4626 'description' => tra('Can start threads in forums'), 4627 'level' => 'registered', 4628 'type' => 'forums', 4629 'admin' => false, 4630 'prefs' => ['feature_forums'], 4631 'scope' => 'object', 4632 ], 4633 [ 4634 'name' => 'tiki_p_forum_read', 4635 'description' => tra('Can read forums'), 4636 'level' => 'basic', 4637 'type' => 'forums', 4638 'admin' => false, 4639 'prefs' => ['feature_forums'], 4640 'scope' => 'object', 4641 ], 4642 [ 4643 'name' => 'tiki_p_forums_report', 4644 'description' => tra('Can report posts to moderator'), 4645 'level' => 'registered', 4646 'type' => 'forums', 4647 'admin' => false, 4648 'prefs' => ['feature_forums'], 4649 'scope' => 'object', 4650 ], 4651 [ 4652 'name' => 'tiki_p_forum_vote', 4653 'description' => tra('Can vote on comments in forums'), 4654 'level' => 'registered', 4655 'type' => 'forums', 4656 'admin' => false, 4657 'prefs' => ['feature_forums'], 4658 'scope' => 'object', 4659 ], 4660 [ 4661 'name' => 'tiki_p_view_freetags', 4662 'description' => tra('Can browse tags'), 4663 'level' => 'basic', 4664 'type' => 'freetags', 4665 'admin' => false, 4666 'prefs' => ['feature_freetags'], 4667 'scope' => 'object', 4668 ], 4669 [ 4670 'name' => 'tiki_p_admin_freetags', 4671 'description' => tra('Can admin tags'), 4672 'level' => 'admin', 4673 'type' => 'freetags', 4674 'admin' => true, 4675 'prefs' => ['feature_freetags'], 4676 'scope' => 'object', 4677 ], 4678 [ 4679 'name' => 'tiki_p_freetags_tag', 4680 'description' => tra('Can tag objects'), 4681 'level' => 'registered', 4682 'type' => 'freetags', 4683 'admin' => false, 4684 'prefs' => ['feature_freetags'], 4685 'scope' => 'object', 4686 ], 4687 [ 4688 'name' => 'tiki_p_unassign_freetags', 4689 'description' => tra('Can unassign tags from an object'), 4690 'level' => 'basic', 4691 'type' => 'freetags', 4692 'admin' => false, 4693 'prefs' => ['feature_freetags'], 4694 'scope' => 'object', 4695 ], 4696 [ 4697 'name' => 'tiki_p_subscribe_groups', 4698 'description' => tra('Can subscribe to groups'), 4699 'level' => 'registered', 4700 'type' => 'group', 4701 'admin' => false, 4702 'prefs' => [], 4703 'scope' => 'global', 4704 ], 4705 [ 4706 'name' => 'tiki_p_invite_to_my_groups', 4707 'description' => tra('Can invite user to my groups'), 4708 'level' => 'editors', 4709 'type' => 'group', 4710 'admin' => false, 4711 'prefs' => [], 4712 'scope' => 'global', 4713 ], 4714 [ 4715 'name' => 'tiki_p_group_view', 4716 'description' => tra('Can view the group'), 4717 'level' => 'basic', 4718 'type' => 'group', 4719 'admin' => false, 4720 'prefs' => [], 4721 'scope' => 'object', 4722 ], 4723 [ 4724 'name' => 'tiki_p_group_view_members', 4725 'description' => tra('Can view the group members'), 4726 'level' => 'basic', 4727 'type' => 'group', 4728 'admin' => false, 4729 'prefs' => [], 4730 'scope' => 'object', 4731 ], 4732 [ 4733 'name' => 'tiki_p_group_add_member', 4734 'description' => tra('Can add group members'), 4735 'level' => 'admin', 4736 'type' => 'group', 4737 'admin' => false, 4738 'prefs' => [], 4739 'scope' => 'object', 4740 ], 4741 [ 4742 'name' => 'tiki_p_group_remove_member', 4743 'description' => tra('Can remove group members'), 4744 'level' => 'admin', 4745 'type' => 'group', 4746 'admin' => false, 4747 'prefs' => [], 4748 'scope' => 'object', 4749 ], 4750 [ 4751 'name' => 'tiki_p_group_join', 4752 'description' => tra('Can join or leave the group'), 4753 'level' => 'admin', 4754 'type' => 'group', 4755 'admin' => false, 4756 'prefs' => [], 4757 'scope' => 'object', 4758 ], 4759 [ 4760 'name' => 'tiki_p_h5p_view', 4761 'description' => tra('Can view H5P content'), 4762 'level' => 'registered', 4763 'type' => 'h5p', 4764 'admin' => false, 4765 'prefs' => ['h5p_enabled'], 4766 'scope' => 'global', // adding as global to start with, probably will need to be object type eventually? 4767 ], 4768 [ 4769 'name' => 'tiki_p_h5p_edit', 4770 'description' => tra('Can edit H5P content'), 4771 'level' => 'editors', 4772 'type' => 'h5p', 4773 'admin' => false, 4774 'prefs' => ['h5p_enabled'], 4775 'scope' => 'global', 4776 ], 4777 [ 4778 'name' => 'tiki_p_h5p_admin', 4779 'description' => tra('Can administer H5P content'), 4780 'level' => 'admins', 4781 'type' => 'h5p', 4782 'admin' => false, 4783 'prefs' => ['h5p_enabled'], 4784 'scope' => 'global', 4785 ], 4786 [ 4787 'name' => 'tiki_p_edit_html_pages', 4788 'description' => tra('Can edit HTML pages'), 4789 'level' => 'editors', 4790 'type' => 'html pages', 4791 'admin' => false, 4792 'prefs' => ['feature_html_pages'], 4793 'scope' => 'global', 4794 ], 4795 [ 4796 'name' => 'tiki_p_view_html_pages', 4797 'description' => tra('Can view HTML pages'), 4798 'level' => 'basic', 4799 'type' => 'html pages', 4800 'admin' => false, 4801 'prefs' => ['feature_html_pages'], 4802 'scope' => 'global', 4803 ], 4804 [ 4805 'name' => 'tiki_p_admin_galleries', 4806 'description' => tra('Can admin Image Galleries'), 4807 'level' => 'editors', 4808 'type' => 'image galleries', 4809 'admin' => true, 4810 'prefs' => ['feature_galleries'], 4811 'scope' => 'object', 4812 ], 4813 [ 4814 'name' => 'tiki_p_assign_perm_image_gallery', 4815 'description' => tra('Can assign permissions to image galleries'), 4816 'level' => 'admin', 4817 'type' => 'image galleries', 4818 'admin' => false, 4819 'prefs' => ['feature_galleries'], 4820 'scope' => 'object', 4821 ], 4822 [ 4823 'name' => 'tiki_p_batch_upload_image_dir', 4824 'description' => tra('Can use Directory Batch Load'), 4825 'level' => 'editors', 4826 'type' => 'image galleries', 4827 'admin' => false, 4828 'prefs' => ['feature_galleries'], 4829 'scope' => 'object', 4830 ], 4831 [ 4832 'name' => 'tiki_p_batch_upload_images', 4833 'description' => tra('Can upload .zip files of images'), 4834 'level' => 'editors', 4835 'type' => 'image galleries', 4836 'admin' => false, 4837 'prefs' => ['feature_galleries'], 4838 'scope' => 'object', 4839 ], 4840 [ 4841 'name' => 'tiki_p_create_galleries', 4842 'description' => tra('Can create image galleries'), 4843 'level' => 'editors', 4844 'type' => 'image galleries', 4845 'admin' => false, 4846 'prefs' => ['feature_galleries'], 4847 'scope' => 'global', 4848 ], 4849 [ 4850 'name' => 'tiki_p_list_image_galleries', 4851 'description' => tra('Can list image galleries'), 4852 'level' => 'basic', 4853 'type' => 'image galleries', 4854 'admin' => false, 4855 'prefs' => ['feature_galleries'], 4856 'scope' => 'global', 4857 ], 4858 [ 4859 'name' => 'tiki_p_upload_images', 4860 'description' => tra('Can upload images'), 4861 'level' => 'registered', 4862 'type' => 'image galleries', 4863 'admin' => false, 4864 'prefs' => ['feature_galleries'], 4865 'scope' => 'object', 4866 ], 4867 [ 4868 'name' => 'tiki_p_view_image_gallery', 4869 'description' => tra('Can view image galleries'), 4870 'level' => 'basic', 4871 'type' => 'image galleries', 4872 'admin' => false, 4873 'prefs' => ['feature_galleries'], 4874 'scope' => 'object', 4875 ], 4876 [ 4877 'name' => 'tiki_p_admin_kaltura', 4878 'description' => tra('Can admin Kaltura video feature'), 4879 'level' => 'admin', 4880 'type' => 'media', 4881 'admin' => true, 4882 'prefs' => ['feature_kaltura'], 4883 'scope' => 'global', 4884 ], 4885 [ 4886 'name' => 'tiki_p_upload_videos', 4887 'description' => tra('Can upload video or record from webcam'), 4888 'level' => 'editors', 4889 'type' => 'media', 4890 'admin' => false, 4891 'prefs' => ['feature_kaltura'], 4892 'scope' => 'global', 4893 ], 4894 [ 4895 'name' => 'tiki_p_edit_videos', 4896 'description' => tra('Can edit media information'), 4897 'level' => 'editors', 4898 'type' => 'media', 4899 'admin' => false, 4900 'prefs' => ['feature_kaltura'], 4901 'scope' => 'global', 4902 ], 4903 [ 4904 'name' => 'tiki_p_delete_videos', 4905 'description' => tra('Can delete media'), 4906 'level' => 'editors', 4907 'type' => 'media', 4908 'admin' => false, 4909 'prefs' => ['feature_kaltura'], 4910 'scope' => 'global', 4911 ], 4912 [ 4913 'name' => 'tiki_p_download_videos', 4914 'description' => tra('Can download media'), 4915 'level' => 'registered', 4916 'type' => 'media', 4917 'admin' => false, 4918 'prefs' => ['feature_kaltura'], 4919 'scope' => 'global', 4920 ], 4921 [ 4922 'name' => 'tiki_p_list_videos', 4923 'description' => tra('Can list media'), 4924 'level' => 'basic', 4925 'type' => 'media', 4926 'admin' => false, 4927 'prefs' => ['feature_kaltura'], 4928 'scope' => 'global', 4929 ], 4930 [ 4931 'name' => 'tiki_p_view_videos', 4932 'description' => tra('Can view media'), 4933 'level' => 'basic', 4934 'type' => 'media', 4935 'admin' => false, 4936 'prefs' => ['feature_kaltura'], 4937 'scope' => 'global', 4938 ], 4939 [ 4940 'name' => 'tiki_p_broadcast_all', 4941 'description' => tra('Can broadcast messages to all users'), 4942 'level' => 'admin', 4943 'type' => 'messages', 4944 'admin' => false, 4945 'prefs' => ['feature_messages'], 4946 'scope' => 'global', 4947 ], 4948 [ 4949 'name' => 'tiki_p_broadcast', 4950 'description' => tra('Can broadcast messages to groups'), 4951 'level' => 'admin', 4952 'type' => 'group', 4953 'admin' => false, 4954 'prefs' => ['feature_messages'], 4955 'scope' => 'object', 4956 ], 4957 [ 4958 'name' => 'tiki_p_messages', 4959 'description' => tra('Can use the messaging system'), 4960 'level' => 'registered', 4961 'type' => 'messages', 4962 'admin' => false, 4963 'prefs' => ['feature_messages'], 4964 'scope' => 'global', 4965 ], 4966 [ 4967 'name' => 'tiki_p_admin_newsletters', 4968 'description' => tra('Can admin newsletters'), 4969 'level' => 'admin', 4970 'type' => 'newsletters', 4971 'admin' => true, 4972 'prefs' => ['feature_newsletters'], 4973 'scope' => 'object', 4974 ], 4975 [ 4976 'name' => 'tiki_p_batch_subscribe_email', 4977 'description' => tra('Can subscribe multiple email addresses at once (requires tiki_p_subscribe email)'), 4978 'level' => 'editors', 4979 'type' => 'newsletters', 4980 'admin' => false, 4981 'prefs' => ['feature_newsletters'], 4982 'scope' => 'global', 4983 ], 4984 [ 4985 'name' => 'tiki_p_send_newsletters', 4986 'description' => tra('Can send newsletters'), 4987 'level' => 'editors', 4988 'type' => 'newsletters', 4989 'admin' => false, 4990 'prefs' => ['feature_newsletters'], 4991 'scope' => 'object', 4992 ], 4993 [ 4994 'name' => 'tiki_p_subscribe_email', 4995 'description' => tra('Can subscribe any email address to newsletters'), 4996 'level' => 'editors', 4997 'type' => 'newsletters', 4998 'admin' => false, 4999 'prefs' => ['feature_newsletters'], 5000 'scope' => 'global', 5001 ], 5002 [ 5003 'name' => 'tiki_p_subscribe_newsletters', 5004 'description' => tra('Can subscribe to newsletters'), 5005 'level' => 'basic', 5006 'type' => 'newsletters', 5007 'admin' => false, 5008 'prefs' => ['feature_newsletters'], 5009 'scope' => 'object', 5010 ], 5011 [ 5012 'name' => 'tiki_p_view_newsletter', 5013 'description' => tra('Can view the archive of a newsletters'), 5014 'level' => 'basic', 5015 'type' => 'newsletters', 5016 'admin' => false, 5017 'prefs' => ['feature_newsletters'], 5018 'scope' => 'object', 5019 ], 5020 [ 5021 'name' => 'tiki_p_list_newsletters', 5022 'description' => tra('Can list newsletters'), 5023 'level' => 'basic', 5024 'type' => 'newsletters', 5025 'admin' => false, 5026 'prefs' => ['feature_newsletters'], 5027 'scope' => 'global', 5028 ], 5029 [ 5030 'name' => 'tiki_p_payment_admin', 5031 'description' => tra('Can administer payments'), 5032 'level' => 'admin', 5033 'type' => 'payment', 5034 'admin' => true, 5035 'prefs' => ['payment_feature'], 5036 'scope' => 'global', 5037 ], 5038 [ 5039 'name' => 'tiki_p_payment_view', 5040 'description' => tra('Can view payment requests and details'), 5041 'level' => 'admin', 5042 'type' => 'payment', 5043 'admin' => false, 5044 'prefs' => ['payment_feature'], 5045 'scope' => 'object', 5046 ], 5047 [ 5048 'name' => 'tiki_p_payment_manual', 5049 'description' => tra('Can enter manual payments'), 5050 'level' => 'admin', 5051 'type' => 'payment', 5052 'admin' => false, 5053 'prefs' => ['payment_feature'], 5054 'scope' => 'object', 5055 ], 5056 [ 5057 'name' => 'tiki_p_payment_request', 5058 'description' => tra('Can request a payment'), 5059 'level' => 'admin', 5060 'type' => 'payment', 5061 'admin' => false, 5062 'prefs' => ['payment_feature'], 5063 'scope' => 'object', 5064 ], 5065 [ 5066 'name' => 'tiki_p_perspective_view', 5067 'description' => tra('Can view the perspective'), 5068 'level' => 'basic', 5069 'type' => 'perspective', 5070 'admin' => false, 5071 'prefs' => ['feature_perspective'], 5072 'scope' => 'object', 5073 ], 5074 [ 5075 'name' => 'tiki_p_perspective_edit', 5076 'description' => tra('Can edit the perspective'), 5077 'level' => 'basic', 5078 'type' => 'perspective', 5079 'admin' => false, 5080 'prefs' => ['feature_perspective'], 5081 'scope' => 'object', 5082 ], 5083 [ 5084 'name' => 'tiki_p_perspective_create', 5085 'description' => tra('Can create a perspective'), 5086 'level' => 'basic', 5087 'type' => 'perspective', 5088 'admin' => false, 5089 'prefs' => ['feature_perspective'], 5090 'scope' => 'global', 5091 ], 5092 [ 5093 'name' => 'tiki_p_perspective_admin', 5094 'description' => tra('Can admin perspectives'), 5095 'level' => 'admin', 5096 'type' => 'perspective', 5097 'admin' => true, 5098 'prefs' => ['feature_perspective'], 5099 'scope' => 'object', 5100 ], 5101 [ 5102 'name' => 'tiki_p_admin_polls', 5103 'description' => tra('Can admin polls'), 5104 'level' => 'admin', 5105 'type' => 'polls', 5106 'admin' => true, 5107 'prefs' => ['feature_polls'], 5108 'scope' => 'global', 5109 ], 5110 [ 5111 'name' => 'tiki_p_view_poll_results', 5112 'description' => tra('Can view poll results'), 5113 'level' => 'basic', 5114 'type' => 'polls', 5115 'admin' => false, 5116 'prefs' => ['feature_polls'], 5117 'scope' => 'global', 5118 ], 5119 [ 5120 'name' => 'tiki_p_view_poll_choices', 5121 'description' => tra('Can view poll user choices'), 5122 'level' => 'basic', 5123 'type' => 'polls', 5124 'admin' => false, 5125 'prefs' => ['feature_polls'], 5126 'scope' => 'object', 5127 ], 5128 [ 5129 'name' => 'tiki_p_vote_poll', 5130 'description' => tra('Can vote in polls'), 5131 'level' => 'basic', 5132 'type' => 'polls', 5133 'admin' => false, 5134 'prefs' => ['feature_polls'], 5135 'scope' => 'object', 5136 ], 5137 [ 5138 'name' => 'tiki_p_view_poll_voters', 5139 'description' => tra('Can view poll voters'), 5140 'level' => 'basic', 5141 'type' => 'polls', 5142 'admin' => false, 5143 'prefs' => ['feature_polls'], 5144 'scope' => 'object', 5145 ], 5146 [ 5147 'name' => 'tiki_p_admin_quizzes', 5148 'description' => tra('Can admin quizzes'), 5149 'level' => 'editors', 5150 'type' => 'quizzes', 5151 'admin' => true, 5152 'prefs' => ['feature_quizzes'], 5153 'scope' => 'global', 5154 ], 5155 [ 5156 'name' => 'tiki_p_take_quiz', 5157 'description' => tra('Can take quizzes'), 5158 'level' => 'basic', 5159 'type' => 'quizzes', 5160 'admin' => false, 5161 'prefs' => ['feature_quizzes'], 5162 'scope' => 'global', 5163 ], 5164 [ 5165 'name' => 'tiki_p_view_quiz_stats', 5166 'description' => tra('Can view quiz stats'), 5167 'level' => 'basic', 5168 'type' => 'quizzes', 5169 'admin' => false, 5170 'prefs' => ['feature_quizzes'], 5171 'scope' => 'global', 5172 ], 5173 [ 5174 'name' => 'tiki_p_view_user_results', 5175 'description' => tra('Can view user quiz results'), 5176 'level' => 'editors', 5177 'type' => 'quizzes', 5178 'admin' => false, 5179 'prefs' => ['feature_quizzes'], 5180 'scope' => 'global', 5181 ], 5182 [ 5183 'name' => 'tiki_p_admin_sheet', 5184 'description' => tra('Can admin spreadsheets'), 5185 'level' => 'admin', 5186 'type' => 'sheet', 5187 'admin' => true, 5188 'prefs' => ['feature_sheet'], 5189 'scope' => 'object', 5190 ], 5191 [ 5192 'name' => 'tiki_p_edit_sheet', 5193 'description' => tra('Can create and edit spreadsheets'), 5194 'level' => 'editors', 5195 'type' => 'sheet', 5196 'admin' => false, 5197 'prefs' => ['feature_sheet'], 5198 'scope' => 'object', 5199 ], 5200 [ 5201 'name' => 'tiki_p_view_sheet', 5202 'description' => tra('Can view spreadsheets'), 5203 'level' => 'basic', 5204 'type' => 'sheet', 5205 'admin' => false, 5206 'prefs' => ['feature_sheet'], 5207 'scope' => 'object', 5208 ], 5209 [ 5210 'name' => 'tiki_p_view_sheet_history', 5211 'description' => tra('Can view spreadsheets history'), 5212 'level' => 'admin', 5213 'type' => 'sheet', 5214 'admin' => false, 5215 'prefs' => ['feature_sheet'], 5216 'scope' => 'object', 5217 ], 5218 [ 5219 'name' => 'tiki_p_admin_shoutbox', 5220 'description' => tra('Can admin the shoutbox (edit/remove messages)'), 5221 'level' => 'editors', 5222 'type' => 'shoutbox', 5223 'admin' => true, 5224 'prefs' => ['feature_shoutbox'], 5225 'scope' => 'global', 5226 ], 5227 [ 5228 'name' => 'tiki_p_post_shoutbox', 5229 'description' => tra('Can post messages in the shoutbox'), 5230 'level' => 'basic', 5231 'type' => 'shoutbox', 5232 'admin' => false, 5233 'prefs' => ['feature_shoutbox'], 5234 'scope' => 'global', 5235 ], 5236 [ 5237 'name' => 'tiki_p_view_shoutbox', 5238 'description' => tra('Can view the shoutbox'), 5239 'level' => 'basic', 5240 'type' => 'shoutbox', 5241 'admin' => false, 5242 'prefs' => ['feature_shoutbox'], 5243 'scope' => 'global', 5244 ], 5245 [ 5246 'name' => 'tiki_p_socialnetworks', 5247 'description' => tra('Can use social network integration'), 5248 'level' => 'registered', 5249 'type' => 'socialnetworks', 5250 'admin' => false, 5251 'prefs' => ['feature_socialnetworks'], 5252 'scope' => 'global', 5253 ], 5254 [ 5255 'name' => 'tiki_p_admin_socialnetworks', 5256 'description' => tra('Can register this site with social networks'), 5257 'level' => 'admin', 5258 'type' => 'socialnetworks', 5259 'admin' => true, 5260 'prefs' => ['feature_socialnetworks'], 5261 'scope' => 'global', 5262 ], 5263 [ 5264 'name' => 'tiki_p_live_support_admin', 5265 'description' => tra('Admin live support system'), 5266 'level' => 'admin', 5267 'type' => 'support', 5268 'admin' => true, 5269 'prefs' => ['feature_live_support'], 5270 'scope' => 'global', 5271 ], 5272 [ 5273 'name' => 'tiki_p_live_support', 5274 'description' => tra('Can use live support system'), 5275 'level' => 'basic', 5276 'type' => 'support', 5277 'admin' => false, 5278 'prefs' => ['feature_live_support'], 5279 'scope' => 'global', 5280 ], 5281 [ 5282 'name' => 'tiki_p_admin_surveys', 5283 'description' => tra('Can admin surveys'), 5284 'level' => 'editors', 5285 'type' => 'surveys', 5286 'admin' => true, 5287 'prefs' => ['feature_surveys'], 5288 'scope' => 'global', 5289 ], 5290 [ 5291 'name' => 'tiki_p_take_survey', 5292 'description' => tra('Can take surveys'), 5293 'level' => 'basic', 5294 'type' => 'surveys', 5295 'admin' => false, 5296 'prefs' => ['feature_surveys'], 5297 'scope' => 'object', 5298 ], 5299 [ 5300 'name' => 'tiki_p_view_survey_stats', 5301 'description' => tra('Can view survey stats'), 5302 'level' => 'basic', 5303 'type' => 'surveys', 5304 'admin' => false, 5305 'prefs' => ['feature_surveys'], 5306 'scope' => 'object', 5307 ], 5308 [ 5309 'name' => 'tiki_p_admin_tikitests', 5310 'description' => tra('Can admin TikiTests'), 5311 'level' => 'admin', 5312 'type' => 'tikitests', 5313 'admin' => false, 5314 'prefs' => ['feature_tikitests'], 5315 'scope' => 'global', 5316 ], 5317 [ 5318 'name' => 'tiki_p_edit_tikitests', 5319 'description' => tra('Can edit TikiTests'), 5320 'level' => 'editors', 5321 'type' => 'tikitests', 5322 'admin' => false, 5323 'prefs' => ['feature_tikitests'], 5324 'scope' => 'global', 5325 ], 5326 [ 5327 'name' => 'tiki_p_play_tikitests', 5328 'description' => tra('Can replay TikiTests'), 5329 'level' => 'registered', 5330 'type' => 'tikitests', 5331 'admin' => false, 5332 'prefs' => ['feature_tikitests'], 5333 'scope' => 'global', 5334 ], 5335 [ 5336 'name' => 'tiki_p_admin_trackers', 5337 'description' => tra('Can admin trackers'), 5338 'level' => 'admin', 5339 'type' => 'trackers', 5340 'admin' => true, 5341 'prefs' => ['feature_trackers'], 5342 'scope' => 'object', 5343 ], 5344 [ 5345 'name' => 'tiki_p_attach_trackers', 5346 'description' => tra('Can attach files to tracker items'), 5347 'level' => 'registered', 5348 'type' => 'trackers', 5349 'admin' => false, 5350 'prefs' => ['feature_trackers'], 5351 'scope' => 'object', 5352 ], 5353 [ 5354 'name' => 'tiki_p_tracker_view_attachments', 5355 'description' => tra('Can view tracker item attachments and download them'), 5356 'level' => 'registered', 5357 'type' => 'trackers', 5358 'admin' => false, 5359 'prefs' => ['feature_trackers'], 5360 'scope' => 'object', 5361 ], 5362 [ 5363 'name' => 'tiki_p_comment_tracker_items', 5364 'description' => tra('Can post tracker item comments'), 5365 'level' => 'basic', 5366 'type' => 'trackers', 5367 'admin' => false, 5368 'prefs' => ['feature_trackers'], 5369 'scope' => 'object', 5370 ], 5371 [ 5372 'name' => 'tiki_p_tracker_view_comments', 5373 'description' => tra('Can view tracker item comments'), 5374 'level' => 'basic', 5375 'type' => 'trackers', 5376 'admin' => false, 5377 'prefs' => ['feature_trackers'], 5378 'scope' => 'object', 5379 ], 5380 [ 5381 'name' => 'tiki_p_create_tracker_items', 5382 'description' => tra('Can create new tracker items'), 5383 'level' => 'registered', 5384 'type' => 'trackers', 5385 'admin' => false, 5386 'prefs' => ['feature_trackers'], 5387 'scope' => 'object', 5388 ], 5389 [ 5390 'name' => 'tiki_p_list_trackers', 5391 'description' => tra('Can list trackers'), 5392 'level' => 'basic', 5393 'type' => 'trackers', 5394 'admin' => false, 5395 'prefs' => ['feature_trackers'], 5396 'scope' => 'global', 5397 ], 5398 [ 5399 'name' => 'tiki_p_modify_tracker_items', 5400 'description' => tra('Can change tracker items'), 5401 'level' => 'registered', 5402 'type' => 'trackers', 5403 'admin' => false, 5404 'prefs' => ['feature_trackers'], 5405 'scope' => 'object', 5406 ], 5407 [ 5408 'name' => 'tiki_p_modify_tracker_items_pending', 5409 'description' => tra('Can change pending tracker items'), 5410 'level' => 'registered', 5411 'type' => 'trackers', 5412 'admin' => false, 5413 'prefs' => ['feature_trackers'], 5414 'scope' => 'object', 5415 ], 5416 [ 5417 'name' => 'tiki_p_modify_tracker_items_closed', 5418 'description' => tra('Can change closed tracker items'), 5419 'level' => 'registered', 5420 'type' => 'trackers', 5421 'admin' => false, 5422 'prefs' => ['feature_trackers'], 5423 'scope' => 'object', 5424 ], 5425 [ 5426 'name' => 'tiki_p_remove_tracker_items', 5427 'description' => tra('Can remove tracker items'), 5428 'level' => 'registered', 5429 'type' => 'trackers', 5430 'admin' => false, 5431 'prefs' => ['feature_trackers'], 5432 'scope' => 'object', 5433 ], 5434 [ 5435 'name' => 'tiki_p_remove_tracker_items_pending', 5436 'description' => tra('Can remove pending tracker items'), 5437 'level' => 'registered', 5438 'type' => 'trackers', 5439 'admin' => false, 5440 'prefs' => ['feature_trackers'], 5441 'scope' => 'object', 5442 ], 5443 [ 5444 'name' => 'tiki_p_remove_tracker_items_closed', 5445 'description' => tra('Can remove closed tracker items'), 5446 'level' => 'registered', 5447 'type' => 'trackers', 5448 'admin' => false, 5449 'prefs' => ['feature_trackers'], 5450 'scope' => 'object', 5451 ], 5452 [ 5453 'name' => 'tiki_p_tracker_view_ratings', 5454 'description' => tra('Can view rating result for tracker items'), 5455 'level' => 'basic', 5456 'type' => 'trackers', 5457 'admin' => false, 5458 'prefs' => ['feature_trackers'], 5459 'scope' => 'object', 5460 ], 5461 [ 5462 'name' => 'tiki_p_tracker_vote_ratings', 5463 'description' => tra('Can rate tracker items'), 5464 'level' => 'registered', 5465 'type' => 'trackers', 5466 'admin' => false, 5467 'prefs' => ['feature_trackers'], 5468 'scope' => 'object', 5469 ], 5470 [ 5471 'name' => 'tiki_p_tracker_revote_ratings', 5472 'description' => tra('Can re-rate tracker items'), 5473 'level' => 'registered', 5474 'type' => 'trackers', 5475 'admin' => false, 5476 'prefs' => ['feature_trackers'], 5477 'scope' => 'object', 5478 ], 5479 [ 5480 'name' => 'tiki_p_view_trackers', 5481 'description' => tra('Can view trackers'), 5482 'level' => 'basic', 5483 'type' => 'trackers', 5484 'admin' => false, 5485 'prefs' => ['feature_trackers'], 5486 'scope' => 'object', 5487 ], 5488 [ 5489 'name' => 'tiki_p_view_trackers_closed', 5490 'description' => tra('Can view closed trackers items'), 5491 'level' => 'registered', 5492 'type' => 'trackers', 5493 'admin' => false, 5494 'prefs' => ['feature_trackers'], 5495 'scope' => 'object', 5496 ], 5497 [ 5498 'name' => 'tiki_p_view_trackers_pending', 5499 'description' => tra('Can view pending trackers items'), 5500 'level' => 'editors', 5501 'type' => 'trackers', 5502 'admin' => false, 5503 'prefs' => ['feature_trackers'], 5504 'scope' => 'object', 5505 ], 5506 [ 5507 'name' => 'tiki_p_watch_trackers', 5508 'description' => tra('Can watch a tracker'), 5509 'level' => 'registered', 5510 'type' => 'trackers', 5511 'admin' => false, 5512 'prefs' => ['feature_trackers'], 5513 'scope' => 'object', 5514 ], 5515 [ 5516 'name' => 'tiki_p_export_tracker', 5517 'description' => tra('Can export tracker items'), 5518 'level' => 'registered', 5519 'type' => 'trackers', 5520 'admin' => false, 5521 'prefs' => ['feature_trackers'], 5522 'scope' => 'object', 5523 ], 5524 [ 5525 'name' => 'tiki_p_tracker_dump', 5526 'description' => tra('Can save a CSV backup of all trackers'), 5527 'level' => 'admin', 5528 'type' => 'trackers', 5529 'admin' => false, 5530 'prefs' => ['feature_trackers'], 5531 'scope' => 'global', 5532 ], 5533 [ 5534 'name' => 'tiki_p_tabular_admin', 5535 'description' => tr('Manage tracker views'), 5536 'level' => 'admin', 5537 'type' => 'tabular', 5538 'admin' => true, 5539 'prefs' => ['tracker_tabular_enabled'], 5540 'scope' => 'object', 5541 ], 5542 [ 5543 'name' => 'tiki_p_tabular_list', 5544 'description' => tr('View list view of tracker tabular data. Tracker item permissions apply.'), 5545 'level' => 'registered', 5546 'type' => 'tabular', 5547 'admin' => false, 5548 'prefs' => ['tracker_tabular_enabled'], 5549 'scope' => 'object', 5550 ], 5551 [ 5552 'name' => 'tiki_p_tabular_export', 5553 'description' => tr('Export a tracker tabular view to CSV. Tracker permissions may not apply.'), 5554 'level' => 'editors', 5555 'type' => 'tabular', 5556 'admin' => false, 5557 'prefs' => ['tracker_tabular_enabled'], 5558 'scope' => 'object', 5559 ], 5560 [ 5561 'name' => 'tiki_p_tabular_import', 5562 'description' => tr('Import a CSV file into a tabular tracker. Tracker permissions may not apply.'), 5563 'level' => 'editors', 5564 'type' => 'tabular', 5565 'admin' => false, 5566 'prefs' => ['tracker_tabular_enabled'], 5567 'scope' => 'object', 5568 ], 5569 [ 5570 'name' => 'tiki_p_trigger_transition', 5571 'description' => tra('Can trigger the transition between two states'), 5572 'level' => 'admin', 5573 'type' => 'transition', 5574 'admin' => false, 5575 'prefs' => ['feature_group_transition', 'feature_category_transition'], 5576 'scope' => 'object', 5577 ], 5578 [ 5579 'name' => 'tiki_p_admin_users', 5580 'description' => tra('Can admin users'), 5581 'level' => 'admin', 5582 'type' => 'user', 5583 'admin' => false, 5584 'prefs' => [], 5585 'scope' => 'global', 5586 ], 5587 [ 5588 'name' => 'tiki_p_cache_bookmarks', 5589 'description' => tra('Can cache user bookmarks'), 5590 'level' => 'admin', 5591 'type' => 'user', 5592 'admin' => false, 5593 'prefs' => ['feature_user_bookmarks'], 5594 'scope' => 'global', 5595 ], 5596 [ 5597 'name' => 'tiki_p_configure_modules', 5598 'description' => tra('Can configure modules'), 5599 'level' => 'registered', 5600 'type' => 'user', 5601 'admin' => false, 5602 'prefs' => ['feature_modulecontrols'], 5603 'scope' => 'global', 5604 ], 5605 [ 5606 'name' => 'tiki_p_create_bookmarks', 5607 'description' => tra('Can create user bookmarks'), 5608 'level' => 'registered', 5609 'type' => 'user', 5610 'admin' => false, 5611 'prefs' => ['feature_user_bookmarks'], 5612 'scope' => 'global', 5613 ], 5614 [ 5615 'name' => 'tiki_p_minical', 5616 'description' => tra('Can use the mini event calendar'), 5617 'level' => 'registered', 5618 'type' => 'user', 5619 'admin' => false, 5620 'prefs' => ['feature_minical'], 5621 'scope' => 'global', 5622 ], 5623 [ 5624 'name' => 'tiki_p_notepad', 5625 'description' => tra('Can use the notepad'), 5626 'level' => 'registered', 5627 'type' => 'user', 5628 'admin' => false, 5629 'prefs' => ['feature_notepad'], 5630 'scope' => 'global', 5631 ], 5632 [ 5633 'name' => 'tiki_p_tasks_admin', 5634 'description' => tra('Can admin public tasks'), 5635 'level' => 'admin', 5636 'type' => 'user', 5637 'admin' => false, 5638 'prefs' => ['feature_tasks'], 5639 'scope' => 'global', 5640 ], 5641 [ 5642 'name' => 'tiki_p_tasks', 5643 'description' => tra('Can use tasks'), 5644 'level' => 'registered', 5645 'type' => 'user', 5646 'admin' => false, 5647 'prefs' => ['feature_tasks'], 5648 'scope' => 'global', 5649 ], 5650 [ 5651 'name' => 'tiki_p_tasks_receive', 5652 'description' => tra('Can receive tasks from other users'), 5653 'level' => 'registered', 5654 'type' => 'user', 5655 'admin' => false, 5656 'prefs' => ['feature_tasks'], 5657 'scope' => 'global', 5658 ], 5659 [ 5660 'name' => 'tiki_p_tasks_send', 5661 'description' => tra('Can send tasks to other users'), 5662 'level' => 'registered', 5663 'type' => 'user', 5664 'admin' => false, 5665 'prefs' => ['feature_tasks'], 5666 'scope' => 'global', 5667 ], 5668 [ 5669 'name' => 'tiki_p_userfiles', 5670 'description' => tra('Can upload personal files'), 5671 'level' => 'registered', 5672 'type' => 'user', 5673 'admin' => false, 5674 'prefs' => ['feature_userfiles'], 5675 'scope' => 'global', 5676 ], 5677 [ 5678 'name' => 'tiki_p_usermenu', 5679 'description' => tra('Can create items in personal menu'), 5680 'level' => 'registered', 5681 'type' => 'user', 5682 'admin' => false, 5683 'prefs' => ['feature_usermenu'], 5684 'scope' => 'global', 5685 ], 5686 [ 5687 'name' => 'tiki_p_list_users', 5688 'description' => tra('Can list registered users'), 5689 'level' => 'registered', 5690 'type' => 'user', 5691 'admin' => false, 5692 'prefs' => [], 5693 'scope' => 'global', 5694 ], 5695 [ 5696 'name' => 'tiki_p_invite', 5697 'description' => tra('Can invite users by email, and include them in groups'), 5698 'level' => 'registered', 5699 'type' => 'user', 5700 'admin' => false, 5701 'prefs' => ['feature_invite'], 5702 'scope' => 'global', 5703 ], 5704 [ 5705 'name' => 'tiki_p_delete_account', 5706 'description' => tra('Can delete his/her own account'), 5707 'level' => 'admin', 5708 'type' => 'user', 5709 'admin' => false, 5710 'prefs' => [], 5711 'scope' => 'global', 5712 ], 5713 [ 5714 'name' => 'tiki_p_use_webmail', 5715 'description' => tra('Can use webmail'), 5716 'level' => 'registered', 5717 'type' => 'webmail', 5718 'admin' => false, 5719 'prefs' => ['feature_webmail', 'feature_contacts'], 5720 'scope' => 'global', 5721 ], 5722 [ 5723 'name' => 'tiki_p_use_group_webmail', 5724 'description' => tra('Can use group webmail'), 5725 'level' => 'registered', 5726 'type' => 'webmail', 5727 'admin' => false, 5728 'prefs' => ['feature_webmail', 'feature_contacts'], 5729 'scope' => 'global', 5730 ], 5731 [ 5732 'name' => 'tiki_p_admin_group_webmail', 5733 'description' => tra('Can admin group webmail accounts'), 5734 'level' => 'admin', 5735 'type' => 'webmail', 5736 'admin' => false, 5737 'prefs' => ['feature_webmail', 'feature_contacts'], 5738 'scope' => 'global', 5739 ], 5740 [ 5741 'name' => 'tiki_p_use_personal_webmail', 5742 'description' => tra('Can use personal webmail accounts'), 5743 'level' => 'registered', 5744 'type' => 'webmail', 5745 'admin' => false, 5746 'prefs' => ['feature_webmail', 'feature_contacts'], 5747 'scope' => 'global', 5748 ], 5749 [ 5750 'name' => 'tiki_p_admin_personal_webmail', 5751 'description' => tra('Can admin personal webmail accounts'), 5752 'level' => 'registered', 5753 'type' => 'webmail', 5754 'admin' => false, 5755 'prefs' => ['feature_webmail', 'feature_contacts'], 5756 'scope' => 'global', 5757 ], 5758 [ 5759 'name' => 'tiki_p_view', 5760 'description' => tra('Can view page/pages'), 5761 'level' => 'basic', 5762 'type' => 'wiki', 5763 'admin' => false, 5764 'prefs' => ['feature_wiki'], 5765 'scope' => 'object', 5766 ], 5767 [ 5768 'name' => 'tiki_p_edit', 5769 'description' => tra('Can edit pages'), 5770 'level' => 'registered', 5771 'type' => 'wiki', 5772 'admin' => false, 5773 'prefs' => ['feature_wiki'], 5774 'scope' => 'object', 5775 ], 5776 [ 5777 'name' => 'tiki_p_edit_inline', 5778 'description' => tra('Can inline-edit pages'), 5779 'level' => 'registered', 5780 'type' => 'wiki', 5781 'admin' => false, 5782 'prefs' => ['feature_wiki'], 5783 'scope' => 'object', 5784 ], 5785 [ 5786 'name' => 'tiki_p_wiki_view_history', 5787 'description' => tra('Can view wiki history'), 5788 'level' => 'basic', 5789 'type' => 'wiki', 5790 'admin' => false, 5791 'prefs' => ['feature_history'], 5792 'scope' => 'object', 5793 ], 5794 [ 5795 'name' => 'tiki_p_admin_wiki', 5796 'description' => tra('Can admin the wiki'), 5797 'level' => 'admin', 5798 'type' => 'wiki', 5799 'admin' => true, 5800 'prefs' => ['feature_wiki'], 5801 'scope' => 'object', 5802 ], 5803 [ 5804 'name' => 'tiki_p_assign_perm_wiki_page', 5805 'description' => tra('Can assign permissions to wiki pages'), 5806 'level' => 'admin', 5807 'type' => 'wiki', 5808 'admin' => false, 5809 'prefs' => ['feature_wiki'], 5810 'scope' => 'object', 5811 ], 5812 [ 5813 'name' => 'tiki_p_edit_copyrights', 5814 'description' => tra('Can edit copyright notices'), 5815 'level' => 'editors', 5816 'type' => 'wiki', 5817 'admin' => false, 5818 'prefs' => ['wiki_feature_copyrights'], 5819 'scope' => 'object', 5820 ], 5821 [ 5822 'name' => 'tiki_p_edit_dynvar', 5823 'description' => tra('Can edit dynamic variables'), 5824 'level' => 'editors', 5825 'type' => 'wiki', 5826 'admin' => false, 5827 'prefs' => ['feature_wiki'], 5828 'scope' => 'global', 5829 ], 5830 [ 5831 'name' => 'tiki_p_export_wiki', 5832 'description' => tra('Can export wiki pages using the export feature'), 5833 'level' => 'admin', 5834 'type' => 'wiki', 5835 'admin' => false, 5836 'prefs' => ['feature_wiki_export'], 5837 'scope' => 'object', 5838 ], 5839 [ 5840 'name' => 'tiki_p_lock', 5841 'description' => tra('Can lock pages'), 5842 'level' => 'editors', 5843 'type' => 'wiki', 5844 'admin' => false, 5845 'prefs' => ['feature_wiki_usrlock'], 5846 'scope' => 'object', 5847 ], 5848 [ 5849 'name' => 'tiki_p_minor', 5850 'description' => tra('Can save as a minor edit'), 5851 'level' => 'registered', 5852 'type' => 'wiki', 5853 'admin' => false, 5854 'prefs' => ['wiki_edit_minor'], 5855 'scope' => 'object', 5856 ], 5857 [ 5858 'name' => 'tiki_p_remove', 5859 'description' => tra('Can remove'), 5860 'level' => 'editors', 5861 'type' => 'wiki', 5862 'admin' => false, 5863 'prefs' => ['feature_wiki'], 5864 'scope' => 'object', 5865 ], 5866 [ 5867 'name' => 'tiki_p_rename', 5868 'description' => tra('Can rename pages'), 5869 'level' => 'editors', 5870 'type' => 'wiki', 5871 'admin' => false, 5872 'prefs' => ['feature_wiki'], 5873 'scope' => 'object', 5874 ], 5875 [ 5876 'name' => 'tiki_p_rollback', 5877 'description' => tra('Can roll back pages'), 5878 'level' => 'editors', 5879 'type' => 'wiki', 5880 'admin' => false, 5881 'prefs' => ['feature_wiki'], 5882 'scope' => 'object', 5883 ], 5884 [ 5885 'name' => 'tiki_p_upload_picture', 5886 'description' => tra('Can upload pictures to wiki pages'), 5887 'level' => 'registered', 5888 'type' => 'wiki', 5889 'admin' => false, 5890 'prefs' => ['feature_wiki_pictures'], 5891 'scope' => 'object', 5892 ], 5893 [ 5894 'name' => 'tiki_p_use_as_template', 5895 'description' => tra('Can use the page as a template for a tracker or unified search'), 5896 'level' => 'basic', 5897 'type' => 'wiki', 5898 'admin' => false, 5899 'prefs' => ['feature_wiki'], 5900 'scope' => 'object', 5901 ], 5902 [ 5903 'name' => 'tiki_p_wiki_view_ref', 5904 'description' => tra('Can view in module and feed the wiki pages reference'), 5905 'level' => 'basic', 5906 'type' => 'wiki', 5907 'admin' => false, 5908 'prefs' => ['feature_wiki'], 5909 'scope' => 'object', 5910 ], 5911 [ 5912 'name' => 'tiki_p_wiki_admin_attachments', 5913 'description' => tra('Can admin attachments on wiki pages'), 5914 'level' => 'editors', 5915 'type' => 'wiki', 5916 'admin' => false, 5917 'prefs' => ['feature_wiki_attachments'], 5918 'scope' => 'object', 5919 ], 5920 [ 5921 'name' => 'tiki_p_wiki_admin_ratings', 5922 'description' => tra('Can add and change ratings on wiki pages'), 5923 'level' => 'admin', 5924 'type' => 'wiki', 5925 'admin' => false, 5926 'prefs' => ['feature_wiki_ratings'], 5927 'scope' => 'global', 5928 ], 5929 [ 5930 'name' => 'tiki_p_wiki_attach_files', 5931 'description' => tra('Can attach files to wiki pages'), 5932 'level' => 'registered', 5933 'type' => 'wiki', 5934 'admin' => false, 5935 'prefs' => ['feature_wiki_attachments'], 5936 'scope' => 'object', 5937 ], 5938 [ 5939 'name' => 'tiki_p_wiki_view_attachments', 5940 'description' => tra('Can view and download wiki page attachments'), 5941 'level' => 'registered', 5942 'type' => 'wiki', 5943 'admin' => false, 5944 'prefs' => ['feature_wiki_attachments'], 5945 'scope' => 'object', 5946 ], 5947 [ 5948 'name' => 'tiki_p_wiki_view_comments', 5949 'description' => tra('Can view wiki comments'), 5950 'level' => 'basic', 5951 'type' => 'wiki', 5952 'admin' => false, 5953 'prefs' => ['feature_wiki_comments'], 5954 'scope' => 'object', 5955 ], 5956 [ 5957 'name' => 'tiki_p_wiki_view_ratings', 5958 'description' => tra('Can view rating of wiki pages'), 5959 'level' => 'basic', 5960 'type' => 'wiki', 5961 'admin' => false, 5962 'prefs' => ['feature_wiki_ratings'], 5963 'scope' => 'object', 5964 ], 5965 [ 5966 'name' => 'tiki_p_wiki_view_source', 5967 'description' => tra('Can view source of wiki pages'), 5968 'level' => 'basic', 5969 'type' => 'wiki', 5970 'admin' => false, 5971 'prefs' => ['feature_source'], 5972 'scope' => 'object', 5973 ], 5974 [ 5975 'name' => 'tiki_p_wiki_vote_ratings', 5976 'description' => tra('Can participate in rating of wiki pages'), 5977 'level' => 'registered', 5978 'type' => 'wiki', 5979 'admin' => false, 5980 'prefs' => ['feature_wiki_ratings'], 5981 'scope' => 'object', 5982 ], 5983 [ 5984 'name' => 'tiki_p_wiki_view_similar', 5985 'description' => tra('Can view similar wiki pages'), 5986 'level' => 'registered', 5987 'type' => 'wiki', 5988 'admin' => false, 5989 'prefs' => ['feature_likePages'], 5990 'scope' => 'object', 5991 ], 5992 [ 5993 'name' => 'tiki_p_view_backlink', 5994 'description' => tra('View page backlinks'), 5995 'level' => 'basic', 5996 'type' => 'wiki', 5997 'admin' => false, 5998 'prefs' => ['feature_backlinks'], 5999 'scope' => 'object', 6000 ], 6001 [ 6002 'name' => 'tiki_p_wiki_view_latest', 6003 'description' => tra('Can view unapproved revisions of pages'), 6004 'level' => 'registered', 6005 'type' => 'wiki', 6006 'admin' => false, 6007 'prefs' => ['flaggedrev_approval'], 6008 'scope' => 'object', 6009 ], 6010 [ 6011 'name' => 'tiki_p_wiki_approve', 6012 'description' => tra('Can approve revisions of pages'), 6013 'level' => 'editors', 6014 'type' => 'wiki', 6015 'admin' => false, 6016 'prefs' => ['flaggedrev_approval'], 6017 'scope' => 'object', 6018 ], 6019 [ 6020 'name' => 'tiki_p_page_contribution_view', 6021 'description' => tra('Can view contributions to a page'), 6022 'level' => 'basic', 6023 'type' => 'wiki', 6024 'admin' => false, 6025 'prefs' => ['feature_page_contribution'], 6026 'scope' => 'global', 6027 ], 6028 [ 6029 'name' => 'tiki_p_use_references', 6030 'description' => tra('Can use reference library items'), 6031 'level' => 'editors', 6032 'type' => 'wiki', 6033 'admin' => false, 6034 'prefs' => ['feature_references'], 6035 'scope' => 'object', 6036 ], 6037 [ 6038 'name' => 'tiki_p_edit_references', 6039 'description' => tra('Can add to, edit and remove reference library items'), 6040 'level' => 'editors', 6041 'type' => 'wiki', 6042 'admin' => false, 6043 'prefs' => ['feature_references'], 6044 'scope' => 'object', 6045 ], 6046 [ 6047 'name' => 'tiki_p_admin_structures', 6048 'description' => tra('Can administer structures'), 6049 'level' => 'admin', 6050 'type' => 'wiki structure', // NB "wiki structure" objects use the perms set on the top "wiki page" 6051 'admin' => true, 6052 'prefs' => ['feature_wiki_structure'], 6053 'scope' => 'object', 6054 ], 6055 [ 6056 'name' => 'tiki_p_edit_structures', 6057 'description' => tra('Can create and edit structures'), 6058 'level' => 'editors', 6059 'type' => 'wiki structure', // NB "wiki structure" objects use the perms set on the top "wiki page" 6060 'admin' => false, 6061 'prefs' => ['feature_wiki_structure'], 6062 'scope' => 'object', 6063 ], 6064 [ 6065 'name' => 'tiki_p_lock_structures', 6066 'description' => tra('Can lock structures'), 6067 'level' => 'editors', 6068 'type' => 'wiki structure', // NB "wiki structure" objects use the perms set on the top "wiki page" 6069 'admin' => false, 6070 'prefs' => ['feature_wiki_structure', 'lock_wiki_structures'], 6071 'scope' => 'object', 6072 ], 6073 [ 6074 'name' => 'tiki_p_watch_structure', 6075 'description' => tra('Can watch structures'), 6076 'level' => 'registered', 6077 'type' => 'wiki structure', // NB "wiki structure" objects use the perms set on the top "wiki page" 6078 'admin' => false, 6079 'prefs' => ['feature_wiki_structure'], 6080 'scope' => 'global', 6081 ], 6082 [ 6083 'name' => 'tiki_p_admin', 6084 'description' => tra('Administrator can manage users, groups and permissions and all features'), 6085 'level' => 'admin', 6086 'type' => 'tiki', 6087 'admin' => true, 6088 'prefs' => [], 6089 'scope' => 'global', 6090 ], 6091 [ 6092 'name' => 'tiki_p_edit_grouplimitedinfo', 6093 'description' => tra('Can edit the name and description of a group.'), 6094 'level' => 'admin', 6095 'type' => 'group', 6096 'admin' => false, 6097 'prefs' => [], 6098 'scope' => 'object', 6099 ], 6100 [ 6101 'name' => 'tiki_p_access_closed_site', 6102 'description' => tra('Can access site when closed'), 6103 'level' => 'admin', 6104 'type' => 'tiki', 6105 'admin' => false, 6106 'prefs' => [], 6107 'scope' => 'global', 6108 ], 6109 [ 6110 'name' => 'tiki_p_admin_banners', 6111 'description' => tra('Administrator can admin banners'), 6112 'level' => 'admin', 6113 'type' => 'tiki', 6114 'admin' => false, 6115 'prefs' => ['feature_banners'], 6116 'scope' => 'global', 6117 ], 6118 [ 6119 'name' => 'tiki_p_admin_banning', 6120 'description' => tra('Can ban users or IP addresses'), 6121 'level' => 'admin', 6122 'type' => 'tiki', 6123 'admin' => false, 6124 'prefs' => ['feature_banning'], 6125 'scope' => 'global', 6126 ], 6127 [ 6128 'name' => 'tiki_p_admin_dynamic', 6129 'description' => tra('Can admin the dynamic content system'), 6130 'level' => 'editors', 6131 'type' => 'tiki', 6132 'admin' => false, 6133 'prefs' => ['feature_dynamic_content'], 6134 'scope' => 'global', 6135 ], 6136 [ 6137 'name' => 'tiki_p_admin_integrator', 6138 'description' => tra('Can admin integrator repositories and rules'), 6139 'level' => 'admin', 6140 'type' => 'tiki', 6141 'admin' => false, 6142 'prefs' => ['feature_integrator'], 6143 'scope' => 'global', 6144 ], 6145 [ 6146 'name' => 'tiki_p_send_mailin', 6147 'description' => tra('Can send email to a mail-in accounts, and have the email integrated. Only applies when the mail-in setting "anonymous" = n'), 6148 'level' => 'basic', 6149 'type' => 'tiki', 6150 'admin' => false, 6151 'prefs' => ['feature_mailin', 'feature_wiki'], 6152 'scope' => 'global', 6153 ], 6154 [ 6155 'name' => 'tiki_p_admin_mailin', 6156 'description' => tra('Can admin mail-in accounts'), 6157 'level' => 'admin', 6158 'type' => 'tiki', 6159 'admin' => false, 6160 'prefs' => ['feature_mailin'], 6161 'scope' => 'global', 6162 ], 6163 [ 6164 'name' => 'tiki_p_admin_objects', 6165 'description' => tra('Can edit object permissions'), 6166 'level' => 'admin', 6167 'type' => 'tiki', 6168 'admin' => false, 6169 'prefs' => [], 6170 'scope' => 'global', 6171 ], 6172 [ 6173 'name' => 'tiki_p_admin_rssmodules', 6174 'description' => tra('Can admin external feeds'), 6175 'level' => 'admin', 6176 'type' => 'tiki', 6177 'admin' => false, 6178 'prefs' => [], 6179 'scope' => 'global', 6180 ], 6181 [ 6182 'name' => 'tiki_p_clean_cache', 6183 'description' => tra('Can clean cache'), 6184 'level' => 'editors', 6185 'type' => 'tiki', 6186 'admin' => false, 6187 'prefs' => [], 6188 'scope' => 'global', 6189 ], 6190 [ 6191 'name' => 'tiki_p_create_css', 6192 'description' => tra('Can create a new CSS file (style sheet) appended with -user'), 6193 'level' => 'registered', 6194 'type' => 'tiki', 6195 'admin' => false, 6196 'prefs' => ['feature_editcss'], 6197 'scope' => 'global', 6198 ], 6199 [ 6200 'name' => 'tiki_p_detach_translation', 6201 'description' => tra('Can remove the association between two pages in a translation set'), 6202 'level' => 'editors', 6203 'type' => 'tiki', 6204 'admin' => false, 6205 'prefs' => ['feature_multilingual'], 6206 'scope' => 'object', 6207 'apply_to' => ['wiki', 'trackers', 'articles'], 6208 ], 6209 [ 6210 'name' => 'tiki_p_edit_cookies', 6211 'description' => tra('Can admin cookies'), 6212 'level' => 'editors', 6213 'type' => 'tiki', 6214 'admin' => false, 6215 'prefs' => [], 6216 'scope' => 'global', 6217 ], 6218 [ 6219 'name' => 'tiki_p_edit_languages', 6220 'description' => tra('Can edit translations and create new languages'), 6221 'level' => 'editors', 6222 'type' => 'tiki', 6223 'admin' => false, 6224 'prefs' => [], 6225 'scope' => 'global', 6226 ], 6227 [ 6228 'name' => 'tiki_p_edit_menu', 6229 'description' => tra('Can edit menus'), 6230 'level' => 'admin', 6231 'type' => 'tiki', 6232 'admin' => false, 6233 'prefs' => [], 6234 'scope' => 'global', 6235 ], 6236 [ 6237 'name' => 'tiki_p_edit_menu_option', 6238 'description' => tra('Can edit menu options'), 6239 'level' => 'admin', 6240 'type' => 'tiki', 6241 'admin' => false, 6242 'prefs' => [], 6243 'scope' => 'global', 6244 ], 6245 [ 6246 'name' => 'tiki_p_edit_templates', 6247 'description' => tra('Can edit site templates'), 6248 'level' => 'admin', 6249 'type' => 'tiki', 6250 'admin' => false, 6251 'prefs' => ['feature_edit_templates'], 6252 'scope' => 'global', 6253 ], 6254 [ 6255 'name' => 'tiki_p_search', 6256 'description' => tra('Can search'), 6257 'level' => 'basic', 6258 'type' => 'tiki', 6259 'admin' => false, 6260 'prefs' => [], // This could depend on feature_search when FULLTEXT search (feature_search_fulltext) is removed 6261 'scope' => 'global', 6262 ], 6263 [ 6264 'name' => 'tiki_p_site_report', 6265 'description' => tra('Can report a link to the webmaster'), 6266 'level' => 'basic', 6267 'type' => 'tiki', 6268 'admin' => false, 6269 'prefs' => ['feature_site_report'], 6270 'scope' => 'object', 6271 ], 6272 [ 6273 'name' => 'tiki_p_share', 6274 'description' => tra('Can share a page (email, Twitter, Facebook, message, forums)'), 6275 'level' => 'basic', 6276 'type' => 'tiki', 6277 'admin' => false, 6278 'prefs' => ['feature_share'], 6279 'scope' => 'global', 6280 ], 6281 [ 6282 'name' => 'tiki_p_use_HTML', 6283 'description' => tra('Can use HTML in pages'), 6284 'level' => 'editors', 6285 'type' => 'tiki', 6286 'admin' => false, 6287 'prefs' => ['feature_wiki_allowhtml', 'feature_articles'], 6288 'scope' => 'global', 6289 ], 6290 [ 6291 'name' => 'tiki_p_view_actionlog', 6292 'description' => tra('Can view action log'), 6293 'level' => 'registered', 6294 'type' => 'tiki', 6295 'admin' => false, 6296 'prefs' => ['feature_actionlog'], 6297 'scope' => 'global', 6298 ], 6299 [ 6300 'name' => 'tiki_p_view_actionlog_owngroups', 6301 'description' => tra('Can view the action log for users of his or her groups'), 6302 'level' => 'registered', 6303 'type' => 'tiki', 6304 'admin' => false, 6305 'prefs' => ['feature_actionlog'], 6306 'scope' => 'global', 6307 ], 6308 [ 6309 'name' => 'tiki_p_view_integrator', 6310 'description' => tra('Can view integrated repositories'), 6311 'level' => 'basic', 6312 'type' => 'tiki', 6313 'admin' => false, 6314 'prefs' => ['feature_integrator'], 6315 'scope' => 'global', 6316 ], 6317 [ 6318 'name' => 'tiki_p_ratings_view_results', 6319 'description' => tra('Can view results from user ratings'), 6320 'level' => 'basic', 6321 'type' => 'tiki', 6322 'admin' => false, 6323 'prefs' => [], 6324 'scope' => 'object', 6325 'apply_to' => ['wiki', 'trackers', 'articles', 'comments', 'forums'], 6326 ], 6327 [ 6328 'name' => 'tiki_p_view_referer_stats', 6329 'description' => tra('Can view referrer stats'), 6330 'level' => 'editors', 6331 'type' => 'tiki', 6332 'admin' => false, 6333 'prefs' => ['feature_referer_stats'], 6334 'scope' => 'global', 6335 ], 6336 [ 6337 'name' => 'tiki_p_view_stats', 6338 'description' => tra('Can view site stats'), 6339 'level' => 'basic', 6340 'type' => 'tiki', 6341 'admin' => false, 6342 'prefs' => ['feature_stats'], 6343 'scope' => 'global', 6344 ], 6345 [ 6346 'name' => 'tiki_p_view_templates', 6347 'description' => tra('Can view site templates'), 6348 'level' => 'admin', 6349 'type' => 'tiki', 6350 'admin' => false, 6351 'prefs' => ['feature_edit_templates'], 6352 'scope' => 'global', 6353 ], 6354 [ 6355 'name' => 'tiki_p_view_webservices', 6356 'description' => tra('Can view results from webservice requests'), 6357 'level' => 'basic', 6358 'type' => 'tiki', 6359 'admin' => false, 6360 'prefs' => ['feature_webservices'], 6361 'scope' => 'global', 6362 ], 6363 [ 6364 'name' => 'tiki_p_admin_webservices', 6365 'description' => tra('Can administer webservices'), 6366 'level' => 'admin', 6367 'type' => 'tiki', 6368 'admin' => false, 6369 'prefs' => ['feature_webservices'], 6370 'scope' => 'global', 6371 ], 6372 [ 6373 'name' => 'tiki_p_admin_toolbars', 6374 'description' => tra('Can admin toolbars'), 6375 'level' => 'admin', 6376 'type' => 'tiki', 6377 'admin' => false, 6378 'prefs' => [], 6379 'scope' => 'global', 6380 ], 6381 [ 6382 'name' => 'tiki_p_trust_input', 6383 'description' => tra('Trust all user inputs including plugins (no security checks)'), 6384 'level' => 'admin', 6385 'type' => 'tiki', 6386 'admin' => false, 6387 'prefs' => ['tiki_allow_trust_input'], 6388 'scope' => 'global', 6389 ], 6390 [ 6391 'name' => 'tiki_p_plugin_viewdetail', 6392 'description' => tra('Can view unapproved plugin details'), 6393 'level' => 'registered', 6394 'type' => 'tiki', 6395 'admin' => false, 6396 'prefs' => ['feature_wiki'], 6397 'scope' => 'global', 6398 ], 6399 [ 6400 'name' => 'tiki_p_plugin_preview', 6401 'description' => tra('Can execute unapproved plugin registered'), 6402 'level' => 'admin', 6403 'type' => 'tiki', 6404 'admin' => false, 6405 'prefs' => ['feature_wiki'], 6406 'scope' => 'global', 6407 ], 6408 [ 6409 'name' => 'tiki_p_plugin_approve', 6410 'description' => tra('Can approve plugin execution'), 6411 'level' => 'editors', 6412 'type' => 'tiki', 6413 'admin' => false, 6414 'prefs' => ['feature_wiki'], 6415 'scope' => 'global', 6416 ], 6417 [ 6418 'name' => 'tiki_p_admin_notifications', 6419 'description' => tra('Can admin mail notifications'), 6420 'level' => 'editors', 6421 'type' => 'tiki', 6422 'admin' => false, 6423 'prefs' => [], 6424 'scope' => 'global', 6425 ], 6426 [ 6427 'name' => 'tiki_p_admin_importer', 6428 'description' => tra('Can use the importer'), 6429 'level' => 'admin', 6430 'type' => 'tiki', 6431 'admin' => false, 6432 'prefs' => [], 6433 'scope' => 'global', 6434 ], 6435 [ 6436 'name' => 'tiki_p_modify_object_categories', 6437 'description' => tra('Can change the categories of an object'), 6438 'level' => 'editors', 6439 'type' => 'tiki', 6440 'admin' => false, 6441 'prefs' => ['feature_categories'], 6442 'scope' => 'object', 6443 'apply_to' => ['wiki', 'trackers'], 6444 ], 6445 [ 6446 'name' => 'tiki_p_admin_modules', 6447 'description' => tra('User can administer modules'), 6448 'level' => 'admin', 6449 'type' => 'tiki', 6450 'admin' => false, 6451 'prefs' => [], 6452 'scope' => 'global', 6453 ], 6454 [ 6455 'name' => 'tiki_p_edit_switch_mode', 6456 'description' => tra('Can switch between wiki and WYSIWYG modes while editing'), 6457 'level' => 'editors', 6458 'type' => 'tiki', 6459 'admin' => false, 6460 'prefs' => ['feature_wysiwyg'], 6461 'scope' => 'global', 6462 ], 6463 [ 6464 'name' => 'tiki_p_workspace_instantiate', 6465 'description' => tra('Can create a new workspace for a given template'), 6466 'level' => 'admin', 6467 'type' => 'workspace', 6468 'admin' => false, 6469 'prefs' => ['workspace_ui'], 6470 'scope' => 'object', 6471 ], 6472 [ 6473 'name' => 'tiki_p_goal_admin', 6474 'description' => tr('Can manage all aspects of a goal'), 6475 'level' => 'admin', 6476 'type' => 'goal', 6477 'admin' => true, 6478 'prefs' => ['goal_enabled'], 6479 'scope' => 'object', 6480 ], 6481 [ 6482 'name' => 'tiki_p_goal_modify_eligible', 6483 'description' => tr('Can manage who is eligible for a goal'), 6484 'level' => 'admin', 6485 'type' => 'goal', 6486 'admin' => false, 6487 'prefs' => ['goal_enabled'], 6488 'scope' => 'object', 6489 ], 6490 ]; 6491 6492 $permissions = $this->getSortingPermissions($permissions); 6493 6494 $cachelib->cacheItem('rawpermissions' . $prefs['language'], serialize($permissions)); 6495 return $permissions; 6496 } 6497 6498 function get_permissions($offset = 0, $maxRecords = -1, $sort_mode = 'permName_asc', $find = '', $type = 'all', $group = '', $enabledOnly = false) 6499 { 6500 if ($enabledOnly) { 6501 $raw = $this->get_enabled_permissions(); 6502 } else { 6503 $raw = $this->get_raw_permissions(); 6504 } 6505 6506 $ret = []; 6507 6508 foreach ($raw as $permission) { 6509 if ($find && stripos($permission['name'], $find) === false) { 6510 continue; 6511 } 6512 6513 if ($type === 'global' || $type == 'all') { 6514 $ret[] = $this->permission_compatibility($permission); 6515 } elseif ($type == $permission['type'] && $permission['scope'] == 'object') { 6516 $ret[] = $this->permission_compatibility($permission); 6517 } elseif ($type == 'category' && $permission['scope'] != 'global') { 6518 $ret[] = $this->permission_compatibility($permission); 6519 } elseif ($permission['scope'] == 'object' && isset($permission['apply_to']) && in_array($type, $permission['apply_to'])) { 6520 $ret[] = $this->permission_compatibility($permission); 6521 } 6522 } 6523 6524 if ($group) { 6525 if (is_string($group)) { 6526 foreach ($ret as &$res) { 6527 if ($this->group_has_permission($group, $res['permName'])) { 6528 $res['hasPerm'] = 'y'; 6529 } else { 6530 $res['hasPerm'] = 'n'; 6531 } 6532 } 6533 } elseif (is_array($group)) { 6534 foreach ($ret as &$res) { 6535 foreach ($group as $groupName) { 6536 if ($this->group_has_permission($groupName, $res['permName'])) { 6537 $res[$groupName . '_hasPerm'] = 'y'; 6538 } else { 6539 $res[$groupName . '_hasPerm'] = 'n'; 6540 } 6541 } 6542 } 6543 } 6544 } 6545 6546 return [ 6547 'data' => $ret, 6548 'cant' => count($ret), 6549 ]; 6550 } 6551 6552 private function permission_compatibility($newFormat) 6553 { 6554 $newFormat['shortName'] = substr($newFormat['name'], strlen('tiki_p_')); 6555 $newFormat['permName'] = $newFormat['name']; 6556 $newFormat['permDesc'] = $newFormat['description']; 6557 $newFormat['feature_checks'] = implode(',', $newFormat['prefs']); 6558 6559 return $newFormat; 6560 } 6561 6562 function get_permission_types() 6563 { 6564 $ret = []; 6565 6566 foreach ($this->get_raw_permissions() as $perm) { 6567 if (! isset($ret[$perm['type']])) { 6568 $ret[$perm['type']] = true; 6569 } 6570 } 6571 6572 return array_keys($ret); 6573 } 6574 6575 function get_group_permissions($group) 6576 { 6577 $cachelib = TikiLib::lib('cache'); 6578 if (! $ret = $cachelib->getSerialized("groupperms_$group")) { 6579 $query = 'select `permName` from `users_grouppermissions` where `groupName`=?'; 6580 $result = $this->query($query, [$group]); 6581 $ret = []; 6582 6583 while ($res = $result->fetchRow()) { 6584 $ret[] = $res['permName']; 6585 } 6586 6587 $cachelib->cacheItem("groupperms_$group", serialize($ret)); 6588 } 6589 6590 return $ret; 6591 } 6592 6593 function assign_permission_to_group($perm, $group) 6594 { 6595 $query = 'delete from `users_grouppermissions` where `groupName` = ? and `permName` = ?'; 6596 $result = $this->query($query, [$group, $perm]); 6597 6598 $query = 'insert into `users_grouppermissions`(`groupName`, `permName`) values(?, ?)'; 6599 $result = $this->query($query, [$group, $perm]); 6600 6601 $cachelib = TikiLib::lib('cache'); 6602 $cachelib->empty_type_cache('fgals_perms'); 6603 $cachelib->invalidate("groupperms_$group"); 6604 6605 $menulib = TikiLib::lib('menu'); 6606 $menulib->empty_menu_cache(); 6607 6608 return true; 6609 } 6610 6611 function get_user_permissions($user) 6612 { 6613 $groups = $this->get_user_groups($user); 6614 6615 $ret = []; 6616 foreach ($groups as $group) { 6617 $perms = $this->get_group_permissions($group); 6618 6619 foreach ($perms as $perm) { 6620 $ret[] = $perm; 6621 } 6622 } 6623 6624 return $ret; 6625 } 6626 6627 function user_has_permission($user, $perm) 6628 { 6629 // Get user_groups ? 6630 $groups = $this->get_user_groups($user); 6631 6632 foreach ($groups as $group) { 6633 if ($this->group_has_permission($group, $perm) || $this->group_has_permission($group, 'tiki_p_admin')) { 6634 return true; 6635 } 6636 } 6637 6638 return false; 6639 } 6640 6641 function group_has_permission($group, $perm) 6642 { 6643 if (empty($perm) || empty($group)) { 6644 return 0; 6645 } 6646 6647 $engroup = urlencode($group); 6648 if (! isset($this->groupperm_cache[$engroup])) { 6649 $this->groupperm_cache[$engroup] = []; 6650 $groupperms = $this->get_group_permissions($group); 6651 foreach ($groupperms as $gp) { 6652 $this->groupperm_cache[$engroup][$gp] = 1; 6653 } 6654 } 6655 6656 return isset($this->groupperm_cache[$engroup][$perm]) ? 1 : 0; 6657 } 6658 6659 function remove_permission_from_group($perm, $group) 6660 { 6661 $query = "delete from `users_grouppermissions` where `permName` = ? and `groupName` = ?"; 6662 $result = $this->query($query, [$perm, $group]); 6663 6664 $cachelib = TikiLib::lib('cache'); 6665 $cachelib->empty_type_cache("fgals_perms"); 6666 $cachelib->invalidate("groupperms_$group"); 6667 6668 $menulib = TikiLib::lib('menu'); 6669 $menulib->empty_menu_cache(); 6670 6671 return true; 6672 } 6673 6674 function get_group_info($group, $sort_mode = 'groupName_asc') 6675 { 6676 $ret = []; 6677 if (is_array($group)) { 6678 if (count($group) > 0) { 6679 $query = 'select * from `users_groups` where `groupName` in (' . 6680 implode(',', array_fill(0, count($group), '?')) . 6681 ') order by ' . $this->convertSortMode($sort_mode); 6682 $ret = $this->fetchAll($query, $group); 6683 } 6684 } else { 6685 $query = 'select * from `users_groups` where `groupName`=?'; 6686 $result = $this->query($query, [$group]); 6687 $ret = $result->fetchRow(); 6688 $perms = $this->get_group_permissions($group); 6689 $ret['perms'] = $perms; 6690 } 6691 return $ret; 6692 } 6693 6694 function get_groupId_info($groupId) 6695 { 6696 $query = 'select * from `users_groups` where `id`=?'; 6697 6698 $result = $this->query($query, [$groupId]); 6699 $res = $result->fetchRow(); 6700 $perms = $this->get_group_permissions($res['groupName']); 6701 $res['perms'] = $perms; 6702 6703 return $res; 6704 } 6705 6706 function assign_user_to_group($user, $group, $bulk = false) 6707 { 6708 if (! $this->group_exists($group)) { 6709 throw new Exception(tr('Cannot add user %0 to nonexistent group %1', $user, $group)); 6710 } 6711 if (! $this->user_exists($user)) { 6712 throw new Exception(tr('Cannot add nonexistent user %0 to group %1', $user, $group)); 6713 } 6714 6715 $groupInfo = $this->get_group_info($group); 6716 if ($groupInfo["isRole"] == "y") { 6717 throw new Exception(tr('Role groups can\'t have users.')); 6718 } 6719 6720 global $prefs, $tiki_p_admin, $page; 6721 $cachelib = TikiLib::lib('cache'); 6722 $tikilib = TikiLib::lib('tiki'); 6723 $access = TikiLib::lib('access'); 6724 6725 if ($this->is_user_banned_from_group($user, $group)) { 6726 $msg = tr('User "%0" is banned from the group "%1".', $user, $group); 6727 if ($tiki_p_admin === 'y') { 6728 $access->check_authenticity($msg . ' ' . tra('Do you want to unban them and continue?')); 6729 $this->unban_user_from_group($user, $group); 6730 } else { 6731 $access->display_error($page, $msg); 6732 } 6733 } 6734 6735 $cachelib->invalidate('user_details_' . $user); 6736 $tikilib->invalidate_usergroups_cache($user); 6737 $this->invalidate_usergroups_cache($user); // this is needed as cache is present in this instance too 6738 6739 $group_ret = false; 6740 $userid = $this->get_user_id($user); 6741 6742 if ($userid > 0) { 6743 $query = "insert ignore into `users_usergroups`(`userId`,`groupName`, `created`) values(?,?,?)"; 6744 $result = $this->query($query, [$userid, $group, $tikilib->now], -1, -1, false); 6745 $group_ret = true; 6746 } 6747 $this->update_group_expiries(); 6748 6749 if ($group_ret) { 6750 $watches = $tikilib->get_event_watches('user_joins_group', $group); 6751 if (count($watches)) { 6752 require_once("lib/notifications/notificationemaillib.php"); 6753 $smarty = TikiLib::lib('smarty'); 6754 $smarty->assign('mail_user', $user); 6755 $smarty->assign('mail_group', $group); 6756 sendEmailNotification($watches, null, 'user_joins_group_notification_subject.tpl', null, 'user_joins_group_notification.tpl'); 6757 } 6758 TikiLib::events()->trigger('tiki.user.groupjoin', [ 6759 'type' => 'user', 6760 'object' => $user, 6761 'group' => $group, 6762 'bulk_import' => $bulk, 6763 ]); 6764 } 6765 6766 return $group_ret; 6767 } 6768 6769 function assign_user_to_groups($user, $groups) 6770 { 6771 $cachelib = TikiLib::lib('cache'); 6772 $cachelib->invalidate('user_details_' . $user); 6773 6774 $userid = $this->get_user_id($user); 6775 6776 $query = 'delete from `users_usergroups` where `userId`=?'; 6777 $this->query($query, [$userid]); 6778 6779 $lastkey = end($groups); 6780 foreach ($groups as $k => $grp) { 6781 $this->assign_user_to_group($user, $grp, $k != $lastkey); 6782 } 6783 } 6784 6785 function ban_user_from_group($user, $group) 6786 { 6787 TikiLib::lib('relation')->add_relation('tiki.user.banned', 'user', $user, 'group', $group); 6788 } 6789 6790 function unban_user_from_group($user, $group) 6791 { 6792 $relationlib = TikiLib::lib('relation'); 6793 $id = $relationlib->get_relation_id('tiki.user.banned', 'user', $user, 'group', $group); 6794 if ($id) { 6795 $relationlib->remove_relation($id); 6796 } 6797 } 6798 6799 function get_group_banned_users($group, $offset = 0, $max = -1, $what = 'login', $sort_mode = 'source_itemId_asc') 6800 { 6801 $res = TikiLib::lib('relation')->get_relations_to('group', $group, 'tiki.user.banned', $sort_mode); 6802 $temp = []; 6803 foreach ($res as $r) { 6804 $temp[] = $r['itemId']; 6805 } 6806 $max = $max > 0 ? $max : null; 6807 $ret['data'] = array_slice($temp, $offset, $max); 6808 $ret['cant'] = count($res); 6809 return $ret; 6810 } 6811 6812 function is_user_banned_from_group($user, $group) 6813 { 6814 return TikiLib::lib('relation')->get_relation_id('tiki.user.banned', 'user', $user, 'group', $group) > 0; 6815 } 6816 6817 6818 function confirm_user($user) 6819 { 6820 $cachelib = TikiLib::lib('cache'); 6821 6822 $query = 'update `users_users` set `provpass`=?, valid=?, `email_confirm`=?, `waiting`=?, `registrationDate`=? where `login`=?'; 6823 $result = $this->query($query, ['', null, $this->now, null, $this->now, $user]); 6824 $cachelib->invalidate('userslist'); 6825 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 6826 } 6827 6828 function invalidate_account($user) 6829 { 6830 $cachelib = TikiLib::lib('cache'); 6831 $tikilib = TikiLib::lib('tiki'); 6832 6833 $query = 'update `users_users` set valid=?, `waiting`=? where `login`=?'; 6834 $result = $this->query($query, [md5($tikilib->genPass()), 'u', $user]); 6835 $cachelib->invalidate('userslist'); 6836 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 6837 } 6838 6839 function change_user_waiting($user, $who) 6840 { 6841 $query = 'update `users_users` set `waiting`=? where `login`=?'; 6842 $this->query($query, [$who, $user]); 6843 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 6844 } 6845 6846 /** 6847 * Adds a user in Tiki. 6848 * 6849 * @param user: username 6850 * @param pass: password (may be an empty string) 6851 * @param email: email 6852 */ 6853 function add_user($user, $pass, $email, $provpass = '', $pass_first_login = false, $valid = null, $openid_url = null, $waiting = null, $groups = []) 6854 { 6855 global $prefs; 6856 $cachelib = TikiLib::lib('cache'); 6857 $tikilib = TikiLib::lib('tiki'); 6858 6859 $autogenerate_uname = false; 6860 if ($prefs['login_autogenerate'] == 'y' && $user == '') { 6861 // only autogenerate if no username is provided (as many features might want to create real user name) 6862 // need to create as tmp uname first before replacing with user ID based number 6863 $user = "tmp" . md5((string) rand()); 6864 $autogenerate_uname = true; 6865 } 6866 6867 $user = trim($user); 6868 6869 if ($this->user_exists($user) 6870 || empty($user) 6871 || (! empty($prefs['username_pattern']) && ! preg_match($prefs['username_pattern'], $user)) 6872 || strtolower($user) == 'anonymous' 6873 || strtolower($user) == 'registered' 6874 ) { 6875 return false; 6876 } 6877 6878 if ($prefs['user_unique_email'] == 'y' && $this->get_user_by_email($email)) { 6879 if ($autogenerate_uname) { 6880 // If the user to be added is to be autogenerated and the email already exists it means the user 6881 // is already created, for example in the 2nd pass in the registration process. To silently exit. 6882 return false; 6883 } 6884 $smarty = TikiLib::lib('smarty'); 6885 $smarty->assign('errortype', 'login'); 6886 $smarty->assign('msg', tra('We were unable to create your account because this email is already in use.')); 6887 $smarty->display('error.tpl'); 6888 die; 6889 } 6890 6891 $userexists_cache[$user] = null; 6892 6893 // Generate a unique hash; this is also done below in set_user_fields() 6894 $lastLogin = null; 6895 if (empty($openid_url)) { 6896 $hash = password_hash($pass, PASSWORD_DEFAULT); 6897 } else { 6898 $hash = ''; 6899 if (! isset($prefs['validateRegistration']) || $prefs['validateRegistration'] != 'y') { 6900 $lastLogin = $tikilib->now; 6901 } 6902 } 6903 6904 if ($pass_first_login) { 6905 $new_pass_confirm = 0; 6906 } else { 6907 $new_pass_confirm = $this->now; 6908 } 6909 $new_email_confirm = $this->now; 6910 $userTable = $this->table('users_users'); 6911 $userId = $userTable->insert( 6912 [ 6913 'login' => $user, 6914 'email' => $email, 6915 'provpass' => $provpass, 6916 'registrationDate' => (int) $this->now, 6917 'hash' => $hash, 6918 'pass_confirm' => (int) $new_pass_confirm, 6919 'email_confirm' => (int) $new_email_confirm, 6920 'created' => (int) $this->now, 6921 'valid' => $valid, 6922 'openid_url' => $openid_url, 6923 'lastLogin' => $lastLogin, 6924 'waiting' => $waiting, 6925 ] 6926 ); 6927 6928 if ($autogenerate_uname) { 6929 // only autogenerate if no username is provided (as many features might want to create real user name) 6930 $user = $this->autogenerate_login($userId); 6931 $userTable->update( 6932 [ 6933 'login' => $user, 6934 ], 6935 [ 6936 'userId' => $userId, 6937 ] 6938 ); 6939 } 6940 6941 if (empty($groups)) { 6942 $this->assign_user_to_group($user, 'Registered'); 6943 } else { 6944 if (is_array($groups)) { 6945 foreach ($groups as $grp) { 6946 $this->assign_user_to_group($user, $grp); 6947 } 6948 } else { 6949 $this->assign_user_to_group($user, 'Registered'); 6950 } 6951 } 6952 6953 if ($prefs['eponymousGroups'] == 'y') { 6954 // Create a group just for this user, for permissions 6955 // assignment. 6956 $this->add_group($user, "Personal group for $user.", '', 0, 0, 0, ''); 6957 6958 $this->assign_user_to_group($user, $user); 6959 } 6960 6961 $this->set_user_default_preferences($user, false); // do not force 6962 6963 if (! empty($prefs['user_tracker_auto_assign_item_field'])) { 6964 // try to assign the user tracker item if exists 6965 TikiLib::lib('trk')->update_user_item($user, $email, $prefs['user_tracker_auto_assign_item_field']); 6966 } 6967 6968 $cachelib->invalidate('userslist'); 6969 6970 TikiLib::events()->trigger('tiki.user.create', [ 6971 'type' => 'user', 6972 'object' => $user, 6973 'userId' => $userId, 6974 ]); 6975 6976 return $user; 6977 } 6978 6979 function autogenerate_login($userId, $digits = 6) 6980 { 6981 //create unique hash based on $userId, between 0 and 999999 (if digits = 6) 6982 $userHash = $userId * pow(9, $digits) % (pow(10, $digits)); 6983 return sprintf('%0' . $digits . 'd', $userHash); //add leading 0's 6984 } 6985 6986 function set_user_default_preferences($user, $force = true) 6987 { 6988 global $prefs; 6989 foreach ($prefs as $pref => $value) { 6990 if (! preg_match('/^users_prefs_/', $pref)) { 6991 continue; 6992 } 6993 if ($pref == 'users_prefs_email_is_public') { 6994 $pref_name = 'email is public'; 6995 } else { 6996 $pref_name = substr($pref, 12); 6997 } 6998 if ($force || is_null($this->get_user_preference($user, $pref_name))) { 6999 $this->set_user_preference($user, $pref_name, $value); 7000 } 7001 } 7002 7003 if ($prefs['change_language'] == 'y' && $prefs['site_language'] != $prefs['language']) { 7004 $this->set_user_preference($user, 'language', $prefs['language']); 7005 } 7006 } 7007 7008 function change_user_email_only($user, $email) 7009 { 7010 global $prefs; 7011 if ($prefs['user_unique_email'] == 'y' && $this->other_user_has_email($user, $email)) { 7012 $smarty = TikiLib::lib('smarty'); 7013 $smarty->assign('errortype', 'login'); 7014 $smarty->assign('msg', tra('Email cannot be set because this email is already in use by another user.')); 7015 $smarty->display('error.tpl'); 7016 die; 7017 } 7018 $query = 'update `users_users` set `email`=? where binary `login`=?'; 7019 $result = $this->query($query, [$email, $user]); 7020 } 7021 7022 function change_user_email($user, $email, $pass = null) 7023 { 7024 global $prefs; 7025 if ($prefs['user_unique_email'] == 'y' && $this->other_user_has_email($user, $email)) { 7026 $smarty = TikiLib::lib('smarty'); 7027 $smarty->assign('errortype', 'login'); 7028 $smarty->assign('msg', tra('Email cannot be set because this email is already in use by another user.')); 7029 $smarty->display('error.tpl'); 7030 die; 7031 } 7032 7033 // Need to change the email-address for notifications, too 7034 $notificationlib = TikiLib::lib('notification'); 7035 $oldMail = $this->get_user_email($user); 7036 $notificationlib->update_mail_address($user, $oldMail, $email); 7037 7038 $this->change_user_email_only($user, $email); 7039 7040 // that block stays here for a time (compatibility) 7041 // lfagundes - only if pass is provided, admin doesn't need it 7042 // is this still necessary? 7043 if (! empty($pass)) { 7044 $hash = password_hash($pass, PASSWORD_DEFAULT); 7045 $query = 'update `users_users` set `hash`=? where binary `login`=?'; 7046 $result = $this->query($query, [$hash, $user]); 7047 } 7048 7049 $query = 'update `tiki_user_watches` set `email`=? where binary `user`=?'; 7050 $result = $this->query($query, [ $email, $user]); 7051 7052 $query = 'update `tiki_live_support_requests` set `email`=? where binary `user`=?'; 7053 $result = $this->query($query, [ $email, $user]); 7054 7055 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 7056 7057 return true; 7058 } 7059 7060 function get_user_email($user) 7061 { 7062 global $prefs; 7063 7064 if (($prefs['login_is_email'] == 'y' && $user != 'admin')) { 7065 return $this->user_exists($user) ? $user : ''; 7066 } else { 7067 return $this->getOne('select `email` from `users_users` where binary `login`=?', [$user]); 7068 } 7069 } 7070 7071 function get_userId_what($userIds, $what = 'email') 7072 { 7073 $query = "select `$what` from `users_users` where `userId` in (" . implode(',', array_fill(0, count($userIds), '?')) . ')'; 7074 $result = $this->query($query, $userIds); 7075 $ret = []; 7076 7077 while ($res = $result->fetchRow()) { 7078 $ret[] = $res[$what]; 7079 } 7080 7081 return $ret; 7082 } 7083 7084 /** 7085 * Returns the contact users' email if set and permitted by Admin->Features settings 7086 */ 7087 function get_admin_email() 7088 { 7089 global $user, $prefs, $tikilib; 7090 if (( ! isset($user) && isset($prefs['contact_anon']) && $prefs['contact_anon'] == 'y' ) || 7091 ( isset($user) && $user != '' && isset($prefs['feature_contact']) && $prefs['feature_contact'] == 'y' ) 7092 ) { 7093 return isset($prefs['sender_email']) ? $prefs['sender_email'] : $this->get_user_email($prefs['contact_user']); 7094 } 7095 } 7096 7097 function create_user_cookie($user, $secret = false) 7098 { 7099 global $prefs; 7100 if (! $secret) { 7101 $secret = $this->get_cookie_check(); 7102 } 7103 if ($prefs['login_multiple_forbidden'] === 'y') { 7104 $this->delete_user_cookie($user); 7105 } 7106 7107 $query = 'insert into `tiki_user_login_cookies`(`userId`, `secret`, `expiration`) values(?, ?, FROM_UNIXTIME(?))'; 7108 $result = $this->query($query, [$user, $secret, $this->now + $prefs['remembertime']]); 7109 7110 return $secret; 7111 } 7112 7113 function delete_user_cookie($user, $secret = '') 7114 { 7115 $query = 'delete from `tiki_user_login_cookies` where `userId`=?'; 7116 $vars = [(int) $user]; 7117 if ($secret) { 7118 $query .= ' and `secret`=?'; 7119 $vars[] = $secret; 7120 } 7121 $this->query($query, $vars); 7122 } 7123 7124 function get_cookie_check() 7125 { 7126 // generate random string but remove fullstops as they are used as the delimiter 7127 return str_replace('.', chr(rand(48, 126)), TikiLib::lib('tiki')->generate_unique_sequence(32)); 7128 } 7129 7130 function get_user_by_cookie($cookie) 7131 { 7132 list($secret, $userId) = explode('.', $cookie, 2); 7133 $query = 'select `userId` from `tiki_user_login_cookies` where `secret`=? and `userId`=? and `expiration` > NOW()'; 7134 7135 if ($userId === $this->getOne($query, [$secret, $userId])) { 7136 return $userId; 7137 } else { 7138 TikiLib::lib('logs')->add_log('login', 'get_user_by_cookie failed', $userId); 7139 return false; 7140 } 7141 } 7142 7143 function get_user_by_email($email) 7144 { 7145 $query = 'select `login` from `users_users` where upper(`email`)=?'; 7146 $pass = $this->getOne($query, [TikiLib::strtoupper($email)]); 7147 7148 return $pass; 7149 } 7150 7151 function other_user_has_email($user, $email) 7152 { 7153 $query = 'select `login` from `users_users` where upper(`email`)=? and `login`!=?'; 7154 $pass = $this->getOne($query, [TikiLib::strtoupper($email), $user]); 7155 7156 return $pass; 7157 } 7158 7159 function is_due($user, $method = null) 7160 { 7161 global $prefs; 7162 if (empty($method)) { 7163 $method = $prefs['auth_method']; 7164 } 7165 // if CAS auth is enabled, don't check if password is due since CAS does not use local Tiki passwords 7166 if ($method == 'cas' || $method == 'ldap' || $prefs['change_password'] != 'y') { 7167 return false; 7168 } 7169 $confirm = $this->getOne('select `pass_confirm` from `users_users` where binary `login`=?', [$user]); 7170 if (! $confirm) { 7171 return true; 7172 } 7173 if ($prefs['pass_due'] < 0) { 7174 return false; 7175 } 7176 if ($confirm + (60 * 60 * 24 * $prefs['pass_due']) < $this->now) { 7177 return true; 7178 } 7179 7180 return false; 7181 } 7182 7183 function is_email_due($user) 7184 { 7185 global $prefs; 7186 7187 if ($prefs['email_due'] < 0) { 7188 return false; 7189 } 7190 7191 $confirm = $this->getOne('select `email_confirm` from `users_users` where binary `login`=?', [$user]); 7192 7193 if ($confirm + (60 * 60 * 24 * $prefs['email_due']) < $this->now) { 7194 return true; 7195 } 7196 7197 return false; 7198 } 7199 7200 function unsuccessful_logins($user) 7201 { 7202 return $this->getOne('select `unsuccessful_logins` from `users_users` where binary `login`=?', [$user]); 7203 } 7204 7205 function renew_user_password($user) 7206 { 7207 $pass = $this->generate_provisional_password(); 7208 // Note that tiki-generated passwords are due inmediatley 7209 // Note: ^ not anymore. old pw is usable until the URL in the password reminder mail is clicked 7210 $query = 'update `users_users` set `provpass` = ? where `login`=?'; 7211 $result = $this->query($query, [$pass, $user]); 7212 return $pass; 7213 } 7214 7215 private function generate_provisional_password() 7216 { 7217 $tikilib = TikiLib::lib('tiki'); 7218 7219 $site_hash = $tikilib->get_site_hash(); 7220 7221 $random_value = \phpseclib\Crypt\Random::string(40); 7222 return base64_encode(sha1($random_value . $site_hash, true)); 7223 } 7224 7225 function activate_password($user, $actpass) 7226 { 7227 // move provpass to password and generate new hash, afterwards clean provpass 7228 $query = 'select `provpass` from `users_users` where `login`=?'; 7229 $pass = $this->getOne($query, [$user]); 7230 if (($pass <> '') && ($actpass == md5($pass))) { 7231 $hash = password_hash($pass, PASSWORD_DEFAULT); 7232 $query = 'update `users_users` set `hash`=?, `pass_confirm`=? where `login`=?'; 7233 $result = $this->query($query, [$hash, (int)$this->now, $user]); 7234 return $pass; 7235 } 7236 return false; 7237 } 7238 7239 /** 7240 * Tests the password against policy enforcement (Admin->Login), namely 7241 * $min_pass_length 7242 * $pass_chr_num 7243 * $pass_ud_chr_num 7244 * 7245 * returns an empty string if password is ok, or the error string otherwise 7246 */ 7247 function check_password_policy($pass) 7248 { 7249 global $prefs, $user; 7250 $errors = []; 7251 7252 // Validate password here 7253 if (( $prefs['auth_method'] != 'cas' || $user == 'admin' ) && strlen($pass) < $prefs['min_pass_length']) { 7254 $errors[] = tr('Password should be at least %0 characters long', $prefs['min_pass_length']); 7255 } 7256 7257 if ($prefs['pass_chr_case'] == 'y') { 7258 if (! preg_match_all('/[a-z]+/', $pass) || ! preg_match_all('/[A-Z]+/', $pass)) { 7259 $errors[] = tra('Password must contain at least one lowercase alphabetical character like "a" and one uppercase character like "A".'); 7260 } 7261 } 7262 7263 if ($prefs['pass_repetition'] == 'y') { 7264 $chars = str_split($pass); 7265 $previous = ''; 7266 foreach ($chars as $char) { 7267 if ($char == $previous) { 7268 $errors[] = tra('Password must not contain a consecutive repetition of the same character such as "111" or "aab"'); 7269 break; 7270 } 7271 $previous = $char; 7272 } 7273 } 7274 7275 $pass = strtolower($pass); // from here on in, we dont check upper case in the password. 7276 7277 // Check this code 7278 if ($prefs['pass_chr_num'] == 'y') { 7279 if (! preg_match_all('/[0-9]+/', $pass) || ! preg_match_all('/[a-z]+/', $pass)) { 7280 $errors[] = tra('Password must contain both letters and numbers'); 7281 } 7282 } 7283 7284 7285 if ($prefs['pass_chr_special'] == 'y') { 7286 if (preg_match_all('/^[0-9a-z]+$/', $pass) > 0) { 7287 $errors[] = tra('Password must contain at least one special character in lower case like " / $ % ? & * ( ) _ + ...'); 7288 } 7289 } 7290 7291 if ($prefs['pass_diff_username'] == 'y') { 7292 if (strtolower($user) == $pass) { 7293 $errors[] = tra('The password must be different from the user\'s log-in name.'); 7294 } 7295 } 7296 7297 if ($prefs['pass_blacklist'] === 'y') { 7298 $query = 'SELECT 1 FROM tiki_password_blacklist WHERE BINARY password=?;'; 7299 $result = $this->query($query, [$pass]); 7300 $isCommon = $result->fetchRow(); 7301 if ($isCommon[1] == 1) { 7302 $errors[] = tra('The password is blacklisted because it is too common.'); 7303 } 7304 } 7305 7306 7307 return empty($errors) ? '' : implode(' ', $errors); 7308 } 7309 7310 function remove_2_factor_secret($user) 7311 { 7312 return $this->update_2_factor_secret($user, ''); 7313 } 7314 7315 function generate_2_factor_secret($user) 7316 { 7317 $google2fa = new Google2FA(); 7318 $tfaSecret = $google2fa->generateSecretKey(); 7319 return $this->update_2_factor_secret($user, $tfaSecret); 7320 } 7321 7322 function update_2_factor_secret($user, $twoFASecret) 7323 { 7324 $query = 'update `users_users` set `twoFactorSecret`=? where binary `login`=?'; 7325 $this->query($query, [$twoFASecret, $user]); 7326 return $twoFASecret; 7327 } 7328 7329 function get_2_factor_secret($user) 7330 { 7331 $query = 'select `twoFactorSecret` from `users_users` where `login`=?'; 7332 return $this->getOne($query, [$user]); 7333 } 7334 7335 function validate_two_factor($twoFactorSecret, $pin) 7336 { 7337 $google2fa = new Google2FA(); 7338 return $google2fa->verifyKey($twoFactorSecret, $pin, 2); 7339 } 7340 7341 function change_user_password($user, $pass, $pass_first_login = false) 7342 { 7343 7344 $hash = password_hash($pass, PASSWORD_DEFAULT); 7345 $new_pass_confirm = $this->now; 7346 7347 if ($pass_first_login) { // if true, set pass_confirm to force passord change upon next login 7348 if (! empty($pass)) { 7349 $query = 'update `users_users` set `hash`=? , `provpass`=?, `pass_confirm`=? where binary `login`=?'; 7350 $this->query($query, [$hash, $pass, 0, $user]); 7351 } else { 7352 $query = 'update `users_users` set `pass_confirm`=? where binary `login`=?'; 7353 $this->query($query, [0, $user]); 7354 } 7355 } else { 7356 $query = 'update `users_users` set `hash`=? ,`pass_confirm`=?, `provpass`=? where binary `login`=?'; 7357 $this->query($query, [$hash, $new_pass_confirm, '', $user]); 7358 } 7359 // invalidate the cache so that after a fresh install, the admin (who has no user details at the install) can log in 7360 $cachelib = TikiLib::lib('cache'); 7361 $cachelib->invalidate('user_details_' . $user); 7362 7363 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 7364 7365 return true; 7366 } 7367 7368 function add_group( 7369 $group, 7370 $desc = '', 7371 $home = '', 7372 $utracker = 0, 7373 $gtracker = 0, 7374 $rufields = '', 7375 $userChoice = '', 7376 $defcat = 0, 7377 $theme = '', 7378 $ufield = 0, 7379 $gfield = 0, 7380 $isexternal = 'n', 7381 $expireAfter = 0, 7382 $emailPattern = '', 7383 $anniversary = '', 7384 $prorateInterval = '', 7385 $color = '', 7386 $isRole = '', 7387 $isTplGroup = '', 7388 $include_groups = [] 7389 ) { 7390 7391 $tikilib = TikiLib::lib('tiki'); 7392 $group = trim($group); 7393 7394 if ($this->group_exists($group)) { 7395 return false; 7396 } 7397 7398 $data = [ 7399 'groupName' => $group, 7400 'groupDesc' => $desc, 7401 'groupHome' => $home, 7402 'groupDefCat' => $defcat, 7403 'groupTheme' => $theme, 7404 'groupColor' => $color, 7405 'usersTrackerId' => (int)$utracker, 7406 'groupTrackerId' => (int)$gtracker, 7407 'registrationUsersFieldIds' => $rufields, 7408 'userChoice' => $userChoice, 7409 'usersFieldId' => (int)$ufield, 7410 'groupFieldId' => (int)$gfield, 7411 'isExternal' => $isexternal, 7412 'expireAfter' => $expireAfter, 7413 'emailPattern' => $emailPattern, 7414 'anniversary' => $anniversary, 7415 'prorateInterval' => $prorateInterval, 7416 'isRole' => $isRole, 7417 'isTplGroup' => empty($isTplGroup) ? 'n' : $isTplGroup, 7418 ]; 7419 7420 $id = $this->table('users_groups')->insert($data); 7421 7422 $this->manage_group($group, $include_groups); 7423 7424 7425 TikiLib::events()->trigger('tiki.group.create', [ 7426 'type' => 'group', 7427 'object' => $group, 7428 ]); 7429 7430 $cachelib = TikiLib::lib('cache'); 7431 $cachelib->invalidate('grouplist'); 7432 $cachelib->invalidate('groupIdlist'); 7433 7434 return $id; 7435 } 7436 7437 function change_group( 7438 $olgroup, 7439 $group, 7440 $desc, 7441 $home, 7442 $utracker = 0, 7443 $gtracker = 0, 7444 $ufield = 0, 7445 $gfield = 0, 7446 $rufields = '', 7447 $userChoice = '', 7448 $defcat = 0, 7449 $theme = '', 7450 $isexternal = 'n', 7451 $expireAfter = 0, 7452 $emailPattern = '', 7453 $anniversary = '', 7454 $prorateInterval = '', 7455 $color = '', 7456 $isRole = '', 7457 $isTplGroup = '', 7458 $include_groups = [] 7459 ) { 7460 $isTplGroup = empty($isTplGroup) ? 'n' : $isTplGroup; 7461 $users = $this->get_group_users($group); 7462 if (! empty($users) && $isRole == "y") { 7463 throw new Exception(tr('Role groups can\'t have users.')); 7464 } 7465 7466 if ($olgroup == 'Anonymous' || $olgroup == 'Registered') { 7467 // Changing group name of 'Anonymous' and 'Registered' is not allowed. 7468 if ($group != $olgroup) { 7469 return false; 7470 } 7471 } 7472 7473 if (! $this->group_exists($olgroup)) { 7474 return $this->add_group( 7475 $group, 7476 $desc, 7477 $home, 7478 $utracker, 7479 $gtracker, 7480 $rufields, 7481 $userChoice, 7482 $defcat, 7483 $theme, 7484 $isexternal, 7485 $expireAfter, 7486 $emailPattern, 7487 $anniversary, 7488 $prorateInterval, 7489 $color, 7490 $isRole, 7491 $isTplGroup 7492 ); 7493 } 7494 7495 $cachelib = TikiLib::lib('cache'); 7496 7497 $tx = TikiDb::get()->begin(); 7498 7499 $data = [ 7500 'groupName' => $group, 7501 'groupDesc' => $desc, 7502 'groupHome' => $home, 7503 'groupDefCat' => $defcat, 7504 'groupTheme' => $theme, 7505 'groupColor' => $color, 7506 'usersTrackerId' => (int)$utracker, 7507 'groupTrackerId' => (int)$gtracker, 7508 'registrationUsersFieldIds' => $rufields, 7509 'userChoice' => $userChoice, 7510 'usersFieldId' => (int)$ufield, 7511 'groupFieldId' => (int)$gfield, 7512 'isExternal' => $isexternal, 7513 'expireAfter' => $expireAfter, 7514 'emailPattern' => $emailPattern, 7515 'anniversary' => $anniversary, 7516 'prorateInterval' => $prorateInterval, 7517 'isRole' => $isRole, 7518 'isTplGroup' => $isTplGroup, 7519 ]; 7520 7521 $this->table('users_groups')->update($data, ['groupName' => $olgroup]); 7522 7523 if ($olgroup != $group) { 7524 $query = []; 7525 $query[] = 'update `users_usergroups` set `groupName`=? where `groupName`=?'; 7526 $query[] = 'update `users_grouppermissions` set `groupName`=? where `groupName`=?'; 7527 $query[] = 'update `users_objectpermissions` set `groupName`=? where `groupName`=?'; 7528 $query[] = 'update `tiki_group_inclusion` set `groupName`=? where `groupName`=?'; 7529 $query[] = 'update `tiki_group_inclusion` set `includeGroup`=? where `includeGroup`=?'; 7530 $query[] = 'update `tiki_newsletter_groups` set `groupName`=? where `groupName`=?'; 7531 $query[] = 'update `tiki_group_watches` set `group`=? where `group`=?'; 7532 7533 foreach ($query as $q) { 7534 $this->query($q, [$group, $olgroup]); 7535 } 7536 7537 // must unserialize before replacing the groups 7538 $query = 'select `name`, `groups` from `tiki_modules` where `groups` like ?'; 7539 $result = $this->query($query, ['%' . $olgroup . '%']); 7540 7541 while ($res = $result->fetchRow()) { 7542 $aux = []; 7543 $aux['name'] = $res['name']; 7544 $aux['groups'] = unserialize($res['groups']); 7545 $aux['groups'] = str_replace($olgroup, $group, $aux['groups']); 7546 $aux['groups'] = serialize($aux['groups']); 7547 $query = 'update `tiki_modules` set `groups`=? where `name`=?'; 7548 $this->query($query, [$aux['groups'], $aux['name']]); 7549 } 7550 7551 $query = 'select * from `tiki_tracker_fields` where `visibleBy` like ?'; 7552 $result = $this->query($query, ['%"' . $olgroup . '"%']); 7553 $query = 'update `tiki_tracker_fields` set `visibleBy`=? where `visibleBy`=?'; 7554 while ($res = $result->fetchRow()) { 7555 $g = unserialize($res['visibleBy']); 7556 $g = str_replace($olgroup, $group, $g); 7557 $g = serialize($g); 7558 $this->query($query, [$g, $res['visibleBy']]); 7559 } 7560 7561 $query = 'select * from `tiki_tracker_fields` where `editableBy` like ?'; 7562 $result = $this->query($query, ['%"' . $olgroup . '"%']); 7563 7564 $query = 'update `tiki_tracker_fields` set `editableBy`=? where `editableBy`=?'; 7565 while ($res = $result->fetchRow()) { 7566 $g = unserialize($res['editableBy']); 7567 $g = str_replace($olgroup, $group, $g); 7568 $g = serialize($g); 7569 $this->query($query, [$g, $res['editableBy']]); 7570 } 7571 7572 $query = 'update `tiki_tracker_item_fields` ttif' . 7573 ' left join `tiki_tracker_fields` ttf on (ttf.`fieldId`=ttif.`fieldId`)' . 7574 ' set ttif.`value`=? where ttif.`value`=? and ttf.`type`=?'; 7575 7576 $this->query($query, [$group, $olgroup, 'g']); 7577 7578 $cachelib->invalidate('grouplist'); 7579 $cachelib->invalidate('group_theme_' . $group); 7580 7581 TikiLib::events()->trigger('tiki.group.delete', [ 7582 'type' => 'group', 7583 'object' => $olgroup, 7584 ]); 7585 } 7586 7587 7588 $this->manage_group($group, $include_groups); 7589 7590 $cachelib->invalidate('group_theme_' . $olgroup); 7591 7592 TikiLib::events()->trigger('tiki.group.update', [ 7593 'type' => 'group', 7594 'object' => $group, 7595 ]); 7596 7597 $tx->commit(); 7598 7599 return true; 7600 } 7601 7602 function edit_group($id, $name, $description) 7603 { 7604 // Limited editing only, for users with the tiki_p_edit_grouplimitedinfo perm 7605 $groupInfo = $this->get_groupId_info($id); 7606 if (!$groupInfo) 7607 return false; 7608 $includeGroups = $this->get_included_groups($groupInfo["groupName"]); 7609 7610 $this->change_group($groupInfo["groupName"], $name, $description 7611 , $groupInfo["groupHome"], $groupInfo["usersTrackerId"], $groupInfo["groupTrackerId"] 7612 , $groupInfo["groupTrackerId"], $groupInfo["groupFieldId"], $groupInfo["registrationUsersFieldIds"] 7613 , $groupInfo["userChoice"], $groupInfo["groupDefCat"], $groupInfo["groupTheme"] 7614 , $groupInfo["isExternal"], $groupInfo["expireAfter"], $groupInfo["emailPattern"] 7615 , $groupInfo["anniversary"], $groupInfo["prorateInterval"], $groupInfo["groupColor"] 7616 , $groupInfo["isRole"], $groupInfo["isTplGroup"], $includeGroups); 7617 return true; 7618 } 7619 7620 function remove_all_inclusions($group) 7621 { 7622 if (! $this->group_exists($group)) { 7623 return false; 7624 } 7625 7626 $query = 'delete from `tiki_group_inclusion` where `groupName` = ?'; 7627 $result = $this->query($query, [$group]); 7628 $cachelib = TikiLib::lib('cache'); 7629 $cachelib->empty_type_cache('group_inclusion_' . $group); 7630 $this->groupinclude_cache = []; 7631 7632 return true; 7633 } 7634 7635 function set_user_fields($u) 7636 { 7637 global $prefs; 7638 7639 $q = []; 7640 $bindvars = []; 7641 7642 if (isset($u['email'])) { 7643 if ($prefs['user_unique_email'] == 'y' && $this->other_user_has_email($u['login'], $u['email'])) { 7644 $smarty = TikiLib::lib('smarty'); 7645 $smarty->assign('errortype', 'login'); 7646 $smarty->assign('msg', tra('Email cannot be set because this email is already in use by another user.')); 7647 $smarty->display('error.tpl'); 7648 die; 7649 } 7650 $q[] = '`email` = ?'; 7651 $bindvars[] = strip_tags($u['email']); 7652 } 7653 7654 if (isset($u['openid_url'])) { 7655 if (isset($_SESSION['openid_url'])) { 7656 $q[] = '`openid_url` = ?'; 7657 $bindvars[] = $u['openid_url']; 7658 } 7659 } 7660 7661 if (count($q) > 0) { 7662 $query = 'update `users_users` set ' . implode(',', $q) . ' where binary `login` = ?'; 7663 $bindvars[] = $u['login']; 7664 $result = $this->query($query, $bindvars); 7665 } 7666 7667 $aUserPrefs = ['realName', 'homePage', 'country']; 7668 foreach ($aUserPrefs as $pref) { 7669 if (isset($u[$pref])) { 7670 $this->set_user_preference($u['login'], $pref, $u[$pref]); 7671 } 7672 } 7673 7674 return $result; 7675 } 7676 7677 function count_users($group) 7678 { 7679 static $rv = []; 7680 7681 if (! isset($rv[$group])) { 7682 if ($group == '') { 7683 $query = 'select count(login) from `users_users`'; 7684 $result = $this->getOne($query); 7685 } else { 7686 $query = 'select count(userId) from `users_usergroups` where `groupName` = ?'; 7687 $result = $this->getOne($query, [$group]); 7688 } 7689 $rv[$group] = $result; 7690 } 7691 7692 return $rv[$group]; 7693 } 7694 7695 function count_users_consolidated($groups) 7696 { 7697 $groupset = implode("','", $groups); 7698 $query = "select userId from `users_usergroups` where `groupName` in ('" . $groupset . "')"; 7699 $result = $this->fetchAll($query, []); 7700 $resultcons = array_unique(array_column($result, 'userId')); 7701 return count($resultcons); 7702 } 7703 7704 function related_users($user, $max = 10, $type = 'wiki') 7705 { 7706 if (! isset($user) || empty($user)) { 7707 return []; 7708 } 7709 7710 // This query was written using a double join for PHP. If you're trying to eke 7711 // additional performance and are running MySQL 4.X, you might want to try a 7712 // subselect and compare perf numbers. 7713 7714 if ($type == 'wiki') { 7715 $query = 'SELECT u1.`login`, COUNT( p1.`pageName` ) AS quantity 7716 FROM `tiki_history` p1 7717 INNER JOIN `users_users` u1 ON ( u1.`login` = p1.`user` ) 7718 INNER JOIN `tiki_history` p2 ON ( p1.`pageName` = p2.`pageName` ) 7719 INNER JOIN `users_users` u2 ON ( u2.`login` = p2.`user` ) 7720 WHERE u2.`login` = ? AND u1.`login` <> ? 7721 GROUP BY p1.`pageName`, u1.`login` 7722 ORDER BY quantity DESC 7723 '; 7724 } else { 7725 return []; 7726 } 7727 7728 $bindvals = [$user, $user]; 7729 7730 return $this->fetchAll($query, $bindvals, $max, 0); 7731 } 7732 7733 // Case-sensitivity regression only. used for patching 7734 function get_object_case_permissions($objectId, $objectType) 7735 { 7736 $query = 'select `groupName`, `permName` from `users_objectpermissions` where `objectId` = ? and `objectType` = ?'; 7737 return $this->fetchAll($query, [md5($objectType . $objectId),$objectType]); 7738 } 7739 7740 function object_has_one_case_permission($objectId, $objectType) 7741 { 7742 $query = 'select count(*) from `users_objectpermissions` where `objectId`=? and `objectType`=?'; 7743 $result = $this->getOne($query, [ md5($objectType . $objectId), $objectType]); 7744 return $result; 7745 } 7746 7747 function remove_object_case_permission($groupName, $objectId, $objectType, $permName) 7748 { 7749 $query = 'delete from `users_objectpermissions`' . 7750 ' where `groupName` = ? and `objectId` = ? and `objectType` = ? and `permName` = ?'; 7751 $result = $this->query($query, [$groupName, md5($objectType . $objectId), $objectType, $permName]); 7752 7753 return true; 7754 } 7755 7756 function send_validation_email( 7757 $name, 7758 $apass, 7759 $email, 7760 $again = '', 7761 $second = '', 7762 $chosenGroup = '', 7763 $mailTemplate = '', 7764 $pass = '' 7765 ) { 7766 7767 global $prefs; 7768 $tikilib = TikiLib::lib('tiki'); 7769 $smarty = TikiLib::lib('smarty'); 7770 7771 // mail_machine kept for BC, use $validation_url 7772 $machine = TikiLib::tikiUrl('tiki-login_validate.php'); 7773 $machine_assignuser = TikiLib::tikiUrl('tiki-assignuser.php'); 7774 $machine_userprefs = TikiLib::tikiUrl('tiki-user_preferences.php'); 7775 $smarty->assign('mail_machine', $machine); 7776 $smarty->assign('mail_machine_assignuser', $machine_assignuser); 7777 $smarty->assign('mail_machine_userprefs', $machine_userprefs); 7778 $smarty->assign('mail_site', $_SERVER['SERVER_NAME']); 7779 $smarty->assign('mail_user', $name); 7780 $smarty->assign('mail_apass', $apass); 7781 $smarty->assign('mail_email', $email); 7782 $smarty->assign('mail_again', $again); 7783 $smarty->assign( 7784 'validation_url', 7785 TikiLib::tikiUrl( 7786 'tiki-login_validate.php', 7787 [ 7788 'user' => $name, 7789 'pass' => $apass, 7790 ] 7791 ) 7792 ); 7793 $smarty->assign( 7794 'assignuser_url', 7795 TikiLib::tikiUrl( 7796 'tiki-assignuser.php', 7797 ['assign_user' => $name] 7798 ) 7799 ); 7800 $smarty->assign( 7801 'userpref_url', 7802 TikiLib::tikiUrl( 7803 'tiki-user_preferences.php', 7804 ['view_user' => $name] 7805 ) 7806 ); 7807 7808 include_once('lib/webmail/tikimaillib.php'); 7809 7810 if ($second == 'y') { 7811 $mail_data = $smarty->fetch('mail/confirm_user_email_after_approval.tpl'); 7812 $mail = new TikiMail(); 7813 $mail->setText($mail_data); 7814 $mail_data = sprintf($smarty->fetch('mail/confirm_user_email_after_approval_subject.tpl'), $_SERVER['SERVER_NAME']); 7815 $mail->setSubject($mail_data); 7816 if (! $mail->send([$email])) { 7817 $smarty->assign('msg', tra("The registration mail can't be sent. Contact the administrator")); 7818 return false; 7819 } 7820 } elseif ($prefs['validateRegistration'] == 'y' && empty($pass) && $mailTemplate != 'user_creation_validation_mail') { 7821 if (! empty($chosenGroup)) { 7822 $smarty->assign_by_ref('chosenGroup', $chosenGroup); 7823 if ($prefs['userTracker'] == 'y') { 7824 $trklib = TikiLib::lib('trk'); 7825 $re = $this->get_group_info(isset($chosenGroup) ? $chosenGroup : 'Registered'); 7826 $fields = $trklib->list_tracker_fields( 7827 $re['usersTrackerId'], 7828 0, 7829 -1, 7830 'position_asc', 7831 '', 7832 true, 7833 ['fieldId' => explode(':', $re['registrationUsersFieldIds'])] 7834 ); 7835 7836 $listfields = []; 7837 7838 foreach ($fields['data'] as $field) { 7839 $listfields[$field['fieldId']] = $field; 7840 } 7841 7842 $definition = Tracker_Definition::get($re['usersTrackerId']); 7843 if ($definition) { 7844 $items = $trklib->list_items( 7845 $re['usersTrackerId'], 7846 0, 7847 1, 7848 '', 7849 $listfields, 7850 $definition->getUserField(), 7851 '', 7852 '', 7853 '', 7854 $name, 7855 '', 7856 null, 7857 true, 7858 true 7859 ); 7860 7861 if (isset($items['data'][0])) { 7862 $smarty->assign_by_ref('item', $items['data'][0]); 7863 } 7864 } else { 7865 Feedback::error(tr('No user tracker found with id #%0', $re['usersTrackerId'])); 7866 } 7867 } 7868 } 7869 $mail_data = $smarty->fetch('mail/moderate_validation_mail.tpl'); 7870 $mail_subject = $smarty->fetch('mail/moderate_validation_mail_subject.tpl'); 7871 7872 $emails = ! empty($prefs['validator_emails']) 7873 ? preg_split('/,/', $prefs['validator_emails']) 7874 : (! empty($prefs['sender_email']) ? [$prefs['sender_email']] : ''); 7875 7876 if (empty($emails)) { 7877 if ($prefs['feature_messages'] != 'y') { 7878 $smarty->assign( 7879 'msg', 7880 tra("The registration mail can't be sent because there is no server email address set, and this feature is disabled") . 7881 ": feature_messages" 7882 ); 7883 return false; 7884 } 7885 7886 TikiLib::lib('message')->post_message( 7887 $prefs['contact_user'], 7888 $prefs['contact_user'], 7889 $prefs['contact_user'], 7890 '', 7891 $mail_subject, 7892 $mail_data, 7893 5 7894 ); 7895 $smarty->assign('msg', $smarty->fetch('mail/user_validation_waiting_msg.tpl')); 7896 } else { 7897 $mail = new TikiMail(); 7898 $mail->setText($mail_data); 7899 $mail->setSubject($mail_subject); 7900 if (! $mail->send($emails)) { 7901 $smarty->assign('msg', tra("The registration mail can't be sent. Contact the administrator")); 7902 return false; 7903 } elseif (empty($again)) { 7904 $smarty->assign('msg', $smarty->fetch('mail/user_validation_waiting_msg.tpl')); 7905 } else { 7906 $smarty->assign('msg', tra('The administrator has not yet validated your account. Please wait.')); 7907 } 7908 } 7909 } elseif ($prefs['validateUsers'] == 'y' || ! empty($pass) || $mailTemplate == 'user_creation_validation_mail') { 7910 if ($mailTemplate == '') { 7911 $mailTemplate = 'user_validation_mail'; 7912 } 7913 7914 $smarty->assign( 7915 'validation_url', 7916 TikiLib::tikiUrl( 7917 'tiki-login_validate.php', 7918 [ 7919 'user' => $name, 7920 'pass' => $apass, 7921 ] 7922 ) 7923 ); 7924 7925 $mail_data = $smarty->fetch("mail/$mailTemplate.tpl"); 7926 $mail = new TikiMail(); 7927 $mail->setText($mail_data); 7928 $mail_data = $smarty->fetch("mail/{$mailTemplate}_subject.tpl"); 7929 $mail->setSubject($mail_data); 7930 if (! $mail->send([$email])) { 7931 $smarty->assign('msg', tra("The registration mail can't be sent. Contact the administrator")); 7932 return false; 7933 } elseif (empty($again)) { 7934 $smarty->assign('msg', $smarty->fetch('mail/user_validation_msg.tpl')); 7935 } else { 7936 $smarty->assign('msg', tra('You must validate your account first. An email has been sent to you')); 7937 } 7938 } 7939 return true; 7940 } 7941 7942 function set_registrationChoice($groups, $flag) 7943 { 7944 $bindvars = []; 7945 $bindvars[] = $flag; 7946 if (is_array($groups)) { 7947 $mid = implode(',', array_fill(0, count($groups), '?')); 7948 $bindvars = array_merge($bindvars, $groups); 7949 } else { 7950 $bindvars[] = $groups; 7951 $mid = 'like ?'; 7952 } 7953 $query = "update `users_groups` set `registrationChoice`= ? where `groupName` in ($mid)"; 7954 $result = $this->query($query, $bindvars); 7955 } 7956 7957 function get_registrationChoice($group) 7958 { 7959 $query = 'select `registrationChoice` from `users_groups` where `groupName` = ?'; 7960 return ($this->getOne($query, [$group])); 7961 } 7962 7963 function reset_email_due($user) 7964 { 7965 $query = 'update `users_users` set `email_confirm`=?, `waiting`=? where `login`=?'; 7966 $result = $this->query($query, [0, 'u', $user]); 7967 TikiLib::events()->trigger('tiki.user.update', ['type' => 'user', 'object' => $user]); 7968 return $result; 7969 } 7970 7971 function confirm_email($user, $pass) 7972 { 7973 $tikilib = TikiLib::lib('tiki'); 7974 $query = 'select `provpass`, `login`, `unsuccessful_logins` from `users_users` where `login`=?'; 7975 $result = $this->query($query, [$user]); 7976 if (! ($res = $result->fetchRow())) { 7977 return false; 7978 } 7979 7980 if (md5($res['provpass']) == $pass) { 7981 $this->confirm_user($user); 7982 7983 $query = 'update `users_users`' . 7984 ' set `provpass`=?, `email_confirm`=?, `unsuccessful_logins`=?, `registrationDate`=?' . 7985 ' where `login`=? and `provpass`=?'; 7986 7987 $this->query($query, ['', $tikilib->now, 0, $this->now, $user, $res['provpass']]); 7988 if (! empty($GLOBALS['user'])) { 7989 $logslib = TikiLib::lib('logs'); 7990 $logslib->add_log('login', 'confirm email ' . $user); 7991 } 7992 TikiLib::lib('user')->set_unsuccessful_logins($_REQUEST['user'], 0); 7993 return true; 7994 } 7995 7996 return false; 7997 } 7998 7999 function set_unsuccessful_logins($user, $nb) 8000 { 8001 $query = 'update `users_users` set `unsuccessful_logins`=? where `login` = ?'; 8002 $this->query($query, [$nb, $user]); 8003 } 8004 8005 function send_confirm_email($user, $tpl = 'confirm_user_email') 8006 { 8007 global $prefs; 8008 $tikilib = TikiLib::lib('tiki'); 8009 $smarty = TikiLib::lib('smarty'); 8010 8011 include_once('lib/webmail/tikimaillib.php'); 8012 $languageEmail = $this->get_user_preference($_REQUEST['username'], 'language', $prefs['site_language']); 8013 $apass = $this->renew_user_password($user); 8014 $apass = md5($apass); 8015 $smarty->assign('mail_apass', $apass); 8016 $smarty->assign('mail_ip', $tikilib->get_ip_address()); 8017 $smarty->assign('user', $user); 8018 $mail = new TikiMail(); 8019 $mail_data = $smarty->fetchLang($languageEmail, "mail/$tpl" . '_subject.tpl'); 8020 $mail_data = sprintf($mail_data, $_SERVER['SERVER_NAME']); 8021 $mail->setSubject($mail_data); 8022 $foo = parse_url($_SERVER['REQUEST_URI']); 8023 $mail_machine = TikiLib::tikiUrl('tiki-confirm_user_email.php'); // for BC 8024 $smarty->assign('mail_machine', $mail_machine); 8025 $mail_data = $smarty->fetchLang($languageEmail, "mail/$tpl.tpl"); 8026 $mail->setText($mail_data); 8027 8028 if (! ($email = $this->get_user_email($user)) || ! $mail->send([$email])) { 8029 $smarty->assign('msg', tra("The user email confirmation can't be sent. Contact the administrator")); 8030 return false; 8031 } else { 8032 $smarty->assign('msg', 'It is time to confirm your email. You will receive an mail with the instruction to follow'); 8033 return true; 8034 } 8035 } 8036 8037 function assign_openid($username, $openid) 8038 { 8039 // This won't update the database unless the openid is different 8040 $this->query( 8041 "UPDATE `users_users` SET openid_url = ? WHERE login = ? AND ( openid_url <> ? OR openid_url IS NULL )", 8042 [$openid, $username, $openid] 8043 ); 8044 } 8045 8046 function intervalidate($remote, $user, $pass, $get_info = false) 8047 { 8048 global $prefs; 8049 $hashkey = $this->get_cookie_check() . '.' . ($this->now + $prefs['remembertime']); 8050 $remote['path'] = preg_replace('/^\/?/', '/', $remote['path']); 8051 $client = new XML_RPC_Client($remote['path'], $remote['host'], $remote['port']); 8052 $client->setDebug(0); 8053 8054 $msg = new XML_RPC_Message( 8055 'intertiki.validate', 8056 [ 8057 new XML_RPC_Value($prefs['tiki_key'], 'string'), 8058 new XML_RPC_Value($user, 'string'), 8059 new XML_RPC_Value($pass, 'string'), 8060 new XML_RPC_Value($get_info, 'boolean'), 8061 new XML_RPC_Value($hashkey, 'string') 8062 ] 8063 ); 8064 $result = $client->send($msg); 8065 8066 return $result; 8067 } 8068 8069 /* send request + interpret email/login */ 8070 function interGetUserInfo($remote, $user, $email) 8071 { 8072 global $prefs; 8073 $remote['path'] = preg_replace('/^\/?/', '/', $remote['path']); 8074 $client = new XML_RPC_Client($remote['path'], $remote['host'], $remote['port']); 8075 $client->setDebug(0); 8076 $params = []; 8077 $params[] = new XML_RPC_Value($prefs['tiki_key'], 'string'); 8078 $params[] = new XML_RPC_Value($user, 'string'); 8079 $params[] = new XML_RPC_Value($email, 'string'); 8080 $msg = new XML_RPC_Message('intertiki.getUserInfo', $params); 8081 $rpcauth = $client->send($msg); 8082 8083 if (! $rpcauth || $rpcauth->faultCode()) { 8084 return false; 8085 } 8086 8087 $response_value = $rpcauth->value(); 8088 8089 for (;;) { 8090 list($key, $value) = $response_value->structeach(); 8091 if ($key == '') { 8092 break; 8093 } elseif ($key == 'login') { 8094 $u['login'] = $value->scalarval(); 8095 } elseif ($key == 'email') { 8096 $u['email'] = $value->scalarval(); 8097 } 8098 } 8099 8100 return $u; 8101 } 8102 8103 /* send via XML_RPC user info to the main */ 8104 function interSendUserInfo($remote, $user) 8105 { 8106 global $prefs; 8107 $userlib = TikiLib::lib('user'); 8108 $remote['path'] = preg_replace('/^\/?/', '/', $remote['path']); 8109 $client = new XML_RPC_Client($remote['path'], $remote['host'], $remote['port']); 8110 $client->setDebug(0); 8111 $params = []; 8112 $params[] = new XML_RPC_Value($prefs['tiki_key'], 'string'); 8113 $params[] = new XML_RPC_Value($user, 'string'); 8114 $user_details = $userlib->get_user_details($user); 8115 $user_info = $userlib->get_user_info($user); 8116 $ret['avatarData'] = new XML_RPC_Value($user_info['avatarData'], 'base64'); 8117 $ret['user_details'] = new XML_RPC_Value(serialize($user_details), 'string'); 8118 $params[] = new XML_RPC_Value($ret, 'struct'); 8119 $msg = new XML_RPC_Message('intertiki.setUserInfo', $params); 8120 $result = $client->send($msg); 8121 8122 return $result; 8123 } 8124 8125 /* interpret the XML_RPC answer about user info */ 8126 function interSetUserInfo($user, $response_value) 8127 { 8128 $userlib = TikiLib::lib('user'); 8129 $tikilib = TikiLib::lib('tiki'); 8130 8131 if ($response_value->kindOf() == 'struct') { 8132 for (;;) { 8133 list($key, $value) = $response_value->structeach(); 8134 if ($key == '') { 8135 break; 8136 } elseif ($key == 'user_details') { 8137 $user_details = unserialize($value->scalarval()); 8138 } elseif ($key == 'avatarData') { 8139 $avatarData = $value->scalarval(); 8140 } 8141 } 8142 } else { 8143 $user_details = unserialize($response_value->scalarval()); 8144 } 8145 8146 $userlib->set_user_fields($user_details['info']); 8147 $tikilib->set_user_preferences($user, $user_details['preferences']); 8148 8149 if (! empty($avatarData)) { 8150 $userprefslib = TikiLib::lib('userprefs'); 8151 $userprefslib->set_user_avatar( 8152 $user, 8153 'u', 8154 '', 8155 $user_details['info']['avatarName'], 8156 $user_details['info']['avatarSize'], 8157 $user_details['info']['avatarFileType'], 8158 $avatarData, 8159 false 8160 ); 8161 } 8162 } 8163 8164 function get_remote_user_by_cookie($hash) 8165 { 8166 global $prefs; 8167 8168 $remote = $prefs['interlist'][$prefs['feature_intertiki_mymaster']]; 8169 $client = new XML_RPC_Client($remote['path'], $remote['host'], $remote['port']); 8170 $client->setDebug(0); 8171 8172 $msg = new XML_RPC_Message( 8173 'intertiki.cookiecheck', 8174 [ 8175 new XML_RPC_Value($prefs['tiki_key'], 'string'), 8176 new XML_RPC_Value($hash, 'string') 8177 ] 8178 ); 8179 $er = error_reporting(); // suppress PHP 7.2 warnings from xmlrpc lib 8180 error_reporting(E_ALL ^ (E_NOTICE | E_WARNING | E_DEPRECATED)); 8181 $result = $client->send($msg); 8182 error_reporting($er); 8183 8184 return $result; 8185 } 8186 8187 function update_expired_groups() 8188 { 8189 $tikilib = TikiLib::lib('tiki'); 8190 $this->update_anniversary_expiry(); 8191 $query = 'SELECT uu.* FROM `users_usergroups` uu' . 8192 ' LEFT JOIN `users_groups` ug ON (uu.`groupName`= ug.`groupName`)' . 8193 ' WHERE ( ug.`expireAfter` > ? AND uu.`created` IS NOT NULL AND uu.`expire` is NULL AND uu.`created` + ug.`expireAfter`*24*60*60 < ?)' . 8194 ' OR ((ug.`expireAfter` IS NOT NULL OR ug.`anniversary` > ?) AND uu.`expire` < ?)'; 8195 8196 $result = $this->query($query, [0, $tikilib->now, 0, $tikilib->now]); 8197 8198 while ($res = $result->fetchRow()) { 8199 $this->remove_user_from_group($this->get_user_login($res['userId']), $res['groupName']); 8200 } 8201 } 8202 8203 function update_anniversary_expiry() 8204 { 8205 $query = 'SELECT uu.* FROM `users_usergroups` uu' . 8206 ' LEFT JOIN `users_groups` ug ON (uu.`groupName`= ug.`groupName`)' . 8207 ' WHERE ( ug.`anniversary` > ? AND uu.`created` IS NOT NULL AND uu.`expire` is NULL )'; 8208 8209 $result = $this->query($query, ['']); 8210 8211 $query = 'UPDATE `users_usergroups` SET `expire` = ? WHERE `groupName`=? AND `userId`=?'; 8212 8213 while ($res = $result->fetchRow()) { 8214 $extend_until_info = $this->get_extend_until_info($res['login'], $res['groupName']); 8215 $this->query($query, [$extend_until_info['timestamp'], $res['groupName'], $res['userId']]); 8216 } 8217 } 8218 8219 function update_group_expiries() 8220 { 8221 $query = 'SELECT uu.* FROM `users_usergroups` uu' . 8222 ' LEFT JOIN `users_groups` ug ON (uu.`groupName`= ug.`groupName`)' . 8223 ' WHERE ( uu.`created` IS NOT NULL AND uu.`expire` is NULL )' . 8224 ' AND (ug.`anniversary` > ? OR ug.`expireAfter` > ?)'; 8225 8226 $result = $this->query($query, ['', 0]); 8227 8228 $query = 'UPDATE `users_usergroups` SET `expire` = ? WHERE `groupName`=? AND `userId`=?'; 8229 8230 while ($res = $result->fetchRow()) { 8231 $uinfo = $this->get_userid_info($res['userId']); 8232 $extend_until_info = $this->get_extend_until_info($uinfo['login'], $res['groupName']); 8233 $this->query($query, [$extend_until_info['timestamp'], $res['groupName'], $res['userId']]); 8234 } 8235 } 8236 8237 8238 function extend_membership($user, $group, $periods = 1, $date = null) 8239 { 8240 $tikilib = TikiLib::lib('tiki'); 8241 $this->update_expired_groups(); 8242 8243 if (! $this->user_is_in_group($user, $group)) { 8244 $this->assign_user_to_group($user, $group); 8245 if ($periods > 1) { 8246 $periods--; 8247 } elseif (empty($date)) { 8248 return; 8249 } 8250 } 8251 8252 $info = $this->get_group_info($group); 8253 $userInfo = $this->get_user_info($user); 8254 if (empty($date)) { 8255 $extend_until_info = $this->get_extend_until_info($user, $group, $periods); 8256 } else { 8257 $extend_until_info['timestamp'] = $date; 8258 } 8259 8260 $this->query( 8261 'UPDATE `users_usergroups` SET `expire` = ? WHERE `userId` = ? AND `groupName` = ?', 8262 [$extend_until_info['timestamp'], $userInfo['userId'], $group] 8263 ); 8264 } 8265 8266 function get_extend_until_info($user, $group, $periods = 1) 8267 { 8268 //use these functions to get current expiry dates for existing members - they are calculated in some cases 8269 //so just grabbing the "expire" field from the users_usergroups table doesn't always work 8270 $userInfo = $this->get_user_info($user); 8271 $usergroupdates = $this->get_user_groups_date($userInfo['userId']); 8272 8273 $info = $this->get_group_info($group); 8274 //set the start date as now for new memberships and as expiry of current membership for existing members 8275 if (array_key_exists($group, $usergroupdates)) { 8276 if (! empty($usergroupdates[$group]['expire'])) { 8277 $date = $usergroupdates[$group]['expire']; 8278 } elseif ($info['expireAfter'] > 0) { 8279 $date = $usergroupdates[$group]['created']; 8280 } 8281 } 8282 if (! isset($date) || ! $date) { 8283 $date = $this->now; 8284 //this is a new membership 8285 $new = true; 8286 } else { 8287 $new = false; 8288 } 8289 //convert start date to object 8290 $rawstartutc = new DateTimeImmutable('@' . $date); 8291 global $prefs; 8292 $tz = TikiDate::TimezoneIsValidId($prefs['server_timezone']) ? $prefs['server_timezone'] : 'UTC'; 8293 $timezone = new DateTimeZone($tz); 8294 $startlocal = $rawstartutc->setTimezone($timezone); 8295 8296 //anniversary memberships 8297 if (! empty($info['anniversary'])) { 8298 //set time to 1 second after midnight so that all times are set to same times for interval calculations 8299 $startlocal = $startlocal->setTime(0, 0, 1); 8300 // annual anniversaries 8301 if (strlen($info['anniversary']) == 4) { 8302 $ann_month = substr($info['anniversary'], 0, 2); 8303 $ann_day = substr($info['anniversary'], 2, 2); 8304 $startyear = $startlocal->format('Y'); 8305 //increment the year if past the annual anniversary 8306 if ($startlocal->format('m') > $ann_month || ($startlocal->format('m') == $ann_month 8307 && $startlocal->format('d') >= $ann_day)) { 8308 $startyear++; 8309 } 8310 //first extension is always to next anniversary 8311 $next_ann = $startlocal->setDate($startyear, $ann_month, $ann_day); 8312 //extend past next anniversary if more than one period 8313 $extendto = $next_ann->modify('+' . $periods - 1 . ' years'); 8314 //previous anniversary for proration 8315 $prev_ann = $next_ann->modify('-1 years'); 8316 // monthly anniversaries 8317 //using modify('+1 month') can result in "skipping" months so fix the day of the previous/next month 8318 } elseif (strlen($info['anniversary']) == 2) { 8319 $ann_day = $info['anniversary']; 8320 $lastday = date('d', strtotime('last day of ' . $startlocal->format('Y') . '-' 8321 . $startlocal->format('m'))); 8322 $mod_ann_day = $ann_day > $lastday ? $lastday : $ann_day; 8323 if ($startlocal->format('d') < $mod_ann_day) { 8324 $mod = $mod_ann_day - $startlocal->format('d'); 8325 $next_ann = $startlocal->modify('+' . $mod . ' days'); 8326 $prev_mo_lastday = $startlocal->modify('last day of last month'); 8327 if ($ann_day >= $prev_mo_lastday->format('d')) { 8328 $prev_ann = $prev_mo_lastday; 8329 } else { 8330 $prev_ann = $startlocal->setDate( 8331 $prev_mo_lastday->format('Y'), 8332 $prev_mo_lastday->format('m'), 8333 $mod_ann_day 8334 ); 8335 } 8336 } else { 8337 //check if last day of month 8338 $next_mo_lastday = $startlocal->modify('last day of next month'); 8339 if ($mod_ann_day >= $next_mo_lastday->format('d')) { 8340 $next_ann = $next_mo_lastday; 8341 } else { 8342 $next_ann = $startlocal->setDate( 8343 $next_mo_lastday->format('Y'), 8344 $next_mo_lastday->format('m'), 8345 $mod_ann_day 8346 ); 8347 } 8348 $mod = $startlocal->format('d') - $mod_ann_day; 8349 $prev_ann = $startlocal->modify('-' . $mod . ' days'); 8350 } 8351 if ($periods - 1 > 0) { 8352 $yrsplus = floor(($periods - 1) / 12); 8353 $yr = $next_ann->format('Y') + $yrsplus; 8354 $moplus = ($periods - 1) - ($yrsplus * 12); 8355 if ($moplus + $next_ann->format('m') < 12) { 8356 $mo = $moplus + $next_ann->format('m'); 8357 } else { 8358 $yr++; 8359 $mo = $moplus + $next_ann->format('m') - 12; 8360 } 8361 if ($ann_day >= date('d', strtotime('last day of ' . $yr . '-' . $mo))) { 8362 $d = date('d', strtotime('last day of ' . $yr . '-' . $mo)); 8363 } else { 8364 $d = $ann_day; 8365 } 8366 $extendto = $next_ann->setDate($yr, $mo, $d); 8367 } else { 8368 $extendto = $next_ann; 8369 } 8370 } 8371 //calculate interval of membership term 8372 $interval = $startlocal->diff($extendto); 8373 //set prorate interval 8374 $prorateInterval = in_array($info['prorateInterval'], ['year', 'month', 'day']) ? $info['prorateInterval'] 8375 : 'day'; 8376 //prorate 8377 if ($prorateInterval == 'year' && strlen($info['anniversary']) == 4) { 8378 $ratio = $interval->y; 8379 $ratio += $interval->m > 0 || $interval->d > 0 ? 1 : 0; 8380 } elseif ($prorateInterval == 'month' 8381 || ($prorateInterval == 'year' && strlen($info['anniversary']) == 2)) { 8382 $round = $interval->d > 0 ? 1 : 0; 8383 $ratio = (($interval->y * 12) + $interval->m + $round); 8384 if (strlen($info['anniversary']) == 4) { 8385 $ratio = $ratio / 12; 8386 } 8387 } elseif ($prorateInterval == 'day') { 8388 $ann_interval = $prev_ann->diff($next_ann); 8389 $stub_interval = $startlocal->diff($next_ann); 8390 $ratio = ($stub_interval->days / $ann_interval->days) + ($periods - 1); 8391 } 8392 $remainder = $ratio > 1 ? $ratio - floor($ratio) : $ratio; 8393 //memberships based on number of days 8394 } else { 8395 $remainder = 1; 8396 $ratio = 1; 8397 $extendto = $startlocal->modify('+' . $info['expireAfter'] * $periods . ' days'); 8398 $interval = $startlocal->diff($extendto); 8399 } 8400 $timestamp = $extendto != null ? $extendto->format('U') : null; 8401 8402 return [ 8403 'timestamp' => $timestamp, 8404 'ratio_prorated_first_period' => $remainder, 8405 'ratio' => $ratio, 8406 'interval' => $interval, 8407 'new' => $new]; 8408 } 8409 8410 function get_users_created_group($group, $user = null, $with_expire = false) 8411 { 8412 if (! empty($user)) { 8413 $query = 'SELECT uug.`created`,uug.`expire` FROM `users_usergroups` uug' . 8414 ' LEFT JOIN `users_users` on (`users_users`.`userId`=uug.`userId`)' . 8415 ' WHERE `groupName`=? AND `login`=?'; 8416 8417 $bindvars = [$group, $user]; 8418 } else { 8419 $query = 'SELECT `login`, uug.`created`,uug.`expire` FROM `users_usergroups` uug' . 8420 ' LEFT JOIN `users_users` on (`users_users`.`userId`=uug.`userId`)' . 8421 ' WHERE `groupName`=?'; 8422 8423 $bindvars = [$group]; 8424 } 8425 $result = $this->query($query, $bindvars); 8426 $ret = []; 8427 8428 while ($res = $result->fetchRow()) { 8429 if ($with_expire) { 8430 $ret[$res['login']]['created'] = $res['created']; 8431 if (empty($res['expire'])) { 8432 $re = $this->get_group_info($group); 8433 } 8434 if ($re['expireAfter'] > 0) { 8435 $res['expire'] = $res['created'] + ($re['expireAfter'] * 24 * 60 * 60); 8436 } 8437 $ret[$res['login']]['expire'] = $res['expire']; 8438 } else { 8439 $ret[$res['login']] = $res['created']; 8440 } 8441 } 8442 8443 return $ret; 8444 } 8445 8446 function nb_users_in_group($group = null) 8447 { 8448 if (! empty($group)) { 8449 $query = 'SELECT count(*) FROM `users_usergroups` WHERE `groupName`=?'; 8450 return $this->getOne($query, [$group]); 8451 } else { 8452 $query = 'SELECT count(*) FROM `users_users`'; 8453 return $this->getOne($query, []); 8454 } 8455 } 8456 8457 function find_best_user($usrs, $group = '', $key = 'login') 8458 { 8459 $finalusers = []; 8460 foreach ($usrs as $u) { 8461 $u = trim($u); 8462 if (! $u) { 8463 continue; 8464 } 8465 if ($u == 'admin') { 8466 $finalusers[] = $u; 8467 } elseif ($key == 'userId' && preg_match('/\(([0-9]+)\)$/', $u, $matches)) { 8468 $finalusers[] = $this->get_user_login($matches[1]); 8469 } elseif ($key == 'login' && preg_match('/\((.+)\)$/', $u, $matches)) { 8470 $finalusers[] = $matches[1]; 8471 } else { 8472 $possibleusers = $this->get_users_light(0, -1, 'login_asc', '', $group); 8473 $unames = array_keys($possibleusers, $u); 8474 if (count($unames) == 1 && $unames[0]) { 8475 $finalusers[] = $unames[0]; 8476 } 8477 } 8478 } 8479 8480 return $finalusers; 8481 } 8482 8483 function clean_user($u, $force_check_realnames = false, $login_fallback = true) 8484 { 8485 global $prefs; 8486 $tikilib = TikiLib::lib('tiki'); 8487 if ($prefs['user_show_realnames'] == 'y' || $force_check_realnames) { 8488 // need to trim to prevent mustMatch failure 8489 $realname = trim($tikilib->get_user_preference($u, 'realName', '')); 8490 } 8491 if (! empty($realname)) { 8492 $u = $realname; 8493 } elseif ($prefs['login_is_email_obscure'] == 'y' && $atsign = strpos($u, '@')) { 8494 $u = substr($u, 0, $atsign); 8495 if (! $login_fallback) { 8496 $u = tra('Anonymous'); 8497 } 8498 } 8499 8500 return $u; 8501 } 8502 8503 private function categorize_user_tracker_item($user, $group) 8504 { 8505 $tikilib = TikiLib::lib('tiki'); 8506 $userid = $this->get_user_id($user); 8507 $tracker = $this->get_usertracker($userid); 8508 if ($tracker && $tracker['usersTrackerId']) { 8509 $trklib = TikiLib::lib('trk'); 8510 $categlib = TikiLib::lib('categ'); 8511 $itemid = $trklib->get_item_id($tracker['usersTrackerId'], $tracker['usersFieldId'], $user); 8512 $cat = $categlib->get_object_categories('trackeritem', $itemid); 8513 $categId = $categlib->get_category_id($group); 8514 if (! $categId) { 8515 return false; 8516 } 8517 $cat[] = $categId; 8518 $cat = array_unique($cat); 8519 8520 // using override_perms=true because if user adding himself to group may not have perms yet 8521 $trklib->categorized_item($tracker["usersTrackerId"], $itemid, '', $cat, [], true); 8522 require_once('lib/search/refresh-functions.php'); 8523 refresh_index('trackeritem', $itemid); 8524 } 8525 } 8526 8527 private function uncategorize_user_tracker_item($user, $group) 8528 { 8529 $tikilib = TikiLib::lib('tiki'); 8530 $userid = $this->get_user_id($user); 8531 $tracker = $this->get_usertracker($userid); 8532 8533 if ($tracker && $tracker['usersTrackerId']) { 8534 $trklib = TikiLib::lib('trk'); 8535 $categlib = TikiLib::lib('categ'); 8536 $itemid = $trklib->get_item_id($tracker['usersTrackerId'], $tracker['usersFieldId'], $user); 8537 $cat = $categlib->get_object_categories('trackeritem', $itemid); 8538 $categId = $categlib->get_category_id($group); 8539 if (! $categId) { 8540 return false; 8541 } 8542 $cat = array_diff($cat, [$categId]); 8543 $trklib->categorized_item($tracker["usersTrackerId"], $itemid, '', $cat, [], true); 8544 require_once('lib/search/refresh-functions.php'); 8545 refresh_index('trackeritem', $itemid); 8546 } 8547 } 8548 8549 /** 8550 * Remove the link between a Tiki user account 8551 * and an OpenID account 8552 * 8553 * @param int $userId 8554 * @return TikiDb_Pdo_Result|TikiDb_Adodb_Result 8555 */ 8556 function remove_openid_link($userId) 8557 { 8558 $query = "UPDATE `users_users` SET `openid_url` = NULL WHERE `userId` = ?"; 8559 $bindvars = [$userId]; 8560 return $this->query($query, $bindvars); 8561 } 8562 8563 function get_lost_groups() 8564 { 8565 $query = 'SELECT ugp.`groupName` FROM `users_grouppermissions` ugp' . 8566 ' LEFT JOIN `users_groups` ug ON ( ug.`groupName` = ugp.`groupName` )' . 8567 ' WHERE ug.`groupName` IS NULL'; 8568 8569 $groups = $this->fetchAll($query); 8570 $ret = []; 8571 8572 foreach ($groups as $res) { 8573 if (! in_array($res['groupName'], $ret)) { 8574 $ret[] = $res['groupName']; 8575 } 8576 } 8577 8578 $query = 'SELECT ugp.`groupName` FROM `users_objectpermissions` ugp' . 8579 ' LEFT JOIN `users_groups` ug ON ( ug.`groupName` = ugp.`groupName` )' . 8580 ' WHERE ug.`groupName` IS NULL'; 8581 8582 $groups = $this->fetchAll($query); 8583 8584 foreach ($groups as $res) { 8585 if (! in_array($res['groupName'], $ret)) { 8586 $ret[] = $res['groupName']; 8587 } 8588 } 8589 8590 return $ret; 8591 } 8592 8593 function remove_lost_groups() 8594 { 8595 $groups = $this->get_lost_groups(); 8596 if (empty($groups)) { 8597 return; 8598 } 8599 $query = 'delete FROM `users_grouppermissions` where `groupName` in (' . implode(',', array_fill(0, count($groups), '?')) . ')'; 8600 $this->query($query, $groups); 8601 $query = 'delete FROM `users_objectpermissions` where `groupName` in (' . implode(',', array_fill(0, count($groups), '?')) . ')'; 8602 8603 $this->query($query, $groups); 8604 } 8605 8606 function get_user_groups_date($userId) 8607 { 8608 $query = 'select * from `users_usergroups` where `userId`=?'; 8609 $result = $this->query($query, [$userId]); 8610 $ret = []; 8611 while ($res = $result->fetchRow()) { 8612 $g = $res['groupName']; 8613 $ret[$g]['created'] = $res['created']; 8614 $ret[$g]['expire'] = $res['expire']; 8615 } 8616 return $ret; 8617 } 8618 8619 /** 8620 * This is a function to automatically login a user programatically 8621 * @param string $uname The user account name to log the user in as 8622 * @return bool true means that successfully logged in or already logged in. false means no such user. 8623 */ 8624 function autologin_user($uname) 8625 { 8626 global $user; 8627 if ($user) { 8628 // already logged in 8629 return true; 8630 } 8631 if (! $this->user_exists($uname)) { 8632 // no such user 8633 return false; 8634 } 8635 // Conduct login 8636 global $user_cookie_site; 8637 $_SESSION[$user_cookie_site] = $uname; 8638 $this->update_expired_groups(); 8639 $this->update_lastlogin($uname); 8640 return true; 8641 } 8642 8643 /** 8644 * This is a function to invite users to temporarily access the site via a token 8645 * @param array $emails Emails to send the invite to 8646 * @param array $groups Groups that the temporary user should have (Registered is not included unless explicitly added) 8647 * @param int $timeout How long the invitation is valid for, in seconds. 8648 * @param string $prefix Username of the created users will be the token ID prefixed with this 8649 * @param string $path Users will have to autologin using this path on the site using the token 8650 * @throws Exception 8651 */ 8652 function invite_tempuser($emails, $groups, $timeout, $prefix = 'guest', $path = 'index.php') 8653 { 8654 global $user, $prefs; 8655 $smarty = TikiLib::lib('smarty'); 8656 include_once('lib/webmail/tikimaillib.php'); 8657 $referer = Services_Utilities::noJsPath(); 8658 8659 $mail = new TikiMail(); 8660 foreach ($emails as $email) { 8661 if (! validate_email($email)) { 8662 $mes = empty($email) ? tr('Email address is required.') : tr('Invalid email address "%0"', $email); 8663 Feedback::error($mes); 8664 Services_Utilities::sendFeedback($referer); 8665 } 8666 } 8667 $foo = parse_url($_SERVER['REQUEST_URI']); 8668 $machine = $this->httpPrefix(true) . dirname($foo['path']); 8669 $machine = preg_replace('!/$!', '', $machine); // just in case 8670 $smarty->assign_by_ref('mail_machine', $machine); 8671 $smarty->assign('mail_sender', $user); 8672 $smarty->assign('expiry', $user); 8673 $mail->setBcc($this->get_user_email($user)); 8674 $smarty->assign('token_expiry', $this->get_long_datetime($this->now + $timeout)); 8675 require_once 'lib/auth/tokens.php'; 8676 8677 foreach ($emails as $email) { 8678 $tokenlib = AuthTokens::build($prefs); 8679 $token_url = $tokenlib->includeToken($machine . "/$path", $groups, $email, $timeout, -1, true, $prefix); 8680 include_once('tiki-sefurl.php'); 8681 $token_url = filter_out_sefurl($token_url); 8682 $smarty->assign('token_url', $token_url); 8683 $mail->setUser($user); 8684 $mail->setSubject($smarty->fetch('mail/invite_tempuser_subject.tpl')); 8685 $mail->setHtml($smarty->fetch('mail/invite_tempuser.tpl')); 8686 8687 if (! $mail->send($email)) { 8688 $errormsg = tr('Unable to send mail to invite "%0"', $email); 8689 if (Perms::get()->admin) { 8690 $mailerrors = print_r($mail->errors, true); 8691 $errormsg .= $mailerrors; 8692 } 8693 Feedback::error($errormsg); 8694 Services_Utilities::sendFeedback($referer); 8695 } 8696 $smarty->assign_by_ref('user', $user); 8697 } 8698 } 8699 8700 /** 8701 * @param string $uname The username of the temporary user to remove (or disable depending on the pref) 8702 * 8703 */ 8704 function remove_temporary_user($uname) 8705 { 8706 global $prefs; 8707 if ($prefs['auth_token_preserve_tempusers'] == 'y') { 8708 $this->remove_user_from_all_groups($uname); 8709 } else { 8710 $this->remove_user($uname); 8711 } 8712 } 8713} 8714 8715 8716 8717/* For the emacs weenies in the crowd. 8718Local Variables: 8719 c-basic-offset: 4 8720End: 8721*/ 8722