paul@11 | 1 | Introduction
|
paul@11 | 2 | ------------
|
paul@11 | 3 |
|
paul@11 | 4 | MoinMessage provides a library for creating, signing, encrypting, decrypting,
|
paul@12 | 5 | and verifying PGP/GPG content in Python along with mechanisms for updating
|
paul@51 | 6 | MoinMoin wiki instances with such content such that contributors can be
|
paul@11 | 7 | identified from their PGP signatures and such details used to authenticate
|
paul@63 | 8 | their contributions. It also permits PGP/GPG content to be stored in dedicated
|
paul@63 | 9 | message stores when received, enabling further processing of received content
|
paul@63 | 10 | and other means of perusal of such content.
|
paul@11 | 11 |
|
paul@11 | 12 | Configuring GPG for a Wiki
|
paul@11 | 13 | --------------------------
|
paul@11 | 14 |
|
paul@37 | 15 | Initialise a homedir for GPG and configure it using filesystem ACL (access
|
paul@37 | 16 | control list) properties:
|
paul@11 | 17 |
|
paul@12 | 18 | ./scripts/init_wiki_keyring.sh WIKI WEBUSER
|
paul@12 | 19 |
|
paul@51 | 20 | Here, WIKI should be replaced by the top-level wiki instance directory, and
|
paul@12 | 21 | WEBUSER should be the name of the user under which the Web server operates.
|
paul@12 | 22 |
|
paul@12 | 23 | Note that this script may need re-running after the homedir has been changed
|
paul@12 | 24 | by gpg operations as gpg likes to remove permissions from various files.
|
paul@11 | 25 |
|
paul@66 | 26 | Configuring GPG: Signing Keys
|
paul@66 | 27 | -----------------------------
|
paul@66 | 28 |
|
paul@11 | 29 | To be in any way useful, signing keys must be made available within this
|
paul@11 | 30 | homedir so that incoming messages can have their senders verified.
|
paul@11 | 31 |
|
paul@11 | 32 | To see the keys available to you in your own environment:
|
paul@11 | 33 |
|
paul@11 | 34 | gpg --list-keys --with-fingerprint
|
paul@11 | 35 |
|
paul@51 | 36 | The full fingerprints are used when defining a user mapping in the wiki, and
|
paul@11 | 37 | the --with-fingerprint option is used to show them. Otherwise, only the last
|
paul@11 | 38 | eight characters of the fingerprints are shown.
|
paul@11 | 39 |
|
paul@11 | 40 | Export the public key used when signing messages from your own environment:
|
paul@11 | 41 |
|
paul@11 | 42 | gpg --armor --output 1C1AAF83.asc --export 1C1AAF83
|
paul@11 | 43 |
|
paul@51 | 44 | Import the key into the wiki's GPG homedir:
|
paul@11 | 45 |
|
paul@65 | 46 | gpg --homedir WIKI/gnupg --import 1C1AAF83.asc
|
paul@11 | 47 |
|
paul@66 | 48 | Configuring GPG: Encryption Keys
|
paul@66 | 49 | --------------------------------
|
paul@66 | 50 |
|
paul@66 | 51 | For the wiki to receive and decrypt encrypted data, a key for the wiki must be
|
paul@66 | 52 | created:
|
paul@11 | 53 |
|
paul@65 | 54 | gpg --homedir WIKI/gnupg --gen-key
|
paul@11 | 55 |
|
paul@51 | 56 | For the wiki environment to be able to use the key, password access must be
|
paul@12 | 57 | disabled. This can be done by either not specifying a password or by removing
|
paul@59 | 58 | it later using the --edit-key option:
|
paul@59 | 59 |
|
paul@65 | 60 | gpg --homedir WIKI/gnupg --edit-key 0891463A
|
paul@59 | 61 | passwd
|
paul@12 | 62 |
|
paul@51 | 63 | Export the wiki's key for encrypting messages sent to the wiki:
|
paul@11 | 64 |
|
paul@65 | 65 | gpg --homedir WIKI/gnupg --armor --output 0891463A.asc --export 0891463A
|
paul@11 | 66 |
|
paul@11 | 67 | This exported key can now be imported into your own environment:
|
paul@11 | 68 |
|
paul@11 | 69 | gpg --import 0891463A.asc
|
paul@11 | 70 |
|
paul@66 | 71 | This key can also be used to sign relayed messages, and this is described in
|
paul@66 | 72 | more detail below.
|
paul@66 | 73 |
|
paul@11 | 74 | Configuring the Wiki
|
paul@11 | 75 | --------------------
|
paul@11 | 76 |
|
paul@51 | 77 | In the wiki configuration, define the following settings:
|
paul@11 | 78 |
|
paul@11 | 79 | moinmessage_gpg_homedir
|
paul@11 | 80 | This sets the path to the homedir initialised above.
|
paul@11 | 81 |
|
paul@11 | 82 | moinmessage_gpg_users_page (optional, default is MoinMessageUserDict)
|
paul@11 | 83 | This provides a mapping from key fingerprints to Moin usernames.
|
paul@11 | 84 |
|
paul@12 | 85 | moinmessage_gpg_signing_users_page (optional, default is MoinMessageSigningUserDict)
|
paul@12 | 86 | This provides a mapping from Moin usernames to key fingerprints.
|
paul@12 | 87 |
|
paul@65 | 88 | moinmessage_gpg_relaying_user (optional)
|
paul@65 | 89 | This specifies the username of a special user who will sign relayed
|
paul@65 | 90 | messages. Partner wikis will need to record the details of this user in
|
paul@65 | 91 | their fingerprint-to-user mapping (see moinmessage_gpg_users_page) to be
|
paul@65 | 92 | able to receive messages from this wiki.
|
paul@65 | 93 |
|
paul@12 | 94 | moinmessage_gpg_recipients_page (optional, default is MoinMessageRecipientsDict)
|
paul@12 | 95 | This provides a mapping from recipients to remote URLs and key fingerprints.
|
paul@37 | 96 | Each user can define the named page as a subpage of their own home page.
|
paul@37 | 97 | If no such personal mapping exists, a common mapping exists relative to the
|
paul@37 | 98 | site root.
|
paul@12 | 99 |
|
paul@20 | 100 | moinmessage_reject_messages_without_dates (optional, default is True)
|
paul@51 | 101 | This causes messages sent to a wiki using the PostMessage action to be
|
paul@20 | 102 | rejected if date information is missing.
|
paul@20 | 103 |
|
paul@40 | 104 | moinmessage_static_files (optional, may refer to the built-in htdocs directory)
|
paul@40 | 105 | This explicitly defines the path to static resources used by Moin, enabling
|
paul@40 | 106 | such resources to be attached to messages. When set, the path must refer to
|
paul@40 | 107 | the htdocs directory (possibly renamed) containing the different theme
|
paul@65 | 108 | resource directories, together with the robots.txt and favicon.ico files.
|
paul@40 | 109 |
|
paul@38 | 110 | For signature verification to function, the following needs to be added:
|
paul@38 | 111 |
|
paul@38 | 112 | from MoinMoin.auth.pgp import PGPAuth
|
paul@38 | 113 |
|
paul@38 | 114 | This should import an authentication handler installed when the MoinMessage
|
paul@38 | 115 | software is installed as an extension package.
|
paul@38 | 116 |
|
paul@38 | 117 | Within the configuration class itself, the auth setting needs to be updated to
|
paul@38 | 118 | include PGPAuth in the list of registered handlers. For example:
|
paul@38 | 119 |
|
paul@38 | 120 | auth = [MoinAuth(), PGPAuth()]
|
paul@38 | 121 |
|
paul@38 | 122 | This would permit the traditional Moin authentication and add signature-based
|
paul@51 | 123 | authentication so that messages can be accepted by the wiki.
|
paul@38 | 124 |
|
paul@12 | 125 | Fingerprints and Keys
|
paul@12 | 126 | ---------------------
|
paul@12 | 127 |
|
paul@12 | 128 | All fingerprints mentioned in the various configuration pages must exclude
|
paul@12 | 129 | space characters - that is, the letters and digits must appear together in a
|
paul@51 | 130 | continuous block of text - and refer to keys available in the wiki homedir.
|
paul@12 | 131 |
|
paul@11 | 132 | The Fingerprint-to-Username Mapping
|
paul@11 | 133 | -----------------------------------
|
paul@11 | 134 |
|
paul@12 | 135 | The mapping from fingerprints to usernames typically defined by the
|
paul@12 | 136 | MoinMessageUserDict page is a WikiDict having the following general format:
|
paul@11 | 137 |
|
paul@11 | 138 | fingerprint:: username
|
paul@11 | 139 |
|
paul@12 | 140 | Each fingerprint corresponds to a key used by a person wanting to send
|
paul@51 | 141 | messages to the wiki to sign such messages.
|
paul@11 | 142 |
|
paul@51 | 143 | Each username must correspond to a registered user in the wiki.
|
paul@11 | 144 |
|
paul@65 | 145 | If a wiki is to perform message relaying, receiving messages from partner
|
paul@65 | 146 | wikis and sending them on, a user is required for this purpose. You could
|
paul@65 | 147 | create such a user as follows:
|
paul@65 | 148 |
|
paul@66 | 149 | moin --config-dir=WIKI account create --name=RelayingUser --email=messagerelay
|
paul@65 | 150 |
|
paul@65 | 151 | (You may need to run this command as the Web server user to be able to change
|
paul@65 | 152 | the wiki installation, as well as indicating the full path to the moin program
|
paul@65 | 153 | either as the program name or by setting the PATH.)
|
paul@65 | 154 |
|
paul@65 | 155 | After doing this, you could define an entry for the relaying user as follows:
|
paul@65 | 156 |
|
paul@66 | 157 | fingerprint:: RelayingUser
|
paul@65 | 158 |
|
paul@65 | 159 | Here, "fingerprint" should be substituted for a key fingerprint used by a
|
paul@65 | 160 | partner wiki to sign messages that it then sends to this wiki. See the next
|
paul@65 | 161 | section for more information on signing keys and identities.
|
paul@65 | 162 |
|
paul@65 | 163 | It may very well be the case that more than one partner wiki will be sending
|
paul@65 | 164 | messages to this wiki: the signing key fingerprint of each partner wiki can be
|
paul@65 | 165 | added to this mapping and specify the same relaying user; there is no
|
paul@65 | 166 | restriction on each fingerprint needing to map to a different user.
|
paul@65 | 167 |
|
paul@12 | 168 | The Username-to-Signing Key Mapping
|
paul@12 | 169 | -----------------------------------
|
paul@12 | 170 |
|
paul@12 | 171 | The mapping from usernames to fingerprints typically defined by the
|
paul@12 | 172 | MoinMessageSigningUserDict page is a WikiDict having the following general
|
paul@12 | 173 | format:
|
paul@12 | 174 |
|
paul@12 | 175 | username:: fingerprint
|
paul@12 | 176 |
|
paul@51 | 177 | Each fingerprint corresponds to a key available in the wiki's GPG homedir
|
paul@12 | 178 | generated for the purpose of signing the specified user's messages. Such a key
|
paul@51 | 179 | is not the same as one used by a person to send messages to the wiki since
|
paul@51 | 180 | only the public key is available to the wiki when verifying such messages,
|
paul@51 | 181 | whereas the signing of messages requires access to a private key. Thus, the
|
paul@51 | 182 | signing process employs a special private key known to the wiki for a user.
|
paul@12 | 183 |
|
paul@65 | 184 | If a wiki is to perform message relaying, the special relaying user must be
|
paul@65 | 185 | defined in this mapping together with an appropriate key fingerprint. You can
|
paul@65 | 186 | use the key generated during the wiki's configuration (see "Configuring GPG
|
paul@65 | 187 | for a Wiki" above) for this purpose. This fingerprint can then be used by
|
paul@65 | 188 | partner wikis in their fingerprint-to-user mapping in order to verify incoming
|
paul@65 | 189 | messages and to process them as relayed messages.
|
paul@65 | 190 |
|
paul@12 | 191 | The Recipients Mapping
|
paul@12 | 192 | ----------------------
|
paul@12 | 193 |
|
paul@12 | 194 | The mapping from recipients to remote URLs and fingerprints typically defined
|
paul@12 | 195 | by the MoinMessageRecipientsDict page is a WikiDict having the following
|
paul@12 | 196 | general format:
|
paul@12 | 197 |
|
paul@43 | 198 | recipient:: type location [ fingerprint ]
|
paul@27 | 199 |
|
paul@43 | 200 | Where the type is "page", the accompanying location must be a page name
|
paul@28 | 201 | indicating a page that provides a message store that will accept messages.
|
paul@63 | 202 | The affected page resides on the same wiki and is thus a bare page name, not
|
paul@63 | 203 | the URL of a page on the same or another wiki.
|
paul@12 | 204 |
|
paul@43 | 205 | Where the type is "url", the accompanying location must be a URL that must
|
paul@43 | 206 | itself refer to a resource that can accept MoinMessage content.
|
paul@12 | 207 |
|
paul@43 | 208 | Where a type of "url" has been given, a fingerprint must accompany this
|
paul@43 | 209 | information in order to encrypt messages sent to the specified resource.
|
paul@27 | 210 |
|
paul@51 | 211 | Each fingerprint corresponds to a key used by the wiki to encrypt messages and
|
paul@27 | 212 | by the remote site (as identified by the URL) to decrypt messages.
|
paul@12 | 213 |
|
paul@55 | 214 | Each wiki user can have their own recipients mapping by making a page, called
|
paul@55 | 215 | MoinMessageRecipientsDict unless overridden by the configuration, as a subpage
|
paul@55 | 216 | of their own home page.
|
paul@55 | 217 |
|
paul@11 | 218 | Quick Start: Signing, Encrypting and Sending Messages
|
paul@11 | 219 | -----------------------------------------------------
|
paul@11 | 220 |
|
paul@11 | 221 | To send a message signed and encrypted to a resource on localhost:
|
paul@11 | 222 |
|
paul@12 | 223 | python tests/test_send.py 1C1AAF83 0891463A http://localhost/wiki/ShareTest \
|
paul@51 | 224 | collection update 'An update to the wiki.' 'Another update.'
|
paul@11 | 225 |
|
paul@11 | 226 | Here, the first identifier is a reference to the signing key (over which you
|
paul@11 | 227 | have complete control), and the second identifier is a reference to the
|
paul@51 | 228 | encryption key (which is a public key published for the wiki).
|
paul@11 | 229 |
|
paul@11 | 230 | This needs password protection to be removed from the secret key in the Web
|
paul@12 | 231 | server environment. It also uses a modified trust model when invoking gpg in
|
paul@12 | 232 | order to avoid complaints about the identity of the sender during encryption.
|
paul@11 | 233 |
|
paul@45 | 234 | To sign the encrypted message for forwarding, the above command is modified:
|
paul@45 | 235 |
|
paul@45 | 236 | python tests/test_send.py 1C1AAF83 0891463A --forward 1C1AAF83 \
|
paul@45 | 237 | http://localhost/wiki/ShareTest \
|
paul@51 | 238 | collection update 'An update to the wiki.' 'Another update.'
|
paul@45 | 239 |
|
paul@11 | 240 | Below, the mechanisms employed are illustrated through the use of the other
|
paul@11 | 241 | test programs.
|
paul@11 | 242 |
|
paul@11 | 243 | Signing
|
paul@11 | 244 | -------
|
paul@11 | 245 |
|
paul@11 | 246 | Prepare a message signed with a "detached signature" (note that this does not
|
paul@11 | 247 | seem to be what gpg calls a detached signature with the --detach-sig option):
|
paul@11 | 248 |
|
paul@51 | 249 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@16 | 250 | 'Another update.' \
|
paul@11 | 251 | | python tests/test_sign.py 1C1AAF83
|
paul@11 | 252 |
|
paul@11 | 253 | The complicated recipe based on the individual operations is as follows:
|
paul@11 | 254 |
|
paul@51 | 255 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@16 | 256 | 'Another update.' \
|
paul@11 | 257 | > test.txt \
|
paul@11 | 258 | && cat test.txt \
|
paul@11 | 259 | | gpg --armor -u 1C1AAF83 --detach-sig \
|
paul@11 | 260 | | python tests/test_sign_wrap.py test.txt
|
paul@11 | 261 |
|
paul@11 | 262 | Encryption
|
paul@11 | 263 | ----------
|
paul@11 | 264 |
|
paul@11 | 265 | Prepare a message with an encrypted payload using the above key:
|
paul@11 | 266 |
|
paul@51 | 267 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@16 | 268 | 'Another update.' \
|
paul@11 | 269 | | python tests/test_encrypt.py 0891463A
|
paul@11 | 270 |
|
paul@11 | 271 | The complicated recipe based on the individual operations is as follows:
|
paul@11 | 272 |
|
paul@51 | 273 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@16 | 274 | 'Another update.' \
|
paul@11 | 275 | > test.txt \
|
paul@11 | 276 | && cat test.txt \
|
paul@11 | 277 | | gpg --armor -r 0891463A --encrypt --trust-model always \
|
paul@11 | 278 | | python tests/test_encrypt_wrap.py
|
paul@11 | 279 |
|
paul@11 | 280 | Note that "--trust-model always" is used only to avoid prompting issues.
|
paul@11 | 281 |
|
paul@11 | 282 | Signing and Encrypting
|
paul@11 | 283 | ----------------------
|
paul@11 | 284 |
|
paul@12 | 285 | Sign and encrypt a message:
|
paul@11 | 286 |
|
paul@51 | 287 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@16 | 288 | 'Another update.' \
|
paul@11 | 289 | | python tests/test_sign.py 1C1AAF83 \
|
paul@11 | 290 | | python tests/test_encrypt.py 0891463A
|
paul@11 | 291 |
|
paul@11 | 292 | The complicated recipe based on the individual operations is as follows:
|
paul@11 | 293 |
|
paul@51 | 294 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@16 | 295 | 'Another update.' \
|
paul@11 | 296 | > test.txt \
|
paul@11 | 297 | && cat test.txt \
|
paul@11 | 298 | | gpg --armor -u 1C1AAF83 --detach-sig \
|
paul@11 | 299 | | python tests/test_sign_wrap.py test.txt \
|
paul@11 | 300 | | gpg --armor -r 0891463A --encrypt --trust-model always \
|
paul@11 | 301 | | python tests/test_encrypt_wrap.py
|
paul@11 | 302 |
|
paul@45 | 303 | Signing and Encrypting then Signing
|
paul@45 | 304 | -----------------------------------
|
paul@45 | 305 |
|
paul@45 | 306 | Where a message is to be forwarded and not decrypted, it will be signed by the
|
paul@45 | 307 | author, encrypted, but then signed by the forwarder (perhaps initially the
|
paul@45 | 308 | author):
|
paul@45 | 309 |
|
paul@51 | 310 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@45 | 311 | 'Another update.' \
|
paul@45 | 312 | | python tests/test_sign.py 1C1AAF83 \
|
paul@45 | 313 | | python tests/test_encrypt.py 0891463A \
|
paul@45 | 314 | | python tests/test_sign.py 1C1AAF83
|
paul@45 | 315 |
|
paul@45 | 316 | The complicated recipe based on the individual operations is as follows:
|
paul@45 | 317 |
|
paul@51 | 318 | python tests/test_message.py collection update 'An update to the wiki.' \
|
paul@45 | 319 | 'Another update.' \
|
paul@45 | 320 | > test.txt \
|
paul@45 | 321 | && cat test.txt \
|
paul@45 | 322 | | gpg --armor -u 1C1AAF83 --detach-sig \
|
paul@45 | 323 | | python tests/test_sign_wrap.py test.txt \
|
paul@45 | 324 | | gpg --armor -r 0891463A --encrypt --trust-model always \
|
paul@45 | 325 | | python tests/test_encrypt_wrap.py \
|
paul@45 | 326 | > test2.txt \
|
paul@45 | 327 | && cat test2.txt \
|
paul@45 | 328 | | gpg --armor -u 1C1AAF83 --detach-sig \
|
paul@45 | 329 | | python tests/test_sign_wrap.py test2.txt
|
paul@45 | 330 |
|
paul@11 | 331 | Posting a Message
|
paul@11 | 332 | -----------------
|
paul@11 | 333 |
|
paul@11 | 334 | To post a signed and/or encrypted message, output from the above activities
|
paul@11 | 335 | can be piped into the following command:
|
paul@11 | 336 |
|
paul@12 | 337 | python tests/test_post.py http://localhost/wiki/ShareTest
|
paul@11 | 338 |
|
paul@11 | 339 | Here, the resource "/wiki/ShareTest" on localhost is presented with the
|
paul@11 | 340 | message.
|
paul@16 | 341 |
|
paul@32 | 342 | Fetching Messages
|
paul@32 | 343 | -----------------
|
paul@32 | 344 |
|
paul@32 | 345 | To fetch messages from a message store associated with a page, the following
|
paul@32 | 346 | command can be used:
|
paul@32 | 347 |
|
paul@32 | 348 | python tests/test_fetch.py 1C1AAF83 0891463A http://localhost/wiki/ShareTest \
|
paul@32 | 349 | RETR
|
paul@32 | 350 |
|
paul@32 | 351 | This should retrieve all messages from the store associated with the
|
paul@32 | 352 | "/wiki/ShareTest" resource on localhost.
|
paul@32 | 353 |
|
paul@16 | 354 | The Message Format
|
paul@16 | 355 | ------------------
|
paul@16 | 356 |
|
paul@16 | 357 | Messages are MIME-encoded and consist of one or more update fragments. Where
|
paul@16 | 358 | the "Update-Type" header is present and set to a value of "collection", a
|
paul@16 | 359 | multipart message describes as many updates as there are parts. Otherwise,
|
paul@16 | 360 | only a single update is described by the message.
|
paul@16 | 361 |
|
paul@16 | 362 | For each update, the "Update-Action" header indicates the action to be taken
|
paul@16 | 363 | with the update content. Where it is absent, the content is inserted into the
|
paul@51 | 364 | wiki page specified in the request; where it is present and set to "replace",
|
paul@51 | 365 | the content replaces all content on the wiki page; where it is set to "store",
|
paul@51 | 366 | the content is stored in a message store associated with the wiki page.
|
paul@16 | 367 |
|
paul@16 | 368 | Each update may describe multiple representations of some content by employing
|
paul@44 | 369 | a multipart/alternative section containing parts for each of the
|
paul@44 | 370 | representations. Alternatively, a single message part may describe a single
|
paul@44 | 371 | representation.
|
paul@44 | 372 |
|
paul@44 | 373 | HTTP Methods
|
paul@44 | 374 | ------------
|
paul@44 | 375 |
|
paul@44 | 376 | Since MoinMoin seems to reserve POST methods for request/entity bodies that
|
paul@44 | 377 | contain HTML form data, it is necessary to use alternative methods to post
|
paul@44 | 378 | messages to a site served by MoinMoin and to fetch messages from such a site.
|
paul@57 | 379 | Consequently, MoinMessage uses PUT to post and fetch messages. Unfortunately,
|
paul@57 | 380 | MoinMoin 1.9 prevents the use of GET with request/entity bodies, and so the
|
paul@57 | 381 | natural usage of GET to fetch messages cannot be employed.
|
paul@54 | 382 |
|
paul@54 | 383 | Contact, Copyright and Licence Information
|
paul@54 | 384 | ------------------------------------------
|
paul@54 | 385 |
|
paul@54 | 386 | See the following Web page for more information about this work:
|
paul@54 | 387 |
|
paul@54 | 388 | http://moinmo.in/ActionMarket/MoinMessage
|
paul@54 | 389 |
|
paul@54 | 390 | The author can be contacted at the following e-mail address:
|
paul@54 | 391 |
|
paul@54 | 392 | paul@boddie.org.uk
|
paul@54 | 393 |
|
paul@54 | 394 | Copyright and licence information can be found in the docs directory - see
|
paul@54 | 395 | docs/COPYING.txt and docs/LICENCE.txt for more information.
|
paul@54 | 396 |
|
paul@54 | 397 | Dependencies
|
paul@54 | 398 | ------------
|
paul@54 | 399 |
|
paul@54 | 400 | MoinMessage has the following basic dependencies:
|
paul@54 | 401 |
|
paul@54 | 402 | Packages Release Information
|
paul@54 | 403 | -------- -------------------
|
paul@54 | 404 |
|
paul@54 | 405 | MoinSupport Tested with 0.4
|
paul@54 | 406 | Source: http://hgweb.boddie.org.uk/MoinSupport
|