Password-protected files

This commit is contained in:
yflory
2018-05-25 18:00:10 +02:00
parent 95218f0fa1
commit c7e08fedfb
18 changed files with 117 additions and 96 deletions

View File

@@ -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)");
}