10 | | It might help a lot to look at [t:wiki:TracDev/Announcer internal structure and event flow] of AnnouncerPlugin in detail. |
11 | | By now I add the following into code of ./announcerplugin_trunk/announcer/distributors/mail.py from trunk of AnnouncerPlugin: |
| 9 | Imagine, you're using Trac in a corporate environment, typically allowing external access to Trac, repositories etc. only after authorization or not at all. |
| 10 | Still, you may wish to keep business partners, support customers, etc. informed about certain or all developments, and that involves sending potentially sensitive information outside the tightly controlled corporate network. Co-workers in a home office setup may create a similar demand. |
13 | | {{{ |
14 | | return msgid |
15 | | |
16 | | def _do_send(self, transport, event, format, recipients, formatter): |
17 | | output = formatter.format(transport, event.realm, format, event) |
18 | | + |
19 | | + email_encrypt = True |
20 | | + if email_encrypt: |
21 | | + output = encrypt_txt(output) |
22 | | + self.log.debug("EmailDistributor successfully encrypted msg.") |
23 | | + |
24 | | alternate_style = formatter.alternative_style_for( |
25 | | transport, |
26 | | event.realm, |
27 | | }}} |
| 12 | Signing emails will help recipients to be sure, that they got unaltered content and got it from you. Encrypting emails will help to distribute announcements to external recipients as freely as to recipients inside without concerns on discretion. |
35 | | ==== !AnnouncerEmailEncryption ==== |
36 | | Now let's look at how OpenPGP could help with Trac and especially with announcements. |
| 20 | == How (proposed implementation) == |
| 21 | It might help a lot to have a closer look at [t:wiki:TracDev/Announcer internal structure and event flow] of AnnouncerPlugin. Where to kick in is of course an essential decision. Since it's not only about mangle the message body (one of the earlier assumptions that all turned out to reach not far enough), there is not a single point but a bunch of changes needed to get cryptographic operations working. |
| 22 | |
| 23 | There are modifications required and code to be added to `announcer/distributors/mail.py`. A new file `announcer/util/mail_crypto` introduces a new class `CryptoTxt`, that provides the cryptographic operations. The approach is generic enough to be extended beyond OpenPGP, currently the only supported crypto standard and handled by GnuPG, to i.e. use X.509 certificates as well. |
38 | | Imagine, you're using trac in a corporate environment, typically allowing external access to trac, repositories etc. only after authorization or not at all. |
39 | | However you may wish to keep business partners, support customers or even co-workers outside the tightly controlled corporate network informed about certain or all developments. Encrypting mail for external recipients will help to deal with issues as discrete as you like while still using announcements for changes in trac. |
40 | | |
41 | | To get !AnnouncerEmailEncryption up and working you'll have to do take the following steps: |
| 25 | === !AnnouncerEmailEncryption === |
| 26 | To get !AnnouncerEmailEncryption up and working you'll have to take the following steps: |
43 | | For Debian GNU/Linux a simple {{{apt-get install gnupg}}} will do. |
44 | | 2. install python-gnupg |
45 | | Currently there is no Debian package available. Install from source of [http://code.google.com/p/python-gnupg/downloads/list project site] is preferred. |
46 | | 3. configure !AnnouncerEmailEncryption in the ![announcer] section of trac.ini for the given trac environment |
47 | | * gnupg_dir = <path_to_dir>, will default to something like {{{<tracenv>/gnupg}}}[[BR]] |
48 | | If not existent, this directory would be created and populated with necessary (initially empty) files on next trac start with !AnnouncerEmailEncryption enabled. |
49 | | * msg_encryption = False|True, default to "False" |
50 | | Pretty self-explaining. External would opt for splitting recipients according to following rules into group require_encryption_group and allow_verbatim_msg_group and sending an local, verbatim as well as an encrypted version in parallel, if both recipient lists are not empty. |
51 | | * external recipient_rule = (list of e-mail addresses or regex describing range of e-mail addresses) |
52 | | 4. import pubkeys and associate with users |
| 28 | For Debian GNU/Linux a simple |
| 29 | {{{ |
| 30 | apt-get install gnupg |
| 31 | }}} |
| 32 | will do. |
| 33 | 2. install `python-gnupg` |
| 34 | Currently there is no Debian package available. Install from source of [http://code.google.com/p/python-gnupg/downloads/list project site] is preferred. So we get a mature and actively maintained Python interface to GnuPG. |
| 35 | 3. configure !AnnouncerEmailEncryption in the !`[announcer]` section of `trac.ini` for the given Trac environment |
| 36 | |
| 37 | ||'''available option''' ||'''value''' ||'''default''' ||'''note''' || |
| 38 | ||rcpt_allow_regexp ||string ||`''` ||not strikly related to cryptography but a way to generally limit the possible scope for any announcement email ^1^|| |
| 39 | ||rcpt_local_regexp ||string ||`''` ||whitelist email addresses excluded from crypto operations ^2^|| |
| 40 | ||email_crypto ||'sign'|'encrypt'|'sign,encrypt' ||`''` ||crypto action selector || |
| 41 | ||gpg_binary ||<gpg_binary_name> ||`'gpg'` ||name, full path prepended optionally to allow for use of custom GnuPG installations in unusual locations or switch between several GnuPG versions installed || |
| 42 | ||gpg_home ||<full_path_to_keyring_file_store> ||`''` ||something like `<full_path_to_tracenv>/gnupg` ^3^|| |
| 43 | ||gpg_signing_key ||OpenPGP key by ID or fingerprint ||`None` ||key selector to set one of several available keys for signing operation || |
| 44 | ^1^ e-mail address(es) or valid Python regex describing range of e-mail addresses[[BR]] |
| 45 | ^2^ string or regex like before, to sort matching recipients, sending verbatim announcement in parallel with an encrypted version, if both resulting recipient lists are not empty[[BR]] |
| 46 | ^3^ if not existent, directory will be created and populated with necessary (initially empty) files on next announcement with !AnnouncerEmailEncryption enabled |
| 47 | |
| 48 | 4. import public keys and optionally associate with users |
64 | | 5. add an automatic signing key for the given trac environment (optional) |
65 | | * upload from local pubkey(ring) file or create it on-demand |
66 | | * use secret key, if only one is available, else provide a drop-down or similar for selection |
| 60 | 5. add an automatic signing key for the given Trac environment (optional) |
| 61 | * upload from local secret key(ring) file or create it on-demand |
| 62 | * just use (only/last added) secret key, provide a drop-down or similar for selection, if more than one is available |
117 | | ==== The code ==== |
| 116 | === Q&A === |
| 117 | [FIXME: add more Q+A here to help with code design evaluation and code review] |
| 118 | ?: Why not implement encryption as another IAnnouncementEmailDecorator |
| 119 | A: Decorators are called without guaranteed order. Encryption needs control, that it'll be the last message body mangling action. |
| 120 | ''We can change this pretty easily'' - '''doki_pen''' |
| 121 | ?: Why not implement encryption as another IAnnouncementFormatter |
| 122 | A: Encryption is not about encoding etc. |
| 123 | ''Formatter is more about turning an event into a message, it shouldn't be done here.'' - '''doki_pen''' |
| 124 | ? Doesn't smtplib or any other stock python library handle encryption? |
| 125 | A: No. Pythons smtplib is dedicated to e-mail construction including MIME, but no PGP/MIME etc. (see http://docs.python.org/library/smtplib.html). Pythons nativ [http://docs.python.org/library/crypto.html crypto utils] currently consist of secure hash and checksum generators (md5, sha). |
| 126 | ?: What are the explicitly handled exceptions? |
| 127 | A: For readability let's try to put this into a table. |
| 128 | |
| 129 | ||exception ||cause ||action/behavior || |
| 130 | ||missing pubkey ||fingerprint in user settings but no corresponding key in pubkeyring file ||delete recipient from recipient list of event in delivery, create new event with info "specified pubkey not in Tracs keyring" to be sent to this user and project admin || |
| 131 | |
| 132 | ?: Does python-gnupg support GnuPG v2? |
| 133 | A: AFAIK yes, both versions support same CLI syntax. I'll continue to test with both versions in the future to maintain compatibility. There might be even a bonus from using GnuPG v2, since it is announced to be PGP/MIME aware. However I'll still have to look into this in detail. |
| 134 | |
| 135 | === Development traces (history) === |
| 136 | This is kept for reference and personal attitude to preserve historical notes. |
141 | | hints, recommendations? known-good code references or popular applications? |
142 | | |
143 | | ==== Q&A ==== |
144 | | [FIXME: add more Q+A here to help with code design evaluation and code review] |
145 | | ?: Why not implement encryption as another IAnnouncementEmailDecorator |
146 | | A: Decorators are called without guaranteed order. Encryption needs control, that it'll be the last message body mangling action. |
147 | | ''We can change this pretty easily'' - '''doki_pen''' |
148 | | ?: Why not implement encryption as another IAnnouncementFormatter |
149 | | A: Encryption is not about encoding etc. |
150 | | ''Formatter is more about turning an event into a message, it shouldn't be done here.'' - '''doki_pen''' |
151 | | ? Doesn't smtplib or any other stock python library handle encryption? |
152 | | A: No. Pythons smtplib is dedicated to e-mail construction including MIME, but no PGP/MIME etc. (see http://docs.python.org/library/smtplib.html). Pythons nativ [http://docs.python.org/library/crypto.html crypto utils] currently consist of secure hash and checksum generators (md5, sha). |
153 | | ?: What are the explicitly handled exceptions? |
154 | | A: For readability let's try to put this into a table. |
155 | | |
156 | | ||exception ||cause ||action/behavior || |
157 | | ||missing pubkey ||fingerprint in user settings but no corresponding key in pubkeyring file ||delete recipient from recipient list of event in delivery, create new event with info "specified pubkey not in Tracs keyring" to be sent to this user and project admin || |
158 | | |
159 | | ?: Does python-gnupg support GnuPG v2? |
160 | | A: AFAIK yes, both versions support same CLI syntax. I'll continue to test with both versions in the future to maintain compatibility. There might be even a bonus from using GnuPG v2, since it is announced to be PGP/MIME aware. However I'll still have to look into this in detail. |
161 | | |
162 | | === Sources (for ideas and code) === |
| 160 | == Resources (for ideas and code) == |