-
Notifications
You must be signed in to change notification settings - Fork 10
PyGPGME-based library #47
base: master
Are you sure you want to change the base?
Conversation
…__master-muelli Conflicts: keysign/Keyserver.py keysign/MainWindow.py keysign/Sections.py
The gpg.py file contains some use cases of monkeysign gpg wrapper that we need to replace with pygpgme. We need to gradually replace all functionality of monkeysign' gpg wrapper. In example.py you can find a basic use of pygpgme to encrypt a file, taken from the original pygpgme repository.
I have set up a simple scenario to test current and future replacement functions for the old monkeysign gpg wrapper. Also added a sample keys/key1.pub key.
I am still now sure how to do the transition from monekeysign' gpg wrapper to pygpgme. There are so many calls to gpg from almost every class in Section.py, SignPages.py modules, and many are using the monkeysign.gpg.Keyring class methods or monkeysign.gpg.Context. For now, I have moved the gpgme implementation from gpg.py to examply.py file.
There is still work to be done to separate the gpg calls from whithin core classes in Sections.py.
For now, only Sections.py module interacts with gpg through gpg.py file.
We now import a GetNewKeyring function from gpg.py module.
… key2. Most of the functionality that we need for gpg interraction is demonstrated through the functions in example.py. Now all is left implement the actual needed functions that are in gpg.py module.
We are calling UIDExport from GetKeySection.sign_key_async method and we do that for every UID of a key that we want to sign. Therefore , for each UID, the call to UIDExport does the following: * imports the key into a temp keyring * removes all other UIDs except the current one passed * returns the exported keydata with the UIDs removed This is how we sign all UIDs and email back the key with its corresponding UID. Unfortunately PyGPGME API doesn't seem to offer an easy way to delete an UID (or I don't know yet) so for know we don't use the UIDExport_gpgme implementation.
It seems that gpgme.Context.import_ call can throw a gpgm.GpgmeError when the data to import is not keydata.
The gpg API can change again in the future depending on how we'll replace the current gpg wrapper. Removed unnecesary asserts from UIDExport_gpgm.
This replaces the keyring functionalities offered by Keyring class.
Most of the functionalities of a keyring is done in gpgme.Context class in PyGPGME. This is good because it removes a layer of abstraction.
It does that by passing a context (gpgme.Context) which should contain the desired key.
It does that by calling import_key_to_tmp for each secret key found for user. This needs more testing because because gpgme doesn't have a way to set additional argument '--homedir' but instead relies to where 'GNUPGHOME' points to.
For now, the keylist seems to be empty. So we print the contents out.
We could not sign anyones key, because the downloaded key was deleted too early. Now, we don't delete the key so that we can sign it. I added a FIXME to think about removing the directory later.
Not hard code the number. It was 0 and 1 for me, so the test failed. I think that if we are asserting that we have more signatures after signing than before, we're good to go.
fixed non-working signing of other keys
@@ -406,7 +309,8 @@ def download_key_http(self, address, port): | |||
params='', | |||
query='', | |||
fragment='') | |||
return requests.get(url.geturl()).text |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the encode? I think you can access the raw bytes of the response via the content property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to return bytes through the content field (commit 67195f2)
If set to True the function will return expired keys also, else it won't. This is how we can implement the check for expiration, because the gpgme module that we use doesn't recognize the expired keys (aka the key.expired is always set to False). Also, the 'expiration date' can only be retrieved from the key.subkeys[0].expires field ... wierdly!
@@ -116,12 +117,18 @@ def gpg_import_keydata(gpgmeContext, keydata): | |||
return result | |||
|
|||
|
|||
def gpg_get_keylist(gpgmeContext, keyid=None, secret=False): | |||
def gpg_get_keylist(gpgmeContext, keyid=None, secret=False, expired=False): | |||
"""Returns the keys found in @gpgmeContext | |||
If @keyid is None then all geys will be returned. | |||
If @secret=True then it will return the secret keys. | |||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very good so far!
can we have the expired attribute documented, too? :o)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks :-) , I've fixed it with this commit 32902ae .
The documentation needs more work though
The gpg module is instended to be imported and used as a namespace for calling the module functions, that's why it is unnecessary to have a gpg_ prefix.
imported_key_fpr = self.tmpkeyring.get_keys().keys()[0] | ||
res = gpg.import_keydata(self.ctx, downloaded_data) | ||
if res and len(res.imports): | ||
(imported_key_fpr, null, null) = res.imports[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this I don't like.
If, in the future, res.imports[0]
will return something else than a three-tuple, this will break.
Would smth like imported_key_fprv = res.imports[0][0]
do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in andreimacavei@faa997c where I'm getting the first element of the result tuple.
I woould like to create a lib/util function that we receives an import result and returns the fingerprint...something like get_fpr_from_import_result
. This way, in the future the result will change, we can only modify the code in one place.
The function `get_personal_keys` will return the personal keys from User's defaul keyring. It can return the secret part or the public part of the key. More logic (for key validaiton) can be done at the caller. This commit also fixes issue #16.
The get_keylist lib function will now receive a `pair` argument. This is used to differentiate between public keys that are imported from other users/keyrings, and public keys that have a secret part existent inside that keyring.
This separates the logic between importing and exporting private keys. The `export_secret_keys` function will return a string with all the private keys found in the current gpg homedir. This is usefull for when we want to sign a key, and we need to import our secret key into a temporary keyring.
return public_keys | ||
|
||
def get_personal_keys(keyid=None, secret=False): | ||
"""Returns the personal keys found in User's own keyring. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's a "personal" key?
What's the difference to get_keylist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a key more "personal" than other keys :-).
I may have thought about a key that the user has generated, such as a key for which he owns the private part.
You're right, the get_keylist function can replace this if the gpgmeContext ,received as arg, represents the User's default keyring (not a temporary keyring set by the app itself).
FWIW: There is a gpgmeh branch right now which looks like something I might merge. |
The work I've did for the new GPG library