From 8f6be9c59257c46d1742829cd38cf7255c6eec08 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 15 Jun 2018 13:56:24 -0400 Subject: [PATCH] SECURITY: Make sure a repo exists before acting on it Also includes refactors to clean up linting / code, adds specs and changes the usage pattern to something safer --- .../docker_manager/admin_controller.rb | 73 ++++++++----------- .../admin/upgrade_required.html.erb | 21 ++++++ lib/docker_manager/git_repo.rb | 20 ++++- plugin.rb | 2 - spec/lib/git_repo_spec.rb | 23 ++++++ 5 files changed, 92 insertions(+), 47 deletions(-) create mode 100644 app/views/docker_manager/admin/upgrade_required.html.erb create mode 100644 spec/lib/git_repo_spec.rb diff --git a/app/controllers/docker_manager/admin_controller.rb b/app/controllers/docker_manager/admin_controller.rb index bee2633..68ddaeb 100644 --- a/app/controllers/docker_manager/admin_controller.rb +++ b/app/controllers/docker_manager/admin_controller.rb @@ -16,45 +16,14 @@ module DockerManager expected_ruby_version = Gem::Version.new('2.4') if (version < expected_version) || (ruby_version < expected_ruby_version) - - message = <<~HTML - -

You are running an old version of the Discourse image.

-

- Upgrades via the web UI are disabled until you run the latest image. -

-

- To do so log in to your server using SSH and run: -

- -
-        cd /var/discourse
-        git pull
-        ./launcher rebuild app
-        
-

- More info on our support site -

- - - HTML - - render html: message.html_safe + render 'upgrade_required', layout: false else render end end def repos - repos = [DockerManager::GitRepo.new(Rails.root.to_s, 'discourse')] - p = Proc.new { |p| - repos << DockerManager::GitRepo.new(File.dirname(p.path), p.name) - } - if Discourse.respond_to?(:visible_plugins) - Discourse.visible_plugins.each(&p) - else - Discourse.plugins.each(&p) - end + repos = DockerManager::GitRepo.find_all repos.map! do |r| result = { name: r.name, @@ -75,26 +44,40 @@ module DockerManager result end - render json: {repos: repos} + render json: { repos: repos } end def progress - repo = DockerManager::GitRepo.new(params[:path]) + repo = DockerManager::GitRepo.find(params[:path]) + raise Discourse::NotFound unless repo.present? + upgrader = Upgrader.new(current_user.id, repo, params[:version]) - render json: {progress: {logs: upgrader.find_logs, percentage: upgrader.last_percentage } } + render json: { + progress: { + logs: upgrader.find_logs, + percentage: upgrader.last_percentage + } + } end def latest - repo = DockerManager::GitRepo.new(params[:path]) + repo = DockerManager::GitRepo.find(params[:path]) + raise Discourse::NotFound unless repo.present? + repo.update! if Rails.env == 'production' - render json: {latest: {version: repo.latest_origin_commit, - commits_behind: repo.commits_behind, - date: repo.latest_origin_commit_date } } + render json: { + latest: { + version: repo.latest_origin_commit, + commits_behind: repo.commits_behind, + date: repo.latest_origin_commit_date + } + } end def upgrade - repo = DockerManager::GitRepo.new(params[:path]) + repo = DockerManager::GitRepo.find(params[:path]) + raise Discourse::NotFound unless repo.present? Thread.new do upgrader = Upgrader.new(current_user.id, repo, params[:version]) upgrader.upgrade @@ -103,7 +86,9 @@ module DockerManager end def reset_upgrade - repo = DockerManager::GitRepo.new(params[:path]) + repo = DockerManager::GitRepo.find(params[:path]) + raise Discourse::NotFound unless repo.present? + upgrader = Upgrader.new(current_user.id, repo, params[:version]) upgrader.reset! render plain: "OK" @@ -123,7 +108,7 @@ module DockerManager Thread.new do a = 1 while true - a += 1 + a += 1 end end render plain: "Killing CPU on #{Process.pid}" @@ -133,7 +118,7 @@ module DockerManager Thread.new do a = [] while true - a << Array.new(50_000_000/8) + a << Array.new(50_000_000 / 8) sleep 30 end end diff --git a/app/views/docker_manager/admin/upgrade_required.html.erb b/app/views/docker_manager/admin/upgrade_required.html.erb new file mode 100644 index 0000000..62bd59d --- /dev/null +++ b/app/views/docker_manager/admin/upgrade_required.html.erb @@ -0,0 +1,21 @@ + + + +

You are running an old version of the Discourse image.

+

+ Upgrades via the web UI are disabled until you run the latest image. +

+

+ To do so log in to your server using SSH and run: +

+ +
+        cd /var/discourse
+        git pull
+        ./launcher rebuild app
+    
+

+ More info on our support site +

+ + diff --git a/lib/docker_manager/git_repo.rb b/lib/docker_manager/git_repo.rb index 740707e..7611555 100644 --- a/lib/docker_manager/git_repo.rb +++ b/lib/docker_manager/git_repo.rb @@ -2,7 +2,7 @@ class DockerManager::GitRepo attr_reader :path, :name, :branch - def initialize(path, name=nil) + def initialize(path, name = nil) @path = path @name = name @memoize = {} @@ -63,6 +63,24 @@ class DockerManager::GitRepo `cd #{path} && git remote update` end + def self.find_all + repos = [DockerManager::GitRepo.new(Rails.root.to_s, 'discourse')] + p = Proc.new { |x| + repos << DockerManager::GitRepo.new(File.dirname(x.path), x.name) + } + if Discourse.respond_to?(:visible_plugins) + Discourse.visible_plugins.each(&p) + else + Discourse.plugins.each(&p) + end + repos + + end + + def self.find(path) + find_all.detect { |r| r.path == path } + end + protected def upgrade_key diff --git a/plugin.rb b/plugin.rb index 2d3822e..a955a86 100644 --- a/plugin.rb +++ b/plugin.rb @@ -4,7 +4,6 @@ # authors: Robin Ward, Sam Saffron # url: https://github.com/discourse/docker_manager - module ::DockerManager # should be automatic, but something is weird load File.expand_path(File.dirname(__FILE__)) << '/app/helpers/application_helper.rb' @@ -22,7 +21,6 @@ assets.skip_minification ||= [] assets.precompile += ['docker-manager-app.js', 'docker-manager-app.css', 'docker-manager-vendor.js', 'docker-manager-vendor.css', 'images/docker-manager.png'] assets.skip_minification += ['docker-manager-app.js', 'docker-manager-vendor.js'] - after_initialize do Discourse::Application.routes.append do mount ::DockerManager::Engine, at: "/" diff --git a/spec/lib/git_repo_spec.rb b/spec/lib/git_repo_spec.rb new file mode 100644 index 0000000..c8aede6 --- /dev/null +++ b/spec/lib/git_repo_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' +require 'docker_manager/git_repo' + +RSpec.describe DockerManager::GitRepo do + + describe ".find_all" do + it "returns a list of repos" do + expect(described_class.find_all).to be_present + end + end + + describe ".find" do + it "does not find invalid repos" do + expect(described_class.find(" NOT A REPO")).to be_blank + end + + it "returns valid repos" do + repo = described_class.find_all.first + expect(repo.path).to be_present + end + end + +end