diff --git a/packages/rocketchat-lib/server/models/Avatars.js b/packages/rocketchat-lib/server/models/Avatars.js index 43c7b6be6af6..76d88df19f1e 100644 --- a/packages/rocketchat-lib/server/models/Avatars.js +++ b/packages/rocketchat-lib/server/models/Avatars.js @@ -1,7 +1,13 @@ +/* globals InstanceStatus */ + RocketChat.models.Avatars = new class extends RocketChat.models._Base { constructor() { super('avatars'); + this.model.before.insert((userId, doc) => { + doc.instanceId = InstanceStatus.id(); + }); + this.tryEnsureIndex({ name: 1 }); } diff --git a/packages/rocketchat-lib/server/models/Uploads.js b/packages/rocketchat-lib/server/models/Uploads.js index 3beaec043b8e..34d1dc6b9ea5 100644 --- a/packages/rocketchat-lib/server/models/Uploads.js +++ b/packages/rocketchat-lib/server/models/Uploads.js @@ -1,7 +1,13 @@ +/* globals InstanceStatus */ + RocketChat.models.Uploads = new class extends RocketChat.models._Base { constructor() { super('uploads'); + this.model.before.insert((userId, doc) => { + doc.instanceId = InstanceStatus.id(); + }); + this.tryEnsureIndex({ 'rid': 1 }); this.tryEnsureIndex({ 'uploadedAt': 1 }); } diff --git a/server/startup/avatar.js b/server/startup/avatar.js index 6c1bcab47b67..eceb9f0aa7bc 100644 --- a/server/startup/avatar.js +++ b/server/startup/avatar.js @@ -1,4 +1,95 @@ -/* globals FileUpload */ +/* globals FileUpload, UploadFS, InstanceStatus */ + +import http from 'http'; +import URL from 'url'; + +const logger = new Logger('UploadProxy'); + +WebApp.connectHandlers.stack.unshift({ + route: '', + handle: Meteor.bindEnvironment(function(req, res, next) { + // Quick check to see if request should be catch + if (req.url.indexOf(UploadFS.config.storesPath) === -1) { + return next(); + } + + logger.debug('Upload URL:', req.url); + + if (req.method !== 'POST') { + return next(); + } + + // Remove store path + const parsedUrl = URL.parse(req.url); + const path = parsedUrl.pathname.substr(UploadFS.config.storesPath.length + 1); + + // Get store + const regExp = new RegExp('^\/([^\/\?]+)\/([^\/\?]+)$'); + const match = regExp.exec(path); + + // Request is not valid + if (match === null) { + res.writeHead(400); + res.end(); + return; + } + + // Get store + const store = UploadFS.getStore(match[1]); + if (!store) { + res.writeHead(404); + res.end(); + return; + } + + // Get file + const fileId = match[2]; + const file = store.getCollection().findOne({_id: fileId}); + if (file === undefined) { + res.writeHead(404); + res.end(); + return; + } + + if (file.instanceId === InstanceStatus.id()) { + logger.debug('Correct instance'); + return next(); + } + + // Proxy to other instance + const instance = InstanceStatus.getCollection().findOne({_id: file.instanceId}); + + if (instance == null) { + res.writeHead(404); + res.end(); + return; + } + + if (instance.extraInformation.host === process.env.INSTANCE_IP && RocketChat.isDocker() === false) { + instance.extraInformation.host = 'localhost'; + } + + logger.debug('Wrong instance, proxing to:', `${ instance.extraInformation.host }:${ instance.extraInformation.port }`); + + const options = { + hostname: instance.extraInformation.host, + port: instance.extraInformation.port, + path: req.url, + method: 'POST' + }; + + const proxy = http.request(options, function(proxy_res) { + proxy_res.pipe(res, { + end: true + }); + }); + + req.pipe(proxy, { + end: true + }); + }) +}); + Meteor.startup(function() { WebApp.connectHandlers.use('/avatar/', Meteor.bindEnvironment(function(req, res/*, next*/) { const params = {