module.exports = BufferUtils
var crypto = require('crypto')
var constants = require('./constants')
/**
* @namespace
* @static
*/
function BufferUtils () {
// static class
}
/**
* @param {Buffer} data
* @return {boolean}
*/
BufferUtils.isJPEG = function (data) {
var h = BufferUtils._getHeader(data)
return h && h.a === 0xFF && h.b === 0xD8 && h.c === 0xFF
}
/**
* @param {Buffer} data
* @return {boolean}
*/
BufferUtils.isPNG = function (data) {
var h = BufferUtils._getHeader(data)
return h && h.a === 0x89 && h.b === 0x50 && h.c === 0x4E && h.d === 0x47
}
/**
* @param {Buffer} data
* @return {boolean}
*/
BufferUtils.isImage = function (data) {
return BufferUtils.isJPEG(data) || BufferUtils.isPNG(data)
}
/**
* @param {Buffer} data
* @return {boolean}
*/
BufferUtils.isMPEG4 = function (data) {
var h = BufferUtils._getHeader(data, 4)
// return h && h.a === 0x00 && h.b === 0x00 && h.c === 0x00
return h && h.a === 0x66 && h.b === 0x74 && h.c === 0x79 && h.d === 0x70
}
/**
* @param {Buffer} data
* @return {boolean}
*/
BufferUtils.isMedia = function (data) {
return BufferUtils.isImage(data) || BufferUtils.isMPEG4(data)
}
/**
* @param {Buffer} data
* @return {boolean}
*/
BufferUtils.isCompressed = function (data) {
var h = BufferUtils._getHeader(data)
// check for presence of a PK header
return h && h.a === 0x50 && h.b === 0x4B
// && h.c === 0x03 && h.d === 0x04
}
/**
* @param {Buffer} data
* @return {Object}
*/
BufferUtils._getHeader = function (data, index) {
index = index || 0
if (!data || data.length < index + 4) {
return null
} else {
return {
a: data.readUInt8(index + 0),
b: data.readUInt8(index + 1),
c: data.readUInt8(index + 2),
d: data.readUInt8(index + 3)
}
}
}
/**
* @param {Buffer} data
* @return {string}
*/
BufferUtils.getFileExtension = function (data) {
if (BufferUtils.isJPEG(data)) return '.jpg'
if (BufferUtils.isPNG(data)) return '.png'
if (BufferUtils.isMPEG4(data)) return '.mp4'
if (BufferUtils.isCompressed(data)) return '.zip'
return '.dat'
}
/**
* @param {Buffer} data
* @return {string}
*/
BufferUtils.sha256HashToBase64 = function (data) {
return crypto.createHash('sha256').update(data).digest('base64')
}
/**
* @param {Buffer} data
* @return {string}
*/
BufferUtils.sha256HashToHex = function (data) {
return crypto.createHash('sha256').update(data).digest('hex')
}
/**
* @param {Buffer} a
* @param {Buffer} b
* @return {string}
*/
BufferUtils.hashSC = function (a, b) {
var secret = new Buffer(constants.core.secret)
var firstData = Buffer.concat([ secret, a ])
var secondData = Buffer.concat([ b, secret ])
var first = BufferUtils.sha256HashToHex(firstData)
var second = BufferUtils.sha256HashToHex(secondData)
var pattern = constants.core.hashPattern
var hash = ''
for (var i = 0; i < pattern.length; ++i) {
if (pattern.charAt(i) === '0') {
hash += first.charAt(i)
} else {
hash += second.charAt(i)
}
}
return hash
}
/**
* Decrypts Buffer data for stories.
*
* @param {Buffer} data
* @param {string} key (base64)
* @param {string} iv (base64)
* @return {Buffer}
*/
BufferUtils.decryptStory = function (data, key, iv) {
if (!data || !key || !iv) throw new Error('BufferUtils.decryptStory invalid params')
var keyBuffer = new Buffer(key, 'base64')
var ivBuffer = new Buffer(iv, 'base64')
return BufferUtils.AES128DecryptedData(data, keyBuffer, ivBuffer)
}
/**
* Decrypts Buffer data for stories.
*
* @param {Buffer} data
* @param {Buffer} key
* @param {Buffer} iv
* @return {Buffer}
*/
BufferUtils.AES128DecryptedData = function (data, key, iv) {
var keyLength = (key.length >= 32 ? 32 : 16)
var algorithm = (keyLength === 32 ? 'aes-256-cbc' : 'aes-128-cbc')
var decipher = crypto.createDecipheriv(algorithm, key.slice(0, keyLength), iv.slice(0, 16))
return Buffer.concat([
decipher.update(data),
decipher.final()
])
}
/**
* Generates a HTTP multipart/form-data boundary for the given key key,value pair.
*
* @param {string} key
* @param {string} value
* @return {Buffer}
*/
BufferUtils.boundaryForString = function (key, value) {
return Buffer.concat([
new Buffer('\r\n--' + constants.core.boundary + '\r\n'),
new Buffer('Content-Disposition: form-data; name="' + key + '"\r\n\r\n'),
new Buffer('' + value)
])
}
/**
* Generates a HTTP multipart/form-data boundary for the given key key,value pair.
*
* @param {string} key
* @param {Buffer} value
* @return {Buffer}
*/
BufferUtils.boundaryForBuffer = function (key, value) {
BufferUtils.assertBuffer(value)
return Buffer.concat([
new Buffer('\r\n--' + constants.core.boundary + '\r\n'),
new Buffer('Content-Disposition: form-data; name="' + key + '"; filename="' + key + '"\r\n'),
new Buffer('Content-Type: application/octet-stream\r\n\r\n'),
value
])
}
BufferUtils.assertBuffer = function (data) {
if (!Buffer.isBuffer(data)) {
throw new Error('invalid Buffer', data)
}
}