θΏ™ζ˜―indexlocζδΎ›ηš„ζœεŠ‘οΌŒδΈθ¦θΎ“ε…₯任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion frontend/src/components/UserMenu/AccountModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Plus, X } from "@phosphor-icons/react";

export default function AccountModal({ user, hideModal }) {
const { pfp, setPfp } = usePfp();

const handleFileUpload = async (event) => {
const file = event.target.files[0];
if (!file) return false;
Expand Down Expand Up @@ -133,6 +134,10 @@ export default function AccountModal({ user, hideModal }) {
required
autoComplete="off"
/>
<p className="mt-2 text-xs text-white/60">
Username must be only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
</p>
</div>
<div>
<label
Expand All @@ -143,10 +148,14 @@ export default function AccountModal({ user, hideModal }) {
</label>
<input
name="password"
type="password"
type="text"
className="bg-zinc-900 placeholder:text-white/20 border-gray-500 text-white text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder={`${user.username}'s new password`}
minLength={8}
/>
<p className="mt-2 text-xs text-white/60">
Password must be at least 8 characters long
</p>
</div>
<LanguagePreference />
</div>
Expand Down
20 changes: 18 additions & 2 deletions frontend/src/pages/Admin/Users/NewUserModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { RoleHintDisplay } from "..";
export default function NewUserModal({ closeModal }) {
const [error, setError] = useState(null);
const [role, setRole] = useState("default");

const handleCreate = async (e) => {
setError(null);
e.preventDefault();
Expand Down Expand Up @@ -54,7 +55,18 @@ export default function NewUserModal({ closeModal }) {
minLength={2}
required={true}
autoComplete="off"
pattern="^[a-z0-9_-]+$"
onInvalid={(e) =>
e.target.setCustomValidity(
"Username must be only contain lowercase letters, numbers, underscores, and hyphens with no spaces"
)
}
onChange={(e) => e.target.setCustomValidity("")}
/>
<p className="mt-2 text-xs text-white/60">
Username must be only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
</p>
</div>
<div>
<label
Expand All @@ -70,7 +82,11 @@ export default function NewUserModal({ closeModal }) {
placeholder="User's initial password"
required={true}
autoComplete="off"
minLength={8}
/>
<p className="mt-2 text-xs text-white/60">
Password must be at least 8 characters long
</p>
</div>
<div>
<label
Expand All @@ -84,10 +100,10 @@ export default function NewUserModal({ closeModal }) {
required={true}
defaultValue={"default"}
onChange={(e) => setRole(e.target.value)}
className="rounded-lg bg-zinc-900 px-4 py-2 text-sm text-white border-gray-500 focus:ring-blue-500 focus:border-blue-500"
className="rounded-lg bg-zinc-900 px-4 py-2 text-sm text-white border-gray-500 focus:ring-blue-500 focus:border-blue-500 w-full"
>
<option value="default">Default</option>
<option value="manager">Manager </option>
<option value="manager">Manager</option>
{user?.role === "admin" && (
<option value="admin">Administrator</option>
)}
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,15 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
type="text"
className="bg-zinc-900 placeholder:text-white/20 border-gray-500 text-white text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder="User's username"
minLength={2}
defaultValue={user.username}
minLength={2}
required={true}
autoComplete="off"
/>
<p className="mt-2 text-xs text-white/60">
Username must be only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
</p>
</div>
<div>
<label
Expand All @@ -71,7 +75,11 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
className="bg-zinc-900 placeholder:text-white/20 border-gray-500 text-white text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder={`${user.username}'s new password`}
autoComplete="off"
minLength={8}
/>
<p className="mt-2 text-xs text-white/60">
Password must be at least 8 characters long
</p>
</div>
<div>
<label
Expand All @@ -85,7 +93,7 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
required={true}
defaultValue={user.role}
onChange={(e) => setRole(e.target.value)}
className="rounded-lg bg-zinc-900 px-4 py-2 text-sm text-white border-gray-500 focus:ring-blue-500 focus:border-blue-500"
className="rounded-lg bg-zinc-900 px-4 py-2 text-sm text-white border-gray-500 focus:ring-blue-500 focus:border-blue-500 w-full"
>
<option value="default">Default</option>
<option value="manager">Manager</option>
Expand Down
22 changes: 18 additions & 4 deletions server/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const prisma = require("../utils/prisma");
const { EventLogs } = require("./eventLogs");

const User = {
usernameRegex: new RegExp(/^[a-z0-9_-]+$/),
writable: [
// Used for generic updates so we can validate keys in request body
"username",
Expand Down Expand Up @@ -32,7 +33,6 @@ const User = {
return String(role);
},
},

// validations for the above writable fields.
castColumnValue: function (key, value) {
switch (key) {
Expand All @@ -55,6 +55,12 @@ const User = {
}

try {
// Do not allow new users to bypass validation
if (!this.usernameRegex.test(username))
throw new Error(
"Username must be only contain lowercase letters, numbers, underscores, and hyphens with no spaces"
);

const bcrypt = require("bcrypt");
const hashedPassword = bcrypt.hashSync(password, 10);
const user = await prisma.users.create({
Expand All @@ -70,7 +76,6 @@ const User = {
return { user: null, error: error.message };
}
},

// Log the changes to a user object, but omit sensitive fields
// that are not meant to be logged.
loggedChanges: function (updates, prev = {}) {
Expand All @@ -93,7 +98,6 @@ const User = {
where: { id: parseInt(userId) },
});
if (!currentUser) return { success: false, error: "User not found" };

// Removes non-writable fields for generic updates
// and force-casts to the proper type;
Object.entries(updates).forEach(([key, value]) => {
Expand Down Expand Up @@ -123,6 +127,17 @@ const User = {
updates.password = bcrypt.hashSync(updates.password, 10);
}

if (
updates.hasOwnProperty("username") &&
currentUser.username !== updates.username &&
!this.usernameRegex.test(updates.username)
)
return {
success: false,
error:
"Username must be only contain lowercase letters, numbers, underscores, and hyphens with no spaces",
};

const user = await prisma.users.update({
where: { id: parseInt(userId) },
data: updates,
Expand Down Expand Up @@ -170,7 +185,6 @@ const User = {
return null;
}
},

// Returns user object with all fields
_get: async function (clause = {}) {
try {
Expand Down