1010
1111Uses the common mail iteration method from the lib file.
1212"""
13+ from functools import cache , cached_property
1314import re
15+
1416from intelmq .lib .utils import unzip
15- from intelmq .lib .exceptions import InvalidArgument
17+ from intelmq .lib .exceptions import InvalidArgument , MissingDependencyError
1618
1719from ._lib import MailCollectorBot
1820
1921
2022class MailAttachCollectorBot (MailCollectorBot ):
2123 """Monitor IMAP mailboxes and retrieve mail attachments"""
24+
2225 attach_regex : str = "csv.zip"
2326 extract_files : bool = True
2427 folder : str = "INBOX"
@@ -28,11 +31,19 @@ class MailAttachCollectorBot(MailCollectorBot):
2831 mail_user : str = "<user>"
2932 rate_limit : int = 60
3033 subject_regex : str = "<subject>"
34+ decrypt : bool = False
35+ """ Decrypt the attachment with GPG """
36+
37+ gpg_passphrase : str = ""
38+ """ The private key passhrase """
39+
40+ gpg_home : str = ""
41+ """ Change the GPG home directory """
3142
3243 def init (self ):
3344 super ().init ()
3445 if self .attach_regex is None :
35- raise InvalidArgument (' attach_regex' , expected = ' string' )
46+ raise InvalidArgument (" attach_regex" , expected = " string" )
3647
3748 def process_message (self , uid , message ):
3849 seen = False
@@ -42,12 +53,14 @@ def process_message(self, uid, message):
4253 continue
4354
4455 try :
45- attach_filename = attach [' filename' ]
56+ attach_filename = attach [" filename" ]
4657 except KeyError :
4758 # https://github.com/certtools/intelmq/issues/1538
48- self .logger .debug (' Skipping attachment because of missing filename.' )
59+ self .logger .debug (" Skipping attachment because of missing filename." )
4960 continue
50- if attach_filename .startswith ('"' ): # for imbox versions older than 0.9.5, see also above
61+ if attach_filename .startswith (
62+ '"'
63+ ): # for imbox versions older than 0.9.5, see also above
5164 attach_filename = attach_filename [1 :- 1 ]
5265
5366 if re .search (self .attach_regex , attach_filename ):
@@ -57,18 +70,33 @@ def process_message(self, uid, message):
5770 report = self .new_report ()
5871
5972 if self .extract_files :
60- raw_reports = unzip (attach ['content' ].read (), self .extract_files ,
61- return_names = True , logger = self .logger )
73+ raw_reports = unzip (
74+ attach ["content" ].read (),
75+ self .extract_files ,
76+ return_names = True ,
77+ logger = self .logger ,
78+ )
6279 else :
63- raw_reports = ((attach_filename , attach [' content' ].read ()), )
80+ raw_reports = ((attach_filename , attach [" content" ].read ()),)
6481
6582 for file_name , raw_report in raw_reports :
83+ if self .decrypt :
84+ gpg = self ._gpg ().decrypt (
85+ raw_report , passphrase = self .gpg_passphrase
86+ )
87+ if gpg .ok :
88+ raw_report = gpg .data
89+ else :
90+ self .logger .error ('Could not decrypt attachment %s: %s.' , file_name , gpg .status )
91+ continue
6692 report = self .new_report ()
6793 report .add ("raw" , raw_report )
6894 if file_name :
6995 report .add ("extra.file_name" , file_name )
7096 report ["extra.email_subject" ] = message .subject
71- report ["extra.email_from" ] = ',' .join (x ['email' ] for x in message .sent_from )
97+ report ["extra.email_from" ] = "," .join (
98+ x ["email" ] for x in message .sent_from
99+ )
72100 report ["extra.email_message_id" ] = message .message_id
73101 report ["extra.email_date" ] = message .date
74102 self .send_message (report )
@@ -80,5 +108,13 @@ def process_message(self, uid, message):
80108 self .logger .info ("Email report read." )
81109 return seen
82110
111+ @cache
112+ def _gpg (self ):
113+ try :
114+ from gnupg import GPG
115+ except ImportError :
116+ raise MissingDependencyError ("python-gnupg" , ">=0.5" )
117+ return GPG (gnupghome = self .gpg_home )
118+
83119
84120BOT = MailAttachCollectorBot
0 commit comments