Commit eb77c9c3 authored by Romain Courteaud's avatar Romain Courteaud

QiniuStorage: use native Crypto implementatiion.

Modify data model to be like local storage: one document with multiple attachments.
parent 369b078d
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b<a;b++)c[f+b>>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535<q.length)for(b=0;b<a;b+=4)c[f+b>>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b<a;b+=4)c.push(4294967296*g.random()|0);return new p.init(c,a)}}),b=e.enc={},n=b.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f<a;f++){var d=c[f>>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f<c;f+=2)b[f>>>3]|=parseInt(a.substr(f,
2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f<a;f++)b.push(String.fromCharCode(c[f>>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f<c;f++)b[f>>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}},
r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;k<a;k+=d)this._doProcessBlock(b,k);k=b.splice(0,a);c.sigBytes-=f}return new p.init(k,f)},clone:function(){var a=k.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});d.Hasher=r.extend({cfg:k.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){r.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,d){return(new a.init(d)).finalize(b)}},_createHmacHelper:function(a){return function(b,d){return(new s.HMAC.init(a,
d)).finalize(b)}}});var s=e.algo={};return e}(Math);
(function(){var g=CryptoJS,l=g.lib,e=l.WordArray,d=l.Hasher,m=[],l=g.algo.SHA1=d.extend({_doReset:function(){this._hash=new e.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(d,e){for(var b=this._hash.words,n=b[0],j=b[1],h=b[2],g=b[3],l=b[4],a=0;80>a;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^
g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})();
(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h<g;h++)n[h]^=1549556828,j[h]^=909522486;p.sigBytes=b.sigBytes=k;this.reset()},reset:function(){var e=this._hasher;e.reset();e.update(this._iKey)},update:function(e){this._hasher.update(e);return this},finalize:function(e){var d=
this._hasher;e=d.finalize(e);d.reset();return d.finalize(this._oKey.clone().concat(e))}})})();
/* /*
* Copyright 2013, Nexedi SA * Copyright 2015, Nexedi SA
* Released under the LGPL license. * Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html * http://www.gnu.org/licenses/lgpl.html
*/ */
...@@ -7,22 +7,23 @@ ...@@ -7,22 +7,23 @@
/** /**
* JIO Qiniu Storage. Type = "qiniu". * JIO Qiniu Storage. Type = "qiniu".
* Qiniu "database" storage. * Qiniu "database" storage.
*
* REMAINING WORK:
* - removeAttachment should support CORS
* - allAttachments should support CORS
* - disable getAttachment HTTP cache
*/ */
/*global FormData, btoa, Blob, CryptoJS, define, jIO */
/*jslint indent: 2, maxlen: 80, nomen: true, unparam: true, bitwise: true */ /*global JSON, FormData, btoa, Blob, jIO, RSVP, UriTemplate, crypto,
(function (dependencies, module) { Uint8Array, TextEncoder*/
"use strict"; /*jslint nomen: true*/
if (typeof define === 'function' && define.amd) { (function (JSON, FormData, btoa, Blob, jIO, RSVP, UriTemplate, Crypto,
return define(dependencies, module); Uint8Array, TextEncoder) {
}
// if (typeof exports === 'object') {
// return module(exports, require('jio'));
// }
module(jIO);
}([
'jio'
], function (jIO) {
"use strict"; "use strict";
var METADATA_URL = "http://{+bucket}/{+key}{?e,token}",
metadata_template = UriTemplate.parse(METADATA_URL),
UPLOAD_URL = "http://up.qiniu.com/",
DEADLINE = 2451491200;
function urlsafe_base64_encode(string) { function urlsafe_base64_encode(string) {
return string return string
...@@ -31,32 +32,38 @@ ...@@ -31,32 +32,38 @@
// .replace(/=+$/, ''); // Remove ending '=' // .replace(/=+$/, ''); // Remove ending '='
} }
function b64_hmac_sha1(secret_key, message) { function bytesToASCIIString(bytes) {
// https://parse.com/questions/hmac-sha1-byte-order return String.fromCharCode.apply(null, new Uint8Array(bytes));
// Not sure why we have to do this, but we need to swap
// the bytes inside each of the five
// words that make up the encoded signature from b0, b1,
// b2, b3 to b3, b2, b1, b0.
var encodedArray = [],
i,
encoded = CryptoJS.HmacSHA1(message, secret_key),
encodedString;
for (i = 0; i < 5; i = i + 1) {
encodedArray[(i * 4)] = ((encoded.words[i] & 0xff000000) >>> 24);
encodedArray[(i * 4) + 1] = ((encoded.words[i] & 0x00ff0000) >>> 16);
encodedArray[(i * 4) + 2] = ((encoded.words[i] & 0x0000ff00) >>> 8);
encodedArray[(i * 4) + 3] = ((encoded.words[i] & 0x000000ff) >>> 0);
} }
// Make string from our array of bytes that we just ordered. // http://blog.engelke.com/tag/webcrypto/
encodedString = String.fromCharCode.apply(null, encodedArray); function stringToArrayBuffer(string) {
var encoder = new TextEncoder("utf-8");
return encoder.encode(string);
}
return urlsafe_base64_encode(btoa(encodedString)); function b64_hmac_sha1(secret_key, message) {
return new RSVP.Queue()
.push(function () {
return Crypto.subtle.importKey(
"raw",
stringToArrayBuffer(secret_key),
{name: "HMAC", hash: "SHA-1"},
false,
["sign"]
);
})
.push(function (key) {
return Crypto.subtle.sign({
name: "HMAC",
hash: "SHA-1"
}, key, stringToArrayBuffer(message));
})
.push(function (signature) {
return urlsafe_base64_encode(btoa(bytesToASCIIString(signature)));
});
} }
var UPLOAD_URL = "http://up.qiniu.com/",
DEADLINE = 2451491200;
/** /**
* The JIO QiniuStorage extension * The JIO QiniuStorage extension
...@@ -83,290 +90,177 @@ ...@@ -83,290 +90,177 @@
this._secret_key = spec.secret_key; this._secret_key = spec.secret_key;
} }
QiniuStorage.prototype._put = function (key, blob, update) { function restrictDocumentId(id) {
if (id !== "/") {
throw new jIO.util.jIOError("id " + id + " is forbidden (!== /)",
400);
}
}
QiniuStorage.prototype.get = function (id) {
restrictDocumentId(id);
return {};
};
QiniuStorage.prototype.getAttachment = function (id, key) {
restrictDocumentId(id);
var context = this,
download_url = metadata_template.expand({
bucket: context._bucket,
key: key,
e: DEADLINE
});
return new RSVP.Queue()
.push(function () {
return b64_hmac_sha1(context._secret_key, download_url);
})
.push(function (token) {
return jIO.util.ajax({
type: "GET",
url: metadata_template.expand({
bucket: context._bucket,
key: key,
e: DEADLINE,
token: context._access_key + ':' + token
})
});
})
.push(function (result) {
return new Blob([result.target.response ||
result.target.responseText]);
}, function (error) {
if ((error.target !== undefined) &&
(error.target.status === 404)) {
throw new jIO.util.jIOError("Cannot find attachment: "
+ id + " , " + key,
404);
}
throw error;
});
};
QiniuStorage.prototype.putAttachment = function (id, key, blob) {
restrictDocumentId(id);
var data, var data,
context = this,
put_policy, put_policy,
encoded, encoded,
encode_signed,
upload_token; upload_token;
data = new FormData(); data = new FormData();
if (update === true) {
put_policy = JSON.stringify({ put_policy = JSON.stringify({
"scope": this._bucket + ':' + key, "scope": "bucket" + ':' + key,
"deadline": DEADLINE "deadline": DEADLINE
}); });
} else {
put_policy = JSON.stringify({
"scope": this._bucket,
"deadline": DEADLINE
});
}
encoded = btoa(put_policy); encoded = btoa(put_policy);
encode_signed = b64_hmac_sha1(this._secret_key, encoded);
upload_token = this._access_key + ":" + encode_signed + ":" + encoded; return new RSVP.Queue()
.push(function () {
return b64_hmac_sha1(context._secret_key, encoded);
})
.push(function (encode_signed) {
upload_token = context._access_key + ":" + encode_signed + ":" +
encoded;
data.append("key", key); data.append("key", key);
data.append("token", upload_token); data.append("token", upload_token);
data.append( data.append(
"file", "file",
// new Blob([JSON.stringify(doc)], {type: "application/json"}),
// new Blob([doc], {type: "application/json"}),
blob, blob,
// new Blob([], {type: "application/octet-stream"}),
key key
); );
return jIO.util.ajax({ return jIO.util.ajax({
"type": "POST", type: "POST",
"url": UPLOAD_URL, url: UPLOAD_URL,
"data": data data: data
}); });
};
/**
* Create a document.
*
* @method post
* @param {Object} command The JIO command
* @param {Object} metadata The metadata to store
*/
QiniuStorage.prototype.post = function (command, metadata) {
var doc = jIO.util.deepClone(metadata),
doc_id = metadata._id;
if (!doc_id) {
doc_id = jIO.util.generateUuid();
doc._id = doc_id;
}
return this._put(
doc_id,
new Blob([JSON.stringify(doc)], {type: "application/json"})
).then(function (doc) {
if (doc !== null) {
command.success({"id": doc_id});
} else {
command.error(
"not_found",
"missing",
"Cannot find document"
);
}
}).fail(function (event) {
command.error(
event.target.status,
event.target.statusText,
"Unable to post doc"
);
}); });
}; };
/** QiniuStorage.prototype.hasCapacity = function (name) {
* Update/create a document. return (name === "list");
*
* @method put
* @param {Object} command The JIO command
* @param {Object} metadata The metadata to store
*/
QiniuStorage.prototype.put = function (command, metadata) {
return this._put(
metadata._id,
new Blob([JSON.stringify(metadata)], {type: "application/json"}),
true
).then(function (doc) {
if (doc !== null) {
command.success({"data": doc});
} else {
command.error(
"not_found",
"missing",
"Cannot find document"
);
}
}).fail(function (event) {
command.error(
event.target.status,
event.target.statusText,
"Unable to put doc"
);
});
}; };
QiniuStorage.prototype._get = function (key) { QiniuStorage.prototype.buildQuery = function () {
var download_url = 'http://' + this._bucket + '.u.qiniudn.com/' + key return [{
// var download_url = 'http://' + this._bucket + '.dn.qbox.me/' + key id: "/",
+ '?e=' + DEADLINE,
token = b64_hmac_sha1(this._secret_key, download_url);
return jIO.util.ajax({
"type": "GET",
"url": download_url + "&token=" + this._access_key + ':' + token
// "dataType": "blob"
});
};
/**
* Get a document or attachment
* @method get
* @param {object} command The JIO command
**/
QiniuStorage.prototype.get = function (command, param) {
return this._get(param._id)
.then(function (doc) {
if (doc.target.responseText !== undefined) {
command.success({"data": JSON.parse(doc.target.responseText)});
} else {
command.error(
"not_found",
"missing",
"Cannot find document"
);
}
}).fail(function (event) {
command.error(
event.target.status,
event.target.statusText,
"Unable to get doc"
);
});
};
/**
* Get an attachment
*
* @method getAttachment
* @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/
QiniuStorage.prototype.getAttachment = function (command, param) {
return this._get(param._id + "/" + param._attachment)
.then(function (doc) {
if (doc.target.response) {
command.success({"data": doc.target.response});
} else {
// XXX Handle error
command.error(
"not_found",
"missing",
"Cannot find document"
);
}
}).fail(function (event) {
command.error(
event.target.status,
event.target.statusText,
"Unable to get attachment"
);
});
};
/**
* Add an attachment to a document
*
* @method putAttachment
* @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/
QiniuStorage.prototype.putAttachment = function (command, param) {
return this._put(
param._id + "/" + param._attachment,
param._blob,
true
).then(function (doc) {
if (doc !== null) {
command.success({"data": doc});
} else {
command.error(
"not_found",
"missing",
"Cannot find document"
);
}
}).fail(function (event) {
command.error(
event.target.status,
event.target.statusText,
"Unable to put attachment"
);
});
};
/**
* Remove a document
*
* @method remove
* @param {Object} command The JIO command
* @param {Object} param The given parameters
*/
QiniuStorage.prototype.remove = function (command, param) {
var DELETE_HOST = "http://rs.qiniu.com",
DELETE_PREFIX = "/delete/",
encoded_entry_uri = urlsafe_base64_encode(btoa(
this._bucket + ':' + param._id
)),
delete_url = DELETE_HOST + DELETE_PREFIX + encoded_entry_uri,
data = DELETE_PREFIX + encoded_entry_uri + '\n',
token = b64_hmac_sha1(this._secret_key, data);
jIO.util.ajax({
"type": "POST",
"url": delete_url,
"headers": {
Authorization: "QBox " + this._access_key + ':' + token,
"Content-Type": 'application/x-www-form-urlencoded'
}
}).then(
command.success
).fail(function (error) {
command.error(
"not_found",
"missing",
"Unable to delete doc"
);
});
};
QiniuStorage.prototype.allDocs = function (command, param, options) {
var LIST_HOST = "http://rsf.qiniu.com",
LIST_PREFIX = "/list?bucket=" + this._bucket,
list_url = LIST_HOST + LIST_PREFIX,
token = b64_hmac_sha1(this._secret_key, LIST_PREFIX + '\n');
jIO.util.ajax({
"type": "POST",
"url": list_url,
"headers": {
Authorization: "QBox " + this._access_key + ':' + token,
"Content-Type": 'application/x-www-form-urlencoded'
}
}).then(function (response) {
var data = JSON.parse(response.target.responseText),
count = data.items.length,
result = [],
item,
i;
for (i = 0; i < count; i += 1) {
item = data.items[i];
result.push({
id: item.key,
key: item.key,
doc: {},
value: {} value: {}
}); }];
}
command.success({"data": {"rows": result, "total_rows": count}});
}).fail(function (error) {
command.error(
"error",
"did not work as expected",
"Unable to call allDocs"
);
});
}; };
// QiniuStorage.prototype.remove = function (command, param) {
//
// var DELETE_HOST = "http://rs.qiniu.com",
// DELETE_PREFIX = "/delete/",
// encoded_entry_uri = urlsafe_base64_encode(btoa(
// this._bucket + ':' + param._id
// )),
// delete_url = DELETE_HOST + DELETE_PREFIX + encoded_entry_uri,
// data = DELETE_PREFIX + encoded_entry_uri + '\n',
// token = b64_hmac_sha1(this._secret_key, data);
//
// jIO.util.ajax({
// "type": "POST",
// "url": delete_url,
// "headers": {
// Authorization: "QBox " + this._access_key + ':' + token,
// "Content-Type": 'application/x-www-form-urlencoded'
// }
// }).then(
// command.success
// ).fail(function (error) {
// command.error(
// "not_found",
// "missing",
// "Unable to delete doc"
// );
// });
// };
//
// QiniuStorage.prototype.allDocs = function (command, param, options) {
// var LIST_HOST = "http://rsf.qiniu.com",
// LIST_PREFIX = "/list?bucket=" + this._bucket,
// list_url = LIST_HOST + LIST_PREFIX,
// token = b64_hmac_sha1(this._secret_key, LIST_PREFIX + '\n');
//
// jIO.util.ajax({
// "type": "POST",
// "url": list_url,
// "headers": {
// Authorization: "QBox " + this._access_key + ':' + token,
// "Content-Type": 'application/x-www-form-urlencoded'
// }
// }).then(function (response) {
// var data = JSON.parse(response.target.responseText),
// count = data.items.length,
// result = [],
// item,
// i;
// for (i = 0; i < count; i += 1) {
// item = data.items[i];
// result.push({
// id: item.key,
// key: item.key,
// doc: {},
// value: {}
// });
// }
// command.success({"data": {"rows": result, "total_rows": count}});
// }).fail(function (error) {
// command.error(
// "error",
// "did not work as expected",
// "Unable to call allDocs"
// );
// });
// };
jIO.addStorage('qiniu', QiniuStorage); jIO.addStorage('qiniu', QiniuStorage);
}));
}(JSON, FormData, btoa, Blob, jIO, RSVP, UriTemplate, crypto, Uint8Array,
TextEncoder));
(function (dependencies, module) {
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
if (typeof exports === 'object') {
return module(exports);
}
module(window);
}(['exports'], function (exports) {
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
function hex_hmac_md5(k, d)
{ return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_md5(k, d)
{ return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_md5(k, d, e)
{ return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
/*
* Perform a simple self-test to see if the VM is working
*/
function md5_vm_test()
{
return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
}
/*
* Calculate the MD5 of a raw string
*/
function rstr_md5(s)
{
return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}
/*
* Calculate the HMAC-MD5, of a key and some data (raw strings)
*/
function rstr_hmac_md5(key, data)
{
var bkey = rstr2binl(key);
if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}
/*
* Convert a raw string to a hex string
*/
function rstr2hex(input)
{
try { hexcase } catch(e) { hexcase=0; }
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var output = "";
var x;
for(var i = 0; i < input.length; i++)
{
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F)
+ hex_tab.charAt( x & 0x0F);
}
return output;
}
/*
* Convert a raw string to a base-64 string
*/
function rstr2b64(input)
{
try { b64pad } catch(e) { b64pad=''; }
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var output = "";
var len = input.length;
for(var i = 0; i < len; i += 3)
{
var triplet = (input.charCodeAt(i) << 16)
| (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
| (i + 2 < len ? input.charCodeAt(i+2) : 0);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > input.length * 8) output += b64pad;
else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
}
}
return output;
}
/*
* Convert a raw string to an arbitrary string encoding
*/
function rstr2any(input, encoding)
{
var divisor = encoding.length;
var i, j, q, x, quotient;
/* Convert to an array of 16-bit big-endian values, forming the dividend */
var dividend = Array(Math.ceil(input.length / 2));
for(i = 0; i < dividend.length; i++)
{
dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
}
/*
* Repeatedly perform a long division. The binary array forms the dividend,
* the length of the encoding is the divisor. Once computed, the quotient
* forms the dividend for the next step. All remainders are stored for later
* use.
*/
var full_length = Math.ceil(input.length * 8 /
(Math.log(encoding.length) / Math.log(2)));
var remainders = Array(full_length);
for(j = 0; j < full_length; j++)
{
quotient = Array();
x = 0;
for(i = 0; i < dividend.length; i++)
{
x = (x << 16) + dividend[i];
q = Math.floor(x / divisor);
x -= q * divisor;
if(quotient.length > 0 || q > 0)
quotient[quotient.length] = q;
}
remainders[j] = x;
dividend = quotient;
}
/* Convert the remainders to the output string */
var output = "";
for(i = remainders.length - 1; i >= 0; i--)
output += encoding.charAt(remainders[i]);
return output;
}
/*
* Encode a string as utf-8.
* For efficiency, this assumes the input is valid utf-16.
*/
function str2rstr_utf8(input)
{
var output = "";
var i = -1;
var x, y;
while(++i < input.length)
{
/* Decode utf-16 surrogate pairs */
x = input.charCodeAt(i);
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
{
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
i++;
}
/* Encode output as utf-8 */
if(x <= 0x7F)
output += String.fromCharCode(x);
else if(x <= 0x7FF)
output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
0x80 | ( x & 0x3F));
else if(x <= 0xFFFF)
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
else if(x <= 0x1FFFFF)
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
}
return output;
}
/*
* Encode a string as utf-16
*/
function str2rstr_utf16le(input)
{
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
(input.charCodeAt(i) >>> 8) & 0xFF);
return output;
}
function str2rstr_utf16be(input)
{
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
input.charCodeAt(i) & 0xFF);
return output;
}
/*
* Convert a raw string to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
function rstr2binl(input)
{
var output = Array(input.length >> 2);
for(var i = 0; i < output.length; i++)
output[i] = 0;
for(var i = 0; i < input.length * 8; i += 8)
output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
return output;
}
/*
* Convert an array of little-endian words to a string
*/
function binl2rstr(input)
{
var output = "";
for(var i = 0; i < input.length * 32; i += 8)
output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
return output;
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function binl_md5(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
exports.hex_md5 = hex_md5;
exports.b64_md5 = b64_md5;
exports.any_md5 = any_md5;
exports.hex_hmac_md5 = hex_hmac_md5;
exports.b64_hmac_md5 = b64_hmac_md5;
exports.any_hmac_md5 = any_hmac_md5;
}));
(function (dependencies, module) {
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
if (typeof exports === 'object') {
return module(exports);
}
module(window);
}(['exports'], function (exports) {
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
/*
* Perform a simple self-test to see if the VM is working
*/
function sha1_vm_test()
{
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
/*
* Calculate the SHA-1 of an array of big-endian words, and a bit length
*/
function core_sha1(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for(var j = 0; j < 80; j++)
{
if(j < 16) w[j] = x[i + j];
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
function sha1_ft(t, b, c, d)
{
if(t < 20) return (b & c) | ((~b) & d);
if(t < 40) return b ^ c ^ d;
if(t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
function sha1_kt(t)
{
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
(t < 60) ? -1894007588 : -899497514;
}
/*
* Calculate the HMAC-SHA1 of a key and some data
*/
function core_hmac_sha1(key, data)
{
var bkey = str2binb(key);
if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert an 8-bit or 16-bit string to an array of big-endian words
* In 8-bit function, characters >255 have their hi-byte silently ignored.
*/
function str2binb(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
return bin;
}
/*
* Convert an array of big-endian words to a string
*/
function binb2str(bin)
{
var str = "";
var mask = (1 << chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
return str;
}
/*
* Convert an array of big-endian words to a hex string.
*/
function binb2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
}
return str;
}
/*
* Convert an array of big-endian words to a base-64 string
*/
function binb2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
exports.hex_sha1 = hex_sha1;
exports.b64_sha1 = b64_sha1;
exports.str_sha1 = str_sha1;
exports.hex_hmac_sha1 = hex_hmac_sha1;
exports.b64_hmac_sha1 = b64_hmac_sha1;
exports.str_hmac_sha1 = str_hmac_sha1;
}));
(function (dependencies, module) {
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
if (typeof exports === 'object') {
return module(exports);
}
module(window);
}(['exports'], function (window) {
/* A JavaScript implementation of the Secure Hash Standard
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
* Distributed under the BSD License
* Some bits taken from Paul Johnston's SHA-1 implementation
*/
(function () {
var chrsz = 8;/* bits per input character. 8 - ASCII; 16 - Unicode */
var hexcase = 0;/* hex output format. 0 - lowercase; 1 - uppercase */
function safe_add (x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function S (X, n) {return ( X >>> n ) | (X << (32 - n));}
function R (X, n) {return ( X >>> n );}
function Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
function Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
function Sigma0256(x) {return (S(x, 2) ^ S(x, 13) ^ S(x, 22));}
function Sigma1256(x) {return (S(x, 6) ^ S(x, 11) ^ S(x, 25));}
function Gamma0256(x) {return (S(x, 7) ^ S(x, 18) ^ R(x, 3));}
function Gamma1256(x) {return (S(x, 17) ^ S(x, 19) ^ R(x, 10));}
function Sigma0512(x) {return (S(x, 28) ^ S(x, 34) ^ S(x, 39));}
function Sigma1512(x) {return (S(x, 14) ^ S(x, 18) ^ S(x, 41));}
function Gamma0512(x) {return (S(x, 1) ^ S(x, 8) ^ R(x, 7));}
function Gamma1512(x) {return (S(x, 19) ^ S(x, 61) ^ R(x, 6));}
function newArray (n) {
var a = [];
for (;n>0;n--) {
a.push(undefined);
}
return a;
}
function core_sha256 (m, l) {
var K = [0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2];
var HASH = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
var W = newArray(64);
var a, b, c, d, e, f, g, h, i, j;
var T1, T2;
/* append padding */
m[l >> 5] |= 0x80 << (24 - l % 32);
m[((l + 64 >> 9) << 4) + 15] = l;
for ( var i = 0; i<m.length; i+=16 ) {
a = HASH[0];
b = HASH[1];
c = HASH[2];
d = HASH[3];
e = HASH[4];
f = HASH[5];
g = HASH[6];
h = HASH[7];
for ( var j = 0; j<64; j++) {
if (j < 16) {
W[j] = m[j + i];
} else {
W[j] = safe_add(safe_add(safe_add(Gamma1256(
W[j - 2]),W[j - 7]),Gamma0256(W[j - 15])), W[j - 16]);
}
T1 = safe_add(safe_add(safe_add(safe_add(
h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
h = g;
g = f;
f = e;
e = safe_add(d, T1);
d = c;
c = b;
b = a;
a = safe_add(T1, T2);
}
HASH[0] = safe_add(a, HASH[0]);
HASH[1] = safe_add(b, HASH[1]);
HASH[2] = safe_add(c, HASH[2]);
HASH[3] = safe_add(d, HASH[3]);
HASH[4] = safe_add(e, HASH[4]);
HASH[5] = safe_add(f, HASH[5]);
HASH[6] = safe_add(g, HASH[6]);
HASH[7] = safe_add(h, HASH[7]);
}
return HASH;
}
function core_sha512 (m, l) {
var K = [0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817];
var HASH = [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179];
var W = newArray(80);
var a, b, c, d, e, f, g, h, i, j;
var T1, T2;
}
function str2binb (str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
return bin;
}
function binb2str (bin) {
var str = "";
var mask = (1 << chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask);
return str;
}
function binb2hex (binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
}
return str;
}
function binb2b64 (binarray) {
var tab =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3) {
var triplet = (((binarray[i >> 2] >> 8 * (3- i %4)) & 0xFF) << 16) |
(((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |
((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++) {
if(i * 8 + j * 6 > binarray.length * 32) { str += b64pad; }
else {str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);}
}
}
return str;
}
function hex_sha256(s){
return binb2hex(core_sha256(str2binb(s),s.length * chrsz));
}
function b64_sha256(s){
return binb2b64(core_sha256(str2binb(s),s.length * chrsz));
}
function str_sha256(s){
return binb2str(core_sha256(str2binb(s),s.length * chrsz));
}
window.hex_sha256 = hex_sha256;
window.b64_sha256 = b64_sha256;
window.str_sha256 = str_sha256;
}());
}));
(function (dependencies, module) {
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
if (typeof exports === 'object') {
return module(exports);
}
module(window);
}(['exports'], function (window) {
/* A JavaScript implementation of the Secure Hash Algorithm, SHA-256
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
* Distributed under the BSD License
* Some bits taken from Paul Johnston's SHA-1 implementation
*/
(function () {
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
function safe_add (x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function S (X, n) {return ( X >>> n ) | (X << (32 - n));}
function R (X, n) {return ( X >>> n );}
function Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
function Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
function Sigma0256(x) {return (S(x, 2) ^ S(x, 13) ^ S(x, 22));}
function Sigma1256(x) {return (S(x, 6) ^ S(x, 11) ^ S(x, 25));}
function Gamma0256(x) {return (S(x, 7) ^ S(x, 18) ^ R(x, 3));}
function Gamma1256(x) {return (S(x, 17) ^ S(x, 19) ^ R(x, 10));}
function newArray (n) {
var a = [];
for (;n>0;n--) {
a.push(undefined);
}
return a;
}
function core_sha256 (m, l) {
var K = [0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2];
var HASH = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
var W = newArray(64);
var a, b, c, d, e, f, g, h, i, j;
var T1, T2;
/* append padding */
m[l >> 5] |= 0x80 << (24 - l % 32);
m[((l + 64 >> 9) << 4) + 15] = l;
for ( var i = 0; i<m.length; i+=16 ) {
a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3];
e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
for ( var j = 0; j<64; j++) {
if (j < 16) {
W[j] = m[j + i];
} else {
W[j] = safe_add(safe_add(safe_add(Gamma1256(
W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
}
T1 = safe_add(safe_add(safe_add(
safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
h = g; g = f; f = e; e = safe_add(d, T1);
d = c; c = b; b = a; a = safe_add(T1, T2);
}
HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]);
HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]);
HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]);
HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
}
return HASH;
}
function str2binb (str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
return bin;
}
function binb2hex (binarray) {
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
}
return str;
}
function hex_sha256(s){
return binb2hex(core_sha256(str2binb(s),s.length * chrsz));
}
window.hex_sha256 = hex_sha256;
}());
}));
/*jslint nomen: true*/
/*global define, module, test_util, RSVP, jIO, test, ok, /*global Blob, sinon, FormData*/
deepEqual, sinon, expect, stop, start, Blob, equal, define */ (function (jIO, Blob, sinon, FormData) {
/*jslint indent: 2 */
(function (dependencies, module) {
"use strict"; "use strict";
if (typeof define === 'function' && define.amd) { var test = QUnit.test,
return define(dependencies, module); stop = QUnit.stop,
start = QUnit.start,
ok = QUnit.ok,
equal = QUnit.equal,
deepEqual = QUnit.deepEqual,
module = QUnit.module,
expect = QUnit.expect,
bucket = "98ad7.com1.z0.glb.clouddn.com",
access_key = "phooMooch6au2shaechah8ee5si3za",
secret_key = "owiehei3j_utaex0kiShoof2goixieb",
qiniu_spec = {
type: "qiniu",
bucket: bucket,
access_key: access_key,
secret_key: secret_key
};
/////////////////////////////////////////////////////////////////
// qiniuStorage constructor
/////////////////////////////////////////////////////////////////
module("qiniuStorage.constructor");
test("Storage store parameters", function () {
var jio = jIO.createJIO(qiniu_spec);
equal(jio.__type, "qiniu");
deepEqual(jio.__storage._bucket, qiniu_spec.bucket);
deepEqual(jio.__storage._access_key, qiniu_spec.access_key);
deepEqual(jio.__storage._secret_key, qiniu_spec.secret_key);
});
/////////////////////////////////////////////////////////////////
// qiniuStorage.get
/////////////////////////////////////////////////////////////////
module("qiniuStorage.get", {
setup: function () {
this.jio = jIO.createJIO(qiniu_spec);
} }
module(test_util, RSVP, jIO); });
}([
'test_util',
'rsvp',
'jio',
'hmacsha1',
'qiniustorage',
'qunit'
// ], function (util, RSVP, jIO) {
], function () {
"use strict";
var qiniu_spec = { test("get non valid document ID", function () {
"type": "qiniu", stop();
"bucket": "uth6nied", expect(3);
"access_key": "Imh9CFmpVZ5L1TE04Pjt-UmR_Ccr2cW9-KjSmvSA",
"secret_key": "vFkNUlI2U4B7G1sz8UL_Z25kYHozfz82z4vMWPgo"
};
module("QiniuStorage", { this.jio.get("inexistent")
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "id inexistent is forbidden (!== /)");
equal(error.status_code, 400);
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get document without attachment", function () {
var id = "/";
stop();
expect(1);
this.jio.get(id)
.then(function (result) {
deepEqual(result, {}, "Check document");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// qiniuStorage.getAttachment
/////////////////////////////////////////////////////////////////
module("qiniuStorage.getAttachment", {
setup: function () { setup: function () {
this.server = sinon.fakeServer.create();
this.server = sinon.fakeServer.create();
this.server.autoRespond = true; this.server.autoRespond = true;
this.server.autoRespondAfter = 5; this.server.autoRespondAfter = 5;
this.jio_storage = jIO.createJIO(qiniu_spec); this.jio = jIO.createJIO(qiniu_spec);
}, },
teardown: function () { teardown: function () {
this.server.restore(); this.server.restore();
delete this.server; delete this.server;
delete this.jio_storage;
} }
}); });
test('get', function () { test("get attachment from inexistent document", function () {
var key = "foobar12345",
server = this.server,
download_url = 'http://uth6nied.u.qiniudn.com/foobar12345?' +
'e=2451491200&token=Imh9CFmpVZ5L1TE04Pjt-UmR_Ccr2cW9-KjSmvSA:' +
'hISFzrC4dQvdOR8A_MozNsB5cME=',
data = {
"_id": key,
"foo": "bar"
};
server.respondWith("GET", download_url, [200, {
"Content-Type": "application/json"
}, JSON.stringify(data)]);
stop(); stop();
this.jio_storage.get({"_id": key}) expect(3);
.then(function (result) {
deepEqual(result, { this.jio.getAttachment("inexistent", "a")
"data": data, .fail(function (error) {
"id": key, ok(error instanceof jIO.util.jIOError);
"method": "get", equal(error.message, "id inexistent is forbidden (!== /)");
"result": "success", equal(error.status_code, 400);
"status": 200,
"statusText": "Ok"
});
}) })
.fail(function (error) { .fail(function (error) {
ok(false, error); ok(false, error);
...@@ -78,42 +116,27 @@ ...@@ -78,42 +116,27 @@
}); });
test('getAttachment', function () { test('getAttachment', function () {
var key = "foobar12345", var attachment = "foobar12345/barfoo54321/e",
attachment = "barfoo54321",
server = this.server, server = this.server,
download_url = 'http://uth6nied.u.qiniudn.com/foobar12345/barfoo54321' + download_url = 'http://' + bucket + '/' +
'?e=2451491200&token=Imh9CFmpVZ5L1TE04Pjt-UmR_Ccr2cW9-KjSmvSA:' + encodeURI(attachment) +
'L88mHkZkfjr11DqPUqb5gsDjHFY=', '?e=2451491200&token=' + access_key +
data = { '%3AxOQx24teaT_yQXl5fU3CjUJSho4%3D';
"_id": key,
"foo": "bar",
"nut": "nut"
};
server.respondWith("GET", download_url, [200, { server.respondWith("GET", download_url, [200, {
"Content-Type": "application/octet-stream" "Content-Type": "application/octet-stream"
}, JSON.stringify(data)]); }, JSON.stringify({foo: 'baré'})]);
stop(); stop();
this.jio_storage.getAttachment({"_id": key, "_attachment": attachment}) this.jio.getAttachment('/', attachment, {format: 'json'})
.then(function (result) { .then(function (result) {
return jIO.util.readBlobAsText(result.data).then(function (e) { equal(server.requests.length, 1);
return { equal(server.requests[0].method, "GET");
"result": result, equal(server.requests[0].url, download_url);
"text": e.target.result equal(server.requests[0].requestBody, undefined);
}; equal(server.requests[0].withCredentials, undefined);
});
}).then(function (result) { deepEqual(result, {foo: 'baré'});
result.result.data = result.text;
deepEqual(result.result, {
"data": JSON.stringify(data),
"id": key,
"attachment": attachment,
"method": "getAttachment",
"result": "success",
"status": 200,
"statusText": "Ok"
});
}) })
.fail(function (error) { .fail(function (error) {
ok(false, error); ok(false, error);
...@@ -123,30 +146,37 @@ ...@@ -123,30 +146,37 @@
}); });
}); });
test('post', function () { /////////////////////////////////////////////////////////////////
var key = "foobar12345", // qiniuStorage.putAttachment
server = this.server, /////////////////////////////////////////////////////////////////
upload_url = 'http://up.qiniu.com/', module("qiniuStorage.putAttachment", {
data = {"ok": "excellent"}; setup: function () {
server.respondWith("POST", upload_url, [200, { this.server = sinon.fakeServer.create();
"Content-Type": "application/json" this.server.autoRespond = true;
}, JSON.stringify(data)]); this.server.autoRespondAfter = 5;
stop(); this.jio = jIO.createJIO(qiniu_spec);
this.jio_storage.post({"_id": key})
.then(function (result) { this.spy = sinon.spy(FormData.prototype, "append");
deepEqual(result, { },
"id": key, teardown: function () {
"method": "post", this.server.restore();
"result": "success", delete this.server;
"status": 201, this.spy.restore();
"statusText": "Created" delete this.spy;
}
}); });
return jIO.util.readBlobAsBinaryString(server.requests[0].requestBody);
}) test("put an attachment to an inexistent document", function () {
.then(function (e) { stop();
equal(e.target.result, "XXX test FormData verification"); expect(3);
this.jio.putAttachment("inexistent", "putattmt2", "")
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "id inexistent is forbidden (!== /)");
equal(error.status_code, 400);
}) })
.fail(function (error) { .fail(function (error) {
ok(false, error); ok(false, error);
...@@ -156,9 +186,11 @@ ...@@ -156,9 +186,11 @@
}); });
}); });
test('put', function () { test('putAttachment', function () {
var key = "foobar12345", var context = this,
attachment = "foobar12345/barfoo54321/e",
server = this.server, server = this.server,
blob = new Blob([JSON.stringify({foo: 'baré'})]),
upload_url = 'http://up.qiniu.com/', upload_url = 'http://up.qiniu.com/',
data = {"ok": "excellent"}; data = {"ok": "excellent"};
...@@ -167,9 +199,37 @@ ...@@ -167,9 +199,37 @@
}, JSON.stringify(data)]); }, JSON.stringify(data)]);
stop(); stop();
this.jio_storage.put({"_id": key}) this.jio.putAttachment(
'/',
attachment,
blob
)
.then(function () { .then(function () {
throw new Error("Not implemented"); equal(server.requests.length, 1);
equal(server.requests[0].method, "POST");
equal(server.requests[0].url, upload_url);
equal(server.requests[0].status, 200);
ok(server.requests[0].requestBody instanceof FormData);
equal(context.spy.callCount, 3, "FormData.append count " +
context.spy.callCount);
equal(context.spy.firstCall.args[0], "key", "First append call");
equal(context.spy.firstCall.args[1], attachment,
"First append call");
equal(context.spy.secondCall.args[0], "token",
"Second append call");
equal(
context.spy.secondCall.args[1],
access_key + ":" +
"TcUXVk75do5aEqQeahrYgXt1X9s=:" +
"eyJzY29wZSI6ImJ1Y2tldDpmb29iYXIxMjM0NS9iYXJmb281NDMyMS9l" +
"IiwiZGVhZGxpbmUiOjI0NTE0OTEyMDB9",
"Second append call"
);
equal(context.spy.thirdCall.args[0], "file", "Third append call");
equal(context.spy.thirdCall.args[1], blob, "Third append call");
equal(server.requests[0].withCredentials, undefined);
}) })
.fail(function (error) { .fail(function (error) {
ok(false, error); ok(false, error);
...@@ -179,32 +239,53 @@ ...@@ -179,32 +239,53 @@
}); });
}); });
test('putAttachment', function () { /////////////////////////////////////////////////////////////////
var key = "foobar12345", // qiniuStorage.hasCapacity
attachment = "barfoo54321", /////////////////////////////////////////////////////////////////
server = this.server, module("qiniuStorage.hasCapacity", {
upload_url = 'http://up.qiniu.com/', setup: function () {
data = {"ok": "excellent"}; this.jio = jIO.createJIO(qiniu_spec);
}
});
server.respondWith("POST", upload_url, [200, { test("can list documents", function () {
"Content-Type": "application/json" ok(this.jio.hasCapacity("list"));
}, JSON.stringify(data)]); });
/////////////////////////////////////////////////////////////////
// qiniuStorage.buildQuery
/////////////////////////////////////////////////////////////////
module("qiniuStorage.buildQuery", {
setup: function () {
this.jio = jIO.createJIO(qiniu_spec);
}
});
test("only return one document", function () {
stop(); stop();
this.jio_storage.putAttachment({ expect(1);
"_id": key,
"_attachment": attachment, this.jio.allDocs()
"_blob": "bar" .then(function (result) {
}) deepEqual(result, {
.then(function () { "data": {
throw new Error("Not implemented"); "rows": [
{
"id": "/",
"value": {}
}
],
"total_rows": 1
}
});
}) })
.fail(function (error) { .fail(function (error) {
ok(false, error); ok(false, error);
}) })
.always(function () { .always(function () {
start(); start();
}); });
}); });
})); }(jIO, Blob, sinon, FormData));
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
<script src="jio.storage/replicatestorage.tests.js"></script> <script src="jio.storage/replicatestorage.tests.js"></script>
<script src="jio.storage/shastorage.tests.js"></script> <script src="jio.storage/shastorage.tests.js"></script>
<!--script src="jio.storage/qiniustorage.tests.js"></script-->
<!--script src="jio.storage/indexstorage.tests.js"></script--> <!--script src="jio.storage/indexstorage.tests.js"></script-->
<script src="jio.storage/cryptstorage.tests.js"></script> <script src="jio.storage/cryptstorage.tests.js"></script>
<script src="jio.storage/dropboxstorage.tests.js"></script> <script src="jio.storage/dropboxstorage.tests.js"></script>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment