diff --git a/ckanext/odsh/fanstatic/tpsh_validate_password.js b/ckanext/odsh/fanstatic/tpsh_validate_password.js new file mode 100644 index 0000000000000000000000000000000000000000..f0f8f71b55e4f6a2cd9e52c6a39b09ab302d2dab --- /dev/null +++ b/ckanext/odsh/fanstatic/tpsh_validate_password.js @@ -0,0 +1,71 @@ +"use strict"; + +function isPasswordValid(password) { + if (password.length == 0) return true; + var minimumLength = 8; + var isValid = + (password.length >= minimumLength) && + (atLeastOneUpperCaseLetter(password)) && + (atLeastOneLowerCaseLetter(password)) && + (atLeastOneNoneLetter(password)); + return isValid + + function atLeastOneUpperCaseLetter(password) { + return (password !== password.toLowerCase()) + } + + function atLeastOneLowerCaseLetter(password) { + return (password !== password.toUpperCase()) + } + + function atLeastOneNoneLetter(password) { + return /[\W\d_]/.test(password) + } +} + + +function showPasswordStatus(isValid, inputElement) { + if (isValid) { + messageText = ''; + } else { + messageText = 'Passwörter müssen länger als 8 Zeichen sein und Großbuchstaben, Kleinbuchstaben und andere Zeichen enthalten.' + } + get_error_element(inputElement).innerHTML = messageText; + + function get_error_element(inputElement) { + // assumes that there is an element after input_element's parent that + // contains a class "inline-error" + var currentNode = inputElement.parentNode + do { + currentNode = currentNode.nextElementSibling; + } while ( + (currentNode !== null) && + !(currentNode.classList.contains('inline-error')) + ) + return currentNode + } +} + + +function setSubmitButtonState(isPasswordValid) { + var submitButton = document.getElementsByName('save')[0]; + submitButton.disabled = !isPasswordValid; +} + + +ckan.module('tpsh_validate_password', function ($) { + return { + initialize: function () { + $.proxyAll(this, /_on/); + this.el.on('input', this._onChange); + }, + + _onChange: function(event) { + var inputElement = event.target; + var newPassword = inputElement.value; + var isValid = isPasswordValid(newPassword); + showPasswordStatus(isValid, inputElement); + setSubmitButtonState(isValid); + } + }; +}); \ No newline at end of file diff --git a/ckanext/odsh/logic/action.py b/ckanext/odsh/logic/action.py index 8c707bcac4ff8ba8afb814010e7052ea0119bdb3..45880b8fdc03378ef303d3b446a38e5cf0454527 100644 --- a/ckanext/odsh/logic/action.py +++ b/ckanext/odsh/logic/action.py @@ -53,9 +53,6 @@ def check_password(password): any((c.isalpha()==False) for c in password)) #Number or Special character - - - def odsh_user_create(context, data_dict): model = context['model'] password = data_dict.get('password') @@ -66,10 +63,8 @@ def odsh_user_create(context, data_dict): for group in groups: group_member_create(context, {'id': group, 'username': user.get('name'), 'role': 'member'}) return model_dictize.user_dictize(model.User.get(user.get('name')), context) - else: - raise logic.ValidationError({'security': ['Passwort muss mindestens acht Zeichen, einen gross, einen klein Buchstaben und entweder eine Zahl oder Sondernzeichen enthalten!']}) - + raise logic.ValidationError({'security': ['Passwort muss mindestens acht Zeichen, einen gross, einen klein Buchstaben und entweder eine Zahl oder Sondernzeichen enthalten!']}) def tpsh_user_update(context, data_dict): password = data_dict.get('password') diff --git a/ckanext/odsh/templates/user/edit_user_form.html b/ckanext/odsh/templates/user/edit_user_form.html index 3395173452b1968ebbab4c5cacf8e7edca0d471e..be3545c6d2565a6bc29b1c4da16b207f56d1415a 100644 --- a/ckanext/odsh/templates/user/edit_user_form.html +++ b/ckanext/odsh/templates/user/edit_user_form.html @@ -1,4 +1,6 @@ {% import 'macros/form.html' as form %} +{% resource 'odsh/tpsh_validate_password.js' %} + <form id="user-edit-form" class="dataset-form form-horizontal" method="post" action="{{ action }}"> {{ form.errors(error_summary) }} @@ -34,7 +36,12 @@ attrs={'autocomplete': 'off'} ) }} +<<<<<<< HEAD {{ form.input('password1', type='password', label=_('Password'), id='field-password', value=data.password1, error=errors.password1, classes=['control-medium'], attrs={'autocomplete': 'off'} ) }} +======= + {{ form.input( + 'password1', type='password', label=_('Password'), id='field-password', value=data.password1, error=errors.password1, classes=['control-medium'], attrs={'autocomplete': 'off', 'data-module': 'tpsh_validate_password'} ) }} +>>>>>>> 5da13a4a8eb9f308d06e55026dd49aa00180f779 {{ form.input('password2', type='password', label=_('Confirm Password'), id='field-password-confirm', value=data.password2, error=errors.password2, classes=['control-medium'], attrs={'autocomplete': 'off'}) }} </fieldset> diff --git a/ckanext/odsh/tests_tpsh/test_checksum.py b/ckanext/odsh/tests_tpsh/test_checksum.py index e3e4afc81f3877f47b6fe7944ee5466293ae41d5..6bff5d4fe469025e396c8b7e291e0d99106aad36 100644 --- a/ckanext/odsh/tests_tpsh/test_checksum.py +++ b/ckanext/odsh/tests_tpsh/test_checksum.py @@ -1,6 +1,6 @@ from mock import patch, mock_open import nose.tools as nt -from ckanext.odsh.lib.uploader import _raise_validation_error_if_hash_values_differ, _calculate_hash +from ckanext.odsh.lib.uploader import _raise_validation_error_if_hash_values_differ, calculate_hash import ckantoolkit as ct import ckan.logic as logic import hashlib @@ -51,7 +51,7 @@ class testHashException(object): # md5sum test.pdf expected_hash_pdf = '66123edf64fabf1c073fc45478bf4a57' with open(dir_path + '/resources/test.pdf') as f: - hash = _calculate_hash(f) + hash = calculate_hash(f) nt.assert_equal(hash, expected_hash_pdf) diff --git a/ckanext/odsh/tests_tpsh/test_password_validation.py b/ckanext/odsh/tests_tpsh/test_password_validation.py new file mode 100644 index 0000000000000000000000000000000000000000..c999b3974784df07d2da8c3d40ac1d9e11e8026d --- /dev/null +++ b/ckanext/odsh/tests_tpsh/test_password_validation.py @@ -0,0 +1,35 @@ +# encoding: utf-8 + +import nose.tools as nt +from ckanext.odsh.logic.action import check_password + +class Test_PasswordValidation(object): + + @staticmethod + def assert_password_invalid(password): + assert not check_password(password) + + @staticmethod + def assert_password_valid(password): + assert check_password(password) + + def test_valid_password(self): + self.assert_password_valid('Passwort1 :) :P :D') + + def test_umlaute(self): + self.assert_password_valid('Pässword') + + def test_no_uppercase(self): + self.assert_password_invalid('passwort1') + + def test_no_lowercase(self): + self.assert_password_invalid('PASSWORT1') + + def test_no_letters(self): + self.assert_password_invalid('37459073245!!?===))/=$§äüöÄÜÖ') + + def test_only_letters(self): + self.assert_password_invalid('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') + + def test_to_short(self): + self.assert_password_invalid('Pw123') \ No newline at end of file