]>
git.ipfire.org Git - ipfire.org.git/blob - src/web/base.py
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 NotFoundHandler(BaseHandler
):
252 # Raises 404 as soon as it is called
253 raise tornado
.web
.HTTPError(404)
256 class ErrorHandler(BaseHandler
):
258 Raises any error we want
264 raise tornado
.web
.HTTPError(400)
266 raise tornado
.web
.HTTPError(code
)
269 class BlockedHandler(BaseHandler
):
274 self
.render("static/blocked.html", address
=self
.get_remote_ip())