diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 3af433d8336f1..2ee7ddb5a203b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -58,3 +58,8 @@ travis-phpunit.xml @mbabker @rdeutz
# Core JS
media/*/js/* @dgt41
+
+# CSP Tooling
+plugins/system/httpheaders/* @zero-24
+administrator/components/com_csp/* @zero-24
+components/com_csp/* @zero-24
diff --git a/administrator/components/com_admin/script.php b/administrator/components/com_admin/script.php
index 5931dd323e5be..511948a680007 100644
--- a/administrator/components/com_admin/script.php
+++ b/administrator/components/com_admin/script.php
@@ -3974,6 +3974,7 @@ public function updateAssets($installer)
{
// List all components added since 4.0
$newComponents = array(
+ 'com_csp',
);
foreach ($newComponents as $component)
diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-06-03.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-06-03.sql
new file mode 100644
index 0000000000000..94acc76b4bce5
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-06-03.sql
@@ -0,0 +1,17 @@
+--
+-- Table structure for table `#__csp`
+--
+
+CREATE TABLE IF NOT EXISTS `#__csp` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `document_uri` varchar(500) NOT NULL DEFAULT '',
+ `blocked_uri` varchar(500) NOT NULL DEFAULT '',
+ `directive` varchar(500) NOT NULL DEFAULT '',
+ `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `published` tinyint(1) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
+
+INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`, `namespace`) VALUES
+(35, 'com_csp', 'component', 'com_csp', '', 0, 0, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0, 'Joomla\\Component\\Csp');
\ No newline at end of file
diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-06-03.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-06-03.sql
new file mode 100644
index 0000000000000..a3911f1e730de
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-06-03.sql
@@ -0,0 +1,17 @@
+--
+-- Table structure for table `#__csp`
+--
+
+CREATE TABLE IF NOT EXISTS "#__csp" (
+ "id" int(11) NOT NULL AUTO_INCREMENT,
+ "document_uri" varchar(500) NOT NULL DEFAULT '',
+ "blocked_uri" varchar(500) NOT NULL DEFAULT '',
+ "directive" varchar(500) NOT NULL DEFAULT '',
+ "created" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL,
+ "modified" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL,
+ "published" smallint DEFAULT 0 NOT NULL,
+ PRIMARY KEY ("id")
+);
+
+INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state", "namespace") VALUES
+(35, 'com_csp', 'component', 'com_csp', ' ', 0, 0, 1, 0, '', '{}', '', '', 0, '1970-01-01 00:00:00', 0, 0, 'Joomla\\Component\\Csp');
\ No newline at end of file
diff --git a/administrator/components/com_csp/Controller/DisplayController.php b/administrator/components/com_csp/Controller/DisplayController.php
new file mode 100644
index 0000000000000..c734a37d1de6f
--- /dev/null
+++ b/administrator/components/com_csp/Controller/DisplayController.php
@@ -0,0 +1,61 @@
+app->enqueueMessage(\JText::sprintf('COM_CSP_PLUGIN_MODAL_DISABLED', $link), 'error');
+ }
+
+ parent::display();
+ }
+}
diff --git a/administrator/components/com_csp/Controller/ReportsController.php b/administrator/components/com_csp/Controller/ReportsController.php
new file mode 100644
index 0000000000000..88cb384b58f26
--- /dev/null
+++ b/administrator/components/com_csp/Controller/ReportsController.php
@@ -0,0 +1,37 @@
+ true))
+ {
+ return parent::getModel($name, $prefix, $config);
+ }
+}
diff --git a/administrator/components/com_csp/Helper/ReporterHelper.php b/administrator/components/com_csp/Helper/ReporterHelper.php
new file mode 100644
index 0000000000000..df0eacf9da980
--- /dev/null
+++ b/administrator/components/com_csp/Helper/ReporterHelper.php
@@ -0,0 +1,50 @@
+getQuery(true)
+ ->select($db->quoteName('extension_id'))
+ ->from($db->quoteName('#__extensions'))
+ ->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
+ ->where($db->quoteName('element') . ' = ' . $db->quote('httpheaders'));
+ $db->setQuery($query);
+
+ try
+ {
+ $result = (int) $db->loadResult();
+ }
+ catch (\RuntimeException $e)
+ {
+ Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
+ }
+
+ return $result;
+ }
+}
diff --git a/administrator/components/com_csp/Model/ReportModel.php b/administrator/components/com_csp/Model/ReportModel.php
new file mode 100644
index 0000000000000..98598a21d851a
--- /dev/null
+++ b/administrator/components/com_csp/Model/ReportModel.php
@@ -0,0 +1,44 @@
+getState('filter.search');
+ $id .= ':' . $this->getState('filter.published');
+
+ return parent::getStoreId($id);
+ }
+
+ /**
+ * Method to create a query for a list of items.
+ *
+ * @return string
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function getListQuery()
+ {
+ $db = $this->getDbo();
+ $query = $db->getQuery(true);
+
+ // Select the required fields from the table.
+ $query
+ ->select('*')
+ ->from('#__csp AS a');
+
+ // Filter by published state
+ $published = (string) $this->getState('filter.published');
+
+ if (is_numeric($published))
+ {
+ $query->where('a.published = ' . (int) $published);
+ }
+ elseif ($published === '')
+ {
+ $query->where('(a.published IN (0, 1))');
+ }
+
+ // Filter by search in title
+ $search = $this->getState('filter.search');
+
+ if (!empty($search))
+ {
+ if (stripos($search, 'id:') === 0)
+ {
+ $query->where('a.id = ' . (int) substr($search, 3));
+ }
+ else
+ {
+ $search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'));
+ $query->where('(a.document_uri LIKE ' . $search . ' OR a.blocked_uri LIKE ' . $search . ' OR a.directive LIKE ' . $search . ')');
+ }
+ }
+
+ // Add the list ordering clause
+ $listOrdering = $this->getState('list.ordering', 'a.id');
+ $listDirn = $db->escape($this->getState('list.direction', 'ASC'));
+
+ $query->order($db->escape($listOrdering) . ' ' . $listDirn);
+
+ return $query;
+ }
+}
diff --git a/administrator/components/com_csp/Table/ReportTable.php b/administrator/components/com_csp/Table/ReportTable.php
new file mode 100644
index 0000000000000..97562a5f2101a
--- /dev/null
+++ b/administrator/components/com_csp/Table/ReportTable.php
@@ -0,0 +1,33 @@
+items = $this->get('Items');
+ $this->pagination = $this->get('Pagination');
+ $this->state = $this->get('State');
+ $this->activeFilters = $this->get('ActiveFilters');
+ $this->filterForm = $this->get('FilterForm');
+
+ // Check for errors.
+ if (count($errors = $this->get('Errors')))
+ {
+ throw new \JViewGenericdataexception(implode("\n", $errors), 500);
+ }
+
+ if (!(PluginHelper::isEnabled('system', 'httpheaders')))
+ {
+ $this->httpHeadersId = ReporterHelper::getHttpHeadersPluginId();
+ }
+
+ $this->addToolbar();
+
+ parent::display($tpl);
+ }
+
+ /**
+ * Add the page title and toolbar.
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function addToolbar()
+ {
+ $canDo = ContentHelper::getActions('com_csp');
+
+ ToolbarHelper::title(\JText::_('COM_CSP_REPORTS'), 'generic');
+
+ if ($canDo->get('core.edit.state'))
+ {
+ ToolbarHelper::publish('reports.publish', 'JTOOLBAR_PUBLISH', true);
+ ToolbarHelper::unpublish('reports.unpublish', 'JTOOLBAR_UNPUBLISH', true);
+ }
+
+ if ($this->state->get('filter.published') == -2 && $canDo->get('core.delete'))
+ {
+ ToolbarHelper::deleteList('JGLOBAL_CONFIRM_DELETE', 'reports.delete', 'JTOOLBAR_EMPTY_TRASH');
+ }
+ elseif ($canDo->get('core.edit.state'))
+ {
+ ToolbarHelper::trash('reports.trash');
+ }
+
+ if ($canDo->get('core.admin') || $canDo->get('core.options'))
+ {
+ ToolbarHelper::preferences('com_csp');
+ }
+
+ ToolbarHelper::help('JHELP_COMPONENTS_CSP_REPORTS');
+ }
+
+ /**
+ * Returns an array of fields the table can be sorted by
+ *
+ * @return array Array containing the field name to sort by as the key and display text as value
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function getSortFields()
+ {
+ return array(
+ 'a.state' => \JText::_('JSTATUS'),
+ 'a.blocked_uri' => \JText::_('COM_CSP_HEADING_BLOCKED_URI'),
+ 'a.document_uri' => \JText::_('COM_CSP_HEADING_DOCUMENT_URI'),
+ 'a.directive' => \JText::_('COM_CSP_HEADING_DIRECTIVE'),
+ 'a.id' => \JText::_('JGRID_HEADING_ID')
+ );
+ }
+}
diff --git a/administrator/components/com_csp/access.xml b/administrator/components/com_csp/access.xml
new file mode 100644
index 0000000000000..5582ccc729ee1
--- /dev/null
+++ b/administrator/components/com_csp/access.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/administrator/components/com_csp/config.xml b/administrator/components/com_csp/config.xml
new file mode 100644
index 0000000000000..cf1dee5c4baf4
--- /dev/null
+++ b/administrator/components/com_csp/config.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
diff --git a/administrator/components/com_csp/csp.xml b/administrator/components/com_csp/csp.xml
new file mode 100644
index 0000000000000..5303d6c009cae
--- /dev/null
+++ b/administrator/components/com_csp/csp.xml
@@ -0,0 +1,41 @@
+
+
+ com_csp
+ Joomla! Project
+ May 2018
+ (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ __DEPLOY_VERSION__
+ COM_CSP_XML_DESCRIPTION
+ Joomla\Component\Csp
+
+ dispatcher.php
+ router.php
+ Controller
+ Helper
+ helpers
+ Model
+
+
+
+
+ access.xml
+ csp.php
+ dispatcher.php
+ Controller
+ Helper
+ helpers
+ Model
+ models
+ Table
+ View
+ views
+
+
+ language/en-GB.com_csp.ini
+ language/en-GB.com_csp.sys.ini
+
+
+
diff --git a/administrator/components/com_csp/forms/filter_reports.xml b/administrator/components/com_csp/forms/filter_reports.xml
new file mode 100644
index 0000000000000..f551a6d146dde
--- /dev/null
+++ b/administrator/components/com_csp/forms/filter_reports.xml
@@ -0,0 +1,51 @@
+
+
diff --git a/administrator/components/com_csp/services/provider.php b/administrator/components/com_csp/services/provider.php
new file mode 100644
index 0000000000000..b0770f43a8144
--- /dev/null
+++ b/administrator/components/com_csp/services/provider.php
@@ -0,0 +1,52 @@
+registerServiceProvider(new MVCFactoryFactory('\\Joomla\\Component\\Csp'));
+ $container->registerServiceProvider(new DispatcherFactory('\\Joomla\\Component\\Csp'));
+ $container->set(
+ ComponentInterface::class,
+ function (Container $container)
+ {
+ $component = new MVCComponent($container->get(DispatcherFactoryInterface::class));
+ $component->setMvcFactoryFactory($container->get(MVCFactoryFactoryInterface::class));
+
+ return $component;
+ }
+ );
+ }
+};
\ No newline at end of file
diff --git a/administrator/components/com_csp/tmpl/reports/default.php b/administrator/components/com_csp/tmpl/reports/default.php
new file mode 100644
index 0000000000000..31fa83d857327
--- /dev/null
+++ b/administrator/components/com_csp/tmpl/reports/default.php
@@ -0,0 +1,126 @@
+get('id');
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+$saveOrder = $listOrder == 'a.id';
+
+?>
+
diff --git a/administrator/language/en-GB/en-GB.com_csp.ini b/administrator/language/en-GB/en-GB.com_csp.ini
new file mode 100644
index 0000000000000..2558cac6768ac
--- /dev/null
+++ b/administrator/language/en-GB/en-GB.com_csp.ini
@@ -0,0 +1,36 @@
+; Joomla! Project
+; Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
+; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
+; Note : All ini files need to be saved as UTF-8
+
+COM_CSP="Content Security Policy"
+COM_CSP_CONFIG_ENABLE_REPORTER_LABEL="Enable Frontend Reporter"
+COM_CSP_CONFIG_ENABLE_REPORTER_DESC="Report and save any issues for review."
+COM_CSP_CONFIGURATION="Content Security Policy: Options"
+COM_CSP_EDIT_PLUGIN_SETTINGS="Edit Plugin Settings"
+COM_CSP_FIELDSET_CONFIG_REPORTER_OPTIONS_LABEL="CSP Reporter Options"
+COM_CSP_FILTER_SEARCH_DESC="Search in the table fields. Prefix with ID: to search by ID."
+COM_CSP_FILTER_SEARCH_LABEL="Search CSP Reports"
+COM_CSP_HEADING_DOCUMENT_URI="URL"
+COM_CSP_HEADING_BLOCKED_URI="Blocked Element"
+COM_CSP_HEADING_DIRECTIVE="Directive"
+COM_CSP_HEADING_CREATED="Created"
+COM_CSP_HEADING_BLOCKED_URI_ASC="Blocked element ascending"
+COM_CSP_HEADING_BLOCKED_URI_DESC="Blocked element descending"
+COM_CSP_HEADING_CREATED_ASC="Created ascending"
+COM_CSP_HEADING_CREATED_DESC="Created descending"
+COM_CSP_HEADING_DIRECTIVE_ASC="Directive ascending"
+COM_CSP_HEADING_DIRECTIVE_DESC="Directive descending"
+COM_CSP_HEADING_DOCUMENT_URI_ASC="URL ascending"
+COM_CSP_HEADING_DOCUMENT_URI_DESC="URL descending"
+COM_CSP_N_ITEMS_DELETED="%d reports deleted."
+COM_CSP_N_ITEMS_DELETED_1="%d report deleted."
+COM_CSP_N_ITEMS_PUBLISHED="%d reports published."
+COM_CSP_N_ITEMS_PUBLISHED_1="%d report published."
+COM_CSP_N_ITEMS_TRASHED="%d reports trashed."
+COM_CSP_N_ITEMS_TRASHED_1="%d report trashed."
+COM_CSP_N_ITEMS_UNPUBLISHED="%d reports unpublished."
+COM_CSP_N_ITEMS_UNPUBLISHED_1="%d report unpublished."
+COM_CSP_PLUGIN_MODAL_DISABLED="The %s is disabled. It needs to be enabled for this component to work."
+COM_CSP_REPORTS="CSP Reports"
+COM_CSP_SYSTEM_PLUGIN="HTTP Headers System Plugin"
\ No newline at end of file
diff --git a/administrator/language/en-GB/en-GB.com_csp.sys.ini b/administrator/language/en-GB/en-GB.com_csp.sys.ini
new file mode 100644
index 0000000000000..a65a70547ec31
--- /dev/null
+++ b/administrator/language/en-GB/en-GB.com_csp.sys.ini
@@ -0,0 +1,7 @@
+; Joomla! Project
+; Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
+; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
+; Note : All ini files need to be saved as UTF-8
+
+COM_CSP="Content Security Policy"
+COM_CSP_XML_DESCRIPTION="This component manages the Content Security Policy (CSP) reports."
diff --git a/administrator/language/en-GB/en-GB.ini b/administrator/language/en-GB/en-GB.ini
index e11894202736b..d0247612d53aa 100644
--- a/administrator/language/en-GB/en-GB.ini
+++ b/administrator/language/en-GB/en-GB.ini
@@ -679,6 +679,7 @@ JHELP_COMPONENTS_CONTACTS_CONTACTS="Components_Contacts_Contacts"
JHELP_COMPONENTS_CONTENT_CATEGORIES="Components_Content_Categories"
JHELP_COMPONENTS_CONTENT_CATEGORY_ADD="Components_Content_Categories_Edit"
JHELP_COMPONENTS_CONTENT_CATEGORY_EDIT="Components_Content_Categories_Edit"
+JHELP_COMPONENTS_CSP_REPORTS="Components_Csp_Reports"
JHELP_COMPONENTS_FIELDS_FIELDS="Components_Fields_Fields"
JHELP_COMPONENTS_FIELDS_FIELDS_EDIT="Components_Fields_Fields_Edit"
JHELP_COMPONENTS_FIELDS_FIELD_GROUPS="Components_Fields_Field_Groups"
diff --git a/components/com_csp/Controller/ReportController.php b/components/com_csp/Controller/ReportController.php
new file mode 100644
index 0000000000000..bf086a6f3c01b
--- /dev/null
+++ b/components/com_csp/Controller/ReportController.php
@@ -0,0 +1,113 @@
+app->getParams();
+
+ if (!$params->get('enable_reporter'))
+ {
+ $this->app->close();
+ }
+
+ $data = $this->input->json->get('csp-report', array(), 'Array');
+
+ if (empty($data))
+ {
+ $this->app->close();
+ }
+
+ $report = new \stdClass;
+ $report->document_uri = $data['document-uri'];
+ $report->blocked_uri = $data['blocked-uri'];
+
+ if (filter_var($report->blocked_uri, FILTER_VALIDATE_URL) !== false)
+ {
+ $report->blocked_uri = parse_url($report->blocked_uri, PHP_URL_HOST);
+ }
+
+ $report->directive = $data['violated-directive'];
+
+ if (empty($data['violated-directive']) && !empty($data['effective-directive']))
+ {
+ $report->directive = $data['effective-directive'];
+ }
+
+ // Empty report
+ if (empty($report->blocked_uri) && empty($report->directive))
+ {
+ $this->app->close();
+ }
+
+ $now = Factory::getDate()->toSql();
+
+ $report->created = $now;
+ $report->modified = $now;
+
+ if ($this->isEntryExisting($report))
+ {
+ $this->app->close();
+ }
+
+ $table = new ReportTable(Factory::getDbo());
+
+ $table->bind($report);
+ $table->store();
+
+ $this->app->close();
+ }
+
+ /**
+ * Check if we already logged this entry
+ *
+ * @param object $report The generated report row
+ *
+ * @return boolean
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ private function isEntryExisting($report)
+ {
+ $db = Factory::getDbo();
+
+ $query = $db->getQuery(true);
+
+ $query
+ ->select('count(*)')
+ ->from('#__csp')
+ ->where($db->quoteName('blocked_uri') . '=' . $db->quote($report->blocked_uri))
+ ->where($db->quoteName('directive') . '=' . $db->quote($report->directive));
+
+ $db->setQuery($query);
+
+ return $db->loadResult() > 0;
+ }
+}
diff --git a/installation/sql/mysql/joomla.sql b/installation/sql/mysql/joomla.sql
index 2bac80ad736aa..610dd04bd8f52 100644
--- a/installation/sql/mysql/joomla.sql
+++ b/installation/sql/mysql/joomla.sql
@@ -453,6 +453,23 @@ CREATE TABLE IF NOT EXISTS `#__core_log_searches` (
-- --------------------------------------------------------
+--
+-- Table structure for table `#__csp`
+--
+
+CREATE TABLE IF NOT EXISTS `#__csp` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `document_uri` varchar(500) NOT NULL DEFAULT '',
+ `blocked_uri` varchar(500) NOT NULL DEFAULT '',
+ `directive` varchar(500) NOT NULL DEFAULT '',
+ `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `published` tinyint(1) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
+
+-- --------------------------------------------------------
+
--
-- Table structure for table `#__extensions`
--
@@ -518,6 +535,7 @@ INSERT INTO `#__extensions` (`extension_id`, `package_id`, `name`, `type`, `elem
(32, 0, 'com_postinstall', 'component', 'com_postinstall', '', 1, 1, 1, 1, '', '', 0, '0000-00-00 00:00:00', 0, 0, 'Joomla\\Component\\Postinstall'),
(33, 0, 'com_fields', 'component', 'com_fields', '', 1, 1, 1, 0, '', '', 0, '0000-00-00 00:00:00', 0, 0, 'Joomla\\Component\\Fields'),
(34, 0, 'com_associations', 'component', 'com_associations', '', 1, 1, 1, 0, '', '', 0, '0000-00-00 00:00:00', 0, 0, 'Joomla\\Component\\Associations'),
+(35, 0, 'com_csp', 'component', 'com_csp', '', 1, 1, 1, 0, '', '', 0, '0000-00-00 00:00:00', 0, 0, 'Joomla\\Component\\Csp'),
(103, 0, 'Joomla! Platform', 'library', 'joomla', '', 0, 1, 1, 1, '', '', 0, '0000-00-00 00:00:00', 0, 0, ''),
(106, 0, 'PHPass', 'library', 'phpass', '', 0, 1, 1, 1, '', '', 0, '0000-00-00 00:00:00', 0, 0, ''),
(200, 0, 'mod_articles_archive', 'module', 'mod_articles_archive', '', 0, 1, 1, 0, '', '', 0, '0000-00-00 00:00:00', 0, 0, ''),
@@ -1172,6 +1190,7 @@ INSERT INTO `#__menu` (`id`, `menutype`, `title`, `alias`, `note`, `path`, `link
(20, 'main', 'com_tags', 'Tags', '', 'Tags', 'index.php?option=com_tags', 'component', 1, 1, 1, 29, 0, '0000-00-00 00:00:00', 0, 1, 'class:tags', 0, '', 35, 36, 0, '', 1),
(21, 'main', 'com_postinstall', 'Post-installation messages', '', 'Post-installation messages', 'index.php?option=com_postinstall', 'component', 1, 1, 1, 32, 0, '0000-00-00 00:00:00', 0, 1, 'class:postinstall', 0, '', 37, 38, 0, '*', 1),
(22, 'main', 'com_associations', 'Multilingual Associations', '', 'Multilingual Associations', 'index.php?option=com_associations', 'component', 1, 1, 1, 34, 0, '0000-00-00 00:00:00', 0, 0, 'class:associations', 0, '', 39, 40, 0, '*', 1),
+(23, 'main', 'com_csp', 'Content-Security-Policy', '', 'Content-Security-Policy', 'index.php?option=com_csp', 'component', 1, 1, 1, 35, 0, '0000-00-00 00:00:00', 0, 0, 'class:associations', 0, '', 41, 42, 0, '*', 1),
(101, 'mainmenu', 'Home', 'home', '', 'home', 'index.php?option=com_content&view=featured', 'component', 1, 1, 1, 22, 0, '0000-00-00 00:00:00', 0, 1, '', 0, '{"featured_categories":[""],"layout_type":"blog","num_leading_articles":"1","num_intro_articles":"3","num_columns":"3","num_links":"0","multi_column_order":"1","orderby_pri":"","orderby_sec":"front","order_date":"","show_pagination":"2","show_pagination_results":"1","show_title":"","link_titles":"","show_intro":"","info_block_position":"","show_category":"","link_category":"","show_parent_category":"","link_parent_category":"","show_author":"","link_author":"","show_create_date":"","show_modify_date":"","show_publish_date":"","show_item_navigation":"","show_vote":"","show_readmore":"","show_readmore_title":"","show_icons":"","show_print_icon":"","show_email_icon":"","show_hits":"","show_noauth":"","show_feed_link":"1","feed_summary":"","menu-anchor_title":"","menu-anchor_css":"","menu_image":"","menu_text":1,"page_title":"","show_page_heading":1,"page_heading":"","pageclass_sfx":"","menu-meta_description":"","menu-meta_keywords":"","robots":"","secure":0}', 41, 42, 1, '*', 0);
-- --------------------------------------------------------
diff --git a/installation/sql/postgresql/joomla.sql b/installation/sql/postgresql/joomla.sql
index d49d12f5fa1ad..a21bae509ae57 100644
--- a/installation/sql/postgresql/joomla.sql
+++ b/installation/sql/postgresql/joomla.sql
@@ -465,6 +465,24 @@ CREATE TABLE IF NOT EXISTS "#__core_log_searches" (
"hits" bigint DEFAULT 0 NOT NULL
);
+--
+-- Table structure for table `#__csp`
+--
+
+CREATE TABLE IF NOT EXISTS "#__csp" (
+ "id" int(11) NOT NULL AUTO_INCREMENT,
+ "document_uri" varchar(500) NOT NULL DEFAULT '',
+ "blocked_uri" varchar(500) NOT NULL DEFAULT '',
+ "directive" varchar(500) NOT NULL DEFAULT '',
+ "created" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL,
+ "modified" timestamp without time zone DEFAULT '1970-01-01 00:00:00' NOT NULL,
+ "published" smallint DEFAULT 0 NOT NULL,
+ PRIMARY KEY ("id")
+);
+
+-- --------------------------------------------------------
+
+
--
-- Table structure for table `#__extensions`
--
@@ -528,6 +546,7 @@ INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "elem
(32, 0, 'com_postinstall', 'component', 'com_postinstall', '', 1, 1, 1, 1, '', '', 0, '1970-01-01 00:00:00', 0, 0, ''),
(33, 0, 'com_fields', 'component', 'com_fields', '', 1, 1, 1, 0, '', '', 0, '1970-01-01 00:00:00', 0, 0, ''),
(34, 0, 'com_associations', 'component', 'com_associations', '', 1, 1, 1, 0, '', '', 0, '1970-01-01 00:00:00', 0, 0, ''),
+(35, 0, 'com_csp', 'component', 'com_csp', '', 1, 1, 1, 0, '', '', 0, '1970-01-01 00:00:00', 0, 0, 'Joomla\\Component\\Csp'),
(102, 0, 'phputf8', 'library', 'phputf8', '', 0, 1, 1, 1, '', '', 0, '1970-01-01 00:00:00', 0, 0, ''),
(103, 0, 'Joomla! Platform', 'library', 'joomla', '', 0, 1, 1, 1, '', '', 0, '1970-01-01 00:00:00', 0, 0, ''),
(106, 0, 'PHPass', 'library', 'phpass', '', 0, 1, 1, 1, '', '', 0, '1970-01-01 00:00:00', 0, 0, ''),
@@ -1180,6 +1199,7 @@ INSERT INTO "#__menu" ("id", "menutype", "title", "alias", "note", "path", "link
(20, 'main', 'com_tags', 'Tags', '', 'Tags', 'index.php?option=com_tags', 'component', 1, 1, 1, 29, 0, '1970-01-01 00:00:00', 0, 1, 'class:tags', 0, '', 35, 36, 0, '', 1),
(21, 'main', 'com_postinstall', 'Post-installation messages', '', 'Post-installation messages', 'index.php?option=com_postinstall', 'component', 1, 1, 1, 32, 0, '1970-01-01 00:00:00', 0, 1, 'class:postinstall', 0, '', 37, 38, 0, '*', 1),
(22, 'main', 'com_associations', 'Multilingual Associations', '', 'Multilingual Associations', 'index.php?option=com_associations', 'component', 1, 1, 1, 34, 0, '1970-01-01 00:00:00', 0, 0, 'class:associations', 0, '', 39, 40, 0, '*', 1),
+(23, 'main', 'com_csp', 'Content-Security-Policy', '', 'Content-Security-Policy', 'index.php?option=com_csp', 'component', 1, 1, 1, 35, 0, '1970-01-01 00:00:00', 0, 0, 'class:associations', 0, '', 41, 42, 0, '*', 1),
(101, 'mainmenu', 'Home', 'home', '', 'home', 'index.php?option=com_content&view=featured', 'component', 1, 1, 1, 22, 0, '1970-01-01 00:00:00', 0, 1, '', 0, '{"featured_categories":[""],"layout_type":"blog","num_leading_articles":"1","num_intro_articles":"3","num_columns":"3","num_links":"0","multi_column_order":"1","orderby_pri":"","orderby_sec":"front","order_date":"","show_pagination":"2","show_pagination_results":"1","show_title":"","link_titles":"","show_intro":"","info_block_position":"","show_category":"","link_category":"","show_parent_category":"","link_parent_category":"","show_author":"","link_author":"","show_create_date":"","show_modify_date":"","show_publish_date":"","show_item_navigation":"","show_vote":"","show_readmore":"","show_readmore_title":"","show_icons":"","show_print_icon":"","show_email_icon":"","show_hits":"","show_noauth":"","show_feed_link":"1","feed_summary":"","menu-anchor_title":"","menu-anchor_css":"","menu_image":"","menu_text":1,"page_title":"","show_page_heading":1,"page_heading":"","pageclass_sfx":"","menu-meta_description":"","menu-meta_keywords":"","robots":"","secure":0}', 41, 42, 1, '*', 0);
SELECT setval('#__menu_id_seq', 102, false);
diff --git a/libraries/src/Extension/ExtensionHelper.php b/libraries/src/Extension/ExtensionHelper.php
index d09580210e57b..53e6214cf38f6 100644
--- a/libraries/src/Extension/ExtensionHelper.php
+++ b/libraries/src/Extension/ExtensionHelper.php
@@ -43,6 +43,7 @@ class ExtensionHelper
array('component', 'com_content', '', 1),
array('component', 'com_contenthistory', '', 1),
array('component', 'com_cpanel', '', 1),
+ array('component', 'com_csp', '', 1),
array('component', 'com_fields', '', 1),
array('component', 'com_finder', '', 1),
array('component', 'com_installer', '', 1),