diff --git a/CHANGELOG.md b/CHANGELOG.md index dc33ae7..a32b307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# v1.5.0 +## 16 June 2018 +1. [](#enhancement) + * Extra security option. Allows for more paranoia + * When enabled, each page with an [sql-table] shortcode must have explicit header permission + * This is to prevent shortcode being added in the frount end by an editor +1. [](#minorbug) + * fix file permission from 0666 to 0664 + # v1.4.0 ## 23 June 2018 1. [](#enhancement) diff --git a/README.md b/README.md index 9286507..4979ffe 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Here is the default configuration and an explanation of available options: enabled: true database_route: data/sqlite database_name: db.sqlite3 +extra_security: false logging: false all_logging: false # this option only becomes active when logging is True error_logging: false # this option only becomes active is False @@ -50,11 +51,11 @@ update_logging: false - `enabled` turns on the plugin for the whole site. If `false`, then making it active on a page will have no effect. - `database_route` is the Grav route (relative to the 'user' subdirectory) to the location of the `SQLite3` database. - `database_name` is the full name (typically with the extension .sqlite3) of the database file. It is the responsibility of the site developer/maintainer to create the database. +- `extra_security` enables a more paranoid setting. When `true`, a page may only contain an [sql-table] shortcode if the page header explicitly allows for on. (See below for onpage configuration when option is enabled.) - `logging` when false, nothing extra happens. When `true`, SQL related data is logged to a file called `sqlite.txt` in the directory given by `database_route`. If however there is an error in setting `database_route`, then the directory is `user/data/sqlite`. ->SUGGESTION: If the DataManager plugin is installed and the default route is retained, then the SQL logs can be viewed -from the Admin panel. +>SUGGESTION: If the DataManager plugin is installed and the default route is retained, then the SQL logs can be viewed from the Admin panel. - `all_logging` only become active when `logging` is enabled. If true, then all stanzas and errors are recorded. - `error_logging` only becomes active when `logging` is enabled and `all_logging` is not enabled. @@ -66,11 +67,15 @@ from the Admin panel. `logging` should not be used in production settings as it writes to the hard drive, slowing performance. ### Per page configuration -Shortcodes can be enabled separately using the `shortcode-core` configuration. To disable shortcodes being used on all pages, but only used on selected pages, configure the shortcode-core plugin inside the Admin panel with `enabled=true` and `active=false`. Then on each page where shortcodes are used, include in the front section of the page: +* Shortcodes can be enabled separately using the `shortcode-core` configuration. To disable shortcodes being used on all pages, but only used on selected pages, configure the shortcode-core plugin inside the Admin panel with `enabled=true` and `active=false`. Then on each page where shortcodes are used, include in the front section of the page: ```yaml shortcode-core: active: true ``` +* When `extra_security` is enabled, then on a page in which the `[sql-table]` shortcode may be used, the page header must contain +```yaml +sqliteSelect: allow +``` ## Usage A shortcode and a Form action are provided. @@ -86,12 +91,13 @@ this happens, then set `error_logging` to **true** whilst debugging. ### [sql-table] Shortcode -In the page content the shortcode is used as: +In the page content the shortcode is used as follows: ```md [sql-table]SELECT stanza[/sql-table] ``` -The plugin then generates an html table with the headers as returned by the select stanza, and the body containing the row data. +If `extra_security` is not enabled, or `extra_security` is enabled ** AND ** the page header contains the field `sqliteSelect: allow`, then +the plugin then generates an html table (or json, see below) with the headers as returned by the select stanza, and the body containing the row data. (In the remainder of this documentation, it is assumed that `extra_security` is **NOT** enabled.) The SELECT stanza can be complex referring to multiple tables in the database. An SQLite3 query will return a table of rows with the same number of elements, which will fit into a simple HTML table. @@ -366,5 +372,7 @@ For example, using the `Login` plugin, only users with certain privileges or bel Alternatively, using the `Private` plugin, a password can be created for the page. +Some plugins allow for authorised users to modify content in the frontend. This would allow a user to add an `[sql-table]` within the markdown content of a page, and thus to access data on a website database. In order to allow a website designer to protect against such an accidental or malicious intrusion, the `extra_security` option is provided in the `sqlite` plugin configuration. It is `false` by default, to allow for backward compatibility. (See above for more information about usage.) + ## To Do - Internationalise. Add more languages to `langages.yaml` diff --git a/blueprints.yaml b/blueprints.yaml index 0aadb8a..6e5c83f 100644 --- a/blueprints.yaml +++ b/blueprints.yaml @@ -1,5 +1,5 @@ name: Sqlite -version: '1.4.0' +version: '1.5.0' description: Plugin to select, update and insert into an sqlite3 database icon: database author: @@ -26,6 +26,17 @@ form: default: data label: PLUGIN_SQLITE.DATABASE_ROUTE help: PLUGIN_SQLITE.DATABASE_ROUTE_HELP + extra_security: + type: toggle + default: 0 + highlight: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + label: PLUGIN_SQLITE.EXTRA_SECURITY + help: PLUGIN_SQLITE.EXTRA_SECURITY_HELP logging: type: toggle highlight: 0 diff --git a/languages.yaml b/languages.yaml index e7908e5..9938f1c 100644 --- a/languages.yaml +++ b/languages.yaml @@ -28,3 +28,5 @@ en: INSERT_LOGGING_HELP: Log file is appended when an INSERT stanza is sent to database. UPDATE_LOGGING: Turn on Update Logging. UPDATE_LOGGING_HELP: Log file is appended when an UPDATE stanza is sent to database. + EXTRA_SECURITY: Enable more paranoid security + EXTRA_SECURITY_HELP: Require explicit permission in header of page where SQL table shortcode is used diff --git a/shortcodes/SqlTableShortcode.php b/shortcodes/SqlTableShortcode.php index 986364d..6660219 100644 --- a/shortcodes/SqlTableShortcode.php +++ b/shortcodes/SqlTableShortcode.php @@ -10,14 +10,15 @@ class SqlTableShortcode extends Shortcode const SELECT = 4; public function init() { - $this->shortcode->getHandlers()->add('sql-table', function(ShortcodeInterface $sc) { + $tagName = $this->grav['sqlite']['extraSecurity'] ? 'sqlSEC-table' : 'sql-table'; + $this->shortcode->getHandlers()->add($tagName, function(ShortcodeInterface $sc) { if ( isset($this->grav['sqlite']['error']) && $this->grav['sqlite']['error'] ) { $this->log($this->grav['sqlite']['error']); return $this->twig->processTemplate( 'partials/sql-db-error.html.twig', - [ 'message' => $this->grav['sqlite']['error'] - ]); + [ 'message' => $this->grav['sqlite']['error'] ] + ); } // database exists $s = $sc->getContent(); @@ -90,7 +91,7 @@ public function log($type, $msg) { $datafh->save($datafh->content() . '
' . date('Y-m-d:H:i') . ': ' . $msg); } else { $datafh->save('' . date('Y-m-d:H:i') . ': ' . $msg); - chmod($path, 0666); + chmod($path, 0664); } } } diff --git a/sqlite.php b/sqlite.php index 2e9c8e0..c3fe290 100644 --- a/sqlite.php +++ b/sqlite.php @@ -41,6 +41,7 @@ public function onPluginsInitialized() + $this->config->get('plugins.sqlite.update_logging') * self::UPDATE ) ); + $this->sqlite['extraSecurity'] = $this->config->get('plugins.sqlite.extra_security'); $dbloc = $path . DS . $dbname; if ( file_exists($dbloc) ) { $this->sqlite['db'] = new SQLite3($dbloc); @@ -52,21 +53,27 @@ public function onPluginsInitialized() $this->enable([ 'onShortcodeHandlers' => ['onShortcodeHandlers', 0], 'onTwigTemplatePaths' => ['onTwigTemplatePaths',0], - 'onFormProcessed' => ['onFormProcessed', 0] + 'onFormProcessed' => ['onFormProcessed', 0], + 'onPageContentRaw' => ['onPageContentRaw', 0] ]); } - public function onTwigTemplatePaths() - { - $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; - } - /** - * Initialize configuration - * @param Event $e - */ - public function onShortcodeHandlers(Event $e) - { - $this->grav['shortcode']->registerAllShortcodes(__DIR__.'/shortcodes'); + public function onPageContentRaw() { + // Not called if page cached. + // Don't proceed if we are in the admin plugin + if ($this->isAdmin()) { + $this->active = false; + return; + } + if ( ! $this->sqlite['extraSecurity'] ) return; // only continue if extraSecurity is enabled + $page = $this->grav['page']; + // is there explicit permission for this page? + if ( $page->header()->{'sqliteSelect'} !== 'allow' ) return; + // extra security is on, so change every occurence of '[sql' to '[sql-sec' + $raw = $page->getRawContent(); + $processed = str_replace( [ '[sql' , '[/sql' ], [ '[sqlSEC' , '[/sqlSEC' ], $raw ); + $page->setRawContent( $processed ); + return; } public function onFormProcessed(Event $event) @@ -177,6 +184,20 @@ public function onFormProcessed(Event $event) } } + public function onTwigTemplatePaths() + { + $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; + } + + /** + * Initialize configuration + * @param Event $e + */ + public function onShortcodeHandlers(Event $e) + { + $this->grav['shortcode']->registerAllShortcodes(__DIR__.'/shortcodes'); + } + public function log($type, $msg) { $log_val =$this->grav['sqlite']['logging']; if ( $log_val == 0 ) return; @@ -191,7 +212,7 @@ public function log($type, $msg) { $datafh->save($datafh->content() . '
' . date('Y-m-d:H:i') . ': ' . $msg); } else { $datafh->save('' . date('Y-m-d:H:i') . ': ' . $msg); - chmod($path, 0666); + chmod($path, 0664); } } } diff --git a/sqlite.yaml b/sqlite.yaml index e7a1020..d993e5e 100644 --- a/sqlite.yaml +++ b/sqlite.yaml @@ -1,6 +1,7 @@ enabled: true database_route: data/sqlite database_name: db.sqlite3 +extra_security: false logging: false error_logging: false select_logging: false