Merged trunk on 14.7.16

This commit is contained in:
suutari-olli 2016-07-14 21:03:57 +03:00
commit 1c133398e2
5 changed files with 74 additions and 12 deletions

View File

@ -226,10 +226,11 @@ def qmd5_hash(salt, data=None):
log.debug('qmd5_hash(salt="{text}"'.format(text=salt)) log.debug('qmd5_hash(salt="{text}"'.format(text=salt))
hash_obj = QHash(QHash.Md5) hash_obj = QHash(QHash.Md5)
hash_obj.addData(salt) hash_obj.addData(salt)
if data:
hash_obj.addData(data) hash_obj.addData(data)
hash_value = hash_obj.result().toHex() hash_value = hash_obj.result().toHex()
log.debug('qmd5_hash() returning "{text}"'.format(text=hash_value)) log.debug('qmd5_hash() returning "{hash}"'.format(hash=hash_value))
return hash_value.data() return hash_value
def clean_button_text(button_text): def clean_button_text(button_text):

View File

@ -49,7 +49,7 @@ from codecs import decode
from PyQt5.QtCore import pyqtSignal, pyqtSlot from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtNetwork import QAbstractSocket, QTcpSocket from PyQt5.QtNetwork import QAbstractSocket, QTcpSocket
from openlp.core.common import translate, qmd5_hash from openlp.core.common import translate, md5_hash
from openlp.core.lib.projector.constants import * from openlp.core.lib.projector.constants import *
# Shortcuts # Shortcuts
@ -297,6 +297,8 @@ class PJLink1(QTcpSocket):
Processes the initial connection and authentication (if needed). Processes the initial connection and authentication (if needed).
Starts poll timer if connection is established. Starts poll timer if connection is established.
NOTE: Qt md5 hash function doesn't work with projector authentication. Use the python md5 hash function.
:param data: Optional data if called from another routine :param data: Optional data if called from another routine
""" """
log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip, data=data)) log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip, data=data))
@ -344,16 +346,25 @@ class PJLink1(QTcpSocket):
return return
elif data_check[1] == '0' and self.pin is not None: elif data_check[1] == '0' and self.pin is not None:
# Pin set and no authentication needed # Pin set and no authentication needed
log.warning('({ip}) Regular connection but PIN set'.format(ip=self.name))
self.disconnect_from_host() self.disconnect_from_host()
self.change_status(E_AUTHENTICATION) self.change_status(E_AUTHENTICATION)
log.debug('({ip}) emitting projectorNoAuthentication() signal'.format(ip=self.name)) log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name))
self.projectorNoAuthentication.emit(self.name) self.projectorNoAuthentication.emit(self.name)
return return
elif data_check[1] == '1': elif data_check[1] == '1':
# Authenticated login with salt # Authenticated login with salt
if self.pin is None:
log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name))
self.disconnect_from_host()
self.change_status(E_AUTHENTICATION)
log.debug('({ip}) Emitting projectorAuthentication() signal'.format(ip=self.name))
self.projectorAuthentication.emit(self.name)
return
else:
log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2]))
log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin))
salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) salt = md5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii'))
else: else:
salt = None salt = None
# We're connected at this point, so go ahead and do regular I/O # We're connected at this point, so go ahead and do regular I/O

View File

@ -362,7 +362,7 @@ class PowerpointDocument(PresentationDocument):
# it is the powerpoint presentation window. # it is the powerpoint presentation window.
(left, top, right, bottom) = win32gui.GetWindowRect(hwnd) (left, top, right, bottom) = win32gui.GetWindowRect(hwnd)
window_title = win32gui.GetWindowText(hwnd) window_title = win32gui.GetWindowText(hwnd)
log.debug('window size: left=left:d}, top={top:d}, ' log.debug('window size: left={left:d}, top={top:d}, '
'right={right:d}, bottom={bottom:d}'.format(left=left, top=top, right=right, bottom=bottom)) 'right={right:d}, bottom={bottom:d}'.format(left=left, top=top, right=right, bottom=bottom))
log.debug('compare size: {y:d} and {top:d}, {height:d} and {vertical:d}, ' log.debug('compare size: {y:d} and {top:d}, {height:d} and {vertical:d}, '
'{x:d} and {left}, {width:d} and {horizontal:d}'.format(y=size.y(), '{x:d} and {left}, {width:d} and {horizontal:d}'.format(y=size.y(),

View File

@ -147,7 +147,7 @@ class testProjectorUtilities(TestCase):
hash_ = qmd5_hash(salt=salt.encode('ascii'), data=pin.encode('ascii')) hash_ = qmd5_hash(salt=salt.encode('ascii'), data=pin.encode('ascii'))
# THEN: Validate return has is same # THEN: Validate return has is same
self.assertEquals(hash_.decode('ascii'), test_hash, 'Qt-MD5 should have returned a good hash') self.assertEquals(hash_, test_hash, 'Qt-MD5 should have returned a good hash')
def test_qmd5_hash_bad(self): def test_qmd5_hash_bad(self):
""" """
@ -157,7 +157,7 @@ class testProjectorUtilities(TestCase):
hash_ = qmd5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii')) hash_ = qmd5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii'))
# THEN: return data is different # THEN: return data is different
self.assertNotEquals(hash_.decode('ascii'), test_hash, 'Qt-MD5 should have returned a bad hash') self.assertNotEquals(hash_, test_hash, 'Qt-MD5 should have returned a bad hash')
def test_md5_non_ascii_string(self): def test_md5_non_ascii_string(self):
""" """

View File

@ -30,7 +30,7 @@ from openlp.core.lib.projector.constants import E_PARAMETER, ERROR_STRING, S_OFF
S_COOLDOWN, PJLINK_POWR_STATUS S_COOLDOWN, PJLINK_POWR_STATUS
from tests.functional import patch from tests.functional import patch
from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE, TEST_HASH
pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True) pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True)
@ -332,3 +332,53 @@ class TestPJLink(TestCase):
self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False') self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called') self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called')
self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called') self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called')
@patch.object(pjlink_test, 'send_command')
@patch.object(pjlink_test, 'waitForReadyRead')
@patch.object(pjlink_test, 'projectorAuthentication')
@patch.object(pjlink_test, 'timer')
@patch.object(pjlink_test, 'socket_timer')
def test_bug_1593882_no_pin_authenticated_connection(self, mock_socket_timer,
mock_timer,
mock_authentication,
mock_ready_read,
mock_send_command):
"""
Test bug 1593882 no pin and authenticated request exception
"""
# GIVEN: Test object and mocks
pjlink = pjlink_test
pjlink.pin = None
mock_ready_read.return_value = True
# WHEN: call with authentication request and pin not set
pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE)
# THEN: No Authentication signal should have been sent
mock_authentication.emit.assert_called_with(pjlink.name)
@patch.object(pjlink_test, 'waitForReadyRead')
@patch.object(pjlink_test, 'state')
@patch.object(pjlink_test, '_send_command')
@patch.object(pjlink_test, 'timer')
@patch.object(pjlink_test, 'socket_timer')
def test_bug_1593883_pjlink_authentication(self, mock_socket_timer,
mock_timer,
mock_send_command,
mock_state,
mock_waitForReadyRead):
"""
Test bugfix 1593883 pjlink authentication
"""
# GIVEN: Test object and data
pjlink = pjlink_test
pjlink.pin = TEST_PIN
mock_state.return_value = pjlink.ConnectedState
mock_waitForReadyRead.return_value = True
# WHEN: Athenticated connection is called
pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE)
# THEN: send_command should have the proper authentication
self.assertEquals("{test}".format(test=mock_send_command.call_args),
"call(data='{hash}%1CLSS ?\\r')".format(hash=TEST_HASH))