def getLocaleFromRequest(request): # See if we did get a request for a certain locale, otherwise fall back # to 'en': # Try evaluating the path /foo first, then check if we got a ?lang=foo default_lang = lang = "en" if len(request.path) > 1: lang = request.path[1:] if lang == default_lang: lang = request.args.get("lang", [default_lang]) lang = lang[0] return I18n.getLang(lang)
def render_GET(self, request): interval = self.schedule.getInterval(time.time()) bridges = ( ) ip = None if self.useForwardedHeader: h = request.getHeader("X-Forwarded-For") if h: ip = h.split(",")[-1].strip() if not bridgedb.Bridges.is_valid_ip(ip): logging.warn("Got weird forwarded-for value %r",h) ip = None else: ip = request.getClientIP() # See if we did get a request for a certain locale, otherwise fall back # to 'en': # Try evaluating the path /foo first, then check if we got a ?lang=foo default_lang = lang = "en" if len(request.path) > 1: lang = request.path[1:] if lang == default_lang: lang = request.args.get("lang", [default_lang]) lang = lang[0] t = I18n.getLang(lang) format = request.args.get("format", None) if format and len(format): format = format[0] # choose the first arg if ip: bridges = self.distributor.getBridgesForIP(ip, interval, self.nBridgesToGive) if bridges: answer = "".join("%s\n" % b.getConfigLine(self.includeFingerprints) for b in bridges) else: answer = t.gettext(I18n.BRIDGEDB_TEXT[-1]) logging.info("Replying to web request from %s. Parameters were %r", ip, request.args) if format == 'plain': request.setHeader("Content-Type", "text/plain") return answer else: HTML_MESSAGE_TEMPLATE = self.buildHTMLMessageTemplate(t) return HTML_MESSAGE_TEMPLATE % answer
def getMailResponse(lines, ctx): """Given a list of lines from an incoming email message, and a MailContext object, parse the email and decide what to do in response. If we want to answer, return a 2-tuple containing the address that will receive the response, and a readable filelike object containing the response. Return None,None if we shouldn't answer. """ # Extract data from the headers. msg = rfc822.Message(MailFile(lines)) subject = msg.getheader("Subject", None) if not subject: subject = "[no subject]" clientFromAddr = msg.getaddr("From") clientSenderAddr = msg.getaddr("Sender") # RFC822 requires at least one 'To' address clientToList = msg.getaddrlist("To") clientToaddr = getBridgeDBEmailAddrFromList(ctx, clientToList) msgID = msg.getheader("Message-ID", None) if clientSenderAddr and clientSenderAddr[1]: clientAddr = clientSenderAddr[1] elif clientFromAddr and clientFromAddr[1]: clientAddr = clientFromAddr[1] else: logging.info("No From or Sender header on incoming mail.") return None, None # Look up the locale part in the 'To:' address, if there is one and get # the appropriate Translation object lang = getLocaleFromPlusAddr(clientToaddr) t = I18n.getLang(lang) try: _, addrdomain = bridgedb.Dist.extractAddrSpec(clientAddr.lower()) except bridgedb.Dist.BadEmail: logging.info("Ignoring bad address on incoming email.") return None, None if not addrdomain: logging.info("Couldn't parse domain from %r", clientAddr) if addrdomain and ctx.cfg.EMAIL_DOMAIN_MAP: addrdomain = ctx.cfg.EMAIL_DOMAIN_MAP.get(addrdomain, addrdomain) if addrdomain not in ctx.cfg.EMAIL_DOMAINS: logging.info("Unrecognized email domain %r", addrdomain) return None, None rules = ctx.cfg.EMAIL_DOMAIN_RULES.get(addrdomain, []) if 'dkim' in rules: # getheader() returns the last of a given kind of header; we want # to get the first, so we use getheaders() instead. dkimHeaders = msg.getheaders("X-DKIM-Authentication-Results") dkimHeader = "<no header>" if dkimHeaders: dkimHeader = dkimHeaders[0] if not dkimHeader.startswith("pass"): logging.info( "Got a bad dkim header (%r) on an incoming mail; " "rejecting it.", dkimHeader) return None, None # Was the magic string included #for ln in lines: # if ln.strip().lower() in ("get bridges", "subject: get bridges"): # break #else: # logging.info("Got a mail from %r with no bridge request; dropping", # clientAddr) # return None,None # Figure out which bridges to send try: interval = ctx.schedule.getInterval(time.time()) bridges = ctx.distributor.getBridgesForEmail(clientAddr, interval, ctx.N, countryCode=None) except bridgedb.Dist.BadEmail, e: logging.info("Got a mail from a bad email address %r: %s.", clientAddr, e) return None, None
def getMailResponse(lines, ctx): """Given a list of lines from an incoming email message, and a MailContext object, parse the email and decide what to do in response. If we want to answer, return a 2-tuple containing the address that will receive the response, and a readable filelike object containing the response. Return None,None if we shouldn't answer. """ # Extract data from the headers. msg = rfc822.Message(MailFile(lines)) subject = msg.getheader("Subject", None) if not subject: subject = "[no subject]" clientFromAddr = msg.getaddr("From") clientSenderAddr = msg.getaddr("Sender") # RFC822 requires at least one 'To' address clientToList = msg.getaddrlist("To") clientToaddr = getBridgeDBEmailAddrFromList(ctx, clientToList) msgID = msg.getheader("Message-ID", None) if clientSenderAddr and clientSenderAddr[1]: clientAddr = clientSenderAddr[1] elif clientFromAddr and clientFromAddr[1]: clientAddr = clientFromAddr[1] else: logging.info("No From or Sender header on incoming mail.") return None, None # Look up the locale part in the 'To:' address, if there is one and get # the appropriate Translation object lang = getLocaleFromPlusAddr(clientToaddr) t = I18n.getLang(lang) try: _, addrdomain = bridgedb.Dist.extractAddrSpec(clientAddr.lower()) except bridgedb.Dist.BadEmail: logging.info("Ignoring bad address on incoming email.") return None, None if not addrdomain: logging.info("Couldn't parse domain from %r", clientAddr) if addrdomain and ctx.cfg.EMAIL_DOMAIN_MAP: addrdomain = ctx.cfg.EMAIL_DOMAIN_MAP.get(addrdomain, addrdomain) if addrdomain not in ctx.cfg.EMAIL_DOMAINS: logging.info("Unrecognized email domain %r", addrdomain) return None, None rules = ctx.cfg.EMAIL_DOMAIN_RULES.get(addrdomain, []) if "dkim" in rules: # getheader() returns the last of a given kind of header; we want # to get the first, so we use getheaders() instead. dkimHeaders = msg.getheaders("X-DKIM-Authentication-Results") dkimHeader = "<no header>" if dkimHeaders: dkimHeader = dkimHeaders[0] if not dkimHeader.startswith("pass"): logging.info("Got a bad dkim header (%r) on an incoming mail; " "rejecting it.", dkimHeader) return None, None # Was the magic string included # for ln in lines: # if ln.strip().lower() in ("get bridges", "subject: get bridges"): # break # else: # logging.info("Got a mail from %r with no bridge request; dropping", # clientAddr) # return None,None # Figure out which bridges to send try: interval = ctx.schedule.getInterval(time.time()) bridges = ctx.distributor.getBridgesForEmail(clientAddr, interval, ctx.N, countryCode=None) except bridgedb.Dist.BadEmail, e: logging.info("Got a mail from a bad email address %r: %s.", clientAddr, e) return None, None
def getMailResponse(lines, ctx): """Given a list of lines from an incoming email message, and a MailContext object, parse the email and decide what to do in response. If we want to answer, return a 2-tuple containing the address that will receive the response, and a readable filelike object containing the response. Return None,None if we shouldn't answer. """ # Extract data from the headers. msg = rfc822.Message(MailFile(lines)) subject = msg.getheader("Subject", None) if not subject: subject = "[no subject]" clientFromAddr = msg.getaddr("From") clientSenderAddr = msg.getaddr("Sender") # RFC822 requires at least one 'To' address clientToList = msg.getaddrlist("To") clientToaddr = getBridgeDBEmailAddrFromList(ctx, clientToList) msgID = msg.getheader("Message-ID", None) if clientSenderAddr and clientSenderAddr[1]: clientAddr = clientSenderAddr[1] elif clientFromAddr and clientFromAddr[1]: clientAddr = clientFromAddr[1] else: logging.info("No From or Sender header on incoming mail.") return None,None # Look up the locale part in the 'To:' address, if there is one and get # the appropriate Translation object lang = getLocaleFromPlusAddr(clientToaddr) t = I18n.getLang(lang) try: _, addrdomain = bridgedb.Dist.extractAddrSpec(clientAddr.lower()) except BadEmail: logging.info("Ignoring bad address on incoming email.") return None,None if not addrdomain: logging.info("Couldn't parse domain from %r", Util.logSafely(clientAddr)) if addrdomain and ctx.cfg.EMAIL_DOMAIN_MAP: addrdomain = ctx.cfg.EMAIL_DOMAIN_MAP.get(addrdomain, addrdomain) if addrdomain not in ctx.cfg.EMAIL_DOMAINS: logging.info("Unrecognized email domain %r", Util.logSafely(addrdomain)) return None,None rules = ctx.cfg.EMAIL_DOMAIN_RULES.get(addrdomain, []) if 'dkim' in rules: # getheader() returns the last of a given kind of header; we want # to get the first, so we use getheaders() instead. dkimHeaders = msg.getheaders("X-DKIM-Authentication-Results") dkimHeader = "<no header>" if dkimHeaders: dkimHeader = dkimHeaders[0] if not dkimHeader.startswith("pass"): logging.info("Got a bad dkim header (%r) on an incoming mail; " "rejecting it.", dkimHeader) return None, None # Was the magic string included #for ln in lines: # if ln.strip().lower() in ("get bridges", "subject: get bridges"): # break #else: # logging.info("Got a mail from %r with no bridge request; dropping", # clientAddr) # return None,None # Figure out which bridges to send unblocked = transport = ipv6 = skippedheaders = False bridgeFilterRules = [] addressClass = None for ln in lines: # ignore all lines before the subject header if "subject" in ln.strip().lower(): skippedheaders = True if not skippedheaders: continue if "ipv6" in ln.strip().lower(): ipv6 = True if "transport" in ln.strip().lower(): try: transport = re.search("transport ([_a-zA-Z][_a-zA-Z0-9]*)", ln).group(1).strip() except (TypeError, AttributeError): transport = None logging.debug("Got request for transport: %s" % transport) if "unblocked" in ln.strip().lower(): try: unblocked = re.search("unblocked ([a-zA-Z]{2,4})", ln).group(1).strip() except (TypeError, AttributeError): transport = None if ipv6: bridgeFilterRules.append(filterBridgesByIP6) addressClass = IPv6Address else: bridgeFilterRules.append(filterBridgesByIP4) addressClass = IPv4Address if transport: bridgeFilterRules = [filterBridgesByTransport(transport, addressClass)] if unblocked: rules.append(filterBridgesByNotBlockedIn(unblocked, addressClass, transport)) try: interval = ctx.schedule.getInterval(time.time()) bridges = ctx.distributor.getBridgesForEmail(clientAddr, interval, ctx.N, countryCode=None, bridgeFilterRules=bridgeFilterRules) # Handle rate limited email except TooSoonEmail, e: logging.info("Got a mail too frequently; warning %r: %s.", Util.logSafely(clientAddr), e) # Compose a warning email # MAX_EMAIL_RATE is in seconds, convert to hours body = buildSpamWarningTemplate(t) % (bridgedb.Dist.MAX_EMAIL_RATE / 3600) return composeEmail(ctx.fromAddr, clientAddr, subject, body, msgID, gpgContext=ctx.gpgContext)