Last active
August 27, 2015 01:45
-
-
Save bschwind/277a078d59a70d451d0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var BUCKET_NAME = process.env.BUCKET; | |
var crypto = require("crypto"); | |
var jwt = require("jsonwebtoken"); | |
var logger = require("services/logger").getLogger("general"); | |
var mime = require("mime-types"); | |
var moment = require("moment"); | |
var uuid = require("node-uuid"); | |
var validation = require("services/validation"); | |
var uploadController = {}; | |
function InvalidFileFormatError() {} | |
InvalidFileFormatError.prototype = Object.create(Error.prototype); | |
function generateUploadToken(userID, objectKey) { | |
var issuedTime = moment(); | |
// An upload token is valid for 10 hours | |
var expiredTime = issuedTime.clone().add(10, "hours"); | |
var token = jwt.sign({ | |
sub: userID, | |
key: objectKey, | |
exp: expiredTime.valueOf(), // exp = Expiration date | |
iat: issuedTime.valueOf() // iat = Issued At Time | |
}, process.env.AWS_SECRET); | |
return token; | |
} | |
function checkUploadToken(token) { | |
var decodedToken; | |
try { | |
decodedToken = jwt.verify(token, process.env.AWS_SECRET); | |
} catch (err) { | |
return false; | |
} | |
if (!decodedToken) { | |
// Invalid or improperly signed token | |
return false; | |
} | |
if (moment(decodedToken.exp) <= moment()) { | |
// Token has expired | |
return false; | |
} | |
return decodedToken; | |
} | |
var allowedVideoTypes = [ | |
"video/h264", // .h264 | |
"video/webm", // .webm | |
"video/x-flv", // .flv | |
"video/quicktime", // .mov, .qt | |
"video/mpeg", // .mpeg, .mpg | |
"video/ogg", // .ogv | |
"video/x-matroska", // .mkv | |
"video/x-ms-wmv", // .wmv | |
"video/x-msvideo", // .avi | |
"video/jpeg" // .jpgv | |
]; | |
uploadController.initiateUploadRequest = function (req, res) { | |
var data = {}; | |
validation.run(req, { | |
file_name: [validation.required] | |
}) | |
.then(function (fields) { | |
var extension = fields.file_name.split(".").pop(); | |
var contentType = mime.types[extension]; | |
if (allowedVideoTypes.indexOf(contentType) >= 0) { | |
var objectKey = "raw_videos/" + uuid.v4() + "." + extension; | |
var token = generateUploadToken(req.user.id, objectKey); | |
data.message_code = 200; | |
data.message = "OK"; | |
data.token = token; | |
data.object_key = objectKey; | |
// TODO - We probably want a separate IAM user specifically | |
// for S3 uploads. Giving out the access key isn't | |
// dangerous but it's not a great practice. | |
data.access_key = process.env.AWS_KEY; | |
res.status(200).json(data); | |
} else { | |
// Invalid file format | |
throw new InvalidFileFormatError(); | |
} | |
}) | |
.catch(validation.ValidationError, function (err) { | |
data.message_code = 1; | |
data.message = "Invalid parameters"; | |
data.errors = err.errors; | |
res.status(400).json(data); | |
}) | |
.catch(InvalidFileFormatError, function (err) { | |
data.message_code = 22; | |
data.message = "Invalid file type"; | |
data.errors = err.errors; | |
res.status(400).json(data); | |
}) | |
.catch(function (err) { | |
logger.error(err); | |
data.message_code = 500; | |
data.message = "Internal server error"; | |
res.status(500).json(data); | |
}); | |
}; | |
uploadController.signMultipartUploadRequest = function (req, res) { | |
if (!req.query.to_sign || !req.query.upload_token) { | |
return res.status(400).send(); | |
} | |
var decodedToken = checkUploadToken(req.query.upload_token); | |
if (!decodedToken) { | |
return res.status(401).send(); | |
} | |
var toSign = decodeURIComponent(req.query.to_sign); | |
var clientObjectKey = "/" + BUCKET_NAME + "/" + decodedToken.key; | |
// The object key the client will use is contained in the last line | |
// of the string we're signing. | |
var lastLine = toSign.split("\n").pop(); | |
// If the client tries to upload an S3 key that is different than what | |
// we issued, we'll smack them with a 403 | |
if (lastLine.indexOf(clientObjectKey) !== 0) { | |
return res.status(403).send(); | |
} | |
res.send(crypto | |
.createHmac("sha1", process.env.AWS_SECRET) | |
.update(req.query.to_sign) | |
.digest("base64") | |
); | |
}; | |
module.exports = uploadController; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment