示例#1
0
    def from_bytes(cls, corre_b):
        mail_parser = BytesFeedParser()
        mail_parser.feed(corre_b)
        correo = mail_parser.close()
        txt_codec = correo.get_content_charset()
        transfer_codec = correo['Content-Transfer-Encoding']

        origen, codec = decode_header(correo['from'])[0]
        origen = origen.decode(codec)

        destino = es_correo.findall(' '.join([correo.get('Cc', ''), correo.get('To', '')]))
        message_id = correo['Message-Id']
        fecha = datetime.strptime(correo['date'], '%a, %d %b %Y %H:%M:%S %z')
        fecha = datetime(fecha.year, fecha.month, fecha.day, fecha.hour, fecha.minute, fecha.second)

        if transfer_codec is None:
            asunto = correo['subject']
            payload = correo.get_payload(0)
            transfer_codec = payload['Content-Transfer-Encoding']
            txt_codec = payload.get_content_charset()
            mensaje = payload.get_payload(decode=transfer_codec).decode(txt_codec)
        elif transfer_codec == '7bit':
            asunto, codec = decode_header(correo['subject'])[0]
            asunto = asunto.decode(codec)
            mensaje = correo.get_payload()
        elif transfer_codec == 'quoted-printable':
            asunto = correo['subject']
            mensaje = correo.get_payload(decode=transfer_codec).decode(txt_codec)
        else:
            raise NotImplementedError(mail_log.error('Este transfer_codec no está implememntado: {}', transfer_codec))

        return cls(message_id, origen, destino, asunto, mensaje, fecha)
def create_msg_from_source(message_source, to=None):
    message_source = message_source.encode('utf-8')
    parser = BytesFeedParser()
    parser.feed(message_source)
    message = parser.close()
    if to is not None:
        message.replace_header('To', to)
    return encode_message(message)
示例#3
0
 def _send_message(self, filename):
     with open("./"+messages_dir+"/"+filename, "rb") as f:
         byte_array = bytearray(f.read())
         parser = BytesFeedParser()
         parser.feed(byte_array)
         msg = parser.close()
         with self.sender as sndr:
             sndr.send_message(msg)
     os.remove("./"+messages_dir+"/"+filename)
示例#4
0
 def truncate(self, size=None):
     if (size is None and self._written != 0) and size != 0:
         raise NotImplementedError(
             "The 'size' argument to truncate() must be 0 - partial "
             "truncation is not supported")
     if self._closed:
         raise ValueError("File is closed")
     self._parser = BytesFeedParser()
     self._written = 0
示例#5
0
    def __init__(self, context):
        self.context = context

        self._mimeType = None
        self._encoding = 'utf-8'
        self._closed = False
        self._name = None
        self._written = 0
        self._parser = BytesFeedParser()
        self._message = None
示例#6
0
def read_headers(fp):
    ''' Read headers from a binary file such as an HTTP stream, return the raw binary data and the corresponding Message object.
  '''
    def is_header_line(line):
        return line.startswith(b' ') or line.startswith(b'\t') or line.rstrip()

    header_lines = list(takewhile(is_header_line, fp))
    parser = BytesFeedParser()
    parser.feed(b''.join(header_lines))
    return b''.join(header_lines), parser.close()
示例#7
0
    def _read_multipart_mixed(self):
        parser = BytesFeedParser()
        for k, v in self.request.headers.items():
            parser.feed('{}: {}\n'.format(k, v).encode('utf-8'))
        parser.feed(b'\n')
        parser.feed(self.request.body)
        msg = parser.close()

        if not msg.is_multipart():
            logger.error('Bad multipart request')
            self.send_error(400)
            return

        main_part = msg.get_payload(0)
        if main_part.get_content_type() != 'application/json':
            logger.error('Mainpart is not JSON')
            self.send_error(400)
            return

        payload = json.loads(main_part.get_payload(decode=True))
        attachments = {}

        for idx in range(1, len(msg.get_payload())):
            part = msg.get_payload(idx)
            if part.is_multipart():
                logger.error('Nesting multipart is not supported')
                self.send_error(400)
                return

            attachments[part.get_filename()] = part.get_content_type(
            ), part.get_payload(decode=True)

        return payload, attachments
示例#8
0
 def handle_xop(self, client, operation, response):
     """Decode a XML-binary Optimized Packaging (XOP) response.
     Spec: https://www.w3.org/TR/xop10/
     """
     # example Content-Type: multipart/related; boundary="192ACTH5zu2kQtJcnRwnTXJzXb2hoxEPoAksrlRlihV2HO2NmRC6h5NdO4n44nSA2Q19"; type="application/xop+xml"; start="<soap:Envelope>"; start-info="application/soap+xml; charset=utf-8"
     content_type = response.headers.get("content-type", "")
     # don't break pre-Py33 code
     if not content_type.strip().lower().startswith("multipart/related"):
         return response.content
     # parse the Content-Type header; is there an easy and robust pre-Py33 way?
     import email.headerregistry  # New in version 3.3: as a provisional module.
     parsed_ct = email.headerregistry.HeaderRegistry()("content-type", content_type)
     if parsed_ct.content_type.lower() != "multipart/related":
         # this is not a XOP Package
         return response.content
     if parsed_ct.params["type"].lower() != "application/xop+xml":
         # this is not a XOP Package (but it's not plain SOAP either...??)
         return response.content
     # OK, this is indeed a XOP Package, so now we need to break down the multipart/related MIME message
     message_parser = BytesFeedParser()
     # we will only feed the parser the actual body of the HTTP response, so we must first simulate at least the
     # Content-Type header
     message_parser.feed(("Content-Type: %s\r\n\r\n" % (content_type,)).encode())  # additional CRLF for end of headers
     for chunk in response.iter_content(CHUNK_SIZE):
         message_parser.feed(chunk)
     message = message_parser.close()
     message_parts = message.get_payload()
     root = message_parts[0]
     assert root.get_content_type() == "application/xop+xml"
     # startwith (not equals) because it might be "application/soap+xml; charset=utf-8" or similar
     assert root.get_param("type").startswith("application/soap+xml")
     assert all(not message.is_multipart() for message in message_parts[1:])
     assert all(message["Content-ID"] for message in message_parts[1:])
     operation.xop_replaced_data_by_cid = {message["Content-ID"]: message.get_payload(decode=True) for message in message_parts[1:]}
     return root.get_payload(decode=True)
示例#9
0
def email_open(args):
    """ Read the file descriptor and return a msg file """
    parser = BytesFeedParser()
    if args.stdin or args.infile is None:
        with io.BufferedReader(sys.stdin.buffer) as input:
            parser.feed(input.read())
    else:
        with open(args.infile, 'rb') as input:
            parser.feed(input.read())
    msg = parser.close()

    # Check for invalid (0 bytes) message
    if len(msg) == 0:
        error(msg, "Invalid Message", out_streams)
    else:
        return msg
示例#10
0
    async def read_form(self):
        if self._form is None:
            self._form = CIMultiDict()

            if (self.headers.content_type.type == 'application') and (self.headers.content_type.subtype == 'x-www-form-urlencoded'):
                body = await self.read_body()

                for parameter in body.split(b'&'):
                    name, value = parameter.split(b'=')
                    self._form.add(
                        unquote_to_bytes(name).decode('utf-8'),
                        unquote_to_bytes(value).decode('utf-8'))
            elif (self.headers.content_type.type == 'multipart') and (self.headers.content_type.subtype == 'form-data'):
                # TODO: replace with multifruits
                parser = BytesFeedParser(policy=HTTP, _factory=message_factory)
                parser.feed(b'Content-Type: %s\r\n\r\n' % self.raw_headers['Content-Type'])

                async with self.open_body() as stream:
                    while True:
                        data = await stream.read()

                        if not data:
                            break

                        parser.feed(data)

                message = parser.close()

                for part in message.walk():
                    if part.get_content_type() != 'multipart/form-data':
                        params = dict(part.get_params(header='content-disposition'))
                        name = params.get('name')

                        if name:
                            payload =  part.get_payload(decode=True)

                            if payload:
                                if part.get_content_type() == 'application/form-data':
                                    self._form.add(name, payload.decode('utf-8'))
                                else:
                                    self._form.add(
                                        name,
                                        RequestFilePart(params.get('filename'), part.items(), part.get_payload(decode=True)))

        return self._form
示例#11
0
def email_open(args):
    """ Read the file descriptor and return a msg file """
    parser = BytesFeedParser()
    if args.stdin or args.infile is None:
        with io.BufferedReader(sys.stdin.buffer) as input:
            parser.feed(input.read())
    else:
        with open(args.infile, "rb") as input:
            parser.feed(input.read())
    msg = parser.close()

    # Check for invalid (0 bytes) message
    if len(msg) == 0:
        error(msg, "Invalid Message", out_streams)
    else:
        return msg
示例#12
0
 def handle_xop(self, client, operation, response):
     """Decode a XML-binary Optimized Packaging (XOP) response.
     Spec: https://www.w3.org/TR/xop10/
     """
     # example Content-Type: multipart/related; boundary="192ACTH5zu2kQtJcnRwnTXJzXb2hoxEPoAksrlRlihV2HO2NmRC6h5NdO4n44nSA2Q19"; type="application/xop+xml"; start="<soap:Envelope>"; start-info="application/soap+xml; charset=utf-8"
     content_type = response.headers.get("content-type", "")
     # don't break pre-Py33 code
     if not content_type.strip().lower().startswith("multipart/related"):
         return response.content
     # parse the Content-Type header; is there an easy and robust pre-Py33 way?
     import email.headerregistry  # New in version 3.3: as a provisional module.
     parsed_ct = email.headerregistry.HeaderRegistry()("content-type",
                                                       content_type)
     if parsed_ct.content_type.lower() != "multipart/related":
         # this is not a XOP Package
         return response.content
     if parsed_ct.params["type"].lower() != "application/xop+xml":
         # this is not a XOP Package (but it's not plain SOAP either...??)
         return response.content
     # OK, this is indeed a XOP Package, so now we need to break down the multipart/related MIME message
     message_parser = BytesFeedParser()
     # we will only feed the parser the actual body of the HTTP response, so we must first simulate at least the
     # Content-Type header
     message_parser.feed(
         ("Content-Type: %s\r\n\r\n" %
          (content_type, )).encode())  # additional CRLF for end of headers
     for chunk in response.iter_content(CHUNK_SIZE):
         message_parser.feed(chunk)
     message = message_parser.close()
     message_parts = message.get_payload()
     root = message_parts[0]
     assert root.get_content_type() == "application/xop+xml"
     # startwith (not equals) because it might be "application/soap+xml; charset=utf-8" or similar
     assert root.get_param("type").startswith("application/soap+xml")
     assert all(not message.is_multipart() for message in message_parts[1:])
     assert all(message["Content-ID"] for message in message_parts[1:])
     operation.xop_replaced_data_by_cid = {
         message["Content-ID"]: message.get_payload(decode=True)
         for message in message_parts[1:]
     }
     return root.get_payload(decode=True)
示例#13
0
文件: http.py 项目: missuzhang/vlcp
    def parseform(self, limit=67108864, tostr=True, safename=True):
        '''
        Parse form-data with multipart/form-data or application/x-www-form-urlencoded
        In Python3, the keys of form and files are unicode, but values are bytes
        If the key ends with '[]', it is considered to be a list:
        a=1&b=2&b=3          =>    {'a':1,'b':3}
        a[]=1&b[]=2&b[]=3    =>    {'a':[1],'b':[2,3]}
        :param limit: limit total input size, default to 64MB. None = no limit. Note that all the form
        data is stored in memory (including upload files), so it is dangerous to accept a very large input.
        :param tostr: convert values to str in Python3. Only apply to form, files data are always bytes
        :param safename: if True, extra security checks are performed on filenames to reduce known security risks.
        '''
        if tostr:

            def _str(s):
                try:
                    if not isinstance(s, str):
                        return s.decode(self.encoding)
                    else:
                        return s
                except:
                    raise HttpInputException(
                        'Invalid encoding in post data: ' + repr(s))
        else:

            def _str(s):
                return s

        try:
            form = {}
            files = {}
            # If there is not a content-type header, maybe there is not a content.
            if b'content-type' in self.headerdict and self.inputstream is not None:
                contenttype = self.headerdict[b'content-type']
                m = Message()
                # Email library expects string, which is unicode in Python 3
                try:
                    m.add_header('Content-Type',
                                 str(contenttype.decode('ascii')))
                except UnicodeDecodeError:
                    raise HttpInputException(
                        'Content-Type has non-ascii characters')
                if m.get_content_type() == 'multipart/form-data':
                    fp = BytesFeedParser()
                    fp.feed(b'Content-Type: ' + contenttype + b'\r\n\r\n')
                    total_length = 0
                    while True:
                        try:
                            for m in self.inputstream.prepareRead(
                                    self.container):
                                yield m
                            data = self.inputstream.readonce()
                            total_length += len(data)
                            if limit is not None and total_length > limit:
                                raise HttpInputException('Data is too large')
                            fp.feed(data)
                        except EOFError:
                            break
                    msg = fp.close()
                    if not msg.is_multipart() or msg.defects:
                        # Reject the data
                        raise HttpInputException(
                            'Not valid multipart/form-data format')
                    for part in msg.get_payload():
                        if part.is_multipart() or part.defects:
                            raise HttpInputException(
                                'Not valid multipart/form-data format')
                        disposition = part.get_params(
                            header='content-disposition')
                        if not disposition:
                            raise HttpInputException(
                                'Not valid multipart/form-data format')
                        disposition = dict(disposition)
                        if 'form-data' not in disposition or 'name' not in disposition:
                            raise HttpInputException(
                                'Not valid multipart/form-data format')
                        if 'filename' in disposition:
                            name = disposition['name']
                            filename = disposition['filename']
                            if safename:
                                filename = _safename(filename)
                            if name.endswith('[]'):
                                files.setdefault(name[:-2], []).append({
                                    'filename':
                                    filename,
                                    'content':
                                    part.get_payload(decode=True)
                                })
                            else:
                                files[name] = {
                                    'filename': filename,
                                    'content': part.get_payload(decode=True)
                                }
                        else:
                            name = disposition['name']
                            if name.endswith('[]'):
                                form.setdefault(name[:-2], []).append(
                                    _str(part.get_payload(decode=True)))
                            else:
                                form[name] = _str(
                                    part.get_payload(decode=True))
                elif m.get_content_type() == 'application/x-www-form-urlencoded' or \
                        m.get_content_type() == 'application/x-url-encoded':
                    if limit is not None:
                        for m in self.inputstream.read(self.container,
                                                       limit + 1):
                            yield m
                        data = self.container.data
                        if len(data) > limit:
                            raise HttpInputException('Data is too large')
                    else:
                        for m in self.inputstream.read(self.container):
                            yield m
                        data = self.container.data
                    result = parse_qs(data, True)

                    def convert(k, v):
                        try:
                            k = str(k.decode('ascii'))
                        except:
                            raise HttpInputException(
                                'Form-data key must be ASCII')
                        if not k.endswith('[]'):
                            v = _str(v[-1])
                        else:
                            k = k[:-2]
                            v = [_str(i) for i in v]
                        return (k, v)

                    form = dict(convert(k, v) for k, v in result.items())
                else:
                    # Other formats, treat like no data
                    pass
            self.form = form
            self.files = files
        except Exception as exc:
            raise HttpInputException('Failed to parse form-data: ' + str(exc))
示例#14
0
class DefaultWriteFile(object):
    """IRawWriteFile file adapter for Dexterity objects.

    Uses RFC822 marshaler.
    """
    def __init__(self, context):
        self.context = context

        self._mimeType = None
        self._encoding = 'utf-8'
        self._closed = False
        self._name = None
        self._written = 0
        self._parser = BytesFeedParser()
        self._message = None

    @property
    def mimeType(self):
        if self._message is None:
            return self._mimeType
        elif not self._message.is_multipart():
            return 'text/plain'
        else:
            return 'message/rfc822'

    @mimeType.setter
    def mimeType(self, value):
        self._mimeType = value

    @property
    def encoding(self):
        if self._message is not None:
            return self._message.get_charset() or self._encoding
        return self._encoding

    @encoding.setter
    def encoding(self, value):
        self._encoding = value

    @property
    def closed(self):
        return self._closed

    @property
    def name(self):
        if self._message is not None:
            return self._message.get_filename(self._name)
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    def seek(self, offset, whence=None):
        raise NotImplementedError("Seeking is not supported")

    def tell(self):
        return self._written

    def close(self):
        self._message = self._parser.close()
        self._closed = True
        initializeObjectFromSchemata(self.context, iterSchemata(self.context),
                                     self._message, self._encoding)

    def write(self, data):
        if self._closed:
            raise ValueError("File is closed")
        if isinstance(data, six.text_type):
            data = data.encode()
        self._written += len(data)
        self._parser.feed(data)

    def writelines(self, sequence):
        for item in sequence:
            self.write(item)

    def truncate(self, size=None):
        if (size is None and self._written != 0) and size != 0:
            raise NotImplementedError(
                "The 'size' argument to truncate() must be 0 - partial "
                "truncation is not supported")
        if self._closed:
            raise ValueError("File is closed")
        self._parser = BytesFeedParser()
        self._written = 0

    def flush(self):
        pass
示例#15
0
def get_email_requests(redis_client, IMAP_SERVER, IMAP_USERNAME,
                       IMAP_PASSWORD):
    """
    This function connects to an email server and retrieves all new emails to
    identify new VPN requests.
    """

    email_requests = []
    msg_type = "email"
    try:
        # Connect to email
        mail = imaplib.IMAP4_SSL(IMAP_SERVER)
        mail.login(IMAP_USERNAME, IMAP_PASSWORD)
        logging.debug("Connected to account successful")

        # Connect to Inbox. Readyonly option: False=marks msgs as read; True=keep messages as unread.
        mail.select("Inbox", readonly=False)

        # Search and return UIDS of all UNSEEN/UNREAD emails in Inbox
        result, data = mail.uid('search', None, "UNSEEN")

        # We receive a list of unread email UID
        id_list = data[0].split()  # data is a list.
        logging.info("Found {} new requests to process".format(len(id_list)))

        # Process the new unread emails. If zero, nothing returns
        while len(id_list) > 0:
            # In case another process checked emails simultaneously, we refresh the list of ids
            result, data = mail.uid('search', None, "UNSEEN")
            id_list = data[0].split()  # data is a list.

            # Get the first email ID to process
            email_uid = id_list.pop(0)
            logging.debug(f"Processing email UID {email_uid}")

            # Fetch the email headers and body (RFC822) for the given email UID
            result, data = mail.uid('fetch', email_uid, '(RFC822)')

            # Parse email to extract header and body
            email_parser = BytesFeedParser()
            email_parser.feed(data[0][1])
            msg = email_parser.close()

            # Do not process answers to the emails we send
            if msg['In-Reply-To'] is not None:
                continue

            # Parse email receiver
            email_to = re.search(r'[\w\.-]+@[\w\.-]+', msg['to']).group(0)
            logging.debug(f"Processing email receiver {email_to}")

            # Do not process messages where we are not the receivers
            if not email_to == IMAP_USERNAME:
                continue

            # Parse subject and find matches for keyword VPN
            email_subject = ""
            msg_request = ""
            try:
                email_subject = re.search(r'NOENCRYPTEDVPN', msg['subject'],
                                          re.IGNORECASE).group(0)
                msg_request = "novpn"
            except:
                try:
                    email_subject = re.search(r'NOTENCRYPTEDVPN',
                                              msg['subject'],
                                              re.IGNORECASE).group(0)
                    msg_request = "novpn"
                except:
                    try:
                        email_subject = re.search(r'WIREGUARD', msg['subject'],
                                                  re.IGNORECASE).group(0)
                        msg_request = "wireguard"
                    except:
                        try:
                            email_subject = re.search(r'VPN', msg['subject'],
                                                      re.IGNORECASE).group(0)
                            msg_request = "openvpn"
                        except:
                            pass
            logging.debug(
                f"Extracted email subject: {email_subject} ({msg_request})")

            # Parse email body and find matches for keyword VPN
            try:
                # Extract email body in rich email
                email_body = msg.get_payload().pop().get_payload()
            except:
                # Extract email body in plain email
                email_body = msg.get_payload()

            try:
                email_body = re.search(r'NOENCRYPTEDVPN', email_body,
                                       re.IGNORECASE).group(0)
                msg_request = "novpn"
            except:
                try:
                    email_body = re.search(r'NOTENCRYPTEDVPN', email_body,
                                           re.IGNORECASE).group(0)
                    msg_request = "novpn"
                except:
                    try:
                        email_body = re.search(r'WIREGUARD', email_body,
                                               re.IGNORECASE).group(0)
                        msg_request = "wireguard"
                    except:
                        try:
                            email_body = re.search(r'VPN', email_body,
                                                   re.IGNORECASE).group(0)
                            msg_request = "openvpn"
                        except:
                            email_body = ""
            logging.debug(
                f"Extracted email body: {email_body} ({msg_request})")

            # We only parse messages that contain VPN in subject or body
            # These prints will be removed after we test everything is good
            if msg_request != "":
                logging.info(
                    f"Extracted email request: {email_subject}:{email_body}({msg_request})"
                )
                # Parse email date
                email_date = msg['date']

                # Parse email sender
                email_from = re.search(r'[\w\.-]+@[\w\.-]+',
                                       msg['from']).group(0)

                # Write pending account to provision in REDIS
                send_request_to_redis(int(email_uid), email_from, msg_type,
                                      msg_request, logging, redis_client)

                # Notify manager of new request
                redis_client.publish('services_status',
                                     'MOD_COMM_RECV:NEW_REQUEST')

                logging.debug("This email matches the keywords")
                logging.debug('{:8}: {}'.format("email id", int(email_uid)))
                logging.debug('{:8}: {}'.format("date", email_date))
                logging.debug('{:8}: {}'.format("to", email_to))
                logging.debug('{:8}: {}'.format("from", email_from))
                logging.debug('{:8}: {}'.format("reply_to",
                                                msg['In-Reply-To']))
                logging.debug('{:8}: {}'.format("subject", email_subject))
                logging.debug('{:8}: {}'.format("body", email_body))
            else:
                logging.debug("This email does not match the keywords")
                logging.debug('{:8}: {}'.format("Email ID", email_uid))
                logging.debug('{:8}: {}'.format("Date", email_date))
                logging.debug('{:8}: {}'.format("To", email_to))
                logging.debug('{:8}: {}'.format("From", email_from))
                logging.debug('{:8}: {}'.format("reply_to",
                                                msg['In-Reply-To']))
                logging.debug('{:8}: {}'.format("Subject", email_subject))
                logging.debug('{:8}: {}'.format("Body", email_body))

        # Close connection to server
        mail.expunge()
        mail.close()
        mail.logout()
        return True
    except Exception as e:
        print(e)
        return False