attachments.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. Attachments = new FS.Collection('attachments', {
  2. stores: [
  3. // XXX Add a new store for cover thumbnails so we don't load big images in
  4. // the general board view
  5. new FS.Store.GridFS('attachments'),
  6. ],
  7. });
  8. if (Meteor.isServer) {
  9. Attachments.allow({
  10. insert(userId, doc) {
  11. return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
  12. },
  13. update(userId, doc) {
  14. return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
  15. },
  16. remove(userId, doc) {
  17. return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
  18. },
  19. // We authorize the attachment download either:
  20. // - if the board is public, everyone (even unconnected) can download it
  21. // - if the board is private, only board members can download it
  22. download(userId, doc) {
  23. const board = Boards.findOne(doc.boardId);
  24. if (board.isPublic()) {
  25. return true;
  26. } else {
  27. return board.hasMember(userId);
  28. }
  29. },
  30. fetch: ['boardId'],
  31. });
  32. }
  33. // XXX Enforce a schema for the Attachments CollectionFS
  34. Attachments.files.before.insert((userId, doc) => {
  35. const file = new FS.File(doc);
  36. doc.userId = userId;
  37. // If the uploaded document is not an image we need to enforce browser
  38. // download instead of execution. This is particularly important for HTML
  39. // files that the browser will just execute if we don't serve them with the
  40. // appropriate `application/octet-stream` MIME header which can lead to user
  41. // data leaks. I imagine other formats (like PDF) can also be attack vectors.
  42. // See https://github.com/wekan/wekan/issues/99
  43. // XXX Should we use `beforeWrite` option of CollectionFS instead of
  44. // collection-hooks?
  45. if (!file.isImage()) {
  46. file.original.type = 'application/octet-stream';
  47. }
  48. });
  49. if (Meteor.isServer) {
  50. Attachments.files.after.insert((userId, doc) => {
  51. Activities.insert({
  52. userId,
  53. type: 'card',
  54. activityType: 'addAttachment',
  55. attachmentId: doc._id,
  56. boardId: doc.boardId,
  57. cardId: doc.cardId,
  58. });
  59. });
  60. Attachments.files.after.remove((userId, doc) => {
  61. Activities.remove({
  62. attachmentId: doc._id,
  63. });
  64. });
  65. }