Skip to content
Open
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
30 changes: 15 additions & 15 deletions backend/webserver/Socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,28 +510,28 @@ module.exports = class Socket {
let fullRowAccess = isPublicOrAdmin;

if (!fullRowAccess) {
// --- Ownership: user always sees their own rows when table has userId ---
if (hasUserIdAttribute) {
rowVisibilityConditions.push({userId});
}

// --- Public rows: always visible regardless of ownership or access rights ---
if ('public' in model.getAttributes()) {
rowVisibilityConditions.push({public: true});
}

// --- User-level row filter ---
// --- User-level row filter (authoritative when present, e.g. template type rules) ---
if (hasModelUserFilter) {
const userFilter = await model.getUserFilter(userId);
const userFilter = await model.getUserFilter(userId, isAdmin);
if (Reflect.ownKeys(userFilter).length > 0) {
rowVisibilityConditions.push(userFilter);
} else {
// getUserFilter returns {} → grants full row access (e.g. for admins)
fullRowAccess = true;
}
} else if (!hasUserIdAttribute && accessRights.length === 0) {
this.logger.warn("User with id " + userId + " requested table " + tableName + " without access rights");
return {filter: allFilter, attributes: allAttributes, accessAllowed: false};
} else {
// --- Ownership: user always sees their own rows when table has userId ---
if (hasUserIdAttribute) {
rowVisibilityConditions.push({userId});
}

// --- Public rows: always visible regardless of ownership or access rights ---
if ('public' in model.getAttributes()) {
rowVisibilityConditions.push({public: true});
} else if (!hasUserIdAttribute && accessRights.length === 0) {
this.logger.warn("User with id " + userId + " requested table " + tableName + " without access rights");
return {filter: allFilter, attributes: allAttributes, accessAllowed: false};
}
}

// --- Access-map limitations (ORed with user filter conditions) ---
Expand Down
5 changes: 5 additions & 0 deletions backend/webserver/sockets/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,15 @@ class TemplateSocket extends Socket {

const isOwner = template.userId === this.userId;
const isPublicFromOthers = template.public === true && !isOwner;
const isAdmin = await this.isAdmin();
const isEmailType = [1, 2, 3, 6, 7].includes(template.type);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the 9th or 10th time that we have the [1,...,7], [1,2,3,6,7] and [4,5] arrays in the template code. I think we should move this into some static lists like emailTemplateTypes = [1,2,3,6,7], otherTemplateTypes = [4,5], allTemplateTypes = emailTemplateTypes + otherTemplateTypes
And then use those statics lists. otherwise we have to adjust many different locations when adding new types in the future


if (!isOwner && !isPublicFromOthers) {
throw new Error("You can only view templates that you own or public templates from others");
}
if (!isAdmin && !isOwner && isEmailType) {
throw new Error("Access denied: Only administrators can view email templates");
}

const langRow = await this.models["template_content"].findOne({
where: { templateId: data.templateId, language: data.language, deleted: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ export default {
.filter(t => t.userId === this.userId && !t.deleted);
},
publicTemplates() {
const importableTypes = [4, 5];
const isAdmin = this.$store.getters["auth/isAdmin"];
return this.$store.getters["table/template/getAll"]
.filter(t => t.public && t.userId !== this.userId && !t.deleted)
.filter(t => isAdmin || importableTypes.includes(t.type))
.map(t => {
const alreadyCopied = this.ownTemplates.some(
own => own.sourceId === t.id
Expand Down
Loading