Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Malte L
gajim-plugins
Commits
2b9780a9
Commit
2b9780a9
authored
Feb 09, 2019
by
Philipp Hörist
Browse files
[openpgp] Refactor Plugin
- Adapt to nbxmpp now supporting openpgp
parent
0189214c
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
openpgp/backend/gpgme.py
View file @
2b9780a9
# Copyright (C) 201
8
Philipp Hörist <philipp AT hoerist.com>
# Copyright (C) 201
9
Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of
Gajim
.
# This file is part of
the OpenPGP Gajim Plugin
.
#
#
Gajim
is free software; you can redistribute it and/or modify
#
OpenPGP Gajim Plugin
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; version 3 only.
#
#
Gajim
is distributed in the hope that it will be useful,
#
OpenPGP Gajim Plugin
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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
# along with OpenPGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import
io
...
...
openpgp/backend/pygpg.py
View file @
2b9780a9
# Copyright (C) 201
8
Philipp Hörist <philipp AT hoerist.com>
# Copyright (C) 201
9
Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of
Gajim
.
# This file is part of
the OpenPGP Gajim Plugin
.
#
#
Gajim
is free software; you can redistribute it and/or modify
#
OpenPGP Gajim Plugin
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; version 3 only.
#
#
Gajim
is distributed in the hope that it will be useful,
#
OpenPGP Gajim Plugin
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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
# along with OpenPGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import
os
import
logging
...
...
@@ -27,7 +25,6 @@ from gajim.common import app
from
openpgp.modules.util
import
DecryptionFailed
log
=
logging
.
getLogger
(
'gajim.plugin_system.openpgp.pygnupg'
)
# gnupg.logger = log
KeyringItem
=
namedtuple
(
'KeyringItem'
,
'jid keyid fingerprint'
)
...
...
@@ -38,7 +35,7 @@ class PGPContext(gnupg.GPG):
self
,
gpgbinary
=
app
.
get_gpg_binary
(),
gnupghome
=
str
(
gnupghome
))
self
.
_passphrase
=
'gajimopenpgppassphrase'
self
.
_jid
=
jid
self
.
_jid
=
jid
.
getBare
()
self
.
_own_fingerprint
=
None
def
_get_key_params
(
self
,
jid
,
passphrase
):
...
...
@@ -122,7 +119,7 @@ class PGPContext(gnupg.GPG):
log
.
error
(
result
.
results
[
0
])
return
if
not
self
.
validate_key
(
data
,
jid
):
if
not
self
.
validate_key
(
data
,
str
(
jid
)
)
:
return
None
key
=
self
.
get_key
(
result
.
results
[
0
][
'fingerprint'
])
return
self
.
_make_keyring_item
(
key
[
0
])
...
...
openpgp/backend/sql.py
View file @
2b9780a9
# Copyright (C) 201
8
Philipp Hörist <philipp AT hoerist.com>
# Copyright (C) 201
9
Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of
Gajim
.
# This file is part of
the OpenPGP Gajim Plugin
.
#
#
Gajim
is free software; you can redistribute it and/or modify
#
OpenPGP Gajim Plugin
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; version 3 only.
#
#
Gajim
is distributed in the hope that it will be useful,
#
OpenPGP Gajim Plugin
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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
# along with OpenPGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import
sqlite3
import
logging
from
collections
import
namedtuple
from
nbxmpp
import
JID
log
=
logging
.
getLogger
(
'gajim.plugin_system.openpgp.sql'
)
TABLE_LAYOUT
=
'''
CREATE TABLE contacts (
jid
TEXT
,
jid
JID
,
fingerprint TEXT,
active BOOLEAN,
trust INTEGER,
...
...
@@ -34,10 +34,25 @@ TABLE_LAYOUT = '''
CREATE UNIQUE INDEX jid_fingerprint ON contacts (jid, fingerprint);'''
def
_jid_adapter
(
jid
):
return
str
(
jid
)
def
_jid_converter
(
jid
):
return
JID
(
jid
.
decode
())
sqlite3
.
register_adapter
(
JID
,
_jid_adapter
)
sqlite3
.
register_converter
(
'JID'
,
_jid_converter
)
class
Storage
:
def
__init__
(
self
,
folder_path
):
self
.
_con
=
sqlite3
.
connect
(
str
(
folder_path
/
'contacts.db'
),
detect_types
=
sqlite3
.
PARSE_DECLTYPES
)
self
.
_con
.
row_factory
=
self
.
_namedtuple_factory
self
.
_create_database
()
self
.
_migrate_database
()
...
...
@@ -72,10 +87,7 @@ class Storage:
pass
def
load_contacts
(
self
):
sql
=
'SELECT * from contacts'
rows
=
self
.
_con
.
execute
(
sql
).
fetchall
()
if
rows
is
not
None
:
return
rows
return
self
.
_con
.
execute
(
'SELECT * from contacts'
).
fetchall
()
def
save_contact
(
self
,
db_values
):
sql
=
'''REPLACE INTO
...
...
openpgp/gtk/key.py
View file @
2b9780a9
# Copyright (C) 201
8
Philipp Hörist <philipp AT hoerist.com>
# Copyright (C) 201
9
Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of
Gajim
.
# This file is part of
the OpenPGP Gajim Plugin
.
#
#
Gajim
is free software; you can redistribute it and/or modify
#
OpenPGP Gajim Plugin
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; version 3 only.
#
#
Gajim
is distributed in the hope that it will be useful,
#
OpenPGP Gajim Plugin
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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
# along with OpenPGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import
logging
import
time
...
...
@@ -24,7 +22,7 @@ from gi.repository import Gtk
from
gajim.common
import
app
from
gajim.common.const
import
DialogButton
,
ButtonAction
from
gajim.gtk
import
NewConfirmationDialog
from
gajim.gtk
.dialogs
import
NewConfirmationDialog
from
gajim.plugins.plugins_i18n
import
_
from
openpgp.modules.util
import
Trust
...
...
@@ -49,8 +47,8 @@ TRUST_DATA = {
class
KeyDialog
(
Gtk
.
Dialog
):
def
__init__
(
self
,
account
,
jid
,
transient
):
flags
=
Gtk
.
DialogFlags
.
DESTROY_WITH_PARENT
super
().
__init__
(
_
(
'Public Keys for %s'
)
%
jid
,
None
,
flags
)
super
().
__init__
(
title
=
_
(
'Public Keys for %s'
)
%
jid
,
destroy_with_parent
=
True
)
self
.
set_transient_for
(
transient
)
self
.
set_resizable
(
True
)
...
...
openpgp/gtk/wizard.py
View file @
2b9780a9
# Copyright (C) 201
8
Philipp Hörist <philipp AT hoerist.com>
# Copyright (C) 201
9
Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of
Gajim
.
# This file is part of
the OpenPGP Gajim Plugin
.
#
#
Gajim
is free software; you can redistribute it and/or modify
#
OpenPGP Gajim Plugin
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; version 3 only.
#
#
Gajim
is distributed in the hope that it will be useful,
#
OpenPGP Gajim Plugin
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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
# along with OpenPGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import
logging
import
threading
...
...
@@ -177,8 +175,8 @@ class NewKeyPage(RequestPage):
error
=
e
else
:
self
.
_con
.
get_module
(
'OpenPGP'
).
get_own_key_details
()
self
.
_con
.
get_module
(
'OpenPGP'
).
publi
sh
_key
()
self
.
_con
.
get_module
(
'OpenPGP'
).
que
ry
_key
_
list
()
self
.
_con
.
get_module
(
'OpenPGP'
).
set_
publi
c
_key
()
self
.
_con
.
get_module
(
'OpenPGP'
).
re
que
st
_keylist
()
GLib
.
idle_add
(
self
.
finished
,
error
)
def
finished
(
self
,
error
):
...
...
openpgp/modules/key_store.py
0 → 100644
View file @
2b9780a9
# Copyright (C) 2019 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of the OpenPGP Gajim Plugin.
#
# OpenPGP Gajim Plugin 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; version 3 only.
#
# OpenPGP Gajim Plugin 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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with OpenPGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import
logging
from
openpgp.modules.util
import
Trust
log
=
logging
.
getLogger
(
'gajim.plugin_system.openpgp.store'
)
class
KeyData
:
'''
Holds all data related to a certain key
'''
def
__init__
(
self
,
contact_data
):
self
.
_contact_data
=
contact_data
self
.
fingerprint
=
None
self
.
active
=
False
self
.
_trust
=
Trust
.
UNKNOWN
self
.
timestamp
=
None
self
.
comment
=
None
self
.
has_pubkey
=
False
@
property
def
trust
(
self
):
return
self
.
_trust
@
trust
.
setter
def
trust
(
self
,
value
):
if
value
not
in
(
Trust
.
NOT_TRUSTED
,
Trust
.
UNKNOWN
,
Trust
.
BLIND
,
Trust
.
VERIFIED
):
raise
ValueError
(
'Trust value not allowed: %s'
%
value
)
self
.
_trust
=
value
self
.
_contact_data
.
set_trust
(
self
.
fingerprint
,
self
.
_trust
)
@
classmethod
def
from_key
(
cls
,
contact_data
,
key
,
trust
):
keydata
=
cls
(
contact_data
)
keydata
.
fingerprint
=
key
.
fingerprint
keydata
.
timestamp
=
key
.
date
keydata
.
active
=
True
keydata
.
_trust
=
trust
return
keydata
@
classmethod
def
from_row
(
cls
,
contact_data
,
row
):
keydata
=
cls
(
contact_data
)
keydata
.
fingerprint
=
row
.
fingerprint
keydata
.
timestamp
=
row
.
timestamp
keydata
.
comment
=
row
.
comment
keydata
.
_trust
=
row
.
trust
keydata
.
active
=
row
.
active
return
keydata
def
delete
(
self
):
self
.
_contact_data
.
delete_key
(
self
.
fingerprint
)
class
ContactData
:
'''
Holds all data related to a contact
'''
def
__init__
(
self
,
jid
,
storage
,
pgp
):
self
.
jid
=
jid
self
.
_key_store
=
{}
self
.
_storage
=
storage
self
.
_pgp
=
pgp
@
property
def
userid
(
self
):
if
self
.
jid
is
None
:
raise
ValueError
(
'JID not set'
)
return
'xmpp:%s'
%
self
.
jid
@
property
def
default_trust
(
self
):
for
key
in
self
.
_key_store
.
values
():
if
key
.
trust
in
(
Trust
.
NOT_TRUSTED
,
Trust
.
BLIND
):
return
Trust
.
UNKNOWN
return
Trust
.
BLIND
def
db_values
(
self
):
for
key
in
self
.
_key_store
.
values
():
yield
(
self
.
jid
,
key
.
fingerprint
,
key
.
active
,
key
.
trust
,
key
.
timestamp
,
key
.
comment
)
def
add_from_key
(
self
,
key
):
try
:
keydata
=
self
.
_key_store
[
key
.
fingerprint
]
except
KeyError
:
keydata
=
KeyData
.
from_key
(
self
,
key
,
self
.
default_trust
)
self
.
_key_store
[
key
.
fingerprint
]
=
keydata
log
.
info
(
'Add from key: %s %s'
,
self
.
jid
,
keydata
.
fingerprint
)
return
keydata
def
add_from_db
(
self
,
row
):
try
:
keydata
=
self
.
_key_store
[
row
.
fingerprint
]
except
KeyError
:
keydata
=
KeyData
.
from_row
(
self
,
row
)
self
.
_key_store
[
row
.
fingerprint
]
=
keydata
log
.
info
(
'Add from row: %s %s'
,
self
.
jid
,
row
.
fingerprint
)
return
keydata
def
process_keylist
(
self
,
keylist
):
log
.
info
(
'Process keylist: %s %s'
,
self
.
jid
,
keylist
)
if
keylist
is
None
:
for
keydata
in
self
.
_key_store
.
values
():
keydata
.
active
=
False
self
.
_storage
.
save_contact
(
self
.
db_values
())
return
[]
missing_pub_keys
=
[]
fingerprints
=
set
([
key
.
fingerprint
for
key
in
keylist
])
if
fingerprints
==
self
.
_key_store
.
keys
():
log
.
info
(
'No updates found'
)
for
key
in
self
.
_key_store
.
values
():
if
not
key
.
has_pubkey
:
missing_pub_keys
.
append
(
key
.
fingerprint
)
return
missing_pub_keys
for
keydata
in
self
.
_key_store
.
values
():
keydata
.
active
=
False
for
key
in
keylist
:
try
:
keydata
=
self
.
_key_store
[
key
.
fingerprint
]
keydata
.
active
=
True
if
not
keydata
.
has_pubkey
:
missing_pub_keys
.
append
(
keydata
.
fingerprint
)
except
KeyError
:
keydata
=
self
.
add_from_key
(
key
)
missing_pub_keys
.
append
(
keydata
.
fingerprint
)
self
.
_storage
.
save_contact
(
self
.
db_values
())
return
missing_pub_keys
def
set_public_key
(
self
,
fingerprint
):
try
:
keydata
=
self
.
_key_store
[
fingerprint
]
except
KeyError
:
log
.
warning
(
'Set public key on unknown fingerprint: %s %s'
,
self
.
jid
,
fingerprint
)
else
:
keydata
.
has_pubkey
=
True
log
.
info
(
'Set public key: %s %s'
,
self
.
jid
,
fingerprint
)
def
get_keys
(
self
,
only_trusted
=
True
):
keys
=
list
(
self
.
_key_store
.
values
())
if
not
only_trusted
:
return
keys
return
[
k
for
k
in
keys
if
k
.
active
and
k
.
trust
in
(
Trust
.
VERIFIED
,
Trust
.
BLIND
)]
def
get_key
(
self
,
fingerprint
):
return
self
.
_key_store
.
get
(
fingerprint
,
None
)
def
set_trust
(
self
,
fingerprint
,
trust
):
self
.
_storage
.
set_trust
(
self
.
jid
,
fingerprint
,
trust
)
def
delete_key
(
self
,
fingerprint
):
self
.
_storage
.
delete_key
(
self
.
jid
,
fingerprint
)
self
.
_pgp
.
delete_key
(
fingerprint
)
del
self
.
_key_store
[
fingerprint
]
class
PGPContacts
:
'''
Holds all contacts available for PGP encryption
'''
def
__init__
(
self
,
pgp
,
storage
):
self
.
_contacts
=
{}
self
.
_storage
=
storage
self
.
_pgp
=
pgp
self
.
_load_from_storage
()
self
.
_load_from_keyring
()
def
_load_from_keyring
(
self
):
log
.
info
(
'Load keys from keyring'
)
keyring
=
self
.
_pgp
.
get_keys
()
for
key
in
keyring
:
log
.
info
(
'Found: %s %s'
,
key
.
jid
,
key
.
fingerprint
)
self
.
set_public_key
(
key
.
jid
,
key
.
fingerprint
)
def
_load_from_storage
(
self
):
log
.
info
(
'Load contacts from storage'
)
rows
=
self
.
_storage
.
load_contacts
()
if
rows
is
None
:
return
for
row
in
rows
:
log
.
info
(
'Found: %s %s'
,
row
.
jid
,
row
.
fingerprint
)
try
:
contact_data
=
self
.
_contacts
[
row
.
jid
]
except
KeyError
:
contact_data
=
ContactData
(
row
.
jid
,
self
.
_storage
,
self
.
_pgp
)
contact_data
.
add_from_db
(
row
)
self
.
_contacts
[
row
.
jid
]
=
contact_data
else
:
contact_data
.
add_from_db
(
row
)
def
process_keylist
(
self
,
jid
,
keylist
):
try
:
contact_data
=
self
.
_contacts
[
jid
]
except
KeyError
:
contact_data
=
ContactData
(
jid
,
self
.
_storage
,
self
.
_pgp
)
missing_pub_keys
=
contact_data
.
process_keylist
(
keylist
)
self
.
_contacts
[
jid
]
=
contact_data
else
:
missing_pub_keys
=
contact_data
.
process_keylist
(
keylist
)
return
missing_pub_keys
def
set_public_key
(
self
,
jid
,
fingerprint
):
try
:
contact_data
=
self
.
_contacts
[
jid
]
except
KeyError
:
log
.
warning
(
'ContactData not found: %s %s'
,
jid
,
fingerprint
)
else
:
contact_data
.
set_public_key
(
fingerprint
)
def
get_keys
(
self
,
jid
,
only_trusted
=
True
):
try
:
contact_data
=
self
.
_contacts
[
jid
]
return
contact_data
.
get_keys
(
only_trusted
=
only_trusted
)
except
KeyError
:
return
[]
def
get_trust
(
self
,
jid
,
fingerprint
):
contact_data
=
self
.
_contacts
.
get
(
jid
,
None
)
if
contact_data
is
None
:
return
Trust
.
UNKNOWN
key
=
contact_data
.
get_key
(
fingerprint
)
if
key
is
None
:
return
Trust
.
UNKNOWN
return
key
.
trust
openpgp/modules/openpgp.py
View file @
2b9780a9
This diff is collapsed.
Click to expand it.
openpgp/modules/pgp_keylist.py
deleted
100644 → 0
View file @
0189214c
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
import
logging
import
time
import
nbxmpp
from
gajim.common
import
app
from
gajim.common.exceptions
import
StanzaMalformed
from
gajim.common.modules.pep
import
AbstractPEPModule
,
AbstractPEPData
from
gajim.common.modules.date_and_time
import
parse_datetime
from
openpgp.modules
import
util
from
openpgp.modules.util
import
Key
log
=
logging
.
getLogger
(
'gajim.plugin_system.openpgp.pep'
)
# Module name
name
=
'PGPKeylist'
zeroconf
=
False
class
PGPKeylistData
(
AbstractPEPData
):
type_
=
'openpgp-keylist'
class
PGPKeylist
(
AbstractPEPModule
):
'''
<item>
<public-keys-list xmlns='urn:xmpp:openpgp:0'>
<pubkey-metadata
v4-fingerprint='1357B01865B2503C18453D208CAC2A9678548E35'
date='2018-03-01T15:26:12Z'
/>
<pubkey-metadata
v4-fingerprint='67819B343B2AB70DED9320872C6464AF2A8E4C02'
date='1953-05-16T12:00:00Z'
/>
</public-keys-list>
</item>
'''
name
=
'openpgp-keylist'
namespace
=
util
.
NS_OPENPGP_PUBLIC_KEYS
pep_class
=
PGPKeylistData
store_publish
=
True
_log
=
log
def
_extract_info
(
self
,
item
):
keylist_tag
=
item
.
getTag
(
'public-keys-list'
,
namespace
=
util
.
NS_OPENPGP
)
if
keylist_tag
is
None
:
raise
StanzaMalformed
(
'No public-keys-list node'
)
metadata
=
keylist_tag
.
getTags
(
'pubkey-metadata'
)
if
not
metadata
:
raise
StanzaMalformed
(
'No metadata found'
)
keylist
=
[]
for
data
in
metadata
:
attrs
=
data
.
getAttrs
()
if
not
attrs
or
'v4-fingerprint'
not
in
attrs
:
raise
StanzaMalformed
(
'No fingerprint in metadata'
)
date
=
attrs
.
get
(
'date'
,
None
)
if
date
is
None
:
raise
StanzaMalformed
(
'No date in metadata'
)
else
:
timestamp
=
parse_datetime
(
date
,
epoch
=
True
)
if
timestamp
is
None
:
raise
StanzaMalformed
(
'Invalid date timestamp: %s'
%
date
)
keylist
.
append
(
Key
(
attrs
[
'v4-fingerprint'
],
int
(
timestamp
)))
return
keylist
def
_notification_received
(
self
,
jid
,
keylist
):
con
=
app
.
connections
[
self
.
_account
]
con
.
get_module
(
'OpenPGP'
).
key_list_received
(
keylist
.
data
,
jid
.
getStripped
())
def
_build_node
(
self
,
keylist
):
keylist_node
=
nbxmpp
.
Node
(
'public-keys-list'
,
{
'xmlns'
:
util
.
NS_OPENPGP
})
if
keylist
is
None
:
return
keylist_node
for
key
in
keylist
:
attrs
=
{
'v4-fingerprint'
:
key
.
fingerprint
}
if
key
.
date
is
not
None
:
date
=
time
.
strftime
(
'%Y-%m-%dT%H:%M:%SZ'
,
time
.
gmtime
(
key
.
date
))
attrs
[
'date'
]
=
date
keylist_node
.
addChild
(
'pubkey-metadata'
,
attrs
=
attrs
)
return
keylist_node
def
get_instance
(
*
args
,
**
kwargs
):
return
PGPKeylist
(
*
args
,
**
kwargs
),
'PGPKeylist'
openpgp/modules/util.py
View file @
2b9780a9
# Copyright (C) 201
8
Philipp Hörist <philipp AT hoerist.com>
# Copyright (C) 201
9
Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of
Gajim
.