]>
git.ipfire.org Git - ipfire.org.git/blob - src/web/base.py
437050acb9126c70376cbb24b0fa7efb4c1c5395
13 from ..decorators
import *
16 def blacklisted(method
):
17 @tornado.gen
.coroutine
18 @functools.wraps(method
)
19 def wrapper(self
, *args
, **kwargs
):
20 # Check if remote is blacklisted
21 is_blacklisted
= yield self
.remote
.is_blacklisted()
23 # If so, redirect to the blocked page
25 logging
.warning("%s is blacklisted" % self
.remote
)
27 return self
.redirect("https://www.ipfire.org/blocked")
29 return method(self
, *args
, **kwargs
)
33 class ratelimit(object):
34 def __init__(self
, minutes
=15, requests
=180):
35 self
.minutes
= minutes
36 self
.requests
= requests
38 def __call__(self
, method
):
39 @functools.wraps(method
)
40 def wrapper(handler
, *args
, **kwargs
):
41 # Pass the request to the rate limiter and get a request object
42 req
= handler
.backend
.ratelimiter
.handle_request(handler
.request
,
43 handler
, minutes
=self
.minutes
, limit
=self
.requests
)
45 # If the rate limit has been reached, we won't allow
46 # processing the request and therefore send HTTP error code 429.
47 if req
.is_ratelimited():
48 raise tornado
.web
.HTTPError(429, "Rate limit exceeded")
50 return method(handler
, *args
, **kwargs
)
55 class BaseHandler(tornado
.web
.RequestHandler
):
56 def set_expires(self
, seconds
):
58 self
.add_header("Cache-Control", "max-age=%s, must-revalidate" % seconds
)
61 expires
= datetime
.datetime
.utcnow() + datetime
.timedelta(seconds
=seconds
)
62 self
.add_header("Expires", expires
)
64 def write_error(self
, status_code
, **kwargs
):
65 # Translate code into message
67 message
= http
.client
.responses
[status_code
]
71 self
.render("error.html", status_code
=status_code
, message
=message
, **kwargs
)
73 def xsrf_form_html(self
, *args
, **kwargs
):
74 # Set Vary: Cookie header
75 self
.add_header("Vary", "Cookie")
77 return super().xsrf_form_html(*args
, **kwargs
)
81 # Remove the development prefix
82 return self
.request
.host
.replace(".dev.", ".")
84 def get_template_namespace(self
):
85 ns
= tornado
.web
.RequestHandler
.get_template_namespace(self
)
87 now
= datetime
.date
.today()
90 "backend" : self
.backend
,
91 "debug" : self
.application
.settings
.get("debug", False),
92 "format_size" : util
.format_size
,
93 "format_time" : util
.format_time
,
94 "hostname" : self
.hostname
,
101 def get_remote_ip(self
):
102 # Fix for clients behind a proxy that sends "X-Forwarded-For".
103 remote_ips
= self
.request
.remote_ip
.split(", ")
105 for remote_ip
in remote_ips
:
107 addr
= ipaddress
.ip_address(remote_ip
)
109 # Skip invalid IP addresses.
112 # Check if the given IP address is from a
119 # Return the last IP if nothing else worked
120 return remote_ips
.pop()
124 address
= self
.get_remote_ip()
127 return self
.backend
.geoip
.lookup(address
)
130 def current_country_code(self
):
131 remote_ip
= self
.get_remote_ip()
134 return self
.backend
.geoip
.get_country(remote_ip
)
136 def get_remote_location(self
):
137 if not hasattr(self
, "__remote_location"):
138 remote_ip
= self
.get_remote_ip()
140 self
.__remote
_location
= self
.geoip
.get_location(remote_ip
)
142 return self
.__remote
_location
144 def get_argument_int(self
, *args
, **kwargs
):
145 arg
= self
.get_argument(*args
, **kwargs
)
147 if arg
is None or arg
== "":
153 raise tornado
.web
.HTTPError(400, "Could not convert integer: %s" % arg
)
155 def get_argument_float(self
, *args
, **kwargs
):
156 arg
= self
.get_argument(*args
, **kwargs
)
158 if arg
is None or arg
== "":
164 raise tornado
.web
.HTTPError(400, "Could not convert float: %s" % arg
)
166 def get_argument_date(self
, arg
, *args
, **kwargs
):
167 value
= self
.get_argument(arg
, *args
, **kwargs
)
172 return dateutil
.parser
.parse(value
)
174 raise tornado
.web
.HTTPError(400)
176 def get_file(self
, name
):
178 file = self
.request
.files
[name
][0]
180 return file["filename"], file["body"], file["content_type"]
186 def get_current_user(self
):
187 session_id
= self
.get_cookie("session_id")
191 # Get account from the session object
192 account
= self
.backend
.accounts
.get_by_session(session_id
, self
.request
.host
)
194 # If the account was not found or the session was not valid
195 # any more, we will remove the cookie.
197 self
.clear_cookie("session_id")
203 return self
.application
.backend
207 return self
.backend
.db
211 return self
.backend
.accounts
215 return self
.backend
.downloads
219 return self
.backend
.fireinfo
223 return self
.backend
.iuse
227 return self
.backend
.memcache
231 return self
.backend
.mirrors
235 return self
.backend
.netboot
239 return self
.backend
.releases
243 return self
.backend
.geoip
247 return self
.backend
.talk
250 class APIHandler(BaseHandler
):
251 def check_xsrf_cookie(self
):
253 Do nothing here, because we cannot verify the XSRF token
258 class NotFoundHandler(BaseHandler
):
260 # Raises 404 as soon as it is called
261 raise tornado
.web
.HTTPError(404)
264 class ErrorHandler(BaseHandler
):
266 Raises any error we want
272 raise tornado
.web
.HTTPError(400)
274 raise tornado
.web
.HTTPError(code
)
277 class BlockedHandler(BaseHandler
):
282 self
.render("static/blocked.html", address
=self
.get_remote_ip())