mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-10 16:52:47 +03:00
Compare commits
2
Commits
master
...
dot-username
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b78d65565b | ||
|
|
ec9319853f |
+1
-1
@@ -912,7 +912,7 @@ def create_user(
|
|||||||
HASH_ITERATIONS = request.app.frigate_config.auth.hash_iterations
|
HASH_ITERATIONS = request.app.frigate_config.auth.hash_iterations
|
||||||
config_roles = list(request.app.frigate_config.auth.roles.keys())
|
config_roles = list(request.app.frigate_config.auth.roles.keys())
|
||||||
|
|
||||||
if not re.match("^[A-Za-z0-9._]+$", body.username):
|
if not re.match(r"^(?!\.+$)[A-Za-z0-9._]+$", body.username):
|
||||||
return JSONResponse(content={"message": "Invalid username"}, status_code=400)
|
return JSONResponse(content={"message": "Invalid username"}, status_code=400)
|
||||||
|
|
||||||
if body.role not in config_roles:
|
if body.role not in config_roles:
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"""Tests for user creation."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from frigate.models import User
|
||||||
|
from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
|
||||||
|
|
||||||
|
PASSWORD = "a-valid-password-123"
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateUser(BaseTestHttp):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp([User])
|
||||||
|
self.app = super().create_app()
|
||||||
|
self.app.config_publisher = MagicMock()
|
||||||
|
|
||||||
|
def _create(self, username: str):
|
||||||
|
with AuthTestClient(self.app) as client:
|
||||||
|
return client.post(
|
||||||
|
"/users",
|
||||||
|
json={"username": username, "password": PASSWORD, "role": "viewer"},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_rejects_dot_only_usernames(self):
|
||||||
|
# browsers resolve these as URL path segments, so the per-user
|
||||||
|
# endpoints can never be reached for them
|
||||||
|
for username in (".", "..", "..."):
|
||||||
|
assert self._create(username).status_code == 400
|
||||||
|
assert User.get_or_none(User.username == username) is None
|
||||||
|
|
||||||
|
def test_accepts_username_containing_dots(self):
|
||||||
|
assert self._create("john.doe_1").status_code == 200
|
||||||
|
assert User.get_or_none(User.username == "john.doe_1") is not None
|
||||||
@@ -1054,6 +1054,7 @@
|
|||||||
"title": "Create New User",
|
"title": "Create New User",
|
||||||
"desc": "Add a new user account and specify a role for access to areas of the Frigate UI.",
|
"desc": "Add a new user account and specify a role for access to areas of the Frigate UI.",
|
||||||
"usernameOnlyInclude": "Username may only include letters, numbers, . or _",
|
"usernameOnlyInclude": "Username may only include letters, numbers, . or _",
|
||||||
|
"usernameOnlyDots": "Username cannot contain only periods",
|
||||||
"confirmPassword": "Please confirm your password"
|
"confirmPassword": "Please confirm your password"
|
||||||
},
|
},
|
||||||
"deleteUser": {
|
"deleteUser": {
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ export default function CreateUserDialog({
|
|||||||
.min(1, t("users.dialog.form.usernameIsRequired"))
|
.min(1, t("users.dialog.form.usernameIsRequired"))
|
||||||
.regex(/^[A-Za-z0-9._]+$/, {
|
.regex(/^[A-Za-z0-9._]+$/, {
|
||||||
message: t("users.dialog.createUser.usernameOnlyInclude"),
|
message: t("users.dialog.createUser.usernameOnlyInclude"),
|
||||||
|
})
|
||||||
|
.regex(/[^.]/, {
|
||||||
|
message: t("users.dialog.createUser.usernameOnlyDots"),
|
||||||
}),
|
}),
|
||||||
password: z
|
password: z
|
||||||
.string()
|
.string()
|
||||||
|
|||||||
Reference in New Issue
Block a user