Move the parseHash code into parsePadUrl
parent
e0293a1162
commit
0f13198119
|
@ -32,9 +32,58 @@ define([
|
|||
return '/1/view/' + hexToBase64(chanKey) + '/'+Crypto.b64RemoveSlashes(keys.viewKeyStr)+'/';
|
||||
};
|
||||
var getFileHashFromKeys = Hash.getFileHashFromKeys = function (fileKey, cryptKey) {
|
||||
return '/2/' + hexToBase64(fileKey) + '/' + Crypto.b64RemoveSlashes(cryptKey) + '/';
|
||||
return '/1/' + hexToBase64(fileKey) + '/' + Crypto.b64RemoveSlashes(cryptKey) + '/';
|
||||
};
|
||||
|
||||
var fixDuplicateSlashes = function (s) {
|
||||
return s.replace(/\/+/g, '/');
|
||||
};
|
||||
|
||||
var parseTypeHash = Hash.parseTypeHash = function (type, hash) {
|
||||
if (!hash) { return; }
|
||||
var parsed = {}
|
||||
var hashArr = fixDuplicateSlashes(hash).split('/');
|
||||
if (['media', 'file', 'user'].indexOf(type) === -1) {
|
||||
parsed.type = 'pad';
|
||||
if (hash.slice(0,1) !== '/' && hash.length >= 56) {
|
||||
// Old hash
|
||||
parsed.channel = hash.slice(0, 32);
|
||||
parsed.key = hash.slice(32);
|
||||
parsed.version = 0;
|
||||
return parsed;
|
||||
}
|
||||
if (hashArr[1] && hashArr[1] === '1') {
|
||||
parsed.version = 1;
|
||||
parsed.mode = hashArr[2];
|
||||
parsed.channel = hashArr[3];
|
||||
parsed.key = hashArr[4].replace(/-/g, '/');
|
||||
parsed.present = typeof(hashArr[5]) === "string" && hashArr[5] === 'present';
|
||||
return parsed;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
if (['media', 'file'].indexOf(type) !== -1) {
|
||||
parsed.type = 'file';
|
||||
if (hashArr[1] && hashArr[1] === '1') {
|
||||
parsed.version = 1;
|
||||
parsed.channel = hashArr[2].replace(/-/g, '/');
|
||||
parsed.key = hashArr[3].replace(/-/g, '/');
|
||||
return parsed;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
if (['user'].indexOf(type) !== -1) {
|
||||
parsed.type = 'user';
|
||||
if (hashArr[1] && hashArr[1] === '1') {
|
||||
parsed.version = 1;
|
||||
parsed.user = hashArr[2];
|
||||
parsed.pubkey = hashArr[3].replace(/-/g, '/');
|
||||
return parsed;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
return;
|
||||
};
|
||||
var parsePadUrl = Hash.parsePadUrl = function (href) {
|
||||
var patt = /^https*:\/\/([^\/]*)\/(.*?)\//i;
|
||||
|
||||
|
@ -43,10 +92,13 @@ define([
|
|||
if (!href) { return ret; }
|
||||
if (href.slice(-1) !== '/') { href += '/'; }
|
||||
|
||||
|
||||
|
||||
if (!/^https*:\/\//.test(href)) {
|
||||
var idx = href.indexOf('/#');
|
||||
ret.type = href.slice(1, idx);
|
||||
ret.hash = href.slice(idx + 2);
|
||||
ret.hashData = parseTypeHash(ret.type, ret.hash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -56,6 +108,7 @@ define([
|
|||
return '';
|
||||
});
|
||||
ret.hash = hash.replace(/#/g, '');
|
||||
ret.hashData = parseTypeHash(ret.type, ret.hash);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
@ -66,16 +119,12 @@ define([
|
|||
return '/' + parsed.type + '/#' + parsed.hash;
|
||||
};
|
||||
|
||||
var fixDuplicateSlashes = function (s) {
|
||||
return s.replace(/\/+/g, '/');
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns all needed keys for a realtime channel
|
||||
* - no argument: use the URL hash or create one if it doesn't exist
|
||||
* - secretHash provided: use secretHash to find the keys
|
||||
*/
|
||||
Hash.getSecrets = function (secretHash) {
|
||||
Hash.getSecrets = function (type, secretHash) {
|
||||
var secret = {};
|
||||
var generate = function () {
|
||||
secret.keys = Crypto.createEditCryptor();
|
||||
|
@ -85,50 +134,55 @@ define([
|
|||
generate();
|
||||
return secret;
|
||||
} else {
|
||||
var hash = secretHash || window.location.hash.slice(1);
|
||||
var parsed;
|
||||
var hash;
|
||||
if (secretHash) {
|
||||
if (!type) { throw new Error("getSecrets with a hash requires a type parameter"); }
|
||||
parsed = parseTypeHash(type, secretHash);
|
||||
hash = secretHash;
|
||||
} else {
|
||||
var pHref = parsePadUrl(window.location.href);
|
||||
parsed = pHref.hashData;
|
||||
hash = pHref.hash;
|
||||
}
|
||||
//var parsed = parsePadUrl(window.location.href);
|
||||
//var hash = secretHash || window.location.hash.slice(1);
|
||||
console.log(hash, parsed);
|
||||
if (hash.length === 0) {
|
||||
generate();
|
||||
return secret;
|
||||
}
|
||||
// old hash system : #{hexChanKey}{cryptKey}
|
||||
// new hash system : #/{hashVersion}/{b64ChanKey}/{cryptKey}
|
||||
if (hash.slice(0,1) !== '/' && hash.length >= 56) {
|
||||
if (parsed.version === 0) {
|
||||
// Old hash
|
||||
secret.channel = hash.slice(0, 32);
|
||||
secret.key = hash.slice(32);
|
||||
}
|
||||
else {
|
||||
else if (parsed.version === 1) {
|
||||
// New hash
|
||||
var hashArray = fixDuplicateSlashes(hash).split('/');
|
||||
if (hashArray.length < 4) {
|
||||
Hash.alert("Unable to parse the key");
|
||||
throw new Error("Unable to parse the key");
|
||||
}
|
||||
var version = hashArray[1];
|
||||
if (version === "1") {
|
||||
var mode = hashArray[2];
|
||||
if (mode === 'edit') {
|
||||
secret.channel = base64ToHex(hashArray[3]);
|
||||
var keys = Crypto.createEditCryptor(hashArray[4].replace(/-/g, '/'));
|
||||
secret.keys = keys;
|
||||
secret.key = keys.editKeyStr;
|
||||
if (parsed.type === "pad") {
|
||||
secret.channel = base64ToHex(parsed.channel);
|
||||
if (parsed.mode === 'edit') {
|
||||
console.log(parsed.key);
|
||||
secret.keys = Crypto.createEditCryptor(parsed.key);
|
||||
secret.key = secret.keys.editKeyStr;
|
||||
if (secret.channel.length !== 32 || secret.key.length !== 24) {
|
||||
Hash.alert("The channel key and/or the encryption key is invalid");
|
||||
throw new Error("The channel key and/or the encryption key is invalid");
|
||||
}
|
||||
}
|
||||
else if (mode === 'view') {
|
||||
secret.channel = base64ToHex(hashArray[3]);
|
||||
secret.keys = Crypto.createViewCryptor(hashArray[4].replace(/-/g, '/'));
|
||||
else if (parsed.mode === 'view') {
|
||||
secret.keys = Crypto.createViewCryptor(parsed.key);
|
||||
if (secret.channel.length !== 32) {
|
||||
Hash.alert("The channel key is invalid");
|
||||
throw new Error("The channel key is invalid");
|
||||
}
|
||||
}
|
||||
} else if (version === "2") {
|
||||
} else if (parsed.type === "file") {
|
||||
// version 2 hashes are to be used for encrypted blobs
|
||||
secret.channel = hashArray[2].replace(/-/g, '/');
|
||||
secret.keys = { fileKeyStr: hashArray[3].replace(/-/g, '/') };
|
||||
secret.channel = parsed.channel;
|
||||
secret.keys = { fileKeyStr: parsed.key };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +229,7 @@ Version 2
|
|||
/file/#/2/K6xWU-LT9BJHCQcDCT-DcQ/ajExFODrFH4lVBwxxsrOKw/image-png
|
||||
*/
|
||||
var parseHash = Hash.parseHash = function (hash) {
|
||||
throw new Error('parseHash deprecated');
|
||||
var parsed = {};
|
||||
if (hash.slice(0,1) !== '/' && hash.length >= 56) {
|
||||
// Old hash
|
||||
|
@ -211,9 +266,13 @@ Version 2
|
|||
var p = parsePadUrl(pad.href);
|
||||
if (p.type !== parsed.type) { return; } // Not the same type
|
||||
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
||||
var pHash = parseHash(p.hash);
|
||||
var parsedHash = parseHash(parsed.hash);
|
||||
var pHash = p.hashData;
|
||||
var parsedHash = parsed.hashData;
|
||||
if (!parsedHash || !pHash) { return; }
|
||||
|
||||
// We don't have stronger/weaker versions of files or users
|
||||
if (pHash.type !== 'pad' && parsedHash.type !== 'pad') { return; }
|
||||
|
||||
if (pHash.version !== parsedHash.version) { return; }
|
||||
if (pHash.channel !== parsedHash.channel) { return; }
|
||||
if (pHash.mode === 'view' && parsedHash.mode === 'edit') {
|
||||
|
@ -233,9 +292,13 @@ Version 2
|
|||
var p = parsePadUrl(pad.href);
|
||||
if (p.type !== parsed.type) { return; } // Not the same type
|
||||
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
||||
var pHash = parseHash(p.hash);
|
||||
var parsedHash = parseHash(parsed.hash);
|
||||
var pHash = p.hashData;
|
||||
var parsedHash = parsed.hashData;
|
||||
if (!parsedHash || !pHash) { return; }
|
||||
|
||||
// We don't have stronger/weaker versions of files or users
|
||||
if (pHash.type !== 'pad' && parsedHash.type !== 'pad') { return; }
|
||||
|
||||
if (pHash.version !== parsedHash.version) { return; }
|
||||
if (pHash.channel !== parsedHash.channel) { return; }
|
||||
if (pHash.mode === 'edit' && parsedHash.mode === 'view') {
|
||||
|
@ -254,8 +317,7 @@ Version 2
|
|||
var parsed = Hash.parsePadUrl(href);
|
||||
if (!parsed || !parsed.hash) { return; }
|
||||
|
||||
parsed = Hash.parseHash(parsed.hash);
|
||||
|
||||
parsed = parsed.hashData;
|
||||
if (parsed.version === 0) {
|
||||
return parsed.channel;
|
||||
} else if (parsed.version !== 1 && parsed.version !== 2) {
|
||||
|
|
|
@ -35,8 +35,8 @@ define([
|
|||
};
|
||||
var realtime = createRealtime();
|
||||
|
||||
var hash = config.href ? common.parsePadUrl(config.href).hash : undefined;
|
||||
var secret = common.getSecrets(hash);
|
||||
var parsed = config.href ? common.parsePadUrl(config.href) : {};
|
||||
var secret = common.getSecrets(parsed.type, parsed.hash);
|
||||
var crypto = Crypto.createEncryptor(secret.keys);
|
||||
|
||||
var to = window.setTimeout(function () {
|
||||
|
|
|
@ -22,7 +22,8 @@ define([
|
|||
};
|
||||
|
||||
var makeConfig = function (hash) {
|
||||
var secret = Cryptpad.getSecrets(hash);
|
||||
// We can't use cryptget with a file or a user so we can use 'pad' as hash type
|
||||
var secret = Cryptpad.getSecrets('pad', hash);
|
||||
if (!secret.keys) { secret.keys = secret.key; } // support old hashses
|
||||
var config = {
|
||||
websocketURL: Cryptpad.getWebsocketURL(),
|
||||
|
|
|
@ -75,10 +75,10 @@ define([
|
|||
|
||||
// import hash utilities for export
|
||||
var createRandomHash = common.createRandomHash = Hash.createRandomHash;
|
||||
var parseTypeHash = common.parseTypeHash = Hash.parseTypeHash;
|
||||
var parsePadUrl = common.parsePadUrl = Hash.parsePadUrl;
|
||||
var isNotStrongestStored = common.isNotStrongestStored = Hash.isNotStrongestStored;
|
||||
var hrefToHexChannelId = common.hrefToHexChannelId = Hash.hrefToHexChannelId;
|
||||
var parseHash = common.parseHash = Hash.parseHash;
|
||||
var getRelativeHref = common.getRelativeHref = Hash.getRelativeHref;
|
||||
common.getBlobPathFromHex = Hash.getBlobPathFromHex;
|
||||
|
||||
|
@ -286,12 +286,12 @@ define([
|
|||
if (!pad.title) {
|
||||
pad.title = common.getDefaultname(parsed);
|
||||
}
|
||||
return parsed.hash;
|
||||
return parsed.hashData;
|
||||
};
|
||||
// Migrate from legacy store (localStorage)
|
||||
var migrateRecentPads = common.migrateRecentPads = function (pads) {
|
||||
return pads.map(function (pad) {
|
||||
var hash;
|
||||
var parsedHash;
|
||||
if (Array.isArray(pad)) { // TODO DEPRECATE_F
|
||||
var href = pad[0];
|
||||
href.replace(/\#(.*)$/, function (a, h) {
|
||||
|
@ -305,8 +305,8 @@ define([
|
|||
ctime: pad[1],
|
||||
};
|
||||
} else if (pad && typeof(pad) === 'object') {
|
||||
hash = checkObjectData(pad);
|
||||
if (!hash || !common.parseHash(hash)) { return; }
|
||||
parsedHash = checkObjectData(pad);
|
||||
if (!parsedHash || !parsedHash.type) { return; }
|
||||
return pad;
|
||||
} else {
|
||||
console.error("[Cryptpad.migrateRecentPads] pad had unexpected value");
|
||||
|
@ -319,8 +319,8 @@ define([
|
|||
var checkRecentPads = common.checkRecentPads = function (pads) {
|
||||
pads.forEach(function (pad, i) {
|
||||
if (pad && typeof(pad) === 'object') {
|
||||
var hash = checkObjectData(pad);
|
||||
if (!hash || !common.parseHash(hash)) {
|
||||
var parsedHash = checkObjectData(pad);
|
||||
if (!parsedHash || !parsedHash.type) {
|
||||
console.error("[Cryptpad.checkRecentPads] pad had unexpected value", pad);
|
||||
getStore().removeData(i);
|
||||
return;
|
||||
|
@ -538,6 +538,7 @@ define([
|
|||
common.setPadTitle = function (name, cb) {
|
||||
var href = window.location.href;
|
||||
var parsed = parsePadUrl(href);
|
||||
if (!parsed.hash) { return; }
|
||||
href = getRelativeHref(href);
|
||||
// getRecentPads return the array from the drive, not a copy
|
||||
// We don't have to call "set..." at the end, everything is stored with listmap
|
||||
|
@ -558,8 +559,8 @@ define([
|
|||
|
||||
// Version 1 : we have up to 4 differents hash for 1 pad, keep the strongest :
|
||||
// Edit > Edit (present) > View > View (present)
|
||||
var pHash = parseHash(p.hash);
|
||||
var parsedHash = parseHash(parsed.hash);
|
||||
var pHash = p.hashData;
|
||||
var parsedHash = parsed.hashData;
|
||||
|
||||
if (!pHash) { return; } // We may have a corrupted pad in our storage, abort here in that case
|
||||
|
||||
|
@ -661,7 +662,8 @@ define([
|
|||
var userHash = localStorage && localStorage.User_hash;
|
||||
if (!userHash) { return null; }
|
||||
|
||||
var userChannel = common.parseHash(userHash).channel;
|
||||
var userParsedHash = common.parseTypeHash('drive', userHash);
|
||||
var userChannel = userParsedHash && userParsedHash.channel;
|
||||
if (!userChannel) { return null; }
|
||||
|
||||
var list = fo.getFiles([fo.FILES_DATA]).map(hrefToHexChannelId)
|
||||
|
@ -1273,20 +1275,21 @@ define([
|
|||
UI.Alertify.reset();
|
||||
|
||||
// Load the new pad when the hash has changed
|
||||
var oldHash = document.location.hash.slice(1);
|
||||
var oldHref = document.location.href;
|
||||
window.onhashchange = function () {
|
||||
var newHash = document.location.hash.slice(1);
|
||||
var parsedOld = parseHash(oldHash);
|
||||
var parsedNew = parseHash(newHash);
|
||||
var newHref = document.location.href;
|
||||
var parsedOld = parsePadUrl(oldHref).hashData;
|
||||
var parsedNew = parsePadUrl(newHref).hashData;
|
||||
if (parsedOld && parsedNew && (
|
||||
parsedOld.channel !== parsedNew.channel
|
||||
parsedOld.type !== parsedNew.type
|
||||
|| parsedOld.channel !== parsedNew.channel
|
||||
|| parsedOld.mode !== parsedNew.mode
|
||||
|| parsedOld.key !== parsedNew.key)) {
|
||||
document.location.reload();
|
||||
return;
|
||||
}
|
||||
if (parsedNew) {
|
||||
oldHash = newHash;
|
||||
oldHref = newHref;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ define([
|
|||
if (!hash) {
|
||||
throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...');
|
||||
}
|
||||
var secret = Cryptpad.getSecrets(hash);
|
||||
var secret = Cryptpad.getSecrets('drive', hash);
|
||||
var listmapConfig = {
|
||||
data: {},
|
||||
websocketURL: Cryptpad.getWebsocketURL(),
|
||||
|
|
|
@ -61,9 +61,7 @@ define([
|
|||
if (!isFile(element)) { return false; }
|
||||
var parsed = Cryptpad.parsePadUrl(element);
|
||||
if (!parsed) { return false; }
|
||||
var hash = parsed.hash;
|
||||
var pHash = Cryptpad.parseHash(hash);
|
||||
if (pHash && !pHash.mode) { return; }
|
||||
var pHash = parsed.hashData;
|
||||
return pHash && pHash.mode === 'view';
|
||||
};
|
||||
|
||||
|
|
|
@ -1103,7 +1103,7 @@ define([
|
|||
var type = Messages.type[hrefData.type] || hrefData.type;
|
||||
var $title = $('<span>', {'class': 'title listElement', title: data.title}).text(data.title);
|
||||
var $type = $('<span>', {'class': 'type listElement', title: type}).text(type);
|
||||
if (hrefData.hash && Cryptpad.parseHash(hrefData.hash) && Cryptpad.parseHash(hrefData.hash).mode === 'view') {
|
||||
if (hrefData.hashData && hrefData.hashData.mode === 'view') {
|
||||
$type.append(' (' + Messages.readonly+ ')');
|
||||
}
|
||||
var $adate = $('<span>', {'class': 'atime listElement', title: getDate(data.atime)}).text(getDate(data.atime));
|
||||
|
@ -2155,9 +2155,9 @@ define([
|
|||
var getReadOnlyUrl = APP.getRO = function (href) {
|
||||
if (!filesOp.isFile(href)) { return; }
|
||||
var i = href.indexOf('#') + 1;
|
||||
var hash = href.slice(i);
|
||||
var parsed = Cryptpad.parsePadUrl(href);;
|
||||
var base = href.slice(0, i);
|
||||
var hrefsecret = Cryptpad.getSecrets(hash);
|
||||
var hrefsecret = Cryptpad.getSecrets(parsed.type, parsed.hash);
|
||||
if (!hrefsecret.keys) { return; }
|
||||
var viewHash = Cryptpad.getViewHashFromKeys(hrefsecret.channel, hrefsecret.keys);
|
||||
return base + viewHash;
|
||||
|
@ -2608,7 +2608,7 @@ define([
|
|||
}
|
||||
|
||||
var hash = window.location.hash.slice(1) || Cryptpad.getUserHash() || localStorage.FS_hash;
|
||||
var secret = Cryptpad.getSecrets(hash);
|
||||
var secret = Cryptpad.getSecrets('drive', hash);
|
||||
var readOnly = APP.readOnly = secret.keys && !secret.keys.editKeyStr;
|
||||
|
||||
var listmapConfig = module.config = {
|
||||
|
|
Loading…
Reference in New Issue