summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/util
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2014-06-06 14:39:30 -0300
committerTomás Touceda <chiiph@leap.se>2014-06-06 14:39:30 -0300
commitc621fa7322b4f8151eb37b27f8aeae563cf6bd63 (patch)
tree55b17318254974378e289f01ec68031ea1f834ad /src/leap/bitmask/util
parent4c550c558dcb554b3ea1bc0246492e39e8532886 (diff)
parent6ab80f96b1ed14ccf96cae37ff207649a26a38ed (diff)
Merge branch 'release-0.5.2'0.5.2
Diffstat (limited to 'src/leap/bitmask/util')
-rw-r--r--src/leap/bitmask/util/__init__.py5
-rw-r--r--src/leap/bitmask/util/credentials.py (renamed from src/leap/bitmask/util/password.py)31
-rw-r--r--src/leap/bitmask/util/leap_log_handler.py137
-rw-r--r--src/leap/bitmask/util/log_silencer.py93
-rw-r--r--src/leap/bitmask/util/streamtologger.py59
-rw-r--r--src/leap/bitmask/util/tests/test_leap_log_handler.py120
-rw-r--r--src/leap/bitmask/util/tests/test_streamtologger.py126
7 files changed, 27 insertions, 544 deletions
diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py
index 2b2cd874..c35be99e 100644
--- a/src/leap/bitmask/util/__init__.py
+++ b/src/leap/bitmask/util/__init__.py
@@ -28,11 +28,6 @@ from leap.common.config import get_path_prefix as common_get_path_prefix
# We'll give your money back if it does not alleviate the eye strain, at least.
-# levelname length == 8, since 'CRITICAL' is the longest
-LOG_FORMAT = ('%(asctime)s - %(levelname)-8s - '
- 'L#%(lineno)-4s : %(name)s:%(funcName)s() - %(message)s')
-
-
def first(things):
"""
Return the head of a collection.
diff --git a/src/leap/bitmask/util/password.py b/src/leap/bitmask/util/credentials.py
index 73659f0d..07ded17b 100644
--- a/src/leap/bitmask/util/password.py
+++ b/src/leap/bitmask/util/credentials.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# password.py
+# credentials.py
# Copyright (C) 2013 LEAP
#
# This program is free software: you can redistribute it and/or modify
@@ -16,14 +16,34 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-Password utilities
+Credentials utilities
"""
-from PySide import QtCore
+from PySide import QtCore, QtGui
WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password")
+USERNAME_REGEX = r"^[A-Za-z][A-Za-z\d_\-\.]+[A-Za-z\d]$"
+USERNAME_VALIDATOR = QtGui.QRegExpValidator(QtCore.QRegExp(USERNAME_REGEX))
-def basic_password_checks(username, password, password2):
+
+def username_checks(username):
+ # translation helper
+ _tr = QtCore.QObject().tr
+
+ message = None
+
+ if message is None and len(username) < 2:
+ message = _tr("Username must have at least 2 characters")
+
+ valid = USERNAME_VALIDATOR.validate(username, 0)
+ valid_username = valid[0] == QtGui.QValidator.State.Acceptable
+ if message is None and not valid_username:
+ message = _tr("Invalid username")
+
+ return message is None, message
+
+
+def password_checks(username, password, password2):
"""
Performs basic password checks to avoid really easy passwords.
@@ -46,6 +66,9 @@ def basic_password_checks(username, password, password2):
if message is None and password != password2:
message = _tr("Passwords don't match")
+ if message is None and not password:
+ message = _tr("You can't use an empty password")
+
if message is None and len(password) < 6:
message = _tr("Password too short")
diff --git a/src/leap/bitmask/util/leap_log_handler.py b/src/leap/bitmask/util/leap_log_handler.py
deleted file mode 100644
index 807e53d4..00000000
--- a/src/leap/bitmask/util/leap_log_handler.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# -*- coding: utf-8 -*-
-# leap_log_handler.py
-# Copyright (C) 2013 LEAP
-#
-# 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 3 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 for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-Custom handler for the logger window.
-"""
-import logging
-
-from PySide import QtCore
-
-from leap.bitmask.util import LOG_FORMAT
-
-
-class LogHandler(logging.Handler):
- """
- This is the custom handler that implements our desired formatting
- and also keeps a history of all the logged events.
- """
-
- MESSAGE_KEY = 'message'
- RECORD_KEY = 'record'
-
- def __init__(self, qtsignal):
- """
- LogHander initialization.
- Calls parent method and keeps a reference to the qtsignal
- that will be used to fire the gui update.
- """
- # TODO This is going to eat lots of memory after some time.
- # Should be pruned at some moment.
- self._log_history = []
-
- logging.Handler.__init__(self)
- self._qtsignal = qtsignal
-
- def _get_format(self, logging_level):
- """
- Sets the log format depending on the parameter.
- It uses html and css to set the colors for the logs.
-
- :param logging_level: the debug level to define the color.
- :type logging_level: str.
- """
- formatter = logging.Formatter(LOG_FORMAT)
- return formatter
-
- def emit(self, logRecord):
- """
- This method is fired every time that a record is logged by the
- logging module.
- This method reimplements logging.Handler.emit that is fired
- in every logged message.
-
- :param logRecord: the record emitted by the logging module.
- :type logRecord: logging.LogRecord.
- """
- self.setFormatter(self._get_format(logRecord.levelname))
- log = self.format(logRecord)
- log_item = {self.RECORD_KEY: logRecord, self.MESSAGE_KEY: log}
- self._log_history.append(log_item)
- self._qtsignal(log_item)
-
-
-class HandlerAdapter(object):
- """
- New style class that accesses all attributes from the LogHandler.
-
- Used as a workaround for a problem with multiple inheritance with Pyside
- that surfaced under OSX with pyside 1.1.0.
- """
- MESSAGE_KEY = 'message'
- RECORD_KEY = 'record'
-
- def __init__(self, qtsignal):
- self._handler = LogHandler(qtsignal=qtsignal)
-
- def setLevel(self, *args, **kwargs):
- return self._handler.setLevel(*args, **kwargs)
-
- def addFilter(self, *args, **kwargs):
- return self._handler.addFilter(*args, **kwargs)
-
- def handle(self, *args, **kwargs):
- return self._handler.handle(*args, **kwargs)
-
- @property
- def level(self):
- return self._handler.level
-
-
-class LeapLogHandler(QtCore.QObject, HandlerAdapter):
- """
- Custom logging handler. It emits Qt signals so it can be plugged to a gui.
-
- Its inner handler also stores an history of logs that can be fetched after
- having been connected to a gui.
- """
- # All dicts returned are of the form
- # {'record': LogRecord, 'message': str}
- new_log = QtCore.Signal(dict)
-
- def __init__(self):
- """
- LeapLogHandler initialization.
- Initializes parent classes.
- """
- QtCore.QObject.__init__(self)
- HandlerAdapter.__init__(self, qtsignal=self.qtsignal)
-
- def qtsignal(self, log_item):
- # WARNING: the new-style connection does NOT work because PySide
- # translates the emit method to self.emit, and that collides with
- # the emit method for logging.Handler
- # self.new_log.emit(log_item)
- QtCore.QObject.emit(
- self,
- QtCore.SIGNAL('new_log(PyObject)'), log_item)
-
- @property
- def log_history(self):
- """
- Returns the history of the logged messages.
- """
- return self._handler._log_history
diff --git a/src/leap/bitmask/util/log_silencer.py b/src/leap/bitmask/util/log_silencer.py
deleted file mode 100644
index 56b290e4..00000000
--- a/src/leap/bitmask/util/log_silencer.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# -*- coding: utf-8 -*-
-# log_silencer.py
-# Copyright (C) 2013 LEAP
-#
-# 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 3 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 for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-Filter for leap logs.
-"""
-import logging
-import os
-import re
-
-from leap.bitmask.util import get_path_prefix
-
-
-class SelectiveSilencerFilter(logging.Filter):
- """
- Configurable filter for root leap logger.
-
- If you want to ignore components from the logging, just add them,
- one by line, to ~/.config/leap/leap.dev.conf
- """
- # TODO we can augment this by properly parsing the log-silencer file
- # and having different sections: ignore, levels, ...
-
- # TODO use ConfigParser to unify sections [log-ignore] [log-debug] etc
-
- CONFIG_NAME = "leap.dev.conf"
-
- # Components to be completely silenced in the main bitmask logs.
- # You probably should think twice before adding a component to
- # the tuple below. Only very well tested components should go here, and
- # only in those cases in which we gain more from silencing them than from
- # having their logs into the main log file that the user will likely send
- # to us.
- SILENCER_RULES = (
- 'leap.common.events',
- 'leap.common.decorators',
- )
-
- def __init__(self):
- """
- Tries to load silencer rules from the default path,
- or load from the SILENCER_RULES tuple if not found.
- """
- self.rules = None
- if os.path.isfile(self._rules_path):
- self.rules = self._load_rules()
- if not self.rules:
- self.rules = self.SILENCER_RULES
-
- @property
- def _rules_path(self):
- """
- The configuration file for custom ignore rules.
- """
- return os.path.join(get_path_prefix(), "leap", self.CONFIG_NAME)
-
- def _load_rules(self):
- """
- Loads a list of paths to be ignored from the logging.
- """
- lines = open(self._rules_path).readlines()
- return map(lambda line: re.sub('\s', '', line),
- lines)
-
- def filter(self, record):
- """
- Implements the filter functionality for this Filter
-
- :param record: the record to be examined
- :type record: logging.LogRecord
- :returns: a bool indicating whether the record should be logged or not.
- :rtype: bool
- """
- if not self.rules:
- return True
- logger_path = record.name
- for path in self.rules:
- if logger_path.startswith(path):
- return False
- return True
diff --git a/src/leap/bitmask/util/streamtologger.py b/src/leap/bitmask/util/streamtologger.py
deleted file mode 100644
index 25a06718..00000000
--- a/src/leap/bitmask/util/streamtologger.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# -*- coding: utf-8 -*-
-# streamtologger.py
-# Copyright (C) 2013 LEAP
-#
-# 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 3 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 for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-Stream object that redirects writes to a logger instance.
-"""
-import logging
-
-
-class StreamToLogger(object):
- """
- Fake file-like stream object that redirects writes to a logger instance.
-
- Credits to:
- http://www.electricmonk.nl/log/2011/08/14/\
- redirect-stdout-and-stderr-to-a-logger-in-python/
- """
- def __init__(self, logger, log_level=logging.INFO):
- """
- Constructor, defines the logger and level to use to log messages.
-
- :param logger: logger object to log messages.
- :type logger: logging.Handler
- :param log_level: the level to use to log messages through the logger.
- :type log_level: int
- look at logging-levels in 'logging' docs.
- """
- self._logger = logger
- self._log_level = log_level
-
- def write(self, data):
- """
- Simulates the 'write' method in a file object.
- It writes the data receibed in buf to the logger 'self._logger'.
-
- :param data: data to write to the 'file'
- :type data: str
- """
- for line in data.rstrip().splitlines():
- self._logger.log(self._log_level, line.rstrip())
-
- def flush(self):
- """
- Dummy method. Needed to replace the twisted.log output.
- """
- pass
diff --git a/src/leap/bitmask/util/tests/test_leap_log_handler.py b/src/leap/bitmask/util/tests/test_leap_log_handler.py
deleted file mode 100644
index 518fd35b..00000000
--- a/src/leap/bitmask/util/tests/test_leap_log_handler.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# -*- coding: utf-8 -*-
-# test_leap_log_handler.py
-# Copyright (C) 2013 LEAP
-#
-# 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 3 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 for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-tests for leap_log_handler
-"""
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
-
-import logging
-
-from leap.bitmask.util.leap_log_handler import LeapLogHandler
-from leap.bitmask.util.pyside_tests_helper import BasicPySlotCase
-from leap.common.testing.basetest import BaseLeapTest
-
-from mock import Mock
-
-
-class LeapLogHandlerTest(BaseLeapTest, BasicPySlotCase):
- """
- LeapLogHandlerTest's tests.
- """
- def _callback(self, *args):
- """
- Simple callback to track if a signal was emitted.
- """
- self.called = True
- self.emitted_msg = args[0][LeapLogHandler.MESSAGE_KEY]
-
- def setUp(self):
- BasicPySlotCase.setUp(self)
-
- # Create the logger
- level = logging.DEBUG
- self.logger = logging.getLogger(name='test')
- self.logger.setLevel(level)
-
- # Create the handler
- self.leap_handler = LeapLogHandler()
- self.leap_handler.setLevel(level)
- self.logger.addHandler(self.leap_handler)
-
- def tearDown(self):
- BasicPySlotCase.tearDown(self)
- try:
- self.leap_handler.new_log.disconnect()
- except Exception:
- pass
-
- def test_history_starts_empty(self):
- self.assertEqual(self.leap_handler.log_history, [])
-
- def test_one_log_captured(self):
- self.logger.debug('test')
- self.assertEqual(len(self.leap_handler.log_history), 1)
-
- def test_history_records_order(self):
- self.logger.debug('test 01')
- self.logger.debug('test 02')
- self.logger.debug('test 03')
-
- logs = []
- for message in self.leap_handler.log_history:
- logs.append(message[LeapLogHandler.RECORD_KEY].msg)
-
- self.assertIn('test 01', logs)
- self.assertIn('test 02', logs)
- self.assertIn('test 03', logs)
-
- def test_history_messages_order(self):
- self.logger.debug('test 01')
- self.logger.debug('test 02')
- self.logger.debug('test 03')
-
- logs = []
- for message in self.leap_handler.log_history:
- logs.append(message[LeapLogHandler.MESSAGE_KEY])
-
- self.assertIn('test 01', logs[0])
- self.assertIn('test 02', logs[1])
- self.assertIn('test 03', logs[2])
-
- def test_emits_signal(self):
- log_format = '%(name)s - %(levelname)s - %(message)s'
- formatter = logging.Formatter(log_format)
- get_format = Mock(return_value=formatter)
- self.leap_handler._handler._get_format = get_format
-
- self.leap_handler.new_log.connect(self._callback)
- self.logger.debug('test')
-
- expected_log_msg = "test - DEBUG - test"
-
- # signal emitted
- self.assertTrue(self.called)
-
- # emitted message
- self.assertEqual(self.emitted_msg, expected_log_msg)
-
- # Mock called
- self.assertTrue(get_format.called)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/src/leap/bitmask/util/tests/test_streamtologger.py b/src/leap/bitmask/util/tests/test_streamtologger.py
deleted file mode 100644
index fc97b794..00000000
--- a/src/leap/bitmask/util/tests/test_streamtologger.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# -*- coding: utf-8 -*-
-# test_streamtologger.py
-# Copyright (C) 2013 LEAP
-#
-# 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 3 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 for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-tests for streamtologger
-"""
-
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
-
-import logging
-import sys
-
-from leap.bitmask.util.streamtologger import StreamToLogger
-from leap.common.testing.basetest import BaseLeapTest
-
-
-class SimpleLogHandler(logging.Handler):
- """
- The simplest log handler that allows to check if the log was
- delivered to the handler correctly.
- """
- def __init__(self):
- logging.Handler.__init__(self)
- self._last_log = ""
- self._last_log_level = ""
-
- def emit(self, record):
- self._last_log = record.getMessage()
- self._last_log_level = record.levelno
-
- def get_last_log(self):
- """
- Returns the last logged message by this handler.
-
- :return: the last logged message.
- :rtype: str
- """
- return self._last_log
-
- def get_last_log_level(self):
- """
- Returns the level of the last logged message by this handler.
-
- :return: the last logged level.
- :rtype: str
- """
- return self._last_log_level
-
-
-class StreamToLoggerTest(BaseLeapTest):
- """
- StreamToLogger's tests.
-
- NOTE: we may need to find a way to test the use case that an exception
- is raised. I couldn't catch the output of an exception because the
- test failed if some exception is raised.
- """
- def setUp(self):
- # Create the logger
- level = logging.DEBUG
- self.logger = logging.getLogger(name='test')
- self.logger.setLevel(level)
-
- # Simple log handler
- self.handler = SimpleLogHandler()
- self.logger.addHandler(self.handler)
-
- # Preserve original values
- self._sys_stdout = sys.stdout
- self._sys_stderr = sys.stderr
-
- # Create the handler
- sys.stdout = StreamToLogger(self.logger, logging.DEBUG)
- sys.stderr = StreamToLogger(self.logger, logging.ERROR)
-
- def tearDown(self):
- # Restore original values
- sys.stdout = self._sys_stdout
- sys.stderr = self._sys_stderr
-
- def test_logger_starts_empty(self):
- self.assertEqual(self.handler.get_last_log(), '')
-
- def test_standard_output(self):
- message = 'Test string'
- print message
-
- log = self.handler.get_last_log()
- log_level = self.handler.get_last_log_level()
-
- self.assertEqual(log, message)
- self.assertEqual(log_level, logging.DEBUG)
-
- def test_standard_error(self):
- message = 'Test string'
- sys.stderr.write(message)
-
- log_level = self.handler.get_last_log_level()
- log = self.handler.get_last_log()
-
- self.assertEqual(log, message)
- self.assertEqual(log_level, logging.ERROR)
-
- def test_twisted_log(self):
- from twisted.python import log
- log.startLogging(sys.stdout)
-
-
-if __name__ == "__main__":
- unittest.main(verbosity=2)