1717import errno
1818from os import path as os_path
1919import mimetypes
20+ import re
21+ import string
2022from urllib import parse as urllib_parse
2123
2224from authlib .integrations import requests_client
@@ -45,6 +47,37 @@ def enforce(self, rule, do_raise=False, exc=None):
4547 return iam .enforcer .enforce (rule , do_raise , exc )
4648
4749
50+ class ValidateMixin :
51+ min_length = 8
52+ not_contain : str = string .whitespace
53+ must_contain : list [str ] = None # [digits, ascii_uppercase, punctuation]
54+ regex : str = None
55+
56+ def validate (self , value ):
57+ error = None
58+ if value is None :
59+ error = "Value is required"
60+ elif self .min_length and len (value ) < self .min_length :
61+ error = f"Value must be at least { self .min_length } characters long"
62+ elif self .not_contain and set (self .not_contain ) & set (value ):
63+ error = f"Value must not contain { self .not_contain } "
64+ elif self .must_contain :
65+ for required in self .must_contain :
66+ if not set (required ) & set (value ):
67+ error = f"Value must contain one of { required } "
68+ break
69+ elif self .regex and not re .match (self .regex , value ):
70+ error = f"Value must match regex { self .regex } "
71+ if error :
72+ exc = ValidationErrorException ()
73+ exc .message = error
74+ raise exc
75+
76+ def validate_secret (self , kwargs : dict ):
77+ if "secret" in kwargs :
78+ self .validate (kwargs ["secret" ])
79+
80+
4881class IamController (controllers .RoutesListController ):
4982
5083 __TARGET_PATH__ = "/v1/iam/"
@@ -69,7 +102,7 @@ def _get_app_endpoint(req):
69102
70103
71104class UserController (
72- controllers .BaseResourceControllerPaginated , EnforceMixin
105+ controllers .BaseResourceControllerPaginated , EnforceMixin , ValidateMixin
73106):
74107 __resource__ = resources .ResourceByModelWithCustomProps (
75108 models .User ,
@@ -119,6 +152,7 @@ class UserController(
119152 )
120153
121154 def create (self , ** kwargs ):
155+ self .validate_secret (kwargs )
122156 kwargs .pop ("email_verified" , None )
123157 user = super ().create (** kwargs )
124158 app_endpoint = _get_app_endpoint (req = self ._req )
@@ -132,6 +166,7 @@ def filter(self, filters, **kwargs):
132166 return super ().filter (filters , ** kwargs )
133167
134168 def update (self , uuid , ** kwargs ):
169+ self .validate_secret (kwargs )
135170 kwargs .pop ("email_verified" , None )
136171 is_me = models .User .me ().uuid == uuid
137172 if self .enforce (c .PERMISSION_USER_WRITE_ALL ) or is_me :
@@ -154,6 +189,7 @@ def delete(self, uuid):
154189
155190 @actions .post
156191 def change_password (self , resource , old_password , new_password ):
192+ self .validate (new_password )
157193 is_me = models .User .me () == resource
158194 if self .enforce (c .PERMISSION_USER_WRITE_ALL ) or is_me :
159195 resource .change_secret_safe (
@@ -237,6 +273,7 @@ def confirm_email(self, resource, code=None):
237273 def reset_password (self , resource , new_password = None , code = None ):
238274 code = code or self ._req .params .get ("code" )
239275 new_secret = new_password or self ._req .params .get ("new_password" )
276+ self .validate (new_secret )
240277 resource .reset_secret_by_code (
241278 new_secret = new_secret ,
242279 code = code ,
0 commit comments