FEATURE: whitelist theme repo mode (experimental)

In some restricted setups all JS payloads need tight control.

This setting bans admins from making changes to JS on the site and
requires all themes be whitelisted to be used.

There are edge cases we still need to work through in this mode
hence this is still not supported in production and experimental.

Use an example like this to enable:

`DISCOURSE_WHITELISTED_THEME_REPOS="https://repo.com/repo.git,https://repo.com/repo2.git"`

By default this feature is not enabled and no changes are made.

One exception is that default theme id was missing a security check
this was added for correctness.
This commit is contained in:
Sam Saffron
2020-06-03 13:19:42 +10:00
parent 062db10c52
commit 57a3d4e0d2
8 changed files with 186 additions and 6 deletions

View File

@@ -14,6 +14,9 @@ class Admin::ThemesController < Admin::AdminController
end
def upload_asset
ban_in_whitelist_mode!
path = params[:file].path
hijack do
@@ -49,6 +52,9 @@ class Admin::ThemesController < Admin::AdminController
def import
@theme = nil
if params[:theme] && params[:theme].content_type == "application/json"
ban_in_whitelist_mode!
# .dcstyle.json import. Deprecated, but still available to allow conversion
json = JSON::parse(params[:theme].read)
theme = json['theme']
@@ -85,15 +91,21 @@ class Admin::ThemesController < Admin::AdminController
else
render json: @theme.errors, status: :unprocessable_entity
end
elsif params[:remote]
elsif remote = params[:remote]
guardian.ensure_allowed_theme_repo_import!(remote.strip)
begin
branch = params[:branch] ? params[:branch] : nil
@theme = RemoteTheme.import_theme(params[:remote], theme_user, private_key: params[:private_key], branch: branch)
@theme = RemoteTheme.import_theme(remote, theme_user, private_key: params[:private_key], branch: branch)
render json: @theme, status: :created
rescue RemoteTheme::ImportError => e
render_json_error e.message
end
elsif params[:bundle] || (params[:theme] && THEME_CONTENT_TYPES.include?(params[:theme].content_type))
ban_in_whitelist_mode!
# params[:bundle] used by theme CLI. params[:theme] used by admin UI
bundle = params[:bundle] || params[:theme]
theme_id = params[:theme_id]
@@ -139,6 +151,9 @@ class Admin::ThemesController < Admin::AdminController
end
def create
ban_in_whitelist_mode!
@theme = Theme.new(name: theme_params[:name],
user_id: theme_user.id,
user_selectable: theme_params[:user_selectable] || false,
@@ -282,6 +297,10 @@ class Admin::ThemesController < Admin::AdminController
private
def ban_in_whitelist_mode!
raise Discourse::InvalidAccess if !GlobalSetting.whitelisted_theme_ids.nil?
end
def add_relative_themes!(kind, ids)
expected = ids.map(&:to_i)
@@ -339,6 +358,8 @@ class Admin::ThemesController < Admin::AdminController
def set_fields
return unless fields = theme_params[:theme_fields]
ban_in_whitelist_mode!
fields.each do |field|
@theme.set_field(
target: field[:target],

View File

@@ -414,7 +414,9 @@ class ApplicationController < ActionController::Base
end
if theme_ids.blank? && SiteSetting.default_theme_id != -1
theme_ids << SiteSetting.default_theme_id
if guardian.allow_themes?([SiteSetting.default_theme_id])
theme_ids << SiteSetting.default_theme_id
end
end
@theme_ids = request.env[:resolved_theme_ids] = theme_ids