diff --git a/.gitignore b/.gitignore index 01b701cf8..755814004 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ user/plugins/* !user/plugins/.* user/themes/* !user/themes/.* +user/localhost/config/security.yaml # OS Generated .DS_Store* diff --git a/composer.lock b/composer.lock index 25c0429a7..d19e9a3f8 100644 --- a/composer.lock +++ b/composer.lock @@ -1,11 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], "hash": "b1323e540382de7390663756b3a87de7", - "content-hash": "158cd4e3e1a40d5d1db9e3f29c24d83a", "packages": [ { "name": "doctrine/cache", @@ -217,12 +216,12 @@ "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "50a288b51058fa94cf5b37cfa4277535983cc9d5" + "reference": "9a393ceb80f7497b6513feb574638e87048fed55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/50a288b51058fa94cf5b37cfa4277535983cc9d5", - "reference": "50a288b51058fa94cf5b37cfa4277535983cc9d5", + "url": "https://api.github.com/repos/filp/whoops/zipball/9a393ceb80f7497b6513feb574638e87048fed55", + "reference": "9a393ceb80f7497b6513feb574638e87048fed55", "shasum": "" }, "require": { @@ -267,7 +266,7 @@ "whoops", "zf2" ], - "time": "2015-11-14 20:08:27" + "time": "2015-09-27 09:47:06" }, { "name": "gregwar/cache", diff --git a/system/src/Grav/Common/Data/Blueprint.php b/system/src/Grav/Common/Data/Blueprint.php index 6f0c71e50..8598d8436 100644 --- a/system/src/Grav/Common/Data/Blueprint.php +++ b/system/src/Grav/Common/Data/Blueprint.php @@ -314,91 +314,105 @@ class Blueprint implements \ArrayAccess, ExportInterface } /** - * Gets all field definitions from the blueprints. - * - * @param array $fields - * @param array $params - * @param string $prefix - * @param array $current - * @internal - */ - protected function parseFormFields(array &$fields, $params, $prefix, array &$current) - { - // Go though all the fields in current level. - foreach ($fields as $key => &$field) { - $current[$key] = &$field; - // Set name from the array key. - $field['name'] = $prefix . $key; - $field += $params; + * Gets all field definitions from the blueprints. + * + * @param array $fields + * @param array $params + * @param string $prefix + * @param array $current + * @internal + */ + protected function parseFormFields(array &$fields, $params, $prefix, array &$current) + { + // Go though all the fields in current level. + foreach ($fields as $key => &$field) { + $current[$key] = &$field; + // Set name from the array key. + $field['name'] = $prefix . $key; + $field += $params; - if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) { - // Recursively get all the nested fields. - $newParams = array_intersect_key($this->filter, $field); - $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']); - } else if ($field['type'] !== 'ignore') { - // Add rule. + if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) { + // Recursively get all the nested fields. + $newParams = array_intersect_key($this->filter, $field); + $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']); + } else if ($field['type'] !== 'ignore') { $this->rules[$prefix . $key] = &$field; $this->addProperty($prefix . $key); - - foreach ($field as $name => $value) { - // Support nested blueprints. - if ($this->context && $name == '@import') { - $values = (array) $value; - if (!isset($field['fields'])) { - $field['fields'] = array(); - } - foreach ($values as $bname) { - $b = $this->context->get($bname); - $field['fields'] = array_merge($field['fields'], $b->fields()); - } - } - - // Support for callable data values. - elseif (substr($name, 0, 6) == '@data-') { - $property = substr($name, 6); - if (is_array($value)) { - $func = array_shift($value); - } else { - $func = $value; - $value = array(); - } - list($o, $f) = preg_split('/::/', $func); - if (!$f && function_exists($o)) { - $data = call_user_func_array($o, $value); - } elseif ($f && method_exists($o, $f)) { - $data = call_user_func_array(array($o, $f), $value); - } - - // If function returns a value, - if (isset($data)) { - if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) { - // Combine field and @data-field together. - $field[$property] += $data; - } else { - // Or create/replace field with @data-field. - $field[$property] = $data; - } - } - } - - elseif (substr($name, 0, 8) == '@config-') { - $property = substr($name, 8); - $default = isset($field[$property]) ? $field[$property] : null; - $config = self::getGrav()['config']->get($value, $default); - - if (!is_null($config)) { - $field[$property] = $config; - } + + if ($field['type'] === 'list') { + // we loop through list to get the actual field + foreach($field['fields'] as $subName => &$subField) { + $this->parseFormField($subField); } + } else { + $this->parseFormField($field); } - - // Initialize predefined validation rule. + if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { $field['validate'] += $this->getRule($field['validate']['rule']); } } - } - } + } + } + /** + * Parses individual field definition + * + * @param array $field + * @internal + */ + protected function parseFormField(&$field) { + foreach ($field as $name => $value) { + // Support nested blueprints. + if ($this->context && $name == '@import') { + $values = (array) $value; + if (!isset($field['fields'])) { + $field['fields'] = array(); + } + foreach ($values as $bname) { + $b = $this->context->get($bname); + $field['fields'] = array_merge($field['fields'], $b->fields()); + } + } + + // Support for callable data values. + elseif (substr($name, 0, 6) == '@data-') { + $property = substr($name, 6); + if (is_array($value)) { + $func = array_shift($value); + } else { + $func = $value; + $value = array(); + } + list($o, $f) = preg_split('/::/', $func); + if (!$f && function_exists($o)) { + $data = call_user_func_array($o, $value); + } elseif ($f && method_exists($o, $f)) { + $data = call_user_func_array(array($o, $f), $value); + } + + // If function returns a value, + if (isset($data)) { + if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) { + // Combine field and @data-field together. + $field[$property] += $data; + } else { + // Or create/replace field with @data-field. + $field[$property] = $data; + } + } + } + + elseif (substr($name, 0, 8) == '@config-') { + $property = substr($name, 8); + $default = isset($field[$property]) ? $field[$property] : null; + $config = self::getGrav()['config']->get($value, $default); + + if (!is_null($config)) { + $field[$property] = $config; + } + } + } + } /** * Add property to the definition. diff --git a/system/src/Grav/Common/Twig/TwigExtension.php b/system/src/Grav/Common/Twig/TwigExtension.php index 4ea09e350..12a1cb633 100644 --- a/system/src/Grav/Common/Twig/TwigExtension.php +++ b/system/src/Grav/Common/Twig/TwigExtension.php @@ -355,6 +355,12 @@ class TwigExtension extends \Twig_Extension $periods[$j] .= '_PLURAL'; } + if ($this->grav['language']->getTranslation($this->grav['language']->getLanguage(), $periods[$j] . '_MORE_THAN_TWO')) { + if ($difference > 2) { + $periods[$j] .= '_MORE_THAN_TWO'; + } + } + $periods[$j] = $this->grav['language']->translate($periods[$j], null, true); return "$difference $periods[$j] {$tense}"; diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index db1162d51..dc378381a 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -442,7 +442,6 @@ abstract class Utils return in_array($value, [true, 1, '1', 'yes', 'on', 'true'], true); } - /** * Generates a nonce string to be hashed. Called by self::getNonce() * @@ -470,7 +469,7 @@ abstract class Utils $i++; } - return ( $i . '|' . $action . '|' . $username . '|' . $token ); + return ( $i . '|' . $action . '|' . $username . '|' . $token . '|' . self::getGrav()['config']->get('security.salt')); } /** @@ -487,19 +486,6 @@ abstract class Utils return (int)ceil(time() / ( $secondsInHalfADay )); } - /** - * Get hash of given string - * - * @param string $data string to hash - * - * @return string hashed value of $data, cut to 10 characters - */ - public static function hash($data) - { - $hash = password_hash($data, PASSWORD_DEFAULT); - return $hash; - } - /** * Creates a hashed nonce tied to the passed action. Tied to the current user and time. The nonce for a given * action is the same for 12 hours. @@ -515,9 +501,8 @@ abstract class Utils if (isset(static::$nonces[$action])) { return static::$nonces[$action]; } - $nonce = self::hash(self::generateNonceString($action, $plusOneTick)); - - static::$nonces[$action] = str_replace('/', 'SLASH', $nonce); + $nonce = md5(self::generateNonceString($action, $plusOneTick)); + static::$nonces[$action] = $nonce; return static::$nonces[$action]; } @@ -532,21 +517,18 @@ abstract class Utils */ public static function verifyNonce($nonce, $action) { - $nonce = str_replace('SLASH', '/', $nonce); - //Nonce generated 0-12 hours ago - if (password_verify(self::generateNonceString($action), $nonce)) { + if ($nonce == self::getNonce($action)) { return true; } //Nonce generated 12-24 hours ago $plusOneTick = true; - if (password_verify(self::generateNonceString($action, $plusOneTick), $nonce)) { + if ($nonce == self::getNonce($action, $plusOneTick)) { return true; } //Invalid nonce return false; } - }