Skip to content

Commit 49c7dde

Browse files
committed
Added private permission and clean up codes, solved potential race condition in realtime.js
1 parent 4732126 commit 49c7dde

6 files changed

Lines changed: 297 additions & 199 deletions

File tree

lib/note.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var db = require("./db.js");
1212
var logger = require("./logger.js");
1313

1414
//permission types
15-
permissionTypes = ["freely", "editable", "locked"];
15+
permissionTypes = ["freely", "editable", "locked", "private"];
1616

1717
// create a note model
1818
var model = mongoose.model('note', {
@@ -126,7 +126,11 @@ function findNote(id, callback) {
126126
});
127127
}
128128

129-
function newNote(id, permission, callback) {
129+
function newNote(id, owner, callback) {
130+
var permission = "freely";
131+
if (owner && owner != "null") {
132+
permission = "editable";
133+
}
130134
var note = new model({
131135
id: id,
132136
permission: permission,

lib/ot/editor-socketio-server.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ EditorSocketIOServer.prototype.addClient = function (socket) {
4343
socket.on('operation', function (revision, operation, selection) {
4444
operation = LZString.decompressFromUTF16(operation);
4545
operation = JSON.parse(operation);
46+
socket.origin = 'operation';
4647
self.mayWrite(socket, function (mayWrite) {
4748
if (!mayWrite) {
4849
console.log("User doesn't have the right to edit.");
@@ -59,6 +60,7 @@ EditorSocketIOServer.prototype.addClient = function (socket) {
5960
self.onGetOperations(socket, base, head);
6061
});
6162
socket.on('selection', function (obj) {
63+
socket.origin = 'selection';
6264
self.mayWrite(socket, function (mayWrite) {
6365
if (!mayWrite) {
6466
console.log("User doesn't have the right to edit.");
@@ -104,6 +106,7 @@ EditorSocketIOServer.prototype.onOperation = function (socket, revision, operati
104106
'operation', clientId, revision,
105107
wrappedPrime.wrapped.toJSON(), wrappedPrime.meta
106108
);
109+
//set document is dirty
107110
this.isDirty = true;
108111
} catch (exc) {
109112
logger.error(exc);

lib/realtime.js

Lines changed: 124 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -90,46 +90,10 @@ var updater = setInterval(function () {
9090
if (note.server.isDirty) {
9191
if (config.debug)
9292
logger.info("updater found dirty note: " + key);
93-
Note.findNote(note.id, function (err, _note) {
94-
if (err || !_note) return callback(err, null);
95-
//mongo update
96-
if (note.lastchangeuser && _note.lastchangeuser != note.lastchangeuser) {
97-
var lastchangeuser = note.lastchangeuser;
98-
var lastchangeuserprofile = null;
99-
User.findUser(lastchangeuser, function (err, user) {
100-
if (err) return callback(err, null);
101-
if (user && user.profile) {
102-
var profile = JSON.parse(user.profile);
103-
if (profile) {
104-
lastchangeuserprofile = {
105-
name: profile.displayName || profile.username,
106-
photo: User.parsePhotoByProfile(profile)
107-
}
108-
note.lastchangeuser = lastchangeuser;
109-
note.lastchangeuserprofile = lastchangeuserprofile;
110-
Note.updateLastChangeUser(_note, lastchangeuser, function (err, result) {
111-
if (err) return callback(err, null);
112-
});
113-
}
114-
}
115-
});
116-
} else {
117-
note.lastchangeuser = null;
118-
note.lastchangeuserprofile = null;
119-
Note.updateLastChangeUser(_note, null, function (err, result) {
120-
if (err) return callback(err, null);
121-
});
122-
}
123-
//postgres update
124-
var body = note.server.document;
125-
var title = Note.getNoteTitle(body);
126-
title = LZString.compressToBase64(title);
127-
body = LZString.compressToBase64(body);
128-
db.saveToDB(key, title, body, function (err, result) {
93+
updaterUpdateMongo(note, function(err, result) {
94+
if (err) return callback(err, null);
95+
updaterUpdatePostgres(note, function(err, result) {
12996
if (err) return callback(err, null);
130-
note.server.isDirty = false;
131-
note.updatetime = Date.now();
132-
emitCheck(note);
13397
callback(null, null);
13498
});
13599
});
@@ -140,6 +104,56 @@ var updater = setInterval(function () {
140104
if (err) return logger.error('updater error', err);
141105
});
142106
}, 1000);
107+
function updaterUpdateMongo(note, callback) {
108+
Note.findNote(note.id, function (err, _note) {
109+
if (err || !_note) return callback(err, null);
110+
if (note.lastchangeuser) {
111+
if (_note.lastchangeuser != note.lastchangeuser) {
112+
var lastchangeuser = note.lastchangeuser;
113+
var lastchangeuserprofile = null;
114+
User.findUser(lastchangeuser, function (err, user) {
115+
if (err) return callback(err, null);
116+
if (user && user.profile) {
117+
var profile = JSON.parse(user.profile);
118+
if (profile) {
119+
lastchangeuserprofile = {
120+
name: profile.displayName || profile.username,
121+
photo: User.parsePhotoByProfile(profile)
122+
}
123+
_note.lastchangeuser = lastchangeuser;
124+
note.lastchangeuserprofile = lastchangeuserprofile;
125+
Note.updateLastChangeUser(_note, lastchangeuser, function (err, result) {
126+
if (err) return callback(err, null);
127+
callback(null, null);
128+
});
129+
}
130+
}
131+
});
132+
}
133+
} else {
134+
_note.lastchangeuser = null;
135+
note.lastchangeuserprofile = null;
136+
Note.updateLastChangeUser(_note, null, function (err, result) {
137+
if (err) return callback(err, null);
138+
callback(null, null);
139+
});
140+
}
141+
});
142+
}
143+
function updaterUpdatePostgres(note, callback) {
144+
//postgres update
145+
var body = note.server.document;
146+
var title = Note.getNoteTitle(body);
147+
title = LZString.compressToBase64(title);
148+
body = LZString.compressToBase64(body);
149+
db.saveToDB(note.id, title, body, function (err, result) {
150+
if (err) return callback(err, null);
151+
note.server.isDirty = false;
152+
note.updatetime = Date.now();
153+
emitCheck(note);
154+
callback(null, null);
155+
});
156+
}
143157
//clean when user not in any rooms or user not in connected list
144158
var cleaner = setInterval(function () {
145159
async.each(Object.keys(users), function (key, callback) {
@@ -310,6 +324,19 @@ var disconnectSocketQueue = [];
310324

311325
function finishConnection(socket, note, user) {
312326
if (!socket || !note || !user) return;
327+
//check view permission
328+
if (note.permission == 'private') {
329+
if (socket.request.user && socket.request.user.logged_in && socket.request.user._id == note.owner) {
330+
//na
331+
} else {
332+
socket.emit('info', {
333+
code: 403
334+
});
335+
clearSocketQueue(connectionSocketQueue, socket);
336+
isConnectionBusy = false;
337+
return socket.disconnect(true);
338+
}
339+
}
313340
note.users[socket.id] = user;
314341
note.socks.push(socket);
315342
note.server.addClient(socket);
@@ -363,13 +390,9 @@ function startConnection(socket) {
363390

364391
var owner = data.rows[0].owner;
365392
var ownerprofile = null;
366-
var permission = "freely";
367-
if (owner && owner != "null") {
368-
permission = "editable";
369-
}
370393

371394
//find or new note
372-
Note.findOrNewNote(notename, permission, function (err, note) {
395+
Note.findOrNewNote(notename, owner, function (err, note) {
373396
if (err) {
374397
responseError(res, "404", "Not Found", "oops.");
375398
clearSocketQueue(connectionSocketQueue, socket);
@@ -399,41 +422,52 @@ function startConnection(socket) {
399422
updatetime: moment(updatetime).valueOf(),
400423
server: server
401424
};
402-
403-
if (lastchangeuser) {
404-
//find last change user profile if lastchangeuser exists
405-
User.findUser(lastchangeuser, function (err, user) {
406-
if (!err && user && user.profile) {
407-
var profile = JSON.parse(user.profile);
408-
if (profile) {
409-
lastchangeuserprofile = {
410-
name: profile.displayName || profile.username,
411-
photo: User.parsePhotoByProfile(profile)
425+
426+
async.parallel([
427+
function getlastchangeuser(callback) {
428+
if (lastchangeuser) {
429+
//find last change user profile if lastchangeuser exists
430+
User.findUser(lastchangeuser, function (err, user) {
431+
if (!err && user && user.profile) {
432+
var profile = JSON.parse(user.profile);
433+
if (profile) {
434+
lastchangeuserprofile = {
435+
name: profile.displayName || profile.username,
436+
photo: User.parsePhotoByProfile(profile)
437+
}
438+
notes[notename].lastchangeuserprofile = lastchangeuserprofile;
439+
}
412440
}
413-
notes[notename].lastchangeuserprofile = lastchangeuserprofile;
414-
}
441+
callback(null, null);
442+
});
443+
} else {
444+
callback(null, null);
415445
}
416-
});
417-
}
418-
419-
if (owner && owner != "null") {
420-
//find owner profile if owner exists
421-
User.findUser(owner, function (err, user) {
422-
if (!err && user && user.profile) {
423-
var profile = JSON.parse(user.profile);
424-
if (profile) {
425-
ownerprofile = {
426-
name: profile.displayName || profile.username,
427-
photo: User.parsePhotoByProfile(profile)
446+
},
447+
function getowner(callback) {
448+
if (owner && owner != "null") {
449+
//find owner profile if owner exists
450+
User.findUser(owner, function (err, user) {
451+
if (!err && user && user.profile) {
452+
var profile = JSON.parse(user.profile);
453+
if (profile) {
454+
ownerprofile = {
455+
name: profile.displayName || profile.username,
456+
photo: User.parsePhotoByProfile(profile)
457+
}
458+
notes[notename].ownerprofile = ownerprofile;
459+
}
428460
}
429-
notes[notename].ownerprofile = ownerprofile;
430-
}
461+
callback(null, null);
462+
});
463+
} else {
464+
callback(null, null);
431465
}
432-
finishConnection(socket, notes[notename], users[socket.id]);
433-
});
434-
} else {
466+
}
467+
], function(err, results){
468+
if (err) return;
435469
finishConnection(socket, notes[notename], users[socket.id]);
436-
}
470+
});
437471
});
438472
});
439473
} else {
@@ -545,14 +579,14 @@ function ifMayEdit(socket, callback) {
545579
if (!socket.request.user || !socket.request.user.logged_in)
546580
mayEdit = false;
547581
break;
548-
case "locked":
582+
case "locked": case "private":
549583
//only owner can change
550584
if (note.owner != socket.request.user._id)
551585
mayEdit = false;
552586
break;
553587
}
554588
//if user may edit and this note have owner (not anonymous usage)
555-
if (mayEdit && note.owner && note.owner != "null") {
589+
if (socket.origin == 'operation' && mayEdit && note.owner && note.owner != "null") {
556590
//save for the last change user id
557591
if (socket.request.user && socket.request.user.logged_in) {
558592
note.lastchangeuser = socket.request.user._id;
@@ -652,12 +686,22 @@ function connection(socket) {
652686
permission: permission
653687
};
654688
realtime.io.to(note.id).emit('permission', out);
655-
/*
656689
for (var i = 0, l = note.socks.length; i < l; i++) {
657690
var sock = note.socks[i];
658-
sock.emit('permission', out);
659-
};
660-
*/
691+
if (typeof sock !== 'undefined' && sock) {
692+
//check view permission
693+
if (permission == 'private') {
694+
if (sock.request.user && sock.request.user.logged_in && sock.request.user._id == note.owner) {
695+
//na
696+
} else {
697+
sock.emit('info', {
698+
code: 403
699+
});
700+
return sock.disconnect(true);
701+
}
702+
}
703+
}
704+
}
661705
});
662706
});
663707
}

0 commit comments

Comments
 (0)