diff options
Diffstat (limited to 'src/node/db/SecurityManager.js')
-rw-r--r-- | src/node/db/SecurityManager.js | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/node/db/SecurityManager.js b/src/node/db/SecurityManager.js new file mode 100644 index 00000000..a092453a --- /dev/null +++ b/src/node/db/SecurityManager.js @@ -0,0 +1,280 @@ +/** + * Controls the security of pad access + */ + +/* + * 2011 Peter 'Pita' Martischka (Primary Technology Ltd) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +var ERR = require("async-stacktrace"); +var db = require("./DB").db; +var async = require("async"); +var authorManager = require("./AuthorManager"); +var padManager = require("./PadManager"); +var sessionManager = require("./SessionManager"); +var settings = require("../utils/Settings") +var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; + +/** + * This function controlls the access to a pad, it checks if the user can access a pad. + * @param padID the pad the user wants to access + * @param sesssionID the session the user has (set via api) + * @param token the token of the author (randomly generated at client side, used for public pads) + * @param password the password the user has given to access this pad, can be null + * @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx}) + */ +exports.checkAccess = function (padID, sessionID, token, password, callback) +{ + var statusObject; + + // a valid session is required (api-only mode) + if(settings.requireSession) + { + // no sessionID, access is denied + if(!sessionID) + { + callback(null, {accessStatus: "deny"}); + return; + } + } + // a session is not required, so we'll check if it's a public pad + else + { + // it's not a group pad, means we can grant access + if(padID.indexOf("$") == -1) + { + //get author for this token + authorManager.getAuthor4Token(token, function(err, author) + { + if(ERR(err, callback)) return; + + // assume user has access + statusObject = {accessStatus: "grant", authorID: author}; + // user can't create pads + if(settings.editOnly) + { + // check if pad exists + padManager.doesPadExists(padID, function(err, exists) + { + if(ERR(err, callback)) return; + + // pad doesn't exist - user can't have access + if(!exists) statusObject.accessStatus = "deny"; + // grant or deny access, with author of token + callback(null, statusObject); + }); + } + // user may create new pads - no need to check anything + else + { + // grant access, with author of token + callback(null, statusObject); + } + }) + + //don't continue + return; + } + } + + var groupID = padID.split("$")[0]; + var padExists = false; + var validSession = false; + var sessionAuthor; + var tokenAuthor; + var isPublic; + var isPasswordProtected; + var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong + + async.series([ + //get basic informations from the database + function(callback) + { + async.parallel([ + //does pad exists + function(callback) + { + padManager.doesPadExists(padID, function(err, exists) + { + if(ERR(err, callback)) return; + padExists = exists; + callback(); + }); + }, + //get informations about this session + function(callback) + { + sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) + { + //skip session validation if the session doesn't exists + if(err && err.message == "sessionID does not exist") + { + callback(); + return; + } + + if(ERR(err, callback)) return; + + var now = Math.floor(new Date().getTime()/1000); + + //is it for this group? and is validUntil still ok? --> validSession + if(sessionInfo.groupID == groupID && sessionInfo.validUntil > now) + { + validSession = true; + } + + sessionAuthor = sessionInfo.authorID; + + callback(); + }); + }, + //get author for token + function(callback) + { + //get author for this token + authorManager.getAuthor4Token(token, function(err, author) + { + if(ERR(err, callback)) return; + tokenAuthor = author; + callback(); + }); + } + ], callback); + }, + //get more informations of this pad, if avaiable + function(callback) + { + //skip this if the pad doesn't exists + if(padExists == false) + { + callback(); + return; + } + + padManager.getPad(padID, function(err, pad) + { + if(ERR(err, callback)) return; + + //is it a public pad? + isPublic = pad.getPublicStatus(); + + //is it password protected? + isPasswordProtected = pad.isPasswordProtected(); + + //is password correct? + if(isPasswordProtected && password && pad.isCorrectPassword(password)) + { + passwordStatus = "correct"; + } + + callback(); + }); + }, + function(callback) + { + //- a valid session for this group is avaible AND pad exists + if(validSession && padExists) + { + //- the pad is not password protected + if(!isPasswordProtected) + { + //--> grant access + statusObject = {accessStatus: "grant", authorID: sessionAuthor}; + } + //- the pad is password protected and password is correct + else if(isPasswordProtected && passwordStatus == "correct") + { + //--> grant access + statusObject = {accessStatus: "grant", authorID: sessionAuthor}; + } + //- the pad is password protected but wrong password given + else if(isPasswordProtected && passwordStatus == "wrong") + { + //--> deny access, ask for new password and tell them that the password is wrong + statusObject = {accessStatus: "wrongPassword"}; + } + //- the pad is password protected but no password given + else if(isPasswordProtected && passwordStatus == "notGiven") + { + //--> ask for password + statusObject = {accessStatus: "needPassword"}; + } + else + { + throw new Error("Ops, something wrong happend"); + } + } + //- a valid session for this group avaible but pad doesn't exists + else if(validSession && !padExists) + { + //--> grant access + statusObject = {accessStatus: "grant", authorID: sessionAuthor}; + //--> deny access if user isn't allowed to create the pad + if(settings.editOnly) statusObject.accessStatus = "deny"; + } + // there is no valid session avaiable AND pad exists + else if(!validSession && padExists) + { + //-- its public and not password protected + if(isPublic && !isPasswordProtected) + { + //--> grant access, with author of token + statusObject = {accessStatus: "grant", authorID: tokenAuthor}; + } + //- its public and password protected and password is correct + else if(isPublic && isPasswordProtected && passwordStatus == "correct") + { + //--> grant access, with author of token + statusObject = {accessStatus: "grant", authorID: tokenAuthor}; + } + //- its public and the pad is password protected but wrong password given + else if(isPublic && isPasswordProtected && passwordStatus == "wrong") + { + //--> deny access, ask for new password and tell them that the password is wrong + statusObject = {accessStatus: "wrongPassword"}; + } + //- its public and the pad is password protected but no password given + else if(isPublic && isPasswordProtected && passwordStatus == "notGiven") + { + //--> ask for password + statusObject = {accessStatus: "needPassword"}; + } + //- its not public + else if(!isPublic) + { + //--> deny access + statusObject = {accessStatus: "deny"}; + } + else + { + throw new Error("Ops, something wrong happend"); + } + } + // there is no valid session avaiable AND pad doesn't exists + else + { + //--> deny access + statusObject = {accessStatus: "deny"}; + } + + callback(); + } + ], function(err) + { + if(ERR(err, callback)) return; + callback(null, statusObject); + }); +} |