python bindings: import keys
* Adapted from prior submissions by Tobias Mueller and Jacob Adams. * key_import function added to gpg.core.Context(). * Two example scripts added to to examples/howto: import-key-file.py imports keys from a local file and import-keys.py accesses the SKS keyserver pool using the requests module to search for keys (includes check for key IDs which may not include the leading 0x). * Added documentation demonstrating the use of the key_import() function with a large number of keys matching one domain (eff.org; the example shows how EFF staff are following their own advice issued last month).
This commit is contained in:
parent
2c4c569247
commit
167847f1bc
@ -454,6 +454,85 @@
|
||||
literals with the fingerprint when getting a key in this way.
|
||||
|
||||
|
||||
** Importing keys
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: howto-import-key
|
||||
:END:
|
||||
|
||||
Importing keys is possible with the =key_import()= 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.
|
||||
|
||||
In the following example a key will be retrieved 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. In order to
|
||||
demonstrate multiple imports this example searches for all the keys
|
||||
of users at a particular domain name; in this case the EFF.
|
||||
|
||||
#+begin_src python
|
||||
import gpg
|
||||
import os.path
|
||||
import requests
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
pattern = input("The pattern to search for in key or user IDs: ")
|
||||
url = "https://sks-keyservers.net/pks/lookup"
|
||||
payload = { "op": "get", "search": pattern }
|
||||
|
||||
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
|
||||
|
||||
r = requests.get(url, verify=True, params=payload)
|
||||
incoming = c.key_import(r.content)
|
||||
|
||||
summary = """
|
||||
Total number of keys: {0}
|
||||
Total number imported: {1}
|
||||
Number of version 3 keys ignored: {2}
|
||||
|
||||
Number of imported key objects or updates: {3}
|
||||
Number of unchanged keys: {4}
|
||||
Number of new signatures: {5}
|
||||
Number of revoked keys: {6}
|
||||
""".format(incoming.considered, len(incoming.imports),
|
||||
incoming.skipped_v3_keys, incoming.imported, incoming.unchanged,
|
||||
incoming.new_signatures, incoming.new_revocations)
|
||||
|
||||
print(summary)
|
||||
#+end_src
|
||||
|
||||
The resulting output in that case, where the search pattern entered
|
||||
was =@eff.org= was:
|
||||
|
||||
#+begin_src shell
|
||||
Total number of keys: 272
|
||||
Total number imported: 249
|
||||
Number of version 3 keys ignored: 23
|
||||
|
||||
Number of imported key objects or updates: 180
|
||||
Number of unchanged keys: 66
|
||||
Number of new signatures: 7
|
||||
Number of revoked keys: 0
|
||||
#+end_src
|
||||
|
||||
The examples for this document in =lang/python/examples/howto/ now
|
||||
include to variations of this; one for searching the SKS keyserver
|
||||
pool and the other for importing from a local file.
|
||||
|
||||
The example above and the corresponding executable script included
|
||||
in the examples requires Kenneth Reitz's excellent [[http://docs.python-requests.org/en/master/][Requests module]].
|
||||
|
||||
|
||||
* Basic Functions
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: howto-the-basics
|
||||
|
70
lang/python/examples/howto/import-key-file.py
Executable file
70
lang/python/examples/howto/import-key-file.py
Executable file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||
# Lesser General Public Licensefor more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License and the GNU
|
||||
# Lesser General Public along with this program; if not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
import gpg
|
||||
import os.path
|
||||
|
||||
print("""
|
||||
This script imports a key or keys matching a pattern from the SKS keyserver
|
||||
pool.
|
||||
""")
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
keyfile = input("Enter the path and filename to the file of key(s): ")
|
||||
|
||||
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
|
||||
|
||||
with open(keyfile, "rb") as f:
|
||||
kdata = f.read()
|
||||
|
||||
incoming = c.key_import(kdata)
|
||||
|
||||
summary = """
|
||||
Total number of keys: {0}
|
||||
Total number imported: {1}
|
||||
Number of version 3 keys ignored: {2}
|
||||
|
||||
Number of imported key objects or updates: {3}
|
||||
Number of unchanged keys: {4}
|
||||
Number of new signatures: {5}
|
||||
Number of revoked keys: {6}
|
||||
""".format(incoming.considered, len(incoming.imports),
|
||||
incoming.skipped_v3_keys, incoming.imported, incoming.unchanged,
|
||||
incoming.new_signatures, incoming.new_revocations)
|
||||
|
||||
print(summary)
|
||||
|
||||
# EOF
|
78
lang/python/examples/howto/import-keys.py
Executable file
78
lang/python/examples/howto/import-keys.py
Executable file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||
# Lesser General Public Licensefor more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License and the GNU
|
||||
# Lesser General Public along with this program; if not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
import gpg
|
||||
import os.path
|
||||
import requests
|
||||
|
||||
print("""
|
||||
This script imports a key or keys matching a pattern from the SKS keyserver
|
||||
pool.
|
||||
|
||||
Uses the requests module.
|
||||
""")
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
pattern = input("The pattern to search for in key or user IDs: ")
|
||||
url = "https://sks-keyservers.net/pks/lookup"
|
||||
payload = { "op": "get", "search": pattern }
|
||||
hexload = { "op": "get", "search": "0x{0}".format(pattern) }
|
||||
|
||||
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
|
||||
|
||||
resp = requests.get(url, verify=True, params=payload)
|
||||
if resp.ok is False:
|
||||
rhex = requests.get(url, verify=True, params=hexload)
|
||||
incoming = c.key_import(rhex.content)
|
||||
else:
|
||||
incoming = c.key_import(resp.content)
|
||||
|
||||
summary = """
|
||||
Total number of keys: {0}
|
||||
Total number imported: {1}
|
||||
Number of version 3 keys ignored: {2}
|
||||
|
||||
Number of imported key objects or updates: {3}
|
||||
Number of unchanged keys: {4}
|
||||
Number of new signatures: {5}
|
||||
Number of revoked keys: {6}
|
||||
""".format(incoming.considered, len(incoming.imports),
|
||||
incoming.skipped_v3_keys, incoming.imported, incoming.unchanged,
|
||||
incoming.new_signatures, incoming.new_revocations)
|
||||
|
||||
print(summary)
|
||||
|
||||
# EOF
|
@ -509,6 +509,28 @@ class Context(GpgmeWrapper):
|
||||
|
||||
return results
|
||||
|
||||
def key_import(self, keydata):
|
||||
"""Importing keys
|
||||
|
||||
Arguments:
|
||||
keydata -- Binary or ASCII armored key(s) to be imported
|
||||
|
||||
Returns
|
||||
-- an object describing the results of keys imported or
|
||||
updated
|
||||
|
||||
Raises:
|
||||
GPGMEError -- as signaled by the underlying library
|
||||
"""
|
||||
if keydata is not None:
|
||||
try:
|
||||
self.op_import(keydata)
|
||||
result = self.op_import_result()
|
||||
except GPGMEError as e:
|
||||
result = e
|
||||
else:
|
||||
result = "No keys found."
|
||||
|
||||
def keylist(self, pattern=None, secret=False,
|
||||
mode=constants.keylist.mode.LOCAL,
|
||||
source=None):
|
||||
|
Loading…
Reference in New Issue
Block a user