python bindings howto: dita version
authorBen McGinnes <ben@adversary.org>
Thu, 28 Jun 2018 08:02:43 +0000 (18:02 +1000)
committerBen McGinnes <ben@adversary.org>
Thu, 28 Jun 2018 08:02:43 +0000 (18:02 +1000)
* Drafts of instructions for exporting public and secret keys ready,
  along in addition to the code.

12 files changed:
lang/python/docs/dita/gpgme-python-howto-footer.xhtml [new file with mode: 0644]
lang/python/docs/dita/gpgme-python-howto.ditamap
lang/python/docs/dita/gpgme-python.ditamap
lang/python/docs/dita/gpgmePython.xpr
lang/python/docs/dita/howto/part01/docs-source.dita
lang/python/docs/dita/howto/part03/exporting-pubkeys.dita [new file with mode: 0644]
lang/python/docs/dita/howto/part03/exporting-seckeys.dita [new file with mode: 0644]
lang/python/docs/dita/howto/part03/exporting.dita [new file with mode: 0644]
lang/python/docs/dita/howto/part03/importing.dita [new file with mode: 0644]
lang/python/docs/dita/howto/part04/decryption.dita
lang/python/docs/dita/howto/part06/group-lines.dita
lang/python/docs/dita/howto/version-info.dita

diff --git a/lang/python/docs/dita/gpgme-python-howto-footer.xhtml b/lang/python/docs/dita/gpgme-python-howto-footer.xhtml
new file mode 100644 (file)
index 0000000..77d681a
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title></title>
+  </head>
+  <body>
+    <div>Copyright © Benjamin D. McGinnes, 2018<br />for the <a href="https://gnupg.org/" target="_blank">GnuPG Project</a></div>
+  </body>
+</html>
\ No newline at end of file
index e66c9f4..1809acb 100644 (file)
       <topicref id="key-count" href="howto/part03/key-counting.dita"/>
     </topicref>
     <topicref id="get-key" href="howto/part03/get-key.dita"/>
+    <topicref id="import-key" href="howto/part03/importing.dita"/>
+    <topicref id="export-key" href="howto/part03/exporting.dita">
+      <topicref id="export-key-pub" href="howto/part03/exporting-pubkeys.dita"/>
+      <topicref id="export-key-sec" href="howto/part03/exporting-seckeys.dita"/>
+    </topicref>
   </part>
   <part id="part-4" href="howto/part-4.dita">
     <topicref id="basics" href="howto/part04/basic-functions.dita"/>
@@ -87,4 +92,7 @@
   <part id="part-6" href="howto/part-6.dita">
     <topicref id="groups" href="howto/part06/group-lines.dita"/>
   </part>
+  <backmatter>
+    <mapref id="resources" href="resources.ditamap" processing-role="resource-only"/>
+  </backmatter>
 </bookmap>
index 5232dca..6b8926b 100644 (file)
@@ -3,4 +3,5 @@
 <map>
   <title>GPGME Python Bindings</title>
   <mapref id="howto-map" href="gpgme-python-howto.ditamap"/>
+  <mapref id="resources" href="resources.ditamap" processing-role="resource-only"/>
 </map>
index e8756fc..59fe977 100644 (file)
@@ -1,20 +1,35 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project version="20.0">
+<project version="20.1">
     <meta>
         <filters directoryPatterns="" filePatterns="gpgmePython.xpr" positiveFilePatterns="" showHiddenFiles="false"/>
         <options>
-            <serialized version="20.0" xml:space="preserve">
+            <serialized version="20.1" xml:space="preserve">
                 <serializableOrderedMap>
                     <entry>
                         <String>scenario.associations</String>
                         <scenarioAssociation-array>
                             <scenarioAssociation>
                                 <field name="url">
+                                    <String>gpgme-python.ditamap</String>
+                                </field>
+                                <field name="scenarioIds">
+                                    <list>
+                                        <String>DITA Map WebHelp - TS/HC - GPGME</String>
+                                    </list>
+                                </field>
+                                <field name="scenarioTypes">
+                                    <list>
+                                        <String>DITAMAP</String>
+                                    </list>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="url">
                                     <String>gpgme-python-howto.ditamap</String>
                                 </field>
                                 <field name="scenarioIds">
                                     <list>
-                                        <String>gpgme-python-howto (WebHelp Responsive)</String>
+                                        <String>DITA Map WebHelp - TS/HC - GPGME</String>
                                     </list>
                                 </field>
                                 <field name="scenarioTypes">
                                     <String>${cfd}</String>
                                 </field>
                                 <field name="outputDir">
+                                    <String>${cfd}/out/webhelp-${ddt}</String>
+                                </field>
+                                <field name="tempDir">
+                                    <String>${cfd}/temp/webhelp-${ddt}</String>
+                                </field>
+                                <field name="transtype">
+                                    <String>webhelp</String>
+                                </field>
+                                <field name="filters">
+                                    <ditavalFilters>
+                                        <field name="useDitavalFilePath">
+                                            <Boolean>false</Boolean>
+                                        </field>
+                                        <field name="useAppliedConditionSet">
+                                            <Boolean>true</Boolean>
+                                        </field>
+                                        <field name="appliedConditionSet">
+                                            <null/>
+                                        </field>
+                                        <field name="ditavalFilePath">
+                                            <null/>
+                                        </field>
+                                        <field name="simpleFiltersList">
+                                            <list/>
+                                        </field>
+                                    </ditavalFilters>
+                                </field>
+                                <field name="addOxygenJars">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="skinCssFile">
+                                    <String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
+                                </field>
+                                <field name="lastCustomSkinCssPath">
+                                    <String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
+                                </field>
+                                <field name="webhelpResponsiveTemplate">
+                                    <null/>
+                                </field>
+                                <field name="publishingTemplateDataPO">
+                                    <null/>
+                                </field>
+                                <field name="additionalAntArgs">
+                                    <String></String>
+                                </field>
+                                <field name="buildTarget">
+                                    <String></String>
+                                </field>
+                                <field name="buildFilePath">
+                                    <String></String>
+                                </field>
+                                <field name="ditaParams">
+                                    <list>
+                                        <ditaParameter>
+                                            <field name="name">
+                                                <String>args.xhtml.classattr</String>
+                                            </field>
+                                            <field name="description">
+                                                <null/>
+                                            </field>
+                                            <field name="value">
+                                                <String>yes</String>
+                                            </field>
+                                            <field name="defaultValue">
+                                                <String>yes</String>
+                                            </field>
+                                            <field name="type">
+                                                <Integer>4</Integer>
+                                            </field>
+                                            <field name="possibleValues">
+                                                <String-array>
+                                                    <String>yes</String>
+                                                    <String>no</String>
+                                                    <null/>
+                                                </String-array>
+                                            </field>
+                                            <field name="possibleValuesDescriptions">
+                                                <String-array>
+                                                    <String></String>
+                                                    <String></String>
+                                                </String-array>
+                                            </field>
+                                        </ditaParameter>
+                                        <ditaParameter>
+                                            <field name="name">
+                                                <String>webhelp.footer.include</String>
+                                            </field>
+                                            <field name="description">
+                                                <null/>
+                                            </field>
+                                            <field name="value">
+                                                <String>yes</String>
+                                            </field>
+                                            <field name="defaultValue">
+                                                <String>yes</String>
+                                            </field>
+                                            <field name="type">
+                                                <Integer>4</Integer>
+                                            </field>
+                                            <field name="possibleValues">
+                                                <String-array>
+                                                    <String>yes</String>
+                                                    <String>no</String>
+                                                    <null/>
+                                                </String-array>
+                                            </field>
+                                            <field name="possibleValuesDescriptions">
+                                                <String-array>
+                                                    <String>If the "webhelp.footer.file" parameter has a value, the content of that file is used as footer.              If "webhelp.footer.file" has no value, the default Oxygen footer is inserted in each Webhelp page.</String>
+                                                    <String>No footer is added to the Webhelp pages.</String>
+                                                </String-array>
+                                            </field>
+                                        </ditaParameter>
+                                        <ditaParameter>
+                                            <field name="name">
+                                                <String>webhelp.footer.file</String>
+                                            </field>
+                                            <field name="description">
+                                                <null/>
+                                            </field>
+                                            <field name="value">
+                                                <String>/Users/ben/dev/hgit/mine/gnupg/dita/gpgme/python/gpgme-python-howto-footer.xhtml</String>
+                                            </field>
+                                            <field name="defaultValue">
+                                                <null/>
+                                            </field>
+                                            <field name="type">
+                                                <Integer>2</Integer>
+                                            </field>
+                                            <field name="possibleValues">
+                                                <null/>
+                                            </field>
+                                            <field name="possibleValuesDescriptions">
+                                                <null/>
+                                            </field>
+                                        </ditaParameter>
+                                        <ditaParameter>
+                                            <field name="name">
+                                                <String>webhelp.copyright</String>
+                                            </field>
+                                            <field name="description">
+                                                <null/>
+                                            </field>
+                                            <field name="value">
+                                                <String>Copyright © Benjamin D. McGinnes, 2018</String>
+                                            </field>
+                                            <field name="defaultValue">
+                                                <null/>
+                                            </field>
+                                            <field name="type">
+                                                <Integer>0</Integer>
+                                            </field>
+                                            <field name="possibleValues">
+                                                <null/>
+                                            </field>
+                                            <field name="possibleValuesDescriptions">
+                                                <null/>
+                                            </field>
+                                        </ditaParameter>
+                                    </list>
+                                </field>
+                                <field name="jvmArgs">
+                                    <String>-Xmx384m</String>
+                                </field>
+                                <field name="useCustomJavaHome">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="customJavaHomeDir">
+                                    <String></String>
+                                </field>
+                                <field name="useCustomANTHome">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="customANTHomeDir">
+                                    <String></String>
+                                </field>
+                                <field name="workingDir">
+                                    <null/>
+                                </field>
+                                <field name="showConsoleAlways">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="advancedOptionsMap">
+                                    <null/>
+                                </field>
+                                <field name="name">
+                                    <String>DITA Map WebHelp - TS/HC - GPGME</String>
+                                </field>
+                                <field name="baseURL">
+                                    <null/>
+                                </field>
+                                <field name="footerURL">
+                                    <null/>
+                                </field>
+                                <field name="fOPMethod">
+                                    <null/>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <null/>
+                                </field>
+                                <field name="headerURL">
+                                    <null/>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <null/>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <null/>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String>DITAMAP</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <null/>
+                                </field>
+                                <field name="outputResource">
+                                    <null/>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInResultSetPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list/>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String>DITA-OT</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </ditaScenario>
+                            <ditaScenario>
+                                <field name="useXEP">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="useAntennaHouse">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="baseDir">
+                                    <String>${cfd}</String>
+                                </field>
+                                <field name="outputDir">
+                                    <String>${cfd}/out/html5-${ddt}</String>
+                                </field>
+                                <field name="tempDir">
+                                    <String>${cfd}/temp/html5-${ddt}</String>
+                                </field>
+                                <field name="transtype">
+                                    <String>html5</String>
+                                </field>
+                                <field name="filters">
+                                    <ditavalFilters>
+                                        <field name="useDitavalFilePath">
+                                            <Boolean>false</Boolean>
+                                        </field>
+                                        <field name="useAppliedConditionSet">
+                                            <Boolean>true</Boolean>
+                                        </field>
+                                        <field name="appliedConditionSet">
+                                            <null/>
+                                        </field>
+                                        <field name="ditavalFilePath">
+                                            <null/>
+                                        </field>
+                                        <field name="simpleFiltersList">
+                                            <list/>
+                                        </field>
+                                    </ditavalFilters>
+                                </field>
+                                <field name="addOxygenJars">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="skinCssFile">
+                                    <String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
+                                </field>
+                                <field name="lastCustomSkinCssPath">
+                                    <String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
+                                </field>
+                                <field name="webhelpResponsiveTemplate">
+                                    <null/>
+                                </field>
+                                <field name="publishingTemplateDataPO">
+                                    <null/>
+                                </field>
+                                <field name="additionalAntArgs">
+                                    <String></String>
+                                </field>
+                                <field name="buildTarget">
+                                    <String></String>
+                                </field>
+                                <field name="buildFilePath">
+                                    <String></String>
+                                </field>
+                                <field name="ditaParams">
+                                    <list/>
+                                </field>
+                                <field name="jvmArgs">
+                                    <String>-Xmx384m</String>
+                                </field>
+                                <field name="useCustomJavaHome">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="customJavaHomeDir">
+                                    <String></String>
+                                </field>
+                                <field name="useCustomANTHome">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="customANTHomeDir">
+                                    <String></String>
+                                </field>
+                                <field name="workingDir">
+                                    <null/>
+                                </field>
+                                <field name="showConsoleAlways">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="advancedOptionsMap">
+                                    <null/>
+                                </field>
+                                <field name="name">
+                                    <String>gpgme-python (HTML5)</String>
+                                </field>
+                                <field name="baseURL">
+                                    <null/>
+                                </field>
+                                <field name="footerURL">
+                                    <null/>
+                                </field>
+                                <field name="fOPMethod">
+                                    <null/>
+                                </field>
+                                <field name="fOProcessorName">
+                                    <null/>
+                                </field>
+                                <field name="headerURL">
+                                    <null/>
+                                </field>
+                                <field name="inputXSLURL">
+                                    <null/>
+                                </field>
+                                <field name="inputXMLURL">
+                                    <null/>
+                                </field>
+                                <field name="defaultScenario">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="isFOPPerforming">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="type">
+                                    <String>DITAMAP</String>
+                                </field>
+                                <field name="saveAs">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="openInBrowser">
+                                    <Boolean>true</Boolean>
+                                </field>
+                                <field name="outputFile">
+                                    <null/>
+                                </field>
+                                <field name="outputResource">
+                                    <null/>
+                                </field>
+                                <field name="openOtherLocationInBrowser">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="locationToOpenInBrowserURL">
+                                    <String></String>
+                                </field>
+                                <field name="openInEditor">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInHTMLPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInXMLPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInSVGPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="showInResultSetPane">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="useXSLTInput">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="xsltParams">
+                                    <list/>
+                                </field>
+                                <field name="cascadingStylesheets">
+                                    <String-array/>
+                                </field>
+                                <field name="xslTransformer">
+                                    <String>DITA-OT</String>
+                                </field>
+                                <field name="extensionURLs">
+                                    <String-array/>
+                                </field>
+                            </ditaScenario>
+                            <ditaScenario>
+                                <field name="useXEP">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="useAntennaHouse">
+                                    <Boolean>false</Boolean>
+                                </field>
+                                <field name="baseDir">
+                                    <String>${cfd}</String>
+                                </field>
+                                <field name="outputDir">
                                     <String>${cfd}/out/html5</String>
                                 </field>
                                 <field name="tempDir">
index 8e97a35..7c90b59 100644 (file)
         <ol id="ol_k3b_wrx_5db">
           <li>A <xref href="https://dev.gnupg.org/T3977" format="html" scope="external">bug</xref>
             in either Org-Mode or Babel prevented the more complex examples included in the HOWTO
-            from displaying correctly.</li>
+            from displaying correctly while also retaining syntax highlighting.</li>
           <li>To demonstrate some of the advantages of DITA XML over existing documentation
             production software used in the project (particularly Texinfo and LaTeX).</li>
         </ol>
       </p>
-      <p>The XML format definitely supports displaying all the more complex Python code correctly,
-        as well as being designed to produce standards compliant print and HTML output.  Whereas
-        currently the existing tools utilised by the GnuPG Project can't display the example code in
-        a way which would actually pass the project's own git commit ruleset.</p>
+      <p>The XML format definitely supports displaying all the more complex Python code correctly
+        with syntax highlighting, as well as being designed to produce standards compliant print and
+        HTML output. Whereas currently the existing tools utilised by the GnuPG Project can't
+        display the example code in a way which would actually pass the project's own git commit
+        ruleset.</p>
       <p> </p>
         </body>
     </topic>
diff --git a/lang/python/docs/dita/howto/part03/exporting-pubkeys.dita b/lang/python/docs/dita/howto/part03/exporting-pubkeys.dita
new file mode 100644 (file)
index 0000000..8ae4f5b
--- /dev/null
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
+<dita xml:lang="en-GB">
+  <topic id="exporting-pubkeys">
+    <title>Exporting Public Keys</title>
+    <body>
+      <p>There are two methods of exporting public keys, both of which are very similar to the
+        other. The default method, <codeph>key_export()</codeph> will export a public key or keys
+        matching a specified pattern as normal. The alternative, the
+          <codeph>key_export_minimal()</codeph> method will do the same thing except producing a
+        minimised output with extra signatures and third party signatures or certifications
+        removed.</p>
+      <p>
+        <codeblock id="export-pubkey-01" outputclass="language-python">import gpg
+import os.path
+import sys
+
+print("""
+This script exports one or more public keys.
+""")
+
+c = gpg.Context(armor=True)
+
+if len(sys.argv) >= 4:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = sys.argv[3]
+elif len(sys.argv) == 3:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+elif len(sys.argv) == 2:
+    keyfile = sys.argv[1]
+    logrus = input("Enter the UID matching the key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+else:
+    keyfile = input("Enter the path and filename to save the secret key to: ")
+    logrus = input("Enter the UID matching the key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+
+if homedir.startswith("~"):
+    if os.path.exists(os.path.expanduser(homedir)) is True:
+        c.home_dir = os.path.expanduser(homedir)
+    else:
+        pass
+elif os.path.exists(homedir) is True:
+    c.home_dir = homedir
+else:
+    pass
+
+try:
+    result = c.key_export(pattern=logrus)
+except:
+    result = c.key_export(pattern=None)
+
+if result is not None:
+    with open(keyfile, "wb") as f:
+        f.write(result)
+else:
+    pass
+</codeblock>
+      </p>
+      <p>It is important to note that the <codeph>result</codeph> will only return
+          <codeph>None</codeph> when a pattern has been entered for <varname>logrus</varname>, but
+        it has not matched any keys. When the search pattern itself is set to <codeph>None</codeph>
+        this triggers the exporting of the entire public keybox.</p>
+      <p>
+        <codeblock id="export-pubkey-02" outputclass="language-python">import gpg
+import os.path
+import sys
+
+print("""
+This script exports one or more public keys in minimised form.
+""")
+
+c = gpg.Context(armor=True)
+
+if len(sys.argv) >= 4:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = sys.argv[3]
+elif len(sys.argv) == 3:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+elif len(sys.argv) == 2:
+    keyfile = sys.argv[1]
+    logrus = input("Enter the UID matching the key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+else:
+    keyfile = input("Enter the path and filename to save the secret key to: ")
+    logrus = input("Enter the UID matching the key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+
+if homedir.startswith("~"):
+    if os.path.exists(os.path.expanduser(homedir)) is True:
+        c.home_dir = os.path.expanduser(homedir)
+    else:
+        pass
+elif os.path.exists(homedir) is True:
+    c.home_dir = homedir
+else:
+    pass
+
+try:
+    result = c.key_export_minimal(pattern=logrus)
+except:
+    result = c.key_export_minimal(pattern=None)
+
+if result is not None:
+    with open(keyfile, "wb") as f:
+        f.write(result)
+else:
+    pass
+</codeblock>
+      </p>
+      <p/>
+    </body>
+  </topic>
+</dita>
diff --git a/lang/python/docs/dita/howto/part03/exporting-seckeys.dita b/lang/python/docs/dita/howto/part03/exporting-seckeys.dita
new file mode 100644 (file)
index 0000000..9093aa0
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
+<dita xml:lang="en-GB">
+  <topic id="exporting-seckeys">
+    <title>Exporting Secret Keys</title>
+    <body>
+      <p>Exporting secret keys is, functionally, very similar to exporting public keys; save for the
+        invocation of <cmdname>pinentry</cmdname> via <cmdname>gpg-agent</cmdname> in order to
+        securely enter the key's passphrase and authorise the export.</p>
+      <p>The following example exports the secret key to a file which is then set with the same
+        permissions as the output files created by the command line secret key export options.</p>
+      <p>
+        <codeblock id="export-seckey-01" outputclass="language-python">import gpg
+import os
+import os.path
+import sys
+
+print("""
+This script exports one or more secret keys.
+
+The gpg-agent and pinentry are invoked to authorise the export.
+""")
+
+c = gpg.Context(armor=True)
+
+if len(sys.argv) >= 4:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = sys.argv[3]
+elif len(sys.argv) == 3:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+elif len(sys.argv) == 2:
+    keyfile = sys.argv[1]
+    logrus = input("Enter the UID matching the secret key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+else:
+    keyfile = input("Enter the path and filename to save the secret key to: ")
+    logrus = input("Enter the UID matching the secret key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+
+if homedir.startswith("~"):
+    if os.path.exists(os.path.expanduser(homedir)) is True:
+        c.home_dir = os.path.expanduser(homedir)
+    else:
+        pass
+elif os.path.exists(homedir) is True:
+    c.home_dir = homedir
+else:
+    pass
+
+try:
+    result = c.key_export_secret(pattern=logrus)
+except:
+    result = c.key_export_secret(pattern=None)
+
+if result is not None:
+    with open(keyfile, "wb") as f:
+        f.write(result)
+    os.chmod(keyfile, 0o600)
+else:
+    pass
+</codeblock>
+      </p>
+      <p>Alternatively the approach of the following script can be used. This longer example saves
+        the exported secret key(s) in files in the GnuPG home directory, in addition to setting the
+        file permissions as only readable and writable by the user. It also exports the secret
+        key(s) twice in order to output both GPG binary (<codeph>.gpg</codeph>) and ASCII armoured
+          (<codeph>.asc</codeph>) files.</p>
+      <p>
+        <codeblock id="export-seckey-02" outputclass="language-python">import gpg
+import os
+import os.path
+import subprocess
+import sys
+
+print("""
+This script exports one or more secret keys as both ASCII armored and binary
+file formats, saved in files within the user's GPG home directory.
+
+The gpg-agent and pinentry are invoked to authorise the export.
+""")
+
+if sys.platform == "win32":
+    gpgconfcmd = "gpgconf.exe --list-dirs homedir"
+else:
+    gpgconfcmd = "gpgconf --list-dirs homedir"
+
+a = gpg.Context(armor=True)
+b = gpg.Context()
+c = gpg.Context()
+
+if len(sys.argv) >= 4:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = sys.argv[3]
+elif len(sys.argv) == 3:
+    keyfile = sys.argv[1]
+    logrus = sys.argv[2]
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+elif len(sys.argv) == 2:
+    keyfile = sys.argv[1]
+    logrus = input("Enter the UID matching the secret key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+else:
+    keyfile = input("Enter the filename to save the secret key to: ")
+    logrus = input("Enter the UID matching the secret key(s) to export: ")
+    homedir = input("Enter the GPG configuration directory path (optional): ")
+
+if homedir.startswith("~"):
+    if os.path.exists(os.path.expanduser(homedir)) is True:
+        c.home_dir = os.path.expanduser(homedir)
+    else:
+        pass
+elif os.path.exists(homedir) is True:
+    c.home_dir = homedir
+else:
+    pass
+
+if c.home_dir is not None:
+    if c.home_dir.endswith("/"):
+        gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile)
+        ascfile = "{0}{1}.asc".format(c.home_dir, keyfile)
+    else:
+        gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile)
+        ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile)
+else:
+    if os.path.exists(os.environ["GNUPGHOME"]) is True:
+        hd = os.environ["GNUPGHOME"]
+    else:
+        hd = subprocess.getoutput(gpgconfcmd)
+    gpgfile = "{0}/{1}.gpg".format(hd, keyfile)
+    ascfile = "{0}/{1}.asc".format(hd, keyfile)
+
+try:
+    a_result = a.key_export_secret(pattern=logrus)
+    b_result = b.key_export_secret(pattern=logrus)
+except:
+    a_result = a.key_export_secret(pattern=None)
+    b_result = b.key_export_secret(pattern=None)
+
+if a_result is not None:
+    with open(ascfile, "wb") as f:
+        f.write(a_result)
+    os.chmod(ascfile, 0o600)
+else:
+    pass
+
+if b_result is not None:
+    with open(gpgfile, "wb") as f:
+        f.write(b_result)
+    os.chmod(gpgfile, 0o600)
+else:
+    pass
+</codeblock>
+      </p>
+      <p/>
+    </body>
+  </topic>
+</dita>
diff --git a/lang/python/docs/dita/howto/part03/exporting.dita b/lang/python/docs/dita/howto/part03/exporting.dita
new file mode 100644 (file)
index 0000000..8c054af
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
+<dita xml:lang="en-GB">
+  <topic id="exporting-keys">
+    <title>Exporting Keys</title>
+    <body>
+      <p>Exporting keys remains a reasonably simple task, but has been separated into three
+        different functions for the OpenPGP cryptographic engine. Two of those functions are for
+        exporting public keys and the third is for exporting secret keys.</p>
+    </body>
+  </topic>
+</dita>
diff --git a/lang/python/docs/dita/howto/part03/importing.dita b/lang/python/docs/dita/howto/part03/importing.dita
new file mode 100644 (file)
index 0000000..267eb94
--- /dev/null
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
+<dita xml:lang="en-GB">
+  <topic id="importing-keys">
+    <title>Importing keys</title>
+    <body>
+      <p>Importing keys is possible with the <codeph>key_import()</codeph> method and takes one
+        argument which is a bytes literal object containing either the binary or ASCII armoured key
+        data for one or more keys.</p>
+      <p>The following example retrieves one or more keys from the SKS keyservers via the web using
+        the requests module. Since requests returns the content as a bytes literal object, we can
+        then use that directly to import the resulting data into our keybox.</p>
+      <p>
+        <codeblock id="key-import-01" outputclass="language-python">import gpg
+import os.path
+import requests
+
+c = gpg.Context()
+url = "https://sks-keyservers.net/pks/lookup"
+pattern = input("Enter the pattern to search for key or user IDs: ")
+payload = { "op": "get", "search": pattern }
+
+r = requests.get(url, verify=True, params=payload)
+result = c.key_import(r.content)
+
+if result is not None and hasattr(result, "considered") is False:
+    print(result)
+elif result is not None and hasattr(result, "considered") is True:
+    num_keys = len(result.imports)
+    new_revs = result.new_revocations
+    new_sigs = result.new_signatures
+    new_subs = result.new_sub_keys
+    new_uids = result.new_user_ids
+    new_scrt = result.secret_imported
+    nochange = result.unchanged
+    print("""
+The total number of keys considered for import was:  {0}
+
+   Number of keys revoked:  {1}
+ Number of new signatures:  {2}
+    Number of new subkeys:  {3}
+   Number of new user IDs:  {4}
+Number of new secret keys:  {5}
+ Number of unchanged keys:  {6}
+
+The key IDs for all considered keys were:
+""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
+           nochange))
+    for i in range(num_keys):
+       print(result.imports[i].fpr)
+    print("")
+else:
+    pass
+</codeblock>
+      </p>
+      <p>
+        <note>When searching for a key ID of any length or a fingerprint (without spaces), the SKS
+          servers require the the leading <codeph>0x</codeph> indicative of hexadecimal be included.
+          Also note that the old short key IDs (e.g. <codeph>0xDEADBEEF</codeph>) should no longer
+          be used due to the relative ease by which such key IDs can be reproduced, as demonstrated
+          by the <xref href="https://evil32.com/" format="html" scope="external">Evil32
+            Project</xref> in 2014 (which was subsequently exploited in 2016).</note>
+      </p>
+      <p/>
+    </body>
+  </topic>
+</dita>
index 41a4650..bb8c368 100644 (file)
@@ -30,9 +30,20 @@ else:
     pass
 </codeblock>
       </p>
-      <p>The data available in <codeph>plaintext</codeph> in this example is the decrypted content
-        as a byte object, the recipient key IDs and algorithms in <codeph>result</codeph> and the
-        results of verifying any signatures of the data in <codeph>verify_result</codeph>.</p>
+      <p>The data available in <codeph>plaintext</codeph> following a successful decryption in this
+        example is the decrypted content as a byte object, the recipient key IDs and algorithms in
+          <codeph>result</codeph> and the results of verifying any signatures of the data in
+          <codeph>verify_result</codeph>.</p>
+      <p>
+        <note>The graceful handling of <codeph>GPGMEError</codeph> with the try/except statement is
+          to handle the decryption error message produced if the file <codeph>ciphertext</codeph>,
+          and thus <codeph>cfile</codeph>, are encrypted with deprecated and insecure methods.
+          Particularly without MDC integrity checks or utilising deprecated encryption algorithms.
+          Messages and files encrypted with these are not decrypted with GPGME at all and any user
+          requiring archival access will need to access it manually with pre-GnuPG 2.3 versions of
+          the software which meets the requirements of the specific use case.</note>
+      </p>
+      <p/>
     </body>
   </topic>
 </dita>
index f4aca74..1dbfc97 100644 (file)
@@ -44,6 +44,10 @@ for i in range(len(group_lists)):
       <p>
         <codeblock id="groups-2" outputclass="language-python">from groups import group_lists</codeblock>
       </p>
+          <p>A demonstration of using the <filepath>groups.py</filepath> module is also available in
+            the form of the executable <cmdname>mutt-groups.py</cmdname> script. This second script
+        reads all the group entries in a user's <filepath>gpg.conf</filepath> file and converts them
+        into crypt-hooks suitable for use with the Mutt and Neomutt mail clients.</p>
         </body>
     </topic>
 </dita>
index 6776820..f9bb42a 100644 (file)
@@ -4,10 +4,12 @@
   <topic id="topic_vnz_nn2_vdb">
     <title>Documentation Version</title>
     <body>
-      <p><b>Version:</b> 0.1.1</p>
+      <p><b>Version:</b> 0.1.2-DRAFT</p>
       <p><b>Author:</b> Ben McGinnes &lt;<xref href="mailto:ben@gnupg.org" format="html"
           scope="external">ben@gnupg.org</xref>></p>
-      <p><b>Author GPG Key ID:</b> DB4724E6FA4286C92B4E55C4321E4E2373590E5D</p>
+      <p><b>Author GPG Key ID:</b>
+        <xref href="http://files.au.adversary.org/crypto/ben-key.asc" format="text" scope="external"
+          >DB4724E6FA4286C92B4E55C4321E4E2373590E5D</xref></p>
       <p><b>Language:</b> Australian English, British English</p>
     </body>
   </topic>