classes/Gems/Project/ProjectSettings.php
<?php
/**
*
* @package Gems
* @subpackage Project
* @author Matijs de Jong <mjong@magnafacta.nl>
* @copyright Copyright (c) 2011 Erasmus MC
* @license New BSD License
*/
/**
* Class that extends Array object to add Gems specific functions.
*
* @package Gems
* @subpackage Project
* @copyright Copyright (c) 2011 Erasmus MC
* @license New BSD License
* @since Class available since version 1.5
*/
class Gems_Project_ProjectSettings extends \ArrayObject
{
/**
* The db adapter for the responses
*
* @var \Zend_Db_Adapter_Abstract
*/
protected $_responsesDb;
/**
* The default session time out for this project in seconds.
*
* Can be overruled in sesssion.idleTimeout
*
* @var int
*/
protected $defaultSessionTimeout = 1800;
/**
* The minimum length for the password of a super admin
* on a production server.
*
* @var int
*/
protected $minimumSuperPasswordLength = 10;
/**
* Array of required keys. Give a string value for root keys
* or name => array() values for required subs keys.
*
* Deeper levels are not supported at the moment.
*
* @see checkRequiredValues()
*
* @var array
*/
protected $requiredKeys = array(
'css' => array('gems'),
'locale' => array('default'),
'salt',
);
/**
* Creates the object and checks for required values.
*
* @param mixed $array
*/
public function __construct($array)
{
// Convert to array when needed
if ($array instanceof \Zend_Config) {
$array = $array->toArray();
} elseif ($array instanceof \ArrayObject) {
$array = $array->getArrayCopy();
} elseif (! is_array($array)) {
$array = (array) $array;
}
// Now load default values for (new) keys and merge them with the ones provided by project.ini
$projectValues = $array + $this->_getDefaultValues();
parent::__construct($projectValues, \ArrayObject::ARRAY_AS_PROPS);
if (! ($this->offsetExists('name') && $this->offsetGet('name'))) {
$this->offsetSet('name', GEMS_PROJECT_NAME);
}
$this->offsetSet('multiLocale', $this->offsetExists('locales') && (count($this->offsetGet('locales')) > 1));
}
/**
* Set the default values for all keys.
*
* By doing this, we make sure the settings show up in the project information
* with the defaults even if the settings was not present in the project.ini
*/
public function _getDefaultValues()
{
return array(
'>>> defaults <<<' => '>>> Below are default settings, since they were not found in your project.ini <<<',
// What to do when user is going to or has answered a survey
'askNextDelay' => -1, // No auto advance
'askDelay' => -1, // No auto advance
// How to react to false token attempts
'askThrottle' => array(
'period' => 15 * 60, // Detection window: 15 minutes
'threshold' => 15 * 20, // Threshold: 20 requests per minute
'delay' => 10 // Delay: 10 seconds
),
'cache' => 'apc', // Use apc cache as default
'logLevel' => $this->getLogLevelDefault(), // Depends on application environment
'organization' => array(
'default' => -1 // No default organization
),
'idleTimeout' => $this->defaultSessionTimeout // Sesison timeout default 1800
);
}
/**
* Add recursively the rules active for this specific set of codes.
*
* @param array $current The current (part)sub) array of $this->passwords to check
* @param array $codes An array of code names that identify rules that should be used only for those codes.
* @param array $rules The array that stores the activated rules.
* @return void
*/
protected function _getPasswordRules(array $current, array $codes, array &$rules)
{
foreach ($current as $key => $value) {
if (is_array($value)) {
// Only act when this is in the set of key values
if (isset($codes[strtolower($key)])) {
$this->_getPasswordRules($value, $codes, $rules);
}
} else {
$rules[$key] = $value;
}
}
}
/**
* This function checks for the required project settings.
*
* Overrule this function or the $requiredParameters to add extra required settings.
*
* @see $requiredParameters
*
* @return void
*/
public function checkRequiredValues()
{
$missing = array();
foreach ($this->requiredKeys as $key => $names) {
if (is_array($names)) {
if (! ($this->offsetExists($key) && $this->offsetGet($key))) {
$subarray = array();
} else {
$subarray = $this->offsetGet($key);
}
foreach ($names as $name) {
if (! isset($subarray[$name])) {
$missing[] = $key . '.' . $name;
}
}
} else {
if (! ($this->offsetExists($names) && $this->offsetGet($names))) {
$missing[] = $names;
}
}
}
// Chek for https
if (!\MUtil_Https::on()) {
if ($this->isHttpsRequired()) {
\MUtil_Https::enforce();
}
}
if ($missing) {
if (count($missing) == 1) {
$error = sprintf("Missing required project setting: '%s'.", reset($missing));
} else {
$error = sprintf("Missing required project settings: '%s'.", implode("', '", $missing));
}
throw new \Gems_Exception_Coding($error);
}
$superPassword = $this->getSuperAdminPassword();
if (('production' === APPLICATION_ENV || 'acceptance' === APPLICATION_ENV) &&
$this->getSuperAdminName() && $superPassword) {
if (strlen($superPassword) < $this->minimumSuperPasswordLength) {
$error = sprintf("Project setting 'admin.pwd' is shorter than %d characters. That is not allowed.", $this->minimumSuperPasswordLength);
throw new \Gems_Exception_Coding($error);
}
}
}
/**
* Checks the super admin password, if it exists
*
* @param string $password
* @return boolean True if the password is correct.
*/
public function checkSuperAdminPassword($password)
{
return $password && ($password == $this->getSuperAdminPassword());
}
/**
* Decrypt a string encrypted with encrypt()
*
* @param string $input String to decrypt
* @param string $key Optional key. If null project salt will be used
* @return string decrypted string
*/
public function decrypt($input, $key=null)
{
if (! $input) {
return $input;
}
$methods = $this->getEncryptionMethods();
if (':' == $input[0]) {
list($empty, $mkey, $base64) = explode(':', $input, 3);
if (! isset($methods[$mkey])) {
$error = sprintf("Encryption method '%s' not defined in project.ini.", $mkey);
throw new \Gems_Exception_Coding($error);
}
$method = $methods[$mkey];
} else {
$mkey = 'mcrypt';
$base64 = $input;
$method = $mkey;
}
if ($key === null) {
$key = $this->getEncryptionSaltKey();
}
$decoded = base64_decode($base64);
if ('mcrypt' == $method) {
$output = $this->decryptMcrypt($decoded, $key);
} elseif ('null' == $method) {
$output = $base64;
} else {
$output = $this->decryptOpenSsl($decoded, $method, $key);
}
if (false === $output) {
return $input;
} else {
return $output;
}
}
/**
* Decrypt a string encrypted with encrypt()
*
* @param string $input String to decrypt
* @param string $key Key to use for decryption
* @return string decrypted string of false
*/
protected function decryptMcrypt($input, $key)
{
$ivlen = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = substr($input, 0, $ivlen);
// Remove trailing zero bytes!
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, substr($input, $ivlen), MCRYPT_MODE_CBC, $iv), "\0");
}
/**
* Reversibly encrypt a string
*
* @param string $input String to decrypt
* @param string $method The cipher method, one of openssl_get_cipher_methods().
* @param string $key Key to use for decryption
* @return string decrypted string of false
*/
protected function decryptOpenSsl($input, $method, $key)
{
$ivlen = openssl_cipher_iv_length($method);
$iv = substr($input, 0, $ivlen);
return openssl_decrypt(substr($input, $ivlen), $method, $key, 0, $iv);
}
/**
* Reversibly encrypt a string
*
* @param string $input String to decrypt
* @param string $key Optional key. If null project salt will be used
* @return string encrypted string
*/
public function encrypt($input, $key=null)
{
if (! $input) {
return $input;
}
$methods = $this->getEncryptionMethods();
$method = reset($methods);
$mkey = key($methods);
if ($key === null) {
$key = $this->getEncryptionSaltKey();
}
if ('mcrypt' == $method) {
$result = $this->encryptMcrypt($input, $key);
} elseif ('null' == $method) {
$result = $input;
} else {
$result = $this->encryptOpenSsl($input, $method, $key);
}
return ":$mkey:" . base64_encode($result);
}
/**
* Reversibly encrypt a string
*
* @param string $input String to encrypt
* @param string $key Key used for encryption
* @return string encrypted string
*/
protected function encryptMcrypt($input, $key)
{
$ivlen = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivlen, MCRYPT_RAND);
return $iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $input, MCRYPT_MODE_CBC, $iv);
}
/**
* Reversibly encrypt a string
*
* @param string $input String to encrypt
* @param string $method The cipher method, one of openssl_get_cipher_methods().
* @param string $key Key used for encryption
* @return string encrypted string
*/
protected function encryptOpenSsl($input, $method, $key)
{
$ivlen = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivlen);
return $iv . openssl_encrypt($input, $method, $key, 0, $iv);
}
/**
* Array of hosts allowed to post data to this project
*
* @return array
* @deprecated since version 1.9.1, is stored in gems__sites
*/
public function getAllowedHosts()
{
if (isset($this['allowedSourceHosts'])) {
return (array) $this['allowedSourceHosts'];
}
return array();
}
/**
* Calculate the delay between surveys being asked for this request. Zero means forward
* at once, a negative value means wait forever.
*
* @param \Zend_Controller_Request_Abstract $request
* @param boolean $wasAnswered When true use the ask delay
* @return int -1 means waiting indefinitely
*/
public function getAskDelay(\Zend_Controller_Request_Abstract $request, $wasAnswered)
{
if ($request->getParam('delay_cancelled', false)) {
return -1;
}
$delay = $request->getParam('delay', null);
if (null != $delay) {
return $delay;
}
if ($wasAnswered) {
if ($this->offsetExists('askNextDelay')) {
return $this->offsetGet('askNextDelay');
}
} else {
if ($this->offsetExists('askDelay')) {
return $this->offsetGet('askDelay');
}
}
return -1;
}
/**
* Returns an array with throttling settings for the ask
* controller
*
* @return array
*/
public function getAskThrottleSettings()
{
// Check for the 'askThrottle' config section
if (!empty($this->askThrottle)) {
return $this->askThrottle;
} else {
// Set some sensible defaults
// Detection window: 15 minutes
// Threshold: 20 requests per minute
// Delay: 10 seconds
$throttleSettings = array(
'period' => 15 * 60,
'threshold' => 15 * 20,
'delay' => 10
);
}
}
/**
* Returns the documentation url
*
* @return string
*/
public function getBugsUrl()
{
if (isset($this['contact'], $this['contact']['bugsUrl'])) {
return $this['contact']['bugsUrl'];
}
return 'https://github.com/GemsTracker/gemstracker-library/issues';
}
/**
* Get the specified cache method from project settings
*
* @return string
*/
public function getCache()
{
if ($this->offsetExists('cache')) {
$cache = $this->offsetGet('cache');
} else {
$cache = 'apc';
}
return $cache;
}
/**
* Get the specified role for the console user from the project setttings.
*
* If the role is not defined (or does not exist) running GemsTracker in
* console mode requires the users login name, organization and password to
* be specified on the command line.
*
* @return string
*/
public function getConsoleRole()
{
if ($this->offsetExists('console')) {
$cons = $this->offsetGet('console');
if (isset($cons['role'])) {
return $cons['role'];
}
}
return false;
}
/**
* The site url during command line actions
*
* @return string
* @deprecated since version 1.9.1, is stored in gems__sites
*/
public function getConsoleUrl()
{
if ($this->offsetExists('console') && isset($this->console['url'])) {
return trim($this->console['url']);
}
return 'localhost';
}
/**
* The logfile for cron jobs
*
* @return string
*/
public function getCronLogfile()
{
if (! ($this->offsetExists('cron') && isset($this->cron['logfile']))) {
return null;
}
$file = trim($this->cron['logfile']);
if (\MUtil_File::isRootPath($file)) {
return $file;
}
return GEMS_ROOT_DIR . '/var/logs/' . $file;
}
/**
* Returns an (optional) default organization from the project settings
*
* @return int Organization number or -1 when not set
*/
public function getDefaultOrganization()
{
if ($this->offsetExists('organization')) {
$orgs = $this->offsetGet('organization');
if (isset($orgs['default'])) {
return $orgs['default'];
}
}
return -1;
}
/**
* Returns an (optional) default track id from the project settings
*
* Usually used in by single track project
*
* @return int Organization number or -1 when not set
*/
public function getDefaultTrackId()
{
return $this->offsetExists('trackId') ? $this->offsetGet('trackId') : null;
}
/**
* Returns the public description of this project.
*
* @return string
*/
public function getDescription()
{
if ($this->offsetExists('description')) {
return $this->offsetGet('description');
} else {
return $this->offsetGet('name');
}
}
/**
* Returns the documentation url
*
* @return string
*/
public function getDocumentationUrl()
{
if (isset($this['contact'], $this['contact']['docsUrl'])) {
return $this['contact']['docsUrl'];
}
}
/**
* The the email BCC address - if any
*
* @return string
*/
public function getEmailBcc()
{
if ($this->offsetExists('email') && isset($this->email['bcc'])) {
return trim($this->email['bcc']);
}
}
/**
* Should all mail be bounced to the sender?
*
* @return boolean
*/
public function getEmailBounce()
{
if ($this->offsetExists('email') && isset($this->email['bounce'])) {
return (boolean) $this->email['bounce'];
}
return false;
}
/**
* The default Email Template for Create Account
*
* @return string Template Code
*/
public function getEmailCreateAccount()
{
if ($this->offsetExists('email') && isset($this->email['createAccountTemplate'])) {
return (string) $this->email['createAccountTemplate'];
}
return false;
}
/**
* Check if multiple language mail templates is supported
* @return boolean
*/
public function getEmailMultiLanguage()
{
if ($this->offsetExists('email') && isset($this->email['multiLanguage'])) {
return (boolean) $this->email['multiLanguage'];
} else {
return true;
}
}
/**
* The default Email template for Reset password
*
* @return string Template Code
*/
public function getEmailResetPassword()
{
if ($this->offsetExists('email') && isset($this->email['resetPasswordTemplate'])) {
return (string) $this->email['resetPasswordTemplate'];
}
return false;
}
/**
*
* @return array (stored) key => openssl_get_cipher_method used
*/
protected function getEncryptionMethods()
{
if (isset($this['security'], $this['security']['methods'])) {
// reverse so first item is used as default
$output = array_reverse($this['security']['methods']);
} else {
$output = [];
}
if (! isset($output['mcrypt'])) {
$output['mcrypt'] = 'mcrypt';
}
if (! isset($output['null'])) {
$output['null'] = 'null';
}
return $output;
}
/**
* Get stored encryption keys by name
*
* @param $keyName string name of the stored key
* @return string|null Stored key, or null if not found
*/
public function getEncryptionKey($keyName)
{
if (isset($this['security'], $this['security']['keys'], $this['security']['keys'][$keyName])) {
return $this['security']['keys'][$keyName];
}
return null;
}
/**
*
* @return string The salt key
*/
protected function getEncryptionSaltKey()
{
return md5($this->offsetExists('salt') ? $this->offsetGet('salt') : 'vadf2646fakjndkjn24656452vqk');
}
/**
* Get the directory to use as the root for automatic import
*
* @return string
*/
public function getFileImportRoot()
{
if ($this->offsetExists('fileImportRoot')) {
return $this->offsetGet('fileImportRoot');
}
return GEMS_ROOT_DIR . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'auto_import';
}
/**
* Returns the forum url
*
* @return string
*/
public function getForumUrl()
{
if (isset($this['contact'], $this['contact']['forumUrl'])) {
return $this['contact']['forumUrl'];
}
}
/**
* Returns the from address
*
* @return string E-Mail address
*/
public function getFrom()
{
return $this->getSiteEmail();
}
/**
* Returns the from address
*
* @return string E-Mail address
*/
public function getImageDir()
{
if (isset($this['imagedir']) && $this['imagedir']) {
return $this['imagedir'];
}
return 'gems/images';
}
/**
* Returns the initial password specified for users - if any.
*
* @return String
*/
public function getInitialPassword()
{
if (isset($this['password'], $this['password']['initialPassword'])) {
return $this['password']['initialPassword'];
} else {
return null;
}
}
/**
* Get the local jQuery directory (without base url)
*
* Instead of e.g. google Content Delivery Network.
*
* @return boolean
*/
public function getJQueryLocal()
{
if (isset($this['jquery'], $this['jquery']['local'])) {
return $this['jquery']['local'];
} else {
return null;
}
}
/**
* Get the LDAP query settings
*
* @return array Settings
*/
public function getLdapSettings()
{
if ($this->offsetExists('ldap')) {
return $this->ldap;
}
}
/**
* Get the default locale
* @return string locale
*/
public function getLocaleDefault()
{
if ($this->offsetExists('locale') && isset($this->locale['default'])) {
return (string) $this->locale['default'];
}
return null;
}
/**
* Get the logLevel to use with the \Gems_Log
*
* Default settings is for development and testing environment to use \Zend_Log::DEBUG and
* for all other environments to use the \Zend_Log::ERR level. This can be overruled by
* specifying a logLevel in the project.ini
*
* Using a level higher than \Zend_Log::ERR will output full error messages, traces and request
* info to the logfile. Please be aware that this might introduce a security risk as passwords
* might be written to the logfile in plain text.
*
* @return int The loglevel to use
*/
public function getLogLevel()
{
if (isset($this['logLevel'])) {
$logLevel = $this['logLevel'];
} else {
$logLevel = $this->getLogLevelDefault();
}
return (int) $logLevel;
}
/**
* Return the default logLevel to use with the \Gems_Log
*
* Default settings is for development and testing environment to use \Zend_Log::DEBUG and
* for all other environments to use the \Zend_Log::ERR level. This can be overruled by
* specifying a logLevel in the project.ini
*
* @return int The loglevel to use
*/
public function getLogLevelDefault() {
if ('development' == APPLICATION_ENV || 'testing' == APPLICATION_ENV) {
$logLevel = \Zend_Log::DEBUG;
} else {
$logLevel = \Zend_Log::ERR;
}
return $logLevel;
}
/**
* Return a long description, in the correct language if available
*
* @param string $language Iso code languahe
* @return string
*/
public function getLongDescription($language)
{
if (isset($this['longDescr' . ucfirst($language)])) {
return $this['longDescr' . ucfirst($language)];
}
if (isset($this['longDescr'])) {
return $this['longDescr'];
}
}
/**
* Array of field name => values for sending E-Mail
*
* @return array
*/
public function getMailFields()
{
$result['project'] = $this->getName();
// $result['project_bcc'] = $this->getEmailBcc();
$result['project_description'] = $this->getDescription();
$result['project_from'] = $this->getFrom();
return $result;
}
/**
* Returns the manual url
*
* @return string
*/
public function getManualUrl()
{
if (isset($this['contact'], $this['contact']['manualUrl'])) {
return $this['contact']['manualUrl'];
}
}
/**
* Get the form address for monitor messages
*
* @param string $name Optional section name
* @return string
*/
public function getMonitorFrom($name = null)
{
if ($name) {
if (isset($this['monitor'], $this['monitor'][$name], $this['monitor'][$name]['from']) &&
trim($this['monitor'][$name]['from'])) {
return $this['monitor'][$name]['from'];
}
}
if (isset($this['monitor'], $this['monitor']['default'], $this['monitor']['default']['from']) &&
trim($this['monitor']['default']['from'])) {
return $this['monitor']['default']['from'];
}
$email = $this->getSiteEmail();
if ($email) {
return $email;
}
return 'noreply@gemstracker.org';
}
/**
* Get the period for monitor messages, optionally for a name
*
* @param string $name Optional section name
* @return string
*/
public function getMonitorPeriod($name = null)
{
if ($name) {
if (isset($this['monitor'], $this['monitor'][$name], $this['monitor'][$name]['period']) &&
strlen(trim($this['monitor'][$name]['period']))) {
return $this['monitor'][$name]['period'];
}
}
if (isset($this['monitor'], $this['monitor']['default'], $this['monitor']['default']['period']) &&
strlen(trim($this['monitor']['default']['period']))) {
return $this['monitor']['default']['period'];
}
return '25h';
}
/**
* Get the to addresses for monitor messages, optionally for a name
*
* @param string $name Optional section name
* @return string
*/
public function getMonitorTo($name = null)
{
if ($name) {
if (isset($this['monitor'], $this['monitor'][$name], $this['monitor'][$name]['to']) &&
trim($this['monitor'][$name]['to'])) {
return $this['monitor'][$name]['to'];
}
}
if (isset($this['monitor'], $this['monitor']['default'], $this['monitor']['default']['to']) &&
trim($this['monitor']['default']['to'])) {
return $this['monitor']['default']['to'];
}
return null;
}
/**
* Returns the public name of this project.
*
* @return string
*/
public function getName()
{
return $this->offsetGet('name');
}
/**
* Get the rules active for this specific set of codes.
*
* @param array $codes An array of code names that identify rules that should be used only for those codes.
* @return array
*/
public function getPasswordRules(array $codes)
{
// Process the codes array to a format better used for filtering
$codes = array_change_key_case(array_flip(array_filter($codes)));
// \MUtil_Echo::track($codes);
$rules = array();
if ($this->offsetExists('passwords') && is_array($this->passwords)) {
$this->_getPasswordRules($this->passwords, $codes, $rules);
}
return $rules;
}
/**
* Get additional meta headers
*
* @return array Of http-equiv => content values for meta tags
*/
public function getMetaHeaders()
{
if ($this->offsetExists('meta') && is_array($this->meta)) {
$meta = $this->meta;
} else {
$meta = [];
}
if (!array_key_exists('Content-Type', $meta)) {
$meta['Content-Type'] = 'text/html;charset=UTF-8';
}
// Remove null/empty values, this allow you to remove the Content-Type by making it empty.
return array_filter($meta);
}
/**
* Get a redis DSN
*
* @return string|false
*/
public function getRedisDsn()
{
if ($this->offsetExists('redis') && isset($this->redis['dsn'])) {
return $this->redis['dsn'];
}
return false;
}
/**
* The response database with a table with one row for each token answer.
*
* @return \Zend_Db_Adapter_Abstract
*/
public function getResponseDatabase()
{
if ((!$this->_responsesDb) && $this->hasResponseDatabase()) {
$adapter = $this['responses']['adapter'];
if (isset($this['responses'], $this['responses']['params'])) {
$options = $this['responses']['params'];
if (! isset(
$options['charset'],
$options['host'],
$options['dbname'],
$options['username'],
$options['password']
)) {
$db = \Zend_Registry::get('db');
if ($db instanceof \Zend_Db_Adapter_Abstract) {
$options = $options + $db->getConfig();
}
}
$this->_responsesDb = \Zend_Db::factory($adapter, $options);
} else {
$db = \Zend_Registry::get('db');
if ($db instanceof \Zend_Db_Adapter_Abstract) {
$this->_responsesDb = $db;
}
}
}
return $this->_responsesDb;
}
/**
* Get additional response headers
*
* @return array Of name => value for HTTP response headers
*/
public function getResponseHeaders()
{
if ($this->offsetExists('headers') && is_array($this->headers)) {
$headers = $this->headers;
} else {
$headers = [];
}
if (!array_key_exists('X-UA-Compatible', $headers)) {
$headers['X-UA-Compatible'] = 'IE=edge,chrome=1';
}
// Remove null/empty values, this allow you to remove the X-UA-Compatible by making it empty.
return array_filter($headers);
}
/**
* Timeout for sessions in seconds.
*
* @return int
*/
public function getSessionTimeOut()
{
if ($this->offsetExists('session') && isset($this->session['idleTimeout'])) {
return $this->session['idleTimeout'];
} else {
return $this->defaultSessionTimeout;
}
}
/**
* The site email address - if any
*
* @return string
*/
public function getSiteEmail()
{
if ($this->offsetExists('email') && isset($this->email['site'])) {
return trim($this->email['site']);
}
}
/**
* Should staff mail be bounced to the sender?
*
* @return boolean
*/
public function getStaffBounce()
{
if ($this->offsetExists('email') && isset($this->email['staffBounce'])) {
return (boolean) $this->email['staffBounce'];
}
return $this->getEmailBounce();
}
/**
* Returns the super admin name, if any
*
* @return string
*/
public function getSuperAdminName()
{
if ($this->offsetExists('admin') && isset($this->admin['user'])) {
return trim($this->admin['user']);
}
}
/**
* Returns the super admin password, if it exists
*
* @return string
*/
protected function getSuperAdminPassword()
{
if ($this->offsetExists('admin') && isset($this->admin['pwd'])) {
return trim($this->admin['pwd']);
}
}
/**
* Get the super admin two factor authentication ip exclude range
*
* @return string
*/
public function getSuperAdminTwoFactorIpExclude()
{
if ($this->offsetExists('admin') && isset($this->admin['2fa'], $this->admin['2fa']['exclude'])) {
return trim($this->admin['2fa']['exclude']);
}
}
/**
* Get the super admin two factor authentication key
*
* @return string
*/
public function getSuperAdminTwoFactorKey()
{
if ($this->offsetExists('admin') && isset($this->admin['2fa'], $this->admin['2fa']['key'])) {
return trim($this->admin['2fa']['key']);
}
}
/**
* Returns the super admin ip range, if it exists
*
* @return string
*/
public function getSuperAdminIPRanges()
{
if ($this->offsetExists('admin') && isset($this->admin['ipRanges'])) {
return $this->admin['ipRanges'];
}
}
/**
* Returns the support url
*
* @return string
*/
public function getSupportUrl()
{
if (isset($this['contact'], $this['contact']['supportUrl'])) {
return $this['contact']['supportUrl'];
}
}
/**
* Return an array with TwoFactor Methods, corresponding to the classnames in User\TwoFactor
*
* @return string[]
*/
public function getTwoFactorMethods()
{
if (isset($this['twoFactor'], $this['twoFactor']['methods'])) {
$methods = [];
foreach($this['twoFactor']['methods'] as $authenticator=>$authSettings) {
// filter specifically disabled methods
if ($authSettings != 0) {
$methods[] = $authenticator;
}
}
return $methods;
}
// Return GoogleAuthenticator as default when nothing is set
return ['GoogleAuthenticator'];
}
/**
* @return array
*/
public function getTwoFactorMethodSettings()
{
if (isset($this['twoFactor'], $this['twoFactor']['methods'])) {
return $this['twoFactor']['methods'];
}
return [];
}
/**
* Returns a salted hash optionally using the specified hash algorithm
*
* @param string $value The value to hash
* @param string $algoritm Optional, hash() algorithm; uses md5() otherwise
* @return string The salted hexadecimal hash, length depending on the algorithm (32 for md5, 128 for sha512.
*/
public function getValueHash($value, $algorithm = null)
{
$salt = $this->offsetExists('salt') ? $this->offsetGet('salt') : '';
if (false === strpos($salt, '%s')) {
$salted = $salt . $value;
} else {
$salted = sprintf($salt, $value);
}
// \MUtil_Echo::track($value, md5($salted));
if (null == $algorithm) {
return md5($salted, false);
}
return hash($algorithm, $value, false);
}
/**
* True at least one support url exists.
*
* @return boolean
* @deprecated Since 1.8.2 No longer in use
*/
public function hasAnySupportUrl()
{
return isset($this['contact']) && (
isset($this['contact']['docsUrl']) ||
isset($this['contact']['forumUrl']) ||
isset($this['contact']['manualUrl']) ||
isset($this['contact']['supportUrl'])
);
}
/**
* True the bugs url exists.
*
* @return boolean
* @deprecated Since 1.8.2 No longer in use
*/
public function hasBugsUrl()
{
return isset($this['contact'], $this['contact']['bugsUrl']) ? $this['contact']['bugsUrl'] : true;
}
/**
* True if an initial password was specified for users.
*
* @return boolean
*/
public function hasInitialPassword()
{
return isset($this['password'], $this['password']['initialPassword']);
}
/**
* @return bool True if the program is using a nonce
*/
public function hasNonce()
{
return isset($this->headers['Content-Security-Policy']) && strpos($this->headers['Content-Security-Policy'], '$scriptNonce') !== false;
}
/**
* True when a response database with a table with one row for each token answer should exist.
*
* @return boolean
*/
public function hasResponseDatabase()
{
return (boolean) isset($this['responses'], $this['responses']['adapter']) && $this['responses']['adapter'];
}
/**
* Is running GemsTracker from the console allowed
*
* If allowed you can call index.php from the command line.
* Use -h as a parameter to get more info, e.g:
* <code>
* php.exe -f index.php -- -f
* </code>
* The -- is needed because otherwise the command is interpreted
* as php.exe -h.
*
* @return string
*/
public function isConsoleAllowed()
{
if ($this->offsetExists('console')) {
$cons = $this->offsetGet('console');
if (isset($cons['allow'])) {
return (boolean) $cons['allow'];
}
}
return false;
}
/**
* Is the use of https required for this site?
*
* @return boolean
*/
public function isHttpsRequired()
{
return ! ($this->offsetExists('http') && $this->offsetGet('http'));
}
/**
* Does this project use a local jQuery
*
* Instead of e.g. google Content Delivery Network.
*
* @return boolean
*/
public function isJQueryLocal()
{
return isset($this['jquery'], $this['jquery']['local']);
}
/**
* Does this project use a local Bootstrap
*
* Instead of e.g. google Content Delivery Network.
*
* @return boolean
*/
public function isBootstrapLocal()
{
return isset($this['bootstrap'], $this['bootstrap']['local']);
}
/**
* Is login shared between organizations (which therefore require
* a unique staff login id for each user, instead of for each
* user within an organization).
*
* @return boolean
*/
public function isLoginShared()
{
return isset($this['organization'], $this['organization']['sharedLogin']) &&
$this['organization']['sharedLogin'];
}
/**
* Is this project use a multi locale project
*
* @return boolean
*/
public function isMultiLocale()
{
return (boolean) (isset($this['multiLocale']) && $this['multiLocale']);
}
/**
* Is a valid until date required for each round in each track
*
* @return boolean
*/
public function isValidUntilRequired()
{
return isset($this['track'], $this['track']['requireValidUntil']) && $this['track']['requireValidUntil'];
}
/**
* @return bool True when there are multiple locales and translate.databasefields is set to 1
*/
public function translateDatabaseFields()
{
return isset($this['multiLocale'], $this['translate'], $this['translate']['databasefields']) &&
$this['multiLocale'] &&
(1 == $this['translate']['databasefields']);
}
/**
* Does this project use Csrf checks
*
* @return boolean
*/
public function useCsrfCheck()
{
if (isset($this['security'], $this['security']['disableCsrf']) && (1 == $this['security']['disableCsrf'])) {
return false;
}
return true;
}
}