|
|
|
@ -11,6 +11,7 @@ define([
|
|
|
|
|
var uint8ArrayToHex = Util.uint8ArrayToHex;
|
|
|
|
|
var hexToBase64 = Util.hexToBase64;
|
|
|
|
|
var base64ToHex = Util.base64ToHex;
|
|
|
|
|
Hash.encodeBase64 = Nacl.util.encodeBase64;
|
|
|
|
|
|
|
|
|
|
// This implementation must match that on the server
|
|
|
|
|
// it's used for a checksum
|
|
|
|
@ -59,6 +60,11 @@ define([
|
|
|
|
|
return '/1/' + hexToBase64(secret.channel) + '/' +
|
|
|
|
|
Crypto.b64RemoveSlashes(data.fileKeyStr) + '/';
|
|
|
|
|
}
|
|
|
|
|
if (version === 2) {
|
|
|
|
|
if (!data.fileKeyStr) { return; }
|
|
|
|
|
var pass = secret.password ? 'p/' : '';
|
|
|
|
|
return '/2/' + secret.type + '/' + Crypto.b64RemoveSlashes(data.fileKeyStr) + '/' + pass;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// V1
|
|
|
|
@ -95,12 +101,22 @@ define([
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Hash.createRandomHash = function (type, password) {
|
|
|
|
|
var cryptor = Crypto.createEditCryptor2(void 0, void 0, password);
|
|
|
|
|
var cryptor;
|
|
|
|
|
if (type === 'file') {
|
|
|
|
|
cryptor = Crypto.createFileCryptor2(void 0, password);
|
|
|
|
|
return getFileHashFromKeys({
|
|
|
|
|
password: Boolean(password),
|
|
|
|
|
version: 2,
|
|
|
|
|
type: type,
|
|
|
|
|
keys: cryptor.fileKeyStr
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
cryptor = Crypto.createEditCryptor2(void 0, void 0, password);
|
|
|
|
|
return getEditHashFromKeys({
|
|
|
|
|
password: Boolean(password),
|
|
|
|
|
version: 2,
|
|
|
|
|
type: type,
|
|
|
|
|
keys: { editKeyStr: cryptor.editKeyStr }
|
|
|
|
|
keys: cryptor.editKeyStr
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -113,6 +129,7 @@ Version 1
|
|
|
|
|
|
|
|
|
|
var parseTypeHash = Hash.parseTypeHash = function (type, hash) {
|
|
|
|
|
if (!hash) { return; }
|
|
|
|
|
var options;
|
|
|
|
|
var parsed = {};
|
|
|
|
|
var hashArr = fixDuplicateSlashes(hash).split('/');
|
|
|
|
|
if (['media', 'file', 'user', 'invite'].indexOf(type) === -1) {
|
|
|
|
@ -125,7 +142,6 @@ Version 1
|
|
|
|
|
parsed.version = 0;
|
|
|
|
|
return parsed;
|
|
|
|
|
}
|
|
|
|
|
var options;
|
|
|
|
|
if (hashArr[1] && hashArr[1] === '1') { // Version 1
|
|
|
|
|
parsed.version = 1;
|
|
|
|
|
parsed.mode = hashArr[2];
|
|
|
|
@ -175,6 +191,25 @@ Version 1
|
|
|
|
|
parsed.key = hashArr[3].replace(/-/g, '/');
|
|
|
|
|
return parsed;
|
|
|
|
|
}
|
|
|
|
|
if (hashArr[1] && hashArr[1] === '2') { // Version 2
|
|
|
|
|
parsed.version = 2;
|
|
|
|
|
parsed.app = hashArr[2];
|
|
|
|
|
parsed.key = hashArr[3];
|
|
|
|
|
|
|
|
|
|
options = hashArr.slice(4);
|
|
|
|
|
parsed.password = options.indexOf('p') !== -1;
|
|
|
|
|
parsed.present = options.indexOf('present') !== -1;
|
|
|
|
|
parsed.embed = options.indexOf('embed') !== -1;
|
|
|
|
|
|
|
|
|
|
parsed.getHash = function (opts) {
|
|
|
|
|
var hash = hashArr.slice(0, 4).join('/') + '/';
|
|
|
|
|
if (parsed.password) { hash += 'p/'; }
|
|
|
|
|
if (opts.embed) { hash += 'embed/'; }
|
|
|
|
|
if (opts.present) { hash += 'present/'; }
|
|
|
|
|
return hash;
|
|
|
|
|
};
|
|
|
|
|
return parsed;
|
|
|
|
|
}
|
|
|
|
|
return parsed;
|
|
|
|
|
}
|
|
|
|
|
if (['user'].indexOf(type) !== -1) {
|
|
|
|
@ -309,11 +344,12 @@ Version 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (parsed.type === "file") {
|
|
|
|
|
// version 2 hashes are to be used for encrypted blobs
|
|
|
|
|
secret.channel = parsed.channel;
|
|
|
|
|
secret.keys = { fileKeyStr: parsed.key };
|
|
|
|
|
secret.channel = base64ToHex(parsed.channel);
|
|
|
|
|
secret.keys = {
|
|
|
|
|
fileKeyStr: parsed.key,
|
|
|
|
|
cryptKey: Nacl.util.decodeBase64(parsed.key)
|
|
|
|
|
};
|
|
|
|
|
} else if (parsed.type === "user") {
|
|
|
|
|
// version 2 hashes are to be used for encrypted blobs
|
|
|
|
|
throw new Error("User hashes can't be opened (yet)");
|
|
|
|
|
}
|
|
|
|
|
} else if (parsed.version === 2) {
|
|
|
|
@ -338,7 +374,12 @@ Version 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (parsed.type === "file") {
|
|
|
|
|
throw new Error("File hashes should be version 1");
|
|
|
|
|
secret.channel = base64ToHex(secret.keys.chanId);
|
|
|
|
|
secret.keys = Crypto.createFileCryptor2(parsed.key, password);
|
|
|
|
|
secret.key = secret.keys.fileKeyStr;
|
|
|
|
|
if (secret.channel.length !== 48 || secret.key.length !== 24) {
|
|
|
|
|
throw new Error("The channel key and/or the encryption key is invalid");
|
|
|
|
|
}
|
|
|
|
|
} else if (parsed.type === "user") {
|
|
|
|
|
throw new Error("User hashes can't be opened (yet)");
|
|
|
|
|
}
|
|
|
|
|