2007-01-22 14:43:50 +01:00
|
|
|
# The filters added to this controller will be run for all controllers in the application.
|
|
|
|
# Likewise will all the methods added be available for all controllers.
|
|
|
|
class ApplicationController < ActionController::Base
|
2009-12-14 09:01:50 +01:00
|
|
|
|
2007-02-14 18:00:11 +01:00
|
|
|
protect_forms_from_spam
|
2008-12-16 07:40:30 +01:00
|
|
|
before_filter :connect_to_model, :check_authorization, :setup_url_generator, :set_content_type_header, :set_robots_metatag
|
2007-01-22 14:43:50 +01:00
|
|
|
after_filter :remember_location, :teardown_url_generator
|
|
|
|
|
|
|
|
# For injecting a different wiki model implementation. Intended for use in tests
|
|
|
|
def self.wiki=(the_wiki)
|
|
|
|
# a global variable is used here because Rails reloads controller and model classes in the
|
|
|
|
# development environment; therefore, storing it as a class variable does not work
|
|
|
|
# class variable is, anyway, not much different from a global variable
|
|
|
|
#$instiki_wiki_service = the_wiki
|
|
|
|
logger.debug("Wiki service: #{the_wiki.to_s}")
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.wiki
|
|
|
|
Wiki.new
|
|
|
|
end
|
|
|
|
|
2010-01-24 01:01:02 +01:00
|
|
|
helper_method :xhtml_enabled?, :html_ext, :darken
|
2009-12-16 07:59:33 +01:00
|
|
|
|
2009-12-15 05:34:31 +01:00
|
|
|
protected
|
|
|
|
|
2009-12-14 09:01:50 +01:00
|
|
|
def xhtml_enabled?
|
|
|
|
in_a_web? and [:markdownMML, :markdownPNG, :markdown].include?(@web.markup)
|
|
|
|
end
|
|
|
|
|
2009-12-16 07:59:33 +01:00
|
|
|
def html_ext
|
|
|
|
if xhtml_enabled? && request.env.include?('HTTP_ACCEPT') &&
|
|
|
|
Mime::Type.parse(request.env["HTTP_ACCEPT"]).include?(Mime::XHTML)
|
|
|
|
'xhtml'
|
|
|
|
else
|
|
|
|
'html'
|
|
|
|
end
|
|
|
|
end
|
2007-01-22 14:43:50 +01:00
|
|
|
|
2010-01-24 01:01:02 +01:00
|
|
|
def darken(s)
|
|
|
|
n=s.length/3
|
|
|
|
s.scan( %r(\w{#{n},#{n}}) ).collect {|a| (a.hex * 2/3).to_s(16).rjust(n,'0')}.join
|
|
|
|
end
|
|
|
|
|
2007-01-22 14:43:50 +01:00
|
|
|
def check_authorization
|
|
|
|
if in_a_web? and authorization_needed? and not authorized?
|
|
|
|
redirect_to :controller => 'wiki', :action => 'login', :web => @web_name
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def connect_to_model
|
2007-05-11 18:47:38 +02:00
|
|
|
@action_name = params['action'] || 'index'
|
|
|
|
@web_name = params['web']
|
2007-01-22 14:43:50 +01:00
|
|
|
@wiki = wiki
|
|
|
|
@author = cookies['author'] || 'AnonymousCoward'
|
|
|
|
if @web_name
|
|
|
|
@web = @wiki.webs[@web_name]
|
|
|
|
if @web.nil?
|
2007-12-30 10:58:57 +01:00
|
|
|
render(:status => 404, :text => "Unknown web '#{@web_name}'", :layout => 'error')
|
2007-01-22 14:43:50 +01:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
FILE_TYPES = {
|
2009-03-03 19:17:14 +01:00
|
|
|
'.aif' => 'audio/x-aiff',
|
|
|
|
'.aiff'=> 'audio/x-aiff',
|
|
|
|
'.avi' => 'video/x-msvideo',
|
2007-01-22 14:43:50 +01:00
|
|
|
'.exe' => 'application/octet-stream',
|
|
|
|
'.gif' => 'image/gif',
|
|
|
|
'.jpg' => 'image/jpeg',
|
|
|
|
'.pdf' => 'application/pdf',
|
|
|
|
'.png' => 'image/png',
|
2009-03-02 09:32:25 +01:00
|
|
|
'.oga' => 'audio/ogg',
|
|
|
|
'.ogg' => 'audio/ogg',
|
2009-03-03 19:17:14 +01:00
|
|
|
'.ogv' => 'video/ogg',
|
|
|
|
'.mov' => 'video/quicktime',
|
|
|
|
'.mp3' => 'audio/mpeg',
|
|
|
|
'.mp4' => 'video/mp4',
|
2009-03-16 15:55:30 +01:00
|
|
|
'.spx' => 'audio/speex',
|
2007-01-22 14:43:50 +01:00
|
|
|
'.txt' => 'text/plain',
|
2007-01-22 15:36:51 +01:00
|
|
|
'.tex' => 'text/plain',
|
2009-03-03 19:17:14 +01:00
|
|
|
'.wav' => 'audio/x-wav',
|
2007-01-22 14:43:50 +01:00
|
|
|
'.zip' => 'application/zip'
|
|
|
|
} unless defined? FILE_TYPES
|
|
|
|
|
|
|
|
DISPOSITION = {
|
|
|
|
'application/octet-stream' => 'attachment',
|
2009-03-03 19:17:14 +01:00
|
|
|
'application/pdf' => 'inline',
|
2007-01-22 14:43:50 +01:00
|
|
|
'image/gif' => 'inline',
|
|
|
|
'image/jpeg' => 'inline',
|
|
|
|
'image/png' => 'inline',
|
2009-03-03 19:17:14 +01:00
|
|
|
'audio/mpeg' => 'inline',
|
|
|
|
'audio/x-wav' => 'inline',
|
|
|
|
'audio/x-aiff' => 'inline',
|
2009-03-16 15:55:30 +01:00
|
|
|
'audio/speex' => 'inline',
|
2009-03-02 09:32:25 +01:00
|
|
|
'audio/ogg' => 'inline',
|
|
|
|
'video/ogg' => 'inline',
|
2009-03-03 19:17:14 +01:00
|
|
|
'video/mp4' => 'inline',
|
|
|
|
'video/quicktime' => 'inline',
|
|
|
|
'video/x-msvideo' => 'inline',
|
2007-01-22 14:43:50 +01:00
|
|
|
'text/plain' => 'inline',
|
|
|
|
'application/zip' => 'attachment'
|
|
|
|
} unless defined? DISPOSITION
|
|
|
|
|
|
|
|
def determine_file_options_for(file_name, original_options = {})
|
|
|
|
original_options[:type] ||= (FILE_TYPES[File.extname(file_name)] or 'application/octet-stream')
|
|
|
|
original_options[:disposition] ||= (DISPOSITION[original_options[:type]] or 'attachment')
|
|
|
|
original_options[:stream] ||= false
|
2009-10-11 21:00:16 +02:00
|
|
|
original_options[:x_sendfile] = true if request.env.include?('HTTP_X_SENDFILE_TYPE') &&
|
|
|
|
( request.remote_addr == LOCALHOST || defined?(PhusionPassenger) )
|
2007-01-22 14:43:50 +01:00
|
|
|
original_options
|
|
|
|
end
|
|
|
|
|
|
|
|
def send_file(file, options = {})
|
|
|
|
determine_file_options_for(file, options)
|
|
|
|
super(file, options)
|
|
|
|
end
|
|
|
|
|
|
|
|
def password_check(password)
|
|
|
|
if password == @web.password
|
2007-02-09 20:19:03 +01:00
|
|
|
cookies[CGI.escape(@web_name)] = password
|
2007-01-22 14:43:50 +01:00
|
|
|
true
|
|
|
|
else
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def password_error(password)
|
|
|
|
if password.nil? or password.empty?
|
|
|
|
'Please enter the password.'
|
|
|
|
else
|
|
|
|
'You entered a wrong password. Please enter the right one.'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def redirect_home(web = @web_name)
|
|
|
|
if web
|
|
|
|
redirect_to_page('HomePage', web)
|
|
|
|
else
|
2008-11-07 05:57:53 +01:00
|
|
|
redirect_to '/'
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def redirect_to_page(page_name = @page_name, web = @web_name)
|
|
|
|
redirect_to :web => web, :controller => 'wiki', :action => 'show',
|
|
|
|
:id => (page_name or 'HomePage')
|
|
|
|
end
|
|
|
|
|
|
|
|
def remember_location
|
2007-05-11 18:47:38 +02:00
|
|
|
if request.method == :get and
|
2009-02-04 21:26:08 +01:00
|
|
|
@status == '200' and not \
|
2007-01-22 14:43:50 +01:00
|
|
|
%w(locked save back file pic import).include?(action_name)
|
2007-05-11 18:47:38 +02:00
|
|
|
session[:return_to] = request.request_uri
|
|
|
|
logger.debug "Session ##{session.object_id}: remembered URL '#{session[:return_to]}'"
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def rescue_action_in_public(exception)
|
2007-12-30 17:41:19 +01:00
|
|
|
render :status => 500, :text => <<-EOL
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml"><body>
|
|
|
|
<h2>Internal Error</h2>
|
|
|
|
<p>An application error occurred while processing your request.</p>
|
2009-09-07 23:02:36 +02:00
|
|
|
<!-- \n#{exception.to_s.purify.gsub!(/-{2,}/, '- -') }\n#{exception.backtrace.join("\n")}\n -->
|
2007-12-30 17:41:19 +01:00
|
|
|
</body></html>
|
|
|
|
EOL
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def return_to_last_remembered
|
|
|
|
# Forget the redirect location
|
2007-05-11 18:47:38 +02:00
|
|
|
redirect_target, session[:return_to] = session[:return_to], nil
|
|
|
|
tried_home, session[:tried_home] = session[:tried_home], false
|
2007-01-22 14:43:50 +01:00
|
|
|
|
|
|
|
# then try to redirect to it
|
|
|
|
if redirect_target.nil?
|
|
|
|
if tried_home
|
|
|
|
raise 'Application could not render the index page'
|
|
|
|
else
|
|
|
|
logger.debug("Session ##{session.object_id}: no remembered redirect location, trying home")
|
|
|
|
redirect_home
|
|
|
|
end
|
|
|
|
else
|
|
|
|
logger.debug("Session ##{session.object_id}: " +
|
|
|
|
"redirect to the last remembered URL #{redirect_target}")
|
2008-11-07 05:57:53 +01:00
|
|
|
redirect_to(redirect_target)
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_content_type_header
|
2008-08-20 07:22:12 +02:00
|
|
|
response.charset = 'utf-8'
|
2007-04-14 00:04:03 +02:00
|
|
|
if %w(atom_with_content atom_with_headlines).include?(action_name)
|
2008-08-20 07:22:12 +02:00
|
|
|
response.content_type = Mime::ATOM
|
2007-01-22 15:36:51 +01:00
|
|
|
elsif %w(tex).include?(action_name)
|
2008-08-20 07:22:12 +02:00
|
|
|
response.content_type = Mime::TEXT
|
2009-01-04 23:40:50 +01:00
|
|
|
elsif xhtml_enabled?
|
|
|
|
if request.user_agent =~ /Validator/ or request.env.include?('HTTP_ACCEPT') &&
|
2007-07-27 20:47:19 +02:00
|
|
|
Mime::Type.parse(request.env["HTTP_ACCEPT"]).include?(Mime::XHTML)
|
2009-01-04 23:40:50 +01:00
|
|
|
response.content_type = Mime::XHTML
|
|
|
|
elsif request.user_agent =~ /MathPlayer/
|
|
|
|
response.charset = nil
|
|
|
|
response.content_type = Mime::XHTML
|
|
|
|
response.extend(MathPlayerHack)
|
|
|
|
else
|
|
|
|
response.content_type = Mime::HTML
|
|
|
|
end
|
2007-01-23 10:25:24 +01:00
|
|
|
else
|
2008-08-20 07:22:12 +02:00
|
|
|
response.content_type = Mime::HTML
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_robots_metatag
|
2009-08-25 00:42:34 +02:00
|
|
|
if controller_name == 'wiki' and %w(show published s5).include? action_name and !(params[:mode] == 'diff')
|
2007-01-22 14:43:50 +01:00
|
|
|
@robots_metatag_value = 'index,follow'
|
|
|
|
else
|
|
|
|
@robots_metatag_value = 'noindex,nofollow'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def setup_url_generator
|
|
|
|
PageRenderer.setup_url_generator(UrlGenerator.new(self))
|
|
|
|
end
|
|
|
|
|
|
|
|
def teardown_url_generator
|
|
|
|
PageRenderer.teardown_url_generator
|
|
|
|
end
|
|
|
|
|
|
|
|
def wiki
|
|
|
|
self.class.wiki
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def in_a_web?
|
|
|
|
not @web_name.nil?
|
|
|
|
end
|
2009-01-04 23:40:50 +01:00
|
|
|
|
2007-01-22 14:43:50 +01:00
|
|
|
def authorization_needed?
|
2009-06-17 19:45:53 +02:00
|
|
|
not %w(login authenticate feeds published atom_with_headlines atom_with_content file blahtex_png).include?(action_name)
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def authorized?
|
|
|
|
@web.nil? or
|
|
|
|
@web.password.nil? or
|
2007-02-09 20:19:03 +01:00
|
|
|
cookies[CGI.escape(@web_name)] == @web.password or
|
2009-06-17 19:45:53 +02:00
|
|
|
password_check(params['password']) or
|
|
|
|
(@web.published? and action_name == 's5')
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
2007-01-23 10:25:24 +01:00
|
|
|
|
|
|
|
module Mime
|
|
|
|
# Fix HTML
|
|
|
|
#HTML = Type.new "text/html", :html, %w( application/xhtml+xml )
|
2007-10-02 05:09:51 +02:00
|
|
|
self.class.const_set("HTML", Type.new("text/html", :html) )
|
2007-02-02 00:22:15 +01:00
|
|
|
|
2007-01-23 10:25:24 +01:00
|
|
|
# Add XHTML
|
|
|
|
XHTML = Type.new "application/xhtml+xml", :xhtml
|
|
|
|
|
2007-02-02 00:22:15 +01:00
|
|
|
# Fix xhtml and html lookups
|
|
|
|
LOOKUP["text/html"] = HTML
|
2007-01-23 10:25:24 +01:00
|
|
|
LOOKUP["application/xhtml+xml"] = XHTML
|
|
|
|
end
|
2007-02-19 17:01:16 +01:00
|
|
|
|
2008-08-20 07:22:12 +02:00
|
|
|
module MathPlayerHack
|
|
|
|
def charset=(encoding)
|
|
|
|
self.headers["Content-Type"] = "#{content_type || Mime::HTML}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2007-02-19 17:01:16 +01:00
|
|
|
module Instiki
|
|
|
|
module VERSION #:nodoc:
|
|
|
|
MAJOR = 0
|
2009-12-27 07:55:48 +01:00
|
|
|
MINOR = 18
|
2010-01-07 07:07:10 +01:00
|
|
|
TINY = 1
|
2007-02-19 17:01:16 +01:00
|
|
|
SUFFIX = '(MML+)'
|
Security: Instiki 0.16.2
On Webs with file uploads enabled, uploaded files were stored
(in version 0.16.1 and earlier) in the public/ directory.
This was a security threat. A miscreant could upload a .html file.
When a user clicked on the link to the file, it was opened (unsanitized)
in the browser.
As of version 0.16.2, uploaded files are stored in the webs/
directory. Now, when the user clicks on the link, the file is sent
with the
Content-Disposition: attachment
header set, which causes the file to be downloaded, rather than opened
in the browser. As always, files downloaded from the internets should be
treated with caution. At least, this way, they are not aoutomatically
opened in the browser.
To move your existing uploaded files to the new location, do a
rake upgrade_instiki
2009-01-26 07:21:30 +01:00
|
|
|
PRERELEASE = false
|
2007-02-19 17:01:16 +01:00
|
|
|
if PRERELEASE
|
|
|
|
STRING = [MAJOR, MINOR].join('.') + PRERELEASE + SUFFIX
|
|
|
|
else
|
|
|
|
STRING = [MAJOR, MINOR, TINY].join('.') + SUFFIX
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-12-02 19:46:15 +01:00
|
|
|
|
|
|
|
# Monkey patch, to make Hash#key work in Ruby 1.8
|
|
|
|
class Hash
|
|
|
|
alias_method(:key, :index) unless method_defined?(:key)
|
|
|
|
end
|