##// END OF EJS Templates
auth: only use X- headers instead of REMOTE_ADDR if explicitly told so in remote_addr_header...
Mads Kiilerich -
r8679:3d7ba590 default
parent child Browse files
Show More
@@ -1,512 +1,515 b''
1 ###################################################################################
1 ###################################################################################
2 ###################################################################################
2 ###################################################################################
3 ## Kallithea config file generated with kallithea-cli ##
3 ## Kallithea config file generated with kallithea-cli ##
4 ## ##
4 ## ##
5 ## The %(here)s variable will generally be replaced with the parent directory of ##
5 ## The %(here)s variable will generally be replaced with the parent directory of ##
6 ## this file. Other use of % must be escaped as %% . ##
6 ## this file. Other use of % must be escaped as %% . ##
7 ###################################################################################
7 ###################################################################################
8 ###################################################################################
8 ###################################################################################
9
9
10 [DEFAULT]
10 [DEFAULT]
11
11
12 ################################################################################
12 ################################################################################
13 ## Email settings ##
13 ## Email settings ##
14 ## ##
14 ## ##
15 ## Refer to the documentation ("Email settings") for more details. ##
15 ## Refer to the documentation ("Email settings") for more details. ##
16 ## ##
16 ## ##
17 ## It is recommended to use a valid sender address that passes access ##
17 ## It is recommended to use a valid sender address that passes access ##
18 ## validation and spam filtering in mail servers. ##
18 ## validation and spam filtering in mail servers. ##
19 ################################################################################
19 ################################################################################
20
20
21 ## 'From' header for application emails. You can optionally add a name.
21 ## 'From' header for application emails. You can optionally add a name.
22 ## Default:
22 ## Default:
23 #app_email_from = Kallithea
23 #app_email_from = Kallithea
24 ## Examples:
24 ## Examples:
25 #app_email_from = Kallithea <kallithea-noreply@example.com>
25 #app_email_from = Kallithea <kallithea-noreply@example.com>
26 #app_email_from = kallithea-noreply@example.com
26 #app_email_from = kallithea-noreply@example.com
27
27
28 ## Subject prefix for application emails.
28 ## Subject prefix for application emails.
29 ## A space between this prefix and the real subject is automatically added.
29 ## A space between this prefix and the real subject is automatically added.
30 ## Default:
30 ## Default:
31 #email_prefix =
31 #email_prefix =
32 ## Example:
32 ## Example:
33 #email_prefix = [Kallithea]
33 #email_prefix = [Kallithea]
34
34
35 ## Recipients for error emails and fallback recipients of application mails.
35 ## Recipients for error emails and fallback recipients of application mails.
36 ## Multiple addresses can be specified, comma-separated.
36 ## Multiple addresses can be specified, comma-separated.
37 ## Only addresses are allowed, do not add any name part.
37 ## Only addresses are allowed, do not add any name part.
38 ## Default:
38 ## Default:
39 #email_to =
39 #email_to =
40 ## Examples:
40 ## Examples:
41 #email_to = admin@example.com
41 #email_to = admin@example.com
42 #email_to = admin@example.com,another_admin@example.com
42 #email_to = admin@example.com,another_admin@example.com
43 email_to =
43 email_to =
44
44
45 ## 'From' header for error emails. You can optionally add a name.
45 ## 'From' header for error emails. You can optionally add a name.
46 ## Default: (none)
46 ## Default: (none)
47 ## Examples:
47 ## Examples:
48 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
48 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
49 #error_email_from = kallithea_errors@example.com
49 #error_email_from = kallithea_errors@example.com
50 error_email_from =
50 error_email_from =
51
51
52 ## SMTP server settings
52 ## SMTP server settings
53 ## If specifying credentials, make sure to use secure connections.
53 ## If specifying credentials, make sure to use secure connections.
54 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
54 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
55 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
55 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
56 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
56 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
57 smtp_server =
57 smtp_server =
58 smtp_username =
58 smtp_username =
59 smtp_password =
59 smtp_password =
60 smtp_port =
60 smtp_port =
61 smtp_use_ssl = false
61 smtp_use_ssl = false
62 smtp_use_tls = false
62 smtp_use_tls = false
63
63
64 ## Entry point for 'gearbox serve'
64 ## Entry point for 'gearbox serve'
65 [server:main]
65 [server:main]
66 #host = 127.0.0.1
66 #host = 127.0.0.1
67 host = 0.0.0.0
67 host = 0.0.0.0
68 port = 5000
68 port = 5000
69
69
70 ## Gearbox serve uses the Waitress web server ##
70 ## Gearbox serve uses the Waitress web server ##
71 use = egg:waitress#main
71 use = egg:waitress#main
72 ## avoid multi threading
72 ## avoid multi threading
73 threads = 1
73 threads = 1
74 ## allow push of repos bigger than the default of 1 GB
74 ## allow push of repos bigger than the default of 1 GB
75 max_request_body_size = 107374182400
75 max_request_body_size = 107374182400
76 ## use poll instead of select, fixes fd limits, may not work on old
76 ## use poll instead of select, fixes fd limits, may not work on old
77 ## windows systems.
77 ## windows systems.
78 #asyncore_use_poll = True
78 #asyncore_use_poll = True
79
79
80 ## middleware for hosting the WSGI application under a URL prefix
80 ## middleware for hosting the WSGI application under a URL prefix
81 #[filter:proxy-prefix]
81 #[filter:proxy-prefix]
82 #use = egg:PasteDeploy#prefix
82 #use = egg:PasteDeploy#prefix
83 #prefix = /<your-prefix>
83 #prefix = /<your-prefix>
84
84
85 [app:main]
85 [app:main]
86 use = egg:kallithea
86 use = egg:kallithea
87 ## enable proxy prefix middleware
87 ## enable proxy prefix middleware
88 #filter-with = proxy-prefix
88 #filter-with = proxy-prefix
89
89
90 full_stack = true
90 full_stack = true
91 static_files = true
91 static_files = true
92
92
93 ## Internationalization (see setup documentation for details)
93 ## Internationalization (see setup documentation for details)
94 ## By default, the languages requested by the browser are used if available, with English as default.
94 ## By default, the languages requested by the browser are used if available, with English as default.
95 ## Set i18n.enabled=false to disable automatic language choice.
95 ## Set i18n.enabled=false to disable automatic language choice.
96 #i18n.enabled = true
96 #i18n.enabled = true
97 ## To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
97 ## To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
98 ## Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
98 ## Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
99 #i18n.lang = en
99 #i18n.lang = en
100
100
101 cache_dir = %(here)s/data
101 cache_dir = %(here)s/data
102 index_dir = %(here)s/data/index
102 index_dir = %(here)s/data/index
103
103
104 ## uncomment and set this path to use archive download cache
104 ## uncomment and set this path to use archive download cache
105 archive_cache_dir = %(here)s/data/tarballcache
105 archive_cache_dir = %(here)s/data/tarballcache
106
106
107 ## change this to unique ID for security
107 ## change this to unique ID for security
108 #app_instance_uuid = VERY-SECRET
108 #app_instance_uuid = VERY-SECRET
109 app_instance_uuid = development-not-secret
109 app_instance_uuid = development-not-secret
110
110
111 ## cut off limit for large diffs (size in bytes)
111 ## cut off limit for large diffs (size in bytes)
112 cut_off_limit = 256000
112 cut_off_limit = 256000
113
113
114 ## WSGI environment variable to get the IP address of the client (default REMOTE_ADDR)
115 #remote_addr_variable = HTTP_X_FORWARDED_FOR
116
114 ## always pretend the client connected using HTTPS (default false)
117 ## always pretend the client connected using HTTPS (default false)
115 #force_https = true
118 #force_https = true
116
119
117 ## use Strict-Transport-Security headers (default false)
120 ## use Strict-Transport-Security headers (default false)
118 #use_htsts = true
121 #use_htsts = true
119
122
120 ## number of commits stats will parse on each iteration
123 ## number of commits stats will parse on each iteration
121 commit_parse_limit = 25
124 commit_parse_limit = 25
122
125
123 ## Path to Python executable to be used for git hooks.
126 ## Path to Python executable to be used for git hooks.
124 ## This value will be written inside the git hook scripts as the text
127 ## This value will be written inside the git hook scripts as the text
125 ## after '#!' (shebang). When empty or not defined, the value of
128 ## after '#!' (shebang). When empty or not defined, the value of
126 ## 'sys.executable' at the time of installation of the git hooks is
129 ## 'sys.executable' at the time of installation of the git hooks is
127 ## used, which is correct in many cases but for example not when using uwsgi.
130 ## used, which is correct in many cases but for example not when using uwsgi.
128 ## If you change this setting, you should reinstall the Git hooks via
131 ## If you change this setting, you should reinstall the Git hooks via
129 ## Admin > Settings > Remap and Rescan.
132 ## Admin > Settings > Remap and Rescan.
130 #git_hook_interpreter = /srv/kallithea/venv/bin/python3
133 #git_hook_interpreter = /srv/kallithea/venv/bin/python3
131
134
132 ## path to git executable
135 ## path to git executable
133 git_path = git
136 git_path = git
134
137
135 ## git rev filter option, --all is the default filter, if you need to
138 ## git rev filter option, --all is the default filter, if you need to
136 ## hide all refs in changelog switch this to --branches --tags
139 ## hide all refs in changelog switch this to --branches --tags
137 #git_rev_filter = --branches --tags
140 #git_rev_filter = --branches --tags
138
141
139 ## RSS feed options
142 ## RSS feed options
140 rss_cut_off_limit = 256000
143 rss_cut_off_limit = 256000
141 rss_items_per_page = 10
144 rss_items_per_page = 10
142 rss_include_diff = false
145 rss_include_diff = false
143
146
144 ## options for showing and identifying changesets
147 ## options for showing and identifying changesets
145 show_sha_length = 12
148 show_sha_length = 12
146 show_revision_number = false
149 show_revision_number = false
147
150
148 ## Canonical URL to use when creating full URLs in UI and texts.
151 ## Canonical URL to use when creating full URLs in UI and texts.
149 ## Useful when the site is available under different names or protocols.
152 ## Useful when the site is available under different names or protocols.
150 ## Defaults to what is provided in the WSGI environment.
153 ## Defaults to what is provided in the WSGI environment.
151 #canonical_url = https://kallithea.example.com/repos
154 #canonical_url = https://kallithea.example.com/repos
152
155
153 ## gist URL alias, used to create nicer urls for gist. This should be an
156 ## gist URL alias, used to create nicer urls for gist. This should be an
154 ## url that does rewrites to _admin/gists/<gistid>.
157 ## url that does rewrites to _admin/gists/<gistid>.
155 ## example: http://gist.example.com/{gistid}. Empty means use the internal
158 ## example: http://gist.example.com/{gistid}. Empty means use the internal
156 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
159 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
157 gist_alias_url =
160 gist_alias_url =
158
161
159 ## default encoding used to convert from and to unicode
162 ## default encoding used to convert from and to unicode
160 ## can be also a comma separated list of encoding in case of mixed encodings
163 ## can be also a comma separated list of encoding in case of mixed encodings
161 default_encoding = utf-8
164 default_encoding = utf-8
162
165
163 ## Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
166 ## Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
164 hgencoding = utf-8
167 hgencoding = utf-8
165
168
166 ## issue tracker for Kallithea (leave blank to disable, absent for default)
169 ## issue tracker for Kallithea (leave blank to disable, absent for default)
167 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
170 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
168
171
169 ## issue tracking mapping for commit messages, comments, PR descriptions, ...
172 ## issue tracking mapping for commit messages, comments, PR descriptions, ...
170 ## Refer to the documentation ("Integration with issue trackers") for more details.
173 ## Refer to the documentation ("Integration with issue trackers") for more details.
171
174
172 ## regular expression to match issue references
175 ## regular expression to match issue references
173 ## This pattern may/should contain parenthesized groups, that can
176 ## This pattern may/should contain parenthesized groups, that can
174 ## be referred to in issue_server_link or issue_sub using Python backreferences
177 ## be referred to in issue_server_link or issue_sub using Python backreferences
175 ## (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
178 ## (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
176 ## To require mandatory whitespace before the issue pattern, use:
179 ## To require mandatory whitespace before the issue pattern, use:
177 ## (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
180 ## (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
178 ## behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
181 ## behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
179
182
180 issue_pat = #(\d+)
183 issue_pat = #(\d+)
181
184
182 ## server url to the issue
185 ## server url to the issue
183 ## This pattern may/should contain backreferences to parenthesized groups in issue_pat.
186 ## This pattern may/should contain backreferences to parenthesized groups in issue_pat.
184 ## A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
187 ## A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
185 ## called 'groupname' in issue_pat.
188 ## called 'groupname' in issue_pat.
186 ## The special token {repo} is replaced with the full repository name
189 ## The special token {repo} is replaced with the full repository name
187 ## including repository groups, while {repo_name} is replaced with just
190 ## including repository groups, while {repo_name} is replaced with just
188 ## the name of the repository.
191 ## the name of the repository.
189
192
190 issue_server_link = https://issues.example.com/{repo}/issue/\1
193 issue_server_link = https://issues.example.com/{repo}/issue/\1
191
194
192 ## substitution pattern to use as the link text
195 ## substitution pattern to use as the link text
193 ## If issue_sub is empty, the text matched by issue_pat is retained verbatim
196 ## If issue_sub is empty, the text matched by issue_pat is retained verbatim
194 ## for the link text. Otherwise, the link text is that of issue_sub, with any
197 ## for the link text. Otherwise, the link text is that of issue_sub, with any
195 ## backreferences to groups in issue_pat replaced.
198 ## backreferences to groups in issue_pat replaced.
196
199
197 issue_sub =
200 issue_sub =
198
201
199 ## issue_pat, issue_server_link and issue_sub can have suffixes to specify
202 ## issue_pat, issue_server_link and issue_sub can have suffixes to specify
200 ## multiple patterns, to other issues server, wiki or others
203 ## multiple patterns, to other issues server, wiki or others
201 ## below an example how to create a wiki pattern
204 ## below an example how to create a wiki pattern
202 ## wiki-some-id -> https://wiki.example.com/some-id
205 ## wiki-some-id -> https://wiki.example.com/some-id
203
206
204 #issue_pat_wiki = wiki-(\S+)
207 #issue_pat_wiki = wiki-(\S+)
205 #issue_server_link_wiki = https://wiki.example.com/\1
208 #issue_server_link_wiki = https://wiki.example.com/\1
206 #issue_sub_wiki = WIKI-\1
209 #issue_sub_wiki = WIKI-\1
207
210
208 ## alternative return HTTP header for failed authentication. Default HTTP
211 ## alternative return HTTP header for failed authentication. Default HTTP
209 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
212 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
210 ## handling that. Set this variable to 403 to return HTTPForbidden
213 ## handling that. Set this variable to 403 to return HTTPForbidden
211 auth_ret_code =
214 auth_ret_code =
212
215
213 ## allows to change the repository location in settings page
216 ## allows to change the repository location in settings page
214 allow_repo_location_change = True
217 allow_repo_location_change = True
215
218
216 ## allows to setup custom hooks in settings page
219 ## allows to setup custom hooks in settings page
217 allow_custom_hooks_settings = True
220 allow_custom_hooks_settings = True
218
221
219 ## extra extensions for indexing, space separated and without the leading '.'.
222 ## extra extensions for indexing, space separated and without the leading '.'.
220 #index.extensions =
223 #index.extensions =
221 # gemfile
224 # gemfile
222 # lock
225 # lock
223
226
224 ## extra filenames for indexing, space separated
227 ## extra filenames for indexing, space separated
225 #index.filenames =
228 #index.filenames =
226 # .dockerignore
229 # .dockerignore
227 # .editorconfig
230 # .editorconfig
228 # INSTALL
231 # INSTALL
229 # CHANGELOG
232 # CHANGELOG
230
233
231 ####################################
234 ####################################
232 ## SSH CONFIG ##
235 ## SSH CONFIG ##
233 ####################################
236 ####################################
234
237
235 ## SSH is disabled by default, until an Administrator decides to enable it.
238 ## SSH is disabled by default, until an Administrator decides to enable it.
236 ssh_enabled = false
239 ssh_enabled = false
237
240
238 ## File where users' SSH keys will be stored *if* ssh_enabled is true.
241 ## File where users' SSH keys will be stored *if* ssh_enabled is true.
239 #ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
242 #ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
240
243
241 ## Path to be used in ssh_authorized_keys file to invoke kallithea-cli with ssh-serve.
244 ## Path to be used in ssh_authorized_keys file to invoke kallithea-cli with ssh-serve.
242 #kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
245 #kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
243
246
244 ## Locale to be used in the ssh-serve command.
247 ## Locale to be used in the ssh-serve command.
245 ## This is needed because an SSH client may try to use its own locale
248 ## This is needed because an SSH client may try to use its own locale
246 ## settings, which may not be available on the server.
249 ## settings, which may not be available on the server.
247 ## See `locale -a` for valid values on this system.
250 ## See `locale -a` for valid values on this system.
248 #ssh_locale = C.UTF-8
251 #ssh_locale = C.UTF-8
249
252
250 ####################################
253 ####################################
251 ## CELERY CONFIG ##
254 ## CELERY CONFIG ##
252 ####################################
255 ####################################
253
256
254 ## Note: Celery doesn't support Windows.
257 ## Note: Celery doesn't support Windows.
255 use_celery = false
258 use_celery = false
256
259
257 ## Celery config settings from https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html prefixed with 'celery.'.
260 ## Celery config settings from https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html prefixed with 'celery.'.
258
261
259 ## Example: use the message queue on the local virtual host 'kallitheavhost' as the RabbitMQ user 'kallithea':
262 ## Example: use the message queue on the local virtual host 'kallitheavhost' as the RabbitMQ user 'kallithea':
260 celery.broker_url = amqp://kallithea:thepassword@localhost:5672/kallitheavhost
263 celery.broker_url = amqp://kallithea:thepassword@localhost:5672/kallitheavhost
261
264
262 celery.worker_concurrency = 2
265 celery.worker_concurrency = 2
263 celery.worker_max_tasks_per_child = 100
266 celery.worker_max_tasks_per_child = 100
264
267
265 ####################################
268 ####################################
266 ## BEAKER CACHE ##
269 ## BEAKER CACHE ##
267 ####################################
270 ####################################
268
271
269 beaker.cache.data_dir = %(here)s/data/cache/data
272 beaker.cache.data_dir = %(here)s/data/cache/data
270 beaker.cache.lock_dir = %(here)s/data/cache/lock
273 beaker.cache.lock_dir = %(here)s/data/cache/lock
271
274
272 beaker.cache.regions = long_term,long_term_file
275 beaker.cache.regions = long_term,long_term_file
273
276
274 beaker.cache.long_term.type = memory
277 beaker.cache.long_term.type = memory
275 beaker.cache.long_term.expire = 36000
278 beaker.cache.long_term.expire = 36000
276 beaker.cache.long_term.key_length = 256
279 beaker.cache.long_term.key_length = 256
277
280
278 beaker.cache.long_term_file.type = file
281 beaker.cache.long_term_file.type = file
279 beaker.cache.long_term_file.expire = 604800
282 beaker.cache.long_term_file.expire = 604800
280 beaker.cache.long_term_file.key_length = 256
283 beaker.cache.long_term_file.key_length = 256
281
284
282 ####################################
285 ####################################
283 ## BEAKER SESSION ##
286 ## BEAKER SESSION ##
284 ####################################
287 ####################################
285
288
286 ## Name of session cookie. Should be unique for a given host and path, even when running
289 ## Name of session cookie. Should be unique for a given host and path, even when running
287 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
290 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
288 session.key = kallithea
291 session.key = kallithea
289 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
292 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
290 session.httponly = true
293 session.httponly = true
291 ## Session lifetime. 2592000 seconds is 30 days.
294 ## Session lifetime. 2592000 seconds is 30 days.
292 session.timeout = 2592000
295 session.timeout = 2592000
293
296
294 ## Server secret used with HMAC to ensure integrity of cookies.
297 ## Server secret used with HMAC to ensure integrity of cookies.
295 #session.secret = VERY-SECRET
298 #session.secret = VERY-SECRET
296 session.secret = development-not-secret
299 session.secret = development-not-secret
297 ## Further, encrypt the data with AES.
300 ## Further, encrypt the data with AES.
298 #session.encrypt_key = <key_for_encryption>
301 #session.encrypt_key = <key_for_encryption>
299 #session.validate_key = <validation_key>
302 #session.validate_key = <validation_key>
300
303
301 ## Type of storage used for the session, current types are
304 ## Type of storage used for the session, current types are
302 ## dbm, file, memcached, database, and memory.
305 ## dbm, file, memcached, database, and memory.
303
306
304 ## File system storage of session data. (default)
307 ## File system storage of session data. (default)
305 #session.type = file
308 #session.type = file
306
309
307 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
310 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
308 #session.type = cookie
311 #session.type = cookie
309
312
310 ## Database storage of session data.
313 ## Database storage of session data.
311 #session.type = ext:database
314 #session.type = ext:database
312 #session.sa.url = postgresql://postgres:qwe@localhost/kallithea
315 #session.sa.url = postgresql://postgres:qwe@localhost/kallithea
313 #session.table_name = db_session
316 #session.table_name = db_session
314
317
315 ####################################
318 ####################################
316 ## ERROR HANDLING ##
319 ## ERROR HANDLING ##
317 ####################################
320 ####################################
318
321
319 ## Show a nice error page for application HTTP errors and exceptions (default true)
322 ## Show a nice error page for application HTTP errors and exceptions (default true)
320 #errorpage.enabled = true
323 #errorpage.enabled = true
321
324
322 ## Enable Backlash client-side interactive debugger (default false)
325 ## Enable Backlash client-side interactive debugger (default false)
323 ## WARNING: *THIS MUST BE false IN PRODUCTION ENVIRONMENTS!!!*
326 ## WARNING: *THIS MUST BE false IN PRODUCTION ENVIRONMENTS!!!*
324 ## This debug mode will allow all visitors to execute malicious code.
327 ## This debug mode will allow all visitors to execute malicious code.
325 #debug = false
328 #debug = false
326 debug = true
329 debug = true
327
330
328 ## Enable Backlash server-side error reporting (unless debug mode handles it client-side) (default true)
331 ## Enable Backlash server-side error reporting (unless debug mode handles it client-side) (default true)
329 #trace_errors.enable = true
332 #trace_errors.enable = true
330 ## Errors will be reported by mail if trace_errors.error_email is set.
333 ## Errors will be reported by mail if trace_errors.error_email is set.
331
334
332 ## Propagate email settings to ErrorReporter of TurboGears2
335 ## Propagate email settings to ErrorReporter of TurboGears2
333 ## You do not normally need to change these lines
336 ## You do not normally need to change these lines
334 get trace_errors.smtp_server = smtp_server
337 get trace_errors.smtp_server = smtp_server
335 get trace_errors.smtp_port = smtp_port
338 get trace_errors.smtp_port = smtp_port
336 get trace_errors.from_address = error_email_from
339 get trace_errors.from_address = error_email_from
337 get trace_errors.error_email = email_to
340 get trace_errors.error_email = email_to
338 get trace_errors.smtp_username = smtp_username
341 get trace_errors.smtp_username = smtp_username
339 get trace_errors.smtp_password = smtp_password
342 get trace_errors.smtp_password = smtp_password
340 get trace_errors.smtp_use_tls = smtp_use_tls
343 get trace_errors.smtp_use_tls = smtp_use_tls
341
344
342 ##################################
345 ##################################
343 ## LOGVIEW CONFIG ##
346 ## LOGVIEW CONFIG ##
344 ##################################
347 ##################################
345
348
346 logview.sqlalchemy = #faa
349 logview.sqlalchemy = #faa
347 logview.pylons.templating = #bfb
350 logview.pylons.templating = #bfb
348 logview.pylons.util = #eee
351 logview.pylons.util = #eee
349
352
350 #########################
353 #########################
351 ## DB CONFIG ##
354 ## DB CONFIG ##
352 #########################
355 #########################
353
356
354 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
357 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
355 #sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
358 #sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
356 #sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
359 #sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
357 ## Note: the mysql:// prefix should also be used for MariaDB
360 ## Note: the mysql:// prefix should also be used for MariaDB
358
361
359 sqlalchemy.pool_recycle = 3600
362 sqlalchemy.pool_recycle = 3600
360
363
361 ################################
364 ################################
362 ## ALEMBIC CONFIGURATION ##
365 ## ALEMBIC CONFIGURATION ##
363 ################################
366 ################################
364
367
365 [alembic]
368 [alembic]
366 script_location = kallithea:alembic
369 script_location = kallithea:alembic
367
370
368 ################################
371 ################################
369 ## LOGGING CONFIGURATION ##
372 ## LOGGING CONFIGURATION ##
370 ################################
373 ################################
371
374
372 [loggers]
375 [loggers]
373 keys = root, routes, kallithea, sqlalchemy, tg, gearbox, beaker, templates, whoosh_indexer, werkzeug, backlash
376 keys = root, routes, kallithea, sqlalchemy, tg, gearbox, beaker, templates, whoosh_indexer, werkzeug, backlash
374
377
375 [handlers]
378 [handlers]
376 keys = console, console_color, console_color_sql, null
379 keys = console, console_color, console_color_sql, null
377
380
378 [formatters]
381 [formatters]
379 keys = generic, color_formatter, color_formatter_sql
382 keys = generic, color_formatter, color_formatter_sql
380
383
381 #############
384 #############
382 ## LOGGERS ##
385 ## LOGGERS ##
383 #############
386 #############
384
387
385 [logger_root]
388 [logger_root]
386 level = NOTSET
389 level = NOTSET
387 #handlers = console
390 #handlers = console
388 ## For coloring based on log level:
391 ## For coloring based on log level:
389 handlers = console_color
392 handlers = console_color
390
393
391 [logger_routes]
394 [logger_routes]
392 #level = WARN
395 #level = WARN
393 level = DEBUG
396 level = DEBUG
394 handlers =
397 handlers =
395 qualname = routes.middleware
398 qualname = routes.middleware
396 ## "level = DEBUG" logs the route matched and routing variables.
399 ## "level = DEBUG" logs the route matched and routing variables.
397
400
398 [logger_beaker]
401 [logger_beaker]
399 #level = WARN
402 #level = WARN
400 level = DEBUG
403 level = DEBUG
401 handlers =
404 handlers =
402 qualname = beaker.container
405 qualname = beaker.container
403
406
404 [logger_templates]
407 [logger_templates]
405 #level = WARN
408 #level = WARN
406 level = INFO
409 level = INFO
407 handlers =
410 handlers =
408 qualname = pylons.templating
411 qualname = pylons.templating
409
412
410 [logger_kallithea]
413 [logger_kallithea]
411 #level = WARN
414 #level = WARN
412 level = DEBUG
415 level = DEBUG
413 handlers =
416 handlers =
414 qualname = kallithea
417 qualname = kallithea
415
418
416 [logger_tg]
419 [logger_tg]
417 #level = WARN
420 #level = WARN
418 level = DEBUG
421 level = DEBUG
419 handlers =
422 handlers =
420 qualname = tg
423 qualname = tg
421
424
422 [logger_gearbox]
425 [logger_gearbox]
423 #level = WARN
426 #level = WARN
424 level = DEBUG
427 level = DEBUG
425 handlers =
428 handlers =
426 qualname = gearbox
429 qualname = gearbox
427
430
428 [logger_sqlalchemy]
431 [logger_sqlalchemy]
429 level = WARN
432 level = WARN
430 handlers =
433 handlers =
431 qualname = sqlalchemy.engine
434 qualname = sqlalchemy.engine
432 ## For coloring based on log level and pretty printing of SQL:
435 ## For coloring based on log level and pretty printing of SQL:
433 #level = INFO
436 #level = INFO
434 #handlers = console_color_sql
437 #handlers = console_color_sql
435 #propagate = 0
438 #propagate = 0
436
439
437 [logger_whoosh_indexer]
440 [logger_whoosh_indexer]
438 #level = WARN
441 #level = WARN
439 level = DEBUG
442 level = DEBUG
440 handlers =
443 handlers =
441 qualname = whoosh_indexer
444 qualname = whoosh_indexer
442
445
443 [logger_werkzeug]
446 [logger_werkzeug]
444 level = WARN
447 level = WARN
445 handlers =
448 handlers =
446 qualname = werkzeug
449 qualname = werkzeug
447
450
448 [logger_backlash]
451 [logger_backlash]
449 level = WARN
452 level = WARN
450 handlers =
453 handlers =
451 qualname = backlash
454 qualname = backlash
452
455
453 ##############
456 ##############
454 ## HANDLERS ##
457 ## HANDLERS ##
455 ##############
458 ##############
456
459
457 [handler_console]
460 [handler_console]
458 class = StreamHandler
461 class = StreamHandler
459 args = (sys.stderr,)
462 args = (sys.stderr,)
460 formatter = generic
463 formatter = generic
461
464
462 [handler_console_color]
465 [handler_console_color]
463 ## ANSI color coding based on log level
466 ## ANSI color coding based on log level
464 class = StreamHandler
467 class = StreamHandler
465 args = (sys.stderr,)
468 args = (sys.stderr,)
466 formatter = color_formatter
469 formatter = color_formatter
467
470
468 [handler_console_color_sql]
471 [handler_console_color_sql]
469 ## ANSI color coding and pretty printing of SQL statements
472 ## ANSI color coding and pretty printing of SQL statements
470 class = StreamHandler
473 class = StreamHandler
471 args = (sys.stderr,)
474 args = (sys.stderr,)
472 formatter = color_formatter_sql
475 formatter = color_formatter_sql
473
476
474 [handler_null]
477 [handler_null]
475 class = NullHandler
478 class = NullHandler
476 args = ()
479 args = ()
477
480
478 ################
481 ################
479 ## FORMATTERS ##
482 ## FORMATTERS ##
480 ################
483 ################
481
484
482 [formatter_generic]
485 [formatter_generic]
483 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
486 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
484 datefmt = %Y-%m-%d %H:%M:%S
487 datefmt = %Y-%m-%d %H:%M:%S
485
488
486 [formatter_color_formatter]
489 [formatter_color_formatter]
487 class = kallithea.lib.colored_formatter.ColorFormatter
490 class = kallithea.lib.colored_formatter.ColorFormatter
488 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
491 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
489 datefmt = %Y-%m-%d %H:%M:%S
492 datefmt = %Y-%m-%d %H:%M:%S
490
493
491 [formatter_color_formatter_sql]
494 [formatter_color_formatter_sql]
492 class = kallithea.lib.colored_formatter.ColorFormatterSql
495 class = kallithea.lib.colored_formatter.ColorFormatterSql
493 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
496 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
494 datefmt = %Y-%m-%d %H:%M:%S
497 datefmt = %Y-%m-%d %H:%M:%S
495
498
496 #################
499 #################
497 ## SSH LOGGING ##
500 ## SSH LOGGING ##
498 #################
501 #################
499
502
500 ## The default loggers use 'handler_console' that uses StreamHandler with
503 ## The default loggers use 'handler_console' that uses StreamHandler with
501 ## destination 'sys.stderr'. In the context of the SSH server process, these log
504 ## destination 'sys.stderr'. In the context of the SSH server process, these log
502 ## messages would be sent to the client, which is normally not what you want.
505 ## messages would be sent to the client, which is normally not what you want.
503 ## By default, when running ssh-serve, just use NullHandler and disable logging
506 ## By default, when running ssh-serve, just use NullHandler and disable logging
504 ## completely. For other logging options, see:
507 ## completely. For other logging options, see:
505 ## https://docs.python.org/2/library/logging.handlers.html
508 ## https://docs.python.org/2/library/logging.handlers.html
506
509
507 [ssh_serve:logger_root]
510 [ssh_serve:logger_root]
508 level = CRITICAL
511 level = CRITICAL
509 handlers = null
512 handlers = null
510
513
511 ## Note: If logging is configured with other handlers, they might need similar
514 ## Note: If logging is configured with other handlers, they might need similar
512 ## muting for ssh-serve too.
515 ## muting for ssh-serve too.
@@ -1,688 +1,692 b''
1 .. _setup:
1 .. _setup:
2
2
3 =====
3 =====
4 Setup
4 Setup
5 =====
5 =====
6
6
7
7
8 Setting up a Kallithea instance
8 Setting up a Kallithea instance
9 -------------------------------
9 -------------------------------
10
10
11 Some further details to the steps mentioned in the overview.
11 Some further details to the steps mentioned in the overview.
12
12
13 Create low level configuration file
13 Create low level configuration file
14 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15
15
16 First, you will need to create a Kallithea configuration file. The
16 First, you will need to create a Kallithea configuration file. The
17 configuration file is a ``.ini`` file that contains various low level settings
17 configuration file is a ``.ini`` file that contains various low level settings
18 for Kallithea, e.g. configuration of how to use database, web server, email,
18 for Kallithea, e.g. configuration of how to use database, web server, email,
19 and logging.
19 and logging.
20
20
21 Change to the desired directory (such as ``/srv/kallithea``) as the right user
21 Change to the desired directory (such as ``/srv/kallithea``) as the right user
22 and run the following command to create the file ``my.ini`` in the current
22 and run the following command to create the file ``my.ini`` in the current
23 directory::
23 directory::
24
24
25 kallithea-cli config-create my.ini http_server=waitress
25 kallithea-cli config-create my.ini http_server=waitress
26
26
27 To get a good starting point for your configuration, specify the http server
27 To get a good starting point for your configuration, specify the http server
28 you intend to use. It can be ``waitress``, ``gearbox``, ``gevent``,
28 you intend to use. It can be ``waitress``, ``gearbox``, ``gevent``,
29 ``gunicorn``, or ``uwsgi``. (Apache ``mod_wsgi`` will not use this
29 ``gunicorn``, or ``uwsgi``. (Apache ``mod_wsgi`` will not use this
30 configuration file, and it is fine to keep the default http_server configuration
30 configuration file, and it is fine to keep the default http_server configuration
31 unused. ``mod_wsgi`` is configured using ``httpd.conf`` directives and a WSGI
31 unused. ``mod_wsgi`` is configured using ``httpd.conf`` directives and a WSGI
32 wrapper script.)
32 wrapper script.)
33
33
34 Extra custom settings can be specified like::
34 Extra custom settings can be specified like::
35
35
36 kallithea-cli config-create my.ini host=8.8.8.8 "[handler_console]" formatter=color_formatter
36 kallithea-cli config-create my.ini host=8.8.8.8 "[handler_console]" formatter=color_formatter
37
37
38 Populate the database
38 Populate the database
39 ^^^^^^^^^^^^^^^^^^^^^
39 ^^^^^^^^^^^^^^^^^^^^^
40
40
41 Next, you need to create the databases used by Kallithea. Kallithea currently
41 Next, you need to create the databases used by Kallithea. Kallithea currently
42 supports PostgreSQL, SQLite and MariaDB/MySQL databases. It is recommended to
42 supports PostgreSQL, SQLite and MariaDB/MySQL databases. It is recommended to
43 start out using SQLite (the default) and move to PostgreSQL if it becomes a
43 start out using SQLite (the default) and move to PostgreSQL if it becomes a
44 bottleneck or to get a "proper" database. MariaDB/MySQL is also supported.
44 bottleneck or to get a "proper" database. MariaDB/MySQL is also supported.
45
45
46 For PostgreSQL, run ``pip install psycopg2`` to get the database driver. Make
46 For PostgreSQL, run ``pip install psycopg2`` to get the database driver. Make
47 sure the PostgreSQL server is initialized and running. Make sure you have a
47 sure the PostgreSQL server is initialized and running. Make sure you have a
48 database user with password authentication with permissions to create databases
48 database user with password authentication with permissions to create databases
49 - for example by running::
49 - for example by running::
50
50
51 sudo -u postgres createuser 'kallithea' --pwprompt --createdb
51 sudo -u postgres createuser 'kallithea' --pwprompt --createdb
52
52
53 For MariaDB/MySQL, run ``pip install mysqlclient`` to get the ``MySQLdb``
53 For MariaDB/MySQL, run ``pip install mysqlclient`` to get the ``MySQLdb``
54 database driver. Make sure the database server is initialized and running. Make
54 database driver. Make sure the database server is initialized and running. Make
55 sure you have a database user with password authentication with permissions to
55 sure you have a database user with password authentication with permissions to
56 create the database - for example by running::
56 create the database - for example by running::
57
57
58 echo 'CREATE USER "kallithea"@"localhost" IDENTIFIED BY "password"' | sudo -u mysql mysql
58 echo 'CREATE USER "kallithea"@"localhost" IDENTIFIED BY "password"' | sudo -u mysql mysql
59 echo 'GRANT ALL PRIVILEGES ON `kallithea`.* TO "kallithea"@"localhost"' | sudo -u mysql mysql
59 echo 'GRANT ALL PRIVILEGES ON `kallithea`.* TO "kallithea"@"localhost"' | sudo -u mysql mysql
60
60
61 Check and adjust ``sqlalchemy.url`` in your ``my.ini`` configuration file to use
61 Check and adjust ``sqlalchemy.url`` in your ``my.ini`` configuration file to use
62 this database.
62 this database.
63
63
64 Create the database, tables, and initial content by running the following
64 Create the database, tables, and initial content by running the following
65 command::
65 command::
66
66
67 kallithea-cli db-create -c my.ini
67 kallithea-cli db-create -c my.ini
68
68
69 This will first prompt you for a "root" path. This "root" path is the location
69 This will first prompt you for a "root" path. This "root" path is the location
70 where Kallithea will store all of its repositories on the current machine. This
70 where Kallithea will store all of its repositories on the current machine. This
71 location must be writable for the running Kallithea application. Next,
71 location must be writable for the running Kallithea application. Next,
72 ``db-create`` will prompt you for a username and password for the initial admin
72 ``db-create`` will prompt you for a username and password for the initial admin
73 account it sets up for you.
73 account it sets up for you.
74
74
75 The ``db-create`` values can also be given on the command line.
75 The ``db-create`` values can also be given on the command line.
76 Example::
76 Example::
77
77
78 kallithea-cli db-create -c my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
78 kallithea-cli db-create -c my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
79
79
80 The ``db-create`` command will create all needed tables and an
80 The ``db-create`` command will create all needed tables and an
81 admin account. When choosing a root path you can either use a new
81 admin account. When choosing a root path you can either use a new
82 empty location, or a location which already contains existing
82 empty location, or a location which already contains existing
83 repositories. If you choose a location which contains existing
83 repositories. If you choose a location which contains existing
84 repositories Kallithea will add all of the repositories at the chosen
84 repositories Kallithea will add all of the repositories at the chosen
85 location to its database. (Note: make sure you specify the correct
85 location to its database. (Note: make sure you specify the correct
86 path to the root).
86 path to the root).
87
87
88 .. note:: It is also possible to use an existing database. For example,
88 .. note:: It is also possible to use an existing database. For example,
89 when using PostgreSQL without granting general createdb privileges to
89 when using PostgreSQL without granting general createdb privileges to
90 the PostgreSQL kallithea user, set ``sqlalchemy.url =
90 the PostgreSQL kallithea user, set ``sqlalchemy.url =
91 postgresql://kallithea:password@localhost/kallithea`` and create the
91 postgresql://kallithea:password@localhost/kallithea`` and create the
92 database like::
92 database like::
93
93
94 sudo -u postgres createdb 'kallithea' --owner 'kallithea'
94 sudo -u postgres createdb 'kallithea' --owner 'kallithea'
95 kallithea-cli db-create -c my.ini --reuse
95 kallithea-cli db-create -c my.ini --reuse
96
96
97 Running
97 Running
98 ^^^^^^^
98 ^^^^^^^
99
99
100 You are now ready to use Kallithea. To run it using a gearbox web server,
100 You are now ready to use Kallithea. To run it using a gearbox web server,
101 simply execute::
101 simply execute::
102
102
103 gearbox serve -c my.ini
103 gearbox serve -c my.ini
104
104
105 - This command runs the Kallithea server. The web app should be available at
105 - This command runs the Kallithea server. The web app should be available at
106 http://127.0.0.1:5000. The IP address and port is configurable via the
106 http://127.0.0.1:5000. The IP address and port is configurable via the
107 configuration file created in the previous step.
107 configuration file created in the previous step.
108 - Log in to Kallithea using the admin account created when running ``db-create``.
108 - Log in to Kallithea using the admin account created when running ``db-create``.
109 - The default permissions on each repository is read, and the owner is admin.
109 - The default permissions on each repository is read, and the owner is admin.
110 Remember to update these if needed.
110 Remember to update these if needed.
111 - In the admin panel you can toggle LDAP, anonymous, and permissions
111 - In the admin panel you can toggle LDAP, anonymous, and permissions
112 settings, as well as edit more advanced options on users and
112 settings, as well as edit more advanced options on users and
113 repositories.
113 repositories.
114
114
115
115
116 Internationalization (i18n support)
116 Internationalization (i18n support)
117 -----------------------------------
117 -----------------------------------
118
118
119 The Kallithea web interface is automatically displayed in the user's preferred
119 The Kallithea web interface is automatically displayed in the user's preferred
120 language, as indicated by the browser. Thus, different users may see the
120 language, as indicated by the browser. Thus, different users may see the
121 application in different languages. If the requested language is not available
121 application in different languages. If the requested language is not available
122 (because the translation file for that language does not yet exist or is
122 (because the translation file for that language does not yet exist or is
123 incomplete), English is used.
123 incomplete), English is used.
124
124
125 If you want to disable automatic language detection and instead configure a
125 If you want to disable automatic language detection and instead configure a
126 fixed language regardless of user preference, set ``i18n.enabled = false`` and
126 fixed language regardless of user preference, set ``i18n.enabled = false`` and
127 specify another language by setting ``i18n.lang`` in the Kallithea
127 specify another language by setting ``i18n.lang`` in the Kallithea
128 configuration file.
128 configuration file.
129
129
130
130
131 Using Kallithea with SSH
131 Using Kallithea with SSH
132 ------------------------
132 ------------------------
133
133
134 Kallithea supports repository access via SSH key based authentication.
134 Kallithea supports repository access via SSH key based authentication.
135 This means:
135 This means:
136
136
137 - repository URLs like ``ssh://kallithea@example.com/name/of/repository``
137 - repository URLs like ``ssh://kallithea@example.com/name/of/repository``
138
138
139 - all network traffic for both read and write happens over the SSH protocol on
139 - all network traffic for both read and write happens over the SSH protocol on
140 port 22, without using HTTP/HTTPS nor the Kallithea WSGI application
140 port 22, without using HTTP/HTTPS nor the Kallithea WSGI application
141
141
142 - encryption and authentication protocols are managed by the system's ``sshd``
142 - encryption and authentication protocols are managed by the system's ``sshd``
143 process, with all users using the same Kallithea system user (e.g.
143 process, with all users using the same Kallithea system user (e.g.
144 ``kallithea``) when connecting to the SSH server, but with users' public keys
144 ``kallithea``) when connecting to the SSH server, but with users' public keys
145 in the Kallithea system user's `.ssh/authorized_keys` file granting each user
145 in the Kallithea system user's `.ssh/authorized_keys` file granting each user
146 sandboxed access to the repositories.
146 sandboxed access to the repositories.
147
147
148 - users and admins can manage SSH public keys in the web UI
148 - users and admins can manage SSH public keys in the web UI
149
149
150 - in their SSH client configuration, users can configure how the client should
150 - in their SSH client configuration, users can configure how the client should
151 control access to their SSH key - without passphrase, with passphrase, and
151 control access to their SSH key - without passphrase, with passphrase, and
152 optionally with passphrase caching in the local shell session (``ssh-agent``).
152 optionally with passphrase caching in the local shell session (``ssh-agent``).
153 This is standard SSH functionality, not something Kallithea provides or
153 This is standard SSH functionality, not something Kallithea provides or
154 interferes with.
154 interferes with.
155
155
156 - network communication between client and server happens in a bidirectional
156 - network communication between client and server happens in a bidirectional
157 stateful stream, and will in some cases be faster than HTTP/HTTPS with several
157 stateful stream, and will in some cases be faster than HTTP/HTTPS with several
158 stateless round-trips.
158 stateless round-trips.
159
159
160 .. note:: At this moment, repository access via SSH has been tested on Unix
160 .. note:: At this moment, repository access via SSH has been tested on Unix
161 only. Windows users that care about SSH are invited to test it and report
161 only. Windows users that care about SSH are invited to test it and report
162 problems, ideally contributing patches that solve these problems.
162 problems, ideally contributing patches that solve these problems.
163
163
164 Users and admins can upload SSH public keys (e.g. ``.ssh/id_rsa.pub``) through
164 Users and admins can upload SSH public keys (e.g. ``.ssh/id_rsa.pub``) through
165 the web interface. The server's ``.ssh/authorized_keys`` file is automatically
165 the web interface. The server's ``.ssh/authorized_keys`` file is automatically
166 maintained with an entry for each SSH key. Each entry will tell ``sshd`` to run
166 maintained with an entry for each SSH key. Each entry will tell ``sshd`` to run
167 ``kallithea-cli`` with the ``ssh-serve`` sub-command and the right Kallithea user ID
167 ``kallithea-cli`` with the ``ssh-serve`` sub-command and the right Kallithea user ID
168 when encountering the corresponding SSH key.
168 when encountering the corresponding SSH key.
169
169
170 To enable SSH repository access, Kallithea must be configured with the path to
170 To enable SSH repository access, Kallithea must be configured with the path to
171 the ``.ssh/authorized_keys`` file for the Kallithea user, and the path to the
171 the ``.ssh/authorized_keys`` file for the Kallithea user, and the path to the
172 ``kallithea-cli`` command. Put something like this in the ``.ini`` file::
172 ``kallithea-cli`` command. Put something like this in the ``.ini`` file::
173
173
174 ssh_enabled = true
174 ssh_enabled = true
175 ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
175 ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
176 kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
176 kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
177
177
178 The SSH service must be running, and the Kallithea user account must be active
178 The SSH service must be running, and the Kallithea user account must be active
179 (not necessarily with password access, but public key access must be enabled),
179 (not necessarily with password access, but public key access must be enabled),
180 all file permissions must be set as sshd wants it, and ``authorized_keys`` must
180 all file permissions must be set as sshd wants it, and ``authorized_keys`` must
181 be writeable by the Kallithea user.
181 be writeable by the Kallithea user.
182
182
183 .. note:: The ``authorized_keys`` file will be rewritten from scratch on
183 .. note:: The ``authorized_keys`` file will be rewritten from scratch on
184 each update. If it already exists with other data, Kallithea will not
184 each update. If it already exists with other data, Kallithea will not
185 overwrite the existing ``authorized_keys``, and the server process will
185 overwrite the existing ``authorized_keys``, and the server process will
186 instead throw an exception. The system administrator thus cannot ssh
186 instead throw an exception. The system administrator thus cannot ssh
187 directly to the Kallithea user but must use su/sudo from another account.
187 directly to the Kallithea user but must use su/sudo from another account.
188
188
189 If ``/home/kallithea/.ssh/`` (the directory of the path specified in the
189 If ``/home/kallithea/.ssh/`` (the directory of the path specified in the
190 ``ssh_authorized_keys`` setting of the ``.ini`` file) does not exist as a
190 ``ssh_authorized_keys`` setting of the ``.ini`` file) does not exist as a
191 directory, Kallithea will attempt to create it. If that path exists but is
191 directory, Kallithea will attempt to create it. If that path exists but is
192 *not* a directory, or is not readable-writable-executable by the server
192 *not* a directory, or is not readable-writable-executable by the server
193 process, the server process will raise an exception each time it attempts to
193 process, the server process will raise an exception each time it attempts to
194 write the ``authorized_keys`` file.
194 write the ``authorized_keys`` file.
195
195
196 .. note:: It is possible to configure the SSH server to look for authorized
196 .. note:: It is possible to configure the SSH server to look for authorized
197 keys in multiple files, for example reserving ``ssh/authorized_keys`` to be
197 keys in multiple files, for example reserving ``ssh/authorized_keys`` to be
198 used for normal SSH and with Kallithea using
198 used for normal SSH and with Kallithea using
199 ``.ssh/authorized_keys_kallithea``. In ``/etc/ssh/sshd_config`` set
199 ``.ssh/authorized_keys_kallithea``. In ``/etc/ssh/sshd_config`` set
200 ``AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys_kallithea``
200 ``AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys_kallithea``
201 and restart sshd, and in ``my.ini`` set ``ssh_authorized_keys =
201 and restart sshd, and in ``my.ini`` set ``ssh_authorized_keys =
202 /home/kallithea/.ssh/authorized_keys_kallithea``. Note that this new
202 /home/kallithea/.ssh/authorized_keys_kallithea``. Note that this new
203 location will apply to all system users, and that multiple entries for the
203 location will apply to all system users, and that multiple entries for the
204 same SSH key will shadow each other.
204 same SSH key will shadow each other.
205
205
206 .. warning:: The handling of SSH access is steered directly by the command
206 .. warning:: The handling of SSH access is steered directly by the command
207 specified in the ``authorized_keys`` file. There is no interaction with the
207 specified in the ``authorized_keys`` file. There is no interaction with the
208 web UI. Once SSH access is correctly configured and enabled, it will work
208 web UI. Once SSH access is correctly configured and enabled, it will work
209 regardless of whether the Kallithea web process is actually running. Hence,
209 regardless of whether the Kallithea web process is actually running. Hence,
210 if you want to perform repository or server maintenance and want to fully
210 if you want to perform repository or server maintenance and want to fully
211 disable all access to the repositories, disable SSH access by setting
211 disable all access to the repositories, disable SSH access by setting
212 ``ssh_enabled = false`` in the correct ``.ini`` file (i.e. the ``.ini`` file
212 ``ssh_enabled = false`` in the correct ``.ini`` file (i.e. the ``.ini`` file
213 specified in the ``authorized_keys`` file.)
213 specified in the ``authorized_keys`` file.)
214
214
215 The ``authorized_keys`` file can be updated manually with ``kallithea-cli
215 The ``authorized_keys`` file can be updated manually with ``kallithea-cli
216 ssh-update-authorized-keys -c my.ini``. This command is not needed in normal
216 ssh-update-authorized-keys -c my.ini``. This command is not needed in normal
217 operation but is for example useful after changing SSH-related settings in the
217 operation but is for example useful after changing SSH-related settings in the
218 ``.ini`` file or renaming that file. (The path to the ``.ini`` file is used in
218 ``.ini`` file or renaming that file. (The path to the ``.ini`` file is used in
219 the generated ``authorized_keys`` file).
219 the generated ``authorized_keys`` file).
220
220
221
221
222 Setting up Whoosh full text search
222 Setting up Whoosh full text search
223 ----------------------------------
223 ----------------------------------
224
224
225 Kallithea provides full text search of repositories using `Whoosh`__.
225 Kallithea provides full text search of repositories using `Whoosh`__.
226
226
227 .. __: https://whoosh.readthedocs.io/
227 .. __: https://whoosh.readthedocs.io/
228
228
229 For an incremental index build, run::
229 For an incremental index build, run::
230
230
231 kallithea-cli index-create -c my.ini
231 kallithea-cli index-create -c my.ini
232
232
233 For a full index rebuild, run::
233 For a full index rebuild, run::
234
234
235 kallithea-cli index-create -c my.ini --full
235 kallithea-cli index-create -c my.ini --full
236
236
237 The ``--repo-location`` option allows the location of the repositories to be overridden;
237 The ``--repo-location`` option allows the location of the repositories to be overridden;
238 usually, the location is retrieved from the Kallithea database.
238 usually, the location is retrieved from the Kallithea database.
239
239
240 The ``--index-only`` option can be used to limit the indexed repositories to a comma-separated list::
240 The ``--index-only`` option can be used to limit the indexed repositories to a comma-separated list::
241
241
242 kallithea-cli index-create -c my.ini --index-only=vcs,kallithea
242 kallithea-cli index-create -c my.ini --index-only=vcs,kallithea
243
243
244 To keep your index up-to-date it is necessary to do periodic index builds;
244 To keep your index up-to-date it is necessary to do periodic index builds;
245 for this, it is recommended to use a crontab entry. Example::
245 for this, it is recommended to use a crontab entry. Example::
246
246
247 0 3 * * * /path/to/virtualenv/bin/kallithea-cli index-create -c /path/to/kallithea/my.ini
247 0 3 * * * /path/to/virtualenv/bin/kallithea-cli index-create -c /path/to/kallithea/my.ini
248
248
249 When using incremental mode (the default), Whoosh will check the last
249 When using incremental mode (the default), Whoosh will check the last
250 modification date of each file and add it to be reindexed if a newer file is
250 modification date of each file and add it to be reindexed if a newer file is
251 available. The indexing daemon checks for any removed files and removes them
251 available. The indexing daemon checks for any removed files and removes them
252 from index.
252 from index.
253
253
254 If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
254 If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
255 or in the admin panel you can check the "build from scratch" checkbox.
255 or in the admin panel you can check the "build from scratch" checkbox.
256
256
257
257
258 Integration with issue trackers
258 Integration with issue trackers
259 -------------------------------
259 -------------------------------
260
260
261 Kallithea provides a simple integration with issue trackers. It's possible
261 Kallithea provides a simple integration with issue trackers. It's possible
262 to define a regular expression that will match an issue ID in commit messages,
262 to define a regular expression that will match an issue ID in commit messages,
263 and have that replaced with a URL to the issue.
263 and have that replaced with a URL to the issue.
264
264
265 This is achieved with following three variables in the ini file::
265 This is achieved with following three variables in the ini file::
266
266
267 issue_pat = #(\d+)
267 issue_pat = #(\d+)
268 issue_server_link = https://issues.example.com/{repo}/issue/\1
268 issue_server_link = https://issues.example.com/{repo}/issue/\1
269 issue_sub =
269 issue_sub =
270
270
271 ``issue_pat`` is the regular expression describing which strings in
271 ``issue_pat`` is the regular expression describing which strings in
272 commit messages will be treated as issue references. The expression can/should
272 commit messages will be treated as issue references. The expression can/should
273 have one or more parenthesized groups that can later be referred to in
273 have one or more parenthesized groups that can later be referred to in
274 ``issue_server_link`` and ``issue_sub`` (see below). If you prefer, named groups
274 ``issue_server_link`` and ``issue_sub`` (see below). If you prefer, named groups
275 can be used instead of simple parenthesized groups.
275 can be used instead of simple parenthesized groups.
276
276
277 If the pattern should only match if it is preceded by whitespace, add the
277 If the pattern should only match if it is preceded by whitespace, add the
278 following string before the actual pattern: ``(?:^|(?<=\s))``.
278 following string before the actual pattern: ``(?:^|(?<=\s))``.
279 If the pattern should only match if it is followed by whitespace, add the
279 If the pattern should only match if it is followed by whitespace, add the
280 following string after the actual pattern: ``(?:$|(?=\s))``.
280 following string after the actual pattern: ``(?:$|(?=\s))``.
281 These expressions use lookbehind and lookahead assertions of the Python regular
281 These expressions use lookbehind and lookahead assertions of the Python regular
282 expression module to avoid the whitespace to be part of the actual pattern,
282 expression module to avoid the whitespace to be part of the actual pattern,
283 otherwise the link text will also contain that whitespace.
283 otherwise the link text will also contain that whitespace.
284
284
285 Matched issue references are replaced with the link specified in
285 Matched issue references are replaced with the link specified in
286 ``issue_server_link``, in which any backreferences are resolved. Backreferences
286 ``issue_server_link``, in which any backreferences are resolved. Backreferences
287 can be ``\1``, ``\2``, ... or for named groups ``\g<groupname>``.
287 can be ``\1``, ``\2``, ... or for named groups ``\g<groupname>``.
288 The special token ``{repo}`` is replaced with the full repository path
288 The special token ``{repo}`` is replaced with the full repository path
289 (including repository groups), while token ``{repo_name}`` is replaced with the
289 (including repository groups), while token ``{repo_name}`` is replaced with the
290 repository name (without repository groups).
290 repository name (without repository groups).
291
291
292 The link text is determined by ``issue_sub``, which can be a string containing
292 The link text is determined by ``issue_sub``, which can be a string containing
293 backreferences to the groups specified in ``issue_pat``. If ``issue_sub`` is
293 backreferences to the groups specified in ``issue_pat``. If ``issue_sub`` is
294 empty, then the text matched by ``issue_pat`` is used verbatim.
294 empty, then the text matched by ``issue_pat`` is used verbatim.
295
295
296 The example settings shown above match issues in the format ``#<number>``.
296 The example settings shown above match issues in the format ``#<number>``.
297 This will cause the text ``#300`` to be transformed into a link:
297 This will cause the text ``#300`` to be transformed into a link:
298
298
299 .. code-block:: html
299 .. code-block:: html
300
300
301 <a href="https://issues.example.com/example_repo/issue/300">#300</a>
301 <a href="https://issues.example.com/example_repo/issue/300">#300</a>
302
302
303 The following example transforms a text starting with either of 'pullrequest',
303 The following example transforms a text starting with either of 'pullrequest',
304 'pull request' or 'PR', followed by an optional space, then a pound character
304 'pull request' or 'PR', followed by an optional space, then a pound character
305 (#) and one or more digits, into a link with the text 'PR #' followed by the
305 (#) and one or more digits, into a link with the text 'PR #' followed by the
306 digits::
306 digits::
307
307
308 issue_pat = (pullrequest|pull request|PR) ?#(\d+)
308 issue_pat = (pullrequest|pull request|PR) ?#(\d+)
309 issue_server_link = https://issues.example.com/\2
309 issue_server_link = https://issues.example.com/\2
310 issue_sub = PR #\2
310 issue_sub = PR #\2
311
311
312 The following example demonstrates how to require whitespace before the issue
312 The following example demonstrates how to require whitespace before the issue
313 reference in order for it to be recognized, such that the text ``issue#123`` will
313 reference in order for it to be recognized, such that the text ``issue#123`` will
314 not cause a match, but ``issue #123`` will::
314 not cause a match, but ``issue #123`` will::
315
315
316 issue_pat = (?:^|(?<=\s))#(\d+)
316 issue_pat = (?:^|(?<=\s))#(\d+)
317 issue_server_link = https://issues.example.com/\1
317 issue_server_link = https://issues.example.com/\1
318 issue_sub =
318 issue_sub =
319
319
320 If needed, more than one pattern can be specified by appending a unique suffix to
320 If needed, more than one pattern can be specified by appending a unique suffix to
321 the variables. For example, also demonstrating the use of named groups::
321 the variables. For example, also demonstrating the use of named groups::
322
322
323 issue_pat_wiki = wiki-(?P<pagename>\S+)
323 issue_pat_wiki = wiki-(?P<pagename>\S+)
324 issue_server_link_wiki = https://wiki.example.com/\g<pagename>
324 issue_server_link_wiki = https://wiki.example.com/\g<pagename>
325 issue_sub_wiki = WIKI-\g<pagename>
325 issue_sub_wiki = WIKI-\g<pagename>
326
326
327 With these settings, wiki pages can be referenced as wiki-some-id, and every
327 With these settings, wiki pages can be referenced as wiki-some-id, and every
328 such reference will be transformed into:
328 such reference will be transformed into:
329
329
330 .. code-block:: html
330 .. code-block:: html
331
331
332 <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
332 <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
333
333
334 Refer to the `Python regular expression documentation`_ for more details about
334 Refer to the `Python regular expression documentation`_ for more details about
335 the supported syntax in ``issue_pat``, ``issue_server_link`` and ``issue_sub``.
335 the supported syntax in ``issue_pat``, ``issue_server_link`` and ``issue_sub``.
336
336
337
337
338 Hook management
338 Hook management
339 ---------------
339 ---------------
340
340
341 Custom Mercurial hooks can be managed in a similar way to that used in ``.hgrc`` files.
341 Custom Mercurial hooks can be managed in a similar way to that used in ``.hgrc`` files.
342 To manage hooks, choose *Admin > Settings > Hooks*.
342 To manage hooks, choose *Admin > Settings > Hooks*.
343
343
344 To add another custom hook simply fill in the first textbox with
344 To add another custom hook simply fill in the first textbox with
345 ``<name>.<hook_type>`` and the second with the hook path. Example hooks
345 ``<name>.<hook_type>`` and the second with the hook path. Example hooks
346 can be found in ``kallithea.lib.hooks``.
346 can be found in ``kallithea.lib.hooks``.
347
347
348 Kallithea will also use some hooks internally. They cannot be modified, but
348 Kallithea will also use some hooks internally. They cannot be modified, but
349 some of them can be enabled or disabled in the *VCS* section.
349 some of them can be enabled or disabled in the *VCS* section.
350
350
351 Kallithea does not actively support custom Git hooks, but hooks can be installed
351 Kallithea does not actively support custom Git hooks, but hooks can be installed
352 manually in the file system. Kallithea will install and use the
352 manually in the file system. Kallithea will install and use the
353 ``post-receive`` Git hook internally, but it will then invoke
353 ``post-receive`` Git hook internally, but it will then invoke
354 ``post-receive-custom`` if present.
354 ``post-receive-custom`` if present.
355
355
356
356
357 Changing default encoding
357 Changing default encoding
358 -------------------------
358 -------------------------
359
359
360 By default, Kallithea uses UTF-8 encoding.
360 By default, Kallithea uses UTF-8 encoding.
361 This is configurable as ``default_encoding`` in the .ini file.
361 This is configurable as ``default_encoding`` in the .ini file.
362 This affects many parts in Kallithea including user names, filenames, and
362 This affects many parts in Kallithea including user names, filenames, and
363 encoding of commit messages. In addition Kallithea can detect if the ``chardet``
363 encoding of commit messages. In addition Kallithea can detect if the ``chardet``
364 library is installed. If ``chardet`` is detected Kallithea will fallback to it
364 library is installed. If ``chardet`` is detected Kallithea will fallback to it
365 when there are encode/decode errors.
365 when there are encode/decode errors.
366
366
367 The Mercurial encoding is configurable as ``hgencoding``. It is similar to
367 The Mercurial encoding is configurable as ``hgencoding``. It is similar to
368 setting the ``HGENCODING`` environment variable, but will override it.
368 setting the ``HGENCODING`` environment variable, but will override it.
369
369
370
370
371 Celery configuration
371 Celery configuration
372 --------------------
372 --------------------
373
373
374 Kallithea can use the distributed task queue system Celery_ to run tasks like
374 Kallithea can use the distributed task queue system Celery_ to run tasks like
375 cloning repositories or sending emails.
375 cloning repositories or sending emails.
376
376
377 Kallithea will in most setups work perfectly fine out of the box (without
377 Kallithea will in most setups work perfectly fine out of the box (without
378 Celery), executing all tasks in the web server process. Some tasks can however
378 Celery), executing all tasks in the web server process. Some tasks can however
379 take some time to run and it can be better to run such tasks asynchronously in
379 take some time to run and it can be better to run such tasks asynchronously in
380 a separate process so the web server can focus on serving web requests.
380 a separate process so the web server can focus on serving web requests.
381
381
382 For installation and configuration of Celery, see the `Celery documentation`_.
382 For installation and configuration of Celery, see the `Celery documentation`_.
383 Note that Celery requires a message broker service like RabbitMQ_ (recommended)
383 Note that Celery requires a message broker service like RabbitMQ_ (recommended)
384 or Redis_.
384 or Redis_.
385
385
386 The use of Celery is configured in the Kallithea ini configuration file.
386 The use of Celery is configured in the Kallithea ini configuration file.
387 To enable it, simply set::
387 To enable it, simply set::
388
388
389 use_celery = true
389 use_celery = true
390
390
391 and add or change the ``celery.*`` configuration variables.
391 and add or change the ``celery.*`` configuration variables.
392
392
393 Configuration settings are prefixed with 'celery.', so for example setting
393 Configuration settings are prefixed with 'celery.', so for example setting
394 `broker_url` in Celery means setting `celery.broker_url` in the configuration
394 `broker_url` in Celery means setting `celery.broker_url` in the configuration
395 file.
395 file.
396
396
397 To start the Celery process, run::
397 To start the Celery process, run::
398
398
399 kallithea-cli celery-run -c my.ini
399 kallithea-cli celery-run -c my.ini
400
400
401 Extra options to the Celery worker can be passed after ``--`` - see ``-- -h``
401 Extra options to the Celery worker can be passed after ``--`` - see ``-- -h``
402 for more info.
402 for more info.
403
403
404 .. note::
404 .. note::
405 Make sure you run this command from the same virtualenv, and with the same
405 Make sure you run this command from the same virtualenv, and with the same
406 user that Kallithea runs.
406 user that Kallithea runs.
407
407
408
408
409 Proxy setups
409 Proxy setups
410 ------------
410 ------------
411
411
412 When Kallithea is processing HTTP requests from a user, it will see and use
412 When Kallithea is processing HTTP requests from a user, it will see and use
413 some of the basic properties of the connection, both at the TCP/IP level and at
413 some of the basic properties of the connection, both at the TCP/IP level and at
414 the HTTP level. The WSGI server will provide this information to Kallithea in
414 the HTTP level. The WSGI server will provide this information to Kallithea in
415 the "environment".
415 the "environment".
416
416
417 In some setups, a proxy server will take requests from users and forward
417 In some setups, a proxy server will take requests from users and forward
418 them to the actual Kallithea server. The proxy server will thus be the
418 them to the actual Kallithea server. The proxy server will thus be the
419 immediate client of the Kallithea WSGI server, and Kallithea will basically see
419 immediate client of the Kallithea WSGI server, and Kallithea will basically see
420 it as such. To make sure Kallithea sees the request as it arrived from the
420 it as such. To make sure Kallithea sees the request as it arrived from the
421 client to the proxy server, the proxy server must be configured to
421 client to the proxy server, the proxy server must be configured to
422 somehow pass the original information on to Kallithea, and Kallithea must be
422 somehow pass the original information on to Kallithea, and Kallithea must be
423 configured to pick that information up and trust it.
423 configured to pick that information up and trust it.
424
424
425 Kallithea will by default rely on its WSGI server to provide the IP of the
425 Kallithea will by default rely on its WSGI server to provide the IP of the
426 client in the WSGI environment as ``REMOTE_ADDR``, but it can also
426 client in the WSGI environment as ``REMOTE_ADDR``, but it can be configured to
427 get it from the ``X-Real-IP`` or ``X-Forwarded-For`` HTTP headers.
427 get it from an HTTP header that has been set by the proxy server. For
428 example, if the proxy server puts the client IP in the ``X-Forwarded-For``
429 HTTP header, set::
430
431 remote_addr_variable = HTTP_X_FORWARDED_FOR
428
432
429 Kallithea will by default rely on finding the protocol (``http`` or ``https``)
433 Kallithea will by default rely on finding the protocol (``http`` or ``https``)
430 in the WSGI environment as ``wsgi.url_scheme``. If the proxy server puts
434 in the WSGI environment as ``wsgi.url_scheme``. If the proxy server puts
431 the protocol of the client request in the ``X-Url-Scheme``,
435 the protocol of the client request in the ``X-Url-Scheme``,
432 ``X-Forwarded-Scheme``, or ``X-Forwarded-Proto`` HTTP header,
436 ``X-Forwarded-Scheme``, or ``X-Forwarded-Proto`` HTTP header,
433 Kallithea can be configured to trust these headers by setting::
437 Kallithea can be configured to trust these headers by setting::
434
438
435 https_fixup = true
439 https_fixup = true
436
440
437
441
438 HTTPS support
442 HTTPS support
439 -------------
443 -------------
440
444
441 Kallithea will by default generate URLs based on the WSGI environment.
445 Kallithea will by default generate URLs based on the WSGI environment.
442
446
443 Alternatively, you can use some special configuration settings to control
447 Alternatively, you can use some special configuration settings to control
444 directly which scheme/protocol Kallithea will use when generating URLs:
448 directly which scheme/protocol Kallithea will use when generating URLs:
445
449
446 - With ``https_fixup = true``, the scheme will be taken from the
450 - With ``https_fixup = true``, the scheme will be taken from the
447 ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
451 ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
448 (default ``http``).
452 (default ``http``).
449 - With ``force_https = true``, the scheme will be seen as ``https``.
453 - With ``force_https = true``, the scheme will be seen as ``https``.
450 - With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
454 - With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
451
455
452 .. _nginx_virtual_host:
456 .. _nginx_virtual_host:
453
457
454
458
455 Nginx virtual host example
459 Nginx virtual host example
456 --------------------------
460 --------------------------
457
461
458 Sample config for Nginx using proxy:
462 Sample config for Nginx using proxy:
459
463
460 .. code-block:: nginx
464 .. code-block:: nginx
461
465
462 upstream kallithea {
466 upstream kallithea {
463 server 127.0.0.1:5000;
467 server 127.0.0.1:5000;
464 # add more instances for load balancing
468 # add more instances for load balancing
465 #server 127.0.0.1:5001;
469 #server 127.0.0.1:5001;
466 #server 127.0.0.1:5002;
470 #server 127.0.0.1:5002;
467 }
471 }
468
472
469 ## gist alias
473 ## gist alias
470 server {
474 server {
471 listen 443;
475 listen 443;
472 server_name gist.example.com;
476 server_name gist.example.com;
473 access_log /var/log/nginx/gist.access.log;
477 access_log /var/log/nginx/gist.access.log;
474 error_log /var/log/nginx/gist.error.log;
478 error_log /var/log/nginx/gist.error.log;
475
479
476 ssl on;
480 ssl on;
477 ssl_certificate gist.your.kallithea.server.crt;
481 ssl_certificate gist.your.kallithea.server.crt;
478 ssl_certificate_key gist.your.kallithea.server.key;
482 ssl_certificate_key gist.your.kallithea.server.key;
479
483
480 ssl_session_timeout 5m;
484 ssl_session_timeout 5m;
481
485
482 ssl_protocols SSLv3 TLSv1;
486 ssl_protocols SSLv3 TLSv1;
483 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
487 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
484 ssl_prefer_server_ciphers on;
488 ssl_prefer_server_ciphers on;
485
489
486 rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
490 rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
487 rewrite (.*) https://kallithea.example.com/_admin/gists;
491 rewrite (.*) https://kallithea.example.com/_admin/gists;
488 }
492 }
489
493
490 server {
494 server {
491 listen 443;
495 listen 443;
492 server_name kallithea.example.com
496 server_name kallithea.example.com
493 access_log /var/log/nginx/kallithea.access.log;
497 access_log /var/log/nginx/kallithea.access.log;
494 error_log /var/log/nginx/kallithea.error.log;
498 error_log /var/log/nginx/kallithea.error.log;
495
499
496 ssl on;
500 ssl on;
497 ssl_certificate your.kallithea.server.crt;
501 ssl_certificate your.kallithea.server.crt;
498 ssl_certificate_key your.kallithea.server.key;
502 ssl_certificate_key your.kallithea.server.key;
499
503
500 ssl_session_timeout 5m;
504 ssl_session_timeout 5m;
501
505
502 ssl_protocols SSLv3 TLSv1;
506 ssl_protocols SSLv3 TLSv1;
503 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
507 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
504 ssl_prefer_server_ciphers on;
508 ssl_prefer_server_ciphers on;
505
509
506 ## uncomment root directive if you want to serve static files by nginx
510 ## uncomment root directive if you want to serve static files by nginx
507 ## requires static_files = false in .ini file
511 ## requires static_files = false in .ini file
508 #root /srv/kallithea/kallithea/kallithea/public;
512 #root /srv/kallithea/kallithea/kallithea/public;
509 include /etc/nginx/proxy.conf;
513 include /etc/nginx/proxy.conf;
510 location / {
514 location / {
511 try_files $uri @kallithea;
515 try_files $uri @kallithea;
512 }
516 }
513
517
514 location @kallithea {
518 location @kallithea {
515 proxy_pass http://127.0.0.1:5000;
519 proxy_pass http://127.0.0.1:5000;
516 }
520 }
517
521
518 }
522 }
519
523
520 Here's the proxy.conf. It's tuned so it will not timeout on long
524 Here's the proxy.conf. It's tuned so it will not timeout on long
521 pushes or large pushes::
525 pushes or large pushes::
522
526
523 proxy_redirect off;
527 proxy_redirect off;
524 proxy_set_header Host $host;
528 proxy_set_header Host $host;
525 ## needed for container auth
529 ## needed for container auth
526 #proxy_set_header REMOTE_USER $remote_user;
530 #proxy_set_header REMOTE_USER $remote_user;
527 #proxy_set_header X-Forwarded-User $remote_user;
531 #proxy_set_header X-Forwarded-User $remote_user;
528 proxy_set_header X-Url-Scheme $scheme;
532 proxy_set_header X-Url-Scheme $scheme;
529 proxy_set_header X-Host $http_host;
533 proxy_set_header X-Host $http_host;
530 proxy_set_header X-Real-IP $remote_addr;
534 proxy_set_header X-Real-IP $remote_addr;
531 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
535 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
532 proxy_set_header Proxy-host $proxy_host;
536 proxy_set_header Proxy-host $proxy_host;
533 proxy_buffering off;
537 proxy_buffering off;
534 proxy_connect_timeout 7200;
538 proxy_connect_timeout 7200;
535 proxy_send_timeout 7200;
539 proxy_send_timeout 7200;
536 proxy_read_timeout 7200;
540 proxy_read_timeout 7200;
537 proxy_buffers 8 32k;
541 proxy_buffers 8 32k;
538 client_max_body_size 1024m;
542 client_max_body_size 1024m;
539 client_body_buffer_size 128k;
543 client_body_buffer_size 128k;
540 large_client_header_buffers 8 64k;
544 large_client_header_buffers 8 64k;
541
545
542 .. _apache_virtual_host_reverse_proxy:
546 .. _apache_virtual_host_reverse_proxy:
543
547
544
548
545 Apache virtual host reverse proxy example
549 Apache virtual host reverse proxy example
546 -----------------------------------------
550 -----------------------------------------
547
551
548 Here is a sample configuration file for Apache using proxy:
552 Here is a sample configuration file for Apache using proxy:
549
553
550 .. code-block:: apache
554 .. code-block:: apache
551
555
552 <VirtualHost *:80>
556 <VirtualHost *:80>
553 ServerName kallithea.example.com
557 ServerName kallithea.example.com
554
558
555 <Proxy *>
559 <Proxy *>
556 # For Apache 2.4 and later:
560 # For Apache 2.4 and later:
557 Require all granted
561 Require all granted
558
562
559 # For Apache 2.2 and earlier, instead use:
563 # For Apache 2.2 and earlier, instead use:
560 # Order allow,deny
564 # Order allow,deny
561 # Allow from all
565 # Allow from all
562 </Proxy>
566 </Proxy>
563
567
564 #important !
568 #important !
565 #Directive to properly generate url (clone url) for Kallithea
569 #Directive to properly generate url (clone url) for Kallithea
566 ProxyPreserveHost On
570 ProxyPreserveHost On
567
571
568 #kallithea instance
572 #kallithea instance
569 ProxyPass / http://127.0.0.1:5000/
573 ProxyPass / http://127.0.0.1:5000/
570 ProxyPassReverse / http://127.0.0.1:5000/
574 ProxyPassReverse / http://127.0.0.1:5000/
571
575
572 #to enable https use line below
576 #to enable https use line below
573 #SetEnvIf X-Url-Scheme https HTTPS=1
577 #SetEnvIf X-Url-Scheme https HTTPS=1
574 </VirtualHost>
578 </VirtualHost>
575
579
576 Additional tutorial
580 Additional tutorial
577 http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
581 http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
578
582
579 .. _apache_subdirectory:
583 .. _apache_subdirectory:
580
584
581
585
582 Apache as subdirectory
586 Apache as subdirectory
583 ----------------------
587 ----------------------
584
588
585 Apache subdirectory part:
589 Apache subdirectory part:
586
590
587 .. code-block:: apache
591 .. code-block:: apache
588
592
589 <Location /PREFIX >
593 <Location /PREFIX >
590 ProxyPass http://127.0.0.1:5000/PREFIX
594 ProxyPass http://127.0.0.1:5000/PREFIX
591 ProxyPassReverse http://127.0.0.1:5000/PREFIX
595 ProxyPassReverse http://127.0.0.1:5000/PREFIX
592 SetEnvIf X-Url-Scheme https HTTPS=1
596 SetEnvIf X-Url-Scheme https HTTPS=1
593 </Location>
597 </Location>
594
598
595 Besides the regular apache setup you will need to add the following line
599 Besides the regular apache setup you will need to add the following line
596 into ``[app:main]`` section of your .ini file::
600 into ``[app:main]`` section of your .ini file::
597
601
598 filter-with = proxy-prefix
602 filter-with = proxy-prefix
599
603
600 Add the following at the end of the .ini file::
604 Add the following at the end of the .ini file::
601
605
602 [filter:proxy-prefix]
606 [filter:proxy-prefix]
603 use = egg:PasteDeploy#prefix
607 use = egg:PasteDeploy#prefix
604 prefix = /PREFIX
608 prefix = /PREFIX
605
609
606 then change ``PREFIX`` into your chosen prefix
610 then change ``PREFIX`` into your chosen prefix
607
611
608 .. _apache_mod_wsgi:
612 .. _apache_mod_wsgi:
609
613
610
614
611 Apache with mod_wsgi
615 Apache with mod_wsgi
612 --------------------
616 --------------------
613
617
614 Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
618 Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
615 that, you'll need to:
619 that, you'll need to:
616
620
617 - Install mod_wsgi. If using a Debian-based distro, you can install
621 - Install mod_wsgi. If using a Debian-based distro, you can install
618 the package libapache2-mod-wsgi::
622 the package libapache2-mod-wsgi::
619
623
620 aptitude install libapache2-mod-wsgi
624 aptitude install libapache2-mod-wsgi
621
625
622 - Enable mod_wsgi::
626 - Enable mod_wsgi::
623
627
624 a2enmod wsgi
628 a2enmod wsgi
625
629
626 - Add global Apache configuration to tell mod_wsgi that Python only will be
630 - Add global Apache configuration to tell mod_wsgi that Python only will be
627 used in the WSGI processes and shouldn't be initialized in the Apache
631 used in the WSGI processes and shouldn't be initialized in the Apache
628 processes::
632 processes::
629
633
630 WSGIRestrictEmbedded On
634 WSGIRestrictEmbedded On
631
635
632 - Create a WSGI dispatch script, like the one below. The ``WSGIDaemonProcess``
636 - Create a WSGI dispatch script, like the one below. The ``WSGIDaemonProcess``
633 ``python-home`` directive will make sure it uses the right Python Virtual
637 ``python-home`` directive will make sure it uses the right Python Virtual
634 Environment and that paste thus can pick up the right Kallithea
638 Environment and that paste thus can pick up the right Kallithea
635 application.
639 application.
636
640
637 .. code-block:: python
641 .. code-block:: python
638
642
639 ini = '/srv/kallithea/my.ini'
643 ini = '/srv/kallithea/my.ini'
640 from logging.config import fileConfig
644 from logging.config import fileConfig
641 fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
645 fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
642 from paste.deploy import loadapp
646 from paste.deploy import loadapp
643 application = loadapp('config:' + ini)
647 application = loadapp('config:' + ini)
644
648
645 - Add the necessary ``WSGI*`` directives to the Apache Virtual Host configuration
649 - Add the necessary ``WSGI*`` directives to the Apache Virtual Host configuration
646 file, like in the example below. Notice that the WSGI dispatch script created
650 file, like in the example below. Notice that the WSGI dispatch script created
647 above is referred to with the ``WSGIScriptAlias`` directive.
651 above is referred to with the ``WSGIScriptAlias`` directive.
648 The default locale settings Apache provides for web services are often not
652 The default locale settings Apache provides for web services are often not
649 adequate, with `C` as the default language and `ASCII` as the encoding.
653 adequate, with `C` as the default language and `ASCII` as the encoding.
650 Instead, use the ``lang`` parameter of ``WSGIDaemonProcess`` to specify a
654 Instead, use the ``lang`` parameter of ``WSGIDaemonProcess`` to specify a
651 suitable locale. See also the :ref:`overview` section and the
655 suitable locale. See also the :ref:`overview` section and the
652 `WSGIDaemonProcess documentation`_.
656 `WSGIDaemonProcess documentation`_.
653
657
654 Apache will by default run as a special Apache user, on Linux systems
658 Apache will by default run as a special Apache user, on Linux systems
655 usually ``www-data`` or ``apache``. If you need to have the repositories
659 usually ``www-data`` or ``apache``. If you need to have the repositories
656 directory owned by a different user, use the user and group options to
660 directory owned by a different user, use the user and group options to
657 WSGIDaemonProcess to set the name of the user and group.
661 WSGIDaemonProcess to set the name of the user and group.
658
662
659 Once again, check that all paths are correctly specified.
663 Once again, check that all paths are correctly specified.
660
664
661 .. code-block:: apache
665 .. code-block:: apache
662
666
663 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
667 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
664 python-home=/srv/kallithea/venv lang=C.UTF-8
668 python-home=/srv/kallithea/venv lang=C.UTF-8
665 WSGIProcessGroup kallithea
669 WSGIProcessGroup kallithea
666 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
670 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
667 WSGIPassAuthorization On
671 WSGIPassAuthorization On
668
672
669
673
670 Other configuration files
674 Other configuration files
671 -------------------------
675 -------------------------
672
676
673 A number of `example init.d scripts`__ can be found in
677 A number of `example init.d scripts`__ can be found in
674 the ``init.d`` directory of the Kallithea source.
678 the ``init.d`` directory of the Kallithea source.
675
679
676 .. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
680 .. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
677
681
678
682
679 .. _python: http://www.python.org/
683 .. _python: http://www.python.org/
680 .. _Python regular expression documentation: https://docs.python.org/2/library/re.html
684 .. _Python regular expression documentation: https://docs.python.org/2/library/re.html
681 .. _Mercurial: https://www.mercurial-scm.org/
685 .. _Mercurial: https://www.mercurial-scm.org/
682 .. _Celery: http://celeryproject.org/
686 .. _Celery: http://celeryproject.org/
683 .. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
687 .. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
684 .. _RabbitMQ: http://www.rabbitmq.com/
688 .. _RabbitMQ: http://www.rabbitmq.com/
685 .. _Redis: http://redis.io/
689 .. _Redis: http://redis.io/
686 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
690 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
687 .. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
691 .. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
688 .. _WSGIDaemonProcess documentation: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html
692 .. _WSGIDaemonProcess documentation: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html
@@ -1,641 +1,633 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
14
15 """
15 """
16 kallithea.controllers.base
16 kallithea.controllers.base
17 ~~~~~~~~~~~~~~~~~~~~~~~~~~
17 ~~~~~~~~~~~~~~~~~~~~~~~~~~
18
18
19 The base Controller API
19 The base Controller API
20 Provides the BaseController class for subclassing. And usage in different
20 Provides the BaseController class for subclassing. And usage in different
21 controllers
21 controllers
22
22
23 This file was forked by the Kallithea project in July 2014.
23 This file was forked by the Kallithea project in July 2014.
24 Original author and date, and relevant copyright and licensing information is below:
24 Original author and date, and relevant copyright and licensing information is below:
25 :created_on: Oct 06, 2010
25 :created_on: Oct 06, 2010
26 :author: marcink
26 :author: marcink
27 :copyright: (c) 2013 RhodeCode GmbH, and others.
27 :copyright: (c) 2013 RhodeCode GmbH, and others.
28 :license: GPLv3, see LICENSE.md for more details.
28 :license: GPLv3, see LICENSE.md for more details.
29 """
29 """
30
30
31 import base64
31 import base64
32 import datetime
32 import datetime
33 import logging
33 import logging
34 import traceback
34 import traceback
35 import warnings
35 import warnings
36
36
37 import decorator
37 import decorator
38 import paste.auth.basic
38 import paste.auth.basic
39 import paste.httpexceptions
39 import paste.httpexceptions
40 import paste.httpheaders
40 import paste.httpheaders
41 import webob.exc
41 import webob.exc
42 from tg import TGController, config, render_template, request, response, session
42 from tg import TGController, config, render_template, request, response, session
43 from tg import tmpl_context as c
43 from tg import tmpl_context as c
44 from tg.i18n import ugettext as _
44 from tg.i18n import ugettext as _
45
45
46 import kallithea
46 import kallithea
47 from kallithea.lib import auth_modules, ext_json, webutils
47 from kallithea.lib import auth_modules, ext_json, webutils
48 from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware
48 from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware
49 from kallithea.lib.exceptions import UserCreationError
49 from kallithea.lib.exceptions import UserCreationError
50 from kallithea.lib.utils import get_repo_slug, is_valid_repo
50 from kallithea.lib.utils import get_repo_slug, is_valid_repo
51 from kallithea.lib.utils2 import AttributeDict, asbool, ascii_bytes, safe_int, safe_str, set_hook_environment
51 from kallithea.lib.utils2 import AttributeDict, asbool, ascii_bytes, safe_int, safe_str, set_hook_environment
52 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError
52 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError
53 from kallithea.lib.webutils import url
53 from kallithea.lib.webutils import url
54 from kallithea.model import db, meta
54 from kallithea.model import db, meta
55 from kallithea.model.scm import ScmModel
55 from kallithea.model.scm import ScmModel
56
56
57
57
58 log = logging.getLogger(__name__)
58 log = logging.getLogger(__name__)
59
59
60
60
61 def render(template_path):
61 def render(template_path):
62 return render_template({'url': url}, 'mako', template_path)
62 return render_template({'url': url}, 'mako', template_path)
63
63
64
64
65 def _filter_proxy(ip):
65 def _filter_proxy(ip):
66 """
66 """
67 HTTP_X_FORWARDED_FOR headers can have multiple IP addresses, with the
67 HTTP_X_FORWARDED_FOR headers can have multiple IP addresses, with the
68 leftmost being the original client. Each proxy that is forwarding the
68 leftmost being the original client. Each proxy that is forwarding the
69 request will usually add the IP address it sees the request coming from.
69 request will usually add the IP address it sees the request coming from.
70
70
71 The client might have provided a fake leftmost value before hitting the
71 The client might have provided a fake leftmost value before hitting the
72 first proxy, so if we have a proxy that is adding one IP address, we can
72 first proxy, so if we have a proxy that is adding one IP address, we can
73 only trust the rightmost address.
73 only trust the rightmost address.
74 """
74 """
75 if ',' in ip:
75 if ',' in ip:
76 _ips = ip.split(',')
76 _ips = ip.split(',')
77 _first_ip = _ips[-1].strip()
77 _first_ip = _ips[-1].strip()
78 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
78 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
79 return _first_ip
79 return _first_ip
80 return ip
80 return ip
81
81
82
82
83 def get_ip_addr(environ):
83 def get_ip_addr(environ):
84 proxy_key = 'HTTP_X_REAL_IP'
84 """The web server will set REMOTE_ADDR to the unfakeable IP layer client IP address.
85 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
85 If using a proxy server, make it possible to use another value, such as
86 def_key = 'REMOTE_ADDR'
86 the X-Forwarded-For header, by setting `remote_addr_variable = HTTP_X_FORWARDED_FOR`.
87
87 """
88 ip = environ.get(proxy_key)
88 remote_addr_variable = kallithea.CONFIG.get('remote_addr_variable', 'REMOTE_ADDR')
89 if ip:
89 return _filter_proxy(environ.get(remote_addr_variable, '0.0.0.0'))
90 return _filter_proxy(ip)
91
92 ip = environ.get(proxy_key2)
93 if ip:
94 return _filter_proxy(ip)
95
96 ip = environ.get(def_key, '0.0.0.0')
97 return _filter_proxy(ip)
98
90
99
91
100 def get_path_info(environ):
92 def get_path_info(environ):
101 """Return PATH_INFO from environ ... using tg.original_request if available.
93 """Return PATH_INFO from environ ... using tg.original_request if available.
102
94
103 In Python 3 WSGI, PATH_INFO is a unicode str, but kind of contains encoded
95 In Python 3 WSGI, PATH_INFO is a unicode str, but kind of contains encoded
104 bytes. The code points are guaranteed to only use the lower 8 bit bits, and
96 bytes. The code points are guaranteed to only use the lower 8 bit bits, and
105 encoding the string with the 1:1 encoding latin1 will give the
97 encoding the string with the 1:1 encoding latin1 will give the
106 corresponding byte string ... which then can be decoded to proper unicode.
98 corresponding byte string ... which then can be decoded to proper unicode.
107 """
99 """
108 org_req = environ.get('tg.original_request')
100 org_req = environ.get('tg.original_request')
109 if org_req is not None:
101 if org_req is not None:
110 environ = org_req.environ
102 environ = org_req.environ
111 return safe_str(environ['PATH_INFO'].encode('latin1'))
103 return safe_str(environ['PATH_INFO'].encode('latin1'))
112
104
113
105
114 def log_in_user(user, remember, is_external_auth, ip_addr):
106 def log_in_user(user, remember, is_external_auth, ip_addr):
115 """
107 """
116 Log a `User` in and update session and cookies. If `remember` is True,
108 Log a `User` in and update session and cookies. If `remember` is True,
117 the session cookie is set to expire in a year; otherwise, it expires at
109 the session cookie is set to expire in a year; otherwise, it expires at
118 the end of the browser session.
110 the end of the browser session.
119
111
120 Returns populated `AuthUser` object.
112 Returns populated `AuthUser` object.
121 """
113 """
122 # It should not be possible to explicitly log in as the default user.
114 # It should not be possible to explicitly log in as the default user.
123 assert not user.is_default_user, user
115 assert not user.is_default_user, user
124
116
125 auth_user = AuthUser.make(dbuser=user, is_external_auth=is_external_auth, ip_addr=ip_addr)
117 auth_user = AuthUser.make(dbuser=user, is_external_auth=is_external_auth, ip_addr=ip_addr)
126 if auth_user is None:
118 if auth_user is None:
127 return None
119 return None
128
120
129 user.update_lastlogin()
121 user.update_lastlogin()
130 meta.Session().commit()
122 meta.Session().commit()
131
123
132 # Start new session to prevent session fixation attacks.
124 # Start new session to prevent session fixation attacks.
133 session.invalidate()
125 session.invalidate()
134 session['authuser'] = cookie = auth_user.to_cookie()
126 session['authuser'] = cookie = auth_user.to_cookie()
135
127
136 # If they want to be remembered, update the cookie.
128 # If they want to be remembered, update the cookie.
137 # NOTE: Assumes that beaker defaults to browser session cookie.
129 # NOTE: Assumes that beaker defaults to browser session cookie.
138 if remember:
130 if remember:
139 t = datetime.datetime.now() + datetime.timedelta(days=365)
131 t = datetime.datetime.now() + datetime.timedelta(days=365)
140 session._set_cookie_expires(t)
132 session._set_cookie_expires(t)
141
133
142 session.save()
134 session.save()
143
135
144 log.info('user %s is now authenticated and stored in '
136 log.info('user %s is now authenticated and stored in '
145 'session, session attrs %s', user.username, cookie)
137 'session, session attrs %s', user.username, cookie)
146
138
147 # dumps session attrs back to cookie
139 # dumps session attrs back to cookie
148 session._update_cookie_out()
140 session._update_cookie_out()
149
141
150 return auth_user
142 return auth_user
151
143
152
144
153 class BasicAuth(paste.auth.basic.AuthBasicAuthenticator):
145 class BasicAuth(paste.auth.basic.AuthBasicAuthenticator):
154
146
155 def __init__(self, realm, authfunc, auth_http_code=None):
147 def __init__(self, realm, authfunc, auth_http_code=None):
156 self.realm = realm
148 self.realm = realm
157 self.authfunc = authfunc
149 self.authfunc = authfunc
158 self._rc_auth_http_code = auth_http_code
150 self._rc_auth_http_code = auth_http_code
159
151
160 def build_authentication(self, environ):
152 def build_authentication(self, environ):
161 head = paste.httpheaders.WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
153 head = paste.httpheaders.WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
162 # Consume the whole body before sending a response
154 # Consume the whole body before sending a response
163 try:
155 try:
164 request_body_size = int(environ.get('CONTENT_LENGTH', 0))
156 request_body_size = int(environ.get('CONTENT_LENGTH', 0))
165 except (ValueError):
157 except (ValueError):
166 request_body_size = 0
158 request_body_size = 0
167 environ['wsgi.input'].read(request_body_size)
159 environ['wsgi.input'].read(request_body_size)
168 if self._rc_auth_http_code and self._rc_auth_http_code == '403':
160 if self._rc_auth_http_code and self._rc_auth_http_code == '403':
169 # return 403 if alternative http return code is specified in
161 # return 403 if alternative http return code is specified in
170 # Kallithea config
162 # Kallithea config
171 return paste.httpexceptions.HTTPForbidden(headers=head)
163 return paste.httpexceptions.HTTPForbidden(headers=head)
172 return paste.httpexceptions.HTTPUnauthorized(headers=head)
164 return paste.httpexceptions.HTTPUnauthorized(headers=head)
173
165
174 def authenticate(self, environ):
166 def authenticate(self, environ):
175 authorization = paste.httpheaders.AUTHORIZATION(environ)
167 authorization = paste.httpheaders.AUTHORIZATION(environ)
176 if not authorization:
168 if not authorization:
177 return self.build_authentication(environ)
169 return self.build_authentication(environ)
178 (authmeth, auth) = authorization.split(' ', 1)
170 (authmeth, auth) = authorization.split(' ', 1)
179 if 'basic' != authmeth.lower():
171 if 'basic' != authmeth.lower():
180 return self.build_authentication(environ)
172 return self.build_authentication(environ)
181 auth = safe_str(base64.b64decode(auth.strip()))
173 auth = safe_str(base64.b64decode(auth.strip()))
182 _parts = auth.split(':', 1)
174 _parts = auth.split(':', 1)
183 if len(_parts) == 2:
175 if len(_parts) == 2:
184 username, password = _parts
176 username, password = _parts
185 if self.authfunc(username, password, environ) is not None:
177 if self.authfunc(username, password, environ) is not None:
186 return username
178 return username
187 return self.build_authentication(environ)
179 return self.build_authentication(environ)
188
180
189 __call__ = authenticate
181 __call__ = authenticate
190
182
191
183
192 class BaseVCSController(object):
184 class BaseVCSController(object):
193 """Base controller for handling Mercurial/Git protocol requests
185 """Base controller for handling Mercurial/Git protocol requests
194 (coming from a VCS client, and not a browser).
186 (coming from a VCS client, and not a browser).
195 """
187 """
196
188
197 scm_alias = None # 'hg' / 'git'
189 scm_alias = None # 'hg' / 'git'
198
190
199 def __init__(self, application, config):
191 def __init__(self, application, config):
200 self.application = application
192 self.application = application
201 self.config = config
193 self.config = config
202 # base path of repo locations
194 # base path of repo locations
203 self.basepath = self.config['base_path']
195 self.basepath = self.config['base_path']
204 # authenticate this VCS request using the authentication modules
196 # authenticate this VCS request using the authentication modules
205 self.authenticate = BasicAuth('', auth_modules.authenticate,
197 self.authenticate = BasicAuth('', auth_modules.authenticate,
206 config.get('auth_ret_code'))
198 config.get('auth_ret_code'))
207
199
208 @classmethod
200 @classmethod
209 def parse_request(cls, environ):
201 def parse_request(cls, environ):
210 """If request is parsed as a request for this VCS, return a namespace with the parsed request.
202 """If request is parsed as a request for this VCS, return a namespace with the parsed request.
211 If the request is unknown, return None.
203 If the request is unknown, return None.
212 """
204 """
213 raise NotImplementedError()
205 raise NotImplementedError()
214
206
215 def _authorize(self, environ, action, repo_name, ip_addr):
207 def _authorize(self, environ, action, repo_name, ip_addr):
216 """Authenticate and authorize user.
208 """Authenticate and authorize user.
217
209
218 Since we're dealing with a VCS client and not a browser, we only
210 Since we're dealing with a VCS client and not a browser, we only
219 support HTTP basic authentication, either directly via raw header
211 support HTTP basic authentication, either directly via raw header
220 inspection, or by using container authentication to delegate the
212 inspection, or by using container authentication to delegate the
221 authentication to the web server.
213 authentication to the web server.
222
214
223 Returns (user, None) on successful authentication and authorization.
215 Returns (user, None) on successful authentication and authorization.
224 Returns (None, wsgi_app) to send the wsgi_app response to the client.
216 Returns (None, wsgi_app) to send the wsgi_app response to the client.
225 """
217 """
226 # Use anonymous access if allowed for action on repo.
218 # Use anonymous access if allowed for action on repo.
227 default_user = db.User.get_default_user()
219 default_user = db.User.get_default_user()
228 default_authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
220 default_authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
229 if default_authuser is None:
221 if default_authuser is None:
230 log.debug('No anonymous access at all') # move on to proper user auth
222 log.debug('No anonymous access at all') # move on to proper user auth
231 else:
223 else:
232 if self._check_permission(action, default_authuser, repo_name):
224 if self._check_permission(action, default_authuser, repo_name):
233 return default_authuser, None
225 return default_authuser, None
234 log.debug('Not authorized to access this repository as anonymous user')
226 log.debug('Not authorized to access this repository as anonymous user')
235
227
236 username = None
228 username = None
237 #==============================================================
229 #==============================================================
238 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
230 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
239 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
231 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
240 #==============================================================
232 #==============================================================
241
233
242 # try to auth based on environ, container auth methods
234 # try to auth based on environ, container auth methods
243 log.debug('Running PRE-AUTH for container based authentication')
235 log.debug('Running PRE-AUTH for container based authentication')
244 pre_auth = auth_modules.authenticate('', '', environ)
236 pre_auth = auth_modules.authenticate('', '', environ)
245 if pre_auth is not None and pre_auth.get('username'):
237 if pre_auth is not None and pre_auth.get('username'):
246 username = pre_auth['username']
238 username = pre_auth['username']
247 log.debug('PRE-AUTH got %s as username', username)
239 log.debug('PRE-AUTH got %s as username', username)
248
240
249 # If not authenticated by the container, running basic auth
241 # If not authenticated by the container, running basic auth
250 if not username:
242 if not username:
251 self.authenticate.realm = self.config['realm']
243 self.authenticate.realm = self.config['realm']
252 result = self.authenticate(environ)
244 result = self.authenticate(environ)
253 if isinstance(result, str):
245 if isinstance(result, str):
254 paste.httpheaders.AUTH_TYPE.update(environ, 'basic')
246 paste.httpheaders.AUTH_TYPE.update(environ, 'basic')
255 paste.httpheaders.REMOTE_USER.update(environ, result)
247 paste.httpheaders.REMOTE_USER.update(environ, result)
256 username = result
248 username = result
257 else:
249 else:
258 return None, result.wsgi_application
250 return None, result.wsgi_application
259
251
260 #==============================================================
252 #==============================================================
261 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
253 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
262 #==============================================================
254 #==============================================================
263 try:
255 try:
264 user = db.User.get_by_username_or_email(username)
256 user = db.User.get_by_username_or_email(username)
265 except Exception:
257 except Exception:
266 log.error(traceback.format_exc())
258 log.error(traceback.format_exc())
267 return None, webob.exc.HTTPInternalServerError()
259 return None, webob.exc.HTTPInternalServerError()
268
260
269 authuser = AuthUser.make(dbuser=user, ip_addr=ip_addr)
261 authuser = AuthUser.make(dbuser=user, ip_addr=ip_addr)
270 if authuser is None:
262 if authuser is None:
271 return None, webob.exc.HTTPForbidden()
263 return None, webob.exc.HTTPForbidden()
272 if not self._check_permission(action, authuser, repo_name):
264 if not self._check_permission(action, authuser, repo_name):
273 return None, webob.exc.HTTPForbidden()
265 return None, webob.exc.HTTPForbidden()
274
266
275 return user, None
267 return user, None
276
268
277 def _handle_request(self, environ, start_response):
269 def _handle_request(self, environ, start_response):
278 raise NotImplementedError()
270 raise NotImplementedError()
279
271
280 def _check_permission(self, action, authuser, repo_name):
272 def _check_permission(self, action, authuser, repo_name):
281 """
273 """
282 :param action: 'push' or 'pull'
274 :param action: 'push' or 'pull'
283 :param user: `AuthUser` instance
275 :param user: `AuthUser` instance
284 :param repo_name: repository name
276 :param repo_name: repository name
285 """
277 """
286 if action == 'push':
278 if action == 'push':
287 if not HasPermissionAnyMiddleware('repository.write',
279 if not HasPermissionAnyMiddleware('repository.write',
288 'repository.admin')(authuser,
280 'repository.admin')(authuser,
289 repo_name):
281 repo_name):
290 return False
282 return False
291
283
292 elif action == 'pull':
284 elif action == 'pull':
293 #any other action need at least read permission
285 #any other action need at least read permission
294 if not HasPermissionAnyMiddleware('repository.read',
286 if not HasPermissionAnyMiddleware('repository.read',
295 'repository.write',
287 'repository.write',
296 'repository.admin')(authuser,
288 'repository.admin')(authuser,
297 repo_name):
289 repo_name):
298 return False
290 return False
299
291
300 else:
292 else:
301 assert False, action
293 assert False, action
302
294
303 return True
295 return True
304
296
305 def __call__(self, environ, start_response):
297 def __call__(self, environ, start_response):
306 try:
298 try:
307 # try parsing a request for this VCS - if it fails, call the wrapped app
299 # try parsing a request for this VCS - if it fails, call the wrapped app
308 parsed_request = self.parse_request(environ)
300 parsed_request = self.parse_request(environ)
309 if parsed_request is None:
301 if parsed_request is None:
310 return self.application(environ, start_response)
302 return self.application(environ, start_response)
311
303
312 # skip passing error to error controller
304 # skip passing error to error controller
313 environ['pylons.status_code_redirect'] = True
305 environ['pylons.status_code_redirect'] = True
314
306
315 # quick check if repo exists...
307 # quick check if repo exists...
316 if not is_valid_repo(parsed_request.repo_name, self.basepath, self.scm_alias):
308 if not is_valid_repo(parsed_request.repo_name, self.basepath, self.scm_alias):
317 raise webob.exc.HTTPNotFound()
309 raise webob.exc.HTTPNotFound()
318
310
319 if parsed_request.action is None:
311 if parsed_request.action is None:
320 # Note: the client doesn't get the helpful error message
312 # Note: the client doesn't get the helpful error message
321 raise webob.exc.HTTPBadRequest('Unable to detect pull/push action for %r! Are you using a nonstandard command or client?' % parsed_request.repo_name)
313 raise webob.exc.HTTPBadRequest('Unable to detect pull/push action for %r! Are you using a nonstandard command or client?' % parsed_request.repo_name)
322
314
323 #======================================================================
315 #======================================================================
324 # CHECK PERMISSIONS
316 # CHECK PERMISSIONS
325 #======================================================================
317 #======================================================================
326 ip_addr = get_ip_addr(environ)
318 ip_addr = get_ip_addr(environ)
327 user, response_app = self._authorize(environ, parsed_request.action, parsed_request.repo_name, ip_addr)
319 user, response_app = self._authorize(environ, parsed_request.action, parsed_request.repo_name, ip_addr)
328 if response_app is not None:
320 if response_app is not None:
329 return response_app(environ, start_response)
321 return response_app(environ, start_response)
330
322
331 #======================================================================
323 #======================================================================
332 # REQUEST HANDLING
324 # REQUEST HANDLING
333 #======================================================================
325 #======================================================================
334 set_hook_environment(user.username, ip_addr,
326 set_hook_environment(user.username, ip_addr,
335 parsed_request.repo_name, self.scm_alias, parsed_request.action)
327 parsed_request.repo_name, self.scm_alias, parsed_request.action)
336
328
337 try:
329 try:
338 log.info('%s action on %s repo "%s" by "%s" from %s',
330 log.info('%s action on %s repo "%s" by "%s" from %s',
339 parsed_request.action, self.scm_alias, parsed_request.repo_name, user.username, ip_addr)
331 parsed_request.action, self.scm_alias, parsed_request.repo_name, user.username, ip_addr)
340 app = self._make_app(parsed_request)
332 app = self._make_app(parsed_request)
341 return app(environ, start_response)
333 return app(environ, start_response)
342 except Exception:
334 except Exception:
343 log.error(traceback.format_exc())
335 log.error(traceback.format_exc())
344 raise webob.exc.HTTPInternalServerError()
336 raise webob.exc.HTTPInternalServerError()
345
337
346 except webob.exc.HTTPException as e:
338 except webob.exc.HTTPException as e:
347 return e(environ, start_response)
339 return e(environ, start_response)
348
340
349
341
350 class BaseController(TGController):
342 class BaseController(TGController):
351
343
352 def _before(self, *args, **kwargs):
344 def _before(self, *args, **kwargs):
353 """
345 """
354 _before is called before controller methods and after __call__
346 _before is called before controller methods and after __call__
355 """
347 """
356 if request.needs_csrf_check:
348 if request.needs_csrf_check:
357 # CSRF protection: Whenever a request has ambient authority (whether
349 # CSRF protection: Whenever a request has ambient authority (whether
358 # through a session cookie or its origin IP address), it must include
350 # through a session cookie or its origin IP address), it must include
359 # the correct token, unless the HTTP method is GET or HEAD (and thus
351 # the correct token, unless the HTTP method is GET or HEAD (and thus
360 # guaranteed to be side effect free. In practice, the only situation
352 # guaranteed to be side effect free. In practice, the only situation
361 # where we allow side effects without ambient authority is when the
353 # where we allow side effects without ambient authority is when the
362 # authority comes from an API key; and that is handled above.
354 # authority comes from an API key; and that is handled above.
363 token = request.POST.get(webutils.session_csrf_secret_name)
355 token = request.POST.get(webutils.session_csrf_secret_name)
364 if not token or token != webutils.session_csrf_secret_token():
356 if not token or token != webutils.session_csrf_secret_token():
365 log.error('CSRF check failed')
357 log.error('CSRF check failed')
366 raise webob.exc.HTTPForbidden()
358 raise webob.exc.HTTPForbidden()
367
359
368 c.kallithea_version = kallithea.__version__
360 c.kallithea_version = kallithea.__version__
369 settings = db.Setting.get_app_settings()
361 settings = db.Setting.get_app_settings()
370
362
371 # Visual options
363 # Visual options
372 c.visual = AttributeDict({})
364 c.visual = AttributeDict({})
373
365
374 ## DB stored
366 ## DB stored
375 c.visual.show_public_icon = asbool(settings.get('show_public_icon'))
367 c.visual.show_public_icon = asbool(settings.get('show_public_icon'))
376 c.visual.show_private_icon = asbool(settings.get('show_private_icon'))
368 c.visual.show_private_icon = asbool(settings.get('show_private_icon'))
377 c.visual.stylify_metalabels = asbool(settings.get('stylify_metalabels'))
369 c.visual.stylify_metalabels = asbool(settings.get('stylify_metalabels'))
378 c.visual.page_size = safe_int(settings.get('dashboard_items', 100))
370 c.visual.page_size = safe_int(settings.get('dashboard_items', 100))
379 c.visual.admin_grid_items = safe_int(settings.get('admin_grid_items', 100))
371 c.visual.admin_grid_items = safe_int(settings.get('admin_grid_items', 100))
380 c.visual.repository_fields = asbool(settings.get('repository_fields'))
372 c.visual.repository_fields = asbool(settings.get('repository_fields'))
381 c.visual.show_version = asbool(settings.get('show_version'))
373 c.visual.show_version = asbool(settings.get('show_version'))
382 c.visual.use_gravatar = asbool(settings.get('use_gravatar'))
374 c.visual.use_gravatar = asbool(settings.get('use_gravatar'))
383 c.visual.gravatar_url = settings.get('gravatar_url')
375 c.visual.gravatar_url = settings.get('gravatar_url')
384
376
385 c.ga_code = settings.get('ga_code')
377 c.ga_code = settings.get('ga_code')
386 # TODO: replace undocumented backwards compatibility hack with db upgrade and rename ga_code
378 # TODO: replace undocumented backwards compatibility hack with db upgrade and rename ga_code
387 if c.ga_code and '<' not in c.ga_code:
379 if c.ga_code and '<' not in c.ga_code:
388 c.ga_code = '''<script type="text/javascript">
380 c.ga_code = '''<script type="text/javascript">
389 var _gaq = _gaq || [];
381 var _gaq = _gaq || [];
390 _gaq.push(['_setAccount', '%s']);
382 _gaq.push(['_setAccount', '%s']);
391 _gaq.push(['_trackPageview']);
383 _gaq.push(['_trackPageview']);
392
384
393 (function() {
385 (function() {
394 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
386 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
395 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
387 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
396 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
388 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
397 })();
389 })();
398 </script>''' % c.ga_code
390 </script>''' % c.ga_code
399 c.site_name = settings.get('title')
391 c.site_name = settings.get('title')
400 c.clone_uri_tmpl = settings.get('clone_uri_tmpl') or db.Repository.DEFAULT_CLONE_URI
392 c.clone_uri_tmpl = settings.get('clone_uri_tmpl') or db.Repository.DEFAULT_CLONE_URI
401 c.clone_ssh_tmpl = settings.get('clone_ssh_tmpl') or db.Repository.DEFAULT_CLONE_SSH
393 c.clone_ssh_tmpl = settings.get('clone_ssh_tmpl') or db.Repository.DEFAULT_CLONE_SSH
402
394
403 ## INI stored
395 ## INI stored
404 c.visual.allow_repo_location_change = asbool(config.get('allow_repo_location_change', True))
396 c.visual.allow_repo_location_change = asbool(config.get('allow_repo_location_change', True))
405 c.visual.allow_custom_hooks_settings = asbool(config.get('allow_custom_hooks_settings', True))
397 c.visual.allow_custom_hooks_settings = asbool(config.get('allow_custom_hooks_settings', True))
406 c.ssh_enabled = asbool(config.get('ssh_enabled', False))
398 c.ssh_enabled = asbool(config.get('ssh_enabled', False))
407
399
408 c.instance_id = config.get('instance_id')
400 c.instance_id = config.get('instance_id')
409 c.issues_url = config.get('bugtracker', url('issues_url'))
401 c.issues_url = config.get('bugtracker', url('issues_url'))
410 # END CONFIG VARS
402 # END CONFIG VARS
411
403
412 c.repo_name = get_repo_slug(request) # can be empty
404 c.repo_name = get_repo_slug(request) # can be empty
413 c.backends = list(kallithea.BACKENDS)
405 c.backends = list(kallithea.BACKENDS)
414
406
415 self.cut_off_limit = safe_int(config.get('cut_off_limit'))
407 self.cut_off_limit = safe_int(config.get('cut_off_limit'))
416
408
417 c.my_pr_count = db.PullRequest.query(reviewer_id=request.authuser.user_id, include_closed=False).count()
409 c.my_pr_count = db.PullRequest.query(reviewer_id=request.authuser.user_id, include_closed=False).count()
418
410
419 self.scm_model = ScmModel()
411 self.scm_model = ScmModel()
420
412
421 @staticmethod
413 @staticmethod
422 def _determine_auth_user(session_authuser, ip_addr):
414 def _determine_auth_user(session_authuser, ip_addr):
423 """
415 """
424 Create an `AuthUser` object given the API key/bearer token
416 Create an `AuthUser` object given the API key/bearer token
425 (if any) and the value of the authuser session cookie.
417 (if any) and the value of the authuser session cookie.
426 Returns None if no valid user is found (like not active or no access for IP).
418 Returns None if no valid user is found (like not active or no access for IP).
427 """
419 """
428
420
429 # Authenticate by session cookie
421 # Authenticate by session cookie
430 # In ancient login sessions, 'authuser' may not be a dict.
422 # In ancient login sessions, 'authuser' may not be a dict.
431 # In that case, the user will have to log in again.
423 # In that case, the user will have to log in again.
432 # v0.3 and earlier included an 'is_authenticated' key; if present,
424 # v0.3 and earlier included an 'is_authenticated' key; if present,
433 # this must be True.
425 # this must be True.
434 if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True):
426 if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True):
435 return AuthUser.from_cookie(session_authuser, ip_addr=ip_addr)
427 return AuthUser.from_cookie(session_authuser, ip_addr=ip_addr)
436
428
437 # Authenticate by auth_container plugin (if enabled)
429 # Authenticate by auth_container plugin (if enabled)
438 if any(
430 if any(
439 plugin.is_container_auth
431 plugin.is_container_auth
440 for plugin in auth_modules.get_auth_plugins()
432 for plugin in auth_modules.get_auth_plugins()
441 ):
433 ):
442 try:
434 try:
443 user_info = auth_modules.authenticate('', '', request.environ)
435 user_info = auth_modules.authenticate('', '', request.environ)
444 except UserCreationError as e:
436 except UserCreationError as e:
445 webutils.flash(e, 'error', logf=log.error)
437 webutils.flash(e, 'error', logf=log.error)
446 else:
438 else:
447 if user_info is not None:
439 if user_info is not None:
448 username = user_info['username']
440 username = user_info['username']
449 user = db.User.get_by_username(username, case_insensitive=True)
441 user = db.User.get_by_username(username, case_insensitive=True)
450 return log_in_user(user, remember=False, is_external_auth=True, ip_addr=ip_addr)
442 return log_in_user(user, remember=False, is_external_auth=True, ip_addr=ip_addr)
451
443
452 # User is default user (if active) or anonymous
444 # User is default user (if active) or anonymous
453 default_user = db.User.get_default_user()
445 default_user = db.User.get_default_user()
454 authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
446 authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
455 if authuser is None: # fall back to anonymous
447 if authuser is None: # fall back to anonymous
456 authuser = AuthUser(dbuser=default_user) # TODO: somehow use .make?
448 authuser = AuthUser(dbuser=default_user) # TODO: somehow use .make?
457 return authuser
449 return authuser
458
450
459 @staticmethod
451 @staticmethod
460 def _basic_security_checks():
452 def _basic_security_checks():
461 """Perform basic security/sanity checks before processing the request."""
453 """Perform basic security/sanity checks before processing the request."""
462
454
463 # Only allow the following HTTP request methods.
455 # Only allow the following HTTP request methods.
464 if request.method not in ['GET', 'HEAD', 'POST']:
456 if request.method not in ['GET', 'HEAD', 'POST']:
465 raise webob.exc.HTTPMethodNotAllowed()
457 raise webob.exc.HTTPMethodNotAllowed()
466
458
467 # Also verify the _method override - no longer allowed.
459 # Also verify the _method override - no longer allowed.
468 if request.params.get('_method') is None:
460 if request.params.get('_method') is None:
469 pass # no override, no problem
461 pass # no override, no problem
470 else:
462 else:
471 raise webob.exc.HTTPMethodNotAllowed()
463 raise webob.exc.HTTPMethodNotAllowed()
472
464
473 # Make sure CSRF token never appears in the URL. If so, invalidate it.
465 # Make sure CSRF token never appears in the URL. If so, invalidate it.
474 if webutils.session_csrf_secret_name in request.GET:
466 if webutils.session_csrf_secret_name in request.GET:
475 log.error('CSRF key leak detected')
467 log.error('CSRF key leak detected')
476 session.pop(webutils.session_csrf_secret_name, None)
468 session.pop(webutils.session_csrf_secret_name, None)
477 session.save()
469 session.save()
478 webutils.flash(_('CSRF token leak has been detected - all form tokens have been expired'),
470 webutils.flash(_('CSRF token leak has been detected - all form tokens have been expired'),
479 category='error')
471 category='error')
480
472
481 # WebOb already ignores request payload parameters for anything other
473 # WebOb already ignores request payload parameters for anything other
482 # than POST/PUT, but double-check since other Kallithea code relies on
474 # than POST/PUT, but double-check since other Kallithea code relies on
483 # this assumption.
475 # this assumption.
484 if request.method not in ['POST', 'PUT'] and request.POST:
476 if request.method not in ['POST', 'PUT'] and request.POST:
485 log.error('%r request with payload parameters; WebOb should have stopped this', request.method)
477 log.error('%r request with payload parameters; WebOb should have stopped this', request.method)
486 raise webob.exc.HTTPBadRequest()
478 raise webob.exc.HTTPBadRequest()
487
479
488 def __call__(self, environ, context):
480 def __call__(self, environ, context):
489 try:
481 try:
490 ip_addr = get_ip_addr(environ)
482 ip_addr = get_ip_addr(environ)
491 self._basic_security_checks()
483 self._basic_security_checks()
492
484
493 api_key = request.GET.get('api_key')
485 api_key = request.GET.get('api_key')
494 try:
486 try:
495 # Request.authorization may raise ValueError on invalid input
487 # Request.authorization may raise ValueError on invalid input
496 type, params = request.authorization
488 type, params = request.authorization
497 except (ValueError, TypeError):
489 except (ValueError, TypeError):
498 pass
490 pass
499 else:
491 else:
500 if type.lower() == 'bearer':
492 if type.lower() == 'bearer':
501 api_key = params # bearer token is an api key too
493 api_key = params # bearer token is an api key too
502
494
503 if api_key is None:
495 if api_key is None:
504 authuser = self._determine_auth_user(
496 authuser = self._determine_auth_user(
505 session.get('authuser'),
497 session.get('authuser'),
506 ip_addr=ip_addr,
498 ip_addr=ip_addr,
507 )
499 )
508 needs_csrf_check = request.method not in ['GET', 'HEAD']
500 needs_csrf_check = request.method not in ['GET', 'HEAD']
509
501
510 else:
502 else:
511 dbuser = db.User.get_by_api_key(api_key)
503 dbuser = db.User.get_by_api_key(api_key)
512 if dbuser is None:
504 if dbuser is None:
513 log.info('No db user found for authentication with API key ****%s from %s',
505 log.info('No db user found for authentication with API key ****%s from %s',
514 api_key[-4:], ip_addr)
506 api_key[-4:], ip_addr)
515 authuser = AuthUser.make(dbuser=dbuser, is_external_auth=True, ip_addr=ip_addr)
507 authuser = AuthUser.make(dbuser=dbuser, is_external_auth=True, ip_addr=ip_addr)
516 needs_csrf_check = False # API key provides CSRF protection
508 needs_csrf_check = False # API key provides CSRF protection
517
509
518 if authuser is None:
510 if authuser is None:
519 log.info('No valid user found')
511 log.info('No valid user found')
520 raise webob.exc.HTTPForbidden()
512 raise webob.exc.HTTPForbidden()
521
513
522 # set globals for auth user
514 # set globals for auth user
523 request.authuser = authuser
515 request.authuser = authuser
524 request.ip_addr = ip_addr
516 request.ip_addr = ip_addr
525 request.needs_csrf_check = needs_csrf_check
517 request.needs_csrf_check = needs_csrf_check
526
518
527 log.info('IP: %s User: %s Request: %s',
519 log.info('IP: %s User: %s Request: %s',
528 request.ip_addr, request.authuser,
520 request.ip_addr, request.authuser,
529 get_path_info(environ),
521 get_path_info(environ),
530 )
522 )
531 return super(BaseController, self).__call__(environ, context)
523 return super(BaseController, self).__call__(environ, context)
532 except webob.exc.HTTPException as e:
524 except webob.exc.HTTPException as e:
533 return e
525 return e
534
526
535
527
536 class BaseRepoController(BaseController):
528 class BaseRepoController(BaseController):
537 """
529 """
538 Base class for controllers responsible for loading all needed data for
530 Base class for controllers responsible for loading all needed data for
539 repository loaded items are
531 repository loaded items are
540
532
541 c.db_repo_scm_instance: instance of scm repository
533 c.db_repo_scm_instance: instance of scm repository
542 c.db_repo: instance of db
534 c.db_repo: instance of db
543 c.repository_followers: number of followers
535 c.repository_followers: number of followers
544 c.repository_forks: number of forks
536 c.repository_forks: number of forks
545 c.repository_following: weather the current user is following the current repo
537 c.repository_following: weather the current user is following the current repo
546 """
538 """
547
539
548 def _before(self, *args, **kwargs):
540 def _before(self, *args, **kwargs):
549 super(BaseRepoController, self)._before(*args, **kwargs)
541 super(BaseRepoController, self)._before(*args, **kwargs)
550 if c.repo_name: # extracted from request by base-base BaseController._before
542 if c.repo_name: # extracted from request by base-base BaseController._before
551 _dbr = db.Repository.get_by_repo_name(c.repo_name)
543 _dbr = db.Repository.get_by_repo_name(c.repo_name)
552 if not _dbr:
544 if not _dbr:
553 return
545 return
554
546
555 log.debug('Found repository in database %s with state `%s`',
547 log.debug('Found repository in database %s with state `%s`',
556 _dbr, _dbr.repo_state)
548 _dbr, _dbr.repo_state)
557 route = getattr(request.environ.get('routes.route'), 'name', '')
549 route = getattr(request.environ.get('routes.route'), 'name', '')
558
550
559 # allow to delete repos that are somehow damages in filesystem
551 # allow to delete repos that are somehow damages in filesystem
560 if route in ['delete_repo']:
552 if route in ['delete_repo']:
561 return
553 return
562
554
563 if _dbr.repo_state in [db.Repository.STATE_PENDING]:
555 if _dbr.repo_state in [db.Repository.STATE_PENDING]:
564 if route in ['repo_creating_home']:
556 if route in ['repo_creating_home']:
565 return
557 return
566 check_url = url('repo_creating_home', repo_name=c.repo_name)
558 check_url = url('repo_creating_home', repo_name=c.repo_name)
567 raise webob.exc.HTTPFound(location=check_url)
559 raise webob.exc.HTTPFound(location=check_url)
568
560
569 dbr = c.db_repo = _dbr
561 dbr = c.db_repo = _dbr
570 c.db_repo_scm_instance = c.db_repo.scm_instance
562 c.db_repo_scm_instance = c.db_repo.scm_instance
571 if c.db_repo_scm_instance is None:
563 if c.db_repo_scm_instance is None:
572 log.error('%s this repository is present in database but it '
564 log.error('%s this repository is present in database but it '
573 'cannot be created as an scm instance', c.repo_name)
565 'cannot be created as an scm instance', c.repo_name)
574 webutils.flash(_('Repository not found in the filesystem'),
566 webutils.flash(_('Repository not found in the filesystem'),
575 category='error')
567 category='error')
576 raise webob.exc.HTTPNotFound()
568 raise webob.exc.HTTPNotFound()
577
569
578 # some globals counter for menu
570 # some globals counter for menu
579 c.repository_followers = self.scm_model.get_followers(dbr)
571 c.repository_followers = self.scm_model.get_followers(dbr)
580 c.repository_forks = self.scm_model.get_forks(dbr)
572 c.repository_forks = self.scm_model.get_forks(dbr)
581 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
573 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
582 c.repository_following = self.scm_model.is_following_repo(
574 c.repository_following = self.scm_model.is_following_repo(
583 c.repo_name, request.authuser.user_id)
575 c.repo_name, request.authuser.user_id)
584
576
585 @staticmethod
577 @staticmethod
586 def _get_ref_rev(repo, ref_type, ref_name, returnempty=False):
578 def _get_ref_rev(repo, ref_type, ref_name, returnempty=False):
587 """
579 """
588 Safe way to get changeset. If error occurs show error.
580 Safe way to get changeset. If error occurs show error.
589 """
581 """
590 try:
582 try:
591 return repo.scm_instance.get_ref_revision(ref_type, ref_name)
583 return repo.scm_instance.get_ref_revision(ref_type, ref_name)
592 except EmptyRepositoryError as e:
584 except EmptyRepositoryError as e:
593 if returnempty:
585 if returnempty:
594 return repo.scm_instance.EMPTY_CHANGESET
586 return repo.scm_instance.EMPTY_CHANGESET
595 webutils.flash(_('There are no changesets yet'), category='error')
587 webutils.flash(_('There are no changesets yet'), category='error')
596 raise webob.exc.HTTPNotFound()
588 raise webob.exc.HTTPNotFound()
597 except ChangesetDoesNotExistError as e:
589 except ChangesetDoesNotExistError as e:
598 webutils.flash(_('Changeset for %s %s not found in %s') %
590 webutils.flash(_('Changeset for %s %s not found in %s') %
599 (ref_type, ref_name, repo.repo_name),
591 (ref_type, ref_name, repo.repo_name),
600 category='error')
592 category='error')
601 raise webob.exc.HTTPNotFound()
593 raise webob.exc.HTTPNotFound()
602 except RepositoryError as e:
594 except RepositoryError as e:
603 log.error(traceback.format_exc())
595 log.error(traceback.format_exc())
604 webutils.flash(e, category='error')
596 webutils.flash(e, category='error')
605 raise webob.exc.HTTPBadRequest()
597 raise webob.exc.HTTPBadRequest()
606
598
607
599
608 @decorator.decorator
600 @decorator.decorator
609 def jsonify(func, *args, **kwargs):
601 def jsonify(func, *args, **kwargs):
610 """Action decorator that formats output for JSON
602 """Action decorator that formats output for JSON
611
603
612 Given a function that will return content, this decorator will turn
604 Given a function that will return content, this decorator will turn
613 the result into JSON, with a content-type of 'application/json' and
605 the result into JSON, with a content-type of 'application/json' and
614 output it.
606 output it.
615 """
607 """
616 response.headers['Content-Type'] = 'application/json; charset=utf-8'
608 response.headers['Content-Type'] = 'application/json; charset=utf-8'
617 data = func(*args, **kwargs)
609 data = func(*args, **kwargs)
618 if isinstance(data, (list, tuple)):
610 if isinstance(data, (list, tuple)):
619 # A JSON list response is syntactically valid JavaScript and can be
611 # A JSON list response is syntactically valid JavaScript and can be
620 # loaded and executed as JavaScript by a malicious third-party site
612 # loaded and executed as JavaScript by a malicious third-party site
621 # using <script>, which can lead to cross-site data leaks.
613 # using <script>, which can lead to cross-site data leaks.
622 # JSON responses should therefore be scalars or objects (i.e. Python
614 # JSON responses should therefore be scalars or objects (i.e. Python
623 # dicts), because a JSON object is a syntax error if intepreted as JS.
615 # dicts), because a JSON object is a syntax error if intepreted as JS.
624 msg = "JSON responses with Array envelopes are susceptible to " \
616 msg = "JSON responses with Array envelopes are susceptible to " \
625 "cross-site data leak attacks, see " \
617 "cross-site data leak attacks, see " \
626 "https://web.archive.org/web/20120519231904/http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
618 "https://web.archive.org/web/20120519231904/http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
627 warnings.warn(msg, Warning, 2)
619 warnings.warn(msg, Warning, 2)
628 log.warning(msg)
620 log.warning(msg)
629 log.debug("Returning JSON wrapped action output")
621 log.debug("Returning JSON wrapped action output")
630 return ascii_bytes(ext_json.dumps(data))
622 return ascii_bytes(ext_json.dumps(data))
631
623
632 @decorator.decorator
624 @decorator.decorator
633 def IfSshEnabled(func, *args, **kwargs):
625 def IfSshEnabled(func, *args, **kwargs):
634 """Decorator for functions that can only be called if SSH access is enabled.
626 """Decorator for functions that can only be called if SSH access is enabled.
635
627
636 If SSH access is disabled in the configuration file, HTTPNotFound is raised.
628 If SSH access is disabled in the configuration file, HTTPNotFound is raised.
637 """
629 """
638 if not c.ssh_enabled:
630 if not c.ssh_enabled:
639 webutils.flash(_("SSH access is disabled."), category='warning')
631 webutils.flash(_("SSH access is disabled."), category='warning')
640 raise webob.exc.HTTPNotFound()
632 raise webob.exc.HTTPNotFound()
641 return func(*args, **kwargs)
633 return func(*args, **kwargs)
@@ -1,590 +1,593 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%text>##</%text>#################################################################################
2 <%text>##</%text>#################################################################################
3 <%text>##</%text>#################################################################################
3 <%text>##</%text>#################################################################################
4 <%text>##</%text> Kallithea config file generated with kallithea-cli ${'%-27s' % version }##
4 <%text>##</%text> Kallithea config file generated with kallithea-cli ${'%-27s' % version }##
5 <%text>##</%text> ##
5 <%text>##</%text> ##
6 <%text>##</%text> The %(here)s variable will generally be replaced with the parent directory of ##
6 <%text>##</%text> The %(here)s variable will generally be replaced with the parent directory of ##
7 <%text>##</%text> this file. Other use of % must be escaped as %% . ##
7 <%text>##</%text> this file. Other use of % must be escaped as %% . ##
8 <%text>##</%text>#################################################################################
8 <%text>##</%text>#################################################################################
9 <%text>##</%text>#################################################################################
9 <%text>##</%text>#################################################################################
10
10
11 [DEFAULT]
11 [DEFAULT]
12
12
13 <%text>##</%text>##############################################################################
13 <%text>##</%text>##############################################################################
14 <%text>##</%text> Email settings ##
14 <%text>##</%text> Email settings ##
15 <%text>##</%text> ##
15 <%text>##</%text> ##
16 <%text>##</%text> Refer to the documentation ("Email settings") for more details. ##
16 <%text>##</%text> Refer to the documentation ("Email settings") for more details. ##
17 <%text>##</%text> ##
17 <%text>##</%text> ##
18 <%text>##</%text> It is recommended to use a valid sender address that passes access ##
18 <%text>##</%text> It is recommended to use a valid sender address that passes access ##
19 <%text>##</%text> validation and spam filtering in mail servers. ##
19 <%text>##</%text> validation and spam filtering in mail servers. ##
20 <%text>##</%text>##############################################################################
20 <%text>##</%text>##############################################################################
21
21
22 <%text>##</%text> 'From' header for application emails. You can optionally add a name.
22 <%text>##</%text> 'From' header for application emails. You can optionally add a name.
23 <%text>##</%text> Default:
23 <%text>##</%text> Default:
24 #app_email_from = Kallithea
24 #app_email_from = Kallithea
25 <%text>##</%text> Examples:
25 <%text>##</%text> Examples:
26 #app_email_from = Kallithea <kallithea-noreply@example.com>
26 #app_email_from = Kallithea <kallithea-noreply@example.com>
27 #app_email_from = kallithea-noreply@example.com
27 #app_email_from = kallithea-noreply@example.com
28
28
29 <%text>##</%text> Subject prefix for application emails.
29 <%text>##</%text> Subject prefix for application emails.
30 <%text>##</%text> A space between this prefix and the real subject is automatically added.
30 <%text>##</%text> A space between this prefix and the real subject is automatically added.
31 <%text>##</%text> Default:
31 <%text>##</%text> Default:
32 #email_prefix =
32 #email_prefix =
33 <%text>##</%text> Example:
33 <%text>##</%text> Example:
34 #email_prefix = [Kallithea]
34 #email_prefix = [Kallithea]
35
35
36 <%text>##</%text> Recipients for error emails and fallback recipients of application mails.
36 <%text>##</%text> Recipients for error emails and fallback recipients of application mails.
37 <%text>##</%text> Multiple addresses can be specified, comma-separated.
37 <%text>##</%text> Multiple addresses can be specified, comma-separated.
38 <%text>##</%text> Only addresses are allowed, do not add any name part.
38 <%text>##</%text> Only addresses are allowed, do not add any name part.
39 <%text>##</%text> Default:
39 <%text>##</%text> Default:
40 #email_to =
40 #email_to =
41 <%text>##</%text> Examples:
41 <%text>##</%text> Examples:
42 #email_to = admin@example.com
42 #email_to = admin@example.com
43 #email_to = admin@example.com,another_admin@example.com
43 #email_to = admin@example.com,another_admin@example.com
44 email_to =
44 email_to =
45
45
46 <%text>##</%text> 'From' header for error emails. You can optionally add a name.
46 <%text>##</%text> 'From' header for error emails. You can optionally add a name.
47 <%text>##</%text> Default: (none)
47 <%text>##</%text> Default: (none)
48 <%text>##</%text> Examples:
48 <%text>##</%text> Examples:
49 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
49 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
50 #error_email_from = kallithea_errors@example.com
50 #error_email_from = kallithea_errors@example.com
51 error_email_from =
51 error_email_from =
52
52
53 <%text>##</%text> SMTP server settings
53 <%text>##</%text> SMTP server settings
54 <%text>##</%text> If specifying credentials, make sure to use secure connections.
54 <%text>##</%text> If specifying credentials, make sure to use secure connections.
55 <%text>##</%text> Default: Send unencrypted unauthenticated mails to the specified smtp_server.
55 <%text>##</%text> Default: Send unencrypted unauthenticated mails to the specified smtp_server.
56 <%text>##</%text> For "SSL", use smtp_use_ssl = true and smtp_port = 465.
56 <%text>##</%text> For "SSL", use smtp_use_ssl = true and smtp_port = 465.
57 <%text>##</%text> For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
57 <%text>##</%text> For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
58 smtp_server =
58 smtp_server =
59 smtp_username =
59 smtp_username =
60 smtp_password =
60 smtp_password =
61 smtp_port =
61 smtp_port =
62 smtp_use_ssl = false
62 smtp_use_ssl = false
63 smtp_use_tls = false
63 smtp_use_tls = false
64
64
65 %if http_server != 'uwsgi':
65 %if http_server != 'uwsgi':
66 <%text>##</%text> Entry point for 'gearbox serve'
66 <%text>##</%text> Entry point for 'gearbox serve'
67 [server:main]
67 [server:main]
68 host = ${host}
68 host = ${host}
69 port = ${port}
69 port = ${port}
70
70
71 %if http_server == 'gearbox':
71 %if http_server == 'gearbox':
72 <%text>##</%text> Gearbox serve uses the built-in development web server ##
72 <%text>##</%text> Gearbox serve uses the built-in development web server ##
73 use = egg:gearbox#wsgiref
73 use = egg:gearbox#wsgiref
74 <%text>##</%text> nr of worker threads to spawn
74 <%text>##</%text> nr of worker threads to spawn
75 threadpool_workers = 1
75 threadpool_workers = 1
76 <%text>##</%text> max request before thread respawn
76 <%text>##</%text> max request before thread respawn
77 threadpool_max_requests = 100
77 threadpool_max_requests = 100
78 <%text>##</%text> option to use threads of process
78 <%text>##</%text> option to use threads of process
79 use_threadpool = true
79 use_threadpool = true
80
80
81 %elif http_server == 'gevent':
81 %elif http_server == 'gevent':
82 <%text>##</%text> Gearbox serve uses the gevent web server ##
82 <%text>##</%text> Gearbox serve uses the gevent web server ##
83 use = egg:gearbox#gevent
83 use = egg:gearbox#gevent
84
84
85 %elif http_server == 'waitress':
85 %elif http_server == 'waitress':
86 <%text>##</%text> Gearbox serve uses the Waitress web server ##
86 <%text>##</%text> Gearbox serve uses the Waitress web server ##
87 use = egg:waitress#main
87 use = egg:waitress#main
88 <%text>##</%text> avoid multi threading
88 <%text>##</%text> avoid multi threading
89 threads = 1
89 threads = 1
90 <%text>##</%text> allow push of repos bigger than the default of 1 GB
90 <%text>##</%text> allow push of repos bigger than the default of 1 GB
91 max_request_body_size = 107374182400
91 max_request_body_size = 107374182400
92 <%text>##</%text> use poll instead of select, fixes fd limits, may not work on old
92 <%text>##</%text> use poll instead of select, fixes fd limits, may not work on old
93 <%text>##</%text> windows systems.
93 <%text>##</%text> windows systems.
94 #asyncore_use_poll = True
94 #asyncore_use_poll = True
95
95
96 %elif http_server == 'gunicorn':
96 %elif http_server == 'gunicorn':
97 <%text>##</%text> Gearbox serve uses the Gunicorn web server ##
97 <%text>##</%text> Gearbox serve uses the Gunicorn web server ##
98 use = egg:gunicorn#main
98 use = egg:gunicorn#main
99 <%text>##</%text> number of process workers. You must set `instance_id = *` when this option
99 <%text>##</%text> number of process workers. You must set `instance_id = *` when this option
100 <%text>##</%text> is set to more than one worker
100 <%text>##</%text> is set to more than one worker
101 workers = 4
101 workers = 4
102 <%text>##</%text> process name
102 <%text>##</%text> process name
103 proc_name = kallithea
103 proc_name = kallithea
104 <%text>##</%text> type of worker class, one of sync, eventlet, gevent, tornado
104 <%text>##</%text> type of worker class, one of sync, eventlet, gevent, tornado
105 <%text>##</%text> recommended for bigger setup is using of of other than sync one
105 <%text>##</%text> recommended for bigger setup is using of of other than sync one
106 worker_class = sync
106 worker_class = sync
107 max_requests = 1000
107 max_requests = 1000
108 <%text>##</%text> amount of time a worker can handle request before it gets killed and
108 <%text>##</%text> amount of time a worker can handle request before it gets killed and
109 <%text>##</%text> restarted
109 <%text>##</%text> restarted
110 timeout = 3600
110 timeout = 3600
111
111
112 %endif
112 %endif
113 %else:
113 %else:
114 <%text>##</%text> UWSGI ##
114 <%text>##</%text> UWSGI ##
115 [uwsgi]
115 [uwsgi]
116 <%text>##</%text> Note: this section is parsed by the uWSGI .ini parser when run as:
116 <%text>##</%text> Note: this section is parsed by the uWSGI .ini parser when run as:
117 <%text>##</%text> uwsgi --venv /srv/kallithea/venv --ini-paste-logged my.ini
117 <%text>##</%text> uwsgi --venv /srv/kallithea/venv --ini-paste-logged my.ini
118 <%text>##</%text> Note: in uWSGI 2.0.18 or older, pastescript needs to be installed to
118 <%text>##</%text> Note: in uWSGI 2.0.18 or older, pastescript needs to be installed to
119 <%text>##</%text> get correct application logging. In later versions this is not necessary.
119 <%text>##</%text> get correct application logging. In later versions this is not necessary.
120 <%text>##</%text> pip install pastescript
120 <%text>##</%text> pip install pastescript
121
121
122 <%text>##</%text> HTTP Basics:
122 <%text>##</%text> HTTP Basics:
123 http-socket = ${host}:${port}
123 http-socket = ${host}:${port}
124 buffer-size = 65535 ; Mercurial will use huge GET headers for discovery
124 buffer-size = 65535 ; Mercurial will use huge GET headers for discovery
125
125
126 <%text>##</%text> Scaling:
126 <%text>##</%text> Scaling:
127 master = true ; Use separate master and worker processes
127 master = true ; Use separate master and worker processes
128 auto-procname = true ; Name worker processes accordingly
128 auto-procname = true ; Name worker processes accordingly
129 lazy = true ; App *must* be loaded in workers - db connections can't be shared
129 lazy = true ; App *must* be loaded in workers - db connections can't be shared
130 workers = 4 ; On demand scaling up to this many worker processes
130 workers = 4 ; On demand scaling up to this many worker processes
131 cheaper = 1 ; Initial and on demand scaling down to this many worker processes
131 cheaper = 1 ; Initial and on demand scaling down to this many worker processes
132 max-requests = 1000 ; Graceful reload of worker processes to avoid leaks
132 max-requests = 1000 ; Graceful reload of worker processes to avoid leaks
133
133
134 <%text>##</%text> Tweak defaults:
134 <%text>##</%text> Tweak defaults:
135 strict = true ; Fail on unknown config directives
135 strict = true ; Fail on unknown config directives
136 enable-threads = true ; Enable Python threads (not threaded workers)
136 enable-threads = true ; Enable Python threads (not threaded workers)
137 vacuum = true ; Delete sockets during shutdown
137 vacuum = true ; Delete sockets during shutdown
138 single-interpreter = true
138 single-interpreter = true
139 die-on-term = true ; Shutdown when receiving SIGTERM (default is respawn)
139 die-on-term = true ; Shutdown when receiving SIGTERM (default is respawn)
140 need-app = true ; Exit early if no app can be loaded.
140 need-app = true ; Exit early if no app can be loaded.
141 reload-on-exception = true ; Don't assume that the application worker can process more requests after a severe error
141 reload-on-exception = true ; Don't assume that the application worker can process more requests after a severe error
142
142
143 %endif
143 %endif
144 <%text>##</%text> middleware for hosting the WSGI application under a URL prefix
144 <%text>##</%text> middleware for hosting the WSGI application under a URL prefix
145 #[filter:proxy-prefix]
145 #[filter:proxy-prefix]
146 #use = egg:PasteDeploy#prefix
146 #use = egg:PasteDeploy#prefix
147 #prefix = /<your-prefix>
147 #prefix = /<your-prefix>
148
148
149 [app:main]
149 [app:main]
150 use = egg:kallithea
150 use = egg:kallithea
151 <%text>##</%text> enable proxy prefix middleware
151 <%text>##</%text> enable proxy prefix middleware
152 #filter-with = proxy-prefix
152 #filter-with = proxy-prefix
153
153
154 full_stack = true
154 full_stack = true
155 static_files = true
155 static_files = true
156
156
157 <%text>##</%text> Internationalization (see setup documentation for details)
157 <%text>##</%text> Internationalization (see setup documentation for details)
158 <%text>##</%text> By default, the languages requested by the browser are used if available, with English as default.
158 <%text>##</%text> By default, the languages requested by the browser are used if available, with English as default.
159 <%text>##</%text> Set i18n.enabled=false to disable automatic language choice.
159 <%text>##</%text> Set i18n.enabled=false to disable automatic language choice.
160 #i18n.enabled = true
160 #i18n.enabled = true
161 <%text>##</%text> To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
161 <%text>##</%text> To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
162 <%text>##</%text> Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
162 <%text>##</%text> Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
163 #i18n.lang = en
163 #i18n.lang = en
164
164
165 cache_dir = %(here)s/data
165 cache_dir = %(here)s/data
166 index_dir = %(here)s/data/index
166 index_dir = %(here)s/data/index
167
167
168 <%text>##</%text> uncomment and set this path to use archive download cache
168 <%text>##</%text> uncomment and set this path to use archive download cache
169 archive_cache_dir = %(here)s/data/tarballcache
169 archive_cache_dir = %(here)s/data/tarballcache
170
170
171 <%text>##</%text> change this to unique ID for security
171 <%text>##</%text> change this to unique ID for security
172 app_instance_uuid = ${uuid()}
172 app_instance_uuid = ${uuid()}
173
173
174 <%text>##</%text> cut off limit for large diffs (size in bytes)
174 <%text>##</%text> cut off limit for large diffs (size in bytes)
175 cut_off_limit = 256000
175 cut_off_limit = 256000
176
176
177 <%text>##</%text> WSGI environment variable to get the IP address of the client (default REMOTE_ADDR)
178 #remote_addr_variable = HTTP_X_FORWARDED_FOR
179
177 <%text>##</%text> always pretend the client connected using HTTPS (default false)
180 <%text>##</%text> always pretend the client connected using HTTPS (default false)
178 #force_https = true
181 #force_https = true
179
182
180 <%text>##</%text> use Strict-Transport-Security headers (default false)
183 <%text>##</%text> use Strict-Transport-Security headers (default false)
181 #use_htsts = true
184 #use_htsts = true
182
185
183 <%text>##</%text> number of commits stats will parse on each iteration
186 <%text>##</%text> number of commits stats will parse on each iteration
184 commit_parse_limit = 25
187 commit_parse_limit = 25
185
188
186 <%text>##</%text> Path to Python executable to be used for git hooks.
189 <%text>##</%text> Path to Python executable to be used for git hooks.
187 <%text>##</%text> This value will be written inside the git hook scripts as the text
190 <%text>##</%text> This value will be written inside the git hook scripts as the text
188 <%text>##</%text> after '#!' (shebang). When empty or not defined, the value of
191 <%text>##</%text> after '#!' (shebang). When empty or not defined, the value of
189 <%text>##</%text> 'sys.executable' at the time of installation of the git hooks is
192 <%text>##</%text> 'sys.executable' at the time of installation of the git hooks is
190 <%text>##</%text> used, which is correct in many cases but for example not when using uwsgi.
193 <%text>##</%text> used, which is correct in many cases but for example not when using uwsgi.
191 <%text>##</%text> If you change this setting, you should reinstall the Git hooks via
194 <%text>##</%text> If you change this setting, you should reinstall the Git hooks via
192 <%text>##</%text> Admin > Settings > Remap and Rescan.
195 <%text>##</%text> Admin > Settings > Remap and Rescan.
193 #git_hook_interpreter = /srv/kallithea/venv/bin/python3
196 #git_hook_interpreter = /srv/kallithea/venv/bin/python3
194 %if git_hook_interpreter:
197 %if git_hook_interpreter:
195 git_hook_interpreter = ${git_hook_interpreter}
198 git_hook_interpreter = ${git_hook_interpreter}
196 %endif
199 %endif
197
200
198 <%text>##</%text> path to git executable
201 <%text>##</%text> path to git executable
199 git_path = git
202 git_path = git
200
203
201 <%text>##</%text> git rev filter option, --all is the default filter, if you need to
204 <%text>##</%text> git rev filter option, --all is the default filter, if you need to
202 <%text>##</%text> hide all refs in changelog switch this to --branches --tags
205 <%text>##</%text> hide all refs in changelog switch this to --branches --tags
203 #git_rev_filter = --branches --tags
206 #git_rev_filter = --branches --tags
204
207
205 <%text>##</%text> RSS feed options
208 <%text>##</%text> RSS feed options
206 rss_cut_off_limit = 256000
209 rss_cut_off_limit = 256000
207 rss_items_per_page = 10
210 rss_items_per_page = 10
208 rss_include_diff = false
211 rss_include_diff = false
209
212
210 <%text>##</%text> options for showing and identifying changesets
213 <%text>##</%text> options for showing and identifying changesets
211 show_sha_length = 12
214 show_sha_length = 12
212 show_revision_number = false
215 show_revision_number = false
213
216
214 <%text>##</%text> Canonical URL to use when creating full URLs in UI and texts.
217 <%text>##</%text> Canonical URL to use when creating full URLs in UI and texts.
215 <%text>##</%text> Useful when the site is available under different names or protocols.
218 <%text>##</%text> Useful when the site is available under different names or protocols.
216 <%text>##</%text> Defaults to what is provided in the WSGI environment.
219 <%text>##</%text> Defaults to what is provided in the WSGI environment.
217 #canonical_url = https://kallithea.example.com/repos
220 #canonical_url = https://kallithea.example.com/repos
218
221
219 <%text>##</%text> gist URL alias, used to create nicer urls for gist. This should be an
222 <%text>##</%text> gist URL alias, used to create nicer urls for gist. This should be an
220 <%text>##</%text> url that does rewrites to _admin/gists/<gistid>.
223 <%text>##</%text> url that does rewrites to _admin/gists/<gistid>.
221 <%text>##</%text> example: http://gist.example.com/{gistid}. Empty means use the internal
224 <%text>##</%text> example: http://gist.example.com/{gistid}. Empty means use the internal
222 <%text>##</%text> Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
225 <%text>##</%text> Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
223 gist_alias_url =
226 gist_alias_url =
224
227
225 <%text>##</%text> default encoding used to convert from and to unicode
228 <%text>##</%text> default encoding used to convert from and to unicode
226 <%text>##</%text> can be also a comma separated list of encoding in case of mixed encodings
229 <%text>##</%text> can be also a comma separated list of encoding in case of mixed encodings
227 default_encoding = utf-8
230 default_encoding = utf-8
228
231
229 <%text>##</%text> Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
232 <%text>##</%text> Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
230 hgencoding = utf-8
233 hgencoding = utf-8
231
234
232 <%text>##</%text> issue tracker for Kallithea (leave blank to disable, absent for default)
235 <%text>##</%text> issue tracker for Kallithea (leave blank to disable, absent for default)
233 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
236 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
234
237
235 <%text>##</%text> issue tracking mapping for commit messages, comments, PR descriptions, ...
238 <%text>##</%text> issue tracking mapping for commit messages, comments, PR descriptions, ...
236 <%text>##</%text> Refer to the documentation ("Integration with issue trackers") for more details.
239 <%text>##</%text> Refer to the documentation ("Integration with issue trackers") for more details.
237
240
238 <%text>##</%text> regular expression to match issue references
241 <%text>##</%text> regular expression to match issue references
239 <%text>##</%text> This pattern may/should contain parenthesized groups, that can
242 <%text>##</%text> This pattern may/should contain parenthesized groups, that can
240 <%text>##</%text> be referred to in issue_server_link or issue_sub using Python backreferences
243 <%text>##</%text> be referred to in issue_server_link or issue_sub using Python backreferences
241 <%text>##</%text> (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
244 <%text>##</%text> (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
242 <%text>##</%text> To require mandatory whitespace before the issue pattern, use:
245 <%text>##</%text> To require mandatory whitespace before the issue pattern, use:
243 <%text>##</%text> (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
246 <%text>##</%text> (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
244 <%text>##</%text> behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
247 <%text>##</%text> behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
245
248
246 issue_pat = #(\d+)
249 issue_pat = #(\d+)
247
250
248 <%text>##</%text> server url to the issue
251 <%text>##</%text> server url to the issue
249 <%text>##</%text> This pattern may/should contain backreferences to parenthesized groups in issue_pat.
252 <%text>##</%text> This pattern may/should contain backreferences to parenthesized groups in issue_pat.
250 <%text>##</%text> A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
253 <%text>##</%text> A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
251 <%text>##</%text> called 'groupname' in issue_pat.
254 <%text>##</%text> called 'groupname' in issue_pat.
252 <%text>##</%text> The special token {repo} is replaced with the full repository name
255 <%text>##</%text> The special token {repo} is replaced with the full repository name
253 <%text>##</%text> including repository groups, while {repo_name} is replaced with just
256 <%text>##</%text> including repository groups, while {repo_name} is replaced with just
254 <%text>##</%text> the name of the repository.
257 <%text>##</%text> the name of the repository.
255
258
256 issue_server_link = https://issues.example.com/{repo}/issue/\1
259 issue_server_link = https://issues.example.com/{repo}/issue/\1
257
260
258 <%text>##</%text> substitution pattern to use as the link text
261 <%text>##</%text> substitution pattern to use as the link text
259 <%text>##</%text> If issue_sub is empty, the text matched by issue_pat is retained verbatim
262 <%text>##</%text> If issue_sub is empty, the text matched by issue_pat is retained verbatim
260 <%text>##</%text> for the link text. Otherwise, the link text is that of issue_sub, with any
263 <%text>##</%text> for the link text. Otherwise, the link text is that of issue_sub, with any
261 <%text>##</%text> backreferences to groups in issue_pat replaced.
264 <%text>##</%text> backreferences to groups in issue_pat replaced.
262
265
263 issue_sub =
266 issue_sub =
264
267
265 <%text>##</%text> issue_pat, issue_server_link and issue_sub can have suffixes to specify
268 <%text>##</%text> issue_pat, issue_server_link and issue_sub can have suffixes to specify
266 <%text>##</%text> multiple patterns, to other issues server, wiki or others
269 <%text>##</%text> multiple patterns, to other issues server, wiki or others
267 <%text>##</%text> below an example how to create a wiki pattern
270 <%text>##</%text> below an example how to create a wiki pattern
268 <%text>##</%text> wiki-some-id -> https://wiki.example.com/some-id
271 <%text>##</%text> wiki-some-id -> https://wiki.example.com/some-id
269
272
270 #issue_pat_wiki = wiki-(\S+)
273 #issue_pat_wiki = wiki-(\S+)
271 #issue_server_link_wiki = https://wiki.example.com/\1
274 #issue_server_link_wiki = https://wiki.example.com/\1
272 #issue_sub_wiki = WIKI-\1
275 #issue_sub_wiki = WIKI-\1
273
276
274 <%text>##</%text> alternative return HTTP header for failed authentication. Default HTTP
277 <%text>##</%text> alternative return HTTP header for failed authentication. Default HTTP
275 <%text>##</%text> response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
278 <%text>##</%text> response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
276 <%text>##</%text> handling that. Set this variable to 403 to return HTTPForbidden
279 <%text>##</%text> handling that. Set this variable to 403 to return HTTPForbidden
277 auth_ret_code =
280 auth_ret_code =
278
281
279 <%text>##</%text> allows to change the repository location in settings page
282 <%text>##</%text> allows to change the repository location in settings page
280 allow_repo_location_change = True
283 allow_repo_location_change = True
281
284
282 <%text>##</%text> allows to setup custom hooks in settings page
285 <%text>##</%text> allows to setup custom hooks in settings page
283 allow_custom_hooks_settings = True
286 allow_custom_hooks_settings = True
284
287
285 <%text>##</%text> extra extensions for indexing, space separated and without the leading '.'.
288 <%text>##</%text> extra extensions for indexing, space separated and without the leading '.'.
286 #index.extensions =
289 #index.extensions =
287 # gemfile
290 # gemfile
288 # lock
291 # lock
289
292
290 <%text>##</%text> extra filenames for indexing, space separated
293 <%text>##</%text> extra filenames for indexing, space separated
291 #index.filenames =
294 #index.filenames =
292 # .dockerignore
295 # .dockerignore
293 # .editorconfig
296 # .editorconfig
294 # INSTALL
297 # INSTALL
295 # CHANGELOG
298 # CHANGELOG
296
299
297 <%text>##</%text>##################################
300 <%text>##</%text>##################################
298 <%text>##</%text> SSH CONFIG ##
301 <%text>##</%text> SSH CONFIG ##
299 <%text>##</%text>##################################
302 <%text>##</%text>##################################
300
303
301 <%text>##</%text> SSH is disabled by default, until an Administrator decides to enable it.
304 <%text>##</%text> SSH is disabled by default, until an Administrator decides to enable it.
302 ssh_enabled = false
305 ssh_enabled = false
303
306
304 <%text>##</%text> File where users' SSH keys will be stored *if* ssh_enabled is true.
307 <%text>##</%text> File where users' SSH keys will be stored *if* ssh_enabled is true.
305 #ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
308 #ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
306 %if user_home_path:
309 %if user_home_path:
307 ssh_authorized_keys = ${user_home_path}/.ssh/authorized_keys
310 ssh_authorized_keys = ${user_home_path}/.ssh/authorized_keys
308 %endif
311 %endif
309
312
310 <%text>##</%text> Path to be used in ssh_authorized_keys file to invoke kallithea-cli with ssh-serve.
313 <%text>##</%text> Path to be used in ssh_authorized_keys file to invoke kallithea-cli with ssh-serve.
311 #kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
314 #kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
312 %if kallithea_cli_path:
315 %if kallithea_cli_path:
313 kallithea_cli_path = ${kallithea_cli_path}
316 kallithea_cli_path = ${kallithea_cli_path}
314 %endif
317 %endif
315
318
316 <%text>##</%text> Locale to be used in the ssh-serve command.
319 <%text>##</%text> Locale to be used in the ssh-serve command.
317 <%text>##</%text> This is needed because an SSH client may try to use its own locale
320 <%text>##</%text> This is needed because an SSH client may try to use its own locale
318 <%text>##</%text> settings, which may not be available on the server.
321 <%text>##</%text> settings, which may not be available on the server.
319 <%text>##</%text> See `locale -a` for valid values on this system.
322 <%text>##</%text> See `locale -a` for valid values on this system.
320 #ssh_locale = C.UTF-8
323 #ssh_locale = C.UTF-8
321 %if ssh_locale:
324 %if ssh_locale:
322 ssh_locale = ${ssh_locale}
325 ssh_locale = ${ssh_locale}
323 %endif
326 %endif
324
327
325 <%text>##</%text>##################################
328 <%text>##</%text>##################################
326 <%text>##</%text> CELERY CONFIG ##
329 <%text>##</%text> CELERY CONFIG ##
327 <%text>##</%text>##################################
330 <%text>##</%text>##################################
328
331
329 <%text>##</%text> Note: Celery doesn't support Windows.
332 <%text>##</%text> Note: Celery doesn't support Windows.
330 use_celery = false
333 use_celery = false
331
334
332 <%text>##</%text> Celery config settings from https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html prefixed with 'celery.'.
335 <%text>##</%text> Celery config settings from https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html prefixed with 'celery.'.
333
336
334 <%text>##</%text> Example: use the message queue on the local virtual host 'kallitheavhost' as the RabbitMQ user 'kallithea':
337 <%text>##</%text> Example: use the message queue on the local virtual host 'kallitheavhost' as the RabbitMQ user 'kallithea':
335 celery.broker_url = amqp://kallithea:thepassword@localhost:5672/kallitheavhost
338 celery.broker_url = amqp://kallithea:thepassword@localhost:5672/kallitheavhost
336
339
337 celery.worker_concurrency = 2
340 celery.worker_concurrency = 2
338 celery.worker_max_tasks_per_child = 100
341 celery.worker_max_tasks_per_child = 100
339
342
340 <%text>##</%text>##################################
343 <%text>##</%text>##################################
341 <%text>##</%text> BEAKER CACHE ##
344 <%text>##</%text> BEAKER CACHE ##
342 <%text>##</%text>##################################
345 <%text>##</%text>##################################
343
346
344 beaker.cache.data_dir = %(here)s/data/cache/data
347 beaker.cache.data_dir = %(here)s/data/cache/data
345 beaker.cache.lock_dir = %(here)s/data/cache/lock
348 beaker.cache.lock_dir = %(here)s/data/cache/lock
346
349
347 beaker.cache.regions = long_term,long_term_file
350 beaker.cache.regions = long_term,long_term_file
348
351
349 beaker.cache.long_term.type = memory
352 beaker.cache.long_term.type = memory
350 beaker.cache.long_term.expire = 36000
353 beaker.cache.long_term.expire = 36000
351 beaker.cache.long_term.key_length = 256
354 beaker.cache.long_term.key_length = 256
352
355
353 beaker.cache.long_term_file.type = file
356 beaker.cache.long_term_file.type = file
354 beaker.cache.long_term_file.expire = 604800
357 beaker.cache.long_term_file.expire = 604800
355 beaker.cache.long_term_file.key_length = 256
358 beaker.cache.long_term_file.key_length = 256
356
359
357 <%text>##</%text>##################################
360 <%text>##</%text>##################################
358 <%text>##</%text> BEAKER SESSION ##
361 <%text>##</%text> BEAKER SESSION ##
359 <%text>##</%text>##################################
362 <%text>##</%text>##################################
360
363
361 <%text>##</%text> Name of session cookie. Should be unique for a given host and path, even when running
364 <%text>##</%text> Name of session cookie. Should be unique for a given host and path, even when running
362 <%text>##</%text> on different ports. Otherwise, cookie sessions will be shared and messed up.
365 <%text>##</%text> on different ports. Otherwise, cookie sessions will be shared and messed up.
363 session.key = kallithea
366 session.key = kallithea
364 <%text>##</%text> Sessions should always only be accessible by the browser, not directly by JavaScript.
367 <%text>##</%text> Sessions should always only be accessible by the browser, not directly by JavaScript.
365 session.httponly = true
368 session.httponly = true
366 <%text>##</%text> Session lifetime. 2592000 seconds is 30 days.
369 <%text>##</%text> Session lifetime. 2592000 seconds is 30 days.
367 session.timeout = 2592000
370 session.timeout = 2592000
368
371
369 <%text>##</%text> Server secret used with HMAC to ensure integrity of cookies.
372 <%text>##</%text> Server secret used with HMAC to ensure integrity of cookies.
370 session.secret = ${uuid()}
373 session.secret = ${uuid()}
371 <%text>##</%text> Further, encrypt the data with AES.
374 <%text>##</%text> Further, encrypt the data with AES.
372 #session.encrypt_key = <key_for_encryption>
375 #session.encrypt_key = <key_for_encryption>
373 #session.validate_key = <validation_key>
376 #session.validate_key = <validation_key>
374
377
375 <%text>##</%text> Type of storage used for the session, current types are
378 <%text>##</%text> Type of storage used for the session, current types are
376 <%text>##</%text> dbm, file, memcached, database, and memory.
379 <%text>##</%text> dbm, file, memcached, database, and memory.
377
380
378 <%text>##</%text> File system storage of session data. (default)
381 <%text>##</%text> File system storage of session data. (default)
379 #session.type = file
382 #session.type = file
380
383
381 <%text>##</%text> Cookie only, store all session data inside the cookie. Requires secure secrets.
384 <%text>##</%text> Cookie only, store all session data inside the cookie. Requires secure secrets.
382 #session.type = cookie
385 #session.type = cookie
383
386
384 <%text>##</%text> Database storage of session data.
387 <%text>##</%text> Database storage of session data.
385 #session.type = ext:database
388 #session.type = ext:database
386 #session.sa.url = postgresql://postgres:qwe@localhost/kallithea
389 #session.sa.url = postgresql://postgres:qwe@localhost/kallithea
387 #session.table_name = db_session
390 #session.table_name = db_session
388
391
389 <%text>##</%text>##################################
392 <%text>##</%text>##################################
390 <%text>##</%text> ERROR HANDLING ##
393 <%text>##</%text> ERROR HANDLING ##
391 <%text>##</%text>##################################
394 <%text>##</%text>##################################
392
395
393 <%text>##</%text> Show a nice error page for application HTTP errors and exceptions (default true)
396 <%text>##</%text> Show a nice error page for application HTTP errors and exceptions (default true)
394 #errorpage.enabled = true
397 #errorpage.enabled = true
395
398
396 <%text>##</%text> Enable Backlash client-side interactive debugger (default false)
399 <%text>##</%text> Enable Backlash client-side interactive debugger (default false)
397 <%text>##</%text> WARNING: *THIS MUST BE false IN PRODUCTION ENVIRONMENTS!!!*
400 <%text>##</%text> WARNING: *THIS MUST BE false IN PRODUCTION ENVIRONMENTS!!!*
398 <%text>##</%text> This debug mode will allow all visitors to execute malicious code.
401 <%text>##</%text> This debug mode will allow all visitors to execute malicious code.
399 #debug = false
402 #debug = false
400
403
401 <%text>##</%text> Enable Backlash server-side error reporting (unless debug mode handles it client-side) (default true)
404 <%text>##</%text> Enable Backlash server-side error reporting (unless debug mode handles it client-side) (default true)
402 #trace_errors.enable = true
405 #trace_errors.enable = true
403 <%text>##</%text> Errors will be reported by mail if trace_errors.error_email is set.
406 <%text>##</%text> Errors will be reported by mail if trace_errors.error_email is set.
404
407
405 <%text>##</%text> Propagate email settings to ErrorReporter of TurboGears2
408 <%text>##</%text> Propagate email settings to ErrorReporter of TurboGears2
406 <%text>##</%text> You do not normally need to change these lines
409 <%text>##</%text> You do not normally need to change these lines
407 get trace_errors.smtp_server = smtp_server
410 get trace_errors.smtp_server = smtp_server
408 get trace_errors.smtp_port = smtp_port
411 get trace_errors.smtp_port = smtp_port
409 get trace_errors.from_address = error_email_from
412 get trace_errors.from_address = error_email_from
410 get trace_errors.error_email = email_to
413 get trace_errors.error_email = email_to
411 get trace_errors.smtp_username = smtp_username
414 get trace_errors.smtp_username = smtp_username
412 get trace_errors.smtp_password = smtp_password
415 get trace_errors.smtp_password = smtp_password
413 get trace_errors.smtp_use_tls = smtp_use_tls
416 get trace_errors.smtp_use_tls = smtp_use_tls
414
417
415 <%text>##</%text>################################
418 <%text>##</%text>################################
416 <%text>##</%text> LOGVIEW CONFIG ##
419 <%text>##</%text> LOGVIEW CONFIG ##
417 <%text>##</%text>################################
420 <%text>##</%text>################################
418
421
419 logview.sqlalchemy = #faa
422 logview.sqlalchemy = #faa
420 logview.pylons.templating = #bfb
423 logview.pylons.templating = #bfb
421 logview.pylons.util = #eee
424 logview.pylons.util = #eee
422
425
423 <%text>##</%text>#######################
426 <%text>##</%text>#######################
424 <%text>##</%text> DB CONFIG ##
427 <%text>##</%text> DB CONFIG ##
425 <%text>##</%text>#######################
428 <%text>##</%text>#######################
426
429
427 %if database_engine == 'sqlite':
430 %if database_engine == 'sqlite':
428 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
431 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
429 %else:
432 %else:
430 #sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
433 #sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
431 %endif
434 %endif
432 %if database_engine == 'postgres':
435 %if database_engine == 'postgres':
433 sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
436 sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
434 %else:
437 %else:
435 #sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
438 #sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
436 %endif
439 %endif
437 %if database_engine == 'mysql':
440 %if database_engine == 'mysql':
438 sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
441 sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
439 %else:
442 %else:
440 #sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
443 #sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
441 %endif
444 %endif
442 <%text>##</%text> Note: the mysql:// prefix should also be used for MariaDB
445 <%text>##</%text> Note: the mysql:// prefix should also be used for MariaDB
443
446
444 sqlalchemy.pool_recycle = 3600
447 sqlalchemy.pool_recycle = 3600
445
448
446 <%text>##</%text>##############################
449 <%text>##</%text>##############################
447 <%text>##</%text> ALEMBIC CONFIGURATION ##
450 <%text>##</%text> ALEMBIC CONFIGURATION ##
448 <%text>##</%text>##############################
451 <%text>##</%text>##############################
449
452
450 [alembic]
453 [alembic]
451 script_location = kallithea:alembic
454 script_location = kallithea:alembic
452
455
453 <%text>##</%text>##############################
456 <%text>##</%text>##############################
454 <%text>##</%text> LOGGING CONFIGURATION ##
457 <%text>##</%text> LOGGING CONFIGURATION ##
455 <%text>##</%text>##############################
458 <%text>##</%text>##############################
456
459
457 [loggers]
460 [loggers]
458 keys = root, routes, kallithea, sqlalchemy, tg, gearbox, beaker, templates, whoosh_indexer, werkzeug, backlash
461 keys = root, routes, kallithea, sqlalchemy, tg, gearbox, beaker, templates, whoosh_indexer, werkzeug, backlash
459
462
460 [handlers]
463 [handlers]
461 keys = console, console_color, console_color_sql, null
464 keys = console, console_color, console_color_sql, null
462
465
463 [formatters]
466 [formatters]
464 keys = generic, color_formatter, color_formatter_sql
467 keys = generic, color_formatter, color_formatter_sql
465
468
466 <%text>##</%text>###########
469 <%text>##</%text>###########
467 <%text>##</%text> LOGGERS ##
470 <%text>##</%text> LOGGERS ##
468 <%text>##</%text>###########
471 <%text>##</%text>###########
469
472
470 [logger_root]
473 [logger_root]
471 level = NOTSET
474 level = NOTSET
472 handlers = console
475 handlers = console
473 <%text>##</%text> For coloring based on log level:
476 <%text>##</%text> For coloring based on log level:
474 #handlers = console_color
477 #handlers = console_color
475
478
476 [logger_routes]
479 [logger_routes]
477 level = WARN
480 level = WARN
478 handlers =
481 handlers =
479 qualname = routes.middleware
482 qualname = routes.middleware
480 <%text>##</%text> "level = DEBUG" logs the route matched and routing variables.
483 <%text>##</%text> "level = DEBUG" logs the route matched and routing variables.
481
484
482 [logger_beaker]
485 [logger_beaker]
483 level = WARN
486 level = WARN
484 handlers =
487 handlers =
485 qualname = beaker.container
488 qualname = beaker.container
486
489
487 [logger_templates]
490 [logger_templates]
488 level = WARN
491 level = WARN
489 handlers =
492 handlers =
490 qualname = pylons.templating
493 qualname = pylons.templating
491
494
492 [logger_kallithea]
495 [logger_kallithea]
493 level = WARN
496 level = WARN
494 handlers =
497 handlers =
495 qualname = kallithea
498 qualname = kallithea
496
499
497 [logger_tg]
500 [logger_tg]
498 level = WARN
501 level = WARN
499 handlers =
502 handlers =
500 qualname = tg
503 qualname = tg
501
504
502 [logger_gearbox]
505 [logger_gearbox]
503 level = WARN
506 level = WARN
504 handlers =
507 handlers =
505 qualname = gearbox
508 qualname = gearbox
506
509
507 [logger_sqlalchemy]
510 [logger_sqlalchemy]
508 level = WARN
511 level = WARN
509 handlers =
512 handlers =
510 qualname = sqlalchemy.engine
513 qualname = sqlalchemy.engine
511 <%text>##</%text> For coloring based on log level and pretty printing of SQL:
514 <%text>##</%text> For coloring based on log level and pretty printing of SQL:
512 #level = INFO
515 #level = INFO
513 #handlers = console_color_sql
516 #handlers = console_color_sql
514 #propagate = 0
517 #propagate = 0
515
518
516 [logger_whoosh_indexer]
519 [logger_whoosh_indexer]
517 level = WARN
520 level = WARN
518 handlers =
521 handlers =
519 qualname = whoosh_indexer
522 qualname = whoosh_indexer
520
523
521 [logger_werkzeug]
524 [logger_werkzeug]
522 level = WARN
525 level = WARN
523 handlers =
526 handlers =
524 qualname = werkzeug
527 qualname = werkzeug
525
528
526 [logger_backlash]
529 [logger_backlash]
527 level = WARN
530 level = WARN
528 handlers =
531 handlers =
529 qualname = backlash
532 qualname = backlash
530
533
531 <%text>##</%text>############
534 <%text>##</%text>############
532 <%text>##</%text> HANDLERS ##
535 <%text>##</%text> HANDLERS ##
533 <%text>##</%text>############
536 <%text>##</%text>############
534
537
535 [handler_console]
538 [handler_console]
536 class = StreamHandler
539 class = StreamHandler
537 args = (sys.stderr,)
540 args = (sys.stderr,)
538 formatter = generic
541 formatter = generic
539
542
540 [handler_console_color]
543 [handler_console_color]
541 <%text>##</%text> ANSI color coding based on log level
544 <%text>##</%text> ANSI color coding based on log level
542 class = StreamHandler
545 class = StreamHandler
543 args = (sys.stderr,)
546 args = (sys.stderr,)
544 formatter = color_formatter
547 formatter = color_formatter
545
548
546 [handler_console_color_sql]
549 [handler_console_color_sql]
547 <%text>##</%text> ANSI color coding and pretty printing of SQL statements
550 <%text>##</%text> ANSI color coding and pretty printing of SQL statements
548 class = StreamHandler
551 class = StreamHandler
549 args = (sys.stderr,)
552 args = (sys.stderr,)
550 formatter = color_formatter_sql
553 formatter = color_formatter_sql
551
554
552 [handler_null]
555 [handler_null]
553 class = NullHandler
556 class = NullHandler
554 args = ()
557 args = ()
555
558
556 <%text>##</%text>##############
559 <%text>##</%text>##############
557 <%text>##</%text> FORMATTERS ##
560 <%text>##</%text> FORMATTERS ##
558 <%text>##</%text>##############
561 <%text>##</%text>##############
559
562
560 [formatter_generic]
563 [formatter_generic]
561 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
564 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
562 datefmt = %Y-%m-%d %H:%M:%S
565 datefmt = %Y-%m-%d %H:%M:%S
563
566
564 [formatter_color_formatter]
567 [formatter_color_formatter]
565 class = kallithea.lib.colored_formatter.ColorFormatter
568 class = kallithea.lib.colored_formatter.ColorFormatter
566 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
569 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
567 datefmt = %Y-%m-%d %H:%M:%S
570 datefmt = %Y-%m-%d %H:%M:%S
568
571
569 [formatter_color_formatter_sql]
572 [formatter_color_formatter_sql]
570 class = kallithea.lib.colored_formatter.ColorFormatterSql
573 class = kallithea.lib.colored_formatter.ColorFormatterSql
571 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
574 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
572 datefmt = %Y-%m-%d %H:%M:%S
575 datefmt = %Y-%m-%d %H:%M:%S
573
576
574 <%text>##</%text>###############
577 <%text>##</%text>###############
575 <%text>##</%text> SSH LOGGING ##
578 <%text>##</%text> SSH LOGGING ##
576 <%text>##</%text>###############
579 <%text>##</%text>###############
577
580
578 <%text>##</%text> The default loggers use 'handler_console' that uses StreamHandler with
581 <%text>##</%text> The default loggers use 'handler_console' that uses StreamHandler with
579 <%text>##</%text> destination 'sys.stderr'. In the context of the SSH server process, these log
582 <%text>##</%text> destination 'sys.stderr'. In the context of the SSH server process, these log
580 <%text>##</%text> messages would be sent to the client, which is normally not what you want.
583 <%text>##</%text> messages would be sent to the client, which is normally not what you want.
581 <%text>##</%text> By default, when running ssh-serve, just use NullHandler and disable logging
584 <%text>##</%text> By default, when running ssh-serve, just use NullHandler and disable logging
582 <%text>##</%text> completely. For other logging options, see:
585 <%text>##</%text> completely. For other logging options, see:
583 <%text>##</%text> https://docs.python.org/2/library/logging.handlers.html
586 <%text>##</%text> https://docs.python.org/2/library/logging.handlers.html
584
587
585 [ssh_serve:logger_root]
588 [ssh_serve:logger_root]
586 level = CRITICAL
589 level = CRITICAL
587 handlers = null
590 handlers = null
588
591
589 <%text>##</%text> Note: If logging is configured with other handlers, they might need similar
592 <%text>##</%text> Note: If logging is configured with other handlers, they might need similar
590 <%text>##</%text> muting for ssh-serve too.
593 <%text>##</%text> muting for ssh-serve too.
General Comments 0
You need to be logged in to leave comments. Login now