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
This commit is contained in:
Robin Ward 2018-06-15 13:56:24 -04:00
parent f75ece9a95
commit 8f6be9c592
5 changed files with 92 additions and 47 deletions

View File

@ -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
<html><head></head><body>
<h2>You are running an old version of the Discourse image.</h2>
<p>
Upgrades via the web UI are disabled until you run the latest image.
</p>
<p>
To do so log in to your server using SSH and run:
</p>
<pre>
cd /var/discourse
git pull
./launcher rebuild app
</pre>
<p>
<a href='https://meta.discourse.org/t/how-do-i-update-my-docker-image-to-latest/23325'>More info on our support site</a>
</p>
</body>
</html>
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

View File

@ -0,0 +1,21 @@
<html>
<head></head>
<body>
<h2>You are running an old version of the Discourse image.</h2>
<p>
Upgrades via the web UI are disabled until you run the latest image.
</p>
<p>
To do so log in to your server using SSH and run:
</p>
<pre>
cd /var/discourse
git pull
./launcher rebuild app
</pre>
<p>
<a href='https://meta.discourse.org/t/how-do-i-update-my-docker-image-to-latest/23325'>More info on our support site</a>
</p>
</body>
</html>

View File

@ -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

View File

@ -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: "/"

23
spec/lib/git_repo_spec.rb Normal file
View File

@ -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