소스 검색

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

John Supplee 3 년 전
부모
커밋
42610d9642
5개의 변경된 파일107개의 추가작업 그리고 84개의 파일을 삭제
  1. 7 0
      client/components/settings/adminReports.jade
  2. 8 0
      client/components/settings/adminReports.js
  3. 14 8
      models/boards.js
  4. 23 34
      models/users.js
  5. 55 42
      server/publications/boards.js

+ 7 - 0
client/components/settings/adminReports.jade

@@ -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' }}

+ 8 - 0
client/components/settings/adminReports.js

@@ -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();
   }
   }

+ 14 - 8
models/boards.js

@@ -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' }];
-  if (userId) {
-    selector.$or.push(
-      { members: { $elemMatch: { userId, isActive: true } } },
-      projection,
-    );
-  }
-  return Boards.find(selector);
+  selector.$or = [
+    { permission: 'public' },
+    { members: { $elemMatch: { userId, isActive: true } } },
+    { 'orgs.orgId': { $in: user.orgIds() } },
+    { 'teams.teamId': { $in : user.teamIds() } },
+  ];
+
+  return Boards.find(selector, projection);
 };
 };
 
 
 Boards.userBoardIds = (userId, archived = false, selector = {}) => {
 Boards.userBoardIds = (userId, archived = false, selector = {}) => {

+ 23 - 34
models/users.js

@@ -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(
-      {
-        'members.userId': this._id,
-      },
-      {
-        sort: {
-          sort: 1 /* boards default sorting */,
-        },
-      },
-    );
+    return Boards.userBoards(this._id, null, {}, { sort: { sort: 1 } })
   },
   },
 
 
   starredBoards() {
   starredBoards() {
     const { starredBoards = [] } = this.profile || {};
     const { starredBoards = [] } = this.profile || {};
-    return Boards.find(
-      {
-        archived: false,
-        _id: {
-          $in: starredBoards,
-        },
-      },
-      {
-        sort: {
-          sort: 1 /* boards default sorting */,
-        },
-      },
+    return Boards.userBoards(
+      this._id,
+      false,
+      { _id: { $in: starredBoards } },
+      { sort: { sort: 1 } }
     );
     );
   },
   },
 
 
@@ -580,18 +576,11 @@ Users.helpers({
 
 
   invitedBoards() {
   invitedBoards() {
     const { invitedBoards = [] } = this.profile || {};
     const { invitedBoards = [] } = this.profile || {};
-    return Boards.find(
-      {
-        archived: false,
-        _id: {
-          $in: invitedBoards,
-        },
-      },
-      {
-        sort: {
-          sort: 1 /* boards default sorting */,
-        },
-      },
+    return Boards.userBoards(
+      this._id,
+      false,
+      { _id: { $in: invitedBoards } },
+      { sort: { sort: 1 } }
     );
     );
   },
   },
 
 

+ 55 - 42
server/publications/boards.js

@@ -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 || {};
-  check(starredBoards, [String]);
+  // const { starredBoards = [] } = (Users.findOne(userId) || {}).profile || {};
+  // check(starredBoards, [String]);
 
 
-  let currUser = Users.findOne(userId);
-  let orgIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.orgIdsUserBelongs() : '';
-  let teamIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.teamIdsUserBelongs() : '';
-  let orgsIds = [];
-  let teamsIds = [];
-  if(orgIdsUserBelongs && orgIdsUserBelongs != ''){
-    orgsIds = orgIdsUserBelongs.split(',');
-  }
-  if(teamIdsUserBelongs && teamIdsUserBelongs != ''){
-    teamsIds = teamIdsUserBelongs.split(',');
-  }
+  // let currUser = Users.findOne(userId);
+  // let orgIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.orgIdsUserBelongs() : '';
+  // let teamIdsUserBelongs = currUser!== 'undefined' && currUser.teams !== 'undefined' ? currUser.teamIdsUserBelongs() : '';
+  // let orgsIds = [];
+  // let teamsIds = [];
+  // if(orgIdsUserBelongs && orgIdsUserBelongs != ''){
+  //   orgsIds = orgIdsUserBelongs.split(',');
+  // }
+  // if(teamIdsUserBelongs && teamIdsUserBelongs != ''){
+  //   teamsIds = teamIdsUserBelongs.split(',');
+  // }
   return Boards.find(
   return Boards.find(
     {
     {
       archived: false,
       archived: false,
-      $or: [
-        {
-          // _id: { $in: starredBoards },  // Commented out, to get a list of all public boards
-          permission: 'public',
-        },
-        { members: { $elemMatch: { userId, isActive: true } } },
-        {'orgs.orgId': {$in : orgsIds}},
-        {'teams.teamId': {$in : teamsIds}},
-      ],
+      _id: { $in: Boards.userBoardIds(userId, false) },
+      // $or: [
+      //   {
+      //     // _id: { $in: starredBoards },  // Commented out, to get a list of all public boards
+      //     permission: 'public',
+      //   },
+      //   { members: { $elemMatch: { userId, isActive: true } } },
+      //   {'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,
-      $or: [
-        {
-          // _id: { $in: starredBoards },  // Commented out, to get a list of all public boards
-          permission: 'public',
-        },
-        { members: { $elemMatch: { userId, isActive: true } } },
-      ],
+      _id: { $in: Boards.userBoardIds(userId, null) },
     },
     },
     {
     {
       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,
-      members: {
-        $elemMatch: {
-          userId,
-          isAdmin: true,
-        },
-      },
+      _id: { $in: Boards.userBoardIds(userId, true)},
+      // archived: true,
+      // members: {
+      //   $elemMatch: {
+      //     userId,
+      //     isAdmin: true,
+      //   },
+      // },
     },
     },
     {
     {
       fields: {
       fields: {