Merge pull request #2160 from bluewave-labs/fix/insecure-user-creation

fix: insecure user creation
This commit is contained in:
Alexander Holliday
2025-04-28 10:59:10 -07:00
committed by GitHub
5 changed files with 34 additions and 25 deletions
@@ -25,7 +25,7 @@ const TeamPanel = () => {
const [toInvite, setToInvite] = useState({
email: "",
role: ["0"],
role: ["user"],
});
const [data, setData] = useState([]);
const [members, setMembers] = useState([]);
@@ -107,7 +107,7 @@ const TeamPanel = () => {
const handleChange = (event) => {
const { value } = event.target;
const newEmail = value?.toLowerCase() || value
const newEmail = value?.toLowerCase() || value;
setToInvite((prev) => ({
...prev,
email: newEmail,
+4 -3
View File
@@ -148,8 +148,8 @@ const Register = ({ isSuperAdmin }) => {
try {
const res = await networkService.verifyInvitationToken(token);
const invite = res.data.data;
const { role, email, teamId } = invite;
setForm({ ...form, email, role, teamId });
const { email } = invite;
setForm({ ...form, email });
} catch (error) {
navigate("/register", { replace: true });
}
@@ -259,7 +259,8 @@ const Register = ({ isSuperAdmin }) => {
const handleChange = (event) => {
const { value, id } = event.target;
const name = idMap[id];
const lowerCasedValue = name === idMap["register-email-input"]? value?.toLowerCase() || value : value
const lowerCasedValue =
name === idMap["register-email-input"] ? value?.toLowerCase() || value : value;
setForm((prev) => ({
...prev,
[name]: lowerCasedValue,
+8 -6
View File
@@ -57,9 +57,9 @@ class AuthController {
*/
registerUser = async (req, res, next) => {
try {
if(req.body?.email){
if (req.body?.email) {
req.body.email = req.body.email?.toLowerCase();
}
}
await registrationBodyValidation.validateAsync(req.body);
} catch (error) {
const validationError = handleValidationError(error, SERVICE_NAME);
@@ -68,11 +68,13 @@ class AuthController {
}
// Create a new user
try {
const { inviteToken } = req.body;
const user = req.body;
// If superAdmin exists, a token should be attached to all further register requests
const superAdminExists = await this.db.checkSuperadmin(req, res);
if (superAdminExists) {
await this.db.getInviteTokenAndDelete(inviteToken);
const invitedUser = await this.db.getInviteTokenAndDelete(user.inviteToken);
user.role = invitedUser.role;
user.teamId = invitedUser.teamId;
} else {
// This is the first account, create JWT secret to use if one is not supplied by env
const jwtSecret = crypto.randomBytes(64).toString("hex");
@@ -133,8 +135,8 @@ class AuthController {
*/
loginUser = async (req, res, next) => {
try {
if(req.body?.email){
req.body.email = req.body.email?.toLowerCase();
if (req.body?.email) {
req.body.email = req.body.email?.toLowerCase();
}
await loginValidation.validateAsync(req.body);
} catch (error) {
+1
View File
@@ -15,6 +15,7 @@ const InviteTokenSchema = mongoose.Schema(
role: {
type: Array,
required: true,
default: ["user"],
},
token: {
type: String,
+19 -14
View File
@@ -63,11 +63,7 @@ const registrationBodyValidation = joi.object({
}),
password: joi.string().min(8).required().pattern(passwordPattern),
profileImage: joi.any(),
role: joi
.array()
.items(joi.string().valid("superadmin", "admin", "user", "demo"))
.min(1)
.required(),
role: joi.array().items(joi.string().valid("superadmin", "admin", "user", "demo")),
teamId: joi.string().allow("").required(),
inviteToken: joi.string().allow("").required(),
});
@@ -83,7 +79,6 @@ const editUserBodyValidation = joi.object({
newPassword: joi.string().min(8).pattern(passwordPattern),
password: joi.string().min(8).pattern(passwordPattern),
deleteProfileImage: joi.boolean(),
role: joi.array(),
});
const recoveryValidation = joi.object({
@@ -305,7 +300,18 @@ const getChecksParamValidation = joi.object({
});
const getChecksQueryValidation = joi.object({
type: joi.string().valid("http", "ping", "pagespeed", "hardware", "docker", "port", "distributed_http", "distributed_test"),
type: joi
.string()
.valid(
"http",
"ping",
"pagespeed",
"hardware",
"docker",
"port",
"distributed_http",
"distributed_test"
),
sortOrder: joi.string().valid("asc", "desc"),
limit: joi.number(),
dateRange: joi.string().valid("recent", "hour", "day", "week", "month", "all"),
@@ -578,16 +584,15 @@ const triggerNotificationBodyValidation = joi.object({
const createAnnouncementValidation = joi.object({
title: joi.string().required().messages({
'string.empty': 'Title cannot be empty',
'any.required': 'Title is required',
"string.empty": "Title cannot be empty",
"any.required": "Title is required",
}),
message: joi.string().required().messages({
'string.empty': 'Message cannot be empty',
'any.required': 'Message is required',
"string.empty": "Message cannot be empty",
"any.required": "Message is required",
}),
userId: joi.string().required(),
});
});
export {
roleValidatior,
@@ -651,5 +656,5 @@ export {
imageValidation,
triggerNotificationBodyValidation,
webhookConfigValidation,
createAnnouncementValidation
createAnnouncementValidation,
};