3 var env = require('gitter-web-env');
4 var nconf = env.config;
5 var redis = require('gitter-web-utils/lib/redis');
6 var uuid = require('uuid/v4');
7 var StatusError = require('statuserror');
8 var Promise = require('bluebird');
9 const policyFactory = require('gitter-web-permissions/lib/policy-factory');
11 var singletonTransloaditClient;
13 function getTransloaditClient() {
14 if (singletonTransloaditClient) {
15 return singletonTransloaditClient;
18 var TransloaditClient = require('transloadit');
19 singletonTransloaditClient = new TransloaditClient({
20 authKey: nconf.get('transloadit:key'),
21 authSecret: nconf.get('transloadit:secret')
24 return singletonTransloaditClient;
27 var redisClient = redis.getClient();
29 function randomString(length) {
30 var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
32 for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))];
36 async function parseAndValidateTransloadit(user, input) {
41 templateId = nconf.get('transloadit:template_image_id');
45 templateId = nconf.get('transloadit:template_avatar_id');
49 // default to a document type
50 templateId = nconf.get('transloadit:template_id');
55 NOTE: All the ngonf config vars used above are defined in all the config
56 files, but for some reason the old code validated that template_image_id is
57 truthy before using it, so just making sure here for now because using the
58 document template type in place of an avatar would just be broken anyway.
61 throw new StatusError(500, 'templateId required');
66 template_id: templateId,
76 // NOTE: This doesn't actually check that room or group uri makes sense for
80 // Any member of the room who can write a message, can upload something to a room.
81 const policy = await policyFactory.createPolicyForRoomId(user, input.room_id);
82 const writeAccess = await policy.canWrite();
84 throw new StatusError(403);
87 // upload a document or image to a room
88 metadata.room_id = input.room_id;
90 params.auth.max_size = 20971520; // 20MB
91 params.fields.room_id = input.room_id;
92 params.steps.export_originals = {
93 path: '${fields.room_id}/${fields.token}/${file.url_name}'
95 params.steps.export_thumbs = {
96 path: '${fields.room_id}/${fields.token}/thumb/${file.url_name}'
98 } else if (input.type === 'avatar' && input.group_id) {
99 const policy = await policyFactory.createPolicyForGroupId(user, input.group_id);
100 const writeAccess = await policy.canAdmin();
102 throw new StatusError(403);
105 // upload an avatar to a group
106 metadata.group_id = input.group_id;
108 params.auth.max_size = 5242880; // 5MB
110 params.steps.export_original = {
111 path: 'groups/' + input.group_id + '/original',
112 bucket: nconf.get('transloadit:avatars:bucket')
114 params.steps.export_thumbs = {
115 path: 'groups/' + input.group_id + '/${file.meta.width}',
116 bucket: nconf.get('transloadit:avatars:bucket')
119 throw new StatusError(400, 'room or group info required');
128 function transloaditSignature(req, res, next) {
129 return Promise.try(async () => {
130 const info = await parseAndValidateTransloadit(req.user, req.query);
132 var params = info.params;
133 var metadata = info.metadata;
135 var apiBasePath = nconf.get('web:apiBasePath');
138 params.fields.token = randomString(4);
139 params.notify_url = apiBasePath + '/private/transloadit/' + token;
141 // Store the token temporarily to verify Transloadit callback
142 var expiry = 30 * 60; // 30 mins to be safe, S3 uploads, etc
143 redisClient.setex('transloadit:' + token, expiry, JSON.stringify(metadata));
145 var signed = getTransloaditClient().calcSignature(params);
147 sig: signed.signature,
148 params: signed.params
153 module.exports = transloaditSignature;
154 module.exports.testOnly = {
155 parseAndValidateTransloadit: parseAndValidateTransloadit