Add basic support for versioned link

pull/1/head
yflory 5 years ago
parent ba854e88c0
commit a798873230

@ -171,7 +171,7 @@ Version 1
return true;
}
});
return k;
return k ? Crypto.b64AddSlashes(k) : '';
};
var getOwnerKey = function (hashArr) {
var k;
@ -227,6 +227,9 @@ Version 1
if (opts.embed) { hash += 'embed/'; }
if (opts.present) { hash += 'present/'; }
var versionHash = typeof(opts.versionHash) !== "undefined" ? opts.versionHash : parsed.versionHash;
if (versionHash) {
hash += 'hash=' + Crypto.b64RemoveSlashes(versionHash) + '/';
}
return hash;
};

@ -329,26 +329,30 @@ define([
}
// warning about sharing links
var localStore = window.cryptpadStore;
var dismissButton = h('span.fa.fa-times');
var shareLinkWarning = h('div.alert.alert-warning.dismissable',
{ style: 'display: none;' },
[
h('span.cp-inline-alert-text', Messages.share_linkWarning),
dismissButton
]);
linkContent.push(shareLinkWarning);
localStore.get('hide-alert-shareLinkWarning', function (val) {
if (val === '1') { return; }
$(shareLinkWarning).show();
// when sharing a version hash, there is a similar warning and we want
// to avoid alert fatigue
if (!opts.versionHash) {
var localStore = window.cryptpadStore;
var dismissButton = h('span.fa.fa-times');
var shareLinkWarning = h('div.alert.alert-warning.dismissable',
{ style: 'display: none;' },
[
h('span.cp-inline-alert-text', Messages.share_linkWarning),
dismissButton
]);
linkContent.push(shareLinkWarning);
localStore.get('hide-alert-shareLinkWarning', function (val) {
if (val === '1') { return; }
$(shareLinkWarning).show();
$(dismissButton).on('click', function () {
localStore.put('hide-alert-shareLinkWarning', '1');
$(shareLinkWarning).remove();
});
$(dismissButton).on('click', function () {
localStore.put('hide-alert-shareLinkWarning', '1');
$(shareLinkWarning).remove();
});
});
}
// Burn after reading
if (opts.barAlert) { linkContent.push(opts.barAlert.cloneNode(true)); }
@ -460,7 +464,8 @@ define([
var pathname = opts.pathname;
var parsed = Hash.parsePadUrl(pathname);
var canPresent = ['code', 'slide'].indexOf(parsed.type) !== -1;
var canBAR = parsed.type !== 'drive';
var versionHash = hashes.viewHash && opts.versionHash;
var canBAR = parsed.type !== 'drive' && !versionHash;
var burnAfterReading = (hashes.viewHash && canBAR) ?
UI.createRadio('accessRights', 'cp-share-bar', Messages.burnAfterReading_linkBurnAfterReading, false, {
@ -519,6 +524,12 @@ define([
var embed = val.embed;
var present = val.present !== undefined ? val.present : Util.isChecked($rights.find('#cp-share-present'));
var burnAfterReading = Util.isChecked($rights.find('#cp-share-bar'));
if (versionHash) {
edit = false;
embed = false;
present = false;
burnAfterReading = false;
}
if (burnAfterReading && !opts.burnAfterReadingUrl) {
if (cb) { // Called from the contacts tab, "share" button
var barHref = origin + pathname + '#' + (hashes.viewHash || hashes.editHash);
@ -533,7 +544,7 @@ define([
var href = burnAfterReading ? opts.burnAfterReadingUrl
: (origin + pathname + '#' + hash);
var parsed = Hash.parsePadUrl(href);
return origin + parsed.getUrl({embed: embed, present: present});
return origin + parsed.getUrl({embed: embed, present: present, versionHash: versionHash});
};
opts.getEmbedValue = function () {
var url = opts.getLinkValue({
@ -543,7 +554,11 @@ define([
};
// disable edit share options if you don't have edit rights
if (!hashes.editHash) {
if (versionHash) {
$rights.find('#cp-share-editable-false').attr('checked', true);
$rights.find('#cp-share-present').removeAttr('checked').attr('disabled', true);
$rights.find('#cp-share-editable-true').removeAttr('checked').attr('disabled', true);
} else if (!hashes.editHash) {
$rights.find('#cp-share-editable-false').attr('checked', true);
$rights.find('#cp-share-editable-true').removeAttr('checked').attr('disabled', true);
} else if (!hashes.viewHash) {
@ -582,7 +597,9 @@ define([
// Set default values
common.getAttribute(['general', 'share'], function (err, val) {
val = val || {};
if (val.present && canPresent) {
if (versionHash) {
$rights.find('#cp-share-editable-false').prop('checked', true);
} else if (val.present && canPresent) {
$rights.find('#cp-share-editable-false').prop('checked', false);
$rights.find('#cp-share-editable-true').prop('checked', false);
$rights.find('#cp-share-present').prop('checked', true);
@ -671,9 +688,22 @@ define([
onHide: resetTab
}];
Modal.getModal(common, opts, tabs, function (err, modal) {
$(modal).find('.cp-bar').hide();
// Hide the burn-after-reading option by default
var $modal = $(modal);
$modal.find('.cp-bar').hide();
// Prepend the "rights" radio selection
$(modal).find('.alertify-tabs-titles').after($rights);
$modal.find('.alertify-tabs-titles').after($rights);
// Add the versionHash warning if needed
if (opts.versionHash) {
Messages.share_versionHash = "You're going to share the selected history version of the document in read-only mode. This will also <b>give view access</b> to the recipients."; // XXX
$rights.after(h('div.alert.alert-warning', [
h('i.fa.fa-history'),
UI.setHTML(h('span'), Messages.share_versionHash)
]));
}
// callback
cb(err, modal);
});

@ -1455,7 +1455,47 @@ define([
var channels = Store.channels = store.channels = {};
var getVersionHash = function (clientId, data) {
var validateKey;
var fakeNetflux = Hash.createChannelId();
nThen(function (waitFor) {
Store.getPadMetadata(null, {
channel: data.channel
}, function (md) {
// XXX not needed? we don't need to validate messages coming from history keeper
validateKey = md.validateKey;
});
}).nThen(function () {
Store.getHistoryRange(clientId, {
cpCount: 1,
channel: data.channel,
lastKnownHash: data.versionHash
}, function (obj) {
if (obj && obj.error) {
postMessage(clientId, "PAD_ERROR", obj.error);
return;
}
postMessage(clientId, "PAD_CONNECT", {
myID: fakeNetflux,
id: data.channel,
members: [fakeNetflux]
});
(obj.messages || []).forEach(function (data) {
postMessage(clientId, "PAD_MESSAGE", {
msg: data.msg,
user: fakeNetflux.slice(0,16), // fake history keeper to avoid validate
validateKey: validateKey
});
});
postMessage(clientId, "PAD_READY");
});
});
};
Store.joinPad = function (clientId, data) {
if (data.versionHash) {
return void getVersionHash(clientId, data);
}
var isNew = typeof channels[data.channel] === "undefined";
var channel = channels[data.channel] = channels[data.channel] || {
queue: [],
@ -2046,7 +2086,7 @@ define([
network.on('message', onMsg);
network.sendto(hk, JSON.stringify(['GET_HISTORY_RANGE', data.channel, {
from: data.lastKnownHash,
cpCount: 2,
cpCount: data.cpCount || 2,
txid: txid
}]));
};

@ -28,10 +28,13 @@ define([], function () {
var padRpc = conf.padRpc;
var sframeChan = conf.sframeChan;
var metadata= conf.metadata || {};
var versionHash = conf.versionHash;
var validateKey = metadata.validateKey;
var onConnect = conf.onConnect || function () { };
conf = undefined;
if (versionHash) { readOnly = true; }
padRpc.onReadyEvent.reg(function () {
sframeChan.event('EV_RT_READY', null);
});
@ -132,6 +135,7 @@ define([], function () {
padRpc.joinPad({
channel: channel || null,
readOnly: readOnly,
versionHash: versionHash,
metadata: metadata
});
};

@ -445,6 +445,7 @@ define([
feedbackAllowed: Utils.Feedback.state,
isPresent: parsed.hashData && parsed.hashData.present,
isEmbed: parsed.hashData && parsed.hashData.embed,
isHistoryVersion: parsed.hashData && parsed.hashData.versionHash,
accounts: {
donateURL: Cryptpad.donateURL,
upgradeURL: Cryptpad.upgradeURL
@ -1499,6 +1500,7 @@ define([
var cpNfCfg = {
sframeChan: sframeChan,
channel: secret.channel,
versionHash: parsed.hashData && parsed.hashData.versionHash,
padRpc: Cryptpad.padRpc,
validateKey: secret.keys.validateKey || undefined,
isNewHash: isNewHash,

Loading…
Cancel
Save