这是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
54 changes: 51 additions & 3 deletions server/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@ const prisma = require("../utils/prisma");
const { EventLogs } = require("./eventLogs");

const User = {
writable: [
// Used for generic updates so we can validate keys in request body
"username",
"password",
"pfpFilename",
"role",
"suspended",
],
// validations for the above writable fields.
castColumnValue: function (key, value) {
switch (key) {
case "suspended":
return Number(Boolean(value));
default:
return String(value);
}
},
create: async function ({ username, password, role = "default" }) {
const passwordCheck = this.checkPasswordComplexity(password);
if (!passwordCheck.checkedOK) {
Expand Down Expand Up @@ -42,13 +59,26 @@ const User = {

update: async function (userId, updates = {}) {
try {
if (!userId) throw new Error("No user id provided for update");
const currentUser = await prisma.users.findUnique({
where: { id: parseInt(userId) },
});
if (!currentUser) {
return { success: false, error: "User not found" };
}
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]) => {
if (this.writable.includes(key)) {
updates[key] = this.castColumnValue(key, value);
return;
}
delete updates[key];
});

if (Object.keys(updates).length === 0)
return { success: false, error: "No valid updates applied." };

// Handle password specific updates
if (updates.hasOwnProperty("password")) {
const passwordCheck = this.checkPasswordComplexity(updates.password);
if (!passwordCheck.checkedOK) {
Expand Down Expand Up @@ -78,6 +108,24 @@ const User = {
}
},

// Explicit direct update of user object.
// Only use this method when directly setting a key value
// that takes no user input for the keys being modified.
_update: async function (id = null, data = {}) {
if (!id) throw new Error("No user id provided for update");

try {
const user = await prisma.users.update({
where: { id },
data,
});
return { user, message: null };
} catch (error) {
console.error(error.message);
return { user: null, message: error.message };
}
},

get: async function (clause = {}) {
try {
const user = await prisma.users.findFirst({ where: clause });
Expand Down
2 changes: 1 addition & 1 deletion server/utils/AiProviders/openRouter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ class OpenRouterLLM {
try {
JSON.parse(message);
validJSON = true;
} catch { }
} catch {}

if (!validJSON) {
// It can be possible that the chunk decoding is running away
Expand Down
7 changes: 6 additions & 1 deletion server/utils/PasswordRecovery/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function generateRecoveryCodes(userId) {
const { error } = await RecoveryCode.createMany(newRecoveryCodes);
if (!!error) throw new Error(error);

const { success } = await User.update(userId, {
const { user: success } = await User._update(userId, {
seen_recovery_codes: true,
});
if (!success) throw new Error("Failed to generate user recovery codes!");
Expand Down Expand Up @@ -80,6 +80,11 @@ async function resetPassword(token, _newPassword = "", confirmPassword = "") {
// JOI password rules will be enforced inside .update.
const { error } = await User.update(resetToken.user_id, {
password: newPassword,
});

// seen_recovery_codes is not publicly writable
// so we have to do direct update here
await User._update(resetToken.user_id, {
seen_recovery_codes: false,
});

Expand Down