Initial commit
This commit is contained in:
29
quart_imp/auth/__init__.py
Normal file
29
quart_imp/auth/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from .__legacy__ import Auth
|
||||
from .authenticate_password import authenticate_password
|
||||
from .dataclasses import PasswordGeneration
|
||||
from .encrypt_password import encrypt_password
|
||||
from .generate_alphanumeric_validator import generate_alphanumeric_validator
|
||||
from .generate_csrf_token import generate_csrf_token
|
||||
from .generate_email_validator import generate_email_validator
|
||||
from .generate_numeric_validator import generate_numeric_validator
|
||||
from .generate_password import generate_password
|
||||
from .generate_private_key import generate_private_key
|
||||
from .generate_salt import generate_salt
|
||||
from .is_email_address_valid import is_email_address_valid
|
||||
from .is_username_valid import is_username_valid
|
||||
|
||||
__all__ = [
|
||||
"PasswordGeneration",
|
||||
"is_email_address_valid",
|
||||
"is_username_valid",
|
||||
"generate_csrf_token",
|
||||
"generate_private_key",
|
||||
"generate_numeric_validator",
|
||||
"generate_alphanumeric_validator",
|
||||
"generate_email_validator",
|
||||
"generate_salt",
|
||||
"encrypt_password",
|
||||
"authenticate_password",
|
||||
"generate_password",
|
||||
"Auth",
|
||||
]
|
||||
178
quart_imp/auth/__legacy__.py
Normal file
178
quart_imp/auth/__legacy__.py
Normal file
@@ -0,0 +1,178 @@
|
||||
import typing as t
|
||||
from random import choice
|
||||
from string import ascii_letters
|
||||
|
||||
from .authenticate_password import authenticate_password
|
||||
from .encrypt_password import encrypt_password
|
||||
from .generate_alphanumeric_validator import generate_alphanumeric_validator
|
||||
from .generate_csrf_token import generate_csrf_token
|
||||
from .generate_email_validator import generate_email_validator
|
||||
from .generate_numeric_validator import generate_numeric_validator
|
||||
from .generate_password import generate_password
|
||||
from .generate_private_key import generate_private_key
|
||||
from .generate_salt import generate_salt
|
||||
from .is_email_address_valid import is_email_address_valid
|
||||
from .is_username_valid import is_username_valid
|
||||
|
||||
|
||||
def auth_password(
|
||||
cls,
|
||||
input_password: str,
|
||||
database_password: str,
|
||||
database_salt: str,
|
||||
encrypt: int = 512,
|
||||
pepper_length: int = 1,
|
||||
) -> bool:
|
||||
"""Legacy method, use authenticate_password instead"""
|
||||
return cls.authenticate_password(
|
||||
input_password, database_password, database_salt, encrypt, pepper_length
|
||||
)
|
||||
|
||||
|
||||
def hash_password(
|
||||
password: str, salt: str, encrypt: int = 512, pepper_length: int = 1
|
||||
) -> str:
|
||||
"""Legacy method, use encrypt_password instead"""
|
||||
return encrypt_password(password, salt, encrypt, pepper_length)
|
||||
|
||||
|
||||
def sha_password(
|
||||
password: str, salt: str, encrypt: int = 512, pepper_length: int = 1
|
||||
) -> str:
|
||||
"""Legacy method, use encrypt_password instead"""
|
||||
return hash_password(password, salt, encrypt, pepper_length)
|
||||
|
||||
|
||||
def generate_pepper(password: str, length: int = 1) -> str:
|
||||
"""Legacy method, stop using this"""
|
||||
return "".join(choice(ascii_letters) for _ in range(length)) + password
|
||||
|
||||
|
||||
def generate_form_token() -> str:
|
||||
"""Legacy method, use generate_csrf_token instead"""
|
||||
return generate_csrf_token()
|
||||
|
||||
|
||||
class Auth:
|
||||
@classmethod
|
||||
def is_email_address_valid(cls, email_address: str) -> bool:
|
||||
"""Legacy class method, use from quart_imp.auth import is_email_address_valid instead"""
|
||||
return is_email_address_valid(email_address)
|
||||
|
||||
@classmethod
|
||||
def is_username_valid(
|
||||
cls,
|
||||
username: str,
|
||||
allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None,
|
||||
) -> bool:
|
||||
"""Legacy class method, use from quart_imp.auth import is_username_valid instead"""
|
||||
return is_username_valid(username, allowed)
|
||||
|
||||
@classmethod
|
||||
def generate_csrf_token(cls) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_csrf_token instead"""
|
||||
return generate_csrf_token()
|
||||
|
||||
@classmethod
|
||||
def generate_private_key(cls, hook: t.Optional[str]) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_private_key instead"""
|
||||
return generate_private_key(hook)
|
||||
|
||||
@classmethod
|
||||
def generate_numeric_validator(cls, length: int) -> int:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_numeric_validator instead"""
|
||||
return generate_numeric_validator(length)
|
||||
|
||||
@classmethod
|
||||
def generate_alphanumeric_validator(cls, length: int) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_alphanumeric_validator instead"""
|
||||
return generate_alphanumeric_validator(length)
|
||||
|
||||
@classmethod
|
||||
def generate_email_validator(cls) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_private_key instead"""
|
||||
return generate_email_validator()
|
||||
|
||||
@classmethod
|
||||
def generate_salt(cls, length: int = 4) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_salt instead"""
|
||||
return generate_salt(length)
|
||||
|
||||
@classmethod
|
||||
def encrypt_password(
|
||||
cls,
|
||||
password: str,
|
||||
salt: str,
|
||||
encryption_level: int = 512,
|
||||
pepper_length: int = 1,
|
||||
pepper_position: t.Literal["start", "end"] = "end",
|
||||
) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import encrypt_password instead"""
|
||||
return encrypt_password(
|
||||
password, salt, encryption_level, pepper_length, pepper_position
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def authenticate_password(
|
||||
cls,
|
||||
input_password: str,
|
||||
database_password: str,
|
||||
database_salt: str,
|
||||
encryption_level: int = 512,
|
||||
pepper_length: int = 1,
|
||||
pepper_position: t.Literal["start", "end"] = "end",
|
||||
) -> bool:
|
||||
"""Legacy class method, use from quart_imp.auth import authenticate_password instead"""
|
||||
return authenticate_password(
|
||||
input_password,
|
||||
database_password,
|
||||
database_salt,
|
||||
encryption_level,
|
||||
pepper_length,
|
||||
pepper_position,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_password(cls, style: str = "mixed", length: int = 3) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_password instead"""
|
||||
return generate_password(style, length)
|
||||
|
||||
# LEGACY METHODS
|
||||
|
||||
@classmethod
|
||||
def auth_password(
|
||||
cls,
|
||||
input_password: str,
|
||||
database_password: str,
|
||||
database_salt: str,
|
||||
encrypt: int = 512,
|
||||
pepper_length: int = 1,
|
||||
) -> bool:
|
||||
"""Legacy class method, use from quart_imp.auth import authenticate_password instead"""
|
||||
return authenticate_password(
|
||||
input_password, database_password, database_salt, encrypt, pepper_length
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def hash_password(
|
||||
cls, password: str, salt: str, encrypt: int = 512, pepper_length: int = 1
|
||||
) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import encrypt_password instead"""
|
||||
return encrypt_password(password, salt, encrypt, pepper_length)
|
||||
|
||||
@classmethod
|
||||
def sha_password(
|
||||
cls, password: str, salt: str, encrypt: int = 512, pepper_length: int = 1
|
||||
) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import encrypt_password instead"""
|
||||
return encrypt_password(password, salt, encrypt, pepper_length)
|
||||
|
||||
@classmethod
|
||||
def generate_pepper(cls, password: str, length: int = 1) -> str:
|
||||
"""Legacy class method, stop using this"""
|
||||
return "".join(choice(ascii_letters) for _ in range(length)) + password
|
||||
|
||||
@classmethod
|
||||
def generate_form_token(cls) -> str:
|
||||
"""Legacy class method, use from quart_imp.auth import generate_csrf_token instead"""
|
||||
return generate_csrf_token()
|
||||
33
quart_imp/auth/__private_funcs__.py
Normal file
33
quart_imp/auth/__private_funcs__.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import typing as t
|
||||
from hashlib import sha256, sha512
|
||||
|
||||
|
||||
def _pps(pepper_, pass_, salt_) -> str:
|
||||
return pepper_ + pass_ + salt_
|
||||
|
||||
|
||||
def _ppe(pepper_, pass_, salt_) -> str:
|
||||
return pass_ + pepper_ + salt_
|
||||
|
||||
|
||||
def _guess_block(
|
||||
guesses: set,
|
||||
input_password: str,
|
||||
database_password: str,
|
||||
database_salt: str,
|
||||
encryption_level: int = 512,
|
||||
pepper_position: t.Literal["start", "end"] = "end",
|
||||
) -> bool:
|
||||
for guess in guesses:
|
||||
_sha = sha512() if encryption_level == 512 else sha256()
|
||||
_sha.update(
|
||||
(
|
||||
_pps(guess, input_password, database_salt)
|
||||
if pepper_position == "start"
|
||||
else _ppe(guess, input_password, database_salt)
|
||||
).encode("utf-8")
|
||||
)
|
||||
if _sha.hexdigest() == database_password:
|
||||
return True
|
||||
|
||||
return False
|
||||
92
quart_imp/auth/authenticate_password.py
Normal file
92
quart_imp/auth/authenticate_password.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import multiprocessing
|
||||
import typing as t
|
||||
from itertools import product
|
||||
from string import ascii_letters
|
||||
|
||||
from more_itertools import batched
|
||||
|
||||
from .__private_funcs__ import _guess_block
|
||||
|
||||
|
||||
def authenticate_password(
|
||||
input_password: str,
|
||||
database_password: str,
|
||||
database_salt: str,
|
||||
encryption_level: int = 512,
|
||||
pepper_length: int = 1,
|
||||
pepper_position: t.Literal["start", "end"] = "end",
|
||||
use_multiprocessing: bool = False,
|
||||
) -> bool:
|
||||
"""
|
||||
Takes the plain input password, the stored hashed password along with the stored salt
|
||||
and will try every possible combination of pepper values to find a match.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
NOTE: use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent
|
||||
commonly used with socketio.
|
||||
|
||||
.. Note::
|
||||
|
||||
You must know the length of the pepper used to hash the password.
|
||||
|
||||
You must know the position of the pepper used to hash the password.
|
||||
|
||||
You must know the encryption level used to hash the password.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:param input_password: str - plain password
|
||||
:param database_password: str - hashed password from database
|
||||
:param database_salt: str - salt from database
|
||||
:param encryption_level: int - encryption used to generate database password
|
||||
:param pepper_length: int - length of pepper used to generate database password
|
||||
:param pepper_position: str - "start" or "end" - position of pepper used to generate database password
|
||||
:param use_multiprocessing: bool - use multiprocessing to speed up the process (not compatible with eventlet/gevent)
|
||||
:return: bool - True if match, False if not
|
||||
"""
|
||||
|
||||
if pepper_length > 3:
|
||||
pepper_length = 3
|
||||
|
||||
_guesses = {"".join(i) for i in product(ascii_letters, repeat=pepper_length)}
|
||||
|
||||
if not use_multiprocessing:
|
||||
for guess in _guesses:
|
||||
if _guess_block(
|
||||
{guess},
|
||||
input_password,
|
||||
database_password,
|
||||
database_salt,
|
||||
encryption_level,
|
||||
pepper_position,
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
thread_pool = multiprocessing.Pool(processes=pepper_length)
|
||||
threads = []
|
||||
|
||||
for batch in batched(_guesses, 1000):
|
||||
threads.append(
|
||||
thread_pool.apply_async(
|
||||
_guess_block,
|
||||
args=(
|
||||
batch,
|
||||
input_password,
|
||||
database_password,
|
||||
database_salt,
|
||||
encryption_level,
|
||||
pepper_position,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
for thread in threads:
|
||||
if thread.get():
|
||||
return True
|
||||
|
||||
return False
|
||||
767
quart_imp/auth/dataclasses.py
Normal file
767
quart_imp/auth/dataclasses.py
Normal file
@@ -0,0 +1,767 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PasswordGeneration:
|
||||
"""
|
||||
This is a bank of words used to generate random passwords.
|
||||
"""
|
||||
|
||||
animals = [
|
||||
"Canidae",
|
||||
"Felidae",
|
||||
"Cat",
|
||||
"Cattle",
|
||||
"Dog",
|
||||
"Donkey",
|
||||
"Goat",
|
||||
"Horse",
|
||||
"Pig",
|
||||
"Rabbit",
|
||||
"Aardvark",
|
||||
"Aardwolf",
|
||||
"Albatross",
|
||||
"Alligator",
|
||||
"Alpaca",
|
||||
"Amphibian",
|
||||
"Anaconda",
|
||||
"Angelfish",
|
||||
"Anglerfish",
|
||||
"Ant",
|
||||
"Anteater",
|
||||
"Antelope",
|
||||
"Antlion",
|
||||
"Ape",
|
||||
"Aphid",
|
||||
"Armadillo",
|
||||
"Asp",
|
||||
"Baboon",
|
||||
"Badger",
|
||||
"Bandicoot",
|
||||
"Barnacle",
|
||||
"Barracuda",
|
||||
"Basilisk",
|
||||
"Bass",
|
||||
"Bat",
|
||||
"Bear",
|
||||
"Beaver",
|
||||
"Bedbug",
|
||||
"Bee",
|
||||
"Beetle",
|
||||
"Bird",
|
||||
"Bison",
|
||||
"Blackbird",
|
||||
"Boa",
|
||||
"Boar",
|
||||
"Bobcat",
|
||||
"Bobolink",
|
||||
"Bonobo",
|
||||
"Bovid",
|
||||
"Bug",
|
||||
"Butterfly",
|
||||
"Buzzard",
|
||||
"Camel",
|
||||
"Canid",
|
||||
"Capybara",
|
||||
"Cardinal",
|
||||
"Caribou",
|
||||
"Carp",
|
||||
"Cat",
|
||||
"Catshark",
|
||||
"Caterpillar",
|
||||
"Catfish",
|
||||
"Cattle",
|
||||
"Centipede",
|
||||
"Cephalopod",
|
||||
"Chameleon",
|
||||
"Cheetah",
|
||||
"Chickadee",
|
||||
"Chicken",
|
||||
"Chimpanzee",
|
||||
"Chinchilla",
|
||||
"Chipmunk",
|
||||
"Clam",
|
||||
"Clownfish",
|
||||
"Cobra",
|
||||
"Cockroach",
|
||||
"Cod",
|
||||
"Condor",
|
||||
"Constrictor",
|
||||
"Coral",
|
||||
"Cougar",
|
||||
"Cow",
|
||||
"Coyote",
|
||||
"Crab",
|
||||
"Crane",
|
||||
"Crawdad",
|
||||
"Crayfish",
|
||||
"Cricket",
|
||||
"Crocodile",
|
||||
"Crow",
|
||||
"Cuckoo",
|
||||
"Cicada",
|
||||
"Damselfly",
|
||||
"Deer",
|
||||
"Dingo",
|
||||
"Dinosaur",
|
||||
"Dog",
|
||||
"Dolphin",
|
||||
"Donkey",
|
||||
"Dormouse",
|
||||
"Dove",
|
||||
"Dragonfly",
|
||||
"Dragon",
|
||||
"Duck",
|
||||
"Eagle",
|
||||
"Earthworm",
|
||||
"Earwig",
|
||||
"Echidna",
|
||||
"Eel",
|
||||
"Egret",
|
||||
"Elephant",
|
||||
"Elk",
|
||||
"Emu",
|
||||
"Ermine",
|
||||
"Falcon",
|
||||
"Ferret",
|
||||
"Finch",
|
||||
"Firefly",
|
||||
"Fish",
|
||||
"Flamingo",
|
||||
"Flea",
|
||||
"Fly",
|
||||
"Flyingfish",
|
||||
"Fowl",
|
||||
"Fox",
|
||||
"Frog",
|
||||
"Gamefowl",
|
||||
"Galliform",
|
||||
"Gazelle",
|
||||
"Gecko",
|
||||
"Gerbil",
|
||||
"Gibbon",
|
||||
"Giraffe",
|
||||
"Goat",
|
||||
"Goldfish",
|
||||
"Goose",
|
||||
"Gopher",
|
||||
"Gorilla",
|
||||
"Grasshopper",
|
||||
"Grouse",
|
||||
"Guan",
|
||||
"Guanaco",
|
||||
"Guineafowl",
|
||||
"Gull",
|
||||
"Guppy",
|
||||
"Haddock",
|
||||
"Halibut",
|
||||
"Hamster",
|
||||
"Hare",
|
||||
"Harrier",
|
||||
"Hawk",
|
||||
"Hedgehog",
|
||||
"Heron",
|
||||
"Herring",
|
||||
"Hippopotamus",
|
||||
"Hookworm",
|
||||
"Hornet",
|
||||
"Horse",
|
||||
"Hoverfly",
|
||||
"Hummingbird",
|
||||
"Hyena",
|
||||
"Iguana",
|
||||
"Impala",
|
||||
"Jackal",
|
||||
"Jaguar",
|
||||
"Jay",
|
||||
"Jellyfish",
|
||||
"Junglefowl",
|
||||
"Kangaroo",
|
||||
"Kingfisher",
|
||||
"Kite",
|
||||
"Kiwi",
|
||||
"Koala",
|
||||
"Koi",
|
||||
"Krill",
|
||||
"Ladybug",
|
||||
"Lamprey",
|
||||
"Landfowl",
|
||||
"Lark",
|
||||
"Leech",
|
||||
"Lemming",
|
||||
"Lemur",
|
||||
"Leopard",
|
||||
"Leopon",
|
||||
"Limpet",
|
||||
"Lion",
|
||||
"Lizard",
|
||||
"Llama",
|
||||
"Lobster",
|
||||
"Locust",
|
||||
"Loon",
|
||||
"Louse",
|
||||
"Lungfish",
|
||||
"Lynx",
|
||||
"Macaw",
|
||||
"Mackerel",
|
||||
"Magpie",
|
||||
"Mammal",
|
||||
"Manatee",
|
||||
"Mandrill",
|
||||
"Marlin",
|
||||
"Marmoset",
|
||||
"Marmot",
|
||||
"Marsupial",
|
||||
"Marten",
|
||||
"Mastodon",
|
||||
"Meadowlark",
|
||||
"Meerkat",
|
||||
"Mink",
|
||||
"Minnow",
|
||||
"Mite",
|
||||
"Mockingbird",
|
||||
"Mole",
|
||||
"Mollusk",
|
||||
"Mongoose",
|
||||
"Monkey",
|
||||
"Moose",
|
||||
"Mosquito",
|
||||
"Moth",
|
||||
"Mouse",
|
||||
"Mule",
|
||||
"Muskox",
|
||||
"Narwhal",
|
||||
"Newt",
|
||||
"Nightingale",
|
||||
"Ocelot",
|
||||
"Octopus",
|
||||
"Opossum",
|
||||
"Orangutan",
|
||||
"Orca",
|
||||
"Ostrich",
|
||||
"Otter",
|
||||
"Owl",
|
||||
"Ox",
|
||||
"Panda",
|
||||
"Panther",
|
||||
"Parakeet",
|
||||
"Parrot",
|
||||
"Parrotfish",
|
||||
"Partridge",
|
||||
"Peacock",
|
||||
"Peafowl",
|
||||
"Pelican",
|
||||
"Penguin",
|
||||
"Perch",
|
||||
"Pheasant",
|
||||
"Pig",
|
||||
"Pigeon",
|
||||
"Pike",
|
||||
"Pinniped",
|
||||
"Piranha",
|
||||
"Planarian",
|
||||
"Platypus",
|
||||
"Pony",
|
||||
"Porcupine",
|
||||
"Porpoise",
|
||||
"Possum",
|
||||
"Prawn",
|
||||
"Primate",
|
||||
"Ptarmigan",
|
||||
"Puffin",
|
||||
"Puma",
|
||||
"Python",
|
||||
"Quail",
|
||||
"Quelea",
|
||||
"Quokka",
|
||||
"Rabbit",
|
||||
"Raccoon",
|
||||
"Rat",
|
||||
"Rattlesnake",
|
||||
"Raven",
|
||||
"Reindeer",
|
||||
"Reptile",
|
||||
"Rhinoceros",
|
||||
"Roadrunner",
|
||||
"Rodent",
|
||||
"Rook",
|
||||
"Rooster",
|
||||
"Roundworm",
|
||||
"Sailfish",
|
||||
"Salamander",
|
||||
"Salmon",
|
||||
"Sawfish",
|
||||
"Scallop",
|
||||
"Scorpion",
|
||||
"Seahorse",
|
||||
"Shark",
|
||||
"Sheep",
|
||||
"Shrew",
|
||||
"Shrimp",
|
||||
"Silkworm",
|
||||
"Silverfish",
|
||||
"Skink",
|
||||
"Skunk",
|
||||
"Sloth",
|
||||
"Slug",
|
||||
"Smelt",
|
||||
"Snail",
|
||||
"Snake",
|
||||
"Snipe",
|
||||
"Sole",
|
||||
"Sparrow",
|
||||
"Spider",
|
||||
"Spoonbill",
|
||||
"Squid",
|
||||
"Squirrel",
|
||||
"Starfish",
|
||||
"Stingray",
|
||||
"Stoat",
|
||||
"Stork",
|
||||
"Sturgeon",
|
||||
"Swallow",
|
||||
"Swan",
|
||||
"Swift",
|
||||
"Swordfish",
|
||||
"Swordtail",
|
||||
"Tahr",
|
||||
"Takin",
|
||||
"Tapir",
|
||||
"Tarantula",
|
||||
"Tarsier",
|
||||
"Termite",
|
||||
"Tern",
|
||||
"Thrush",
|
||||
"Tick",
|
||||
"Tiger",
|
||||
"Tiglon",
|
||||
"Toad",
|
||||
"Tortoise",
|
||||
"Toucan",
|
||||
"Trout",
|
||||
"Tuna",
|
||||
"Turkey",
|
||||
"Turtle",
|
||||
"Tyrannosaurus",
|
||||
"Urial",
|
||||
"Vicuna",
|
||||
"Viper",
|
||||
"Vole",
|
||||
"Vulture",
|
||||
"Wallaby",
|
||||
"Walrus",
|
||||
"Wasp",
|
||||
"Warbler",
|
||||
"Weasel",
|
||||
"Whale",
|
||||
"Whippet",
|
||||
"Whitefish",
|
||||
"Wildcat",
|
||||
"Wildebeest",
|
||||
"Wildfowl",
|
||||
"Wolf",
|
||||
"Wolverine",
|
||||
"Wombat",
|
||||
"Woodpecker",
|
||||
"Worm",
|
||||
"Wren",
|
||||
"Xerinae",
|
||||
"Yak",
|
||||
"Zebra",
|
||||
"Alpaca",
|
||||
"Cat",
|
||||
"Cattle",
|
||||
"Chicken",
|
||||
"Dog",
|
||||
"Donkey",
|
||||
"Ferret",
|
||||
"Gayal",
|
||||
"Goldfish",
|
||||
"Guppy",
|
||||
"Horse",
|
||||
"Koi",
|
||||
"Llama",
|
||||
"Sheep",
|
||||
"Yak",
|
||||
]
|
||||
|
||||
colors = [
|
||||
"DarkViolet",
|
||||
"MediumVioletRed",
|
||||
"Rose",
|
||||
"Avocado",
|
||||
"Greenish",
|
||||
"Blood",
|
||||
"Sangria",
|
||||
"Pastel",
|
||||
"Night",
|
||||
"Celeste",
|
||||
"Ocean",
|
||||
"Cloudy",
|
||||
"Battleship",
|
||||
"Oak",
|
||||
"BlanchedAlmond",
|
||||
"Gold",
|
||||
"Slate",
|
||||
"DarkGray",
|
||||
"MidnightBlue",
|
||||
"PeachPuff",
|
||||
"Dark",
|
||||
"Chartreuse",
|
||||
"Bashful",
|
||||
"PaleVioletRed",
|
||||
"DarkTurquoise",
|
||||
"Grapefruit",
|
||||
"Sun",
|
||||
"Eggplant",
|
||||
"Golden",
|
||||
"Cyan",
|
||||
"Sand",
|
||||
"LightYellow",
|
||||
"Cobalt",
|
||||
"Tron",
|
||||
"Ruby",
|
||||
"Mustard",
|
||||
"AntiqueWhite",
|
||||
"Western",
|
||||
"Deep-Sea",
|
||||
"Iron",
|
||||
"LimeGreen",
|
||||
"Orange",
|
||||
"DarkCyan",
|
||||
"Velvet",
|
||||
"Clover",
|
||||
"Butterfly",
|
||||
"Jasmine",
|
||||
"Fire",
|
||||
"DarkSlateGray",
|
||||
"Heliotrope",
|
||||
"Scarlet",
|
||||
"Medium",
|
||||
"Unbleached",
|
||||
"Dimorphotheca",
|
||||
"Cornsilk",
|
||||
"GoldenRod",
|
||||
"Beer",
|
||||
"Canary",
|
||||
"DeepPink",
|
||||
"Sunrise",
|
||||
"SlateGray",
|
||||
"Burnt",
|
||||
"Algae",
|
||||
"Granite",
|
||||
"Baby",
|
||||
"Cream",
|
||||
"LightBlue",
|
||||
"Tan",
|
||||
"Yellow",
|
||||
"Burgundy",
|
||||
"Cherry",
|
||||
"Papaya",
|
||||
"Lapis",
|
||||
"Robin",
|
||||
"Mango",
|
||||
"Blush",
|
||||
"Blueberry",
|
||||
"Roman",
|
||||
"Bisque",
|
||||
"Iceberg",
|
||||
"Rosy",
|
||||
"Teal",
|
||||
"SeaShell",
|
||||
"Copper",
|
||||
"Pea",
|
||||
"Jeans",
|
||||
"Watermelon",
|
||||
"Grayish",
|
||||
"Flamingo",
|
||||
"Rich",
|
||||
"Navy",
|
||||
"Raspberry",
|
||||
"Lime",
|
||||
"Halloween",
|
||||
"RosyBrown",
|
||||
"Tangerine",
|
||||
"Sea",
|
||||
"Wood",
|
||||
"MediumOrchid",
|
||||
"Shamrock",
|
||||
"Chameleon",
|
||||
"Glacial",
|
||||
"BlueViolet",
|
||||
"Deep",
|
||||
"FloralWhite",
|
||||
"Fall",
|
||||
"Black",
|
||||
"Marble",
|
||||
"Hazel",
|
||||
"Hot",
|
||||
"DarkSalmon",
|
||||
"LavenderBlush",
|
||||
"Organic",
|
||||
"Violet",
|
||||
"MintCream",
|
||||
"Slime",
|
||||
"DarkSlateBlue",
|
||||
"DodgerBlue",
|
||||
"MediumSpringGreen",
|
||||
"Bee",
|
||||
"Jade",
|
||||
"Sage",
|
||||
"Egg",
|
||||
"Neon",
|
||||
"WhiteSmoke",
|
||||
"Grape",
|
||||
"LightCyan",
|
||||
"Acid",
|
||||
"Day",
|
||||
"Earth",
|
||||
"Olive",
|
||||
"Balloon",
|
||||
"Pine",
|
||||
"Rice",
|
||||
"OliveDrab",
|
||||
"Tulip",
|
||||
"Corn",
|
||||
"Rosy-Finch",
|
||||
"Dirty",
|
||||
"Coffee",
|
||||
"Vampire",
|
||||
"Pig",
|
||||
"Jellyfish",
|
||||
"Salmon",
|
||||
"Vermilion",
|
||||
"Camouflage",
|
||||
"IndianRed",
|
||||
"Mint",
|
||||
"Viola",
|
||||
"Venom",
|
||||
"Cookie",
|
||||
"HoneyDew",
|
||||
"MediumSeaGreen",
|
||||
"DarkMagenta",
|
||||
"Magic",
|
||||
"DarkGoldenRod",
|
||||
"Lipstick",
|
||||
"Tomato",
|
||||
"Lavender",
|
||||
"LightSkyBlue",
|
||||
"Midday",
|
||||
"Seafoam",
|
||||
"CornflowerBlue",
|
||||
"GhostWhite",
|
||||
"Carbon",
|
||||
"PapayaWhip",
|
||||
"Wheat",
|
||||
"Harvest",
|
||||
"SteelBlue",
|
||||
"Gulf",
|
||||
"Mauve",
|
||||
"Champagne",
|
||||
"DarkOliveGreen",
|
||||
"PaleGoldenRod",
|
||||
"Oil",
|
||||
"Clematis",
|
||||
"Deer",
|
||||
"Purple",
|
||||
"LightGray",
|
||||
"Parchment",
|
||||
"PaleTurquoise",
|
||||
"Northern",
|
||||
"MistyRose",
|
||||
"Tea",
|
||||
"Ginger",
|
||||
"New",
|
||||
"AliceBlue",
|
||||
"Jungle",
|
||||
"SlateBlue",
|
||||
"Khaki",
|
||||
"RebeccaPurple",
|
||||
"Pale",
|
||||
"Water",
|
||||
"School",
|
||||
"Sepia",
|
||||
"Wisteria",
|
||||
"LightPink",
|
||||
"Stoplight",
|
||||
"Seaweed",
|
||||
"DimGray",
|
||||
"Mocha",
|
||||
"LightGoldenRodYellow",
|
||||
"Donut",
|
||||
"Basket",
|
||||
"Dusty",
|
||||
"Construction",
|
||||
"Metallic",
|
||||
"Chestnut",
|
||||
"Light",
|
||||
"Fuchsia",
|
||||
"SeaGreen",
|
||||
"Plum",
|
||||
"RoyalBlue",
|
||||
"BurlyWood",
|
||||
"Azure",
|
||||
"Very",
|
||||
"Aztech",
|
||||
"Gray",
|
||||
"DarkSeaGreen",
|
||||
"LemonChiffon",
|
||||
"FireBrick",
|
||||
"Dull",
|
||||
"Brown",
|
||||
"Ash",
|
||||
"Denim",
|
||||
"Dull-Sea",
|
||||
"Sapphire",
|
||||
"Carnation",
|
||||
"Antique",
|
||||
"Dragon",
|
||||
"PaleGreen",
|
||||
"LightSteelBlue",
|
||||
"Cinnamon",
|
||||
"Heavenly",
|
||||
"Sonic",
|
||||
"Coral",
|
||||
"SkyBlue",
|
||||
"Jet",
|
||||
"Thistle",
|
||||
"Beetle",
|
||||
"Blonde",
|
||||
"Red",
|
||||
"MediumSlateBlue",
|
||||
"HotPink",
|
||||
"MediumBlue",
|
||||
"DarkKhaki",
|
||||
"Carrot",
|
||||
"DeepSkyBlue",
|
||||
"Taupe",
|
||||
"Aquamarine",
|
||||
"Pistachio",
|
||||
"DarkOrange",
|
||||
"Camel",
|
||||
"Gainsboro",
|
||||
"DarkRed",
|
||||
"Linen",
|
||||
"Kelly",
|
||||
"Off",
|
||||
"Macaw",
|
||||
"Bullet",
|
||||
"MediumPurple",
|
||||
"Brass",
|
||||
"Cardboard",
|
||||
"Sienna",
|
||||
"Midnight",
|
||||
"Electric",
|
||||
"CadetBlue",
|
||||
"Chilli",
|
||||
"Columbia",
|
||||
"Vanilla",
|
||||
"Puce",
|
||||
"Snow",
|
||||
"Bean",
|
||||
"Cadillac",
|
||||
"LightCoral",
|
||||
"Soft",
|
||||
"MediumTurquoise",
|
||||
"Bold",
|
||||
"NavajoWhite",
|
||||
"Cantaloupe",
|
||||
"Blue",
|
||||
"Maroon",
|
||||
"LightSlateGray",
|
||||
"Cotton",
|
||||
"Iguana",
|
||||
"Chrome",
|
||||
"DarkOrchid",
|
||||
"Indigo",
|
||||
"Moccasin",
|
||||
"Orchid",
|
||||
"Nebula",
|
||||
"Milk",
|
||||
"Fern",
|
||||
"GreenYellow",
|
||||
"Ferrari",
|
||||
"Pearl",
|
||||
"Bakers",
|
||||
"Bright",
|
||||
"Emerald",
|
||||
"Beige",
|
||||
"Army",
|
||||
"Alien",
|
||||
"Periwinkle",
|
||||
"SpringGreen",
|
||||
"Rubber",
|
||||
"Chocolate",
|
||||
"Charcoal",
|
||||
"Tiger",
|
||||
"Nardo",
|
||||
"Rogue",
|
||||
"Aqua",
|
||||
"Lilac",
|
||||
"PowderBlue",
|
||||
"OrangeRed",
|
||||
"SaddleBrown",
|
||||
"DarkBlue",
|
||||
"Hummingbird",
|
||||
"White",
|
||||
"Saffron",
|
||||
"Old",
|
||||
"LightSalmon",
|
||||
"LightSeaGreen",
|
||||
"OldLace",
|
||||
"Cranberry",
|
||||
"Zombie",
|
||||
"Crocus",
|
||||
"Windows",
|
||||
"Frog",
|
||||
"Peru",
|
||||
"DarkGreen",
|
||||
"Ivory",
|
||||
"Love",
|
||||
"Pink",
|
||||
"Sky",
|
||||
"Mahogany",
|
||||
"French",
|
||||
"SandyBrown",
|
||||
"Dollar",
|
||||
"Dinosaur",
|
||||
"Sedona",
|
||||
"ForestGreen",
|
||||
"Mist",
|
||||
"Smokey",
|
||||
"Crystal",
|
||||
"Iridium",
|
||||
"Banana",
|
||||
"Desert",
|
||||
"LightGreen",
|
||||
"Sandstone",
|
||||
"Silver",
|
||||
"Valentine",
|
||||
"Silk",
|
||||
"Green",
|
||||
"Parrot",
|
||||
"Macaroni",
|
||||
"Caramel",
|
||||
"Pumpkin",
|
||||
"Indian",
|
||||
"Crimson",
|
||||
"Tiffany",
|
||||
"Gunmetal",
|
||||
"Salad",
|
||||
"Platinum",
|
||||
"MediumAquaMarine",
|
||||
"Bronze",
|
||||
"Lava",
|
||||
"Peach",
|
||||
"Tyrian",
|
||||
"Rust",
|
||||
"Petra",
|
||||
"Lovely",
|
||||
"Aloe",
|
||||
"Blossom",
|
||||
"Rat",
|
||||
"Shocking",
|
||||
"LawnGreen",
|
||||
"YellowGreen",
|
||||
"Turquoise",
|
||||
]
|
||||
66
quart_imp/auth/encrypt_password.py
Normal file
66
quart_imp/auth/encrypt_password.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import typing as t
|
||||
from hashlib import sha256, sha512
|
||||
from random import choice
|
||||
from string import ascii_letters
|
||||
|
||||
from .__private_funcs__ import _pps, _ppe
|
||||
|
||||
|
||||
def encrypt_password(
|
||||
password: str,
|
||||
salt: str,
|
||||
encryption_level: int = 512,
|
||||
pepper_length: int = 1,
|
||||
pepper_position: t.Literal["start", "end"] = "end",
|
||||
) -> str:
|
||||
"""
|
||||
Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
Can set the encryption level to 256 or 512, defaults to 512.
|
||||
|
||||
Can set the pepper length, defaults to 1. Max is 3.
|
||||
|
||||
Can set the pepper position, "start" or "end", defaults to "end".
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
For use in password hashing.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
.. Note::
|
||||
|
||||
You must inform the authenticate_password function of the pepper length used to hash the password.
|
||||
|
||||
You must inform the authenticate_password function of the position of the pepper used to hash the password.
|
||||
|
||||
You must inform the authenticate_password function of the encryption level used to hash the password.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:param password: str - plain password
|
||||
:param salt: str - salt
|
||||
:param encryption_level: int - 256 or 512 - defaults to 512
|
||||
:param pepper_length: int - length of pepper
|
||||
:param pepper_position: str - "start" or "end" - defaults to "end"
|
||||
:return str: hash:
|
||||
"""
|
||||
|
||||
if pepper_length > 3:
|
||||
pepper_length = 3
|
||||
|
||||
_sha = sha512() if encryption_level == 512 else sha256()
|
||||
_pepper = "".join(choice(ascii_letters) for _ in range(pepper_length))
|
||||
|
||||
_sha.update(
|
||||
(
|
||||
_pps(_pepper, password, salt)
|
||||
if pepper_position == "start"
|
||||
else _ppe(_pepper, password, salt)
|
||||
).encode("utf-8")
|
||||
)
|
||||
return _sha.hexdigest()
|
||||
21
quart_imp/auth/generate_alphanumeric_validator.py
Normal file
21
quart_imp/auth/generate_alphanumeric_validator.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from random import choice
|
||||
from string import ascii_uppercase, digits
|
||||
|
||||
|
||||
def generate_alphanumeric_validator(length: int) -> str:
|
||||
"""
|
||||
Generates (length) of alphanumeric.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
For use in MFA email, or unique filename generation.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
:param length: int - length of alphanumeric to generate
|
||||
:return: str - Example return of "F5R6" if length is 4
|
||||
"""
|
||||
|
||||
_alpha_numeric = ascii_uppercase + digits
|
||||
return "".join([choice(_alpha_numeric) for _ in range(length)])
|
||||
21
quart_imp/auth/generate_csrf_token.py
Normal file
21
quart_imp/auth/generate_csrf_token.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from datetime import datetime
|
||||
from hashlib import sha1
|
||||
|
||||
|
||||
def generate_csrf_token() -> str:
|
||||
"""
|
||||
Generates a SHA1 using the current date and time.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
For use in Cross-Site Request Forgery.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:return: str - sha1
|
||||
"""
|
||||
sha = sha1()
|
||||
sha.update(str(datetime.now()).encode("utf-8"))
|
||||
return sha.hexdigest()
|
||||
20
quart_imp/auth/generate_email_validator.py
Normal file
20
quart_imp/auth/generate_email_validator.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from .generate_alphanumeric_validator import generate_alphanumeric_validator
|
||||
|
||||
|
||||
def generate_email_validator() -> str:
|
||||
"""
|
||||
Uses generate_alphanumeric_validator with a length of 8 to
|
||||
generate a random alphanumeric value for the specific use of
|
||||
validating accounts via email.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
See `generate_alphanumeric_validator` for more information.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:return: str - alphanumeric of length 8
|
||||
"""
|
||||
return str(generate_alphanumeric_validator(length=8))
|
||||
24
quart_imp/auth/generate_numeric_validator.py
Normal file
24
quart_imp/auth/generate_numeric_validator.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from random import randrange
|
||||
|
||||
|
||||
def generate_numeric_validator(length: int) -> int:
|
||||
"""
|
||||
Generates random choice between 1 * (length) and 9 * (length).
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
If the length is 4, it will generate a number between 1111 and 9999.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
For use in MFA email, or unique filename generation.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
:param length: int - length of number to generate
|
||||
:return: int - Example return of number between 1111 and 9999 if length is 4
|
||||
"""
|
||||
start = int("1" * length)
|
||||
end = int("9" * length)
|
||||
return randrange(start, end)
|
||||
56
quart_imp/auth/generate_password.py
Normal file
56
quart_imp/auth/generate_password.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from random import choice
|
||||
|
||||
from .dataclasses import PasswordGeneration
|
||||
from .generate_numeric_validator import generate_numeric_validator
|
||||
|
||||
|
||||
def generate_password(style: str = "mixed", length: int = 3) -> str:
|
||||
"""
|
||||
Generates a plain text password based on choice of style and length.
|
||||
2 random numbers are appended to the end of every generated password.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
style options: "animals", "colors", "mixed" - defaults to "mixed"
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
**Example use:**
|
||||
|
||||
.. code-block::
|
||||
|
||||
generate_password(style="animals", length=3)
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
**Output:**
|
||||
|
||||
Cat-Goat-Pig12
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:param style: str - "animals", "colors", "mixed" - defaults to "mixed"
|
||||
:param length: int - how many words are chosen - defaults to 3
|
||||
:return: str - a generated plain text password
|
||||
"""
|
||||
if style == "animals":
|
||||
return "-".join(
|
||||
[choice(PasswordGeneration.animals) for _ in range(length)]
|
||||
) + str(generate_numeric_validator(length=2))
|
||||
|
||||
if style == "colors":
|
||||
return "-".join(
|
||||
[choice(PasswordGeneration.colors) for _ in range(length)]
|
||||
) + str(generate_numeric_validator(length=2))
|
||||
|
||||
if style == "mixed":
|
||||
return "-".join(
|
||||
[
|
||||
choice([*PasswordGeneration.animals, *PasswordGeneration.colors])
|
||||
for _ in range(length)
|
||||
]
|
||||
) + str(generate_numeric_validator(length=2))
|
||||
|
||||
raise ValueError(f"Invalid style passed in {style}")
|
||||
30
quart_imp/auth/generate_private_key.py
Normal file
30
quart_imp/auth/generate_private_key.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import typing as t
|
||||
from datetime import datetime
|
||||
from hashlib import sha256
|
||||
from random import randrange
|
||||
|
||||
|
||||
def generate_private_key(hook: t.Optional[str]) -> str:
|
||||
"""
|
||||
Generates a sha256 private key from a passed in hook value.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
If no hook is passed in, it will generate a hook using datetime.now() and a
|
||||
random number between 1 and 1000.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:param hook: str - hook value to generate private key from
|
||||
:return: str - sha256
|
||||
"""
|
||||
|
||||
if hook is None:
|
||||
_range = randrange(1, 1000)
|
||||
hook = f"{datetime.now()}-{_range}"
|
||||
|
||||
sha = sha256()
|
||||
sha.update(hook.encode("utf-8"))
|
||||
return sha.hexdigest()
|
||||
23
quart_imp/auth/generate_salt.py
Normal file
23
quart_imp/auth/generate_salt.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from random import choice
|
||||
from string import punctuation
|
||||
|
||||
|
||||
def generate_salt(length: int = 4) -> str:
|
||||
"""
|
||||
Generates a string of (length) characters of punctuation.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
The Default length is 4.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
For use in password salting
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:return: str - salt of (length)
|
||||
"""
|
||||
return "".join(choice(punctuation) for _ in range(length))
|
||||
41
quart_imp/auth/is_email_address_valid.py
Normal file
41
quart_imp/auth/is_email_address_valid.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import re
|
||||
|
||||
|
||||
def is_email_address_valid(email_address: str) -> bool:
|
||||
"""
|
||||
Checks if email_address is a valid email address.
|
||||
|
||||
Is not completely RFC 5322 compliant, but it is good enough for most use cases.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
Here are examples of mistakes that it will not catch:
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
Valid but fails:
|
||||
|
||||
- email@[123.123.123.123] is VALID => PASSED : False
|
||||
- “email”@example.com is VALID => PASSED : False
|
||||
- very.unusual.“@”.unusual.com@example.com is VALID => PASSED : False
|
||||
- very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com is VALID => PASSED : False
|
||||
|
||||
Invalid but passes:
|
||||
|
||||
- email@example.com (Joe Smith) is INVALID => PASSED : True
|
||||
- email@111.222.333.44444 is INVALID => PASSED : True
|
||||
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:param email_address: str
|
||||
:return: bool
|
||||
"""
|
||||
pattern = re.compile(
|
||||
r"[a-z\d!#$%&'*+?^_`{|}~-]+(?:\.[a-z\d!#$%&'*+?^_`"
|
||||
r"{|}~-]+)*@(?:[a-z\d](?:[a-z\d-]*[a-z\d])?\.)+[a-z\d](?:[a-z\d-]*[a-z\d])?",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
return bool(pattern.match(email_address))
|
||||
92
quart_imp/auth/is_username_valid.py
Normal file
92
quart_imp/auth/is_username_valid.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import re
|
||||
import typing as t
|
||||
|
||||
|
||||
def is_username_valid(
|
||||
username: str,
|
||||
allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Checks if a username is valid.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
Valid usernames can only include letters,
|
||||
numbers, ., -, and _ but cannot begin or end with
|
||||
the last three mentioned.
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
|
||||
**Example use:**
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
.. code-block::
|
||||
|
||||
is_username_valid("username", allowed=["all"])
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
**Output:**
|
||||
|
||||
.. code-block::
|
||||
|
||||
username : WILL PASS : True
|
||||
user.name : WILL PASS : True
|
||||
user-name : WILL PASS : True
|
||||
user_name : WILL PASS : True
|
||||
_user_name : WILL PASS : False
|
||||
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
.. code-block::
|
||||
|
||||
is_username_valid("username", allowed=["dot", "dash"])
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
**Output:**
|
||||
|
||||
.. code-block::
|
||||
|
||||
username : WILL PASS : True
|
||||
user.name : WILL PASS : True
|
||||
user-name : WILL PASS : True
|
||||
user-name.name : WILL PASS : True
|
||||
user_name : WILL PASS : False
|
||||
_user_name : WILL PASS : False
|
||||
.user.name : WILL PASS : False
|
||||
|
||||
:raw-html:`<br />`
|
||||
|
||||
-----
|
||||
|
||||
:param username: str
|
||||
:param allowed: list - ["all", "dot", "dash", "under"] - defaults to ["all"]
|
||||
:return bool:
|
||||
"""
|
||||
|
||||
if not username[0].isalnum() or not username[-1].isalnum():
|
||||
return False
|
||||
|
||||
if allowed is None:
|
||||
allowed = ["all"]
|
||||
|
||||
if "all" in allowed:
|
||||
return bool(re.match(r"^[a-zA-Z0-9._-]+$", username))
|
||||
|
||||
if "under" not in allowed:
|
||||
if "_" in username:
|
||||
return False
|
||||
|
||||
if "dot" not in allowed:
|
||||
if "." in username:
|
||||
return False
|
||||
|
||||
if "dash" not in allowed:
|
||||
if "-" in username:
|
||||
return False
|
||||
|
||||
return True
|
||||
Reference in New Issue
Block a user