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
Jens Korte
gajim-plugins
Commits
a319b1f9
Commit
a319b1f9
authored
Apr 26, 2017
by
Philipp Hörist
Browse files
[pgp] Initial
parent
de369fc6
Changes
3
Hide whitespace changes
Inline
Side-by-side
pgp/__init__.py
0 → 100644
View file @
a319b1f9
from
.pgpplugin
import
OldPGPPlugin
pgp/manifest.ini
0 → 100644
View file @
a319b1f9
[info]
name:
PGP
short_name:
PGP
version:
1.0.0
description:
PGP
encryption
as
per
XEP-0027
authors:
Philipp
Hörist
<philipp@hoerist.com>
homepage:
https://dev.gajim.org/gajim/gajim-plugins/wikis/pgp
min_gajim_version:
0.16.10
pgp/pgpplugin.py
0 → 100644
View file @
a319b1f9
# -*- coding: utf-8 -*-
'''
Copyright 2017 Philipp Hörist <philipp@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/>.
'''
import
os
import
logging
import
time
import
threading
import
queue
import
nbxmpp
from
gi.repository
import
GLib
import
dialogs
from
common
import
gajim
from
common.connection_handlers_events
import
(
MessageNotSentEvent
,
MessageReceivedEvent
)
from
plugins
import
GajimPlugin
log
=
logging
.
getLogger
(
'gajim.plugin_system.oldpgp'
)
ERROR_MSG
=
''
if
not
gajim
.
HAVE_GPG
:
ERROR_MSG
=
'Please install python-gnupg'
ALLOWED_TAGS
=
[(
'request'
,
nbxmpp
.
NS_RECEIPTS
),
(
'active'
,
nbxmpp
.
NS_CHATSTATES
),
(
'gone'
,
nbxmpp
.
NS_CHATSTATES
),
(
'inactive'
,
nbxmpp
.
NS_CHATSTATES
),
(
'paused'
,
nbxmpp
.
NS_CHATSTATES
),
(
'composing'
,
nbxmpp
.
NS_CHATSTATES
),
(
'no-store'
,
nbxmpp
.
NS_MSG_HINTS
),
(
'store'
,
nbxmpp
.
NS_MSG_HINTS
),
(
'no-copy'
,
nbxmpp
.
NS_MSG_HINTS
),
(
'no-permanent-store'
,
nbxmpp
.
NS_MSG_HINTS
),
(
'replace'
,
nbxmpp
.
NS_CORRECT
)]
class
OldPGPPlugin
(
GajimPlugin
):
def
init
(
self
):
if
ERROR_MSG
:
self
.
activatable
=
False
self
.
available_text
=
ERROR_MSG
return
self
.
config_dialog
=
None
self
.
encryption_name
=
'PGP'
self
.
config_dialog
=
None
self
.
gui_extension_points
=
{
'encrypt'
+
self
.
encryption_name
:
(
self
.
_encrypt_message
,
None
),
'decrypt'
:
(
self
.
_message_received
,
None
),
'send_message'
+
self
.
encryption_name
:
(
self
.
_before_sendmessage
,
None
),
'encryption_dialog'
+
self
.
encryption_name
:
(
self
.
on_encryption_button_clicked
,
None
),
'encryption_state'
+
self
.
encryption_name
:
(
self
.
encryption_state
,
None
)}
self
.
gpg_instances
=
{}
self
.
decrypt_queue
=
queue
.
Queue
()
self
.
thread
=
None
def
get_gpg
(
self
,
account
):
return
self
.
gpg_instances
[
account
]
def
activate
(
self
):
for
account
in
gajim
.
connections
:
self
.
gpg_instances
[
account
]
=
gajim
.
connections
[
account
].
gpg
def
deactivate
(
self
):
pass
@
staticmethod
def
activate_encryption
(
chat_control
):
return
True
@
staticmethod
def
encryption_state
(
chat_control
,
state
):
key_id
=
chat_control
.
contact
.
keyID
account
=
chat_control
.
account
authenticated
,
_
=
check_state
(
key_id
,
account
)
state
[
'visible'
]
=
True
state
[
'authenticated'
]
=
authenticated
@
staticmethod
def
on_encryption_button_clicked
(
chat_control
):
account
=
chat_control
.
account
key_id
=
chat_control
.
contact
.
keyID
transient
=
chat_control
.
parent_win
.
window
authenticated
,
info
=
check_state
(
key_id
,
account
)
dialogs
.
InformationDialog
(
authenticated
,
info
,
transient
)
@
staticmethod
def
_before_sendmessage
(
chat_control
):
account
=
chat_control
.
account
if
not
chat_control
.
contact
.
keyID
:
dialogs
.
ErrorDialog
(
_
(
'No OpenPGP key assigned'
),
_
(
'No OpenPGP key is assigned to this contact. So you cannot '
'encrypt messages with OpenPGP.'
))
chat_control
.
sendmessage
=
False
elif
not
gajim
.
config
.
get_per
(
'accounts'
,
account
,
'keyid'
):
dialogs
.
ErrorDialog
(
_
(
'No OpenPGP key assigned'
),
_
(
'No OpenPGP key is assigned to your account. So you cannot '
'encrypt messages with OpenPGP.'
))
chat_control
.
sendmessage
=
False
@
staticmethod
def
_get_info_message
():
msg
=
'[This message is *encrypted* (See :XEP:`27`]'
lang
=
os
.
getenv
(
'LANG'
)
if
lang
is
not
None
and
not
lang
.
startswith
(
'en'
):
# we're not english: one in locale and one en
msg
=
_
(
'[This message is *encrypted* (See :XEP:`27`]'
)
+
\
' ('
+
msg
+
')'
return
msg
def
_message_received
(
self
,
conn
,
obj
,
callback
):
if
obj
.
encrypted
:
# Another Plugin already decrypted the message
return
account
=
conn
.
name
if
isinstance
(
obj
,
MessageReceivedEvent
):
enc_tag
=
obj
.
stanza
.
getTag
(
'x'
,
namespace
=
nbxmpp
.
NS_ENCRYPTED
)
else
:
enc_tag
=
obj
.
msg_
.
getTag
(
'x'
,
namespace
=
nbxmpp
.
NS_ENCRYPTED
)
if
enc_tag
:
encmsg
=
enc_tag
.
getData
()
key_id
=
gajim
.
config
.
get_per
(
'accounts'
,
account
,
'keyid'
)
if
key_id
:
obj
.
encrypted
=
'xep27'
self
.
decrypt_queue
.
put
([
encmsg
,
key_id
,
obj
,
conn
,
callback
])
if
not
self
.
thread
:
self
.
thread
=
threading
.
Thread
(
target
=
self
.
worker
)
self
.
thread
.
start
()
return
def
worker
(
self
):
while
True
:
try
:
item
=
self
.
decrypt_queue
.
get
(
block
=
False
)
encmsg
,
key_id
,
obj
,
conn
,
callback
=
item
account
=
conn
.
name
decmsg
=
self
.
get_gpg
(
account
).
decrypt
(
encmsg
,
key_id
)
decmsg
=
conn
.
connection
.
Dispatcher
.
\
replace_non_character
(
decmsg
)
# \x00 chars are not allowed in C (so in GTK)
msg
=
decmsg
.
replace
(
'
\x00
'
,
''
)
obj
.
msgtxt
=
msg
GLib
.
idle_add
(
callback
,
obj
)
except
queue
.
Empty
:
self
.
thread
=
None
break
def
_encrypt_message
(
self
,
conn
,
obj
,
callback
):
account
=
conn
.
name
if
not
obj
.
message
:
# We only encrypt the actual message
self
.
_finished_encrypt
(
obj
,
callback
=
callback
)
return
if
obj
.
keyID
==
'UNKNOWN'
:
error
=
_
(
'Neither the remote presence is signed, nor a key was '
'assigned.'
)
elif
obj
.
keyID
.
endswith
(
'MISMATCH'
):
error
=
_
(
'The contact
\'
s key (%s) does not match the key assigned '
'in Gajim.'
%
obj
.
keyID
[:
8
])
else
:
my_key_id
=
gajim
.
config
.
get_per
(
'accounts'
,
account
,
'keyid'
)
key_list
=
[
obj
.
keyID
,
my_key_id
]
def
_on_encrypted
(
output
):
msgenc
,
error
=
output
if
error
.
startswith
(
'NOT_TRUSTED'
):
def
on_yes
(
checked
):
if
checked
:
obj
.
conn
.
gpg
.
always_trust
.
append
(
obj
.
keyID
)
gajim
.
thread_interface
(
self
.
get_gpg
(
account
).
encrypt
,
[
obj
.
message
,
key_list
,
True
],
_on_encrypted
,
[])
def
on_no
():
self
.
_finished_encrypt
(
obj
,
msgenc
=
msgenc
,
error
=
error
,
conn
=
conn
)
dialogs
.
YesNoDialog
(
_
(
'Untrusted OpenPGP key'
),
_
(
'The OpenPGP key used to encrypt this chat is not '
'trusted. Do you really want to encrypt this '
'message?'
),
checktext
=
_
(
'_Do not ask me again'
),
on_response_yes
=
on_yes
,
on_response_no
=
on_no
)
else
:
self
.
_finished_encrypt
(
obj
,
msgenc
=
msgenc
,
error
=
error
,
conn
=
conn
,
callback
=
callback
)
gajim
.
thread_interface
(
self
.
get_gpg
(
account
).
encrypt
,
[
obj
.
message
,
key_list
,
False
],
_on_encrypted
,
[])
return
self
.
_finished_encrypt
(
conn
,
obj
,
error
=
error
)
def
_finished_encrypt
(
self
,
obj
,
msgenc
=
None
,
error
=
None
,
conn
=
None
,
callback
=
None
):
if
error
:
log
.
error
(
'python-gnupg error: %s'
,
error
)
gajim
.
nec
.
push_incoming_event
(
MessageNotSentEvent
(
None
,
conn
=
conn
,
jid
=
obj
.
jid
,
message
=
obj
.
message
,
error
=
error
,
time_
=
time
.
time
(),
session
=
obj
.
session
))
return
self
.
cleanup_stanza
(
obj
)
if
msgenc
:
obj
.
msg_iq
.
setBody
(
self
.
_get_info_message
())
obj
.
msg_iq
.
setTag
(
'x'
,
namespace
=
nbxmpp
.
NS_ENCRYPTED
).
setData
(
msgenc
)
eme_node
=
nbxmpp
.
Node
(
'encryption'
,
attrs
=
{
'xmlns'
:
nbxmpp
.
NS_EME
,
'namespace'
:
nbxmpp
.
NS_ENCRYPTED
})
obj
.
msg_iq
.
addChild
(
node
=
eme_node
)
# Set xhtml to None so it doesnt get logged
obj
.
xhtml
=
None
print_msg_to_log
(
obj
.
msg_iq
)
callback
(
obj
)
@
staticmethod
def
cleanup_stanza
(
obj
):
''' We make sure only allowed tags are in the stanza '''
stanza
=
nbxmpp
.
Message
(
to
=
obj
.
msg_iq
.
getTo
(),
typ
=
obj
.
msg_iq
.
getType
())
stanza
.
setThread
(
obj
.
msg_iq
.
getThread
())
for
tag
,
ns
in
ALLOWED_TAGS
:
node
=
obj
.
msg_iq
.
getTag
(
tag
,
namespace
=
ns
)
if
node
:
stanza
.
addChild
(
node
=
node
)
obj
.
msg_iq
=
stanza
def
print_msg_to_log
(
stanza
):
""" Prints a stanza in a fancy way to the log """
stanzastr
=
'
\n
'
+
stanza
.
__str__
(
fancy
=
True
)
+
'
\n
'
stanzastr
=
stanzastr
[
0
:
-
1
]
log
.
debug
(
'
\n
'
+
'-'
*
15
+
stanzastr
+
'-'
*
15
)
def
check_state
(
key_id
,
account
):
error
=
None
if
key_id
.
endswith
(
'MISMATCH'
):
verification_status
=
_
(
'''Contact's identity NOT verified'''
)
info
=
_
(
'The contact
\'
s key (%s) <b>does not match</b> the key '
'assigned in Gajim.'
)
%
key_id
[:
8
]
elif
not
key_id
:
# No key assigned nor a key is used by remote contact
verification_status
=
_
(
'No OpenPGP key assigned'
)
info
=
_
(
'No OpenPGP key is assigned to this contact. So you cannot'
' encrypt messages.'
)
else
:
error
=
gajim
.
connections
[
account
].
gpg
.
encrypt
(
'test'
,
[
key_id
])[
1
]
if
error
:
verification_status
=
_
(
'''Contact's identity NOT verified'''
)
info
=
_
(
'OpenPGP key is assigned to this contact, but <b>you '
'do not trust their key</b>, so message <b>cannot</b> be '
'encrypted. Use your OpenPGP client to trust their key.'
)
else
:
verification_status
=
_
(
'''Contact's identity verified'''
)
info
=
_
(
'OpenPGP Key is assigned to this contact, and you '
'trust their key, so messages will be encrypted.'
)
return
(
verification_status
,
info
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment