Rock Lobster
Rock Lobster

Reputation: 35

Python Password Checker

I need some help figuring out how to make a function that checks a string for a bunch of conditions.

right now this is all that I have

def passwordChecker(password):
    '''
    '''
    caps = sum(1 for c in password if c.isupper())
    nums = sum(1 for c in password if c.isdigit())
    symb = any(c in password for c in '!@#$%^&')
    note = any(c in password for c in 'Ee')
    if len(password) <5:
        return False
    elif caps < 1:
        return False
    elif nums < 1:
        return False
    elif symb == False:
        return False
    else:
        return True

Edit**

Just realized that I have to check also if there are commonly used passwords like 'password' or '111111' and I dont really know about how I would approach this.

Upvotes: 2

Views: 2462

Answers (5)

pzp
pzp

Reputation: 6607

Yet another way to do this...

def passwordChecker(password):
    return (len(password) > 4 and
            len(filter(str.isupper, password)) > 0 and
            len(filter(str.isdigit, password)) > 1 and
            'e' not in password.lower() and
            any(special in password for special in '!@#$%^&') and
            password not in ('password', '111111'))

I think the most interesting part of my solution is the use of filter; some people like it, others hate it. Anyway, all of the other solutions work just as well. Just thought I'd throw this one into the mix for completeness.

Upvotes: 0

Adam Smith
Adam Smith

Reputation: 54223

This is a good time to talk about decorators! I love using decorators to validate data, probably too much. You could make validators for all that, and wrap it around your get_password method.

def v_length(password):
    return len(password) >= 5
def v_upper(password):
    return password.lower() != password
def v_2_nums(password):
    return sum(c.isdigit() for c in password) >= 2
def v_no_e(password):
    return "e" not in password.lower()
def v_specialchar(password):
    any(s in password for s in "!@#$%^&")

def validator(*tests):
    def wrap(func):
        def wrapped(*args, **kwargs):
            result = func(*args, **kwargs)
            if not all(test(result) for test in tests):
                # fail the input somehow -- how??
            return result
        return wrapped
    return wrap

@validator(v_length, v_upper, v_2_nums, v_no_e, v_specialchar)
def get_password():
    pwd = input("Enter your password: ")

I like to wrap my validators in their own factories when I do this in real code, so that it's easier to change per application

def v_length(min_length):
    def wrapped(password):
        return len(password) >= min_length
    return wrapped

@validator(v_length(8))
def get_weak_password():
    input("Enter your wussy password: ")

@validator(v_length(64))
def get_strong_password():
    input("Enter your Herculean password: ")

This second approach works well for checking for common passwords.

def v_common(common_pwd_set):
    def wrapped(password):
        return password not in common_pwd_set
    return wrapped

COMMON_PASSWORDS = {"hunter2", "111111", "password"}
@validator(v_common(COMMON_PASSWORDS))
def get_password():
    pwd = input("Use a tricksy one! ")

Upvotes: 1

Stefan Pochmann
Stefan Pochmann

Reputation: 28656

Just an alternative using regular expressions:

import re
def passwordChecker(password):
    return all(re.search(pattern, password) for pattern in
               ('.{5}', '[A-Z]', '\d.*\d', '^[^Ee]*$', '[!@#$%^&]'))

Demo using five barely invalid and five barely valid tests (one invalid and one valid for each of the five rules):

for password in ('1A!',   '12!34', 'A1bc!', 'A12E!', 'A12bc',
                 '1A!2.', 'A2!34', 'A12c!', 'A12b!', 'A12b@'):
    print(passwordChecker(password))

Prints False for the first five and True for the last five.

Upvotes: 2

TigerhawkT3
TigerhawkT3

Reputation: 49330

The following checks for each failure condition, with short-circuiting (it'll stop checking once it finds something). The "common" passwords aren't really common, but I wanted values that would pass the rest of the checks.

def passwordChecker(password):
    '''
    A password checker. Returns True if the password is acceptable; False otherwise.
    '''
    if (len(password) < 5 or
        not any(c.isupper() for c in password) or
        sum(c.isdigit() for c in password) < 2 or
        'e' in password.lower() or
        not (set(password) & set('!@#$%^&')) or
        password in {'Password12!', 'Passwd12!'}):
        return False
    return True

>>> passwordChecker('Password12!')
False
>>> passwordChecker('hi')
False
>>> passwordChecker('H12!')
False
>>> passwordChecker('Hi12!')
True

Upvotes: 0

fferri
fferri

Reputation: 18950

you are just missing a branch

elif note:
    return False

before the else:

Upvotes: 1

Related Questions