Dedicated form share modal and auditor role

This commit is contained in:
yflory 2021-05-26 11:57:14 +02:00
parent 6f64d62698
commit 4a1de32994
6 changed files with 80 additions and 7 deletions

View File

@ -215,6 +215,17 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
});
return k ? Crypto.b64AddSlashes(k) : '';
};
var getAuditorKey = function (hashArr) {
var k;
// Check if we have a ownerKey for this pad
hashArr.some(function (data) {
if (/^auditor=/.test(data)) {
k = data.slice(8);
return true;
}
});
return k ? Crypto.b64AddSlashes(k) : '';
};
var getOwnerKey = function (hashArr) {
var k;
// Check if we have a ownerKey for this pad
@ -237,6 +248,7 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
parsed.present = options.indexOf('present') !== -1;
parsed.embed = options.indexOf('embed') !== -1;
parsed.versionHash = getVersionHash(options);
parsed.auditorKey = getAuditorKey(options);
parsed.newPadOpts = getNewPadOpts(options);
parsed.loginOpts = getLoginOpts(options);
parsed.ownerKey = getOwnerKey(options);
@ -278,6 +290,7 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
present: parsed.present,
ownerKey: parsed.ownerKey,
versionHash: parsed.versionHash,
auditorKey: parsed.auditorKey,
newPadOpts: parsed.newPadOpts,
loginOpts: parsed.loginOpts,
password: parsed.password
@ -304,6 +317,10 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
if (versionHash) {
hash += 'hash=' + Crypto.b64RemoveSlashes(versionHash) + '/';
}
var auditorKey = typeof(opts.auditorKey) !== "undefined" ? opts.auditorKey : parsed.auditorKey;
if (auditorKey) {
hash += 'auditor=' + Crypto.b64RemoveSlashes(auditorKey) + '/';
}
if (opts.newPadOpts) { hash += 'newpad=' + opts.newPadOpts + '/'; }
if (opts.loginOpts) { hash += 'login=' + opts.loginOpts + '/'; }
return hash;

View File

@ -494,7 +494,23 @@ define([
var parsed = Hash.parsePadUrl(pathname);
var canPresent = ['code', 'slide'].indexOf(parsed.type) !== -1;
var versionHash = hashes.viewHash && opts.versionHash;
var canBAR = parsed.type !== 'drive' && !versionHash;
var isForm = parsed.type === "form"; // && opts.auditorHash;
var canBAR = parsed.type !== 'drive' && !versionHash && !isForm;
var labelEdit = Messages.share_linkEdit;
var labelView = Messages.share_linkView;
var auditor;
if (isForm) {
Messages.share_formEdit = "Author"; // XXX
Messages.share_formView = "Participant"; // XXX
Messages.share_formAuditor = "Auditor"; // XXX
labelEdit = Messages.share_formEdit;
labelView = Messages.share_formView;
auditor = UI.createRadio('accessRights', 'cp-share-form', Messages.share_formAuditor, false, {
mark: {tabindex:1},
});
}
var burnAfterReading = (hashes.viewHash && canBAR) ?
UI.createRadio('accessRights', 'cp-share-bar', Messages.burnAfterReading_linkBurnAfterReading, false, {
@ -505,12 +521,13 @@ define([
h('label', Messages.share_linkAccess),
h('div.radio-group',[
UI.createRadio('accessRights', 'cp-share-editable-false',
Messages.share_linkView, true, { mark: {tabindex:1} }),
labelView, true, { mark: {tabindex:1} }),
canPresent ? UI.createRadio('accessRights', 'cp-share-present',
Messages.share_linkPresent, false, { mark: {tabindex:1} }) : undefined,
UI.createRadio('accessRights', 'cp-share-editable-true',
Messages.share_linkEdit, false, { mark: {tabindex:1} })]),
burnAfterReading
labelEdit, false, { mark: {tabindex:1} }),
auditor]),
burnAfterReading,
]);
// Burn after reading
@ -553,6 +570,7 @@ 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'));
var formAuditor = Util.isChecked($rights.find('#cp-share-form'));
if (versionHash) {
edit = false;
present = false;
@ -569,6 +587,9 @@ define([
}
var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash
: hashes.viewHash;
if (formAuditor && opts.auditorHash) {
hash = opts.auditorHash;
}
var href = burnAfterReading ? opts.burnAfterReadingUrl
: (origin + pathname + '#' + hash);
var parsed = Hash.parsePadUrl(href);
@ -594,6 +615,9 @@ define([
$rights.find('#cp-share-present').removeAttr('checked').attr('disabled', true);
$rights.find('#cp-share-editable-true').attr('checked', true);
}
if (isForm && !opts.auditorHash) {
$rights.find('#cp-share-form').removeAttr('checked').attr('disabled', true);
}
var getLink = function () {
return $rights.parent().find('#cp-share-link-preview');

View File

@ -553,11 +553,13 @@ MessengerUI, Messages, Pages) {
if (toolbar.isDeleted) {
return void UI.warn(Messages.deletedFromServer);
}
var privateData = config.metadataMgr.getPrivateData();
var title = (config.title && config.title.getTitle && config.title.getTitle())
|| (config.title && config.title.defaultName)
|| "";
Common.getSframeChannel().event('EV_SHARE_OPEN', {
title: title
title: title,
auditorHash: privateData.form_auditorHash
});
});

View File

@ -689,6 +689,20 @@ define([
// XXX fetch answers and
// * viewers ==> check if you've already answered and show form (new or edit)
// * editors ==> show schema and warn users if existing questions already have answers
if (priv.form_auditorKey) {
sframeChan.query("Q_FORM_FETCH_ANSWERS", {
channel: content.answers.channel,
validateKey: content.answers.validateKey,
publicKey: content.answers.publicKey,
privateKey: priv.form_auditorKey
}, function (err, obj) {
$body.addClass('cp-app-form-results');
renderResults(content, obj);
});
return;
}
if (APP.isEditor) {
sframeChan.query("Q_FORM_FETCH_ANSWERS", {
channel: content.answers.channel,

View File

@ -19,6 +19,13 @@ define([
var privateKey, publicKey;
var addData = function (meta, CryptPad, user, Utils) {
var keys = Utils.secret && Utils.secret.keys;
var parsed = Utils.Hash.parseTypeHash('pad', hash.slice(1));
if (parsed.auditorKey) {
meta.form_auditorKey = parsed.auditorKey;
meta.form_auditorHash = hash;
}
var secondary = keys && keys.secondaryKey;
if (!secondary) { return; }
var curvePair = Nacl.box.keyPair.fromSecretKey(Nacl.util.decodeUTF8(secondary).slice(0,32));
@ -27,10 +34,19 @@ define([
publicKey = meta.form_public = Nacl.util.encodeBase64(curvePair.publicKey);
privateKey = meta.form_private = Nacl.util.encodeBase64(curvePair.secretKey);
var auditorHash = Utils.Hash.getViewHashFromKeys({
version: 1,
channel: Utils.secret.channel,
keys: { viewKeyStr: Nacl.util.encodeBase64(keys.cryptKey) }
});
var parsed = Utils.Hash.parseTypeHash('pad', auditorHash);
meta.form_auditorHash = parsed.getHash({auditorKey: privateKey});
};
var addRpc = function (sframeChan, Cryptpad, Utils) {
sframeChan.on('Q_FORM_FETCH_ANSWERS', function (data, cb) {
var myKeys;
var myKeys = {};
var CPNetflux;
var network;
nThen(function (w) {
@ -48,7 +64,6 @@ define([
return true;
}
});
console.error(myKeys);
}));
Cryptpad.makeNetwork(w(function (err, nw) {
network = nw;

View File

@ -58,6 +58,7 @@ define([
hashes: data.hashes || priv.hashes,
common: common,
title: data.title,
auditorHash: data.auditorHash,
versionHash: data.versionHash,
friends: friends,
onClose: function () {