tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
March 2015
- 23 participants
- 1889 discussions

[bridgedb/master] Remove libgpgme11-dev from install section of .travis.yml.
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit a524b4923a18d0e4668189f87c4705dc1a88cf16
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 23:23:24 2015 +0000
Remove libgpgme11-dev from install section of .travis.yml.
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 4bc10ad..19d0196 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -59,7 +59,7 @@ before_install:
- chmod -R og-w $PYTHON_EGG_CACHE
install:
- - sudo apt-get install -qq --no-install-suggests --no-install-recommends build-essential openssl sqlite3 libgpgme11 libgpgme11-dev python-dev python-setuptools libgeoip-dev geoip-database
+ - sudo apt-get install -qq --no-install-suggests --no-install-recommends build-essential openssl sqlite3 python-dev python-setuptools libgeoip-dev geoip-database
- pip install -q --no-use-wheel -r .travis.requirements.txt
- pip install -q --no-use-wheel Twisted==$TWISTED_VERSION pyOpenSSL==$PYOPENSSL_VERSION
- make install
1
0

[bridgedb/master] Move gnupghome/ to .gnupg/ and update public key files.
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit d911be06d5ad4fb68b4f8c626fee493ac6ebbc5d
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 10:08:38 2015 +0000
Move gnupghome/ to .gnupg/ and update public key files.
* MOVE gnupghome/TESTING.subkeys.sec → .gnupg/TESTING.subkeys.sec
* MOVE gnupghome/bridgedb-offline-key.pub.asc → .gnupg/bridgedb-offline-key.pub.asc
* MOVE gnupghome/bridgedb-online-signing-key.pub.asc → .gnupg/bridgedb-online-key.pub.asc
* MOVE gnupghome/gpg.conf → .gnupg/gpg.conf
* REMOVE gnupghome/TESTING.subkeys.sec.EXPIRED-2013-09-11
* ADD .gnupg/TESTING.pub file, which contains the public keys
corresponding to the private subkeys in the
.gnupg.TESTING.subkeys.sec file.
* UPDATE OpenPGP public key DF811109E17C8BF134B5EEB68DC43A2848821E32 in
.gnupg/bridgedb-online-key.pub.asc with the version with the new
expiration date (2015-09-11).
* ADD keyring files .gnupg/pubring.gpg and .gnupg/secring.gpg which
contain the keys in the TESTING.pub and TESTING.subkeys.sec files.
* REMOVE the gnupghome/ directory from .gitignore.
---
.gitignore | 3 -
.gnupg/TESTING.pub | Bin 0 -> 4622 bytes
.gnupg/TESTING.subkeys.sec | Bin 0 -> 7212 bytes
.gnupg/bridgedb-offline-key.pub.asc | 113 +++++++++++++++++
.gnupg/bridgedb-online-key.pub.asc | 100 +++++++++++++++
.gnupg/gpg.conf | 96 ++++++++++++++
.gnupg/pubring.gpg | Bin 0 -> 4634 bytes
.gnupg/secring.gpg | Bin 0 -> 7224 bytes
gnupghome/TESTING.subkeys.sec | Bin 7212 -> 0 bytes
gnupghome/TESTING.subkeys.sec.EXPIRED-2013-09-11 | Bin 6505 -> 0 bytes
gnupghome/bridgedb-offline-key.pub.asc | 113 -----------------
gnupghome/bridgedb-online-signing-key.pub.asc | 148 ----------------------
gnupghome/gpg.conf | 96 --------------
13 files changed, 309 insertions(+), 360 deletions(-)
diff --git a/.gitignore b/.gitignore
index 61d4b0a..f208f3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -85,9 +85,6 @@ run/*
# (the "supported" variable is supposed to be rewritten at install time)
lib/bridgedb/_langs.py
-# ignore any changes to our GnuPG directory:
-gnupghome/*
-
# ignore persistent state files
*bridgedb.state*
diff --git a/.gnupg/TESTING.pub b/.gnupg/TESTING.pub
new file mode 100644
index 0000000..764bf47
Binary files /dev/null and b/.gnupg/TESTING.pub differ
diff --git a/.gnupg/TESTING.subkeys.sec b/.gnupg/TESTING.subkeys.sec
new file mode 100644
index 0000000..688f7e9
Binary files /dev/null and b/.gnupg/TESTING.subkeys.sec differ
diff --git a/.gnupg/bridgedb-offline-key.pub.asc b/.gnupg/bridgedb-offline-key.pub.asc
new file mode 100644
index 0000000..47d1310
--- /dev/null
+++ b/.gnupg/bridgedb-offline-key.pub.asc
@@ -0,0 +1,113 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+ILUXBkpIDfVSoZD7qWlntai53BDQr5pfMJhv15di4XAhtqv43vAmA57ifd+QJS2U
+AfYc4CdX0lk2BZ4jRD8jCZ4Uxw15E3RqhnXsWDRxtD4fwsb2ZFi0DDuPlwBdGgh5
+Rm2Bz9JjSV6gDEuXr/JtAzjSz1Jdh8wPkSofiHGTfxysVhlGlg+YPRziRlzML8A2
+0xY+9mPxEEin5ZQ9wmrDyiiOBvPTbG3O9+Sp5VZDuD4ivW/DHumPWGVSRdjcAQDe
+HMXUVGjhBDnj06XNrgJPhODdJeYq0EnGTt15ofZQSswD7TTTRPDOn0Cz/QARAQAB
+tDpCcmlkZ2VEQiAoT2ZmbGluZSBJRCBLZXkpIDxicmlkZ2VzQGJyaWRnZXMudG9y
+cHJvamVjdC5vcmc+iQkfBBMBCgEJBQJSWQfkSBSAAAAAABcAKHZlcmlmaWVkQHRv
+cnByb2plY3Qub3JnN0I3ODQzNzAxNUU2M0RGNDdCQjEyNzBBQ0JEOTdBQTI0RThF
+NDcyRU8UgAAAAAAeAChicmlkZ2VzQGJyaWRnZXMudG9ycHJvamVjdC5vcmc3Qjc4
+NDM3MDE1RTYzREY0N0JCMTI3MEFDQkQ5N0FBMjRFOEU0NzJFKhpodHRwczovL2Jy
+aWRnZXMudG9ycHJvamVjdC5vcmcvcG9saWN5LnR4dAIbAQMLDQkEFQoJCAQWAgEA
+Ah4BAheAJxhodHRwczovL2JyaWRnZXMudG9ycHJvamVjdC5vcmcva2V5LmFzYwAK
+CRDL2XqiTo5HLoqEP/48rFpJCVStn8xo+KkHSVvsqpxDRlb/nNheI+ov2UxILdwl
+NIU6kLsvKECKPe1AHKdS/MzANbkTF35Y4QgZsNpVXaCVL7adGBSzOdPFupDJJVOu
+wa+uFRc/FuNJyH/TIn56/+R5J5C54OxIYNxvW3WF4eHKLJYk/JZOMMfy4iWm7Sql
+0nDC5O435nK4F4Jb4GLPlUIzioIy2OWqGoFHXymbGhL1tWaqasYmED4n3AMqlYw6
+xnNhdWOc/KZelPl9nanybyh0IIdZqUKZleRt4BxSgIT8FqC2sZuZ8z7O9s987Naz
+Q32SKaP4i2M9lai/Y2QYfKo+wlG+egmxtujz7etQMGlpgBZzFLdJ8/w4U11ku1ai
+om74RIn8zl/LHjMQHnCKGoVlscTI1ZPt+p+p8hO2/9vOwTR8y8O/3DQSOfTSipwc
+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
+YnJpZGdlc0BicmlkZ2VzLnRvcnByb2plY3Qub3JnREY4MTExMDlFMTdDOEJGMTM0
+QjVFRUI2OERDNDNBMjg0ODgyMUUzMioaaHR0cHM6Ly9icmlkZ2VzLnRvcnByb2pl
+Y3Qub3JnL3BvbGljeS50eHQACgkQjcQ6KEiCHjIaqBAA0BuEs7horx6iCq4cjAhv
+YPLrxuC4fKEfVyhAjCJMJSFFCPAlGgU+BjyPNDD57wzKAmUkdJG+Ss25mwWXa53w
+5R2kDqDnHocOdZGtxZ7zx/uUd2eWLNBfVuK7nHOk1d1Hs0OZBnckc+MCqnLtuYe5
+68pa9+jW6cNIjAnzMIListmoXWgYYWJvMKeBMG4DGtYJ8w7CJQjOHc5yar12DrX3
+wnQ7hXtFuuqQblpEUnLnZGvHf2NKMZfBBMcP96h9OmLGNa+vmNYsMyPKU7n5hPgX
+nTgmQ4xrv1G7JukjppZRA8SFoxupcaQeTixyWERGBhBiAbwZsbQz8L/TVZKierzg
+sdNngHcFzE8MyjuJDvTos7qXPmgSRXFqJLRn0ZxpR5V1V8BVZUqCGuSZT89TizsD
+z5vyv8c9r7HKD4pRjw32P2dgcEqyGRkqERAgSuFpObP+juty+kxYyfnadBNCyjgP
+s7u0GmsTt4CZi7BbowNRL6bynrwrmQI9LJI1bPhgqfdDUbqG3HXwHz80oRFfKou8
+JTYKxK4Iumfw2l/uAACma5ZyrwIDBX/H5XEQqch4sORzQnuhlTmZRf6ldVIIWjdJ
+ef+DpOt12s+cS2F4D5g8G6t9CprCLYyrXiHwM/U8N5ywL9IeYKSWJxa7si3l9A6o
+ZxOds8F/UJYDSIB97MQFzBo=
+=JdC7
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/.gnupg/bridgedb-online-key.pub.asc b/.gnupg/bridgedb-online-key.pub.asc
new file mode 100644
index 0000000..a848a2b
--- /dev/null
+++ b/.gnupg/bridgedb-online-key.pub.asc
@@ -0,0 +1,100 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBFIv8YABEADRqvfLB4xWj3Fz+HEmUUt/qbJnZhqIjo5WBHaBJOmrzx1c9fLN
+aYG36Hgo6A7NygI1oQmFnDinSrZAtrPaT63d1Jg49yZwr/OhMaxHYJElMFHGJ876
+kLZHmQTysquYKDHhv+fH51t7UVaZ9NkP5cI+V3pqck0DW5DwMsVJXNaU317kk9me
+mPJUDMb5FM4d2Vtk1N+54bHJgpgmnukNtpJmRyHRbZBqNMln5nWF7vdZ4u5PGPWj
+bA0rPZhayeE3FQ0MHiGL12kHAy30pfg54QfPJDQBCywjABetRE+xaM9TcS+R31Pf
+2VbLeb+Km7QpHMwOXI5xZLss9BAWm9EBbmXxuqaRBHyi830jjCrK9UYuzzOqKoUV
+Mk1BRelZTFnGPWeVTE+Ps+pwJ0Dwx4ghppJBCoArmEbkNliblxR/2wYOOFi/ZVA4
+Zc2ok9T3rBLVg07b7ezFUScGiTnc7ac7hp6r8Qsh09ZbhRr9erK/n194aEvkXTfr
+qepwrAE7YeF4YuR206UOFFWDhxWDLbRu0gIWgrevEQu/cvQPrO9uH5fL6Gw/+mNP
+Q/NIteejhkDyvyTUKyBu7x+Gls71zT2u/X13eOAJ8IxBkSVRKQ8tRD+oqJkWplOf
++BpaGU+g6u4kT2AzFDxTOupfrYcPvORTAV/V3suys2YQE4x422GASXDivQARAQAB
+tClCcmlkZ2VEQiA8YnJpZGdlc0BicmlkZ2VzLnRvcnByb2plY3Qub3JnPokDJQQT
+AQoBD0gUgAAAAAAXACh2ZXJpZmllZEB0b3Jwcm9qZWN0Lm9yZ0RGODExMTA5RTE3
+QzhCRjEzNEI1RUVCNjhEQzQzQTI4NDg4MjFFMzJPFIAAAAAAHgAoYnJpZGdlc0Bi
+cmlkZ2VzLnRvcnByb2plY3Qub3JnREY4MTExMDlFMTdDOEJGMTM0QjVFRUI2OERD
+NDNBMjg0ODgyMUUzMioaaHR0cHM6Ly9icmlkZ2VzLnRvcnByb2plY3Qub3JnL3Bv
+bGljeS50eHQCGwEDCw0JBBUKCQgEFgIBAAIeAQIXgCcYaHR0cHM6Ly9icmlkZ2Vz
+LnRvcnByb2plY3Qub3JnL2tleS5hc2MFAlSKBKIFCQPDTiIACgkQjcQ6KEiCHjIs
+jg//bJ12eRnBMfIGzOGh+T4wz7/YyKLfARAMnqDnSxhTxuE+M5hWm3QbxP03R6eY
+x+PKwQaDJSmm7HhRhltb7QXUe8dqjnocFwwagpoLZ/81mBLxByqg5TKHGGIGy+DX
+omIzCq5ijx1IUkHlgh708a5alG7bjRTqedT4Wxxyl6psGzDhGQdS8bqx/f32nQaE
+h41l+A/EY1g2HVqky63ZHAP3S2v+mWCrk5DnkElc0229MXqaBuEr4nbYMXRkahMb
+E2gnCmdSoeD21AY6bNyz7IcJGpyKCx9+hVgPjpm3J23JEYyPL+s48jn6QcI/Q2gD
+yAtgU65y6IrdYn8SwkABI1FIq9WAwG7DaInxvkqkYqyBQLaZJEMyX8NTBvFoT5JS
+jnkxG0xu61Vxq0BLYBIOJE0VFHAJ40/jOvSxQJkQhu9G4BK7htnADbtstmMDMM3q
+xuuO5pcj2rl7YthNunyZ1yhPHXijUUyKrwR9piENpptztFBVN6+ijqU/TmWMOtbH
+X7p9F+3tXCHHqwO5U/JMtsb/9M39MR8BrdcLc7m6dCpeuSUuR2LLroh+MoMJGviI
+iesxHF95kFqkJAecW1Z3eKL9vrlbfO3waeuCi18k1TePnZuG5lmf2KjKDW5vHK4O
+WFqvvfK2kxkCUjvGdLeTOAVOV+X+PQ23jvBJO2bS7YbOb9C5Ag0EUi/ygQEQALZ/
+p7xRINHY7MMf3/bo/I0WRxWHd1AE9tRToyEg1S2u1YrWWL5M9D8saRsp9cpnpGEu
+hW3vu7G4nasY27qOz4bSKu1YMAVIC58v1tEnBqdo1zErNjhs38PrmJKbbs9tDfYY
+Oi2x0GlhMbIrNStcZpnCdLa6U6NLMbggDL1GxjMPYBMi4TtLgcIeRDUSjsZscZkg
+Kxs5QkSVc3SrYyraayIc8WtIpDLcxPt6/g90rbatZzBfO+93Rz7qUXHmgzuM0hy1
+Fvn619o3I5DsWrfOz9t/QuznoOBw4PfzDPNT7VlzZN4xHAcr5+7B+DH9IsvlCt5N
+kQFuYpFZCpXNaD2XOtmIqjTCeLNfcgTEj0qoUIEKyKbBIgfP+7S2tLXy8JKUTy5g
+9kxXQeHueLykQ4Mt18JH0nMHbHbQl0K3LGT4ucRDOmjNtlQCltVLkIk3GimyqKs/
+vdZ9c+dm4Akx1qsJcwvveX+imJe2e9RUodcxWXxWrYnuPa5b5nfR1i+GfV0on/Pt
+AQ8gc9CkJpMiq5TQDOFhFP6yQcq77sXuUkEl5qamptedz28E0I693ulnfwcsE80p
+xkpIG6n33DZJSEyqgtWjE1P2pnsVfO5ILs3mKLe7bO1v3qMXcCkMCGH/kwzvtowq
+YvY4gaZMDZtQFY8U7lI9FdRUvVdeHAB24y291nhzABEBAAGJBYMEGAEKANNIFIAA
+AAAAFwAodmVyaWZpZWRAdG9ycHJvamVjdC5vcmdERjgxMTEwOUUxN0M4QkYxMzRC
+NUVFQjY4REM0M0EyODQ4ODIxRTMyTxSAAAAAAB4AKGJyaWRnZXNAYnJpZGdlcy50
+b3Jwcm9qZWN0Lm9yZ0RGODExMTA5RTE3QzhCRjEzNEI1RUVCNjhEQzQzQTI4NDg4
+MjFFMzIqGmh0dHBzOi8vYnJpZGdlcy50b3Jwcm9qZWN0Lm9yZy9wb2xpY3kudHh0
+AhsCBQJUigTTBQkDw01SAqTB2CAEGQEKAIEFAlIv8oFPFIAAAAAAHgAoYnJpZGdl
+c0BicmlkZ2VzLnRvcnByb2plY3Qub3JnOUZFMzlEMUE3NDM4OTIyMzNCM0Y2NkYy
+MjFCNTU0RTk1OTM4RjREMCoaaHR0cHM6Ly9icmlkZ2VzLnRvcnByb2plY3Qub3Jn
+L3BvbGljeS50eHQACgkQIbVU6Vk49NDbPw/5ATe/T8+eaToC3v0TYNRH5nveQvzA
+WdnshD3lnvfsgDhbilwifKpc5LHKXU3rvb42HH2cu0ckuksdDTvICZD9cJjRq/F+
+Mzm0pNCAJg0pQnHaaWFQjw+CHYEoizai3S+iYxhNHeSdA6Ty7xm4+bHNf0Aqblbd
+6dKwq9EvjwAI6zZsAHtsmHRUMdrFwGdKae6CSchUT2JQFBPEWMhvzdpDGACWVaSP
+sxYKuYg9LgpswGcof+tprRjKRl8MtSh0ufjbVBlTeSKpL5Y+fcTRD3PI8w7Ocr3z
+jr6XpYG4SUNHsWwxyu/DTXg76Lk1/+BdaH25hDOAasLUOU7yRL8zD/c7M0FkGXdj
+r5I2DEEqwzJ9cPHWjpgb8N9fZLoPFP9JOmKGHINqxNe7TfwiTdD6uDKs/u/QK1U+
+o3iYBXBTREdopPUdBTM9wYRUhyGXTEKLhUP3MGpXYlgeYPrSdp76VyN3BzLTbMv+
++7rxyKxL9cWYU0pnXHgPC5nyHX5nqXmhMnkxAD3Bnm8n9XDfgiyTDExqksEh2VXt
+yhVfLezylEP2fwtd8/mABBCsTjzZW6FRfRRAjUZWZGFpFg8no1x5JS9uiswRP5g1
+qHijNFWpGyTtJWl5VNd0d9+LtVUX1jRpDUpsjZcxqs3fsvw2p+H/zQ1wFvDrsoav
+hqOTq+AEnJc7ZG8JEI3EOihIgh4ych8P/3GTyWb29+43YVibbSPPvEv4gFqziC+9
+1p92FJ0V4XdaT7TW3qaZVp5edUNwB/jjF0SxBybwaMX2ZIGXOjnjF6/Zby4ynuTX
+vZkS1mKRA0KWupB3e9PSMY3ZtssnqpGna/+3qlpxtunW7HcW4nCF/f59WHhlVjaO
+MXjtuWj59yB56Dd1sNjwhcNCyp4/NpzGnRW97ZV3Pp4oqIOqcGzCQXkVPcnaqcOh
+Cs9vIDJlMtn/IWBzUGimuRllDSSVSWkYkyJcG2NUHUwgXYpLwQz7sScvmCPchf4K
+qarpX0FpkUDfqaVVuQ7A2XbPUAVFzIk930G1WzgOuOdg9vhWSEjou+SKrAoMz90w
+3xHwEvmPDTTVJQft9ytoRbwZkIPfzzhII3mr4agbORAfzDaj5g/f6CVRdg6D3ME1
+Etg9ZrfLgRY993g/arfIME6OOsiNcy5+PunN96Rw0o1xoD+97NmZuQrs/p4Mfn5o
+8EwXHutREhahin+3/SV3hz9ReeLYmClq+OVhjPzPdtwZsFoyQyUJoFVHPTuSdChZ
+FPaqN68FjlNMugmxnvski3ZDVT7pw3B6otjjaL3rr6q0PC2yhEb2ntb3IFUizHjn
+80SmfE1Bqwit7ZHu8r/Gt/0iecGk5h84VzSgiGZGF/7m1i5UMVlNSeWnsInGa5Su
+7HSzfMq+YmkzuQINBFIv8p4BEADTOLR5e5NKKRPpjCb4B/8YYkWh+orb70EogIZ6
+j5v8d/djLyhjqZ9BIkh41/hYKMwnsa4KkDkTaX0eNu3BFB2zGgZ1GSd7525ESxiq
+suXIlAg2pex7bysaFfua0nUx64tmaQm2XArdkj/wI0pbg+idWym3WQQmZLyTTbzl
+8rpTEtTt+S2m6z3EeAhEHuNFH16hEDUywlef3EotX3njuFiLqaNvnzUYDxhUvKd2
+2K1es1ggispgP+eb1bkMApxecf2rqmSUEcvsuTWip4oGZPBLGDQeNKHkCUVbj4wT
+yWDIRtto3wi+4CFPEVzw+htj1cQfTstPqUdG7NSOmLQggedoUdv7AJm4MJJiyEax
+l+IAf6Afwrrm3eOSv0PgoUxOrUb9vhIoL8ih8gtiqvQ9qYaRQfQA/w3Z0Su2Yfoc
+fQS8Uw99qG+oTgieG6F6ud8+hMZAYVZFqbU+ztzMyDE6h4Hflkt6VNJ0Hk0VoF38
+TTs77pHXXBbLD6SzR6tbNuR9r/lbmC8Qf2A1ZAThR0iuGhNRFtUPo28GxakxGdLZ
+9kHIxjl7EN/gsmYTwuEhr+yfNtLwtSH0ojeqbDmgufvgh+SITCtyNDAUspjrZYEt
+F0NHRpSom2NFVELMqMRydU/ncph1rGZgVp6/zVj6xIlhKmqj5P1y/9B0c4Tu1CzJ
+pkJ5wwARAQABiQLpBBgBCgDTSBSAAAAAABcAKHZlcmlmaWVkQHRvcnByb2plY3Qu
+b3JnREY4MTExMDlFMTdDOEJGMTM0QjVFRUI2OERDNDNBMjg0ODgyMUUzMk8UgAAA
+AAAeAChicmlkZ2VzQGJyaWRnZXMudG9ycHJvamVjdC5vcmdERjgxMTEwOUUxN0M4
+QkYxMzRCNUVFQjY4REM0M0EyODQ4ODIxRTMyKhpodHRwczovL2JyaWRnZXMudG9y
+cHJvamVjdC5vcmcvcG9saWN5LnR4dAIbDAUCVIoE4QUJA8NNQwAKCRCNxDooSIIe
+Mo7JEADDBtQpYxPhbj3MT0xpk96EDlon/5yHVf+cnk1pNisc+HkJsVe1nh7gAWOz
+wJKdeqOVpgxiJTxIQdl6mipKwwFi0DreP7h56s1WQkuSSWJzqssAwWHfVAsX13fV
+zWd0XyxN/OF9ZKQjX4qwpJ/na631PSwZLvHYhMaZnb9pjNwC5/PEKRmFqLbQT6Px
+12miZT6ToPDCczHxJ4BxbEGVU+PtRsHwmTRT3JhxFNDfeVd+uwsQIMidJbUoqVW7
+fe2zNd0TaWyz4Rw087oZE2OXdctjvtsu8fzXx6d/tkazI6cUOqoaMTR41KEu5X0T
+BpWSAMADBYjNs9QRWXX7ZlsJRUSCX1EKbMhgoL6KIGceIkjH61M/LF6HqDgSgSWt
+h+LIYGa+LrB/6819o32QSOSHHJ5+NJrbCSaLgKE/LKnf92V2QbZE8IGY6EOSjHqn
+n1+j+CLRKY/kUyvk+1TumTghjg/aDs/8Jv8PvgSWLQ0q1rxHYbX7q9ZJhYC/4LdR
+ya/Cho6w2l0N3tV/IMAwvFNHsaiIiiwfoOQbkBUvkyzBwjKt96Ai4I0QKt/63uH0
+drQhlJEgIyGkOrorBByVqZAQdnoLENYIu6tDUj0bTbGObKqua4iPlSK3/g40zCm4
+9OgcN7A8kFuNpgp2EHqj1/jrwd7mZYKsWTuGiR/7fwXf+4xbvg==
+=raCx
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/.gnupg/gpg.conf b/.gnupg/gpg.conf
new file mode 100644
index 0000000..d4a9913
--- /dev/null
+++ b/.gnupg/gpg.conf
@@ -0,0 +1,96 @@
+##
+## Options for GnuPG
+##
+## :author: isis <isis(a)patternsinthevoid.net>
+
+no-greeting
+no-emit-version
+charset utf-8
+display-charset utf-8
+utf8-strings
+keyid-format long
+default-key 8DC43A2848821E32
+trusted-key CBD97AA24E8E472E
+
+# When outputting certificates, view user IDs distinctly from keys:
+fixed-list-mode
+
+verify-options no-show-photos show-uid-validity show-notations show-user-notations show-policy-urls show-keyserver-urls no-pka-lookups no-pka-trust-increase
+
+list-options no-show-photos show-uid-validity no-show-unusable-uids show-unusable-subkeys show-notations show-user-notations show-policy-urls show-keyserver-urls show-sig-expire show-sig-subpackets
+
+export-options no-export-attributes
+
+# Because some mailers change lines starting with "From " to ">From "
+# it is good to handle such lines in a special way when creating
+# cleartext signatures; all other PGP versions do it this way too.
+#no-escape-from-lines
+
+## Indymedia Keyservers:
+##----------------------
+keyserver hkps://2eghzlv2wwcq7u7y.onion
+keyserver hkp://2eghzlv2wwcq7u7y.onion
+keyserver hkps://keys.indymedia.org
+keyserver hkp://keys.indymedia.org
+keyserver https://keys.indymedia.org
+keyserver http://keys.indymedia.org
+keyserver https://qtt2yl5jocgrk7nu.onion
+keyserver http://qtt2yl5jocgrk7nu.onion
+keyserver-options ca-cert-file=~/scripts/certs/keys.indymedia.org
+
+## Normal keyservers:
+##--------------------
+keyserver hkp://subkeys.pgp.net
+keyserver mailto:pgp-public-keys@keys.pgp.net
+keyserver pgp.mit.edu
+
+keyserver-options verbose verbose verbose no-include-revoked no-include-disabled no-auto-key-retrieve no-honor-keyserver-url no-honor-pka-record include-subkeys no-include-attributes
+
+#keyserver-options http-proxy=socks://127.0.0.1:59050
+
+expert
+allow-freeform-uid
+cert-digest-algo SHA512
+digest-algo SHA512
+default-preference-list SHA512 SHA384 SHA256 CAMELLIA256 AES256 ZLIB ZIP Uncompressed
+personal-cipher-preferences CAMELLIA256 AES256
+personal-digest-preferences SHA512 SHA384 SHA256
+personal-compress-preferences ZLIB ZIP
+compress-level 9
+default-cert-expire 2y
+ask-cert-expire
+ask-cert-level
+default-sig-expire 1y
+no-ask-sig-expire
+
+## algorithm to protect the key in memory:
+s2k-cipher-algo AES256
+
+## use this one to mangle the passphrases:
+s2k-digest-algo SHA512
+
+## passphrase mangling mode:
+## 0=plaintest
+## 1=salt
+## 3=salt+iteration
+s2k-mode 3
+
+## how mangly should we mangle it? 1024 < mangle < 65011712
+##
+## try "python -c'import random;a=random.randint(32505856, 65011712);print a'
+s2k-count 48454407
+
+## Don't run if we can't secure mempages
+require-secmem
+
+## Check the back sig on subkey which has made a signature
+require-cross-certification
+
+## The notation on certifications we make:
+## see http://thread.gmane.org/gmane.mail.notmuch.general/3721/focus=7234
+sig-notation bridges(a)bridges.torproject.org=%g
+cert-notation bridges(a)bridges.torproject.org=%g
+cert-notation verified(a)torproject.org=%f
+set-policy-url https://bridges.torproject.org/policy.txt
+sig-keyserver-url !https://bridges.torproject.org/key.asc
+default-keyserver-url https://bridges.torproject.org/key.asc
diff --git a/.gnupg/pubring.gpg b/.gnupg/pubring.gpg
new file mode 100644
index 0000000..82c5477
Binary files /dev/null and b/.gnupg/pubring.gpg differ
diff --git a/.gnupg/secring.gpg b/.gnupg/secring.gpg
new file mode 100644
index 0000000..5e0fb5d
Binary files /dev/null and b/.gnupg/secring.gpg differ
diff --git a/gnupghome/TESTING.subkeys.sec b/gnupghome/TESTING.subkeys.sec
deleted file mode 100644
index 688f7e9..0000000
Binary files a/gnupghome/TESTING.subkeys.sec and /dev/null differ
diff --git a/gnupghome/TESTING.subkeys.sec.EXPIRED-2013-09-11 b/gnupghome/TESTING.subkeys.sec.EXPIRED-2013-09-11
deleted file mode 100644
index ae13a98..0000000
Binary files a/gnupghome/TESTING.subkeys.sec.EXPIRED-2013-09-11 and /dev/null differ
diff --git a/gnupghome/bridgedb-offline-key.pub.asc b/gnupghome/bridgedb-offline-key.pub.asc
deleted file mode 100644
index 47d1310..0000000
--- a/gnupghome/bridgedb-offline-key.pub.asc
+++ /dev/null
@@ -1,113 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-
-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
-ILUXBkpIDfVSoZD7qWlntai53BDQr5pfMJhv15di4XAhtqv43vAmA57ifd+QJS2U
-AfYc4CdX0lk2BZ4jRD8jCZ4Uxw15E3RqhnXsWDRxtD4fwsb2ZFi0DDuPlwBdGgh5
-Rm2Bz9JjSV6gDEuXr/JtAzjSz1Jdh8wPkSofiHGTfxysVhlGlg+YPRziRlzML8A2
-0xY+9mPxEEin5ZQ9wmrDyiiOBvPTbG3O9+Sp5VZDuD4ivW/DHumPWGVSRdjcAQDe
-HMXUVGjhBDnj06XNrgJPhODdJeYq0EnGTt15ofZQSswD7TTTRPDOn0Cz/QARAQAB
-tDpCcmlkZ2VEQiAoT2ZmbGluZSBJRCBLZXkpIDxicmlkZ2VzQGJyaWRnZXMudG9y
-cHJvamVjdC5vcmc+iQkfBBMBCgEJBQJSWQfkSBSAAAAAABcAKHZlcmlmaWVkQHRv
-cnByb2plY3Qub3JnN0I3ODQzNzAxNUU2M0RGNDdCQjEyNzBBQ0JEOTdBQTI0RThF
-NDcyRU8UgAAAAAAeAChicmlkZ2VzQGJyaWRnZXMudG9ycHJvamVjdC5vcmc3Qjc4
-NDM3MDE1RTYzREY0N0JCMTI3MEFDQkQ5N0FBMjRFOEU0NzJFKhpodHRwczovL2Jy
-aWRnZXMudG9ycHJvamVjdC5vcmcvcG9saWN5LnR4dAIbAQMLDQkEFQoJCAQWAgEA
-Ah4BAheAJxhodHRwczovL2JyaWRnZXMudG9ycHJvamVjdC5vcmcva2V5LmFzYwAK
-CRDL2XqiTo5HLoqEP/48rFpJCVStn8xo+KkHSVvsqpxDRlb/nNheI+ov2UxILdwl
-NIU6kLsvKECKPe1AHKdS/MzANbkTF35Y4QgZsNpVXaCVL7adGBSzOdPFupDJJVOu
-wa+uFRc/FuNJyH/TIn56/+R5J5C54OxIYNxvW3WF4eHKLJYk/JZOMMfy4iWm7Sql
-0nDC5O435nK4F4Jb4GLPlUIzioIy2OWqGoFHXymbGhL1tWaqasYmED4n3AMqlYw6
-xnNhdWOc/KZelPl9nanybyh0IIdZqUKZleRt4BxSgIT8FqC2sZuZ8z7O9s987Naz
-Q32SKaP4i2M9lai/Y2QYfKo+wlG+egmxtujz7etQMGlpgBZzFLdJ8/w4U11ku1ai
-om74RIn8zl/LHjMQHnCKGoVlscTI1ZPt+p+p8hO2/9vOwTR8y8O/3DQSOfTSipwc
-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
-YnJpZGdlc0BicmlkZ2VzLnRvcnByb2plY3Qub3JnREY4MTExMDlFMTdDOEJGMTM0
-QjVFRUI2OERDNDNBMjg0ODgyMUUzMioaaHR0cHM6Ly9icmlkZ2VzLnRvcnByb2pl
-Y3Qub3JnL3BvbGljeS50eHQACgkQjcQ6KEiCHjIaqBAA0BuEs7horx6iCq4cjAhv
-YPLrxuC4fKEfVyhAjCJMJSFFCPAlGgU+BjyPNDD57wzKAmUkdJG+Ss25mwWXa53w
-5R2kDqDnHocOdZGtxZ7zx/uUd2eWLNBfVuK7nHOk1d1Hs0OZBnckc+MCqnLtuYe5
-68pa9+jW6cNIjAnzMIListmoXWgYYWJvMKeBMG4DGtYJ8w7CJQjOHc5yar12DrX3
-wnQ7hXtFuuqQblpEUnLnZGvHf2NKMZfBBMcP96h9OmLGNa+vmNYsMyPKU7n5hPgX
-nTgmQ4xrv1G7JukjppZRA8SFoxupcaQeTixyWERGBhBiAbwZsbQz8L/TVZKierzg
-sdNngHcFzE8MyjuJDvTos7qXPmgSRXFqJLRn0ZxpR5V1V8BVZUqCGuSZT89TizsD
-z5vyv8c9r7HKD4pRjw32P2dgcEqyGRkqERAgSuFpObP+juty+kxYyfnadBNCyjgP
-s7u0GmsTt4CZi7BbowNRL6bynrwrmQI9LJI1bPhgqfdDUbqG3HXwHz80oRFfKou8
-JTYKxK4Iumfw2l/uAACma5ZyrwIDBX/H5XEQqch4sORzQnuhlTmZRf6ldVIIWjdJ
-ef+DpOt12s+cS2F4D5g8G6t9CprCLYyrXiHwM/U8N5ywL9IeYKSWJxa7si3l9A6o
-ZxOds8F/UJYDSIB97MQFzBo=
-=JdC7
------END PGP PUBLIC KEY BLOCK-----
diff --git a/gnupghome/bridgedb-online-signing-key.pub.asc b/gnupghome/bridgedb-online-signing-key.pub.asc
deleted file mode 100644
index 4f10dcf..0000000
--- a/gnupghome/bridgedb-online-signing-key.pub.asc
+++ /dev/null
@@ -1,148 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-
-mQINBFIv8YABEADRqvfLB4xWj3Fz+HEmUUt/qbJnZhqIjo5WBHaBJOmrzx1c9fLN
-aYG36Hgo6A7NygI1oQmFnDinSrZAtrPaT63d1Jg49yZwr/OhMaxHYJElMFHGJ876
-kLZHmQTysquYKDHhv+fH51t7UVaZ9NkP5cI+V3pqck0DW5DwMsVJXNaU317kk9me
-mPJUDMb5FM4d2Vtk1N+54bHJgpgmnukNtpJmRyHRbZBqNMln5nWF7vdZ4u5PGPWj
-bA0rPZhayeE3FQ0MHiGL12kHAy30pfg54QfPJDQBCywjABetRE+xaM9TcS+R31Pf
-2VbLeb+Km7QpHMwOXI5xZLss9BAWm9EBbmXxuqaRBHyi830jjCrK9UYuzzOqKoUV
-Mk1BRelZTFnGPWeVTE+Ps+pwJ0Dwx4ghppJBCoArmEbkNliblxR/2wYOOFi/ZVA4
-Zc2ok9T3rBLVg07b7ezFUScGiTnc7ac7hp6r8Qsh09ZbhRr9erK/n194aEvkXTfr
-qepwrAE7YeF4YuR206UOFFWDhxWDLbRu0gIWgrevEQu/cvQPrO9uH5fL6Gw/+mNP
-Q/NIteejhkDyvyTUKyBu7x+Gls71zT2u/X13eOAJ8IxBkSVRKQ8tRD+oqJkWplOf
-+BpaGU+g6u4kT2AzFDxTOupfrYcPvORTAV/V3suys2YQE4x422GASXDivQARAQAB
-tClCcmlkZ2VEQiA8YnJpZGdlc0BicmlkZ2VzLnRvcnByb2plY3Qub3JnPokDJQQT
-AQoBDwUCUi/xgEgUgAAAAAAXACh2ZXJpZmllZEB0b3Jwcm9qZWN0Lm9yZ0RGODEx
-MTA5RTE3QzhCRjEzNEI1RUVCNjhEQzQzQTI4NDg4MjFFMzJPFIAAAAAAHgAoYnJp
-ZGdlc0BicmlkZ2VzLnRvcnByb2plY3Qub3JnREY4MTExMDlFMTdDOEJGMTM0QjVF
-RUI2OERDNDNBMjg0ODgyMUUzMioaaHR0cHM6Ly9icmlkZ2VzLnRvcnByb2plY3Qu
-b3JnL3BvbGljeS50eHQCGwEFCQHhM4ADCw0JBBUKCQgEFgIBAAIeAQIXgCcYaHR0
-cHM6Ly9icmlkZ2VzLnRvcnByb2plY3Qub3JnL2tleS5hc2MACgkQjcQ6KEiCHjIW
-qw//WM8jAeuZaNl+2Cdt8Mbe4TCS4jggy4IfRgVqOiKEdIcMXUrDIUXsfg1tc+Jg
-Gk6Ztcw4Mt8HYIEn2MyhuSWOlRoPlLNzN8i8bVBsPHUGKoX0Z1xIahBhkcXVJTJe
-cxRHhvXOpUe+vd54fGYBz/7ViXwwZOjCA7e1zsdkhkpjAkWdJgPynH93bXMU8PYA
-XlMR4rJDTs2LCvMIw3BKfv3Z5zE1a3vQFE1dKsKj6Q3fBYw0gZuobF5Z7fgbN9L+
-f9H9bz0A9K7z6AH+6/C9kHwsjWa2zI7Ei+jexQX+v9udNeR1GphLorgewe+1X+9z
-UsWhBnczSQU/lQFiFuMFgbzFsuwqD8lmDPrO7Ek3b2R0Klv8ge0cA2Y6z7cVZ8Px
-BIEJ5Z9FEqhNBsaLvbbCGbeXUnvzue3Gqcv2WJ8aNfDnPV7BBrtgRSTMP+ErEqyq
-DTPWdOASZmEgqox62zMFP42U7UrgHrGKO801Z6P50ELYAganCOEDFC8YM/R1l+Sq
-ZezRjjNYj0qNUEm2bBNzLDhi7VvMpoxr2D5oIIrm2i+WeankO2hQuPGuRc0rvASb
-tOazhVWqRSddVxeFGlIye8J93NLgEzlHaU1yBwsq/y09/uvmpW65+424HaYzdWVq
-s3H4GCa7VyxH6GoQJeXxqQbJP3gsNkSeEyuXF7LyuFl6hVSJCOYEEwEKANAFAlJZ
-D9AFgwG4FTBIFIAAAAAAFwAodmVyaWZpZWRAdG9ycHJvamVjdC5vcmdERjgxMTEw
-OUUxN0M4QkYxMzRCNUVFQjY4REM0M0EyODQ4ODIxRTMyTxSAAAAAAB4AKGJyaWRn
-ZXNAYnJpZGdlcy50b3Jwcm9qZWN0Lm9yZzdCNzg0MzcwMTVFNjNERjQ3QkIxMjcw
-QUNCRDk3QUEyNEU4RTQ3MkUqGmh0dHBzOi8vYnJpZGdlcy50b3Jwcm9qZWN0Lm9y
-Zy9wb2xpY3kudHh0AAoJEMvZeqJOjkcuVyY//3Gqkvf84Mo3cLcpux1L6F1UqyQ7
-ZwgFAVbrtsR/8HbDD0BUIEoKUbqkqdMhhNeE+yNzlZHLMqgUxveb4sgfYNStMTJ/
-VSlNPTf/T25FShmS6BghWF8qubyKi4cpqyt3zD1INvvTWdRVzRpwxYRBKKWdALl2
-7J5PqvDSvevjx6h6Gc4FoO97WbK5qaQFOc2Nnw2CKCiEiyL3RciMR4IkvAPoxv+E
-Wi6uhCD72s4apqkPiSnsdDqWI/MMkxP7ZKwyyAy/8qMsI79DqwEr2dmLs6AOIXgb
-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
-klHqPZwzyHw0O+tBuQINBFIv8oEBEAC2f6e8USDR2OzDH9/26PyNFkcVh3dQBPbU
-U6MhINUtrtWK1li+TPQ/LGkbKfXKZ6RhLoVt77uxuJ2rGNu6js+G0irtWDAFSAuf
-L9bRJwanaNcxKzY4bN/D65iSm27PbQ32GDotsdBpYTGyKzUrXGaZwnS2ulOjSzG4
-IAy9RsYzD2ATIuE7S4HCHkQ1Eo7GbHGZICsbOUJElXN0q2Mq2msiHPFrSKQy3MT7
-ev4PdK22rWcwXzvvd0c+6lFx5oM7jNIctRb5+tfaNyOQ7Fq3zs/bf0Ls56DgcOD3
-8wzzU+1Zc2TeMRwHK+fuwfgx/SLL5QreTZEBbmKRWQqVzWg9lzrZiKo0wnizX3IE
-xI9KqFCBCsimwSIHz/u0trS18vCSlE8uYPZMV0Hh7ni8pEODLdfCR9JzB2x20JdC
-tyxk+LnEQzpozbZUApbVS5CJNxopsqirP73WfXPnZuAJMdarCXML73l/opiXtnvU
-VKHXMVl8Vq2J7j2uW+Z30dYvhn1dKJ/z7QEPIHPQpCaTIquU0AzhYRT+skHKu+7F
-7lJBJeampqbXnc9vBNCOvd7pZ38HLBPNKcZKSBup99w2SUhMqoLVoxNT9qZ7FXzu
-SC7N5ii3u2ztb96jF3ApDAhh/5MM77aMKmL2OIGmTA2bUBWPFO5SPRXUVL1XXhwA
-duMtvdZ4cwARAQABiQWDBBgBCgDTBQJSL/KBSBSAAAAAABcAKHZlcmlmaWVkQHRv
-cnByb2plY3Qub3JnREY4MTExMDlFMTdDOEJGMTM0QjVFRUI2OERDNDNBMjg0ODgy
-MUUzMk8UgAAAAAAeAChicmlkZ2VzQGJyaWRnZXMudG9ycHJvamVjdC5vcmdERjgx
-MTEwOUUxN0M4QkYxMzRCNUVFQjY4REM0M0EyODQ4ODIxRTMyKhpodHRwczovL2Jy
-aWRnZXMudG9ycHJvamVjdC5vcmcvcG9saWN5LnR4dAIbAgUJAeEzgAKkCRCNxDoo
-SIIeMsHYIAQZAQoAgQUCUi/ygU8UgAAAAAAeAChicmlkZ2VzQGJyaWRnZXMudG9y
-cHJvamVjdC5vcmc5RkUzOUQxQTc0Mzg5MjIzM0IzRjY2RjIyMUI1NTRFOTU5MzhG
-NEQwKhpodHRwczovL2JyaWRnZXMudG9ycHJvamVjdC5vcmcvcG9saWN5LnR4dAAK
-CRAhtVTpWTj00Ns/D/kBN79Pz55pOgLe/RNg1Efme95C/MBZ2eyEPeWe9+yAOFuK
-XCJ8qlzkscpdTeu9vjYcfZy7RyS6Sx0NO8gJkP1wmNGr8X4zObSk0IAmDSlCcdpp
-YVCPD4IdgSiLNqLdL6JjGE0d5J0DpPLvGbj5sc1/QCpuVt3p0rCr0S+PAAjrNmwA
-e2yYdFQx2sXAZ0pp7oJJyFRPYlAUE8RYyG/N2kMYAJZVpI+zFgq5iD0uCmzAZyh/
-62mtGMpGXwy1KHS5+NtUGVN5Iqkvlj59xNEPc8jzDs5yvfOOvpelgbhJQ0exbDHK
-78NNeDvouTX/4F1ofbmEM4BqwtQ5TvJEvzMP9zszQWQZd2OvkjYMQSrDMn1w8daO
-mBvw319kug8U/0k6YoYcg2rE17tN/CJN0Pq4Mqz+79ArVT6jeJgFcFNER2ik9R0F
-Mz3BhFSHIZdMQouFQ/cwaldiWB5g+tJ2nvpXI3cHMtNsy/77uvHIrEv1xZhTSmdc
-eA8LmfIdfmepeaEyeTEAPcGebyf1cN+CLJMMTGqSwSHZVe3KFV8t7PKUQ/Z/C13z
-+YAEEKxOPNlboVF9FECNRlZkYWkWDyejXHklL26KzBE/mDWoeKM0VakbJO0laXlU
-13R334u1VRfWNGkNSmyNlzGqzd+y/Dan4f/NDXAW8Ouyhq+Go5Or4ASclztkbznu
-D/9mG59d6ZeeT+1u+dYeWNUjAYkIt3B/TMOs0KQjxHgvbogto1jy4MMvSfyygkCq
-zDURZslBXw6gZbSHu1XZrfApaX0tphhOmiwztbwOr4aEDKv5MsT9MgkXEEh8BesF
-g/3yUnZ34I8laKfWJQqxVI+reKz/aJYCx9gcoY2jJAaMQoSsxjtFU/KAPvkRhgq/
-QobO5BS/DPWn8SqMzLXlrG2UjR/E5mb6aQU5yDEtSrMuIHQk0hnc3OrgoNX8mt/B
-uhVirtqmsJmrftcfvAfXFWp0RIzsh9qixYeE4yAUSX5mZ4a0zheq/jVAnL0KJEEn
-p2Mw8pkBSmfJS0QpHtMxoaOkZSZO/Ofah751X2Hlr7KVG9ZUdqm8kKtDMJc/JCDz
-tJSpzioUBcXcuG31sfUOayYtS3RG385SuxaC1IiY6QVQvVSh90UVtatfv/jiuWmb
-ddgM7Eifto5ybTnPFNkQASRiFmz3NyrWbinmjnMfC94JJRJVwgOUree3KahjopLC
-r6WiZEknm8SqaipkH7o7xKN7HIe0kvx67YqwTmCH1wK81pQQrbqZPh6xzCys+AXb
-5VK8yoVX4duo7cQGYiODGaw0SqNqXFkzsJ0fy00LDfmKF7KVvtF2qSK50kgAe3Fc
-tQRxUklWHHz5IEviG8nBETtXERQLhilK4E3BPc9BA+aPm7kCDQRSL/KeARAA0zi0
-eXuTSikT6Ywm+Af/GGJFofqK2+9BKICGeo+b/Hf3Yy8oY6mfQSJIeNf4WCjMJ7Gu
-CpA5E2l9HjbtwRQdsxoGdRkne+duREsYqrLlyJQINqXse28rGhX7mtJ1MeuLZmkJ
-tlwK3ZI/8CNKW4PonVspt1kEJmS8k0285fK6UxLU7fktpus9xHgIRB7jRR9eoRA1
-MsJXn9xKLV9547hYi6mjb581GA8YVLyndtitXrNYIIrKYD/nm9W5DAKcXnH9q6pk
-lBHL7Lk1oqeKBmTwSxg0HjSh5AlFW4+ME8lgyEbbaN8IvuAhTxFc8PobY9XEH07L
-T6lHRuzUjpi0IIHnaFHb+wCZuDCSYshGsZfiAH+gH8K65t3jkr9D4KFMTq1G/b4S
-KC/IofILYqr0PamGkUH0AP8N2dErtmH6HH0EvFMPfahvqE4InhuhernfPoTGQGFW
-Ram1Ps7czMgxOoeB35ZLelTSdB5NFaBd/E07O+6R11wWyw+ks0erWzbkfa/5W5gv
-EH9gNWQE4UdIrhoTURbVD6NvBsWpMRnS2fZByMY5exDf4LJmE8LhIa/snzbS8LUh
-9KI3qmw5oLn74IfkiEwrcjQwFLKY62WBLRdDR0aUqJtjRVRCzKjEcnVP53KYdaxm
-YFaev81Y+sSJYSpqo+T9cv/QdHOE7tQsyaZCecMAEQEAAYkC6QQYAQoA0wUCUi/y
-nkgUgAAAAAAXACh2ZXJpZmllZEB0b3Jwcm9qZWN0Lm9yZ0RGODExMTA5RTE3QzhC
-RjEzNEI1RUVCNjhEQzQzQTI4NDg4MjFFMzJPFIAAAAAAHgAoYnJpZGdlc0Bicmlk
-Z2VzLnRvcnByb2plY3Qub3JnREY4MTExMDlFMTdDOEJGMTM0QjVFRUI2OERDNDNB
-Mjg0ODgyMUUzMioaaHR0cHM6Ly9icmlkZ2VzLnRvcnByb2plY3Qub3JnL3BvbGlj
-eS50eHQCGwwFCQHhM4AACgkQjcQ6KEiCHjIPZhAAs5l8T2mWL+kG8WbNyjdISe/W
-D0zZ5E2vAnCq5DcxZ4rax3GblJWRxo1frRT5xoq21adGs8TC5NG1u/40KYn30aB2
-9YE6ida9yCR2R2EYKgX5sKGTXXOpnbFa9og4gXHrgU0f9vwT0rY7CyaRmjBfBxRX
-fCy7i/+dnsuwhMHn0RHJL4yIEdmQk/HFA6Taep6ACl8Wfrebg0TX5zi63v1RbC4e
-KBt39p+l46+UzGWGqP7yfLrHpYNMUIGJOgImvOWeHa2QWJWojHjCuXt5oIuER4ib
-p0lUO2B56wljoAjYvgPHWLAVIAMaxQMriMalF4Nlmcgj0I4aWcFuKMXZVUuie/Ps
-Epj8U2JpIWmGQhzUNN2eUF5WNV/8VPF/WqzcYBBlmGz1lMzRCmQ/Ws1DlJz2i5Pj
-L2cOVatJrRH7Iwz4YPHxgtv+T777GfezuqaIq+ZDKlICxFjalg1gHe40hxsUDdH1
-oJrb5Tg6RD7QV//wDxHDi43p4iL57d3V8LLl/dICA03n/c4ilBBfoh0gWTCjw3pb
-sgww4Q39lcUmcittWG5/xS1OLD9WVLSQ42rUu3c5hPL35zAOhFZsFJSIPuZ2ip8E
-T94oJR/vE4KRRZca7Uy5A0TcPmB4qTMfaCmWjQOyCxPyJKc2ECx+thiHKglL62Ww
-qgQ42nQM/debtU+2aTo=
-=ieIZ
------END PGP PUBLIC KEY BLOCK-----
diff --git a/gnupghome/gpg.conf b/gnupghome/gpg.conf
deleted file mode 100644
index d4a9913..0000000
--- a/gnupghome/gpg.conf
+++ /dev/null
@@ -1,96 +0,0 @@
-##
-## Options for GnuPG
-##
-## :author: isis <isis(a)patternsinthevoid.net>
-
-no-greeting
-no-emit-version
-charset utf-8
-display-charset utf-8
-utf8-strings
-keyid-format long
-default-key 8DC43A2848821E32
-trusted-key CBD97AA24E8E472E
-
-# When outputting certificates, view user IDs distinctly from keys:
-fixed-list-mode
-
-verify-options no-show-photos show-uid-validity show-notations show-user-notations show-policy-urls show-keyserver-urls no-pka-lookups no-pka-trust-increase
-
-list-options no-show-photos show-uid-validity no-show-unusable-uids show-unusable-subkeys show-notations show-user-notations show-policy-urls show-keyserver-urls show-sig-expire show-sig-subpackets
-
-export-options no-export-attributes
-
-# Because some mailers change lines starting with "From " to ">From "
-# it is good to handle such lines in a special way when creating
-# cleartext signatures; all other PGP versions do it this way too.
-#no-escape-from-lines
-
-## Indymedia Keyservers:
-##----------------------
-keyserver hkps://2eghzlv2wwcq7u7y.onion
-keyserver hkp://2eghzlv2wwcq7u7y.onion
-keyserver hkps://keys.indymedia.org
-keyserver hkp://keys.indymedia.org
-keyserver https://keys.indymedia.org
-keyserver http://keys.indymedia.org
-keyserver https://qtt2yl5jocgrk7nu.onion
-keyserver http://qtt2yl5jocgrk7nu.onion
-keyserver-options ca-cert-file=~/scripts/certs/keys.indymedia.org
-
-## Normal keyservers:
-##--------------------
-keyserver hkp://subkeys.pgp.net
-keyserver mailto:pgp-public-keys@keys.pgp.net
-keyserver pgp.mit.edu
-
-keyserver-options verbose verbose verbose no-include-revoked no-include-disabled no-auto-key-retrieve no-honor-keyserver-url no-honor-pka-record include-subkeys no-include-attributes
-
-#keyserver-options http-proxy=socks://127.0.0.1:59050
-
-expert
-allow-freeform-uid
-cert-digest-algo SHA512
-digest-algo SHA512
-default-preference-list SHA512 SHA384 SHA256 CAMELLIA256 AES256 ZLIB ZIP Uncompressed
-personal-cipher-preferences CAMELLIA256 AES256
-personal-digest-preferences SHA512 SHA384 SHA256
-personal-compress-preferences ZLIB ZIP
-compress-level 9
-default-cert-expire 2y
-ask-cert-expire
-ask-cert-level
-default-sig-expire 1y
-no-ask-sig-expire
-
-## algorithm to protect the key in memory:
-s2k-cipher-algo AES256
-
-## use this one to mangle the passphrases:
-s2k-digest-algo SHA512
-
-## passphrase mangling mode:
-## 0=plaintest
-## 1=salt
-## 3=salt+iteration
-s2k-mode 3
-
-## how mangly should we mangle it? 1024 < mangle < 65011712
-##
-## try "python -c'import random;a=random.randint(32505856, 65011712);print a'
-s2k-count 48454407
-
-## Don't run if we can't secure mempages
-require-secmem
-
-## Check the back sig on subkey which has made a signature
-require-cross-certification
-
-## The notation on certifications we make:
-## see http://thread.gmane.org/gmane.mail.notmuch.general/3721/focus=7234
-sig-notation bridges(a)bridges.torproject.org=%g
-cert-notation bridges(a)bridges.torproject.org=%g
-cert-notation verified(a)torproject.org=%f
-set-policy-url https://bridges.torproject.org/policy.txt
-sig-keyserver-url !https://bridges.torproject.org/key.asc
-default-keyserver-url https://bridges.torproject.org/key.asc
1
0

21 Mar '15
commit a9688d06fd6ae7ebe0c47174ef70ae0bc774c390
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 09:56:12 2015 +0000
Add new GnuPG options to bridgedb.conf.
* ADD new options to bridgedb.conf:
- EMAIL_GPG_HOMEDIR
- EMAIL_GPG_PRIMARY_KEY_FINGERPRINT
- EMAIL_GPG_PASSPHRASE
- EMAIL_GPG_PASSPHRASE_FILE
* ADD EMAIL_GPG_HOMEDIR and EMAIL_GPG_PASSPHRASE_FILE to the options
whose paths are expanded in ``bridgedb.configure.loadConfig()``.
---
bridgedb.conf | 55 ++++++++++++++++++++++++++++++++++++++++++---
lib/bridgedb/configure.py | 3 ++-
2 files changed, 54 insertions(+), 4 deletions(-)
diff --git a/bridgedb.conf b/bridgedb.conf
index f8b126c..e0b25f0 100644
--- a/bridgedb.conf
+++ b/bridgedb.conf
@@ -15,11 +15,19 @@
# for details.
# :copyright: (c) 2007-2014 The Tor Project, Inc.
# (c) 2007-2014, all sentient entities within the AUTHORS file
-# :version: 0.0.13
+# :version: 0.0.14
#===============================================================================
#
# CHANGELOG:
# ~~~~~~~~~~
+# Changes in version 0.0.14 - 2015-02-22
+# * ADD new OpenPGP-related options:
+# - EMAIL_GPG_HOMEDIR
+# - EMAIL_GPG_PRIMARY_KEY_FINGERPRINT
+# - EMAIL_GPG_PASSPHRASE
+# - EMAIL_GPG_PASSPHRASE_FILE
+# * REMOVE old OpenPGP signing key file option, EMAIL_GPG_SIGNING_KEY.
+#
# Changes in version 0.0.13 - 2015-02-20
# * ADD NO_DISTRIBUTION_COUNRIES option for refusing to distribute bridges
# whose primary ORAddress is geolocated to any of some certain countries.
@@ -388,9 +396,50 @@ EMAIL_N_BRIDGES_PER_ANSWER = 3
# once we have the vidalia/tor interaction fixed for everbody.
EMAIL_INCLUDE_FINGERPRINTS = True
-# Configuration options for GPG signed messages
+#
+# Configuration options for OpenPGP signing and encryption
+# ------------------------------------------------------------------------------
+
+# Should we sign all email responses to clients with the key specified by
+# EMAIL_GPG_PRIMARY_KEY_FINGERPRINT (or one of its subkeys)?
EMAIL_GPG_SIGNING_ENABLED = True
-EMAIL_GPG_SIGNING_KEY = 'gnupghome/TESTING.subkeys.sec'
+
+# The directory, relative to BridgeDB's runtime directory, in which to store
+# OpenPGP keyrings and associated files.
+EMAIL_GPG_HOMEDIR = '.gnupg'
+
+# This should be a 40-character hexadecimal string containing the OpenPGP
+# fingerprint (without spaces) of the default primary key to use. The key
+# should be capable of both signing and encryption, or have subkeys capable of
+# such.
+#
+# The default primary key fingerprint below is the test key contained in the
+# '.gnupg/TESTING.subkeys.sec' and '.gnupg/TESTING.pub' files:
+EMAIL_GPG_PRIMARY_KEY_FINGERPRINT = '0017098C5DF4197E3C884DCFF1B240D43F148C21'
+
+# If the key referred to by EMAIL_GPG_PRIMARY_KEY_FINGERPRINT requires a
+# passphrase for signing or encryption, then the passphrase may be given in
+# the EMAIL_GPG_PASSPHRASE option (as a string), or it may be contained within
+# the file pointed to by EMAIL_GPG_PASSPHRASE_FILE. Currently, only one
+# passphrase is supported, so if the key specified by
+# EMAIL_GPG_PRIMARY_KEY_FINGERPRINT has multiple subkeys, those subkeys MUST
+# all have the same passphrase.
+#
+# If EMAIL_GPG_PASSPHRASE_FILE is used, and the filepath is not absolute, the
+# path is interpreted as being relative to BridgeDB's runtime directory.
+# (Note: be sure not to put any newlines after the phassphrase in the
+# EMAIL_GPG_PASSPHRASE_FILE, or else they will be interpreted as part of the
+# passphrase.)
+#
+# There are currently no safety checks on the permissions of either this
+# configuration file or the EMAIL_GPG_PASSPHRASE_FILE, so beware and use at
+# your own risk.
+#
+# If both EMAIL_GPG_PASSPHRASE and EMAIL_GPG_PASSPHRASE_FILE are ``None``,
+# then it is assumed that the key specified by
+# EMAIL_GPG_PRIMARY_KEY_FINGERPRINT does not require a passphrase.
+EMAIL_GPG_PASSPHRASE = None
+EMAIL_GPG_PASSPHRASE_FILE = None
#-------------------------------
# Hashring Allocation Options \
diff --git a/lib/bridgedb/configure.py b/lib/bridgedb/configure.py
index 83b53d6..55fcba5 100644
--- a/lib/bridgedb/configure.py
+++ b/lib/bridgedb/configure.py
@@ -104,7 +104,8 @@ def loadConfig(configFile=None, configCls=None):
"ASSIGNMENTS_FILE", "HTTPS_CERT_FILE", "HTTPS_KEY_FILE",
"LOG_FILE", "STATUS_FILE", "COUNTRY_BLOCK_FILE",
"GIMP_CAPTCHA_DIR", "GIMP_CAPTCHA_HMAC_KEYFILE",
- "GIMP_CAPTCHA_RSA_KEYFILE"]:
+ "GIMP_CAPTCHA_RSA_KEYFILE", "EMAIL_GPG_HOMEDIR",
+ "EMAIL_GPG_PASSPHRASE_FILE"]:
setting = getattr(config, attr, None)
if setting is None:
setattr(config, attr, setting)
1
0

[bridgedb/master] Update multiple integration tests to point to the new .gnupg directory.
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit 2a39538e267fb43a9f96a1410b1e4e979fe65eb1
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 10:21:51 2015 +0000
Update multiple integration tests to point to the new .gnupg directory.
* UPDATE test_Main.py, test_email_autoresponder.py, and
email_helpers.py to use the new .gnupg/ directory (rather than
gnupghome/).
* ADD new GnuPG options to b.test.email_helpers._createConfig().
---
lib/bridgedb/test/email_helpers.py | 15 ++++++++++++---
lib/bridgedb/test/test_Main.py | 5 ++++-
lib/bridgedb/test/test_email_autoresponder.py | 2 +-
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/lib/bridgedb/test/email_helpers.py b/lib/bridgedb/test/email_helpers.py
index 867ff58..5e4262d 100644
--- a/lib/bridgedb/test/email_helpers.py
+++ b/lib/bridgedb/test/email_helpers.py
@@ -26,7 +26,10 @@ from bridgedb.test.test_HTTPServer import DummyBridge
EMAIL_DIST = True
EMAIL_INCLUDE_FINGERPRINTS = True
EMAIL_GPG_SIGNING_ENABLED = True
-EMAIL_GPG_SIGNING_KEY = 'TESTING.subkeys.sec'
+EMAIL_GPG_HOMEDIR = '.gnupg'
+EMAIL_GPG_PRIMARY_KEY_FINGERPRINT = '0017098C5DF4197E3C884DCFF1B240D43F148C21'
+EMAIL_GPG_PASSPHRASE = None
+EMAIL_GPG_PASSPHRASE_FILE = None
EMAIL_DOMAIN_MAP = {
'googlemail.com': 'gmail.com',
'mail.google.com': 'gmail.com',
@@ -53,7 +56,10 @@ TEST_CONFIG_FILE = io.StringIO(unicode("""\
EMAIL_DIST = %s
EMAIL_INCLUDE_FINGERPRINTS = %s
EMAIL_GPG_SIGNING_ENABLED = %s
-EMAIL_GPG_SIGNING_KEY = %s
+EMAIL_GPG_HOMEDIR = %s
+EMAIL_GPG_PRIMARY_KEY_FINGERPRINT = %s
+EMAIL_GPG_PASSPHRASE = %s
+EMAIL_GPG_PASSPHRASE_FILE = %s
EMAIL_DOMAIN_MAP = %s
EMAIL_DOMAIN_RULES = %s
EMAIL_DOMAINS = %s
@@ -71,7 +77,10 @@ EMAIL_PORT = %s
""" % (repr(EMAIL_DIST),
repr(EMAIL_INCLUDE_FINGERPRINTS),
repr(EMAIL_GPG_SIGNING_ENABLED),
- repr(EMAIL_GPG_SIGNING_KEY),
+ repr(EMAIL_GPG_HOMEDIR),
+ repr(EMAIL_GPG_PRIMARY_KEY_FINGERPRINT),
+ repr(EMAIL_GPG_PASSPHRASE),
+ repr(EMAIL_GPG_PASSPHRASE_FILE),
repr(EMAIL_DOMAIN_MAP),
repr(EMAIL_DOMAIN_RULES),
repr(EMAIL_DOMAINS),
diff --git a/lib/bridgedb/test/test_Main.py b/lib/bridgedb/test/test_Main.py
index 7525b72..0b14319 100644
--- a/lib/bridgedb/test/test_Main.py
+++ b/lib/bridgedb/test/test_Main.py
@@ -415,7 +415,10 @@ EMAIL_PORT = 55557
EMAIL_N_BRIDGES_PER_ANSWER = 3
EMAIL_INCLUDE_FINGERPRINTS = True
EMAIL_GPG_SIGNING_ENABLED = False
-EMAIL_GPG_SIGNING_KEY = '../gnupghome/TESTING.subkeys.sec'
+EMAIL_GPG_HOMEDIR = '../.gnupg'
+EMAIL_GPG_PRIMARY_KEY_FINGERPRINT = '0017098C5DF4197E3C884DCFF1B240D43F148C21'
+EMAiL_GPG_PASSPHRASE = None
+EMAIL_GPG_PASSPHRASE_FILE = None
HTTPS_SHARE = 10
EMAIL_SHARE = 5
RESERVED_SHARE = 2
diff --git a/lib/bridgedb/test/test_email_autoresponder.py b/lib/bridgedb/test/test_email_autoresponder.py
index c94c909..2895802 100644
--- a/lib/bridgedb/test/test_email_autoresponder.py
+++ b/lib/bridgedb/test/test_email_autoresponder.py
@@ -37,7 +37,7 @@ class CreateResponseBodyTests(unittest.TestCase):
def _moveGPGTestKeyfile(self):
here = os.getcwd()
topDir = here.rstrip('_trial_temp')
- self.gpgFile = os.path.join(topDir, 'gnupghome', 'TESTING.subkeys.sec')
+ self.gpgFile = os.path.join(topDir, '.gnupg', 'TESTING.subkeys.sec')
self.gpgMoved = os.path.join(here, 'TESTING.subkeys.sec')
shutil.copy(self.gpgFile, self.gpgMoved)
1
0

[bridgedb/master] Remove old GPGME-based GnuPG functions from bridgedb.crypto.
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit a87eb73576cd23a9891c69448e44a38732cd963f
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 10:52:15 2015 +0000
Remove old GPGME-based GnuPG functions from bridgedb.crypto.
* REMOVE PythonicGpgmeError.
* REMOVE LessCrypticGPGMEError.
* REMOVE _createGPGMEErrorInterpreters.
* REMOVE gpgmeErrorTranslations.
* REMOVE getGPGContext.
* REMOVE gpgSignMessage.
* REMOVE all associated tests.
---
lib/bridgedb/crypto.py | 208 --------------------------------------
lib/bridgedb/test/test_crypto.py | 202 ------------------------------------
2 files changed, 410 deletions(-)
diff --git a/lib/bridgedb/crypto.py b/lib/bridgedb/crypto.py
index 724d649..a16e45a 100644
--- a/lib/bridgedb/crypto.py
+++ b/lib/bridgedb/crypto.py
@@ -41,7 +41,6 @@ Module Overview
from __future__ import absolute_import
from __future__ import unicode_literals
-import gpgme
import hashlib
import hmac
import io
@@ -93,46 +92,6 @@ class PKCS1PaddingError(Exception):
class RSAKeyGenerationError(Exception):
"""Raised when there was an error creating an RSA keypair."""
-class PythonicGpgmeError(Exception):
- """Replacement for ``gpgme.GpgmeError`` with understandable error info."""
-
-class LessCrypticGPGMEError(Exception):
- """Holds interpreted info on source/type of a ``gpgme.GpgmeError``."""
-
- def __init__(self, gpgmeError, *args):
- self.interpretCrypticGPGMEError(gpgmeError)
- super(LessCrypticGPGMEError, self).__init__(self.message)
-
- def interpretCrypticGPGMEError(self, gpgmeError):
- """Set our ``message`` attribute with a decoded explanation of the
- GPGME error code received.
-
- :type gpgmeError: ``gpgme.GpgmeError``
- :param gpgmeError: An exception raised by the gpgme_ module.
-
- .. _gpgme: https://bazaar.launchpad.net/~jamesh/pygpgme/trunk/view/head:/src/pygpgme-e…
- """
- try:
- errorSource, errorCode, errorMessage = gpgmeError.args
- except (AttributeError, ValueError):
- self.message = "Could not get error code from gpgme.GpgmeError!"
- return
-
- if errorCode and errorSource:
- try:
- sources = gpgmeErrorTranslations[str(errorSource)]
- except KeyError:
- sources = ['UNKNOWN']
- sources = ', '.join(sources).strip(',')
-
- try:
- names = gpgmeErrorTranslations[str(errorCode)]
- except KeyError:
- names = ['UNKNOWN']
- names = ', '.join(names).strip(',')
-
- self.message = "GpgmeError: {0} stemming from {1}: '{2}'""".format(
- names, sources, str(errorMessage))
def writeKeyToFile(key, filename):
"""Write **key** to **filename**, with ``0400`` permissions.
@@ -314,181 +273,14 @@ def removePKCS1Padding(message):
return unpadded
-def _createGPGMEErrorInterpreters():
- """Create a mapping of GPGME ERRNOs ←→ human-readable error names/causes.
- This function is called automatically when :mod:`this module
- <bridgedb.crypto>` is loaded. The resulting dictionary mapping is stored
- as :attr:`~bridgedb.crypto.gpgmeErrorTranslations`, and is used by
- :exc:`~bridgedb.crypto.LessCrypticGPGMEError`.
- :returns: A dict of::
- {str(ERRNO): [ERRORNAME, ANOTHER_ERRORNAME, …],
- …,
- str(ERRORNAME): str(ERRNO),
- …}
- for all known error numbers and error names/causes.
- """
- errorDict = {}
- errorAttrs = []
-
- if gpgme is not None:
- errorAttrs = dir(gpgme)
-
- for attr in errorAttrs:
- if attr.startswith('ERR'):
- errorName = attr
- errorCode = getattr(gpgme, attr, None)
- if errorCode is not None:
- try:
- allErrorNames = errorDict[str(errorCode)]
- except KeyError:
- allErrorNames = []
- allErrorNames.append(str(errorName))
-
- errorDict.update({str(errorCode): allErrorNames})
- errorDict.update({str(errorName): str(errorCode)})
-
- return errorDict
-
-#: This is a dictionary which holds a translation of GPGME ERRNOs ←→ all known
-#: names/causes for that ERRNO, and vice versa. It is created automatically,
-#: via the :func:`_createGPGMEErrorInterpreters` function, when this module is
-#: loaded so that :exc:`LessCrypticGPGMEError` can use it to display
-#: human-readable information about why GPGME borked itself on something.
-gpgmeErrorTranslations = _createGPGMEErrorInterpreters()
-
-def getGPGContext(cfg):
- """Import a key from a file and initialise a context for GnuPG operations.
-
- The key should not be protected by a passphrase, and should have the
- signing flag enabled.
-
- :type cfg: :class:`bridgedb.persistent.Conf`
- :param cfg: The loaded config file.
- :rtype: :class:`gpgme.Context` or None
- :returns: A GPGME context with the signers initialized by the keyfile
- specified by the option EMAIL_GPG_SIGNING_KEY in bridgedb.conf, or
- None if the option was not enabled, or was unable to initialize.
- """
- try:
- # must have enabled signing and specified a key file
- if not cfg.EMAIL_GPG_SIGNING_ENABLED or not cfg.EMAIL_GPG_SIGNING_KEY:
- return None
- except AttributeError:
- return None
- keyfile = None
- ctx = gpgme.Context()
- try:
- binary = GPGME_CONTEXT_BINARY[0]
- except Exception:
- # Setting this to ``None`` will cause libgpgme to "use the default
- # binary", according their docs:
- binary = None
- try:
- homedir = os.path.abspath(GPGME_CONTEXT_HOMEDIR)
- logging.debug("Setting GPG homedir to %r" % homedir)
- if not os.path.isdir(homedir):
- os.makedirs(homedir)
- # This is done to ensure that we don't ever use keys in the process
- # owner's $GNUPGHOME directory, see:
- # http://www.gnupg.org/documentation/manuals/gpgme/Crypto-Engine.html#Crypto-…
- ctx.set_engine_info(gpgme.PROTOCOL_OpenPGP, binary, homedir)
-
- logging.debug("Opening GPG keyfile %s..." % cfg.EMAIL_GPG_SIGNING_KEY)
- keyfile = open(cfg.EMAIL_GPG_SIGNING_KEY)
- key = ctx.import_(keyfile)
-
- if not len(key.imports) > 0:
- logging.debug("Unexpected result from gpgme.Context.import_(): %r"
- % key)
- raise PythonicGpgmeError("Could not import GnuPG key from file %r"
- % cfg.EMAIL_GPG_SIGNING_KEY)
-
- fingerprint = key.imports[0][0]
- subkeyFingerprints = []
- # For some reason, if we don't do it exactly like this, we can get
- # signatures for *any* key in the current process owner's keyring
- # file:
- bridgedbKey = ctx.get_key(fingerprint)
- bridgedbUID = bridgedbKey.uids[0].uid
- logging.info("GnuPG key imported: %s" % bridgedbUID)
- logging.info(" Fingerprint: %s" % fingerprint)
- for subkey in bridgedbKey.subkeys:
- logging.info("Subkey fingerprint: %s" % subkey.fpr)
- subkeyFingerprints.append(subkey.fpr)
-
- ctx.armor = True
- ctx.signers = (bridgedbKey,)
-
- logging.debug("Testing signature created with GnuPG key...")
- signatureText, sigs = gpgSignMessage(ctx, "Testing 1 2 3")
-
- if not len(sigs) == 1:
- raise PythonicGpgmeError("Testing couldn't produce a signature "\
- "with GnuPG key: %s" % fingerprint)
-
- sigFingerprint = sigs[0].fpr
- if sigFingerprint in subkeyFingerprints:
- logging.info("GPG signatures will use subkey with fingerprint: %s"
- % sigFingerprint)
- else:
- if sigFingerprint != fingerprint:
- raise PythonicGpgmeError(
- "Test sig fingerprint '%s' not from any appropriate key!"
- % sigFingerprint)
-
- except (IOError, OSError) as error:
- logging.debug(error)
- logging.error("Could not open or read from GnuPG key file %r!"
- % cfg.EMAIL_GPG_SIGNING_KEY)
- ctx = None
- except gpgme.GpgmeError as error:
- lessCryptic = LessCrypticGPGMEError(error)
- logging.error(lessCryptic)
- ctx = None
- except PythonicGpgmeError as error:
- logging.error(error)
- ctx = None
- finally:
- if keyfile and not keyfile.closed:
- keyfile.close()
-
- return ctx
-
-def gpgSignMessage(gpgmeCtx, messageString, mode=None):
- """Sign a **messageString** with a GPGME context.
-
- :param gpgmeCtx: A ``gpgme.Context`` initialised with the appropriate
- settings.
- :param str messageString: The message to sign.
- :param mode: The signing mode. (default: ``gpgme.SIG_MODE_CLEAR``)
- :rtype: tuple
- :returns: A 2-tuple of ``(signature, list)``, where:
- * ``signature`` is the ascii-armored signature text.
- * ``list`` is a list of ``gpgme.NewSignature``s.
-
- .. warning:: The returned signature text and list *may* be empty, if no
- signature was created.
- """
- if not mode:
- mode = gpgme.SIG_MODE_CLEAR
- if NEW_BUFFER_INTERFACE:
- msgFile = io.BytesIO(buffer(messageString))
- sigFile = io.BytesIO()
- else:
- msgFile = io.StringIO(unicode(messageString))
- sigFile = io.StringIO()
- sigList = gpgmeCtx.sign(msgFile, sigFile, mode)
- sigFile.seek(0)
- signature = sigFile.read()
- return (signature, sigList)
class SSLVerifyingContextFactory(ssl.CertificateOptions):
diff --git a/lib/bridgedb/test/test_crypto.py b/lib/bridgedb/test/test_crypto.py
index 801a369..da93f07 100644
--- a/lib/bridgedb/test/test_crypto.py
+++ b/lib/bridgedb/test/test_crypto.py
@@ -15,7 +15,6 @@ from __future__ import print_function
from __future__ import unicode_literals
import base64
-import gpgme
import io
import logging
import math
@@ -24,7 +23,6 @@ import shutil
import OpenSSL
-
from twisted.internet import defer
from twisted.trial import unittest
from twisted.test.proto_helpers import StringTransport
@@ -286,143 +284,6 @@ class RemovePKCS1PaddingTests(unittest.TestCase):
self.blob)
-class LessCrypticGPGMEErrorTests(unittest.TestCase):
- """Unittests for :class:`bridgedb.crypto.LessCrypticGPGMEError`."""
-
- def test_error1(self):
- """libgpgme will raise an error when given an io.StringIO for the
- message or sigfile.
- """
- message = io.StringIO(unicode(self.id()))
- sigfile = io.StringIO()
-
- lessCryptic = None
- ctx = gpgme.Context()
-
- try:
- ctx.sign(message, sigfile)
- except gpgme.GpgmeError as error:
- lessCryptic = crypto.LessCrypticGPGMEError(error)
-
- self.assertTrue('Invalid argument' in lessCryptic.message)
-
- def test_noGpgmeErrorArgs(self):
- """A gpgme.GpgmeError() without error code args should result in a
- 'Could not get error code from gpgme.GpgmeError!' message.
- """
- error = gpgme.GpgmeError()
- lessCryptic = crypto.LessCrypticGPGMEError(error)
- self.assertEqual(lessCryptic.message,
- 'Could not get error code from gpgme.GpgmeError!')
-
- def test_unknownErrorSource(self):
- """A gpgme.GpgmeError() without a recognisable error source should say
- that the error source is 'UNKNOWN'.
- """
- msg = "These numbers make more sense than libgpgme's error codes."
- error = gpgme.GpgmeError(math.pi, math.e, msg)
- lessCryptic = crypto.LessCrypticGPGMEError(error)
- self.assertSubstring('UNKNOWN', lessCryptic.message)
- self.assertSubstring(msg, lessCryptic.message)
-
- def test_unknownErrorCode(self):
- """A gpgme.GpgmeError() without a recognisable error code should say
- that the error code is 'UNKNOWN'.
- """
- msg = "These numbers make more sense than libgpgme's error codes."
- error = gpgme.GpgmeError(math.pi, math.e, msg)
- lessCryptic = crypto.LessCrypticGPGMEError(error)
- self.assertSubstring('UNKNOWN', lessCryptic.message)
- self.assertSubstring(msg, lessCryptic.message)
-
-
-class GPGContextTests(unittest.TestCase):
- """Tests for :func:`bridgedb.crypto.getGPGContext`."""
-
- timeout = 15
-
- @fileCheckDecorator
- def doCopyFile(self, src, dst, description=None):
- shutil.copy(src, dst)
-
- def removeRundir(self):
- """Remove the rundir from the _trial_tmp directory."""
- if os.path.isdir(self.runDir):
- shutil.rmtree(self.runDir)
-
- def makeBadKey(self):
- """Make a bad keyfile and set its path in our config."""
- keyfile = os.path.join(self.runDir, 'badkey.asc')
- with open(keyfile, 'w') as badkey:
- badkey.write(str('NO PASARAN, DEATH CAKES!'))
- badkey.flush()
- self.setKey(keyfile)
-
- def enableSigning(self, enable=True):
- """Enable or disable the config setting for email signing."""
- setattr(self.config, 'EMAIL_GPG_SIGNING_ENABLED', enable)
-
- def setKey(self, keyfile=''):
- """Set the config keyfile path to **keyfile**."""
- setattr(self.config, 'EMAIL_GPG_SIGNING_KEY', keyfile)
-
- def setUp(self):
- here = os.getcwd()
- topDir = here.rstrip('_trial_temp')
- self.runDir = os.path.join(here, 'rundir')
- self.gpgFile = os.path.join(topDir, 'gnupghome', 'TESTING.subkeys.sec')
- self.gpgExpr = os.path.join(topDir, 'gnupghome',
- 'TESTING.subkeys.sec.EXPIRED-2013-09-11')
-
- if not os.path.isdir(self.runDir):
- os.makedirs(self.runDir)
-
- self.config = Conf()
- self.enableSigning()
- self.addCleanup(self.enableSigning)
- self.addCleanup(self.removeRundir)
-
- def test_getGPGContext_good_keyfile(self):
- """Test EmailServer.getGPGContext() with a good key filename."""
- self.setKey(self.gpgFile)
- ctx = crypto.getGPGContext(self.config)
- self.assertIsInstance(ctx, gpgme.Context)
-
- def test_getGPGContext_missing_keyfile(self):
- """Test EmailServer.getGPGContext() with a missing key filename."""
- self.setKey('missing-keyfile.asc')
- ctx = crypto.getGPGContext(self.config)
- self.assertTrue(ctx is None)
-
- def test_getGPGContext_bad_keyfile(self):
- """Test EmailServer.getGPGContext() with a missing key filename."""
- self.makeBadKey()
- ctx = crypto.getGPGContext(self.config)
- self.assertTrue(ctx is None)
-
- def test_getGPGContext_expired_keyfile(self):
- """getGPGContext() with an expired key should return None."""
- self.setKey(self.gpgExpr)
- ctx = crypto.getGPGContext(self.config)
- self.assertTrue(ctx is None)
-
- def test_getGPGContext_signing_disabled(self):
- """getGPGContext() with signing disabled should return None."""
- self.setKey(self.gpgFile)
- self.enableSigning(False)
- ctx = crypto.getGPGContext(self.config)
- self.assertIsNone(ctx)
-
- def test_getGPGContext_config_signing_missing(self):
- """getGPGContext() with a missing/unset 'EMAIL_GPG_SIGNING_ENABLED'
- config line should return None.
- """
- self.setKey(self.gpgFile)
- delattr(self.config, 'EMAIL_GPG_SIGNING_ENABLED')
- ctx = crypto.getGPGContext(self.config)
- self.assertIsNone(ctx)
-
-
class SSLVerifyingContextFactoryTests(unittest.TestCase,
txtagent.FakeReactorAndConnectMixin):
"""Tests for :class:`bridgedb.crypto.SSLVerifyingContextFactory`."""
@@ -503,66 +364,3 @@ class SSLVerifyingContextFactoryTests(unittest.TestCase,
contextFactory = crypto.SSLVerifyingContextFactory(self.url)
self.assertIsInstance(contextFactory.getContext(),
OpenSSL.SSL.Context)
-
-
-class GetGPGContextTest(unittest.TestCase):
- """Unittests for :func:`bridgedb.crypto.getGPGContext`."""
-
- timeout = 15
-
- @fileCheckDecorator
- def doCopyFile(self, src, dst, description=None):
- shutil.copy(src, dst)
-
- def removeRundir(self):
- if os.path.isdir(self.runDir):
- shutil.rmtree(self.runDir)
-
- def makeBadKey(self):
- self.setKey(self.badKeyfile)
-
- def setKey(self, keyfile=''):
- setattr(self.config, 'EMAIL_GPG_SIGNING_KEY', keyfile)
-
- def setUp(self):
- here = os.getcwd()
- topDir = here.rstrip('_trial_temp')
- self.runDir = os.path.join(here, 'rundir')
- self.gpgMoved = os.path.join(here, 'TESTING.subkeys.sec')
- self.gpgFile = os.path.join(topDir, 'gnupghome',
- 'TESTING.subkeys.sec')
-
- if not os.path.isdir(self.runDir):
- os.makedirs(self.runDir)
-
- self.badKeyfile = os.path.join(here, 'badkey.asc')
- with open(self.badKeyfile, 'w') as badkey:
- badkey.write('NO PASARAN, DEATH CAKES!')
- badkey.flush()
-
- self.doCopyFile(self.gpgFile, self.gpgMoved, "GnuPG test keyfile")
-
- self.config = Conf()
- setattr(self.config, 'EMAIL_GPG_SIGNING_ENABLED', True)
- setattr(self.config, 'EMAIL_GPG_SIGNING_KEY',
- 'gnupghome/TESTING.subkeys.sec')
-
- self.addCleanup(self.removeRundir)
-
- def test_getGPGContext_good_keyfile(self):
- """Test EmailServer.getGPGContext() with a good key filename."""
- self.setKey(self.gpgMoved)
- ctx = crypto.getGPGContext(self.config)
- self.assertIsInstance(ctx, crypto.gpgme.Context)
-
- def test_getGPGContext_missing_keyfile(self):
- """Test EmailServer.getGPGContext() with a missing key filename."""
- self.setKey('missing-keyfile.asc')
- ctx = crypto.getGPGContext(self.config)
- self.assertTrue(ctx is None)
-
- def test_getGPGContext_bad_keyfile(self):
- """Test EmailServer.getGPGContext() with a missing key filename."""
- self.makeBadKey()
- ctx = crypto.getGPGContext(self.config)
- self.assertTrue(ctx is None)
1
0

[bridgedb/master] Add integration tests for bridgedb.crypto.initializeGnuPG().
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit 9ed91fb1403b44dbf0f6b6e08e9a0173862c9c3c
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 10:20:36 2015 +0000
Add integration tests for bridgedb.crypto.initializeGnuPG().
---
lib/bridgedb/test/test_crypto.py | 139 ++++++++++++++++++++++++++++++++++++++
1 file changed, 139 insertions(+)
diff --git a/lib/bridgedb/test/test_crypto.py b/lib/bridgedb/test/test_crypto.py
index 2187475..801a369 100644
--- a/lib/bridgedb/test/test_crypto.py
+++ b/lib/bridgedb/test/test_crypto.py
@@ -24,6 +24,7 @@ import shutil
import OpenSSL
+
from twisted.internet import defer
from twisted.trial import unittest
from twisted.test.proto_helpers import StringTransport
@@ -33,6 +34,7 @@ from bridgedb import crypto
from bridgedb import txrecaptcha
from bridgedb.persistent import Conf
from bridgedb.test.util import fileCheckDecorator
+from bridgedb.test.email_helpers import _createConfig
logging.disable(50)
@@ -87,6 +89,143 @@ class GetKeyTests(unittest.TestCase):
% (key.encode('hex'), SEKRIT_KEY.encode('hex')))
+class InitializeGnuPGTests(unittest.TestCase):
+ """Unittests for :func:`bridgedb.crypto.initializeGnupG`."""
+
+ def _moveGnuPGHomedir(self):
+ """Move the .gnupg/ directory from the top-level of this repo to the
+ current working directory.
+
+ :rtype: str
+ :returns: The full path to the new gnupg home directory.
+ """
+ here = os.getcwd()
+ topDir = here.rstrip('_trial_temp')
+ gnupghome = os.path.join(topDir, '.gnupg')
+ gnupghomeNew = os.path.join(here, '.gnupg')
+
+ if os.path.isdir(gnupghomeNew):
+ shutil.rmtree(gnupghomeNew)
+
+ shutil.copytree(gnupghome, gnupghomeNew)
+
+ return gnupghomeNew
+
+ def _writePassphraseToFile(self, passphrase, filename):
+ """Write **passphrase** to the file at **filename**.
+
+ :param str passphrase: The GnuPG passphase.
+ :param str filename: The file to write the passphrase to.
+ """
+ fh = open(filename, 'w')
+ fh.write(passphrase)
+ fh.flush()
+ fh.close()
+
+ def setUp(self):
+ """Create a config object and setup our gnupg home directory."""
+ self.config = _createConfig()
+ self.gnupghome = self._moveGnuPGHomedir()
+ self.config.EMAIL_GPG_HOMEDIR = self.gnupghome
+
+ self.passphraseFile = 'gpg-passphrase-file'
+ self._writePassphraseToFile('sekrit', self.passphraseFile)
+
+ def test_crypto_initializeGnuPG(self):
+ """crypto.initializeGnuPG() should return a 2-tuple with a gpg object
+ and a signing function.
+ """
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNotNone(gpg)
+ self.assertIsNotNone(signfunc)
+
+ def test_crypto_initializeGnuPG_disabled(self):
+ """When EMAIL_GPG_SIGNING_ENABLED=False, crypto.initializeGnuPG()
+ should return a 2-tuple of None.
+ """
+ self.config.EMAIL_GPG_SIGNING_ENABLED = False
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+
+ self.assertIsNone(gpg)
+ self.assertIsNone(signfunc)
+
+ def test_crypto_initializeGnuPG_no_secrets(self):
+ """When the secring.gpg is missing, crypto.initializeGnuPG() should
+ return a 2-tuple of None.
+ """
+ secring = os.path.join(self.gnupghome, 'secring.gpg')
+ if os.path.isfile(secring):
+ os.remove(secring)
+
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNone(gpg)
+ self.assertIsNone(signfunc)
+
+ def test_crypto_initializeGnuPG_no_publics(self):
+ """When the pubring.gpg is missing, crypto.initializeGnuPG() should
+ return a 2-tuple of None.
+ """
+ pubring = os.path.join(self.gnupghome, 'pubring.gpg')
+ if os.path.isfile(pubring):
+ os.remove(pubring)
+
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNone(gpg)
+ self.assertIsNone(signfunc)
+
+ def test_crypto_initializeGnuPG_with_passphrase(self):
+ """crypto.initializeGnuPG() should initialize correctly when a
+ passphrase is given but no passphrase is needed.
+ """
+ self.config.EMAIL_GPG_PASSPHRASE = 'password'
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNotNone(gpg)
+ self.assertIsNotNone(signfunc)
+
+ def test_crypto_initializeGnuPG_with_passphrase_file(self):
+ """crypto.initializeGnuPG() should initialize correctly when a
+ passphrase file is given but no passphrase is needed.
+ """
+ self.config.EMAIL_GPG_PASSPHRASE_FILE = self.passphraseFile
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNotNone(gpg)
+ self.assertIsNotNone(signfunc)
+
+ def test_crypto_initializeGnuPG_missing_passphrase_file(self):
+ """crypto.initializeGnuPG() should initialize correctly if a passphrase
+ file is given but that file is missing (when no passphrase is actually
+ necessary).
+ """
+ self.config.EMAIL_GPG_PASSPHRASE_FILE = self.passphraseFile
+ os.remove(self.passphraseFile)
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNotNone(gpg)
+ self.assertIsNotNone(signfunc)
+
+ def test_crypto_initializeGnuPG_signingFunc(self):
+ """crypto.initializeGnuPG() should return a signing function which
+ produces OpenPGP signatures.
+ """
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNotNone(gpg)
+ self.assertIsNotNone(signfunc)
+
+ sig = signfunc("This is a test of the public broadcasting system.")
+ print(sig)
+ self.assertIsNotNone(sig)
+ self.assertTrue(sig.startswith('-----BEGIN PGP SIGNED MESSAGE-----'))
+
+ def test_crypto_initializeGnuPG_nonexistent_default_key(self):
+ """When the key specified by EMAIL_GPG_PRIMARY_KEY_FINGERPRINT doesn't
+ exist in the keyrings, crypto.initializeGnuPG() should return a 2-tuple
+ of None.
+ """
+ self.config.EMAIL_GPG_PRIMARY_KEY_FINGERPRINT = 'A' * 40
+ gpg, signfunc = crypto.initializeGnuPG(self.config)
+ self.assertIsNone(gpg)
+ self.assertIsNone(signfunc)
+
+
class RemovePKCS1PaddingTests(unittest.TestCase):
"""Unittests for :func:`bridgedb.crypto.removePKCS1Padding`."""
1
0

[bridgedb/master] Change .travis.yml before_script to copy .gnupg/ directory into run/.
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit 83772a99e8c067acfdd346001541ee9ea7b31b31
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 21:39:43 2015 +0000
Change .travis.yml before_script to copy .gnupg/ directory into run/.
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 19d0196..75f8857 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -67,7 +67,7 @@ install:
# Start a BridgeDB instance before running the tests:
before_script:
- mkdir run
- - cp -R -t run bridgedb.conf captchas gnupghome
+ - cp -R -t run bridgedb.conf captchas .gnupg
# Add '127.0.0.1' to EMAIL_DOMAINS in bridgedb.conf. This should ONLY be
# done on testing servers, never on production servers.
- sed -r -i -e "s/(EMAIL_DOMAINS)(.*)(])/\1\2\, '127.0.0.1']/" run/bridgedb.conf
1
0

[bridgedb/master] Use crypto.initializeGnuPG() in b.e.server and b.e.autoresponder.
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit f7bb49f84eeab0b80096a88d060b4638c4e9ae52
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 11:00:52 2015 +0000
Use crypto.initializeGnuPG() in b.e.server and b.e.autoresponder.
---
lib/bridgedb/email/autoresponder.py | 45 +++++++++++++++++------------------
lib/bridgedb/email/server.py | 12 ++++++----
2 files changed, 29 insertions(+), 28 deletions(-)
diff --git a/lib/bridgedb/email/autoresponder.py b/lib/bridgedb/email/autoresponder.py
index 3f53e6e..e96ad91 100644
--- a/lib/bridgedb/email/autoresponder.py
+++ b/lib/bridgedb/email/autoresponder.py
@@ -46,7 +46,6 @@ from twisted.mail import smtp
from twisted.python import failure
from bridgedb import safelog
-from bridgedb.crypto import gpgSignMessage
from bridgedb.crypto import NEW_BUFFER_INTERFACE
from bridgedb.Dist import EmailRequestedHelp
from bridgedb.Dist import EmailRequestedKey
@@ -129,7 +128,7 @@ def createResponseBody(lines, context, client, lang='en'):
return templates.buildAnswerMessage(translator, client, answer)
def generateResponse(fromAddress, client, body, subject=None,
- messageID=None, gpgContext=None):
+ messageID=None, gpgSignFunc=None):
"""Create a :class:`EmailResponse`, which acts like an in-memory
``io.StringIO`` file, by creating and writing all headers and the email
body into the file-like ``EmailResponse.mailfile``.
@@ -140,21 +139,21 @@ def generateResponse(fromAddress, client, body, subject=None,
:param client: The client's email address which should be in the
``'To:'`` header of the response email.
:param str subject: The string to write to the ``Subject:'`` header.
- :param str body: The body of the email. If a **gpgContext** is also given,
- and that ``Context`` has email signing configured, then
- :meth:`EmailResponse.writeBody` will generate and include any
- ascii-armored OpenPGP signatures in the **body**.
+ :param str body: The body of the email. If a **gpgSignFunc** is also
+ given, then :meth:`EmailResponse.writeBody` will generate and include
+ an ascii-armored OpenPGP signature in the **body**.
:type messageID: None or str
:param messageID: The :rfc:`2822` specifier for the ``'Message-ID:'``
header, if including one is desirable.
- :type gpgContext: None or ``gpgme.Context``
- :param gpgContext: A pre-configured GPGME context. See
- :func:`~bridgedb.crypto.getGPGContext`.
+ :type gpgSignFunc: ``None`` or callable
+ :param gpgSignFunc: A function for signing messages. See
+ :func:`bridgedb.crypto.initializeGnuPG` for obtaining a pre-configured
+ **gpgSignFunc**.
:returns: An :class:`EmailResponse` which contains the entire email. To
obtain the contents of the email, including all headers, simply use
:meth:`EmailResponse.readContents`.
"""
- response = EmailResponse(gpgContext)
+ response = EmailResponse(gpgSignFunc)
response.to = client
response.writeHeaders(fromAddress.encode('utf-8'), str(client), subject,
inReplyTo=messageID)
@@ -196,21 +195,18 @@ class EmailResponse(object):
_buff = buffer if NEW_BUFFER_INTERFACE else unicode
mailfile = io.BytesIO if NEW_BUFFER_INTERFACE else io.StringIO
- def __init__(self, gpgContext=None):
+ def __init__(self, gpgSignFunc=None):
"""Create a response to an email we have recieved.
This class deals with correctly formatting text for the response email
headers and the response body into an instance of :data:`mailfile`.
- :type gpgContext: None or ``gpgme.Context``
- :param gpgContext: A pre-configured GPGME context. See
- :meth:`bridgedb.crypto.getGPGContext` for obtaining a
- pre-configured **gpgContext**. If given, and the ``Context`` has
- been configured to sign emails, then a response email body string
- given to :meth:`writeBody` will be signed before being written
- into the ``mailfile``.
+ :type gpgSignFunc: ``None`` or callable
+ :param gpgSignFunc: A function for signing messages. See
+ :func:`bridgedb.crypto.initializeGnuPG` for obtaining a
+ pre-configured **gpgSignFunc**.
"""
- self.gpgContext = gpgContext
+ self.gpgSign = gpgSignFunc
self.mailfile = self.mailfile()
self.delimiter = '\n'
self.closed = False
@@ -349,16 +345,19 @@ class EmailResponse(object):
def writeBody(self, body):
"""Write the response body into the :cvar:`mailfile`.
- If ``EmailResponse.gpgContext`` is set, and signing is configured, the
+ If ``EmailResponse.gpgSignFunc`` is set, and signing is configured, the
**body** will be automatically signed before writing its contents into
the ``mailfile``.
:param str body: The body of the response email.
"""
logging.info("Writing email body...")
- if self.gpgContext:
+ if self.gpgSign:
logging.info("Attempting to sign email...")
- body, _ = gpgSignMessage(self.gpgContext, body)
+ sig = self.gpgSign(body)
+ if sig:
+ body = sig
+ print("Signed email body:\n%s" % body) # XXX
self.writelines(body)
@@ -428,7 +427,7 @@ class SMTPAutoresponder(smtp.SMTPClient):
subject = self.incoming.message.getheader("Subject", None)
response = generateResponse(recipient, client,
body, subject, messageID,
- self.incoming.context.gpgContext)
+ self.incoming.context.gpgSignFunc)
return response
def getMailTo(self):
diff --git a/lib/bridgedb/email/server.py b/lib/bridgedb/email/server.py
index 110c381..05cecb7 100644
--- a/lib/bridgedb/email/server.py
+++ b/lib/bridgedb/email/server.py
@@ -61,7 +61,7 @@ from zope.interface import implements
from bridgedb import __version__
from bridgedb import safelog
-from bridgedb.crypto import getGPGContext
+from bridgedb.crypto import initializeGnuPG
from bridgedb.email import autoresponder
from bridgedb.email import templates
from bridgedb.email import request
@@ -90,9 +90,11 @@ class MailServerContext(object):
:ivar int fuzzyMatch: An integer specifying the maximum Levenshtein
Distance from an incoming email address to a blacklisted email address
for the incoming email to be dropped.
- :ivar gpgContext: A ``gpgme.GpgmeContext`` (as created by
- :func:`bridgedb.crypto.getGPGContext`), or None if we couldn't create
- a proper GPGME context for some reason.
+ :ivar gpg: A :class:`gnupg.GPG` interface_, as returned by
+ :func:`~bridgedb.crypto.initialiseGnuPG`, or ``None`` if we couldn't
+ initialize GnuPG for some reason.
+ :ivar gpgSignFunc: A callable which signs a message, e.g. the one returned
+ from :func:`~bridgedb.crypto.initialiseGnuPG`.
"""
def __init__(self, config, distributor, schedule):
@@ -128,7 +130,7 @@ class MailServerContext(object):
self.blacklist = config.EMAIL_BLACKLIST or []
self.fuzzyMatch = config.EMAIL_FUZZY_MATCH or 0
- self.gpgContext = getGPGContext(config)
+ self.gpg, self.gpgSignFunc = initializeGnuPG(config)
def buildCanonicalDomainMap(self):
"""Build a map for all email provider domains from which we will accept
1
0

[bridgedb/master] Merge branch 'fix/10385-python-gnupg_r1' into develop
by isis@torproject.org 21 Mar '15
by isis@torproject.org 21 Mar '15
21 Mar '15
commit b8365ad36d78d279af4d19736991262b2f9c8268
Merge: 95ad0a6 f7bb49f
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Mon Feb 23 23:31:26 2015 +0000
Merge branch 'fix/10385-python-gnupg_r1' into develop
.gitignore | 3 -
.gnupg/TESTING.pub | Bin 0 -> 4622 bytes
.gnupg/TESTING.subkeys.sec | Bin 0 -> 7212 bytes
.gnupg/bridgedb-offline-key.pub.asc | 113 ++++++++
.gnupg/bridgedb-online-key.pub.asc | 100 +++++++
.gnupg/gpg.conf | 96 ++++++
.gnupg/pubring.gpg | Bin 0 -> 4634 bytes
.gnupg/secring.gpg | Bin 0 -> 7224 bytes
.travis.requirements.txt | 2 +-
.travis.yml | 4 +-
README.rst | 6 +-
bridgedb.conf | 55 +++-
gnupghome/TESTING.subkeys.sec | Bin 7212 -> 0 bytes
gnupghome/TESTING.subkeys.sec.EXPIRED-2013-09-11 | Bin 6505 -> 0 bytes
gnupghome/bridgedb-offline-key.pub.asc | 113 --------
gnupghome/bridgedb-online-signing-key.pub.asc | 148 ----------
gnupghome/gpg.conf | 96 ------
lib/bridgedb/configure.py | 3 +-
lib/bridgedb/crypto.py | 285 +++++-------------
lib/bridgedb/email/autoresponder.py | 45 ++-
lib/bridgedb/email/server.py | 12 +-
lib/bridgedb/test/email_helpers.py | 15 +-
lib/bridgedb/test/test_Main.py | 5 +-
lib/bridgedb/test/test_crypto.py | 339 +++++++++-------------
lib/bridgedb/test/test_email_autoresponder.py | 2 +-
requirements.txt | 2 +-
26 files changed, 631 insertions(+), 813 deletions(-)
1
0

21 Mar '15
commit a4fc36eabb00bb47114b8379319d3897a63427ac
Author: Isis Lovecruft <isis(a)torproject.org>
Date: Sun Feb 22 10:58:04 2015 +0000
Add crypto.initializeGnuPG() function.
This switches BridgeDB to using python-gnupg rather than pygpgme.
* FIXES #10385 https://bugs.torproject.org/10385
---
lib/bridgedb/crypto.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/lib/bridgedb/crypto.py b/lib/bridgedb/crypto.py
index a16e45a..6bb5c7d 100644
--- a/lib/bridgedb/crypto.py
+++ b/lib/bridgedb/crypto.py
@@ -41,6 +41,7 @@ Module Overview
from __future__ import absolute_import
from __future__ import unicode_literals
+import gnupg
import hashlib
import hmac
import io
@@ -273,14 +274,92 @@ def removePKCS1Padding(message):
return unpadded
+def initializeGnuPG(config):
+ """Initialize a GnuPG interface and test our configured keys.
+
+ .. note:: This function uses python-gnupg_.
+
+ :type config: :class:`bridgedb.persistent.Conf`
+ :param config: The loaded config file.
+ :rtype: 2-tuple
+ :returns: If ``EMAIL_GPG_SIGNING_ENABLED`` isn't ``True``, or we couldn't
+ initialize GnuPG and make a successful test signature with the
+ specified key, then a 2-tuple of ``None`` is returned. Otherwise, the
+ first item in the tuple is a :class:`gnupg.GPG` interface_ with the
+ GnuPG homedir set to the ``EMAIL_GPG_HOMEDIR`` option and the signing
+ key specified by the ``EMAIL_GPG_SIGNING_KEY_FINGERPRINT`` option in
+ bridgedb.conf set as the default key. The second item in the tuple is
+ a signing function with the passphrase (as specified in either
+ ``EMAIL_GPG_PASSPHRASE`` or ``EMAIL_GPG_PASSPHRASE_FILE``) already
+ set.
+
+ .. _python-gnupg: https://pypi.python.org/pypi/gnupg/
+ .. _interface: https://python-gnupg.readthedocs.org/en/latest/gnupg.html#gnupg-module
+ """
+ ret = (None, None)
+ if not config.EMAIL_GPG_SIGNING_ENABLED:
+ return ret
+ homedir = config.EMAIL_GPG_HOMEDIR
+ primary = config.EMAIL_GPG_PRIMARY_KEY_FINGERPRINT
+ passphrase = config.EMAIL_GPG_PASSPHRASE
+ passFile = config.EMAIL_GPG_PASSPHRASE_FILE
+ logging.info("Using %s as our GnuPG home directory..." % homedir)
+ gpg = gnupg.GPG(homedir=homedir)
+ logging.info("Initialized GnuPG interface using %s binary with version %s."
+ % (gpg.binary, gpg.binary_version))
+ primarySK = None
+ primaryPK = None
+ secrets = gpg.list_keys(secret=True)
+ publics = gpg.list_keys()
+ if not secrets:
+ logging.warn("No secret keys found in %s!" % gpg.secring)
+ return ret
+ primarySK = filter(lambda key: key['fingerprint'] == primary, secrets)
+ primaryPK = filter(lambda key: key['fingerprint'] == primary, publics)
+ if primarySK and primaryPK:
+ logging.info("Found GnuPG primary key with fingerprint: %s" % primary)
+ for sub in primaryPK[0]['subkeys']:
+ logging.info(" Subkey: %s Usage: %s" % (sub[0], sub[1].upper()))
+ else:
+ logging.warn("GnuPG key %s could not be found in %s!" % (primary, gpg.secring))
+ return ret
+
+ if passphrase:
+ logging.info("Read GnuPG passphrase from config.")
+ elif passFile:
+ try:
+ with open(passFile) as fh:
+ passphrase = fh.read()
+ except (IOError, OSError):
+ logging.error("Could not open GnuPG passphrase file: %s!" % passFile)
+ else:
+ logging.info("Read GnuPG passphrase from file: %s" % passFile)
+ def gpgSignMessage(message):
+ """Sign **message** with the default key specified by
+ ``EMAIL_GPG_PRIMARY_KEY_FINGERPRINT``.
+
+ :param str message: A message to sign.
+ :rtype: str or ``None``.
+ :returns: A string containing the clearsigned message, or ``None`` if
+ the signing failed.
+ """
+ sig = gpg.sign(message, default_key=primary, passphrase=passphrase)
+ if sig and sig.data:
+ return sig.data
+
+ logging.debug("Testing signature created with GnuPG key...")
+ sig = gpgSignMessage("Testing 1 2 3")
+ if sig:
+ logging.info("Test signature with GnuPG key %s okay:\n%s" % (primary, sig))
+ return (gpg, gpgSignMessage)
class SSLVerifyingContextFactory(ssl.CertificateOptions):
1
0