add function to disable editing, resolves #879
This commit is contained in:
@@ -22,6 +22,7 @@ options = { 'port' => 4567, 'bind' => '0.0.0.0' }
|
|||||||
wiki_options = {
|
wiki_options = {
|
||||||
:live_preview => false,
|
:live_preview => false,
|
||||||
:allow_uploads => false,
|
:allow_uploads => false,
|
||||||
|
:allow_editing => true,
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = OptionParser.new do |opts|
|
opts = OptionParser.new do |opts|
|
||||||
@@ -76,6 +77,10 @@ opts = OptionParser.new do |opts|
|
|||||||
wiki_options[:ref] = ref
|
wiki_options[:ref] = ref
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.on("--no-edit", "Restricts editing capability through frontend.") do
|
||||||
|
wiki_options[:allow_editing] = false
|
||||||
|
end
|
||||||
|
|
||||||
opts.on("--no-live-preview", "Disables livepreview.") do
|
opts.on("--no-live-preview", "Disables livepreview.") do
|
||||||
wiki_options[:live_preview] = false
|
wiki_options[:live_preview] = false
|
||||||
end
|
end
|
||||||
|
|||||||
+9
-1
@@ -13,6 +13,8 @@ require 'gollum/views/has_page'
|
|||||||
|
|
||||||
require File.expand_path '../helpers', __FILE__
|
require File.expand_path '../helpers', __FILE__
|
||||||
|
|
||||||
|
require 'gollum/editing_auth'
|
||||||
|
|
||||||
#required to upload bigger binary files
|
#required to upload bigger binary files
|
||||||
Gollum::set_git_timeout(120)
|
Gollum::set_git_timeout(120)
|
||||||
Gollum::set_git_max_filesize(190 * 10**6)
|
Gollum::set_git_max_filesize(190 * 10**6)
|
||||||
@@ -42,6 +44,7 @@ module Precious
|
|||||||
class App < Sinatra::Base
|
class App < Sinatra::Base
|
||||||
register Mustache::Sinatra
|
register Mustache::Sinatra
|
||||||
include Precious::Helpers
|
include Precious::Helpers
|
||||||
|
use Precious::EditingAuth
|
||||||
|
|
||||||
dir = File.dirname(File.expand_path(__FILE__))
|
dir = File.dirname(File.expand_path(__FILE__))
|
||||||
|
|
||||||
@@ -91,6 +94,8 @@ module Precious
|
|||||||
settings.wiki_options.merge!({ :base_path => @base_url })
|
settings.wiki_options.merge!({ :base_path => @base_url })
|
||||||
@css = settings.wiki_options[:css]
|
@css = settings.wiki_options[:css]
|
||||||
@js = settings.wiki_options[:js]
|
@js = settings.wiki_options[:js]
|
||||||
|
@mathjax_config = settings.wiki_options[:mathjax_config]
|
||||||
|
@allow_editing = settings.wiki_options[:allow_editing]
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/' do
|
get '/' do
|
||||||
@@ -105,7 +110,6 @@ module Precious
|
|||||||
# name, path, version
|
# name, path, version
|
||||||
def wiki_page(name, path = nil, version = nil, exact = true)
|
def wiki_page(name, path = nil, version = nil, exact = true)
|
||||||
wiki = wiki_new
|
wiki = wiki_new
|
||||||
|
|
||||||
path = name if path.nil?
|
path = name if path.nil?
|
||||||
name = extract_name(name) || wiki.index_page
|
name = extract_name(name) || wiki.index_page
|
||||||
path = extract_path(path)
|
path = extract_path(path)
|
||||||
@@ -126,6 +130,7 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
get '/edit/*' do
|
get '/edit/*' do
|
||||||
|
forbid unless @allow_editing
|
||||||
wikip = wiki_page(params[:splat].first)
|
wikip = wiki_page(params[:splat].first)
|
||||||
@name = wikip.name
|
@name = wikip.name
|
||||||
@path = wikip.path
|
@path = wikip.path
|
||||||
@@ -253,6 +258,7 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
get '/delete/*' do
|
get '/delete/*' do
|
||||||
|
forbid unless @allow_editing
|
||||||
wikip = wiki_page(params[:splat].first)
|
wikip = wiki_page(params[:splat].first)
|
||||||
name = wikip.name
|
name = wikip.name
|
||||||
wiki = wikip.wiki
|
wiki = wikip.wiki
|
||||||
@@ -267,6 +273,7 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
get '/create/*' do
|
get '/create/*' do
|
||||||
|
forbid unless @allow_editing
|
||||||
wikip = wiki_page(params[:splat].first.gsub('+', '-'))
|
wikip = wiki_page(params[:splat].first.gsub('+', '-'))
|
||||||
@name = wikip.name.to_url
|
@name = wikip.name.to_url
|
||||||
@path = wikip.path
|
@path = wikip.path
|
||||||
@@ -476,6 +483,7 @@ module Precious
|
|||||||
elsif file = wiki.file(fullpath, wiki.ref, true)
|
elsif file = wiki.file(fullpath, wiki.ref, true)
|
||||||
show_file(file)
|
show_file(file)
|
||||||
else
|
else
|
||||||
|
not_found unless @allow_editing
|
||||||
page_path = [path, name].compact.join('/')
|
page_path = [path, name].compact.join('/')
|
||||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
module Precious
|
||||||
|
class EditingAuth < Sinatra::Base
|
||||||
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
# Blocks all potentially editable pages. Use EditingAuth::whitelist_pages to unblock pages.
|
||||||
|
unless (env["REQUEST_METHOD"] == "GET") || App::settings.wiki_options[:allow_editing]
|
||||||
|
return block unless excluded_page?
|
||||||
|
end
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def block
|
||||||
|
[403, {'Content-Type' => 'text/html', 'Content-Length' => '9'}, ['Forbidden']]
|
||||||
|
end
|
||||||
|
|
||||||
|
def excluded_page?
|
||||||
|
return false if env["REQUEST_PATH"].nil?
|
||||||
|
whitelist_pages.any? do |whitelisted_page|
|
||||||
|
env["REQUEST_PATH"].include? whitelisted_page
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# List pages paths as str that you want to whitelist.
|
||||||
|
# Pages will be compared with env["REQUEST_PATH"] using String::include? method.
|
||||||
|
def whitelist_pages
|
||||||
|
return ["/compare/"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -39,5 +39,17 @@ module Precious
|
|||||||
url.gsub('%2F', '/').gsub(/^\/+/, '').gsub('//', '/')
|
url.gsub('%2F', '/').gsub(/^\/+/, '').gsub('//', '/')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def forbid(msg = "Forbidden.")
|
||||||
|
@message = msg
|
||||||
|
status 403
|
||||||
|
halt mustache :error
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_found(msg = nil)
|
||||||
|
@message = msg || "The requested page does not exist."
|
||||||
|
status 404
|
||||||
|
return mustache :error
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,8 +8,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="minibutton"><a href="{{base_url}}/{{escaped_url_path}}"
|
<li class="minibutton"><a href="{{base_url}}/{{escaped_url_path}}"
|
||||||
class="action-view-page">View Page</a></li>
|
class="action-view-page">View Page</a></li>
|
||||||
<li class="minibutton"><a href="{{base_url}}/edit/{{escaped_url_path}}"
|
{{#allow_editing}}
|
||||||
class="action-edit-page">Edit Page</a></li>
|
<li class="minibutton"><a href="{{base_url}}/edit/{{escaped_url_path}}"
|
||||||
|
class="action-edit-page">Edit Page</a></li>
|
||||||
|
{{/allow_editing}}
|
||||||
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
||||||
class="action-page-history">Page History</a></li>
|
class="action-page-history">Page History</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -25,11 +27,13 @@
|
|||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
||||||
class="action-page-history">Back to Page History</a></li>
|
class="action-page-history">Back to Page History</a></li>
|
||||||
<li class="minibutton">
|
{{#allow_editing}}
|
||||||
<form name="gollum-revert" action="{{base_url}}/revert/{{escaped_url_path}}/{{before}}/{{after}}" method="post" id="gollum-revert-form">
|
<li class="minibutton">
|
||||||
<a href="#" class="gollum-revert-button">Revert Changes</a>
|
<form name="gollum-revert" action="{{base_url}}/revert/{{escaped_url_path}}/{{before}}/{{after}}" method="post" id="gollum-revert-form">
|
||||||
</form>
|
<a href="#" class="gollum-revert-button">Revert Changes</a>
|
||||||
</li>
|
</form>
|
||||||
|
</li>
|
||||||
|
{{/allow_editing}}
|
||||||
</ul>
|
</ul>
|
||||||
{{/show_revert}}
|
{{/show_revert}}
|
||||||
|
|
||||||
@@ -52,9 +56,11 @@
|
|||||||
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
||||||
class="action-page-history">Back to Page History</a></li>
|
class="action-page-history">Back to Page History</a></li>
|
||||||
{{#show_revert}}
|
{{#show_revert}}
|
||||||
<li class="minibutton">
|
{{#allow_editing}}
|
||||||
<a href="#" class="gollum-revert-button">Revert Changes</a>
|
<li class="minibutton">
|
||||||
</li>
|
<a href="#" class="gollum-revert-button">Revert Changes</a>
|
||||||
|
</li>
|
||||||
|
{{/allow_editing}}
|
||||||
{{/show_revert}}
|
{{/show_revert}}
|
||||||
<li class="minibutton"><a href="#">Back to Top</a></li>
|
<li class="minibutton"><a href="#">Back to Top</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="minibutton"><a href="{{base_url}}/{{escaped_url_path}}"
|
<li class="minibutton"><a href="{{base_url}}/{{escaped_url_path}}"
|
||||||
class="action-view-page">View Page</a></li>
|
class="action-view-page">View Page</a></li>
|
||||||
<li class="minibutton"><a href="{{base_url}}/edit/{{escaped_url_path}}"
|
{{#allow_editing}}
|
||||||
class="action-edit-page">Edit Page</a></li>
|
<li class="minibutton"><a href="{{base_url}}/edit/{{escaped_url_path}}"
|
||||||
|
class="action-edit-page">Edit Page</a></li>
|
||||||
|
{{/allow_editing}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="wiki-history">
|
<div id="wiki-history">
|
||||||
|
|||||||
@@ -18,18 +18,28 @@ Mousetrap.bind(['e'], function( e ) {
|
|||||||
class="action-all-pages">All</a></li>
|
class="action-all-pages">All</a></li>
|
||||||
<li class="minibutton"><a href="{{base_url}}/fileview"
|
<li class="minibutton"><a href="{{base_url}}/fileview"
|
||||||
class="action-fileview">Files</a></li>
|
class="action-fileview">Files</a></li>
|
||||||
<li class="minibutton jaws">
|
{{#allow_editing}}
|
||||||
<a href="#" id="minibutton-new-page">New</a></li>
|
<li class="minibutton jaws">
|
||||||
{{#allow_uploads}}
|
<a href="#" id="minibutton-new-page">New</a></li>
|
||||||
<li class="minibutton jaws">
|
{{/allow_editing}}
|
||||||
<a href="#" id="minibutton-upload-page">Upload</a></li>
|
{{#allow_editing}}
|
||||||
{{/allow_uploads}}
|
{{#allow_uploads}}
|
||||||
{{#editable}}
|
<li class="minibutton jaws">
|
||||||
<li class="minibutton jaws">
|
<a href="#" id="minibutton-upload-page">Upload</a></li>
|
||||||
<a href="#" id="minibutton-rename-page">Rename</a></li>
|
{{/allow_uploads}}
|
||||||
<li class="minibutton"><a href="{{base_url}}/edit/{{escaped_url_path}}"
|
{{/allow_editing}}
|
||||||
class="action-edit-page">Edit</a></li>
|
{{#allow_editing}}
|
||||||
{{/editable}}
|
{{#editable}}
|
||||||
|
<li class="minibutton jaws">
|
||||||
|
<a href="#" id="minibutton-rename-page">Rename</a></li>
|
||||||
|
{{/editable}}
|
||||||
|
{{/allow_editing}}
|
||||||
|
{{#allow_editing}}
|
||||||
|
{{#editable}}
|
||||||
|
<li class="minibutton"><a href="{{base_url}}/edit/{{escaped_url_path}}"
|
||||||
|
class="action-edit-page">Edit</a></li>
|
||||||
|
{{/editable}}
|
||||||
|
{{/allow_editing}}
|
||||||
{{#page_exists}}
|
{{#page_exists}}
|
||||||
<li class="minibutton jaws">
|
<li class="minibutton jaws">
|
||||||
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
<li class="minibutton"><a href="{{base_url}}/history/{{escaped_url_path}}"
|
||||||
@@ -75,9 +85,11 @@ Mousetrap.bind(['e'], function( e ) {
|
|||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<p id="last-edit">Last edited by <b>{{author}}</b>, {{date}}</p>
|
<p id="last-edit">Last edited by <b>{{author}}</b>, {{date}}</p>
|
||||||
<p>
|
{{#allow_editing}}
|
||||||
<a id="delete-link" href="{{base_url}}/{{escaped_url_path}}" data-confirm="Are you sure you want to delete this page?"><span>Delete this Page</span></a>
|
<p>
|
||||||
</p>
|
<a id="delete-link" href="{{base_url}}/{{escaped_url_path}}" data-confirm="Are you sure you want to delete this page?"><span>Delete this Page</span></a>
|
||||||
|
</p>
|
||||||
|
{{/allow_editing}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="minibutton"><a href="{{base_url}}/"
|
<li class="minibutton"><a href="{{base_url}}/"
|
||||||
class="action-home-page">Home</a></li>
|
class="action-home-page">Home</a></li>
|
||||||
<li class="minibutton jaws">
|
{{#allow_editing}}
|
||||||
<a href="#" id="minibutton-new-page">New</a>
|
<li class="minibutton jaws">
|
||||||
</li>
|
<a href="#" id="minibutton-new-page">New</a></li>
|
||||||
|
{{/allow_editing}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="pages">
|
<div id="pages">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module Precious
|
|||||||
class Compare < Layout
|
class Compare < Layout
|
||||||
include HasPage
|
include HasPage
|
||||||
|
|
||||||
attr_reader :page, :diff, :versions, :message
|
attr_reader :page, :diff, :versions, :message, :allow_editing
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Comparison of #{@page.title}"
|
"Comparison of #{@page.title}"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module Precious
|
|||||||
class History < Layout
|
class History < Layout
|
||||||
include HasPage
|
include HasPage
|
||||||
|
|
||||||
attr_reader :page, :page_num
|
attr_reader :page, :page_num, :allow_editing
|
||||||
|
|
||||||
def title
|
def title
|
||||||
@page.title
|
@page.title
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ module Precious
|
|||||||
@page_exists
|
@page_exists
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allow_editing
|
||||||
|
@allow_editing
|
||||||
|
end
|
||||||
|
|
||||||
def allow_uploads
|
def allow_uploads
|
||||||
@allow_uploads
|
@allow_uploads
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require "pathname"
|
|||||||
module Precious
|
module Precious
|
||||||
module Views
|
module Views
|
||||||
class Pages < Layout
|
class Pages < Layout
|
||||||
attr_reader :results, :ref
|
attr_reader :results, :ref, :allow_editing
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"All pages in #{@ref}"
|
"All pages in #{@ref}"
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# ~*~ encoding: utf-8 ~*~
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
||||||
|
|
||||||
|
context "Precious::Views::Editing" do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
setup do
|
||||||
|
examples = testpath "examples"
|
||||||
|
@path = File.join(examples, "test.git")
|
||||||
|
Precious::App.set(:gollum_path, @path)
|
||||||
|
FileUtils.cp_r File.join(examples, "revert.git"), @path, :remove_destination => true
|
||||||
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
FileUtils.rm_r(File.join(File.dirname(__FILE__), *%w[examples test.git]))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "creating page is blocked" do
|
||||||
|
Precious::App.set(:wiki_options, { allow_editing: false})
|
||||||
|
post "/create", :content => 'abc', :page => "D",
|
||||||
|
:format => 'markdown', :message => 'def'
|
||||||
|
assert !last_response.ok?
|
||||||
|
|
||||||
|
page = @wiki.page('D')
|
||||||
|
assert page.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test "frontend links for editing are not blocked" do
|
||||||
|
Precious::App.set(:wiki_options, { allow_editing: true, allow_uploads: true })
|
||||||
|
get '/A'
|
||||||
|
|
||||||
|
assert_match /Delete this Page/, last_response.body, "'Delete this Page' link is blocked in page template"
|
||||||
|
assert_match /New/, last_response.body, "'New' button is blocked in page template"
|
||||||
|
assert_match /Upload/, last_response.body, "'Upload' link is blocked in page template"
|
||||||
|
assert_match /Rename/, last_response.body, "'Rename' link is blocked in page template"
|
||||||
|
assert_match /Edit/, last_response.body, "'Edit' link is blocked in page template"
|
||||||
|
|
||||||
|
get '/pages'
|
||||||
|
|
||||||
|
assert_match /New/, last_response.body, "'New' link is blocked in pages template"
|
||||||
|
|
||||||
|
get '/history/A'
|
||||||
|
|
||||||
|
assert_match /Edit/, last_response.body, "'Edit' link is blocked in history template"
|
||||||
|
|
||||||
|
get '/compare/A/fc66539528eb96f21b2bbdbf557788fe8a1196ac..b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f'
|
||||||
|
|
||||||
|
assert_match /Edit Page/, last_response.body, "'Edit Page' link is blocked in compare template"
|
||||||
|
assert_match /Revert Changes/, last_response.body, "'Revert Changes' link is blocked in compare template"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "frontend links for editing blocked" do
|
||||||
|
Precious::App.set(:wiki_options, { allow_editing: false })
|
||||||
|
get '/A'
|
||||||
|
|
||||||
|
assert_no_match /Delete this Page/, last_response.body, "'Delete this Page' link not blocked in page template"
|
||||||
|
assert_no_match /New/, last_response.body, "'New' button not blocked in page template"
|
||||||
|
assert_no_match /Upload/, last_response.body, "'Upload' link not blocked in page template"
|
||||||
|
assert_no_match /Rename/, last_response.body, "'Rename' link not blocked in page template"
|
||||||
|
assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in page template"
|
||||||
|
|
||||||
|
get '/pages'
|
||||||
|
|
||||||
|
assert_no_match /New/, last_response.body, "'New' link not blocked in pages template"
|
||||||
|
|
||||||
|
get '/history/A'
|
||||||
|
|
||||||
|
assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in history template"
|
||||||
|
|
||||||
|
get '/compare/A/fc66539528eb96f21b2bbdbf557788fe8a1196ac..b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f'
|
||||||
|
|
||||||
|
assert_no_match /Edit Page/, last_response.body, "'Edit Page' link not blocked in compare template"
|
||||||
|
assert_no_match /Revert Changes/, last_response.body, "'Revert Changes' link not blocked in compare template"
|
||||||
|
end
|
||||||
|
|
||||||
|
def app
|
||||||
|
Precious::App
|
||||||
|
end
|
||||||
|
end
|
||||||
+1
-1
@@ -8,7 +8,7 @@ context "Frontend" do
|
|||||||
@path = cloned_testpath("examples/revert.git")
|
@path = cloned_testpath("examples/revert.git")
|
||||||
@wiki = Gollum::Wiki.new(@path)
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
Precious::App.set(:gollum_path, @path)
|
Precious::App.set(:gollum_path, @path)
|
||||||
Precious::App.set(:wiki_options, {})
|
Precious::App.set(:wiki_options, {allow_editing: true})
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
|
|||||||
Reference in New Issue
Block a user