|
const Promise = require('bluebird'); |
|
const redis = require('redis'); |
|
const crypto = require('crypto'); |
|
const moment = require('moment'); |
|
|
|
var REDIS_CLIENT_CACHE; |
|
|
|
Promise.promisifyAll(redis.RedisClient.prototype); |
|
|
|
// Encryption algorithm to use |
|
const algo = 'aes256'; |
|
|
|
/** |
|
* Encrypt data stored in redis |
|
* @param {String} data String to encrypt for redis storage |
|
* @param {String} id The ID of the store being created |
|
* @returns {String} encrypted string |
|
*/ |
|
const encrypt = (data, id) => { |
|
const cipher = crypto.createCipher(algo, id); |
|
cipher.update(data, 'utf8'); |
|
return cipher.final('base64'); |
|
}; |
|
|
|
/** |
|
* Decrypt data stored in redis |
|
* @param {String} data String to decrypt from redis storage |
|
* @param {String} id The ID of the store being read |
|
* @returns {String} decrypted string |
|
*/ |
|
const decrypt = (data, id) => { |
|
if (!data) return 'EXPIRED!'; |
|
const decipher = crypto.createDecipher(algo, id); |
|
decipher.update(data, 'base64'); |
|
return decipher.final('utf8'); |
|
}; |
|
|
|
/** |
|
* Creates new Redis client connection |
|
* @param {Object} context The context of the execution |
|
* @returns {Object} promisified redis client |
|
*/ |
|
const createRedisClient = (context) => Promise.resolve().then(() => { |
|
if (REDIS_CLIENT_CACHE) return REDIS_CLIENT_CACHE; |
|
// Create client |
|
const client = redis.createClient({ |
|
host: context.secrets.REDIS_URL, |
|
port: context.meta.REDIS_PORT || 6379, |
|
no_ready_check: true |
|
}); |
|
// Authenticate |
|
return client.authAsync(context.secrets.REDIS_PASSWORD) |
|
.then(() => { |
|
CLIENT_CACHE = client; |
|
return client; |
|
}); |
|
}); |
|
|
|
/** |
|
* Builds formatted response for Slack |
|
* @param {Object} obj Properties required for response |
|
* @returns {Object} slack response Object |
|
*/ |
|
const buildResponse = (obj) => { |
|
return { |
|
response_type: 'ephemeral', |
|
text: `Your Slecret will expire in ${obj.expireIn}`, |
|
attachments: [{ |
|
title: 'Only you can see this! Share the link below carefully!', |
|
text: obj.url |
|
}] |
|
}; |
|
}; |
|
|
|
module.exports = function(context, cb) { |
|
// Retrieve a slecret if id in query |
|
if (context.query.id) { |
|
return createRedisClient(context) |
|
.then((client) => client.getAsync(context.query.id)) |
|
.then((data) => cb(null, { slecret: decrypt(data, context.query.id) })) |
|
.catch((err) => cb(null, `Could not get data: ${err.message}`)); |
|
} |
|
|
|
// Create a slecret |
|
const id = crypto.randomBytes(10).toString('hex'); |
|
const lifespan = context.meta.SLECRET_LIFESPAN || 300; |
|
const expireIn = moment().startOf('day').seconds(lifespan).format('HH:mm:ss'); |
|
const url = `https://${context.headers.host}/slecret?id=${id}`; |
|
// Save to Redis |
|
return createRedisClient(context) |
|
.then((client) => client.setexAsync(id, lifespan, encrypt(context.body.text, id))) |
|
// Fire callback |
|
.then(() => cb(null, buildResponse(Object.assign({ url }, { id })))) |
|
.catch((e) => cb(null, `There was an error: ${e.message}`)); |
|
}; |