Esempio n. 1
0
 def handle(self, *args, **options):
     if len(args) != 3:
         raise CommandError(
             _(u'Insufficient number of arguments specified, please check help for correct usage'
               ))
     try:
         org = models.Organization.objects.get(as2_name=args[0])
     except models.Organization.DoesNotExist:
         raise CommandError(_(u'Organization "%s" does not exist' %
                              args[0]))
     try:
         partner = models.Partner.objects.get(as2_name=args[1])
     except models.Partner.DoesNotExist:
         raise CommandError(_(u'Partner "%s" does not exist' % args[1]))
     if not os.path.isfile(args[2]):
         raise CommandError(
             _(u'Payload at location "%s" does not exist' % args[2]))
     if options['delete'] and not os.access(args[2], os.W_OK):
         raise CommandError('Insufficient file permission for payload %s' %
                            args[2])
     outdir = as2utils.join(pyas2init.gsettings['payload_send_store'],
                            time.strftime('%Y%m%d'))
     as2utils.dirshouldbethere(outdir)
     outfile = as2utils.join(outdir, os.path.basename(args[2]))
     shutil.copy2(args[2], outfile)
     if options['delete']:
         os.remove(args[2])
     payload = models.Payload.objects.create(
         name=os.path.basename(args[2]),
         file=outfile,
         content_type=partner.content_type)
     message = models.Message.objects.create(
         message_id=email.utils.make_msgid().strip('<>'),
         partner=partner,
         organization=org,
         direction='OUT',
         status='IP',
         payload=payload)
     try:
         payload = as2lib.build_message(message)
         as2lib.send_message(message, payload)
     except Exception, e:
         txt = as2utils.txtexc()
         reporttxt = _(u'Failed to send message, error:\n%(txt)s') % {
             'txt': txt
         }
         pyas2init.logger.error(reporttxt)
         message.status = 'E'
         models.Log.objects.create(
             message=message,
             status='E',
             text=_(u'Failed to send message, error is %s' % e))
         message.save()
         ### Send mail here
         as2utils.senderrorreport(
             message, _(u'Failed to send message, error is %s' % e))
         sys.exit(2)
Esempio n. 2
0
def update_dirs():
    partners = Partner.objects.all()
    orgs = Organization.objects.all()
    for partner in partners:
	for org in orgs:
	    as2utils.dirshouldbethere(as2utils.join(pyas2init.gsettings['root_dir'], 'messages', org.as2_name, 'inbox', partner.as2_name))
    for org in orgs:
	for partner in partners:
	    as2utils.dirshouldbethere(as2utils.join(pyas2init.gsettings['root_dir'], 'messages', partner.as2_name, 'outbox', org.as2_name))
Esempio n. 3
0
def check_odirs(sender, instance, created, **kwargs):
    partners = Partner.objects.all()
    for partner in partners:
        as2utils.dirshouldbethere(
            as2utils.join(pyas2init.gsettings['root_dir'], 'messages',
                          instance.as2_name, 'inbox', partner.as2_identifier))
        as2utils.dirshouldbethere(
            as2utils.join(pyas2init.gsettings['root_dir'], 'messages',
                          partner.as2_identifier, 'outbox', instance.as2_name))
Esempio n. 4
0
def check_pdirs(sender, instance, created, **kwargs):
    orgs = Organization.objects.all()
    for org in orgs:
        as2utils.dirshouldbethere(
            as2utils.join(pyas2init.gsettings['root_dir'], 'messages',
                          org.as2_name, 'inbox', instance.as2_name))
        as2utils.dirshouldbethere(
            as2utils.join(pyas2init.gsettings['root_dir'], 'messages',
                          instance.as2_name, 'outbox', org.as2_name))
Esempio n. 5
0
 def handle(self, *args, **options):
     if len(args) != 3:
         raise CommandError(
             _(u'Insufficient number of arguments specified, please check help for correct usage'
               ))
     try:
         org = models.Organization.objects.get(as2_name=args[0])
     except models.Organization.DoesNotExist:
         raise CommandError(
             _(u'Organization "%s" does not exist' % args[0]))
     try:
         partner = models.Partner.objects.get(as2_name=args[1])
     except models.Partner.DoesNotExist:
         raise CommandError(_(u'Partner "%s" does not exist' % args[1]))
     if not os.path.isfile(args[2]):
         raise CommandError(
             _(u'Payload at location "%s" does not exist' % args[2]))
     if options['delete'] and not os.access(args[2], os.W_OK):
         raise CommandError(
             'Insufficient file permission for payload %s' % args[2])
     outdir = as2utils.join(pyas2init.gsettings['payload_send_store'],
                            time.strftime('%Y%m%d'))
     as2utils.dirshouldbethere(outdir)
     outfile = as2utils.join(outdir, os.path.basename(args[2]))
     shutil.copy2(args[2], outfile)
     if options['delete']:
         os.remove(args[2])
     payload = models.Payload.objects.create(
         name=os.path.basename(args[2]),
         file=outfile,
         content_type=partner.content_type)
     message = models.Message.objects.create(
         message_id=email.utils.make_msgid().strip('<>'),
         partner=partner,
         organization=org,
         direction='OUT',
         status='IP',
         payload=payload)
     try:
         payload = as2lib.build_message(message)
         as2lib.send_message(message, payload)
     except Exception, e:
         txt = as2utils.txtexc()
         reporttxt = _(u'Failed to send message, error:\n%(txt)s') % {
             'txt': txt
         }
         pyas2init.logger.error(reporttxt)
         message.status = 'E'
         models.Log.objects.create(
             message=message,
             status='E',
             text=_(u'Failed to send message, error is %s' % e))
         message.save()
         ### Send mail here
         as2utils.senderrorreport(
             message, _(u'Failed to send message, error is %s' % e))
         sys.exit(2)
Esempio n. 6
0
def update_dirs():
    partners = Partner.objects.all()
    orgs = Organization.objects.all()
    for partner in partners:
        for org in orgs:
            as2utils.dirshouldbethere(
                as2utils.join(pyas2init.gsettings['root_dir'], 'messages',
                              org.as2_name, 'inbox', partner.as2_identifier))
    for org in orgs:
        for partner in partners:
            as2utils.dirshouldbethere(
                as2utils.join(pyas2init.gsettings['root_dir'], 'messages',
                              partner.as2_identifier, 'outbox', org.as2_name))
Esempio n. 7
0
def initialize():
    global gsettings
    pyas2_settings = {}
    if hasattr(settings, 'PYAS2'):
        pyas2_settings = settings.PYAS2
    if not gsettings:
        gsettings['environment'] = pyas2_settings.get('ENVIRONMENT','production')
        gsettings['port'] = pyas2_settings.get('PORT', 8080)
        gsettings['ssl_certificate'] = pyas2_settings.get('SSLCERTIFICATE',None)
        gsettings['ssl_private_key'] = pyas2_settings.get('SSLPRIVATEKEY',None)
        gsettings['environment_text'] = pyas2_settings.get('ENVIRONMENTTEXT','Production')
        gsettings['environment_text_color'] = pyas2_settings.get('ENVIRONMENTTEXTCOLOR','Black')
        gsettings['root_dir'] = settings.BASE_DIR
        gsettings['python_path'] = pyas2_settings.get('PYTHONPATH', sys.executable)
        gsettings['managepy_path'] = as2utils.join(settings.BASE_DIR, 'manage.py')
        gsettings['daemon_port'] = pyas2_settings.get('DAEMONPORT', 16388)
        if pyas2_settings.get('DATADIR') and os.path.isdir(pyas2_settings.get('DATADIR')): 
            gsettings['root_dir'] = pyas2_settings.get('DATADIR')
        gsettings['payload_receive_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'payload', 'received')
        gsettings['payload_send_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'payload', 'sent')
        gsettings['mdn_receive_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'mdn', 'received')
        gsettings['mdn_send_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'mdn', 'sent')
        gsettings['log_dir'] = as2utils.join(gsettings['root_dir'], 'logging')
        for sett in ['payload_receive_store', 'payload_send_store', 'mdn_receive_store', 'mdn_send_store', 'log_dir']:
            as2utils.dirshouldbethere(gsettings[sett])
        gsettings['log_level'] = pyas2_settings.get('LOGLEVEL','INFO')
        gsettings['log_console'] = pyas2_settings.get('LOGCONSOLE',True)
        gsettings['log_console_level'] = pyas2_settings.get('LOGCONSOLELEVEL','STARTINFO')
        gsettings['max_retries'] = pyas2_settings.get('MAXRETRIES',30)
        gsettings['mdn_url'] = pyas2_settings.get('MDNURL','http://localhost:8080/pyas2/as2receive')
        gsettings['async_mdn_wait'] = pyas2_settings.get('ASYNCMDNWAIT',30)
        gsettings['max_arch_days'] = pyas2_settings.get('MAXARCHDAYS',30)
        gsettings['minDate'] = 0 - gsettings['max_arch_days']
Esempio n. 8
0
def initialize():
    """ Function initializes the global variables for pyAS2 """

    global gsettings
    pyas2_settings = {}
    if hasattr(settings, 'PYAS2'):
        pyas2_settings = settings.PYAS2
    if not gsettings:
        gsettings['environment'] = pyas2_settings.get('ENVIRONMENT',
                                                      'production')
        gsettings['port'] = pyas2_settings.get('PORT', 8080)
        gsettings['ssl_certificate'] = pyas2_settings.get(
            'SSLCERTIFICATE', None)
        gsettings['ssl_private_key'] = pyas2_settings.get(
            'SSLPRIVATEKEY', None)
        gsettings['environment_text'] = pyas2_settings.get(
            'ENVIRONMENTTEXT', 'Production')
        gsettings['environment_text_color'] = pyas2_settings.get(
            'ENVIRONMENTTEXTCOLOR', 'Black')
        gsettings['root_dir'] = settings.BASE_DIR
        gsettings['python_path'] = pyas2_settings.get('PYTHONPATH',
                                                      sys.executable)
        gsettings['managepy_path'] = as2utils.join(settings.BASE_DIR,
                                                   'manage.py')
        gsettings['daemon_port'] = pyas2_settings.get('DAEMONPORT', 16388)
        if pyas2_settings.get('DATADIR') and os.path.isdir(
                pyas2_settings.get('DATADIR')):
            gsettings['root_dir'] = pyas2_settings.get('DATADIR')
        gsettings['payload_receive_store'] = as2utils.join(
            gsettings['root_dir'], 'messages', '__store', 'payload',
            'received')
        gsettings['payload_send_store'] = as2utils.join(
            gsettings['root_dir'], 'messages', '__store', 'payload', 'sent')
        gsettings['mdn_receive_store'] = as2utils.join(gsettings['root_dir'],
                                                       'messages', '__store',
                                                       'mdn', 'received')
        gsettings['mdn_send_store'] = as2utils.join(gsettings['root_dir'],
                                                    'messages', '__store',
                                                    'mdn', 'sent')
        gsettings['log_dir'] = as2utils.join(gsettings['root_dir'], 'logging')
        for sett in [
                'payload_receive_store', 'payload_send_store',
                'mdn_receive_store', 'mdn_send_store', 'log_dir'
        ]:
            as2utils.dirshouldbethere(gsettings[sett])
        gsettings['log_level'] = pyas2_settings.get('LOGLEVEL', 'INFO')
        gsettings['log_console'] = pyas2_settings.get('LOGCONSOLE', True)
        gsettings['log_console_level'] = pyas2_settings.get(
            'LOGCONSOLELEVEL', 'STARTINFO')
        gsettings['max_retries'] = pyas2_settings.get('MAXRETRIES', 30)
        gsettings['mdn_url'] = pyas2_settings.get(
            'MDNURL', 'http://localhost:8080/pyas2/as2receive')
        gsettings['async_mdn_wait'] = pyas2_settings.get('ASYNCMDNWAIT', 30)
        gsettings['max_arch_days'] = pyas2_settings.get('MAXARCHDAYS', 30)
        gsettings['minDate'] = 0 - gsettings['max_arch_days']
Esempio n. 9
0
def as2receive(request, *args, **kwargs):
    """
       Function receives AS2 requests from partners.
       Checks whether its an AS2 message or an MDN and acts accordingly.
    """
    if request.method == 'POST':
        # Create separate raw_payload with only message-id and content type
        # as M2Crypto's signatur verification method does not like many headers
        raw_payload = '%s: %s\n' % ('message-id',
                                    request.META['HTTP_MESSAGE_ID'])
        raw_payload += '%s: %s\n\n' % ('content-type',
                                       request.META['CONTENT_TYPE'])
        raw_payload += request.body

        # Extract all the relevant headers from the http request
        as2headers = ''
        for key in request.META:
            if key.startswith('HTTP') or key.startswith('CONTENT'):
                h_key = key.replace("HTTP_", "").replace("_", "-").lower()
                as2headers += '%s: %s\n' % (h_key, request.META[key])

        request_content = as2headers.encode('utf-8') + '\n'.encode(
            'utf-8') + request.body
        pyas2init.logger.debug(
            'Recevied an HTTP POST from %s with payload :\n%s' %
            (request.META['REMOTE_ADDR'], request_content))
        try:
            pyas2init.logger.debug(
                'Check payload to see if its an AS2 Message or ASYNC MDN.')
            # Load the request header and body as a MIME Email Message
            payload = email.message_from_string(request_content)

            # Get the message sender and receiver AS2 identifiers
            message_org_as2name = as2utils.unescape_as2name(
                payload.get('as2-to'))
            message_partner_as2name = as2utils.unescape_as2name(
                payload.get('as2-from'))
            message = None

            # Check if this is an MDN message
            mdn_message = None
            if payload.get_content_type() == 'multipart/report':
                mdn_message = payload
            elif payload.get_content_type() == 'multipart/signed':
                for part in payload.walk():
                    if part.get_content_type() == 'multipart/report':
                        mdn_message = part

            # If this is an MDN, get the message ID and check if it exists
            if mdn_message:
                msg_id = None

                for part in mdn_message.walk():
                    if part.get_content_type(
                    ) == 'message/disposition-notification':
                        msg_id = part.get_payload().pop().get(
                            'Original-Message-ID')
                pyas2init.logger.info(
                    'Asynchronous MDN received for AS2 message %s to organization %s '
                    'from partner %s' %
                    (msg_id, message_org_as2name, message_partner_as2name))
                try:
                    # Get the related organization, partner and message from the db.
                    org = get_object_or_404(models.Organization,
                                            as2_name=message_org_as2name)
                    partner = as2lib.get_partner_from_payload(payload)
                    if not partner:
                        raise Http404('No Partner matches the given query.')
                    message = get_object_or_404(models.Message,
                                                message_id=msg_id.strip('<>'),
                                                organization=org,
                                                partner=partner)
                    models.Log.objects.create(
                        message=message,
                        status='S',
                        text=_(
                            u'Processing asynchronous mdn received from partner'
                        ))
                    as2lib.save_mdn(message, raw_payload)

                except Http404:
                    # Send 404 response
                    pyas2init.logger.error(
                        'Unknown Asynchronous MDN AS2 message %s. '
                        'Either the partner, org or message was not found in the system'
                        % msg_id)
                    return HttpResponseServerError(
                        _(u'Unknown AS2 MDN received. Will not be processed'))

                except Exception, e:
                    message.status = 'E'
                    message.adv_status = _(
                        u'Failed to send message, error is:\n %s' %
                        traceback.format_exc(None).decode('utf-8', 'ignore'))
                    models.Log.objects.create(message=message,
                                              status='E',
                                              text=message.adv_status)

                    # Send mail here
                    as2utils.senderrorreport(message, message.adv_status)

                finally:
                    # Save message and send response to HTTP request
                    if message:
                        message.save()
                    return HttpResponse(_(u'AS2 ASYNC MDN has been received'))

            else:
                try:
                    # Process the received AS2 message from partner
                    # Initialize the processing status variables
                    status, adv_status, status_message = '', '', ''

                    pyas2init.logger.info(
                        'Received an AS2 message with id %s for organization %s from partner %s'
                        % (payload.get('message-id'), message_org_as2name,
                           message_partner_as2name))

                    # Raise duplicate message error in case message already exists in the system
                    # TODO: Create composite key (message_id, organization, partner)
                    if models.Message.objects.filter(message_id=payload.get(
                            'message-id').strip('<>')).exists():
                        message = models.Message.objects.create(
                            message_id='%s_%s' %
                            (payload.get('message-id').strip('<>'),
                             payload.get('date')),
                            direction='IN',
                            status='IP',
                            headers=as2headers)
                        raise as2utils.As2DuplicateDocument(
                            _(u'An identical message has already '
                              u'been sent to our server'))

                    # Create a new message in the system
                    message = models.Message.objects.create(
                        message_id=payload.get('message-id').strip('<>'),
                        direction='IN',
                        status='IP',
                        headers=as2headers)

                    # Process the received payload to extract the actual message from partner
                    payload = as2lib.save_message(message, payload,
                                                  raw_payload)

                    # Get the inbox folder for this partner and organization
                    output_dir = as2utils.join(pyas2init.gsettings['root_dir'],
                                               'messages',
                                               message.organization.as2_name,
                                               'inbox',
                                               message.partner.as2_identifier)

                    # Get the filename from the header and if not there set to message id
                    if message.partner.keep_filename and payload.get_filename(
                    ):
                        filename = payload.get_filename()[:100]
                    else:
                        filename = '%s.msg' % uuid.uuid4()

                    # Save the message content to the store and inbox
                    content = payload.get_payload(decode=True)
                    full_filename = as2utils.storefile(output_dir, filename,
                                                       content, False)
                    store_filename = as2utils.storefile(
                        pyas2init.gsettings['payload_receive_store'],
                        message.message_id, content, True)

                    models.Log.objects.create(
                        message=message,
                        status='S',
                        text=_(u'Message has been saved successfully to %s' %
                               full_filename))
                    message.payload = models.Payload.objects.create(
                        name=filename,
                        file=store_filename,
                        content_type=payload.get_content_type())

                    # Set processing status and run the post receive command.
                    status = 'success'
                    as2lib.run_post_receive(message, full_filename)
                    message.save()

                # Catch each of the possible exceptions while processing an as2 message
                except as2utils.As2DuplicateDocument, e:
                    status = 'warning'
                    adv_status = 'duplicate-document'
                    status_message = _(
                        u'An error occurred during the AS2 message processing: %s'
                        % e)

                except as2utils.As2PartnerNotFound, e:
                    status = 'error'
                    adv_status = 'unknown-trading-partner'
                    status_message = _(
                        u'An error occurred during the AS2 message processing: %s'
                        % e)
Esempio n. 10
0
def check_pdirs(sender, instance, created, **kwargs):
    orgs = Organization.objects.all()
    for org in orgs:
        as2utils.dirshouldbethere(as2utils.join(pyas2init.gsettings['root_dir'], 'messages', org.as2_name, 'inbox', instance.as2_name))
        as2utils.dirshouldbethere(as2utils.join(pyas2init.gsettings['root_dir'], 'messages', instance.as2_name, 'outbox', org.as2_name))
Esempio n. 11
0
def check_odirs(sender, instance, created, **kwargs):
    partners = Partner.objects.all()
    for partner in partners:
        as2utils.dirshouldbethere(as2utils.join(pyas2init.gsettings['root_dir'], 'messages', instance.as2_name, 'inbox', partner.as2_name))
        as2utils.dirshouldbethere(as2utils.join(pyas2init.gsettings['root_dir'], 'messages', partner.as2_name, 'outbox', instance.as2_name))
Esempio n. 12
0
 def handle(self, *args, **options):
     pyas2init.logger.info(_(u'Starting PYAS2 send daemon.'))
     try:
         engine_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         engine_socket.bind(
             ('127.0.0.1', pyas2init.gsettings['daemon_port']))
     except socket.error:
         engine_socket.close()
         raise CommandError(
             _(u'An instance of the send daemon is already running'))
     else:
         atexit.register(engine_socket.close)
     cond = threading.Condition()
     tasks = set()
     dir_watch_data = []
     orgs = models.Organization.objects.all()
     partners = models.Partner.objects.all()
     python_executable_path = pyas2init.gsettings['python_path']
     managepy_path = pyas2init.gsettings['managepy_path']
     for partner in partners:
         for org in orgs:
             dir_watch_data.append({})
             dir_watch_data[-1]['path'] = as2utils.join(
                 pyas2init.gsettings['root_dir'], 'messages',
                 partner.as2_name, 'outbox', org.as2_name)
             dir_watch_data[-1]['organization'] = org.as2_name
             dir_watch_data[-1]['partner'] = partner.as2_name
     if not dir_watch_data:
         pyas2init.logger.error(_(u'No partners have been configured!'))
         sys.exit(0)
     pyas2init.logger.info(_(u'Process existing files in the directory.'))
     for dir_watch in dir_watch_data:
         files = [
             f for f in os.listdir(dir_watch['path'])
             if os.path.isfile(as2utils.join(dir_watch['path'], f))
         ]
         for file in files:
             lijst = [
                 python_executable_path, managepy_path, 'sendas2message',
                 '--delete', dir_watch['organization'],
                 dir_watch['partner'],
                 as2utils.join(dir_watch['path'], file)
             ]
             pyas2init.logger.info(
                 u'Send as2 message with params "%(task)s".',
                 {'task': lijst})
             subprocess.Popen(lijst)
     if os.name == 'nt':
         # for windows: start a thread per directory watcher
         for dir_watch in dir_watch_data:
             dir_watch_thread = threading.Thread(
                 target=windows_event_handler,
                 args=(pyas2init.logger, dir_watch, cond, tasks))
             dir_watch_thread.daemon = True  # do not wait for thread when exiting
             dir_watch_thread.start()
     else:
         # for linux: one watch-thread, but multiple watches.
         dir_watch_thread = threading.Thread(target=linux_event_handler,
                                             args=(pyas2init.logger,
                                                   dir_watch_data, cond,
                                                   tasks))
         dir_watch_thread.daemon = True  # do not wait for thread when exiting
         dir_watch_thread.start()
     # this main thread get the results from the watch-thread(s).
     pyas2init.logger.info(_(u'PYAS2 send daemon started started.'))
     active_receiving = False
     timeout = 2.0
     cond.acquire()
     while True:
         # this functions as a buffer: all events go into set tasks.
         # the tasks are fired to jobqueue after TIMOUT sec.
         # this is to avoid firing to many tasks to jobqueue; events typically come in bursts.
         # is value of timeout is larger, reaction times are slower...but less tasks are fired to jobqueue.
         # in itself this is not a problem, as jobqueue will alos discard duplicate jobs.
         # 2 sec seems to e a good value: reasonable quick, not to nervous.
         cond.wait(
             timeout=timeout)  # get back when results, or after timeout sec
         if tasks:
             if not active_receiving:  # first request (after tasks have been  fired, or startup of dirmonitor)
                 active_receiving = True
                 last_time = time.time()
             else:  # active receiving events
                 current_time = time.time()
                 if current_time - last_time >= timeout:
                     try:
                         for task in tasks:
                             lijst = [
                                 python_executable_path, managepy_path,
                                 'sendas2message', '--delete', task[0],
                                 task[1], task[2]
                             ]
                             pyas2init.logger.info(
                                 u'Send as2 message with params "%(task)s".',
                                 {'task': lijst})
                             subprocess.Popen(lijst)
                     except Exception as msg:
                         pyas2init.logger.info(
                             u'Error in running task: "%(msg)s".',
                             {'msg': msg})
                     tasks.clear()
                     active_receiving = False
                 else:
                     pyas2init.logger.debug(u'time difference to small.')
                     last_time = current_time
     cond.release()
     sys.exit(0)
Esempio n. 13
0
    def handle(self, *args, **options):
        # Check if organization and partner exists
        try:
            org = models.Organization.objects.get(
                as2_name=options['organization_as2name'])
        except models.Organization.DoesNotExist:
            raise CommandError(
                _(u'Organization "%s" does not exist' %
                  options['organization_as2name']))
        try:
            partner = models.Partner.objects.get(
                as2_name=options['partner_as2name'])
        except models.Partner.DoesNotExist:
            raise CommandError(
                _(u'Partner "%s" does not exist' % options['partner_as2name']))

        # Check if file exists and we have the right permissions
        if not os.path.isfile(options['path_to_payload']):
            raise CommandError(
                _(u'Payload at location "%s" does not exist' %
                  options['path_to_payload']))
        if options['delete'] and not os.access(options['path_to_payload'],
                                               os.W_OK):
            raise CommandError('Insufficient file permission for payload %s' %
                               options['path_to_payload'])

        # Copy the file to the store
        output_dir = as2utils.join(pyas2init.gsettings['payload_send_store'],
                                   time.strftime('%Y%m%d'))
        as2utils.dirshouldbethere(output_dir)
        outfile = as2utils.join(output_dir,
                                os.path.basename(options['path_to_payload']))
        shutil.copy2(options['path_to_payload'], outfile)

        # Delete original file if option is set
        if options['delete']:
            os.remove(options['path_to_payload'])

        # Create the payload and message objects
        payload = models.Payload.objects.create(
            name=os.path.basename(options['path_to_payload']),
            file=outfile,
            content_type=partner.content_type)
        message = models.Message.objects.create(
            message_id=email.utils.make_msgid().strip('<>'),
            partner=partner,
            organization=org,
            direction='OUT',
            status='IP',
            payload=payload)

        # Build and send the AS2 message
        try:
            payload = as2lib.build_message(message)
            as2lib.send_message(message, payload)
        except Exception:
            message.status = 'E'
            txt = traceback.format_exc(None).decode('utf-8', 'ignore')
            message.adv_status = \
                _(u'Failed to send message, error:\n%(txt)s') % {'txt': txt}
            pyas2init.logger.error(message.adv_status)

            models.Log.objects.create(message=message,
                                      status='E',
                                      text=message.adv_status)
            message.save()

            # Send mail here
            as2utils.senderrorreport(message, message.adv_status)
            sys.exit(2)

        sys.exit(0)
Esempio n. 14
0
def as2receive(request, *args, **kwargs):
    """
       Function receives AS2 requests from partners.
       Checks whether its an AS2 message or an MDN and acts accordingly.
    """
    if request.method == 'POST':
        # Process the posted AS2 message
        request_body = request.read()

        # Create separate raw_payload with only message-id and content type as M2Crypto's signature
        # verification method does not like too many header
        raw_payload = '%s: %s\n' % ('message-id', request.META['HTTP_MESSAGE_ID'])
        raw_payload += '%s: %s\n\n' % ('content-type', request.META['CONTENT_TYPE'])
        raw_payload += request_body

        # Extract all the relevant headers from the http request
        as2headers = ''
        for key in request.META:
            if key.startswith('HTTP') or key.startswith('CONTENT'):
                as2headers += '%s: %s\n' % (key.replace("HTTP_", "").replace("_", "-").lower(), request.META[key])

        pyas2init.logger.debug('Recevied an HTTP POST from %s with payload :\n%s' %
                               (request.META['REMOTE_ADDR'], as2headers + '\n' + request_body))
        try:
            pyas2init.logger.debug('Check payload to see if its an AS2 Message or ASYNC MDN.')
            # Load the request header and body as a MIME Email Message
            payload = email.message_from_string(as2headers + '\n' + request_body)
            # Get the message sender and receiver AS2 IDs
            message_org = as2utils.unescape_as2name(payload.get('as2-to'))
            message_partner = as2utils.unescape_as2name(payload.get('as2-from'))
            message = None

            # Check if this is an MDN message
            mdn_message = None
            if payload.get_content_type() == 'multipart/report':
                mdn_message = payload
            elif payload.get_content_type() == 'multipart/signed':
                for part in payload.walk():
                    if part.get_content_type() == 'multipart/report':
                        mdn_message = part

            # If this is an MDN, get the message ID and check if it exists
            if mdn_message:
                msg_id = None

                for part in mdn_message.walk():
                    if part.get_content_type() == 'message/disposition-notification':
                        msg_id = part.get_payload().pop().get('Original-Message-ID')
                pyas2init.logger.info('Asynchronous MDN received for AS2 message %s to organization %s '
                                      'from partner %s' % (msg_id, message_org, message_partner))
                try:
                    # Get the related organization, partner and message from the db.
                    org = get_object_or_404(models.Organization, as2_name=message_org)
                    partner = get_object_or_404(models.Partner, as2_name=message_partner)
                    message = get_object_or_404(models.Message, message_id=msg_id.strip('<>'), organization=org, partner=partner)
                    models.Log.objects.create(message=message,
                                              status='S',
                                              text=_(u'Processing asynchronous mdn received from partner'))
                    as2lib.save_mdn(message, raw_payload)

                except Http404:
                    # Send 404 response
                    pyas2init.logger.error('Unknown Asynchronous MDN AS2 message %s. '
                                           'Either the partner, org or message was not found in the system' % msg_id)
                    return HttpResponseServerError(_(u'Unknown AS2 MDN received. Will not be processed'))

                except Exception, e:
                    message.status = 'E'
                    models.Log.objects.create(message=message,
                                              status='E',
                                              text=_(u'Failed to send message, error is %s' % e))

                    # Send mail here
                    as2utils.senderrorreport(message, _(u'Failed to send message, error is %s' % e))

                finally:
                    # Save message and send response to HTTP request
                    if message:
                        message.save()
                    return HttpResponse(_(u'AS2 ASYNC MDN has been received'))

            else:
                try:
                    # Process the received AS2 message from partner
                    # Initialize the processing status variables
                    status, adv_status, status_message = '', '', ''

                    pyas2init.logger.info('Received an AS2 message with id %s for organization %s from partner %s' %
                                          (payload.get('message-id'), message_org, message_partner))

                    # Raise duplicate message error in case message already exists in the system
                    # TODO: Create composite key (message_id, organization, partner)
                    if models.Message.objects.filter(message_id=payload.get('message-id').strip('<>')).exists():
                        message = models.Message.objects.create(
                            message_id='%s_%s' % (payload.get('message-id').strip('<>'), payload.get('date')),
                            direction='IN',
                            status='IP',
                            headers=as2headers
                        )
                        raise as2utils.As2DuplicateDocument(_(u'An identical message has already '
                                                              u'been sent to our server'))

                    # Create a new message in the system
                    message = models.Message.objects.create(
                        message_id=payload.get('message-id').strip('<>'),
                        direction='IN',
                        status='IP',
                        headers=as2headers)

                    # Process the received payload to extract the actual message from partner
                    payload = as2lib.save_message(message, payload, raw_payload)

                    # Get the inbox folder for this partner and organization
                    output_dir = as2utils.join(pyas2init.gsettings['root_dir'],
                                               'messages',
                                               message.organization.as2_name,
                                               'inbox',
                                               message.partner.as2_name)

                    # Get the filename from the header and if not there set to message id
                    if message.partner.keep_filename and payload.get_filename():
                        filename = payload.get_filename()
                    else:
                        filename = '%s.msg' % message.message_id

                    # Save the message content to the store and inbox
                    content = payload.get_payload(decode=True)
                    full_filename = as2utils.storefile(output_dir, filename, content, False)
                    store_filename = as2utils.storefile(pyas2init.gsettings['payload_receive_store'],
                                                        message.message_id,
                                                        content,
                                                        True)

                    models.Log.objects.create(message=message,
                                              status='S',
                                              text=_(u'Message has been saved successfully to %s' % full_filename))
                    message.payload = models.Payload.objects.create(name=filename,
                                                                    file=store_filename,
                                                                    content_type=payload.get_content_type())

                    # Set processing status and run the post receive command.
                    status = 'success'
                    as2lib.run_post_receive(message, full_filename)
                    message.save()

                # Catch each of the possible exceptions while processing an as2 message
                except as2utils.As2DuplicateDocument, e:
                    status = 'warning'
                    adv_status = 'duplicate-document'
                    status_message = _(u'An error occurred during the AS2 message processing: %s' % e)

                except as2utils.As2PartnerNotFound, e:
                    status = 'error'
                    adv_status = 'unknown-trading-partner'
                    status_message = _(u'An error occurred during the AS2 message processing: %s' % e)
Esempio n. 15
0
 def handle(self, *args, **options):
     pyas2init.logger.info(_(u'Starting PYAS2 send daemon.'))
     try:
         engine_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         engine_socket.bind(('127.0.0.1', pyas2init.gsettings['daemon_port']))
     except socket.error:
         engine_socket.close()
         raise CommandError(_(u'An instance of the send daemon is already running'))
     else:
         atexit.register(engine_socket.close)
     cond = threading.Condition()
     tasks = set()   
     dir_watch_data = []
     orgs = models.Organization.objects.all()
     partners = models.Partner.objects.all()
     python_executable_path = pyas2init.gsettings['python_path']
     managepy_path = pyas2init.gsettings['managepy_path'] ##as2utils.join(os.path.dirname(os.path.dirname(__file__)), 'manage.py')
     for partner in partners:
         for org in orgs:
             dir_watch_data.append({})
             dir_watch_data[-1]['path'] = as2utils.join(pyas2init.gsettings['root_dir'], 'messages', partner.as2_name, 'outbox', org.as2_name)
             dir_watch_data[-1]['organization'] = org.as2_name
             dir_watch_data[-1]['partner'] = partner.as2_name
     if not dir_watch_data:
         pyas2init.logger.error(_(u'No partners have been configured!'))
         sys.exit(0)
     pyas2init.logger.info(_(u'Process exisitng files in the directory.'))
     for dir_watch in dir_watch_data:
         files =  [f for f in os.listdir(dir_watch['path']) if os.path.isfile(as2utils.join(dir_watch['path'],f))]
         for file in files:
             lijst = [python_executable_path,managepy_path,'sendas2message','--delete',dir_watch['organization'],dir_watch['partner'],as2utils.join(dir_watch['path'],file)]
             pyas2init.logger.info(u'Send as2 message with params "%(task)s".',{'task':lijst})
             subprocess.Popen(lijst)
     if os.name == 'nt':
         #for windows: start a thread per directory watcher
         for dir_watch in dir_watch_data:
             dir_watch_thread = threading.Thread(target=windows_event_handler, args=(pyas2init.logger,dir_watch,cond,tasks))
             dir_watch_thread.daemon = True  #do not wait for thread when exiting
             dir_watch_thread.start()
     else:
         #for linux: one watch-thread, but multiple watches. 
         dir_watch_thread = threading.Thread(target=linux_event_handler, args=(pyas2init.logger,dir_watch_data,cond,tasks))
         dir_watch_thread.daemon = True  #do not wait for thread when exiting
         dir_watch_thread.start()
     # this main thread get the results from the watch-thread(s).
     pyas2init.logger.info(_(u'PYAS2 send daemon started started.'))
     active_receiving = False
     timeout = 2.0
     cond.acquire()
     while True:
         #this functions as a buffer: all events go into set tasks.
         #the tasks are fired to jobqueue after TIMOUT sec.
         #this is to avoid firing to many tasks to jobqueue; events typically come in bursts.
         #is value of timeout is larger, reaction times are slower...but less tasks are fired to jobqueue.
         #in itself this is not a problem, as jobqueue will alos discard duplicate jobs.
         #2 sec seems to e a good value: reasonable quick, not to nervous. 
         cond.wait(timeout=timeout)    #get back when results, or after timeout sec
         if tasks:
             if not active_receiving:    #first request (after tasks have been  fired, or startup of dirmonitor)
                 active_receiving = True
                 last_time = time.time()
             else:     #active receiving events
                 current_time = time.time()
                 if current_time - last_time >= timeout:
                     try:
                         for task in tasks:
                             lijst = [python_executable_path,managepy_path,'sendas2message','--delete',task[0],task[1],task[2]]
                             pyas2init.logger.info(u'Send as2 message with params "%(task)s".',{'task':lijst})
                             subprocess.Popen(lijst) 
                     except Exception as msg:
                         pyas2init.logger.info(u'Error in running task: "%(msg)s".',{'msg':msg})
                     tasks.clear()
                     active_receiving = False
                 else:
                     pyas2init.logger.debug(u'time difference to small.')
                     last_time = current_time
     cond.release()
     sys.exit(0)
Esempio n. 16
0
def as2receive(request,*args,**kwargs):
    ''' 
       Function receives requests from partners.  
       Checks whether its an AS2 message or an MDN and acts accordingly.
    '''
    if request.method == 'POST':
        as2payload = ''
        for key in request.META:
            if key.startswith('HTTP') or key.startswith('CONTENT'):
                as2payload = as2payload + '%s: %s\n'%(key.replace("HTTP_","").replace("_","-").lower(), request.META[key])
        as2headers = as2payload
        as2payload = as2payload + '\n' + request.read()
        pyas2init.logger.debug('Recevied an HTTP POST from %s with payload :\n%s'%(request.META['REMOTE_ADDR'],as2payload))
        try:
            pyas2init.logger.debug('Check payload to see if its an AS2 Message or ASYNC MDN.')
            payload = email.message_from_string(as2payload)
            mdn_message = None 
            if payload.get_content_type() == 'multipart/report':
                mdn_message = payload
            elif payload.get_content_type() == 'multipart/signed':
                for part in payload.walk():
                    if part.get_content_type() == 'multipart/report':
                        mdn_message = part
            if mdn_message:
                for part in mdn_message.walk():
                    if (part.get_content_type() == 'message/disposition-notification'):
                        msg_id = part.get_payload().pop().get('Original-Message-ID')
                pyas2init.logger.debug('Received MDN for AS2 message %s'%msg_id)
                message = models.Message.objects.get(message_id=msg_id.strip('<>'))
                models.Log.objects.create(message=message, status='S', text=_(u'Processing asynchronous mdn received from partner'))
                try:
                    as2lib.save_mdn(message, as2payload)
                except Exception,e:
                    message.status = 'E'
                    models.Log.objects.create(message=message, status='E', text=_(u'Failed to send message, error is %s' %e))		
                    #### Send mail here
                    as2utils.senderrorreport(message,_(u'Failed to send message, error is %s' %e))
                finally:
                    message.save()    
                    return HttpResponse(_(u'AS2 ASYNC MDN has been received'))
            else:
                try:
                    pyas2init.logger.debug('Received an AS2 message with id %s'%payload.get('message-id'))
                    if  models.Message.objects.filter(message_id=payload.get('message-id').strip('<>')).exists():
                        message = models.Message.objects.create(message_id='%s_%s'%(payload.get('message-id').strip('<>'),payload.get('date')),direction='IN', status='IP', headers=as2headers)
                        raise as2utils.as2duplicatedocument(_(u'An identical message has already been sent to our server'))
                    message = models.Message.objects.create(message_id=payload.get('message-id').strip('<>'),direction='IN', status='IP', headers=as2headers)	
                    payload = as2lib.save_message(message, as2payload)
                    outputdir = as2utils.join(pyas2init.gsettings['root_dir'], 'messages', message.organization.as2_name, 'inbox', message.partner.as2_name)
                    storedir = pyas2init.gsettings['payload_receive_store'] 
                    if message.partner.keep_filename and payload.get_filename():
                        filename = payload.get_filename()
                    else:
                        filename = '%s.msg' %message.message_id
                    content = payload.get_payload(decode=True)
                    fullfilename = as2utils.storefile(outputdir,filename,content,False)
                    storefilename = as2utils.storefile(pyas2init.gsettings['payload_receive_store'],message.message_id,content,True)
                    models.Log.objects.create(message=message, status='S', text=_(u'Message has been saved successfully to %s'%fullfilename))
                    message.payload = models.Payload.objects.create(name=filename, file=storefilename, content_type=payload.get_content_type())
                    status, adv_status, status_message = 'success', '', ''
                    as2lib.run_postreceive(message,fullfilename)
                    message.save()
                except as2utils.as2duplicatedocument,e:
                    status, adv_status, status_message = 'warning', 'duplicate-document', _(u'An error occured during the AS2 message processing: %s'%e)
                except as2utils.as2partnernotfound,e:
                    status, adv_status, status_message = 'error', 'unknown-trading-partner', _(u'An error occured during the AS2 message processing: %s'%e)