def auth(commands, user_session): if user_session: if user_session.is_expired(): mailpile.auth.SESSION_CACHE.delete_expired() user_session = None else: user_session.update_ts() if user_session and method == 'POST': if isinstance(post_data, cgi.FieldStorage): try: csrf = post_data['csrf'].value except KeyError: csrf = '' else: csrf = post_data.get('csrf', [''])[0] if not security.valid_csrf_token(request, sid, csrf): user_session = None if not user_session or not user_session.auth: for c in commands: if (c.HTTP_AUTH_REQUIRED is True or (c.HTTP_AUTH_REQUIRED == 'Maybe' and self.session.config.prefs.gpg_recipient)): if is_async or is_api: raise AccessError() self.redirect_to_auth_or_setup(method, path, query_data) return commands
def auth(commands, user_session): if user_session: if user_session.is_expired(): mailpile.auth.SESSION_CACHE.delete_expired() user_session = None else: user_session.update_ts() if user_session and method == 'POST': if isinstance(post_data, cgi.FieldStorage): try: csrf = post_data['csrf'].value except KeyError: csrf = '' else: csrf = post_data.get('csrf', [''])[0] if not security.valid_csrf_token( request.server.secret, sid, csrf): user_session = None if not user_session or not user_session.auth: for c in commands: if (c.HTTP_AUTH_REQUIRED is True or (c.HTTP_AUTH_REQUIRED == 'Maybe' and self.session.config.prefs.gpg_recipient)): if is_async or is_api: raise AccessError() self.redirect_to_auth_or_setup( method, path, query_data) return commands
def command(self): html_variables = self.session.ui.html_variables request = html_variables['http_request'] if not (html_variables and security.valid_csrf_token(request, html_variables['http_session'], self.data.get('csrf', [''])[0])): raise AccessError('Invalid CSRF token') url = self.data['url'][0] timeout = float(self.data.get('timeout', ['10'])[0]) conn_reject = [] # FIXME: reject ConnBroker.OUTGOING_TRACKABLE ? if url[:6].lower() == 'https:': conn_need = [ConnBroker.OUTGOING_HTTP] elif url[:5].lower() == 'http:': conn_need = [ConnBroker.OUTGOING_HTTPS] else: raise AccessError('Invalid URL scheme') try: with ConnBroker.context(need=conn_need, reject=conn_reject) as ctx: self.session.ui.mark('Getting: %s' % url) response = urlopen(url, data=None, timeout=timeout) except HTTPError, e: response = e
def command(self): html_variables = self.session.ui.html_variables request = html_variables["http_request"] if not ( html_variables and security.valid_csrf_token(request, html_variables["http_session"], self.data.get("csrf", [""])[0]) ): raise AccessError("Invalid CSRF token") url = self.data["url"][0] timeout = float(self.data.get("timeout", ["10"])[0]) conn_reject = [] # FIXME: reject ConnBroker.OUTGOING_TRACKABLE ? if url[:6].lower() == "https:": conn_need = [ConnBroker.OUTGOING_HTTP] elif url[:5].lower() == "http:": conn_need = [ConnBroker.OUTGOING_HTTPS] else: raise AccessError("Invalid URL scheme") try: with ConnBroker.context(need=conn_need, reject=conn_reject) as ctx: self.session.ui.mark("Getting: %s" % url) response = urlopen(url, data=None, timeout=timeout) except HTTPError, e: response = e
def _real_do_GET(self, post_data={}, suppress_body=False, method='GET'): (scheme, netloc, path, params, query, frag) = urlparse(self.path) query_data = parse_qs(query) opath = path = unquote(path) # HTTP is stateless, so we create a new session for each request. self.session, config = self.server.session, self.server.session.config server_session = self.server.session # Debugging... if 'httpdata' in config.sys.debug: self.wfile = DebugFileWrapper(sys.stderr, self.wfile) # Path manipulation... if path == '/favicon.ico': path = '%s/static/favicon.ico' % (config.sys.http_path or '') if config.sys.http_path: if not path.startswith(config.sys.http_path): self.send_full_response(_("File not found (invalid path)"), code=404, mimetype='text/plain') return None path = path[len(config.sys.http_path):] if path.startswith('/_/'): path = path[2:] for static in ('/static/', '/bower_components/'): if path.startswith(static): return self.send_file(config, path[len(static):], suppress_body=suppress_body) self.session = session = Session(config) session.ui = HttpUserInteraction(self, config, log_parent=server_session.ui) if 'context' in post_data: session.load_context(post_data['context'][0]) elif 'context' in query_data: session.load_context(query_data['context'][0]) mark_name = 'Processing HTTP API request at %s' % time.time() session.ui.start_command(mark_name, [], {}) if 'http' in config.sys.debug: session.ui.warning = server_session.ui.warning session.ui.notify = server_session.ui.notify session.ui.error = server_session.ui.error session.ui.debug = server_session.ui.debug session.ui.debug('%s: %s qs = %s post = %s' % (method, opath, query_data, post_data)) idx = session.config.index if session.config.loaded_config: name = session.config.get_profile().get('name', 'Chelsea Manning') else: name = 'Chelsea Manning' http_headers = [] http_session = self.http_session() csrf_token = security.make_csrf_token(self.server.secret, http_session) session.ui.html_variables = { 'csrf_token': csrf_token, 'csrf_field': ('<input type="hidden" name="csrf" value="%s">' % csrf_token), 'http_host': self.headers.get('host', 'localhost'), 'http_hostname': self.http_host(), 'http_method': method, 'http_session': http_session, 'http_request': self, 'http_response_headers': http_headers, 'message_count': (idx and len(idx.INDEX) or 0), 'name': name, 'title': 'Mailpile dummy title', 'url_protocol': self.headers.get('x-forwarded-proto', 'http'), 'mailpile_size': idx and len(idx.INDEX) or 0 } session.ui.valid_csrf_token = lambda token: security.valid_csrf_token( self.server.secret, http_session, token) try: try: need_auth = not (mailpile.util.TESTING or session.config.sys.http_no_auth) commands = UrlMap(session).map(self, method, path, query_data, post_data, authenticate=need_auth) except UsageError: if (not path.endswith('/') and not session.config.sys.debug and method == 'GET'): commands = UrlMap(session).map(self, method, path + '/', query_data, post_data) url = quote(path) + '/' if query: url += '?' + query return self.send_http_redirect(url) else: raise cachectrl = None if 'http' not in config.sys.debug: etag_data = [] max_ages = [] have_ed = 0 for c in commands: max_ages.append(c.max_age()) ed = c.etag_data() have_ed += 1 if ed else 0 etag_data.extend(ed) if have_ed == len(commands): etag = self._mk_etag(*etag_data) conditional = self.headers.get('if-none-match') if conditional == etag: self.send_full_response('OK', code=304, msg='Unmodified') return None else: http_headers.append(('ETag', etag)) max_age = min(max_ages) if max_ages else 10 if max_age: cachectrl = 'must-revalidate, max-age=%d' % max_age else: cachectrl = 'must-revalidate, no-store, max-age=0' global LIVE_HTTP_REQUESTS hang_fix = 1 if ([1 for c in commands if c.IS_HANGING_ACTIVITY]) else 0 try: LIVE_HTTP_REQUESTS -= hang_fix session.ui.mark('Running %d commands' % len(commands)) results = [cmd.run() for cmd in commands] session.ui.mark('Displaying final result') session.ui.display_result(results[-1]) finally: LIVE_HTTP_REQUESTS += hang_fix session.ui.mark('Rendering response') mimetype, content = session.ui.render_response(session.config) session.ui.mark('Sending response') self.send_full_response(content, mimetype=mimetype, header_list=http_headers, cachectrl=cachectrl) except UrlRedirectException as e: return self.send_http_redirect(e.url) except SuppressHtmlOutput: return None except AccessError: self.send_full_response(_('Access Denied'), code=403, mimetype='text/plain') return None except: e = traceback.format_exc() session.ui.debug(e) if not session.config.sys.debug: e = _('Internal Error') self.send_full_response(e, code=500, mimetype='text/plain') return None finally: session.ui.report_marks( details=('timing' in session.config.sys.debug)) session.ui.finish_command(mark_name)