mirror of
https://github.com/wekan/wekan.git
synced 2025-12-24 03:10:12 +01:00
More enhancements to Admin Reports and security fixes
* update Boards Report * use Boards.userBoards() instead of Boards.find() to make sure user has access permission
This commit is contained in:
parent
d9c290deda
commit
42610d9642
5 changed files with 107 additions and 84 deletions
|
|
@ -154,12 +154,19 @@ template(name="boardsReport")
|
||||||
tr
|
tr
|
||||||
th Title
|
th Title
|
||||||
th Id
|
th Id
|
||||||
|
th Permission
|
||||||
|
th Archived?
|
||||||
th Members
|
th Members
|
||||||
|
th Organizations
|
||||||
|
th Teams
|
||||||
|
|
||||||
each board in results
|
each board in results
|
||||||
tr
|
tr
|
||||||
td {{abbreviate board.title }}
|
td {{abbreviate board.title }}
|
||||||
td {{abbreviate board._id }}
|
td {{abbreviate board._id }}
|
||||||
|
td {{ board.permission }}
|
||||||
|
td
|
||||||
|
= yesOrNo(board.archived)
|
||||||
td {{userNames board.members }}
|
td {{userNames board.members }}
|
||||||
else
|
else
|
||||||
div {{_ 'no-results' }}
|
div {{_ 'no-results' }}
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,14 @@ class AdminReport extends BlazeComponent {
|
||||||
return this.collection.find();
|
return this.collection.find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yesOrNo(value) {
|
||||||
|
if (value) {
|
||||||
|
return TAPi18n.__('yes');
|
||||||
|
} else {
|
||||||
|
return TAPi18n.__('no');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resultsCount() {
|
resultsCount() {
|
||||||
return this.collection.find().count();
|
return this.collection.find().count();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
TYPE_TEMPLATE_BOARD,
|
TYPE_TEMPLATE_BOARD,
|
||||||
TYPE_TEMPLATE_CONTAINER,
|
TYPE_TEMPLATE_CONTAINER,
|
||||||
} from '/config/const';
|
} from '/config/const';
|
||||||
|
import Users from "./users";
|
||||||
|
|
||||||
const escapeForRegex = require('escape-string-regexp');
|
const escapeForRegex = require('escape-string-regexp');
|
||||||
Boards = new Mongo.Collection('boards');
|
Boards = new Mongo.Collection('boards');
|
||||||
|
|
@ -1485,6 +1486,11 @@ Boards.userBoards = (
|
||||||
selector = {},
|
selector = {},
|
||||||
projection = {},
|
projection = {},
|
||||||
) => {
|
) => {
|
||||||
|
const user = Users.findOne(userId);
|
||||||
|
if (!user) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof archived === 'boolean') {
|
if (typeof archived === 'boolean') {
|
||||||
selector.archived = archived;
|
selector.archived = archived;
|
||||||
}
|
}
|
||||||
|
|
@ -1492,14 +1498,14 @@ Boards.userBoards = (
|
||||||
selector.type = 'board';
|
selector.type = 'board';
|
||||||
}
|
}
|
||||||
|
|
||||||
selector.$or = [{ permission: 'public' }];
|
selector.$or = [
|
||||||
if (userId) {
|
{ permission: 'public' },
|
||||||
selector.$or.push(
|
{ members: { $elemMatch: { userId, isActive: true } } },
|
||||||
{ members: { $elemMatch: { userId, isActive: true } } },
|
{ 'orgs.orgId': { $in: user.orgIds() } },
|
||||||
projection,
|
{ 'teams.teamId': { $in : user.teamIds() } },
|
||||||
);
|
];
|
||||||
}
|
|
||||||
return Boards.find(selector);
|
return Boards.find(selector, projection);
|
||||||
};
|
};
|
||||||
|
|
||||||
Boards.userBoardIds = (userId, archived = false, selector = {}) => {
|
Boards.userBoardIds = (userId, archived = false, selector = {}) => {
|
||||||
|
|
|
||||||
|
|
@ -519,6 +519,18 @@ Users.helpers({
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
|
teamIds() {
|
||||||
|
if (this.teams) {
|
||||||
|
return this.teams.map(team => { return team.teamId });
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
orgIds() {
|
||||||
|
if (this.orgs) {
|
||||||
|
return this.orgs.map(org => { return org.orgId });
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
orgsUserBelongs() {
|
orgsUserBelongs() {
|
||||||
if (this.orgs) {
|
if (this.orgs) {
|
||||||
return this.orgs.map(function(org){return org.orgDisplayName}).sort().join(',');
|
return this.orgs.map(function(org){return org.orgDisplayName}).sort().join(',');
|
||||||
|
|
@ -544,32 +556,16 @@ Users.helpers({
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
boards() {
|
boards() {
|
||||||
return Boards.find(
|
return Boards.userBoards(this._id, null, {}, { sort: { sort: 1 } })
|
||||||
{
|
|
||||||
'members.userId': this._id,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sort: {
|
|
||||||
sort: 1 /* boards default sorting */,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
starredBoards() {
|
starredBoards() {
|
||||||
const { starredBoards = [] } = this.profile || {};
|
const { starredBoards = [] } = this.profile || {};
|
||||||
return Boards.find(
|
return Boards.userBoards(
|
||||||
{
|
this._id,
|
||||||
archived: false,
|
false,
|
||||||
_id: {
|
{ _id: { $in: starredBoards } },
|
||||||
$in: starredBoards,
|
{ sort: { sort: 1 } }
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sort: {
|
|
||||||
sort: 1 /* boards default sorting */,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -580,18 +576,11 @@ Users.helpers({
|
||||||
|
|
||||||
invitedBoards() {
|
invitedBoards() {
|
||||||
const { invitedBoards = [] } = this.profile || {};
|
const { invitedBoards = [] } = this.profile || {};
|
||||||
return Boards.find(
|
return Boards.userBoards(
|
||||||
{
|
this._id,
|
||||||
archived: false,
|
false,
|
||||||
_id: {
|
{ _id: { $in: invitedBoards } },
|
||||||
$in: invitedBoards,
|
{ sort: { sort: 1 } }
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sort: {
|
|
||||||
sort: 1 /* boards default sorting */,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,41 +3,46 @@
|
||||||
// 1. that the user is a member of
|
// 1. that the user is a member of
|
||||||
// 2. the user has starred
|
// 2. the user has starred
|
||||||
import Users from "../../models/users";
|
import Users from "../../models/users";
|
||||||
|
import Org from "../../models/org";
|
||||||
|
import Team from "../../models/team";
|
||||||
|
|
||||||
Meteor.publish('boards', function() {
|
Meteor.publish('boards', function() {
|
||||||
const userId = this.userId;
|
const userId = this.userId;
|
||||||
// Ensure that the user is connected. If it is not, we need to return an empty
|
// Ensure that the user is connected. If it is not, we need to return an empty
|
||||||
// array to tell the client to remove the previously published docs.
|
// array to tell the client to remove the previously published docs.
|
||||||
if (!Match.test(userId, String) || !userId) return [];
|
if (!Match.test(userId, String) || !userId) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// Defensive programming to verify that starredBoards has the expected
|
// Defensive programming to verify that starredBoards has the expected
|
||||||
// format -- since the field is in the `profile` a user can modify it.
|
// format -- since the field is in the `profile` a user can modify it.
|
||||||
const { starredBoards = [] } = (Users.findOne(userId) || {}).profile || {};
|
// const { starredBoards = [] } = (Users.findOne(userId) || {}).profile || {};
|
||||||
check(starredBoards, [String]);
|
// check(starredBoards, [String]);
|
||||||
|
|
||||||
let currUser = Users.findOne(userId);
|
// let currUser = Users.findOne(userId);
|
||||||
let orgIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.orgIdsUserBelongs() : '';
|
// let orgIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.orgIdsUserBelongs() : '';
|
||||||
let teamIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.teamIdsUserBelongs() : '';
|
// let teamIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.teamIdsUserBelongs() : '';
|
||||||
let orgsIds = [];
|
// let orgsIds = [];
|
||||||
let teamsIds = [];
|
// let teamsIds = [];
|
||||||
if(orgIdsUserBelongs && orgIdsUserBelongs != ''){
|
// if(orgIdsUserBelongs && orgIdsUserBelongs != ''){
|
||||||
orgsIds = orgIdsUserBelongs.split(',');
|
// orgsIds = orgIdsUserBelongs.split(',');
|
||||||
}
|
// }
|
||||||
if(teamIdsUserBelongs && teamIdsUserBelongs != ''){
|
// if(teamIdsUserBelongs && teamIdsUserBelongs != ''){
|
||||||
teamsIds = teamIdsUserBelongs.split(',');
|
// teamsIds = teamIdsUserBelongs.split(',');
|
||||||
}
|
// }
|
||||||
return Boards.find(
|
return Boards.find(
|
||||||
{
|
{
|
||||||
archived: false,
|
archived: false,
|
||||||
$or: [
|
_id: { $in: Boards.userBoardIds(userId, false) },
|
||||||
{
|
// $or: [
|
||||||
// _id: { $in: starredBoards }, // Commented out, to get a list of all public boards
|
// {
|
||||||
permission: 'public',
|
// // _id: { $in: starredBoards }, // Commented out, to get a list of all public boards
|
||||||
},
|
// permission: 'public',
|
||||||
{ members: { $elemMatch: { userId, isActive: true } } },
|
// },
|
||||||
{'orgs.orgId': {$in : orgsIds}},
|
// { members: { $elemMatch: { userId, isActive: true } } },
|
||||||
{'teams.teamId': {$in : teamsIds}},
|
// {'orgs.orgId': {$in : orgsIds}},
|
||||||
],
|
// {'teams.teamId': {$in : teamsIds}},
|
||||||
|
// ],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: {
|
fields: {
|
||||||
|
|
@ -66,16 +71,9 @@ Meteor.publish('boardsReport', function() {
|
||||||
// array to tell the client to remove the previously published docs.
|
// array to tell the client to remove the previously published docs.
|
||||||
if (!Match.test(userId, String) || !userId) return [];
|
if (!Match.test(userId, String) || !userId) return [];
|
||||||
|
|
||||||
boards = Boards.find(
|
const boards = Boards.find(
|
||||||
{
|
{
|
||||||
archived: false,
|
_id: { $in: Boards.userBoardIds(userId, null) },
|
||||||
$or: [
|
|
||||||
{
|
|
||||||
// _id: { $in: starredBoards }, // Commented out, to get a list of all public boards
|
|
||||||
permission: 'public',
|
|
||||||
},
|
|
||||||
{ members: { $elemMatch: { userId, isActive: true } } },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: {
|
fields: {
|
||||||
|
|
@ -97,18 +95,32 @@ Meteor.publish('boardsReport', function() {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const users = [];
|
const userIds = [];
|
||||||
|
const orgIds = [];
|
||||||
|
const teamIds = [];
|
||||||
boards.forEach(board => {
|
boards.forEach(board => {
|
||||||
if (board.members) {
|
if (board.members) {
|
||||||
board.members.forEach(member => {
|
board.members.forEach(member => {
|
||||||
users.push(member.userId);
|
userIds.push(member.userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (board.orgs) {
|
||||||
|
board.orgs.forEach(org => {
|
||||||
|
orgIds.push(org.orgId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (board.teams) {
|
||||||
|
board.teams.forEach(team => {
|
||||||
|
teamIds.push(team.teamId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return [
|
return [
|
||||||
boards,
|
boards,
|
||||||
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
Users.find({ _id: { $in: userIds } }, { fields: Users.safeFields }),
|
||||||
|
Team.find({ _id: { $in: teamIds } }),
|
||||||
|
Org.find({ _id: { $in: orgIds } }),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -118,13 +130,14 @@ Meteor.publish('archivedBoards', function() {
|
||||||
|
|
||||||
return Boards.find(
|
return Boards.find(
|
||||||
{
|
{
|
||||||
archived: true,
|
_id: { $in: Boards.userBoardIds(userId, true)},
|
||||||
members: {
|
// archived: true,
|
||||||
$elemMatch: {
|
// members: {
|
||||||
userId,
|
// $elemMatch: {
|
||||||
isAdmin: true,
|
// userId,
|
||||||
},
|
// isAdmin: true,
|
||||||
},
|
// },
|
||||||
|
// },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: {
|
fields: {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue