Add a pad room when the messenger is active in a pad

pull/1/head
yflory 6 years ago
parent 9e27f111cb
commit d4dd58e7df

@ -67,7 +67,7 @@ define([
update: [], update: [],
friend: [], friend: [],
unfriend: [], unfriend: [],
ready: [] event: []
}, },
range_requests: {}, range_requests: {},
}; };
@ -189,6 +189,8 @@ define([
var friend = getFriendFromChannel(id); var friend = getFriendFromChannel(id);
if (!friend) { return void cb('NO_SUCH_FRIEND'); } if (!friend) { return void cb('NO_SUCH_FRIEND'); }
friend.lastKnownHash = hash; friend.lastKnownHash = hash;
} else if (channel.isPadChat) {
// Nothing to do
} else { } else {
// TODO room // TODO room
return void cb('NOT_IMPLEMENTED'); return void cb('NOT_IMPLEMENTED');
@ -200,6 +202,7 @@ define([
var checkFriendData = function (curve, data) { var checkFriendData = function (curve, data) {
if (curve === proxy.curvePublic) { return; } if (curve === proxy.curvePublic) { return; }
var friend = getFriend(proxy, curve); var friend = getFriend(proxy, curve);
if (!friend) { return; }
var types = []; var types = [];
Object.keys(data).forEach(function (k) { Object.keys(data).forEach(function (k) {
if (friend[k] !== data[k]) { if (friend[k] !== data[k]) {
@ -215,17 +218,21 @@ define([
// Id message allows us to map a netfluxId with a public curve key // Id message allows us to map a netfluxId with a public curve key
var onIdMessage = function (msg, sender) { var onIdMessage = function (msg, sender) {
var channel; var channel, parsed0;
var isId = Object.keys(channels).some(function (chanId) {
if (channels[chanId].userList.indexOf(sender) !== -1) {
channel = channels[chanId];
return true;
}
});
if (!isId) { return; } try {
parsed0 = JSON.parse(msg);
channel = channels[parsed0.channel];
if (!channel) { return; }
if (channel.userList.indexOf(sender) === -1) { return; }
} catch (e) {
console.log(msg);
console.error(e);
// Not an ID message
return;
}
var decryptedMsg = channel.encryptor.decrypt(msg); var decryptedMsg = channel.encryptor.decrypt(parsed0.msg);
if (decryptedMsg === null) { if (decryptedMsg === null) {
return void console.error("Failed to decrypt message"); return void console.error("Failed to decrypt message");
@ -261,7 +268,11 @@ define([
var rMsg = [Types.mapIdAck, myData, channel.wc.myID]; var rMsg = [Types.mapIdAck, myData, channel.wc.myID];
var rMsgStr = JSON.stringify(rMsg); var rMsgStr = JSON.stringify(rMsg);
var cryptMsg = channel.encryptor.encrypt(rMsgStr); var cryptMsg = channel.encryptor.encrypt(rMsgStr);
network.sendto(sender, cryptMsg); var data = {
channel: channel.id,
msg: cryptMsg
};
network.sendto(sender, JSON.stringify(data));
}; };
var orderMessages = function (channel, new_messages /*, sig */) { var orderMessages = function (channel, new_messages /*, sig */) {
@ -295,15 +306,19 @@ define([
author: parsedMsg[1], author: parsedMsg[1],
time: parsedMsg[2], time: parsedMsg[2],
text: parsedMsg[3], text: parsedMsg[3],
channel: channel.id channel: channel.id,
name: parsedMsg[4] // Display name for multi-user rooms
// this makes debugging a whole lot easier // this makes debugging a whole lot easier
//curve: getCurveForChannel(channel.id), //curve: getCurveForChannel(channel.id),
}; };
channel.messages.push(res); channel.messages.push(res);
eachHandler('message', function (f) { if (!joining[channel.id]) {
f(res); // Channel is ready
}); eachHandler('message', function (f) {
f(res);
});
}
return true; return true;
} }
@ -414,7 +429,8 @@ define([
author: O.d[1], author: O.d[1],
time: O.d[2], time: O.d[2],
text: O.d[3], text: O.d[3],
channel: req.chanId channel: req.chanId,
name: O.d[4]
}; };
}); });
@ -516,7 +532,7 @@ define([
var getChannelMessagesSince = function (chan, data, keys) { var getChannelMessagesSince = function (chan, data, keys) {
console.log('Fetching [%s] messages since [%s]', chan.id, data.lastKnownHash || ''); console.log('Fetching [%s] messages since [%s]', chan.id, data.lastKnownHash || '');
var cfg = { var cfg = {
validateKey: keys.validateKey, validateKey: keys ? keys.validateKey : undefined,
owners: [proxy.edPublic, data.edPublic], owners: [proxy.edPublic, data.edPublic],
lastKnownHash: data.lastKnownHash lastKnownHash: data.lastKnownHash
}; };
@ -529,11 +545,12 @@ define([
var openChannel = function (data) { var openChannel = function (data) {
var keys = data.keys; var keys = data.keys;
var encryptor = Curve.createEncryptor(keys); var encryptor = data.encryptor || Curve.createEncryptor(keys);
network.join(data.channel).then(function (chan) { network.join(data.channel).then(function (chan) {
var channel = channels[data.channel] = { var channel = channels[data.channel] = {
id: data.channel, id: data.channel,
isFriendChat: data.isFriendChat, isFriendChat: data.isFriendChat,
isPadChat: data.isPadChat,
sending: false, sending: false,
encryptor: encryptor, encryptor: encryptor,
messages: [], messages: [],
@ -556,7 +573,11 @@ define([
var msg = [Types.mapId, myData, chan.myID]; var msg = [Types.mapId, myData, chan.myID];
var msgStr = JSON.stringify(msg); var msgStr = JSON.stringify(msg);
var cryptMsg = channel.encryptor.encrypt(msgStr); var cryptMsg = channel.encryptor.encrypt(msgStr);
network.sendto(peer, cryptMsg); var data = {
channel: channel.id,
msg: cryptMsg
};
network.sendto(peer, JSON.stringify(data));
}; };
chan.members.forEach(function (peer) { chan.members.forEach(function (peer) {
if (peer === Msg.hk) { return; } if (peer === Msg.hk) { return; }
@ -758,15 +779,16 @@ define([
// TODO send event chat ready // TODO send event chat ready
// Remove spinner in chatbox // Remove spinner in chatbox
ready = true; ready = true;
eachHandler('ready', function (f) { eachHandler('event', function (f) {
f(); f('READY');
}); });
}); });
}; };
init(); init();
var getRooms = function (curvePublic, cb) { var getRooms = function (data, cb) {
if (curvePublic) { if (data && data.curvePublic) {
var curvePublic = data.curvePublic;
// We need to get data about a new friend's room // We need to get data about a new friend's room
var friend = getFriend(proxy, curvePublic); var friend = getFriend(proxy, curvePublic);
if (!friend) { return void cb({error: 'NO_SUCH_FRIEND'}); } if (!friend) { return void cb({error: 'NO_SUCH_FRIEND'}); }
@ -777,7 +799,18 @@ define([
isFriendChat: true, isFriendChat: true,
name: friend.displayName, name: friend.displayName,
lastKnownHash: friend.lastKnownHash, lastKnownHash: friend.lastKnownHash,
curvePublic: friend.curvePublic curvePublic: friend.curvePublic,
messages: channel.messages
}]);
}
if (data && data.padChat) {
var pCChannel = getChannel(data.padChat);
if (!pCChannel) { return void cb({error: 'NO_SUCH_CHANNEL'}); }
return void cb([{
id: pCChannel.id,
isPadChat: true,
messages: pCChannel.messages
}]); }]);
} }
@ -798,7 +831,8 @@ define([
isFriendChat: r.isFriendChat, isFriendChat: r.isFriendChat,
name: name, name: name,
lastKnownHash: lastKnownHash, lastKnownHash: lastKnownHash,
curvePublic: curvePublic curvePublic: curvePublic,
messages: r.messages
}; };
}).filter(function (x) { return x; }); }).filter(function (x) { return x; });
cb(rooms); cb(rooms);
@ -814,7 +848,30 @@ define([
} else { } else {
// TODO room userlist in rooms... // TODO room userlist in rooms...
// (this is the static userlist, not the netflux one) // (this is the static userlist, not the netflux one)
} cb([]);
}
};
var openPadChat = function (data, cb) {
var channel = data.channel;
var keys = data.secret && data.secret.keys;
var cryptKey = keys.viewKeyStr ? Crypto.b64AddSlashes(keys.viewKeyStr) : data.secret.key;
var encryptor = Crypto.createEncryptor(cryptKey);
var chanData = {
encryptor: encryptor,
channel: data.channel,
isPadChat: true,
//lastKnownHash: friend.lastKnownHash,
//owners: [proxy.edPublic, friend.edPublic],
//isFriendChat: true
};
openChannel(chanData);
joining[channel] = function () {
eachHandler('event', function (f) {
f('PADCHAT_READY', channel);
});
};
cb();
}; };
messenger.execCommand = function (obj, cb) { messenger.execCommand = function (obj, cb) {
@ -829,6 +886,9 @@ define([
if (cmd === 'GET_USERLIST') { if (cmd === 'GET_USERLIST') {
return void getUserList(data, cb); return void getUserList(data, cb);
} }
if (cmd === 'OPEN_PAD_CHAT') {
return void openPadChat(data, cb);
}
}; };
Object.freeze(messenger); Object.freeze(messenger);

@ -1372,10 +1372,10 @@ define([
removedByMe: removedByMe removedByMe: removedByMe
}); });
}); });
messenger.on('ready', function () { messenger.on('event', function (ev, data) {
console.log('here');
sendMessengerEvent('CHAT_EVENT', { sendMessengerEvent('CHAT_EVENT', {
ev: 'READY' ev: ev,
data: data
}); });
}); });
}; };

@ -322,6 +322,8 @@ define([
if (!readOnly) { onLocal(); } if (!readOnly) { onLocal(); }
evOnReady.fire(newPad); evOnReady.fire(newPad);
common.openPadChat(onLocal);
UI.removeLoadingScreen(emitResize); UI.removeLoadingScreen(emitResize);
var privateDat = cpNfInner.metadataMgr.getPrivateData(); var privateDat = cpNfInner.metadataMgr.getPrivateData();

@ -776,11 +776,19 @@ define([
Cryptpad.messenger.setChannelHead(opt, cb); Cryptpad.messenger.setChannelHead(opt, cb);
}); });
sframeChan.on('Q_CHAT_OPENPADCHAT', function (data, cb) {
Cryptpad.messenger.execCommand({
cmd: 'OPEN_PAD_CHAT',
data: {
channel: data,
secret: secret
}
}, cb);
});
sframeChan.on('Q_CHAT_COMMAND', function (data, cb) { sframeChan.on('Q_CHAT_COMMAND', function (data, cb) {
Cryptpad.messenger.execCommand(data, cb); Cryptpad.messenger.execCommand(data, cb);
}); });
Cryptpad.messenger.onEvent.reg(function (data) { Cryptpad.messenger.onEvent.reg(function (data) {
console.log(data);
sframeChan.event('EV_CHAT_EVENT', data); sframeChan.event('EV_CHAT_EVENT', data);
}); });

@ -161,6 +161,19 @@ define([
}); });
}; };
// Chat
funcs.openPadChat = function (saveChanges) {
var md = JSON.parse(JSON.stringify(ctx.metadataMgr.getMetadata()));
var channel = md.chat || Hash.createChannelId();
if (!md.chat) {
md.chat = channel;
ctx.metadataMgr.updateMetadata(md);
setTimeout(saveChanges);
}
ctx.sframeChan.query('Q_CHAT_OPENPADCHAT', channel, function (err, obj) {
if (err || (obj && obj.error)) { console.error(err || (obj && obj.error)); }
});
};
// CodeMirror // CodeMirror
funcs.initCodeMirrorApp = callWithCommon(CodeMirror.create); funcs.initCodeMirrorApp = callWithCommon(CodeMirror.create);

@ -174,6 +174,7 @@ define({
// Chat // Chat
'EV_CHAT_EVENT': true, 'EV_CHAT_EVENT': true,
'Q_CHAT_COMMAND': true, 'Q_CHAT_COMMAND': true,
'Q_CHAT_OPENPADCHAT': true,
// Put one or more entries to the localStore which will go in localStorage. // Put one or more entries to the localStore which will go in localStorage.
'EV_LOCALSTORE_PUT': true, 'EV_LOCALSTORE_PUT': true,

@ -24,13 +24,19 @@ define([
var initChannel = function (state, info) { var initChannel = function (state, info) {
console.log('initializing channel for [%s]', info.id); console.log('initializing channel for [%s]', info.id);
var h, t;
if (Array.isArray(info.messages) && info.messages.length) {
h = info.messages[info.messages.length -1].sig;
t = info.messages[0].sig;
}
state.channels[info.id] = { state.channels[info.id] = {
messages: [], messages: info.messages || [],
name: info.name, name: info.name,
isFriendChat: info.isFriendChat, isFriendChat: info.isFriendChat,
isPadChat: info.isPadChat,
curvePublic: info.curvePublic, curvePublic: info.curvePublic,
HEAD: info.lastKnownHash, HEAD: h || info.lastKnownHash,
TAIL: null, TAIL: t || null,
}; };
}; };
@ -114,7 +120,7 @@ define([
var markup = {}; var markup = {};
markup.message = function (msg) { markup.message = function (msg) {
var curvePublic = msg.author; var curvePublic = msg.author;
var name = contactsData[msg.author].displayName; var name = msg.name || contactsData[msg.author].displayName;
return h('div.cp-app-contacts-message', { return h('div.cp-app-contacts-message', {
title: msg.time? new Date(msg.time).toLocaleString(): '?', title: msg.time? new Date(msg.time).toLocaleString(): '?',
'data-user': curvePublic, 'data-user': curvePublic,
@ -172,9 +178,13 @@ define([
return; return;
} }
history.forEach(function (msg) { history.forEach(function (msg, i) {
if (channel.exhausted) { return; } if (channel.exhausted) { return; }
if (msg.sig) { if (msg.sig) {
if (i === 0 && history.length > 1 && msg.sig === channel.TAIL) {
// First message is usually the lastKnownHash, ignore it
return;
}
if (msg.sig === channel.TAIL) { if (msg.sig === channel.TAIL) {
console.error('No more messages to fetch'); console.error('No more messages to fetch');
channel.exhausted = true; channel.exhausted = true;
@ -227,7 +237,7 @@ define([
var header = h('div.cp-app-contacts-header', [ var header = h('div.cp-app-contacts-header', [
avatar, avatar,
moreHistory, moreHistory,
removeHistory, data.isFriendChat ? removeHistory: undefined,
]); ]);
var messages = h('div.cp-app-contacts-messages'); var messages = h('div.cp-app-contacts-messages');
var input = h('textarea', { var input = h('textarea', {
@ -242,18 +252,16 @@ define([
]); ]);
var $avatar = $(avatar); var $avatar = $(avatar);
if (data.isFriendChat) { var friend = contactsData[curvePublic] || {};
var friend = contactsData[curvePublic]; if (friend.avatar && avatars[friend.avatar]) {
if (friend.avatar && avatars[friend.avatar]) { $avatar.append(avatars[friend.avatar]).append(rightCol);
$avatar.append(avatars[friend.avatar]).append(rightCol); } else {
} else { common.displayAvatar($avatar, friend.avatar, displayName, function ($img) {
common.displayAvatar($avatar, friend.avatar, friend.displayName, function ($img) { if (friend.avatar && $img) {
if (friend.avatar && $img) { avatars[friend.avatar] = $img[0].outerHTML;
avatars[friend.avatar] = $img[0].outerHTML; }
} $(rightCol).insertAfter($avatar);
$(rightCol).insertAfter($avatar); });
});
}
} }
var sending = false; var sending = false;
@ -368,7 +376,13 @@ define([
var $more = $chat.find('.cp-app-contacts-more-history'); var $more = $chat.find('.cp-app-contacts-more-history');
$more.click(); $more.click();
} }
return void $chat.show(); $chat.show();
if (channel.isPadChat) {
// Always scroll bottom for now in pad chat (no last known hash)
var $messagebox = $chat.find('.cp-app-contacts-messages');
$messagebox.scrollTop($messagebox.outerHeight());
}
return;
} else { } else {
console.error("Chat is missing... Please reload the page and try again."); console.error("Chat is missing... Please reload the page and try again.");
} }
@ -389,10 +403,14 @@ define([
var remove = h('span.cp-app-contacts-remove.fa.fa-user-times', { var remove = h('span.cp-app-contacts-remove.fa.fa-user-times', {
title: Messages.contacts_remove title: Messages.contacts_remove
}); });
var leaveRoom = h('span.cp-app-contacts-remove.fa.fa-sign-out', {
title: 'Leave this room' // XXX
});
var status = h('span.cp-app-contacts-status'); var status = h('span.cp-app-contacts-status');
var rightCol = h('span.cp-app-contacts-right-col', [ var rightCol = h('span.cp-app-contacts-right-col', [
h('span.cp-app-contacts-name', [room.name]), h('span.cp-app-contacts-name', [room.name]),
remove, room.isFriendChat ? remove : leaveRoom,
]); ]);
var friendData = room.isFriendChat ? userlist[0] : {}; var friendData = room.isFriendChat ? userlist[0] : {};
@ -406,23 +424,20 @@ define([
$(remove).click(function (e) { $(remove).click(function (e) {
e.stopPropagation(); e.stopPropagation();
var channel = state.channels[id]; var channel = state.channels[id];
if (channel.isFriendChat) { if (!channel.isFriendChat) { return; }
var curvePublic = channel.curvePublic; var curvePublic = channel.curvePublic;
var friend = contactsData[curvePublic] || friendData; var friend = contactsData[curvePublic] || friendData;
UI.confirm(Messages._getKey('contacts_confirmRemove', [ UI.confirm(Messages._getKey('contacts_confirmRemove', [
Util.fixHTML(friend.name) Util.fixHTML(friend.name)
]), function (yes) { ]), function (yes) {
if (!yes) { return; } if (!yes) { return; }
removeFriend(curvePublic, function (e) { removeFriend(curvePublic, function (e) {
if (e) { return void console.error(e); } if (e) { return void console.error(e); }
}); });
// TODO remove friend from userlist ui // TODO remove friend from userlist ui
// FIXME seems to trigger EJOINED from netflux-websocket (from server); // FIXME seems to trigger EJOINED from netflux-websocket (from server);
// (tried to join a channel in which you were already present) // (tried to join a channel in which you were already present)
}, undefined, true); }, undefined, true);
} else {
// TODO room remove room
}
}); });
if (friendData.avatar && avatars[friendData.avatar]) { if (friendData.avatar && avatars[friendData.avatar]) {
@ -457,6 +472,7 @@ define([
var channel = state.channels[chanId]; var channel = state.channels[chanId];
if (!channel) { if (!channel) {
console.log(message);
console.error('expected channel [%s] to be open', chanId); console.error('expected channel [%s] to be open', chanId);
return; return;
} }
@ -568,31 +584,40 @@ define([
execCommand('GET_USERLIST', {id: id}, function (e, list) { execCommand('GET_USERLIST', {id: id}, function (e, list) {
if (e || list.error) { return void console.error(e || list.error); } if (e || list.error) { return void console.error(e || list.error); }
if (!Array.isArray(list) || !list.length) { if (!room.isPadChat && (!Array.isArray(list) || !list.length)) {
return void console.error("Empty room!"); return void console.error("Empty room!");
} }
debug('userlist: ' + JSON.stringify(list)); debug('userlist: ' + JSON.stringify(list));
// This is a friend, the userlist is only one user. var friend = {};
var friend = list[0];
contactsData[friend.curvePublic] = friend; if (room.isFriendChat) {
// This is a friend, the userlist is only one user.
friend = list[0];
contactsData[friend.curvePublic] = friend;
}
var chatbox = markup.chatbox(id, room, friend.curvePublic); var chatbox = markup.chatbox(id, room, friend.curvePublic);
$(chatbox).hide(); $(chatbox).hide();
$messages.append(chatbox); $messages.append(chatbox);
var $messagebox = $(chatbox).find('.cp-app-contacts-messages');
room.messages.forEach(function (msg) {
var el_message = markup.message(msg);
$messagebox.append(el_message);
});
normalizeLabels($messagebox);
var roomEl = markup.room(id, room, list); var roomEl = markup.room(id, room, list);
$userlist.append(roomEl); $userlist.append(roomEl);
updateStatus(id); updateStatus(id);
}); });
// TODO room group chat
}; };
messenger.on('friend', function (curvePublic) { messenger.on('friend', function (curvePublic) {
debug('new friend: ', curvePublic); debug('new friend: ', curvePublic);
execCommand('GET_ROOMS', curvePublic, function (err, rooms) { execCommand('GET_ROOMS', {curvePublic: curvePublic}, function (err, rooms) {
if (err) { return void console.error(err); } if (err) { return void console.error(err); }
debug('rooms: ' + JSON.stringify(rooms)); debug('rooms: ' + JSON.stringify(rooms));
rooms.forEach(initializeRoom); rooms.forEach(initializeRoom);
@ -636,16 +661,34 @@ define([
$container.removeClass('cp-app-contacts-initializing'); $container.removeClass('cp-app-contacts-initializing');
}; };
var onPadChatReady = function (data) {
execCommand('GET_ROOMS', {padChat: data}, function (err, rooms) {
if (err) { return void console.error(err); }
if (!Array.isArray(rooms) || rooms.length !== 1) {
return void console.error('Invalid pad chat');
}
var room = rooms[0];
room.name = 'XXX Pad chat';
rooms.forEach(initializeRoom);
});
$container.removeClass('cp-app-contacts-initializing');
};
// Initialize chat when outer is ready (all channels loaded) // Initialize chat when outer is ready (all channels loaded)
// TODO: try again in outer if fail to load a channel // TODO: try again in outer if fail to load a channel
execCommand('IS_READY', null, function (err, yes) { execCommand('IS_READY', null, function (err, yes) {
if (yes) { onMessengerReady(); } if (yes) { onMessengerReady(); }
}); });
sframeChan.on('EV_CHAT_EVENT', function (data) { sframeChan.on('EV_CHAT_EVENT', function (obj) {
if (data.ev === 'READY') { if (obj.ev === 'READY') {
onMessengerReady(); onMessengerReady();
return; return;
} }
if (obj.ev === 'PADCHAT_READY') {
onPadChatReady(obj.data);
return;
}
}); });
}; };

Loading…
Cancel
Save