|
|
@ -78,7 +78,7 @@ define([
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var AppConfig;
|
|
|
|
var AppConfig;
|
|
|
|
var Test;
|
|
|
|
var Test;
|
|
|
|
var password, newPadPassword;
|
|
|
|
var password, newPadPassword, newPadPasswordForce;
|
|
|
|
var initialPathInDrive;
|
|
|
|
var initialPathInDrive;
|
|
|
|
var burnAfterReading;
|
|
|
|
var burnAfterReading;
|
|
|
|
|
|
|
|
|
|
|
@ -221,8 +221,11 @@ define([
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e) { console.error(e); }
|
|
|
|
} catch (e) { console.error(e); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: Driveless mode should only work for existing pads, but we can't check that
|
|
|
|
|
|
|
|
// before creating the worker because we need the anon RPC to do so.
|
|
|
|
|
|
|
|
// We're only going to check if a hash exists in the URL or not.
|
|
|
|
Cryptpad.ready(waitFor(), {
|
|
|
|
Cryptpad.ready(waitFor(), {
|
|
|
|
noDrive: cfg.noDrive,
|
|
|
|
noDrive: cfg.noDrive && AppConfig.allowDrivelessMode && currentPad.hash,
|
|
|
|
driveEvents: cfg.driveEvents,
|
|
|
|
driveEvents: cfg.driveEvents,
|
|
|
|
cache: Boolean(cfg.cache),
|
|
|
|
cache: Boolean(cfg.cache),
|
|
|
|
currentPad: currentPad
|
|
|
|
currentPad: currentPad
|
|
|
@ -309,6 +312,7 @@ define([
|
|
|
|
newPadPassword = Crypto.decrypt(newPad.pw, uKey);
|
|
|
|
newPadPassword = Crypto.decrypt(newPad.pw, uKey);
|
|
|
|
} catch (e) { console.error(e); }
|
|
|
|
} catch (e) { console.error(e); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newPad.f) { newPadPasswordForce = 1; }
|
|
|
|
if (newPad.d) {
|
|
|
|
if (newPad.d) {
|
|
|
|
Cryptpad.fromFileData = newPad.d;
|
|
|
|
Cryptpad.fromFileData = newPad.d;
|
|
|
|
var _parsed1 = Utils.Hash.parsePadUrl(Cryptpad.fromFileData.href);
|
|
|
|
var _parsed1 = Utils.Hash.parsePadUrl(Cryptpad.fromFileData.href);
|
|
|
@ -316,6 +320,7 @@ define([
|
|
|
|
delete Cryptpad.fromFileData;
|
|
|
|
delete Cryptpad.fromFileData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e, parsed.hashData.newPadOpts);
|
|
|
|
console.error(e, parsed.hashData.newPadOpts);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -346,7 +351,7 @@ define([
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// We now need to check if there is a password and if we know the correct password.
|
|
|
|
// We now need to check if there is a password and if we know the correct password.
|
|
|
|
// We'll use getFileSize and isNewChannel to detect incorrect passwords.
|
|
|
|
// We'll use getFileSize and hasChannelHistory to detect incorrect passwords.
|
|
|
|
|
|
|
|
|
|
|
|
// First we'll get the password value from our drive (getPadAttribute), and we'll check
|
|
|
|
// First we'll get the password value from our drive (getPadAttribute), and we'll check
|
|
|
|
// if the channel is valid. If the pad is not stored in our drive, we'll test with an
|
|
|
|
// if the channel is valid. If the pad is not stored in our drive, we'll test with an
|
|
|
@ -394,15 +399,15 @@ define([
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (parsed.type === "file") {
|
|
|
|
if (parsed.type === "file") {
|
|
|
|
// `isNewChannel` doesn't work for files (not a channel)
|
|
|
|
// `hasChannelHistory` doesn't work for files (not a channel)
|
|
|
|
// `getFileSize` is not adapted to channels because of metadata
|
|
|
|
// `getFileSize` is not adapted to channels because of metadata
|
|
|
|
Cryptpad.getFileSize(currentPad.href, password, function (e, size) {
|
|
|
|
Cryptpad.getFileSize(currentPad.href, password, function (e, size) {
|
|
|
|
next(e, size === 0);
|
|
|
|
next(e, size === 0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Not a file, so we can use `isNewChannel`
|
|
|
|
// Not a file, so we can use `hasChannelHistory`
|
|
|
|
Cryptpad.isNewChannel(currentPad.href, password, next);
|
|
|
|
Cryptpad.hasChannelHistory(currentPad.href, password, next);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
sframeChan.event("EV_PAD_PASSWORD", cfg);
|
|
|
|
sframeChan.event("EV_PAD_PASSWORD", cfg);
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -464,19 +469,32 @@ define([
|
|
|
|
currentPad.href = parsed.getUrl(opts);
|
|
|
|
currentPad.href = parsed.getUrl(opts);
|
|
|
|
currentPad.hash = parsed.hashData && parsed.hashData.getHash(opts);
|
|
|
|
currentPad.hash = parsed.hashData && parsed.hashData.getHash(opts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Cryptpad.getPadAttribute('title', w(function (err, data) {
|
|
|
|
Cryptpad.getPadAttribute('channel', w(function (err, data) {
|
|
|
|
stored = (!err && typeof (data) === "string");
|
|
|
|
stored = (!err && typeof (data) === "string");
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
Cryptpad.getPadAttribute('password', w(function (err, val) {
|
|
|
|
Cryptpad.getPadAttribute('password', w(function (err, val) {
|
|
|
|
password = val;
|
|
|
|
password = val;
|
|
|
|
}), parsed.getUrl());
|
|
|
|
}), parsed.getUrl());
|
|
|
|
}).nThen(function (w) {
|
|
|
|
}).nThen(function (w) {
|
|
|
|
|
|
|
|
// If we've already tested this password and this is a redirect, force
|
|
|
|
|
|
|
|
if (typeof(newPadPassword) !== "undefined" && newPadPasswordForce) {
|
|
|
|
|
|
|
|
password = newPadPassword;
|
|
|
|
|
|
|
|
return void todo();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the pad is not stored and we have a newPadPassword, it probably
|
|
|
|
|
|
|
|
// comes from a notification: password prompt pre-filled
|
|
|
|
if (!password && !stored && newPadPassword) {
|
|
|
|
if (!password && !stored && newPadPassword) {
|
|
|
|
passwordCfg.value = newPadPassword;
|
|
|
|
passwordCfg.value = newPadPassword;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Pad not stored && password required: always ask for the password
|
|
|
|
|
|
|
|
if (!stored && parsed.hashData.password && !newPadPasswordForce) {
|
|
|
|
|
|
|
|
return void askPassword(true, passwordCfg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (parsed.type === "file") {
|
|
|
|
if (parsed.type === "file") {
|
|
|
|
// `isNewChannel` doesn't work for files (not a channel)
|
|
|
|
// `hasChannelHistory` doesn't work for files (not a channel)
|
|
|
|
// `getFileSize` is not adapted to channels because of metadata
|
|
|
|
// `getFileSize` is not adapted to channels because of metadata
|
|
|
|
Cryptpad.getFileSize(currentPad.href, password, w(function (e, size) {
|
|
|
|
Cryptpad.getFileSize(currentPad.href, password, w(function (e, size) {
|
|
|
|
if (size !== 0) { return void todo(); }
|
|
|
|
if (size !== 0) { return void todo(); }
|
|
|
@ -485,8 +503,8 @@ define([
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Not a file, so we can use `isNewChannel`
|
|
|
|
// Not a file, so we can use `hasChannelHistory`
|
|
|
|
Cryptpad.isNewChannel(currentPad.href, password, w(function(e, isNew) {
|
|
|
|
Cryptpad.hasChannelHistory(currentPad.href, password, w(function(e, isNew) {
|
|
|
|
if (isNew && expire && expire < (+new Date())) {
|
|
|
|
if (isNew && expire && expire < (+new Date())) {
|
|
|
|
sframeChan.event("EV_EXPIRED_ERROR");
|
|
|
|
sframeChan.event("EV_EXPIRED_ERROR");
|
|
|
|
waitFor.abort();
|
|
|
|
waitFor.abort();
|
|
|
@ -500,10 +518,6 @@ define([
|
|
|
|
waitFor.abort();
|
|
|
|
waitFor.abort();
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!stored && !parsed.hashData.password) {
|
|
|
|
|
|
|
|
// We've received a link without /p/ and it doesn't work without a password: abort
|
|
|
|
|
|
|
|
return void todo();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrong password or deleted file?
|
|
|
|
// Wrong password or deleted file?
|
|
|
|
askPassword(true, passwordCfg);
|
|
|
|
askPassword(true, passwordCfg);
|
|
|
|
}));
|
|
|
|
}));
|
|
|
@ -537,8 +551,7 @@ define([
|
|
|
|
|
|
|
|
|
|
|
|
if (realtime) {
|
|
|
|
if (realtime) {
|
|
|
|
// TODO we probably don't need to check again for password-protected pads
|
|
|
|
// TODO we probably don't need to check again for password-protected pads
|
|
|
|
// (we use isNewChannel to test the password...)
|
|
|
|
Cryptpad.hasChannelHistory(currentPad.href, password, waitFor(function (e, isNew) {
|
|
|
|
Cryptpad.isNewChannel(currentPad.href, password, waitFor(function (e, isNew) {
|
|
|
|
|
|
|
|
if (e) { return console.error(e); }
|
|
|
|
if (e) { return console.error(e); }
|
|
|
|
isNewFile = Boolean(isNew);
|
|
|
|
isNewFile = Boolean(isNew);
|
|
|
|
}));
|
|
|
|
}));
|
|
|
@ -604,6 +617,7 @@ define([
|
|
|
|
feedbackAllowed: Utils.Feedback.state,
|
|
|
|
feedbackAllowed: Utils.Feedback.state,
|
|
|
|
isPresent: parsed.hashData && parsed.hashData.present,
|
|
|
|
isPresent: parsed.hashData && parsed.hashData.present,
|
|
|
|
isEmbed: parsed.hashData && parsed.hashData.embed,
|
|
|
|
isEmbed: parsed.hashData && parsed.hashData.embed,
|
|
|
|
|
|
|
|
oldVersionHash: parsed.hashData && parsed.hashData.version < 2, // password
|
|
|
|
isHistoryVersion: parsed.hashData && parsed.hashData.versionHash,
|
|
|
|
isHistoryVersion: parsed.hashData && parsed.hashData.versionHash,
|
|
|
|
notifications: notifs,
|
|
|
|
notifications: notifs,
|
|
|
|
accounts: {
|
|
|
|
accounts: {
|
|
|
@ -1404,6 +1418,7 @@ define([
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config.data = {
|
|
|
|
config.data = {
|
|
|
|
app: parsed.type,
|
|
|
|
app: parsed.type,
|
|
|
|
|
|
|
|
channel: secret.channel,
|
|
|
|
hashes: hashes,
|
|
|
|
hashes: hashes,
|
|
|
|
password: password,
|
|
|
|
password: password,
|
|
|
|
isTemplate: isTemplate,
|
|
|
|
isTemplate: isTemplate,
|
|
|
@ -1669,6 +1684,45 @@ define([
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sframeChan.on('Q_PASSWORD_CHECK', function (pw, cb) {
|
|
|
|
|
|
|
|
Cryptpad.isNewChannel(currentPad.href, pw, function (e, isNew) {
|
|
|
|
|
|
|
|
if (isNew === false) {
|
|
|
|
|
|
|
|
var channel = Utils.Hash.hrefToHexChannelId(currentPad.href, pw);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nThen(function (w) {
|
|
|
|
|
|
|
|
// If the pad is stored, update its data
|
|
|
|
|
|
|
|
var _secret = Utils.Hash.getSecrets(parsed.type, parsed.hash, pw);
|
|
|
|
|
|
|
|
var chan = _secret.channel;
|
|
|
|
|
|
|
|
var editH = Utils.Hash.getEditHashFromKeys(_secret);
|
|
|
|
|
|
|
|
var viewH = Utils.Hash.getViewHashFromKeys(_secret);
|
|
|
|
|
|
|
|
var href = Utils.Hash.hashToHref(editH, parsed.type);
|
|
|
|
|
|
|
|
var roHref = Utils.Hash.hashToHref(viewH, parsed.type);
|
|
|
|
|
|
|
|
Cryptpad.setPadAttribute('password', password, w(), parsed.getUrl());
|
|
|
|
|
|
|
|
Cryptpad.setPadAttribute('channel', chan, w(), parsed.getUrl());
|
|
|
|
|
|
|
|
Cryptpad.setPadAttribute('href', href, w(), parsed.getUrl());
|
|
|
|
|
|
|
|
Cryptpad.setPadAttribute('roHref', roHref, w(), parsed.getUrl());
|
|
|
|
|
|
|
|
}).nThen(function () {
|
|
|
|
|
|
|
|
// Get redirect URL
|
|
|
|
|
|
|
|
var uHash = Utils.LocalStore.getUserHash();
|
|
|
|
|
|
|
|
var uSecret = Utils.Hash.getSecrets('drive', uHash);
|
|
|
|
|
|
|
|
var uKey = uSecret.keys.cryptKey;
|
|
|
|
|
|
|
|
var url = Utils.Hash.getNewPadURL(currentPad.href, {
|
|
|
|
|
|
|
|
pw: Crypto.encrypt(pw, uKey),
|
|
|
|
|
|
|
|
f: 1
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// redirect
|
|
|
|
|
|
|
|
window.location.href = url;
|
|
|
|
|
|
|
|
document.location.reload();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cb({
|
|
|
|
|
|
|
|
error: e
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (cfg.messaging) {
|
|
|
|
if (cfg.messaging) {
|
|
|
|
sframeChan.on('Q_CHAT_OPENPADCHAT', function (data, cb) {
|
|
|
|
sframeChan.on('Q_CHAT_OPENPADCHAT', function (data, cb) {
|
|
|
|
Cryptpad.universal.execCommand({
|
|
|
|
Cryptpad.universal.execCommand({
|
|
|
|