kevin 3 years ago
parent
commit
b6ed4d771e
38 changed files with 964 additions and 223 deletions
  1. 66 0
      .github/workflows/tests.yml
  2. 30 0
      CHANGELOG.md
  3. 15 0
      SECURITY.md
  4. 2 3
      composer.json
  5. 398 59
      composer.lock
  6. 1 1
      fixperms.sh
  7. 0 1
      system/assets/jquery/jquery-3.x.min.js
  8. 2 1
      system/blueprints/config/scheduler.yaml
  9. 3 3
      system/config/media.yaml
  10. 1 1
      system/defines.php
  11. 1 1
      system/src/Grav/Common/Backup/Backups.php
  12. 3 3
      system/src/Grav/Common/Config/Setup.php
  13. 18 4
      system/src/Grav/Common/GPM/GPM.php
  14. 4 2
      system/src/Grav/Common/GPM/Response.php
  15. 22 1
      system/src/Grav/Common/Processors/ConfigurationProcessor.php
  16. 2 2
      system/src/Grav/Common/Scheduler/Job.php
  17. 1 1
      system/src/Grav/Common/Scheduler/Scheduler.php
  18. 1 1
      system/src/Grav/Common/Security.php
  19. 3 7
      system/src/Grav/Common/Utils.php
  20. 3 2
      system/src/Grav/Console/Gpm/InstallCommand.php
  21. 21 2
      system/src/Grav/Console/Gpm/SelfupgradeCommand.php
  22. 2 1
      system/src/Grav/Framework/Object/Base/ObjectCollectionTrait.php
  23. 32 0
      user/config/system.yaml
  24. 6 0
      user/config/versions.yaml
  25. 2 2
      user/pages/02.whats-on/01.exhibitions/current-upcoming/at-large/events.md
  26. 56 34
      user/themes/vocurations/css-compiled/theme.css
  27. 0 0
      user/themes/vocurations/css-compiled/theme.min.css
  28. 16 0
      user/themes/vocurations/js/site.js
  29. 1 0
      user/themes/vocurations/scss/theme.scss
  30. 0 82
      user/themes/vocurations/scss/theme/_extensions.scss
  31. 5 0
      user/themes/vocurations/scss/theme/_forms.scss
  32. 113 0
      user/themes/vocurations/scss/theme/_search.scss
  33. 118 0
      user/themes/vocurations/templates/forms/fields/file/file.html.twig
  34. 3 2
      user/themes/vocurations/templates/partials/navigation.html.twig
  35. 7 2
      user/themes/vocurations/templates/partials/simplesearch_item.html.twig
  36. 1 0
      user/themes/vocurations/templates/partials/simplesearch_searchbox.html.twig
  37. 2 5
      user/themes/vocurations/templates/simplesearch_results.html.twig
  38. 3 0
      webserver-configs/htaccess.txt

+ 66 - 0
.github/workflows/tests.yml

@@ -0,0 +1,66 @@
+name: PHP Tests
+
+on:
+  push:
+    branches: [ develop ]
+  pull_request:
+    branches: [ develop ]
+
+jobs:
+  test:
+
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        php: [ 7.4, 7.3, 7.2 ]
+        os: [ubuntu-latest]
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Setup PHP
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          extensions: opcache, gd
+          coverage: none      
+
+      - name: Validate composer.json and composer.lock
+        run: composer validate
+
+      - name: Get composer cache directory
+        id: composer-cache
+        run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+      - name: Cache dependencies
+        uses: actions/cache@v2
+        with:
+          path: ${{ steps.composer-cache.outputs.dir }}
+          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+          restore-keys: ${{ runner.os }}-composer-  
+
+      - name: Install dependencies
+        run: composer install --prefer-dist --no-progress
+
+      - name: Run test suite
+        run: vendor/bin/codecept run
+
+      - name: Slack Notification
+        uses: 8398a7/action-slack@v3
+        with:
+          status: custom
+          fields: workflow,job,commit,repo,ref,author,took
+          custom_payload: |
+            {
+              username: 'action-slack',
+              icon_emoji: ':octocat:',
+              attachments: [{
+                color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
+                text: `${process.env.AS_WORKFLOW}\n${process.env.AS_JOB} (${process.env.AS_COMMIT}) of ${process.env.AS_REPO}@${process.env.AS_REF} by ${process.env.AS_AUTHOR} succeeded in ${process.env.AS_TOOK}`,
+              }]
+            }
+        env:
+          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} # required
+        if: always() # Pick up events even if the job fails or is canceled.
+        

+ 30 - 0
CHANGELOG.md

@@ -1,3 +1,33 @@
+# v1.6.30
+## 12/03/2020
+
+1. [](#bugfix)
+    * Rollback `samesite` cookie logic as it causes issues with PHP < 7.3 [#309](https://github.com/getgrav/grav/issues/3089)
+    * Fixed issue with `.travis.yml` due to GitHub API deprecated functionality
+
+# v1.6.29
+## 12/02/2020
+
+1. [](#new)
+    * Added basic support for `user/config/versions.yaml`
+1. [](#improved)
+    * Updated bundled JQuery to latest version `3.5.1`
+    * Forward a `sid` to GPM when downloading a premium package via CLI
+    * Better handling of missing repository index [grav-plugin-admin#1916](https://github.com/getgrav/grav-plugin-admin/issues/1916)
+    * Set `grav_cli` as referrer when using `Response` from CLI
+    * Add option for timeout in `self-upgrade` command [#3013](https://github.com/getgrav/grav/pull/3013)
+    * Allow to set SameSite from system.yaml [#3063](https://github.com/getgrav/grav/pull/3063)
+    * Update media.yaml with some MS Office mimetypes [#3070](https://github.com/getgrav/grav/pull/3070)
+1. [](#bugfix)
+    * Fixed hardcoded system folder in blueprints, config and language streams
+    * Added `.htaccess` rule to block attempts to use Twig in the request URL
+    * Fix compatibility with Symfony 4.2 and up. [#3048](https://github.com/getgrav/grav/pull/3048)
+    * Fix failing example custom shceduled job. [#3050](https://github.com/getgrav/grav/pull/3050)
+    * Fix for XSS advisory [GHSA-cvmr-6428-87w9](https://github.com/getgrav/grav/security/advisories/GHSA-cvmr-6428-87w9)
+    * Fix uploads_dangerous_extensions checking [#3060](https://github.com/getgrav/grav/pull/3060)
+    * Remove redundant prefixing of `.` to extension [#3060](https://github.com/getgrav/grav/pull/3060)
+    * Check exact extension in checkFilename utility [#3061](https://github.com/getgrav/grav/pull/3061)
+
 # v1.6.28
 ## 10/07/2020
 

+ 15 - 0
SECURITY.md

@@ -0,0 +1,15 @@
+# Security Policy
+
+## Supported Versions
+
+We are focusing our security updates on the following versions
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 1.7.x   | :white_check_mark: |
+| 1.6.x   | :white_check_mark: |
+| < 1.6   | :x:                |
+
+## Reporting a Vulnerability
+
+Please contact contact@getgrav.org with a detailed explaination of the security issue found and we will work with you to get it resolved as fast as possible.

+ 2 - 3
composer.json

@@ -50,15 +50,14 @@
         "composer/ca-bundle": "^1.0",
         "dragonmantank/cron-expression": "^1.2",
         "phive/twig-extensions-deferred": "^1.0",
-        "willdurand/negotiation": "2.x-dev"
+        "willdurand/negotiation": "^3.0"
     },
     "require-dev": {
         "codeception/codeception": "^2.4",
         "phpstan/phpstan": "^0.11",
         "phpstan/phpstan-deprecation-rules": "^0.11.0",
         "phpunit/php-code-coverage": "~6.0",
-        "fzaninotto/faker": "^1.8",
-        "victorjonsson/markdowndocs": "dev-master"
+        "fzaninotto/faker": "^1.8"
     },
     "suggest": {
         "ext-zend-opcache": "Recommended for better performance",

File diff suppressed because it is too large
+ 398 - 59
composer.lock


+ 1 - 1
fixperms.sh

@@ -1,5 +1,5 @@
 #!/bin/sh
-chown -R kevin:http .
+chown -R 1000:www-data .
 find . -type f -exec chmod 664 {} \;
 find ./bin -type f -exec chmod 775 {} \;
 find . -type d -exec chmod 775 {} \;

File diff suppressed because it is too large
+ 0 - 1
system/assets/jquery/jquery-3.x.min.js


+ 2 - 1
system/blueprints/config/scheduler.yaml

@@ -39,12 +39,13 @@ form:
             .command:
               type: text
               label: PLUGIN_ADMIN.COMMAND
-              placeholder: 'cd ~;ls -lah;'
+              placeholder: 'ls'
               validate:
                   required: true
             .args:
               type: text
               label: PLUGIN_ADMIN.EXTRA_ARGUMENTS
+              placeholder: '-lah'
             .at:
               type: cron
               label: PLUGIN_ADMIN.SCHEDULER_RUNAT

+ 3 - 3
system/config/media.yaml

@@ -103,7 +103,7 @@ types:
   docx:
     type: file
     thumb: media/thumb-docx.png
-    mime: application/msword
+    mime: application/vnd.openxmlformats-officedocument.wordprocessingml.document
   xls:
     type: file
     thumb: media/thumb-xls.png
@@ -111,7 +111,7 @@ types:
   xlsx:
     type: file
     thumb: media/thumb-xlsx.png
-    mime: application/vnd.ms-excel
+    mime: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
   ppt:
     type: file
     thumb: media/thumb-ppt.png
@@ -119,7 +119,7 @@ types:
   pptx:
     type: file
     thumb: media/thumb-pptx.png
-    mime: application/vnd.ms-powerpoint
+    mime: application/vnd.openxmlformats-officedocument.presentationml.presentation
   pps:
     type: file
     thumb: media/thumb-pps.png

+ 1 - 1
system/defines.php

@@ -8,7 +8,7 @@
 
 // Some standard defines
 define('GRAV', true);
-define('GRAV_VERSION', '1.6.28');
+define('GRAV_VERSION', '1.6.30');
 define('GRAV_TESTING', false);
 define('DS', '/');
 

+ 1 - 1
system/src/Grav/Common/Backup/Backups.php

@@ -70,7 +70,7 @@ class Backups
     public function getBackupDownloadUrl($backup, $base_url)
     {
         $param_sep = $param_sep = Grav::instance()['config']->get('system.param_sep', ':');
-        $download = urlencode(base64_encode($backup));
+        $download = urlencode(base64_encode(basename($backup)));
         $url      = rtrim(Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim($base_url,
                 '/') . '/task' . $param_sep . 'backup/download' . $param_sep . $download . '/admin-nonce' . $param_sep . Utils::getNonce('admin-form');
 

+ 3 - 3
system/src/Grav/Common/Config/Setup.php

@@ -59,13 +59,13 @@ class Setup extends Data
         'blueprints' => [
             'type' => 'ReadOnlyStream',
             'prefixes' => [
-                '' => ['environment://blueprints', 'user://blueprints', 'system/blueprints'],
+                '' => ['environment://blueprints', 'user://blueprints', 'system://blueprints'],
             ]
         ],
         'config' => [
             'type' => 'ReadOnlyStream',
             'prefixes' => [
-                '' => ['environment://config', 'user://config', 'system/config'],
+                '' => ['environment://config', 'user://config', 'system://config'],
             ]
         ],
         'plugins' => [
@@ -89,7 +89,7 @@ class Setup extends Data
         'languages' => [
             'type' => 'ReadOnlyStream',
             'prefixes' => [
-                '' => ['environment://languages', 'user://languages', 'system/languages'],
+                '' => ['environment://languages', 'user://languages', 'system://languages'],
             ]
         ],
         'cache' => [

+ 18 - 4
system/src/Grav/Common/GPM/GPM.php

@@ -233,6 +233,11 @@ class GPM extends Iterator
     public function getUpdatablePlugins()
     {
         $items = [];
+
+        if (!$this->repository) {
+            return $items;
+        }
+
         $repository = $this->repository['plugins'];
 
         // local cache to speed things up
@@ -312,6 +317,11 @@ class GPM extends Iterator
     public function getUpdatableThemes()
     {
         $items = [];
+
+        if (!$this->repository) {
+            return $items;
+        }
+
         $repository = $this->repository['themes'];
 
         // local cache to speed things up
@@ -359,6 +369,10 @@ class GPM extends Iterator
      */
     public function getReleaseType($package_name)
     {
+        if (!$this->repository) {
+            return null;
+        }
+
         $repository = $this->repository['plugins'];
         if (isset($repository[$package_name])) {
             return $repository[$package_name]->release_type;
@@ -407,7 +421,7 @@ class GPM extends Iterator
      */
     public function getRepositoryPlugin($slug)
     {
-        return @$this->repository['plugins'][$slug];
+        return $this->repository['plugins'][$slug] ?? null;
     }
 
     /**
@@ -416,7 +430,7 @@ class GPM extends Iterator
      */
     public function getRepositoryPlugins()
     {
-        return $this->repository['plugins'];
+        return $this->repository['plugins'] ?? null;
     }
 
     /**
@@ -426,7 +440,7 @@ class GPM extends Iterator
      */
     public function getRepositoryTheme($slug)
     {
-        return @$this->repository['themes'][$slug];
+        return $this->repository['themes'][$slug] ?? null;
     }
 
     /**
@@ -435,7 +449,7 @@ class GPM extends Iterator
      */
     public function getRepositoryThemes()
     {
-        return $this->repository['themes'];
+        return $this->repository['themes'] ?? null;
     }
 
     /**

+ 4 - 2
system/src/Grav/Common/GPM/Response.php

@@ -284,7 +284,8 @@ class Response
             $options['fopen']['notification'] = ['self', 'progress'];
         }
 
-        $options['fopen']['header'] = 'Referer: ' . Grav::instance()['uri']->rootUrl(true);
+        $referer = \defined('GRAV_CLI') ? 'grav_cli' : Grav::instance()['uri']->rootUrl(true);
+        $options['fopen']['header'] = 'Referer: ' . $referer;
         if (isset($options['fopen']['ssl'])) {
             $ssl = $options['fopen']['ssl'];
             unset($options['fopen']['ssl']);
@@ -367,7 +368,8 @@ class Response
      */
     private static function curlExecFollow($ch, $options, $callback)
     {
-        curl_setopt_array($ch, [ CURLOPT_REFERER => Grav::instance()['uri']->rootUrl(true) ]);
+        $referer = \defined('GRAV_CLI') ? 'grav_cli' : Grav::instance()['uri']->rootUrl(true);
+        curl_setopt_array($ch, [ CURLOPT_REFERER => $referer ]);
 
         if ($callback) {
             curl_setopt_array(

+ 22 - 1
system/src/Grav/Common/Processors/ConfigurationProcessor.php

@@ -9,6 +9,8 @@
 
 namespace Grav\Common\Processors;
 
+use Grav\Framework\File\Formatter\YamlFormatter;
+use Grav\Framework\File\YamlFile;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\RequestHandlerInterface;
@@ -21,8 +23,27 @@ class ConfigurationProcessor extends ProcessorBase
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
     {
         $this->startTimer();
-        $this->container['config']->init();
+        $config = $this->container['config'];
+        $config->init();
         $this->container['plugins']->setup();
+
+        if ($config->get('versions') === null) {
+            $filename = GRAV_ROOT . '/user/config/versions.yaml';
+            if (!is_file($filename)) {
+                $versions = [
+                    'core' => [
+                        'grav' => [
+                            'version' => GRAV_VERSION,
+                            'history' => ['version' => GRAV_VERSION, 'date' => gmdate('Y-m-d H:i:s')]
+                        ]
+                    ]
+                ];
+                $config->set('versions', $versions);
+
+                $file = new YamlFile($filename, new YamlFormatter(['inline' => 4]));
+                $file->save($versions);
+            }
+        }
         $this->stopTimer();
 
         return $handler->handle($request);

+ 2 - 2
system/src/Grav/Common/Scheduler/Job.php

@@ -298,8 +298,8 @@ class Job
         if (is_callable($this->command)) {
             $this->output = $this->exec();
         } else {
-            $args = \is_string($this->args) ? $this->args : implode(' ', $this->args);
-            $command = $this->command . ' ' . $args;
+            $args = \is_string($this->args) ? explode(' ', $this->args) : $this->args;
+            $command = array_merge([$this->command], $args);
             $process = new Process($command);
 
             $this->process = $process;

+ 1 - 1
system/src/Grav/Common/Scheduler/Scheduler.php

@@ -246,7 +246,7 @@ class Scheduler
      */
     public function isCrontabSetup()
     {
-        $process = new Process('crontab -l');
+        $process = new Process(['crontab', '-l']);
         $process->run();
 
         if ($process->isSuccessful()) {

+ 1 - 1
system/src/Grav/Common/Security.php

@@ -133,7 +133,7 @@ class Security
         // Set the patterns we'll test against
         $patterns = [
             // Match any attribute starting with "on" or xmlns
-            'on_events' => '#(<[^>]+[[a-z\x00-\x20\"\'\/])(\son|\sxmlns)[a-z].*=>?#iUu',
+            'on_events' => '#(<[^>]+[[a-z\x00-\x20\"\'\/])([\s\/]on|\sxmlns)[a-z].*=>?#iUu',
 
             // Match javascript:, livescript:, vbscript:, mocha:, feed: and data: protocols
             'invalid_protocols' => '#(' . implode('|', $invalid_protocols) . '):.*?#iUu',

+ 3 - 7
system/src/Grav/Common/Utils.php

@@ -859,11 +859,7 @@ abstract class Utils
     public static function checkFilename($filename)
     {
         $dangerous_extensions = Grav::instance()['config']->get('security.uploads_dangerous_extensions', []);
-        array_walk($dangerous_extensions, function(&$val) {
-            $val = '.' . $val;
-        });
-
-        $extension = '.' . pathinfo($filename, PATHINFO_EXTENSION);
+        $extension = pathinfo($filename, PATHINFO_EXTENSION);
 
         return !(
             // Empty filenames are not allowed.
@@ -872,8 +868,8 @@ abstract class Utils
             || strtr($filename, "\t\v\n\r\0\\/", '_______') !== $filename
             // Filename should not start or end with dot or space.
             || trim($filename, '. ') !== $filename
-            // Filename should not contain .php in it.
-            || static::contains($extension, $dangerous_extensions)
+            // File extension should not be part of configured dangerous extensions
+            || in_array($extension, $dangerous_extensions)
         );
     }
 

+ 3 - 2
system/src/Grav/Console/Gpm/InstallCommand.php

@@ -445,7 +445,7 @@ class InstallCommand extends ConsoleCommand
             } else {
                 $repo_dir = $matches[2];
             }
-            
+
             $paths = (array) $paths;
             foreach ($paths as $repo) {
                 $path = rtrim($repo, '/') . '/' . $repo_dir;
@@ -570,7 +570,8 @@ class InstallCommand extends ConsoleCommand
                 [
                     'slug' => $package->slug,
                     'filename' => $package->premium['filename'],
-                    'license_key' => $license
+                    'license_key' => $license,
+                    'sid' => md5(GRAV_ROOT)
                 ]
             ));
 

+ 21 - 2
system/src/Grav/Console/Gpm/SelfupgradeCommand.php

@@ -46,6 +46,9 @@ class SelfupgradeCommand extends ConsoleCommand
 
     protected $overwrite;
 
+    /** @var int */
+    protected $timeout;
+
     protected function configure()
     {
         $this
@@ -69,6 +72,13 @@ class SelfupgradeCommand extends ConsoleCommand
                 InputOption::VALUE_NONE,
                 'Option to overwrite packages if they already exist'
             )
+            ->addOption(
+                'timeout',
+                't',
+                InputOption::VALUE_OPTIONAL,
+                'Option to set the timeout in seconds when downloading the update (0 for no timeout)',
+                30
+            )
             ->setDescription('Detects and performs an update of Grav itself when available')
             ->setHelp('The <info>update</info> command updates Grav itself when a new version is available');
     }
@@ -78,6 +88,7 @@ class SelfupgradeCommand extends ConsoleCommand
         $this->upgrader = new Upgrader($this->input->getOption('force'));
         $this->all_yes = $this->input->getOption('all-yes');
         $this->overwrite = $this->input->getOption('overwrite');
+        $this->timeout = (int) $this->input->getOption('timeout');
 
         $this->displayGPMRelease();
 
@@ -116,7 +127,6 @@ class SelfupgradeCommand extends ConsoleCommand
 
         $questionHelper = $this->getHelper('question');
 
-
         $this->output->writeln("Grav v<cyan>{$remote}</cyan> is now available [release date: {$release}].");
         $this->output->writeln('You are currently using v<cyan>' . GRAV_VERSION . '</cyan>.');
 
@@ -185,7 +195,16 @@ class SelfupgradeCommand extends ConsoleCommand
     {
         $tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
         $this->tmp = $tmp_dir . '/Grav-' . uniqid('', false);
-        $output = Response::get($package['download'], [], [$this, 'progress']);
+        $options = [
+            'curl' => [
+                CURLOPT_TIMEOUT => $this->timeout,
+            ],
+            'fopen' => [
+                'timeout' => $this->timeout,
+            ],
+        ];
+
+        $output = Response::get($package['download'], $options, [$this, 'progress']);
 
         Folder::create($this->tmp);
 

+ 2 - 1
system/src/Grav/Framework/Object/Base/ObjectCollectionTrait.php

@@ -63,9 +63,10 @@ trait ObjectCollectionTrait
     /**
      * @param string $property      Object property to be fetched.
      * @param mixed $default        Default value if not set.
+     * @param bool $doCreate        Not being used.
      * @return mixed[]              Key/Value pairs of the properties.
      */
-    public function doGetProperty($property, $default = null)
+    public function &doGetProperty($property, $default = null, $doCreate = false)
     {
         $list = [];
 

+ 32 - 0
user/config/system.yaml

@@ -1,14 +1,22 @@
 absolute_urls: false
 timezone: Europe/Paris
+default_locale: null
 param_sep: ':'
 wrapped_site: false
 reverse_proxy_setup: false
 force_ssl: false
 force_lowercase_urls: true
+custom_base_url: null
 username_regex: '^[a-z0-9_-]{3,16}$'
 pwd_regex: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}'
 intl_enabled: true
+http_x_forwarded:
+  protocol: true
+  host: false
+  port: true
+  ip: true
 languages:
+  supported: null
   default_lang: fr
   include_default_lang: false
   pages_fallback_only: false
@@ -28,6 +36,7 @@ pages:
   list:
     count: 50
   dateformat:
+    default: null
     short: 'jS M Y'
     long: 'jS M Y'
   publish_dates: true
@@ -47,6 +56,12 @@ pages:
     special_chars:
       '>': gt
       '<': lt
+    valid_link_attributes:
+      - rel
+      - target
+      - id
+      - class
+      - classes
   types:
     - html
     - htm
@@ -55,6 +70,7 @@ pages:
     - json
     - rss
     - atom
+  append_url_extension: null
   expires: 604800
   cache_control: '31536000'
   last_modified: false
@@ -69,6 +85,7 @@ pages:
     - .git
     - .idea
   ignore_hidden: true
+  hide_empty_folders: false
   url_taxonomy_filters: true
   frontmatter:
     process_twig: false
@@ -89,6 +106,17 @@ cache:
   lifetime: 604800
   gzip: false
   allow_webserver_gzip: false
+  redis:
+    socket: null
+    server: null
+    port: null
+    password: null
+  memcache:
+    server: null
+    port: null
+  memcached:
+    server: null
+    port: null
 twig:
   cache: false
   debug: false
@@ -132,6 +160,8 @@ images:
   seofriendly: false
 media:
   enable_media_timestamp: false
+  unsupported_inline_types: null
+  allowed_fallback_types: null
   auto_metadata_exif: false
   upload_limit: 8388608
 session:
@@ -143,8 +173,10 @@ session:
   secure: false
   httponly: true
   split: true
+  path: null
 gpm:
   releases: stable
+  proxy_url: null
   method: auto
   verify_peer: true
   official_gpm_only: true

+ 6 - 0
user/config/versions.yaml

@@ -0,0 +1,6 @@
+core:
+  grav:
+    version: 1.6.30
+    history:
+      version: 1.6.30
+      date: '2020-12-06 17:57:16'

+ 2 - 2
user/pages/02.whats-on/01.exhibitions/current-upcoming/at-large/events.md

@@ -6,9 +6,9 @@ lieux: '93 Baker Street'
 artistes: ' Olivia Bax'
 title: '‘at large'', '
 media_order: 'Olivia Bax, Boulder (with handle), 2015.jpg,Detail of Olivia Bax, Hot Spot, 2018.jpg,Olivia Bax, Love Handles, 2017.jpg,Olivia Bax, Pump, 2016.jpg,Olivia Bax, Slot _ Groove, 2015.jpg,Olivia Bax, Rumble, 2018.jpg,Installation Olivia Bax.jpg,Detail ''Footloose'', 2017.jpg,Olivia Bax, Footloose, 2017.jpg'
-show_sidebar: false
 aura:
     pagetype: website
+show_sidebar: false
 ---
 
 An awareness of materials is crucial in pursuing any artistic endeavour.
@@ -27,7 +27,7 @@ materials for further assembly (Iza Genzken). Olivia Bax's work is a
 distinct example of this aesthetic manu propria, for Bax not only
 physically leaves the imprint of her hand, her gestures on the surface of her
 sculptures, but she also uses handles as a recurring motif (Hot Spot,
-Boulder (with handle) and Pump). Her stand-alone pieces (Rumble and
+Boulder (**with handle) and Pump). Her stand-alone pieces (Rumble** and
 Roar) have a human scale, as if they were based on her own height.
 
 Bax's investigation of material rhythms can be likened to the act of

File diff suppressed because it is too large
+ 56 - 34
user/themes/vocurations/css-compiled/theme.css


File diff suppressed because it is too large
+ 0 - 0
user/themes/vocurations/css-compiled/theme.min.css


+ 16 - 0
user/themes/vocurations/js/site.js

@@ -127,7 +127,23 @@ function newsletter() {
 
 }
 
+
+function OpenSearch(){
+  $('.wrap_search a').click(function() {
+    $('.search-wrapper').toggleClass("opacity");
+  });
+
+  var url = window.location.pathname
+  var splitUrl = url.split("/");
+
+  console.log(splitUrl);
+  if(splitUrl[1] == "search" ){
+    $('.search-wrapper').addClass("opacity");
+  }
+}
+
 $(document).ready(function(){
   // more();
   // newsletter();
+  OpenSearch();
 });

+ 1 - 0
user/themes/vocurations/scss/theme.scss

@@ -14,6 +14,7 @@
 @import 'theme/header';
 @import 'theme/footer';
 @import 'theme/menu';
+@import 'theme/search';
 
 // Extra Skeleton Styling
 @import 'theme/blog';

+ 0 - 82
user/themes/vocurations/scss/theme/_extensions.scss

@@ -115,86 +115,4 @@
   }
 }
 
-.simplesearch_results{
-  .section{
-    // width: calc((100% / 12) * 9);
-    width: 100%;
-    .simplesearch{
-      .center{
-        width: calc((100% / 12) * 9);
-      }
-      .result_for{
-        text-transform: uppercase;
-        p{
-          margin: 0!important;
-        }
-      }
-
-      .search-wrapper{
-        form{
-          display: inline-flex;
-          .search-input, button{
-            font-family: $Bold;
-            font-size: 6rem;
-            text-transform: uppercase;
-            width: 100%;
-            height: auto;
-            border: none;
-            background: none;
-          }
-        }
-      }
-    }
-  }
-  .card-cat{
-    margin-bottom:0.6rem;
-  }
-}
 
-.search-results{
-  .results{
-    margin-top: 6rem;
-    @include flexbox;
-    align-items: flex-end;
-    width: 100%;
-    .search-row{
-      width: calc((100% / 12) * 6);
-      margin-bottom: 6rem;
-      a{
-        display: block;
-      }
-      &:nth-child(odd){
-        padding-right: 0.7rem;
-      }
-      &:nth-child(even){
-        padding-left: 0.7rem;
-      }
-      .search-item{
-        margin: 0;
-      }
-      .card-cat{
-        margin-bottom:0.6rem;
-      }
-      .search-title{
-        h2{
-          font-size: 2.5rem;
-          line-height: 2.7rem;
-         }
-      }
-      .search-details{
-        font-family: $Bold;
-        font-size: 2.5rem;
-        line-height: 2.7rem;
-        font-weight: 400;
-        margin: 0;
-        text-transform: uppercase;
-      }
-      .search-image{
-        float: none;
-        width: 100%;
-        margin-top: 1.5rem;
-        margin-bottom: 1.5rem;
-      }
-    }
-  }
-}

+ 5 - 0
user/themes/vocurations/scss/theme/_forms.scss

@@ -157,6 +157,7 @@
               }
             }
             .dz-default{
+              display: none;
               span{
                 display: none;
               }
@@ -279,3 +280,7 @@
     margin-left: 1rem;
   }
 }
+
+input{
+  outline: none; 
+}

+ 113 - 0
user/themes/vocurations/scss/theme/_search.scss

@@ -0,0 +1,113 @@
+.simplesearch_results{
+    .section{
+      // width: calc((100% / 12) * 9);
+      width: 100%;
+      .simplesearch{
+        .center{
+          width: calc((100% / 12) * 9);
+        }
+        .result_for{
+          text-transform: uppercase;
+          p{
+            margin: 0!important;
+          }
+        }
+  
+      }
+    }
+    .card-cat{
+      margin-bottom:0.6rem;
+    }
+  }
+  
+  .wrap_search{
+    display: inline-flex;
+    align-items: baseline;
+    & > a{
+        margin-right: 1.2rem;
+    }
+  }
+
+  .search-wrapper{
+      opacity: 0;
+      transition: opacity 0.2s ease;
+      &.opacity{
+          opacity: 1;
+          transition: opacity 0.2s ease;
+      }
+    form{
+      display: inline-flex;
+      .search-input, button{
+        font-family: $Bold;
+        font-size: 1.5rem;
+        text-transform: uppercase;
+        height: auto;
+        border: none;
+        background: none;
+    }
+    button{
+        width: auto;
+    }
+    .search-input{
+        max-width: 200px;
+        width: 100%;
+        border-bottom: 1px solid black;
+        margin-right: 1.2rem;
+        background: white!important;
+        &:focus, &:active, &::placeholder{
+            outline: none;
+            background-color:transparent!important;
+        }
+      }
+    }
+  }
+
+
+  .search-results{
+    .results{
+      margin-top: 6rem;
+      @include flexbox;
+      align-items: flex-end;
+      width: 100%;
+      .search-row{
+        width: calc((100% / 12) * 6);
+        margin-bottom: 6rem;
+        a{
+          display: block;
+        }
+        &:nth-child(odd){
+          padding-right: 0.7rem;
+        }
+        &:nth-child(even){
+          padding-left: 0.7rem;
+        }
+        .search-item{
+          margin: 0;
+        }
+        .card-cat{
+          margin-bottom:0.6rem;
+        }
+        .search-title{
+          h2{
+            font-size: 2.5rem;
+            line-height: 2.7rem;
+           }
+        }
+        .search-details{
+          font-family: $Bold;
+          font-size: 2.5rem;
+          line-height: 2.7rem;
+          font-weight: 400;
+          margin: 0;
+          text-transform: uppercase;
+        }
+        .search-image{
+          float: none;
+          width: 100%;
+          margin-top: 1.5rem;
+          margin-bottom: 1.5rem;
+        }
+      }
+    }
+  }
+  

+ 118 - 0
user/themes/vocurations/templates/forms/fields/file/file.html.twig

@@ -0,0 +1,118 @@
+{% extends "forms/field.html.twig" %}
+
+{% macro bytesToSize(bytes) -%}
+    {% spaceless %}
+        {% set kilobyte = 1024 %}
+        {% set megabyte = kilobyte * 1024 %}
+        {% set gigabyte = megabyte * 1024 %}
+        {% set terabyte = gigabyte * 1024 %}
+
+        {% if bytes < kilobyte %}
+            {{ bytes ~ ' B' }}
+        {% elseif bytes < megabyte %}
+            {{ (bytes / kilobyte)|number_format(2, '.') ~ ' KB' }}
+        {% elseif bytes < gigabyte %}
+            {{ (bytes / megabyte)|number_format(2, '.') ~ ' MB' }}
+        {% elseif bytes < terabyte %}
+            {{ (bytes / gigabyte)|number_format(2, '.') ~ ' GB' }}
+        {% else %}
+            {{ (bytes / terabyte)|number_format(2, '.') ~ ' TB' }}
+        {% endif %}
+    {% endspaceless %}
+{%- endmacro %}
+
+{% macro preview(path, value, global) %}
+    {% if value %}
+        {% set uri = global.grav.uri %}
+        {% set files = global.files %}
+        {% set config = global.grav.config %}
+        {% set route = global.context.route() %}
+        {% set type =  global.context.content() is not null ? 'pages' : global.plugin ? 'plugins' : global.theme ? 'themes' : 'config' %}
+        {% set blueprint_name = global.blueprints.getFilename %}
+        {% if type == 'pages' %}
+            {% set blueprint_name = type ~ '/' ~ blueprint_name %}
+        {% endif %}
+        {% set blueprint = base64_encode(blueprint_name) %}
+        {% set real_path = value.thumb ?? global.context.media[path].relativePath ?? global.form.getPagePathFromToken(path) %}
+        {% set remove = global.form.getFileDeleteAjaxRoute(files.name, path)|string ?: uri.addNonce(
+            global.base_url_relative ~
+            '/media.json' ~
+            '/task' ~ config.system.param_sep ~ 'removeFileFromBlueprint' ~
+            '/proute' ~ config.system.param_sep ~ base64_encode(route) ~
+            '/blueprint' ~ config.system.param_sep ~ blueprint ~
+            '/type' ~ config.system.param_sep ~ type ~
+            '/field' ~ config.system.param_sep ~ files.name ~
+            '/path' ~ config.system.param_sep ~ base64_encode(value.path), 'admin-form', 'admin-nonce') %}
+
+        {% set file = value|merge({remove: remove, path: value.thumb_url ?? (uri.rootUrl == '/' ? '/' : uri.rootUrl ~ '/' ~ real_path) }) %}
+        <div class="hidden" data-file="{{ file|json_encode|e('html_attr') }}"></div>
+    {% endif %}
+{% endmacro %}
+
+{% import _self as macro %}
+
+{% set defaults = config.plugins.form %}
+{% set files = defaults.files|merge(field|default([])) %}
+{% set limit = not field.multiple ? 1 : files.limit %}
+
+{% do config.set('forms.dropzone.enabled', true) %}
+
+{% block input %}
+    {% set page_can_upload = exists or (type == 'page' and not exists and not (field.destination starts with '@self' or field.destination starts with 'self@')) %}
+    {% set max_filesize = (field.filesize > form_max_filesize or field.filesize == 0) ? form_max_filesize : field.filesize %}
+
+    {% block prepend %}{% endblock %}
+    {% set settings = {name: field.name, paramName: (scope ~ field.name)|fieldName ~ (files.multiple ? '[]' : ''), limit: limit, filesize: max_filesize, accept: files.accept, resolution: files.resolution, resizeWidth: files.resizeWidth, resizeHeight: files.resizeHeight, resizeQuality: files.resizeQuality } %}
+    {% set dropzoneSettings = field.dropzone %}
+    <div class="{{ form_field_wrapper_classes ?: 'form-input-wrapper' }} {{ field.classes }} dropzone files-upload form-input-file {{ field.size }}" data-grav-file-settings="{{ settings|json_encode|e('html_attr') }}" data-dropzone-options="{{ dropzoneSettings|json_encode|e('html_attr') }}" {% if form.getFileUploadAjaxRoute %}data-file-url-add="{{ form.getFileUploadAjaxRoute() }}"{% endif %}>
+        {% block file_extras %}{% endblock %}
+        <input
+                {# required attribute structures #}
+                {% block input_attributes %}
+                    type="file"
+                    {% if files.multiple %}multiple="multiple"{% endif %}
+                    {% if files.accept %}accept="{{ files.accept|join(',') }}"{% endif %}
+                    {% if field.disabled %}disabled="disabled"{% endif %}
+                    {% if field.random_name %}random="true"{% endif %}
+                    {% if required %}required="required"{% endif %}
+                    {{ parent() }}
+                {% endblock %}
+        />
+
+        {% for path, file in value %}
+            {{ macro.preview(path, file, _context) }}
+        {% endfor %}
+        {% include 'forms/fields/hidden/hidden.html.twig' with {field: {name: '_json.' ~ field.name}, value: (value ?? [])|json_encode } %}
+    </div>
+
+    {% if grav.browser.browser == 'msie' and grav.browser.version < 12 %}
+        {% do assets.addJs('plugin://form/assets/object.assign.polyfill.js') %}
+    {% endif %}
+    {% do assets.addJs('jquery', 101) %}
+    {% do assets.addJs('plugin://form/assets/form.vendor.js', { 'group': 'bottom', 'loading': 'defer' }) %}
+    {% do assets.addJs('plugin://form/assets/form.min.js', { 'group': 'bottom', 'loading': 'defer'  }) %}
+    {% do assets.addCss('plugin://form/assets/dropzone.min.css', { 'group': 'form'}) %}
+    {{ assets.css('form')|raw }}
+    {% do assets.addInlineJs("
+    window.GravForm = window.GravForm || {};
+    window.GravForm = Object.assign({}, window.GravForm, {
+        translations: {
+            PLUGIN_FORM: {
+                'DROPZONE_CANCEL_UPLOAD': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD'|t|json_encode ~ ",
+                'DROPZONE_CANCEL_UPLOAD_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION'|t|json_encode ~ ",
+                'DROPZONE_DEFAULT_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE'|t|json_encode ~ ",
+                'DROPZONE_FALLBACK_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE'|t|json_encode ~ ",
+                'DROPZONE_FALLBACK_TEXT': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_TEXT'|t|json_encode ~ ",
+                'DROPZONE_FILE_TOO_BIG': " ~ 'PLUGIN_FORM.DROPZONE_FILE_TOO_BIG'|t|json_encode ~ ",
+                'DROPZONE_INVALID_FILE_TYPE': " ~ 'PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE'|t|json_encode ~ ",
+                'DROPZONE_MAX_FILES_EXCEEDED': " ~ 'PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED'|t|json_encode ~ ",
+                'DROPZONE_REMOVE_FILE': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE'|t|json_encode ~ ",
+                'DROPZONE_REMOVE_FILE_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION'|t|json_encode ~ ",
+                'DROPZONE_RESPONSE_ERROR': " ~ 'PLUGIN_FORM.DROPZONE_RESPONSE_ERROR'|t|json_encode ~ ",
+                'RESOLUTION_MIN': " ~ 'PLUGIN_FORM.RESOLUTION_MIN'|t|json_encode ~ ",
+                'RESOLUTION_MAX': " ~ 'PLUGIN_FORM.RESOLUTION_MAX'|t|json_encode ~ "
+            }
+        }
+    });
+    ", {'group': 'bottom', 'position': 'before'}) %}
+{% endblock %}

+ 3 - 2
user/themes/vocurations/templates/partials/navigation.html.twig

@@ -2,9 +2,10 @@
 
 <ul {{ tree ? 'class="tree"' : '' }}>
     {{ macros.nav_loop(pages) }}
-    <li>
-      <a href="/search">
+    <li class="wrap_search">
+      <a href="#">
         <img src="/user/themes/vocurations/images/Icone_search.svg" alt="">
       </a>
+    {% include 'partials/simplesearch_searchbox.html.twig' %}
     </li>
 </ul>

+ 7 - 2
user/themes/vocurations/templates/partials/simplesearch_item.html.twig

@@ -2,7 +2,6 @@
 {% set pageCollection = search_results %}
 
 {% if page.template == 'modular' %}
-
   {% for item in page.collection %}
     {% if item.media.images %}
       {% set value = query|hyphenize %}
@@ -10,7 +9,9 @@
       {% if title|contains(value) == 1  %}
 
         <section class="search-row">
-          <a href="{{ item.header.url_news }}" target="_blank">
+          {% if item.header.url_news %}
+            <a href="{{ item.header.url_news }}" target="_blank">
+          {% endif %}
             {% set banner = item.media.images|first %}
             <div class="search-item">
 
@@ -35,7 +36,10 @@
                 {% endif %}
 
             </div>
+        {% if item.header.url_news %}
           </a>
+        {% endif %}
+
         </section>
       {% endif %}
 
@@ -46,6 +50,7 @@
 
   {% if page.media.images %}
   <section class="search-row">
+
     <a href="{{page.url}}">
       {% set banner = page.media.images|first %}
       <div class="search-item">

+ 1 - 0
user/themes/vocurations/templates/partials/simplesearch_searchbox.html.twig

@@ -2,6 +2,7 @@
 <div class="search-wrapper">
     <form name="search" data-simplesearch-form>
         <input
+            autocomplete="off"
             name="searchfield"
             class="search-input"
             type="text"

+ 2 - 5
user/themes/vocurations/templates/simplesearch_results.html.twig

@@ -2,17 +2,14 @@
 
 {% block content %}
     <div class="content-padding simplesearch">
-        <div class="center">
-            {% include 'partials/simplesearch_searchbox.html.twig' %}
-        </div>
         <div class="result_for">
           <p>
               {% if query %}
                   {% set count = search_results ? search_results.count : 0 %}
                   {% if count is same as( 1 ) %}
-                      {{ "PLUGIN_SIMPLESEARCH.SEARCH_RESULTS_SUMMARY_SINGULAR"|t(query|e)|raw }}
+                      "{{ query }}" - Found {{ search_results.count }} {{ 'Result'|pluralize(search_results.count) }}
                   {% else %}
-                      {{ "PLUGIN_SIMPLESEARCH.SEARCH_RESULTS_SUMMARY_PLURAL"|t(query|e, count)|raw }}
+                        "{{ query }}" - Found {{ search_results.count }} {{ 'Results'|t(query|e, count)|raw }}
                   {% endif %}
               {% endif %}
           </p>

+ 3 - 0
webserver-configs/htaccess.txt

@@ -27,6 +27,9 @@ RewriteEngine On
 # If you experience problems on your site block out the operations listed below
 # This attempts to block the most common type of exploit `attempts` to Grav
 #
+# Block out any script trying to use twig tags in URL.
+RewriteCond %{REQUEST_URI} ({{|}}|{%|%}) [OR]
+RewriteCond %{QUERY_STRING} ({{|}}|{%25|%25}) [OR]
 # Block out any script trying to base64_encode data within the URL.
 RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR]
 # Block out any script that includes a <script> tag in URL.

Some files were not shown because too many files changed in this diff