mirror of
https://github.com/wekan/wekan.git
synced 2026-01-23 17:56:09 +01:00
Security Fix 5: PositionHistoryBleed.
Thanks to [Joshua Rogers](https://joshua.hu) of [Aisle Research](https://aisle.com) and xet7.
This commit is contained in:
parent
cc35dafef5
commit
55576ec177
1 changed files with 127 additions and 0 deletions
|
|
@ -4,6 +4,7 @@ import PositionHistory from '/models/positionHistory';
|
|||
import Swimlanes from '/models/swimlanes';
|
||||
import Lists from '/models/lists';
|
||||
import Cards from '/models/cards';
|
||||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
|
||||
/**
|
||||
* Server-side methods for position history tracking
|
||||
|
|
@ -15,11 +16,20 @@ Meteor.methods({
|
|||
'positionHistory.trackSwimlane'(swimlaneId) {
|
||||
check(swimlaneId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const swimlane = Swimlanes.findOne(swimlaneId);
|
||||
if (!swimlane) {
|
||||
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(swimlane.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return swimlane.trackOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -29,11 +39,20 @@ Meteor.methods({
|
|||
'positionHistory.trackList'(listId) {
|
||||
check(listId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const list = Lists.findOne(listId);
|
||||
if (!list) {
|
||||
throw new Meteor.Error('list-not-found', 'List not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(list.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return list.trackOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -43,11 +62,20 @@ Meteor.methods({
|
|||
'positionHistory.trackCard'(cardId) {
|
||||
check(cardId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const card = Cards.findOne(cardId);
|
||||
if (!card) {
|
||||
throw new Meteor.Error('card-not-found', 'Card not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(card.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return card.trackOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -57,11 +85,20 @@ Meteor.methods({
|
|||
'positionHistory.getSwimlaneOriginalPosition'(swimlaneId) {
|
||||
check(swimlaneId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const swimlane = Swimlanes.findOne(swimlaneId);
|
||||
if (!swimlane) {
|
||||
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(swimlane.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return swimlane.getOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -71,11 +108,20 @@ Meteor.methods({
|
|||
'positionHistory.getListOriginalPosition'(listId) {
|
||||
check(listId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const list = Lists.findOne(listId);
|
||||
if (!list) {
|
||||
throw new Meteor.Error('list-not-found', 'List not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(list.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return list.getOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -85,11 +131,20 @@ Meteor.methods({
|
|||
'positionHistory.getCardOriginalPosition'(cardId) {
|
||||
check(cardId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const card = Cards.findOne(cardId);
|
||||
if (!card) {
|
||||
throw new Meteor.Error('card-not-found', 'Card not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(card.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return card.getOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -99,11 +154,20 @@ Meteor.methods({
|
|||
'positionHistory.hasSwimlaneMoved'(swimlaneId) {
|
||||
check(swimlaneId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const swimlane = Swimlanes.findOne(swimlaneId);
|
||||
if (!swimlane) {
|
||||
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(swimlane.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return swimlane.hasMovedFromOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -113,11 +177,20 @@ Meteor.methods({
|
|||
'positionHistory.hasListMoved'(listId) {
|
||||
check(listId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const list = Lists.findOne(listId);
|
||||
if (!list) {
|
||||
throw new Meteor.Error('list-not-found', 'List not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(list.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return list.hasMovedFromOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -127,11 +200,20 @@ Meteor.methods({
|
|||
'positionHistory.hasCardMoved'(cardId) {
|
||||
check(cardId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const card = Cards.findOne(cardId);
|
||||
if (!card) {
|
||||
throw new Meteor.Error('card-not-found', 'Card not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(card.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return card.hasMovedFromOriginalPosition();
|
||||
},
|
||||
|
||||
|
|
@ -141,11 +223,20 @@ Meteor.methods({
|
|||
'positionHistory.getSwimlaneDescription'(swimlaneId) {
|
||||
check(swimlaneId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const swimlane = Swimlanes.findOne(swimlaneId);
|
||||
if (!swimlane) {
|
||||
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(swimlane.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return swimlane.getOriginalPositionDescription();
|
||||
},
|
||||
|
||||
|
|
@ -155,11 +246,20 @@ Meteor.methods({
|
|||
'positionHistory.getListDescription'(listId) {
|
||||
check(listId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const list = Lists.findOne(listId);
|
||||
if (!list) {
|
||||
throw new Meteor.Error('list-not-found', 'List not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(list.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return list.getOriginalPositionDescription();
|
||||
},
|
||||
|
||||
|
|
@ -169,11 +269,20 @@ Meteor.methods({
|
|||
'positionHistory.getCardDescription'(cardId) {
|
||||
check(cardId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const card = Cards.findOne(cardId);
|
||||
if (!card) {
|
||||
throw new Meteor.Error('card-not-found', 'Card not found');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(card.boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return card.getOriginalPositionDescription();
|
||||
},
|
||||
|
||||
|
|
@ -183,6 +292,15 @@ Meteor.methods({
|
|||
'positionHistory.getBoardHistory'(boardId) {
|
||||
check(boardId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
return PositionHistory.find({
|
||||
boardId: boardId,
|
||||
}, {
|
||||
|
|
@ -197,6 +315,15 @@ Meteor.methods({
|
|||
check(boardId, String);
|
||||
check(entityType, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('not-authorized', 'You must be logged in.');
|
||||
}
|
||||
|
||||
const board = ReactiveCache.getBoard(boardId);
|
||||
if (!board || !board.isVisibleBy({ _id: this.userId })) {
|
||||
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
|
||||
}
|
||||
|
||||
if (!['swimlane', 'list', 'card'].includes(entityType)) {
|
||||
throw new Meteor.Error('invalid-entity-type', 'Entity type must be swimlane, list, or card');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue