mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-07-18 17:05:17 +00:00
feature(edit) rm client sha
This commit is contained in:
parent
c94515d0a2
commit
1b47867f9c
5 changed files with 18 additions and 389 deletions
|
|
@ -1781,30 +1781,24 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
|
|||
* @param data
|
||||
* @param callback
|
||||
*/
|
||||
this.saveDataToStorage = function(name, data, hash, callback) {
|
||||
this.saveDataToStorage = function(name, data, callback) {
|
||||
CloudCmd.getConfig(function(config) {
|
||||
var allowed = config.localStorage,
|
||||
isDir = DOM.isCurrentIsDir(),
|
||||
nameHash = name + '-hash',
|
||||
nameData = name + '-data',
|
||||
save = function(hash) {
|
||||
Storage.set(nameHash, hash);
|
||||
Storage.set(nameData, data);
|
||||
};
|
||||
nameData = name + '-data';
|
||||
|
||||
if (!allowed || isDir)
|
||||
Util.exec(callback);
|
||||
else {
|
||||
if (hash)
|
||||
save(hash);
|
||||
else
|
||||
DOM.checkStorageHash(name, function(error, equal, hash) {
|
||||
if (!error && !equal)
|
||||
save(hash);
|
||||
|
||||
Util.exec(callback, hash);
|
||||
});
|
||||
}
|
||||
else
|
||||
DOM.checkStorageHash(name, function(error, equal, hash) {
|
||||
if (!error && !equal) {
|
||||
Storage.set(nameHash, hash);
|
||||
Storage.set(nameData, data);
|
||||
}
|
||||
|
||||
Util.exec(callback, hash);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
|
|||
Value,
|
||||
Edit = this,
|
||||
Diff,
|
||||
SHA,
|
||||
Ace,
|
||||
Msg,
|
||||
Dialog = DOM.Dialog,
|
||||
|
|
@ -161,20 +160,12 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
|
|||
}
|
||||
|
||||
DOM.checkStorageHash(lPath, function(error, equal) {
|
||||
var ret,
|
||||
msg = 'File is changed, overwrite?',
|
||||
saveFunc = function(text) {
|
||||
var hash = SHA.digest(Value);
|
||||
onSave(text, hash);
|
||||
};
|
||||
|
||||
if (!error && !equal)
|
||||
ret = Dialog.confirm(msg);
|
||||
else
|
||||
DOM.RESTful.save(lPath, lValue, saveFunc, query);
|
||||
if (!error) {
|
||||
if (!equal)
|
||||
query = '';
|
||||
|
||||
if (ret)
|
||||
DOM.RESTful.save(lPath, lValue, saveFunc);
|
||||
DOM.RESTful.save(lPath, lValue, onSave, query);
|
||||
}
|
||||
});
|
||||
|
||||
}, function(callback) {
|
||||
|
|
@ -188,16 +179,12 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
|
|||
function diff(pNewValue, pCallBack) {
|
||||
var libs = [
|
||||
LIBDIR + 'diff.js',
|
||||
LIBDIR + 'diff/diff-match-patch.js',
|
||||
LIBDIR + 'sha1/rusha.js'
|
||||
LIBDIR + 'diff/diff-match-patch.js'
|
||||
];
|
||||
|
||||
DOM.anyLoadInParallel(libs, function() {
|
||||
var patch;
|
||||
|
||||
if (!SHA)
|
||||
SHA = new Rusha();
|
||||
|
||||
if (!Diff)
|
||||
Diff = new DiffProto(diff_match_patch);
|
||||
|
||||
|
|
@ -243,7 +230,7 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
|
|||
|
||||
if (!isError) {
|
||||
Edit.showMessage(text);
|
||||
DOM.saveDataToStorage(path, Value, hash);
|
||||
DOM.saveDataToStorage(path, Value);
|
||||
} else {
|
||||
ret = Dialog.confirm(text + msg);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
# Rusha
|
||||
*A high-performance pure-javascript SHA1 implementation suitable for large binary data.*
|
||||
|
||||
## Prologue: The Sad State of Javascript SHA1 implementations
|
||||
|
||||
When we started experimenting with alternative upload technologies at [doctape](http://doctape.com) that required creating SHA1 hashes of the data locally on the client, it quickly became obvious that there were no performant pure-js implementations of SHA1 that worked correctly on binary data.
|
||||
|
||||
Jeff Mott's [CryptoJS](http://code.google.com/p/crypto-js/) and Brian Turek's [jsSHA](http://caligatio.github.com/jsSHA/) were both hash functions that worked correctly on ASCII strings of a small size, but didn't scale to large data and/or didn't work correctly with binary data.
|
||||
|
||||
(On a sidenode, as of now Tim Caswell's [Cifre](http://github.com/openpeer/cifre) actually works with large binary data, as opposed to previously statet.)
|
||||
|
||||
By modifying Paul Johnston's [sha1.js](http://pajhome.org.uk/crypt/md5/sha1.html) slightly, it worked correctly on binary data but was unfortunately very slow, especially on V8. So a few days were invested on my side to implement a Johnston-inspired SHA1 hashing function with a heavy focus on performance.
|
||||
|
||||
The result of this process is Rusha, a SHA1 hash function that works flawlessly on large amounts binary data, such as binary strings or ArrayBuffers returned by the HTML5 File API, and leverages the soon-to-be-landed-in-firefox [asm.js](http://asmjs.org/spec/latest/) with whose support its within *half of native speed*!
|
||||
|
||||
## Installing
|
||||
|
||||
### Node.JS
|
||||
|
||||
There is really no point in doing this, since Node.JS already has a wonderful `crypto` module that is leveraging low-level hardware instructions to perform really nice. Your can see the comparison below in the benchmarks.
|
||||
|
||||
Rusha is available on [npm](http://npmjs.org/) via `npm install rusha`.
|
||||
|
||||
If you still want to do this, anyhow, just `require()` the `rusha.js` file, follow the instructions on _Using the Rusha Object_.
|
||||
|
||||
### Browser
|
||||
|
||||
Rusha is available on [bower](http://twitter.github.com/bower/) via `bower install rusha`.
|
||||
|
||||
It is highly recommended to run CPU-intensive tasks in a [Web Worker](http://developer.mozilla.org/en-US/docs/DOM/Using_web_workers). To do so, just start a worker with `var worker = new Worker('rusha.js')` and start sending it jobs. Follow the instructions on _Using the Rusha Worker_.
|
||||
|
||||
If you can't, for any reason, use Web Workers, include the `rusha.js` file in a `<script>` tag and follow the instructions on _Using the Rusha Object_.
|
||||
|
||||
## Using the Rusha Object
|
||||
|
||||
Your instantiate a new Rusha object by doing `var r = new Rusha(optionalSizeHint)`. When created, it provides the following methods:
|
||||
|
||||
- `Rusha#digest(d)`: Create a hex digest from data of the three kinds mentioned below, or throw and error if the type is unsupported.
|
||||
- `Rusha#digestFromString(s)`: Create a hex digest from a binary `String`. A binary string is expected to only contain characters whose charCode < 256.
|
||||
- `Rusha#digestFromBuffer(b)`: Create a hex digest from a `Buffer` or `Array`. Both are expected to only contain elements < 256.
|
||||
- `Rusha#digestFromArrayBuffer(a)`: Create a hex digest from an `ArrayBuffer` object.
|
||||
- `Rusha#rawDigest(d)`: Behaves just like #digest(d), except that it returns the digest as an Int32Array of size 5.
|
||||
|
||||
## Using the Rusha Worker
|
||||
|
||||
You can send your instance of the web worker messages in the format `{id: jobid, data: dataobject}`. The worker then sends back a message in the format `{id: jobid, hash: hash}`, were jobid is the id of the job previously received and hash is the hash of the data-object you passed, be it a `Blob`, `Array`, `Buffer`, `ArrayBuffer` or `String`.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Tested were my Rusha implementation, the sha1.js implementation by [P. A. Johnston](http://pajhome.org.uk/crypt/md5/sha1.html), Tim Caswell's [Cifre](http://github.com/openpeer/cifre) and the Node.JS native implementation.
|
||||
|
||||
If you want to check the performance for yourself in your own browser, I compiled a [JSPerf Page](http://jsperf.com/rusha/2).
|
||||
|
||||
A normalized estimation based on the best results for each implementation, smaller is better:
|
||||

|
||||
|
||||
Results per Implementation and Platform:
|
||||

|
||||
|
||||
All tests were performed on a MacBook Air 1.7 GHz Intel Core i5 and 4 GB 1333 MHz DDR3.
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"name": "rusha",
|
||||
"version": "0.7.2",
|
||||
"description": "A high-performance pure-javascript SHA1 implementation suitable for large binary data.",
|
||||
"main": "rusha.js",
|
||||
"keywords": [
|
||||
"sha1",
|
||||
"binary",
|
||||
"crypto",
|
||||
"hash"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/srijs/rusha"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsmin": "~1.0"
|
||||
},
|
||||
"author": "Sam Rijs",
|
||||
"license": "MIT",
|
||||
"readmeFilename": "README.md"
|
||||
}
|
||||
|
|
@ -1,270 +0,0 @@
|
|||
|
||||
|
||||
(function () {
|
||||
|
||||
// If we'e running in Node.JS, export a module.
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = Rusha;
|
||||
}
|
||||
|
||||
// If we're running in a DOM context, export
|
||||
// the Rusha object to toplevel.
|
||||
if (typeof window !== 'undefined') {
|
||||
window.Rusha = Rusha;
|
||||
}
|
||||
|
||||
// If we're running in a webworker, accept
|
||||
// messages containing a jobid and a buffer
|
||||
// or blob object, and return the hash result.
|
||||
if (typeof FileReaderSync !== 'undefined') {
|
||||
var reader = new FileReaderSync(),
|
||||
hasher = new Rusha(4 * 1024 * 1024);
|
||||
self.onmessage = function onMessage (event) {
|
||||
var hash, data = event.data.data;
|
||||
if (data instanceof Blob) {
|
||||
try {
|
||||
data = reader.readAsBinaryString(data);
|
||||
} catch (e) {
|
||||
self.postMessage({id: event.data.id, error: e.name});
|
||||
return;
|
||||
}
|
||||
}
|
||||
hash = hasher.digest(data);
|
||||
self.postMessage({id: event.data.id, hash: hash});
|
||||
};
|
||||
}
|
||||
|
||||
// The Rusha object is a wrapper around the low-level RushaCore.
|
||||
// It provides means of converting different inputs to the
|
||||
// format accepted by RushaCore as well as other utility methods.
|
||||
function Rusha (sizeHint) {
|
||||
"use strict";
|
||||
|
||||
// Private object structure.
|
||||
var self = {fill: 0};
|
||||
|
||||
// Calculate the length of buffer that the sha1 routine uses
|
||||
// including the padding.
|
||||
var padlen = function (len) {
|
||||
return len + 1 + ((len ) % 64 < 56 ? 56 : 56 + 64) - (len ) % 64 + 8;
|
||||
};
|
||||
|
||||
var padZeroes = function (bin, len) {
|
||||
for (var i = len >> 2; i < bin.length; i++) bin[i] = 0;
|
||||
};
|
||||
|
||||
var padData = function (bin, len) {
|
||||
bin[len>>2] |= 0x80 << (24 - (len % 4 << 3));
|
||||
bin[(((len >> 2) + 2) & ~0x0f) + 15] = len << 3;
|
||||
};
|
||||
|
||||
// Convert a binary string to a big-endian Int32Array using
|
||||
// four characters per slot and pad it per the sha1 spec.
|
||||
// A binary string is expected to only contain char codes < 256.
|
||||
var convStr = function (str, bin, len) {
|
||||
var i;
|
||||
for (i = 0; i < len; i = i + 4 |0) {
|
||||
bin[i>>2] = str.charCodeAt(i) << 24 |
|
||||
str.charCodeAt(i+1) << 16 |
|
||||
str.charCodeAt(i+2) << 8 |
|
||||
str.charCodeAt(i+3);
|
||||
}
|
||||
};
|
||||
|
||||
// Convert a buffer or array to a big-endian Int32Array using
|
||||
// four elements per slot and pad it per the sha1 spec.
|
||||
// The buffer or array is expected to only contain elements < 256.
|
||||
var convBuf = function (buf, bin, len) {
|
||||
var i, m = len % 4, j = len - m;
|
||||
for (i = 0; i < j; i = i + 4 |0) {
|
||||
bin[i>>2] = buf[i] << 24 |
|
||||
buf[i+1] << 16 |
|
||||
buf[i+2] << 8 |
|
||||
buf[i+3];
|
||||
}
|
||||
switch (m) {
|
||||
case 0: bin[j>>2] |= buf[j+3];
|
||||
case 3: bin[j>>2] |= buf[j+2] << 8;
|
||||
case 2: bin[j>>2] |= buf[j+1] << 16;
|
||||
case 1: bin[j>>2] |= buf[j] << 24;
|
||||
}
|
||||
};
|
||||
|
||||
// Convert general data to a big-endian Int32Array written on the
|
||||
// heap and return it's length;
|
||||
var conv = function (data, bin, len) {
|
||||
if (typeof data === 'string') {
|
||||
return convStr(data, bin, len);
|
||||
} else if (data instanceof Array || (typeof global !== 'undefined' &&
|
||||
typeof global.Buffer !== 'undefined' &&
|
||||
data instanceof global.Buffer)) {
|
||||
return convBuf(data, bin, len);
|
||||
} else if (data instanceof ArrayBuffer) {
|
||||
return convBuf(new Uint8Array(data), bin, len);
|
||||
} else if (data.buffer instanceof ArrayBuffer) {
|
||||
return convBuf(new Uint8Array(data.buffer), bin, len);
|
||||
} else {
|
||||
throw new Error('Unsupported data type.');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Convert a array containing 32 bit integers
|
||||
// into its hexadecimal string representation.
|
||||
var hex = function (binarray) {
|
||||
var i, x, hex_tab = "0123456789abcdef", res = [];
|
||||
for (i = 0; i < binarray.length; i++) {
|
||||
x = binarray[i];
|
||||
res[i] = hex_tab.charAt((x >> 28) & 0xF) +
|
||||
hex_tab.charAt((x >> 24) & 0xF) +
|
||||
hex_tab.charAt((x >> 20) & 0xF) +
|
||||
hex_tab.charAt((x >> 16) & 0xF) +
|
||||
hex_tab.charAt((x >> 12) & 0xF) +
|
||||
hex_tab.charAt((x >> 8) & 0xF) +
|
||||
hex_tab.charAt((x >> 4) & 0xF) +
|
||||
hex_tab.charAt((x >> 0) & 0xF);
|
||||
}
|
||||
return res.join('');
|
||||
};
|
||||
|
||||
var nextPow2 = function (v) {
|
||||
var p = 1; while (p < v) p = p << 1; return p;
|
||||
};
|
||||
|
||||
// Resize the internal data structures to a new capacity.
|
||||
var resize = function (size) {
|
||||
self.sizeHint = size;
|
||||
self.heap = new ArrayBuffer(nextPow2(padlen(size) + 320));
|
||||
self.core = RushaCore({Int32Array: Int32Array}, {}, self.heap);
|
||||
};
|
||||
|
||||
// On initialize, resize the datastructures according
|
||||
// to an optional size hint.
|
||||
resize(sizeHint || 0);
|
||||
|
||||
// Initialize and call the RushaCore,
|
||||
// assuming an input buffer of length len * 4.
|
||||
var coreCall = function (len) {
|
||||
var h = new Int32Array(self.heap, len << 2, 5);
|
||||
h[0] = 1732584193;
|
||||
h[1] = -271733879;
|
||||
h[2] = -1732584194;
|
||||
h[3] = 271733878;
|
||||
h[4] = -1009589776;
|
||||
self.core.hash(len);
|
||||
};
|
||||
|
||||
// Calculate the hash digest as an array of 5 32bit integers.
|
||||
var rawDigest = this.rawDigest = function (str) {
|
||||
var len = str.byteLength || str.length;
|
||||
if (len > self.sizeHint) {
|
||||
resize(len);
|
||||
}
|
||||
var view = new Int32Array(self.heap, 0, padlen(len) >> 2);
|
||||
padZeroes(view, len);
|
||||
conv(str, view, len);
|
||||
padData(view, len);
|
||||
coreCall(view.length);
|
||||
return new Int32Array(self.heap, 0, 5);
|
||||
};
|
||||
|
||||
// The digest and digestFrom* interface returns the hash digest
|
||||
// as a hex string.
|
||||
this.digest = this.digestFromString =
|
||||
this.digestFromBuffer = this.digestFromArrayBuffer =
|
||||
function (str) {
|
||||
return hex(rawDigest(str));
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// The low-level RushCore module provides the heart of Rusha,
|
||||
// a high-speed sha1 implementation working on an Int32Array heap.
|
||||
// At first glance, the implementation seems complicated, however
|
||||
// with the SHA1 spec at hand, it is obvious this almost a textbook
|
||||
// implementation that has a few functions hand-inlined and a few loops
|
||||
// hand-unrolled.
|
||||
function RushaCore (stdlib, foreign, heap) {
|
||||
"use asm";
|
||||
|
||||
var H = new stdlib.Int32Array(heap);
|
||||
|
||||
function hash (k) {
|
||||
|
||||
k = k|0;
|
||||
var i = 0, j = 0,
|
||||
y0 = 0, z0 = 0, y1 = 0, z1 = 0,
|
||||
y2 = 0, z2 = 0, y3 = 0, z3 = 0,
|
||||
y4 = 0, z4 = 0, t0 = 0, t1 = 0;
|
||||
|
||||
y0 = H[k+0<<2>>2]|0;
|
||||
y1 = H[k+1<<2>>2]|0;
|
||||
y2 = H[k+2<<2>>2]|0;
|
||||
y3 = H[k+3<<2>>2]|0;
|
||||
y4 = H[k+4<<2>>2]|0;
|
||||
|
||||
for (i = 0; (i|0) < (k|0); i = i + 16 |0) {
|
||||
|
||||
z0 = y0;
|
||||
z1 = y1;
|
||||
z2 = y2;
|
||||
z3 = y3;
|
||||
z4 = y4;
|
||||
|
||||
|
||||
for (j = 0; (j|0) < 16; j = j + 1 |0) {
|
||||
t1 = H[i+j<<2>>2]|0;
|
||||
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0) +1518500249 |0) |0);
|
||||
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
|
||||
H[k+j<<2>>2] = t1;
|
||||
}
|
||||
|
||||
for (j = k + 16 |0; (j|0) < (k + 20 |0); j = j + 1 |0) {
|
||||
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
|
||||
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0) +1518500249 |0) |0);
|
||||
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
|
||||
H[j<<2>>2] = t1;
|
||||
}
|
||||
|
||||
for (j = k + 20 |0; (j|0) < (k + 40 |0); j = j + 1 |0) {
|
||||
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
|
||||
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0) +1859775393 |0) |0);
|
||||
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
|
||||
H[j<<2>>2] = t1;
|
||||
}
|
||||
|
||||
for (j = k + 40 |0; (j|0) < (k + 60 |0); j = j + 1 |0) {
|
||||
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
|
||||
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3) |0) + ((t1 + y4 | 0) -1894007588 |0) |0);
|
||||
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
|
||||
H[j<<2>>2] = t1;
|
||||
}
|
||||
|
||||
for (j = k + 60 |0; (j|0) < (k + 80 |0); j = j + 1 |0) {
|
||||
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
|
||||
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0) -899497514 |0) |0);
|
||||
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
|
||||
H[j<<2>>2] = t1;
|
||||
}
|
||||
|
||||
y0 = y0 + z0 |0;
|
||||
y1 = y1 + z1 |0;
|
||||
y2 = y2 + z2 |0;
|
||||
y3 = y3 + z3 |0;
|
||||
y4 = y4 + z4 |0;
|
||||
|
||||
}
|
||||
|
||||
H[0] = y0;
|
||||
H[1] = y1;
|
||||
H[2] = y2;
|
||||
H[3] = y3;
|
||||
H[4] = y4;
|
||||
|
||||
}
|
||||
|
||||
return {hash: hash};
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue