aboutsummaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/brakeman.ignore63
-rw-r--r--config/brakeman.yml4
-rw-r--r--config/crontab-example5
-rw-r--r--config/deploy.rb5
-rw-r--r--config/deploy.yml.example2
-rw-r--r--config/general.yml-example7
-rw-r--r--config/httpd.conf-example7
-rw-r--r--config/initializers/alaveteli.rb5
-rw-r--r--config/initializers/missing_source_file.rb2
-rw-r--r--config/initializers/secure_headers.rb24
-rw-r--r--config/routes.rb174
-rwxr-xr-xconfig/sysvinit-thin.ugly8
12 files changed, 222 insertions, 84 deletions
diff --git a/config/brakeman.ignore b/config/brakeman.ignore
new file mode 100644
index 000000000..391013a5a
--- /dev/null
+++ b/config/brakeman.ignore
@@ -0,0 +1,63 @@
+{
+ "ignored_warnings": [
+ {
+ "location": {
+ "type": "method",
+ "method": "list_all_csv",
+ "class": "PublicBodyController"
+ },
+ "file": "app/controllers/public_body_controller.rb",
+ "warning_code": 16,
+ "render_path": null,
+ "link": "http://brakemanscanner.org/docs/warning_types/file_access/",
+ "warning_type": "File Access",
+ "code": "File.open(Tempfile.new(\"all-authorities.csv\", File.join(InfoRequest.download_zip_dir, \"download\")).path, \"w\")",
+ "line": 211,
+ "confidence": "Weak",
+ "user_input": "InfoRequest.download_zip_dir",
+ "message": "Model attribute used in file name",
+ "fingerprint": "00ce9cdd1d2c3f220bae94cb854393b5072ee1da064ca7a3af693fe2867d51c8",
+ "note": "InfoRequest.download_zip_dir does not contain user input"
+ },
+ {
+ "location": {
+ "type": "method",
+ "method": "list_all_csv",
+ "class": "PublicBodyController"
+ },
+ "file": "app/controllers/public_body_controller.rb",
+ "warning_code": 16,
+ "render_path": null,
+ "link": "http://brakemanscanner.org/docs/warning_types/file_access/",
+ "warning_type": "File Access",
+ "code": "File.rename(Tempfile.new(\"all-authorities.csv\", File.join(InfoRequest.download_zip_dir, \"download\")).path, File.join(File.join(InfoRequest.download_zip_dir, \"download\"), \"all-authorities.csv\"))",
+ "line": 213,
+ "confidence": "Weak",
+ "user_input": "InfoRequest.download_zip_dir",
+ "message": "Model attribute used in file name",
+ "fingerprint": "6078628aa47451d597e211629d80dcea0fdc7600dc066cabf2c0a4b9e07a75cc",
+ "note": "InfoRequest.download_zip_dir does not contain user input"
+ },
+ {
+ "location": {
+ "type": "method",
+ "method": "list_all_csv",
+ "class": "PublicBodyController"
+ },
+ "file": "app/controllers/public_body_controller.rb",
+ "warning_code": 16,
+ "render_path": null,
+ "link": "http://brakemanscanner.org/docs/warning_types/file_access/",
+ "warning_type": "File Access",
+ "code": "FileUtils.mkdir_p(File.join(InfoRequest.download_zip_dir, \"download\"))",
+ "line": 194,
+ "confidence": "Weak",
+ "user_input": "InfoRequest.download_zip_dir",
+ "message": "Model attribute used in file name",
+ "fingerprint": "5ed20f867c17c814cfe117906161a26f37b986d694996c9fd0089d4f971dc1d0",
+ "note": "InfoRequest.download_zip_dir does not contain user input"
+ }
+ ],
+ "updated": "Thu Oct 02 10:43:19 +0000 2014",
+ "brakeman_version": "2.6.2"
+}
diff --git a/config/brakeman.yml b/config/brakeman.yml
new file mode 100644
index 000000000..1f95903fd
--- /dev/null
+++ b/config/brakeman.yml
@@ -0,0 +1,4 @@
+---
+:output_files:
+- tmp/brakeman.html
+- tmp/brakeman.json
diff --git a/config/crontab-example b/config/crontab-example
index 44e328e4e..f65555b11 100644
--- a/config/crontab-example
+++ b/config/crontab-example
@@ -21,6 +21,7 @@ MAILTO=!!(*= $mailto *)!!
31 * * * * root !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/load-mail-server-logs.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/load-mail-server-logs || echo "stalled?"
# Once a day, early morning
+31 1 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/change-xapian-database.lock "!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/compact-xapian-database production !!(*= $site *)!!" || echo "stalled?"
23 4 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/delete-old-things.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/delete-old-things || echo "stalled?"
0 6 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/alert-overdue-requests.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/alert-overdue-requests || echo "stalled?"
0 7 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/alert-new-response-reminders.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/alert-new-response-reminders || echo "stalled?"
@@ -29,10 +30,6 @@ MAILTO=!!(*= $mailto *)!!
45 3 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/stop-new-responses-on-old-requests.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/stop-new-responses-on-old-requests || echo "stalled?"
55 4 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/update-public-body-stats.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/update-public-body-stats || echo "stalled?"
-# Only root can restart apache
-31 1 * * * root !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/change-xapian-database.lock "!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/compact-xapian-database production" || echo "stalled?"
-
-
# Once a day on all servers
43 2 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/request-creation-graph
48 2 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/user-use-graph
diff --git a/config/deploy.rb b/config/deploy.rb
index c1954d058..f4a0b536a 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -14,6 +14,7 @@ set :deploy_to, configuration['deploy_to']
set :user, configuration['user']
set :use_sudo, false
set :rails_env, configuration['rails_env']
+set :daemon_name, configuration.fetch('daemon_name', 'alaveteli')
server configuration['server'], :app, :web, :db, :primary => true
@@ -35,9 +36,9 @@ end
namespace :deploy do
[:start, :stop, :restart].each do |t|
- desc "#{t.to_s.capitalize} Alaveteli service defined in /etc/init.d/alaveteli"
+ desc "#{t.to_s.capitalize} Alaveteli service defined in /etc/init.d/"
task t, :roles => :app, :except => { :no_release => true } do
- run "/etc/init.d/alaveteli #{t}"
+ run "service #{ daemon_name } #{ t }"
end
end
diff --git a/config/deploy.yml.example b/config/deploy.yml.example
index a20eb3c22..93aba439a 100644
--- a/config/deploy.yml.example
+++ b/config/deploy.yml.example
@@ -6,6 +6,7 @@ production:
user: deploy
rails_env: production
deploy_to: /srv/www/alaveteli_production
+ daemon_name: alaveteli
staging:
repository: git://github.com/mysociety/alaveteli.git
branch: develop
@@ -13,3 +14,4 @@ staging:
user: deploy
rails_env: production
deploy_to: /srv/www/alaveteli_staging
+ daemon_name: alaveteli_staging
diff --git a/config/general.yml-example b/config/general.yml-example
index 5be62ee21..8acea374b 100644
--- a/config/general.yml-example
+++ b/config/general.yml-example
@@ -154,6 +154,11 @@ USE_DEFAULT_BROWSER_LANGUAGE: true
# ---
INCLUDE_DEFAULT_LOCALE_IN_URLS: true
+# Are authorities required to respond by law?
+#
+# AUTHORITY_MUST_RESPOND: Boolean (default: true)
+AUTHORITY_MUST_RESPOND: true
+
# The REPLY...AFTER_DAYS settings define how many days must have passed before
# an answer to a request is officially late. The SPECIAL case is for some types
# of authority (for example: in the UK, schools) which are granted a bit longer
@@ -411,7 +416,7 @@ READ_ONLY: ''
# STAGING_SITE: 0
#
# ---
-STAGING_SITE: 0
+STAGING_SITE: 1
# Recaptcha, for detecting humans. Get keys here:
# http://recaptcha.net/whyrecaptcha.html
diff --git a/config/httpd.conf-example b/config/httpd.conf-example
index e010ac22f..00722fbdf 100644
--- a/config/httpd.conf-example
+++ b/config/httpd.conf-example
@@ -34,7 +34,7 @@
# Passenger's default MaxPoolSize is 6. At the time of writing
# normal instances of Alaveteli seem to take 150-200MB per
# process, so we've set this conservatively at 3. Read the guides
- # above to tune this for your system
+ # above to tune this for your system
PassengerMaxPoolSize 3
# The RAILS_ENV that the app is running in. This can be any of
@@ -97,6 +97,11 @@
#
# The condition means that the rule will fire only if the cached
# file exists.
+ #
+ # The second condition-rule pair handles the same transformation for
+ # files served from a non-default locale, 'cy'. You will need one
+ # set of rules for each non-default locale.
+
RewriteMap escape int:escape
RewriteCond %{DOCUMENT_ROOT}/views_cache/request/$2/$1/${escape:$3} -f
RewriteRule ^/request/((\d{1,3})\d*)/(response/\d+/attach/(html/)?\d+/.+) /views_cache/request/$2/$1/${escape:$3} [L]
diff --git a/config/initializers/alaveteli.rb b/config/initializers/alaveteli.rb
index ec403b477..19e8df7d1 100644
--- a/config/initializers/alaveteli.rb
+++ b/config/initializers/alaveteli.rb
@@ -10,7 +10,7 @@ load "debug_helpers.rb"
load "util.rb"
# Application version
-ALAVETELI_VERSION = '0.20.0.14'
+ALAVETELI_VERSION = '0.21.0.0'
# Add new inflection rules using the following format
# (all these examples are active by default):
@@ -53,9 +53,8 @@ require 'theme'
require 'xapian_queries'
require 'date_quarter'
require 'public_body_csv'
-require 'category_and_heading_migrator'
-require 'public_body_categories'
require 'routing_filters'
+require 'alaveteli_text_masker'
AlaveteliLocalization.set_locales(AlaveteliConfiguration::available_locales,
AlaveteliConfiguration::default_locale)
diff --git a/config/initializers/missing_source_file.rb b/config/initializers/missing_source_file.rb
deleted file mode 100644
index a114fa972..000000000
--- a/config/initializers/missing_source_file.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# For Rails 2.3 on Ruby 1.9.3 @see https://github.com/rails/rails/pull/3745
-MissingSourceFile::REGEXPS << [/^cannot load such file -- (.+)$/i, 1]
diff --git a/config/initializers/secure_headers.rb b/config/initializers/secure_headers.rb
new file mode 100644
index 000000000..99730e6b2
--- /dev/null
+++ b/config/initializers/secure_headers.rb
@@ -0,0 +1,24 @@
+::SecureHeaders::Configuration.configure do |config|
+
+ # https://tools.ietf.org/html/rfc6797
+ if AlaveteliConfiguration::force_ssl
+ config.hsts = { :max_age => 20.years.to_i, :include_subdomains => true }
+ else
+ config.hsts = false
+ end
+ # https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-02
+ config.x_frame_options = "sameorigin"
+
+ # http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx
+ config.x_content_type_options = "nosniff"
+
+ # http://msdn.microsoft.com/en-us/library/dd565647%28v=vs.85%29.aspx
+ config.x_xss_protection = { :value => 1 }
+
+ # https://w3c.github.io/webappsec/specs/content-security-policy/
+ config.csp = false
+
+ # https://www.nwebsec.com/HttpHeaders/SecurityHeaders/XDownloadOptions
+ config.x_download_options = false
+end
+
diff --git a/config/routes.rb b/config/routes.rb
index 4b2eb5695..c975d6007 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -169,17 +169,15 @@ Alaveteli::Application.routes.draw do
####
#### AdminPublicBody controller
- match '/admin/missing_scheme' => 'admin_public_body#missing_scheme', :as => :admin_body_missing
- match '/admin/body' => 'admin_public_body#index', :as => :admin_body_index
- match '/admin/body/list' => 'admin_public_body#list', :as => :admin_body_list
- match '/admin/body/show/:id' => 'admin_public_body#show', :as => :admin_body_show
- match '/admin/body/new' => 'admin_public_body#new', :as => :admin_body_new
- match '/admin/body/edit/:id' => 'admin_public_body#edit', :as => :admin_body_edit
- match '/admin/body/update/:id' => 'admin_public_body#update', :as => :admin_body_update
- match '/admin/body/create' => 'admin_public_body#create', :as => :admin_body_create
- match '/admin/body/destroy/:id' => 'admin_public_body#destroy', :as => :admin_body_destroy
- match '/admin/body/import_csv' => 'admin_public_body#import_csv', :as => :admin_body_import_csv
- match '/admin/body/mass_tag_add' => 'admin_public_body#mass_tag_add', :as => :admin_body_mass_tag_add
+ scope '/admin', :as => 'admin' do
+ resources :bodies,
+ :controller => 'admin_public_body' do
+ get 'missing_scheme', :on => :collection
+ post 'mass_tag_add', :on => :collection
+ get 'import_csv', :on => :collection
+ post 'import_csv', :on => :collection
+ end
+ end
####
#### AdminPublicBodyCategory controller
@@ -200,9 +198,27 @@ Alaveteli::Application.routes.draw do
end
####
+ #### AdminHoliday controller
+ scope '/admin', :as => 'admin' do
+ resources :holidays,
+ :controller => 'admin_holidays'
+ end
+ ####
+
+ #### AdminHolidayImports controller
+ scope '/admin', :as => 'admin' do
+ resources :holiday_imports,
+ :controller => 'admin_holiday_imports',
+ :only => [:new, :create]
+ end
+ ####
+
#### AdminPublicBodyChangeRequest controller
- match '/admin/change_request/edit/:id' => 'admin_public_body_change_requests#edit', :as => :admin_change_request_edit
- match '/admin/change_request/update/:id' => 'admin_public_body_change_requests#update', :as => :admin_change_request_update
+ scope '/admin', :as => 'admin' do
+ resources :change_requests,
+ :controller => 'admin_public_body_change_requests',
+ :only => [:edit, :update]
+ end
####
#### AdminGeneral controller
@@ -213,81 +229,99 @@ Alaveteli::Application.routes.draw do
####
#### AdminRequest controller
- match '/admin/request' => 'admin_request#index', :as => :admin_request_index
- match '/admin/request/list' => 'admin_request#list', :as => :admin_request_list
- match '/admin/request/show/:id' => 'admin_request#show', :as => :admin_request_show
- match '/admin/request/resend' => 'admin_request#resend', :as => :admin_request_resend
- match '/admin/request/edit/:id' => 'admin_request#edit', :as => :admin_request_edit
- match '/admin/request/update/:id' => 'admin_request#update', :as => :admin_request_update
- match '/admin/request/destroy/:id' => 'admin_request#fully_destroy', :as => :admin_request_destroy
- match '/admin/request/edit_comment/:id' => 'admin_request#edit_comment', :as => :admin_request_edit_comment
- match '/admin/request/update_comment/:id' => 'admin_request#update_comment', :as => :admin_request_update_comment
- match '/admin/request/move_request' => 'admin_request#move_request', :as => :admin_request_move_request
- match '/admin/request/generate_upload_url/:id' => 'admin_request#generate_upload_url', :as => :admin_request_generate_upload_url
- match '/admin/request/show_raw_email/:id' => 'admin_request#show_raw_email', :as => :admin_request_show_raw_email
- match '/admin/request/download_raw_email/:id' => 'admin_request#download_raw_email', :as => :admin_request_download_raw_email
- match '/admin/request/mark_event_as_clarification' => 'admin_request#mark_event_as_clarification', :as => :admin_request_clarification
- match '/admin/request/hide/:id' => 'admin_request#hide_request', :as => :admin_request_hide
- ####
+ scope '/admin', :as => 'admin' do
+ resources :requests,
+ :controller => 'admin_request',
+ :except => [:new, :create] do
+ post 'move', :on => :member
+ post 'generate_upload_url', :on => :member
+ post 'hide', :on => :member
+ resources :censor_rules,
+ :controller => 'admin_censor_rule',
+ :only => [:new, :create],
+ :name_prefix => 'request_'
- #### AdminIncomingMessage controller
- match '/admin/incoming/destroy' => 'admin_incoming_message#destroy', :as => :admin_incoming_destroy
- match '/admin/incoming/redeliver' => 'admin_incoming_message#redeliver', :as => :admin_incoming_redeliver
- match '/admin/incoming/edit/:id' => 'admin_incoming_message#edit', :as => :admin_incoming_edit
- match '/admin/incoming/update/:id' => 'admin_incoming_message#update', :as => :admin_incoming_update
+ end
+ end
####
- #### AdminOutgoingMessage controller
- match '/admin/outgoing/edit/:id' => 'admin_outgoing_message#edit', :as => :admin_outgoing_edit
- match '/admin/outgoing/destroy/:id' => 'admin_outgoing_message#destroy', :as => :admin_outgoing_destroy
- match '/admin/outgoing/update/:id' => 'admin_outgoing_message#update', :as => :admin_outgoing_update
+ #### AdminComment controller
+ scope '/admin', :as => 'admin' do
+ resources :comments,
+ :controller => 'admin_comment',
+ :only => [:edit, :update]
+ end
####
- #### AdminUser controller
- match '/admin/user' => 'admin_user#index', :as => :admin_user_index
- match '/admin/user/list' => 'admin_user#list', :as => :admin_user_list
- match '/admin/user/banned' => 'admin_user#list_banned', :as => :admin_user_list_banned
- match '/admin/user/show/:id' => 'admin_user#show', :as => :admin_user_show
- match '/admin/user/edit/:id' => 'admin_user#edit', :as => :admin_user_edit
- match '/admin/user/show_bounce_message/:id' => 'admin_user#show_bounce_message', :as => :admin_user_show_bounce
- match '/admin/user/update/:id' => 'admin_user#update', :as => :admin_user_update
- match '/admin/user/clear_bounce/:id' => 'admin_user#clear_bounce', :as => :admin_user_clear_bounce
- match '/admin/user/destroy_track' => 'admin_user#destroy_track', :as => :admin_user_destroy_track
- match '/admin/user/login_as/:id' => 'admin_user#login_as', :as => :admin_user_login_as
- match '/admin/user/clear_profile_photo/:id' => 'admin_user#clear_profile_photo', :as => :admin_clear_profile_photo
- match '/admin/user/modify_comment_visibility/:id' => 'admin_user#modify_comment_visibility', :as => 'admin_user_modify_comment_visibility'
+ #### AdminRawEmail controller
+ scope '/admin', :as => 'admin' do
+ resources :raw_emails,
+ :controller => 'admin_raw_email',
+ :only => [:show]
+ end
####
- #### AdminTrack controller
- match '/admin/track/list' => 'admin_track#list', :as => :admin_track_list
- ####
+ #### AdminInfoRequestEvent controller
+ scope '/admin', :as => 'admin' do
+ resources :info_request_events,
+ :controller => 'admin_info_request_event',
+ :only => [:update]
+ end
- #### AdminCensorRule controller
- match '/admin/censor/new' => 'admin_censor_rule#new', :as => :admin_rule_new
- match '/admin/censor/create' => 'admin_censor_rule#create', :as => :admin_rule_create
- match '/admin/censor/edit/:id' => 'admin_censor_rule#edit', :as => :admin_rule_edit
- match '/admin/censor/update/:id' => 'admin_censor_rule#update', :as => :admin_rule_update
- match '/admin/censor/destroy/:censor_rule_id' => 'admin_censor_rule#destroy', :as => :admin_rule_destroy
+ #### AdminIncomingMessage controller
+ scope '/admin', :as => 'admin' do
+ resources :incoming_messages,
+ :controller => 'admin_incoming_message',
+ :only => [:edit, :update, :destroy] do
+ post 'redeliver', :on => :member
+ end
+ end
+ ####
+ #### AdminOutgoingMessage controller
scope '/admin', :as => 'admin' do
- resources :info_requests, :only => [] do
- resources :censor_rules,
- :controller => 'admin_censor_rule',
- :only => [:new, :create],
- :name_prefix => 'info_request_'
+ resources :outgoing_messages,
+ :controller => 'admin_outgoing_message',
+ :only => [:edit, :update, :destroy] do
+ post 'resend', :on => :member
end
end
+ ####
+ #### AdminUser controller
scope '/admin', :as => 'admin' do
- resources :users, :only => [] do
- resources :censor_rules,
- :controller => 'admin_censor_rule',
- :only => [:new, :create],
- :name_prefix => 'user_'
+ resources :users,
+ :controller => 'admin_user',
+ :except => [:new, :create, :destroy] do
+ get 'banned', :on => :collection
+ get 'show_bounce_message', :on => :member
+ post 'clear_bounce', :on => :member
+ post 'login_as', :on => :member
+ post 'clear_profile_photo', :on => :member
+ post 'modify_comment_visibility', :on => :collection
+ resources :censor_rules,
+ :controller => 'admin_censor_rule',
+ :only => [:new, :create],
+ :name_prefix => 'user_'
end
end
####
+ #### AdminTrack controller
+ scope '/admin', :as => 'admin' do
+ resources :tracks,
+ :controller => 'admin_track',
+ :only => [:index, :destroy]
+ end
+ ####
+
+ #### AdminCensorRule controller
+ scope '/admin', :as => 'admin' do
+ resources :censor_rules,
+ :controller => 'admin_censor_rule',
+ :except => [:index, :new, :create]
+ end
+
#### AdminSpamAddresses controller
scope '/admin', :as => 'admin' do
resources :spam_addresses,
diff --git a/config/sysvinit-thin.ugly b/config/sysvinit-thin.ugly
index b333f3738..0155ff8c3 100755
--- a/config/sysvinit-thin.ugly
+++ b/config/sysvinit-thin.ugly
@@ -22,7 +22,13 @@ RAILS_ENV=!!(*= $rails_env *)!!
set -e
# Check that the Daemon can be run
-su -l -c "cd $SITE_HOME && bundle exec thin --version &> /dev/null || exit 0" $USER
+CURRENT_USER=$(whoami)
+if [ "$CURRENT_USER" = "$USER" ]
+ then
+ cd $SITE_HOME && bundle exec thin --version > /dev/null 2>&1 || exit 0
+ else
+ su -l -c "cd $SITE_HOME && bundle exec thin --version &> /dev/null || exit 0" $USER
+fi
start_daemon() {
echo -n "Starting $DESC: "