git-webserver
Version:
Web Server Integrated GIT Version Control System
753 lines (752 loc) • 34.5 kB
JavaScript
/**
* User Validation based on URL filter
* @param {object} route Express Route object
* @param {JSON} config Master configuration JSON
*/
exports.userValidation = function (route, config) {
var gitAction = require("./gitAction");
var validate = require("./validation");
//Retrive/update loged in user privilage
route.all("*", function (req, res, next) {
if (validate().loginValidation(req, res, config)) {
var accessCntrl = require("../dbSchema/accessCntrl");
accessCntrl.accessCntrlGetAccessPermission(req, res, config, next);
} else {
next();
}
});
//Login verification for user data
route.all("/user*", function (req, res, next) {
if (validate().loginValidation(req, res, config)) {
next();
} else {
unAuthorisedRequest(config, res);
}
});
//Git login verification
//flag to check the request is from GIT-SCM
var gitRequest = false;
route.all(config.gitURL + "/:repoName.git*", function (req, res, next) {
if (req.params.repoName) {
if ("gzip" === req.headers["accept-encoding"] &&
"git/" === req.headers["user-agent"].substring(0, 4)) {
gitRequest = true;
gitAction.checkAuth(req, res, next, config);
} else {
res.redirect(config.gitURL + "/" + req.params.repoName);
}
} else {
res.status(401);
res.send();
}
});
//user login verification
route.all(config.gitURL + "/:repoName*", function (req, res, next) {
if (!gitRequest) {
if (validate().loginValidation(req, res, config)) {
next(); //TODO : Futher Validation and mapping
} else {
unAuthorisedRequest(config, res);
}
} else {
next(); //If it's a gitRequest Call the URL pattern match skips
}
});
//Git/Web Access Control
route.all(config.gitURL + "/:repoName*", function (req, res, next) {
if (req.params.repoName) {
var data = {
authorised: false,
owner: false, //Has access to repository settings
private: false,
userList: [{
userName: "",
readOnly: true
}],
readOnly: true
};
config.repoAccess = data;
next(); //TODO : Access Control
} else {
if (gitRequest) {
res.status(403);
res.send();
} else {
res.redirect("/");
}
}
});
return route;
};
/**
* Handle the static file like CSS,JS,etc...
* @param {object} route Express Route object
* @param {JSON} config Master configuration JSON
*/
exports.staticFile = function (route, config) {
route.get("/bootstrap.css", function (req, res) {
res.sendFile(config.dirname + "/public/css/bootstrap.min.css");
});
route.get("/fontawesome.css", function (req, res) {
res.sendFile(config.dirname + "/public/css/fontawesome.css");
});
route.get("/style.css", function (req, res) {
res.sendFile(config.dirname + "/public/css/style.min.css");
});
route.get("/jquery.js", function (req, res) {
res.sendFile(config.dirname + "/public/js/jquery-3.3.1.min.js");
});
route.get("/bootstrap.js", function (req, res) {
res.sendFile(config.dirname + "/public/js/bootstrap.min.js");
});
route.get("/bootbox.js", function (req, res) {
res.sendFile(config.dirname + "/public/js/bootbox.min.js");
});
route.get("/home.js", function (req, res) {
res.sendFile(config.dirname + "/public/js/home.js");
});
route.get("/favicon.ico", function (req, res) {
res.sendFile(config.dirname + "/public/img/favicon.ico");
});
route.get("/fonts/:fontFile", function (req, res) {
res.sendFile(config.dirname + "/public/fonts/" + req.params.fontFile);
});
return route;
};
/**
* Handles the Get request made to the server
* @param {object} route Express Route object
* @param {JSON} config Master configuration JSON
*/
exports.get = function (route, config) {
var gitAction = require("./gitAction");
var validate = require("./validation");
route.get("/", function (req, res) {
if (validate().loginValidation(req, res, config)) {
var gitRepo = require("../dbSchema/gitRepo");
gitRepo.gitRepoFindOne({
createdUser: req.session.userData.userNameDisplay
}, req, res, config, function (req, res, config, result) {
if (result) {
res.redirect(config.gitURL + "/" + result.repo + "/readme");
} else {
res.render("user/home", {
helpers: {
controlPannelPage: function () {
if (req.session.userAccess.Serverconfiguration) {
return "configuration";
} else if (req.session.userAccess.userControl) {
return "userAccess";
} else {
return "";
}
}
},
name: req.session.userData.name,
config: config,
userAccess: req.session.userAccess
});
}
});
} else {
var handlebarLayout = "public";
if (req.body.opti) {
handlebarLayout = false;
}
res.render("pages/login", {
layout: handlebarLayout,
config: config
});
}
});
route.get("/login", function (req, res) {
var validate = require("./validation");
if (validate().loginValidation(req, res, config)) {
res.redirect("/");
} else {
var handlebarLayout = "public";
if (req.body.opti) {
handlebarLayout = false;
}
res.render("pages/login", {
layout: handlebarLayout,
config: config
});
}
});
route.get("/signup", function (req, res) {
var validate = require("./validation");
if (validate().loginValidation(req, res, config)) {
res.redirect("/");
} else {
var handlebarLayout = "public";
if (req.body.opti) {
handlebarLayout = false;
}
res.render("pages/signup", {
layout: handlebarLayout,
config: config
});
}
});
route.get("/forgotPass", function (req, res) {
var validate = require("./validation");
if (validate().loginValidation(req, res, config)) {
res.redirect("/");
} else {
var handlebarLayout = "public";
if (req.body.opti) {
handlebarLayout = false;
}
res.render("pages/forgotPass", {
layout: handlebarLayout,
config: config
});
}
});
route.get(config.gitURL + "/:repoName/:repoPage", function (req, res) {
var validate = require("./validation");
if ((validate(req.params.repoName)
.isNotEmpty()
.boolResult()) &&
(validate(req.params.repoPage)
.isNotEmpty()
.boolResult())) {
var repoDetails = require("./branchesCommits");
var headDetails = repoDetails.generalDetails(config, req.params.repoName + ".git");
headDetails.head = validate(headDetails.head)
.isNotEmpty()
.boolResult() ? headDetails.head : "emptyRepository";
res.redirect(config.gitURL + "/" + req.params.repoName + "/" + req.params.repoPage + "/" + headDetails.head);
} else {
if (gLogging) console.log("Invalid Input rejected");
res.status(503);
res.send();
}
});
route.get(config.gitURL + "/:repoName/:repoPage/:repoBranch", function (req, res, next) {
if (!req.params.repoName.match(/.git/)) {
var validate = require("./validation");
if ((validate(req.params.repoName)
.isNotEmpty()
.boolResult()) &&
(validate(req.params.repoPage)
.isNotEmpty()
.boolResult())) {
var gitRepo = require("../dbSchema/gitRepo");
var page;
var details = {};
var repoDetails = require("./branchesCommits");
var branchDetails = repoDetails.generalDetails(config, req.params.repoName + ".git");
if (validate(req.params.repoBranch).isNotEmpty().isEquals("emptyRepository").boolResult() &&
validate(branchDetails.head).isNotEmpty().boolResult()) {
res.redirect(config.gitURL + "/" + req.params.repoName + "/" + req.params.repoPage + "/" + branchDetails.head);
} else {
req.params.repoBranch = req.params.repoBranch || branchDetails.head;
req.params.repoBranch = validate(req.params.repoBranch)
.isNotEmpty()
.boolResult() ? req.params.repoBranch : "emptyRepository";
details.branchDropDown = branchDetails.branches;
var notEmptyBranch = req.params.repoBranch != "emptyRepository";
switch (req.params.repoPage) {
case "files":
var isFiles = true;
if (notEmptyBranch) {
var document = require('html-element').document;
//Folder Hirecharch creation uling html doc element
var directoryStructureBuilder = function (data) {
var masterList = document.createElement('ul');
if (typeof directoryStructureBuilder.itemCounter == 'undefined') {
directoryStructureBuilder.itemCounter = 0;
masterList.setAttribute("class", "file-structure primary");
} else {
++directoryStructureBuilder.itemCounter;
masterList.setAttribute("style", "display: none;");
masterList.setAttribute("class", "file-structure");
}
masterList.setAttribute("data-fileitem", directoryStructureBuilder.itemCounter);
for (var i in data) {
var item = document.createElement('li');
var itemIcon = document.createElement("span");
if (Object.keys(data[i]).length > 2) {
itemIcon.setAttribute("class", "glyphicon glyphicon-folder-close");
var aitem = document.createElement('a');
aitem.appendChild(document.createTextNode(" " + data[i].name));
aitem.setAttribute("onclick", "$('[data-fileitem=" + (directoryStructureBuilder.itemCounter + 1) + "]').toggle();");
item.setAttribute("href", "javascript:;;;");
item.appendChild(itemIcon);
item.appendChild(aitem);
delete data[i].name;
delete data[i].type;
item.appendChild(new directoryStructureBuilder(data[i]));
} else {
if (data[i].type == "file") {
itemIcon.setAttribute("class", "glyphicon glyphicon-file");
} else {
itemIcon.setAttribute("class", "glyphicon glyphicon-folder-open");
}
item.appendChild(itemIcon);
item.appendChild(document.createTextNode(" " + data[i].name));
}
masterList.appendChild(item);
}
return masterList;
};
var folders = repoDetails.repoFileStructure(config, req.params.repoName + ".git", req.params.repoBranch);
if (Object.keys(folders).length) {
details.folders = new directoryStructureBuilder(folders).outerHTML;
} else {
details.folders = "<h3>Repository is empty</h3>";
}
} else {
details.folders = "<h3>Repository is empty</h3>";
}
page = "repo/files";
if (req.body.opti) {
res.render("partials/" + page, {
folders: details.folders
});
}
break;
case "branches":
var isBranches = true;
var branchesCommits = require("./branchesCommits");
details = branchesCommits.generalDetails(config, req.params.repoName + ".git");
var verify = false; //Check for empty repository
if (details.head) {
verify = true;
}
page = "repo/branches";
if (req.body.opti) {
res.render("partials/" + page, {
branchName: details.head,
branches: details.branches,
verify: verify
});
}
break;
case "pullrequest":
var isPullRequest = true;
page = "repo/pullRequest";
//TODO : Opti Load
break;
case "history":
var isHistory = true;
var branchHistory = require("./branchesCommits");
details.history = branchHistory.repoHistory(config, req.params.repoName);
page = "repo/history";
//TODO : Opti Load
break;
case "setting":
var isSetting = true;
page = "repo/setting";
if (req.body.opti) {
gitRepo.gitRepoFindOne({
repo: req.params.repoName
}, req, res, config, function (req, res, config, repoResult) {
var setting = false;
if (repoResult.createdUser.toUpperCase() == req.session.userData.userName) {
setting = true;
}
res.render("partials/" + page, {
branchName: details.head,
branches: details.branches,
setting: setting,
verify: verify
});
});
}
break;
case "readme":
var isReadME = true;
var markdown = require("markdown").markdown;
var readMe = gitAction.getRepoFile(config, req.params.repoName + ".git", req.params.repoBranch, "README.md");
if (validate(readMe).isNotEmpty().boolResult()) {
details.readmeHTML = markdown.toHTML(readMe);
} else {
details.readmeHTML = '<h3 class="text-center">No README.md file found in repository</h3>';
}
if (req.body.opti) {
res.render("partials/" + page, {
readmeHTML: details.readmeHTML
});
}
page = "repo/readme";
break;
default:
next();
break;
}
if (page) {
gitRepo.gitRepoFind({}, req, res, config, function (req, res, config, repoResult) {
var currentRepoDetails = {};
repoResult.forEach(function (repoDetails) {
if (repoDetails.repo == req.params.repoName) {
currentRepoDetails.descripton = repoDetails.description;
currentRepoDetails.url = repoDetails.url;
currentRepoDetails.private = repoDetails.private;
currentRepoDetails.repo = repoDetails.repo;
if (repoDetails.createdUser.toUpperCase() == req.session.userData.userName) {
currentRepoDetails.setting = true;
}
}
});
if (currentRepoDetails.url) {
res.render("repo/repoHome", { //Read Me
helpers: {
selectedRepo: function (repo) {
if (repo == req.params.repoName) return "list-group-item-info";
else return "";
},
activeTab: function () {
return page;
},
controlPannelPage: function () {
if (req.session.userAccess.Serverconfiguration) {
return "configuration";
} else if (req.session.userAccess.userControl) {
return "userAccess";
} else {
return "";
}
}
},
name: req.session.userData.name,
repo: repoResult,
descripton: currentRepoDetails.descripton,
url: currentRepoDetails.url,
private: currentRepoDetails.private,
repoName: currentRepoDetails.repo,
branchName: details.head,
branches: details.branches,
readmeHTML: details.readmeHTML,
config: config,
userAccess: req.session.userAccess,
setting: currentRepoDetails.setting,
verify: verify,
folders: details.folders,
history: details.history,
branchDropDown: details.branchDropDown,
activeBranch: req.params.repoBranch,
notEmptyBranch: notEmptyBranch,
isReadME: isReadME,
isFiles: isFiles,
isBranches: isBranches,
isHistory: isHistory,
isPullRequest: isPullRequest,
isSetting: isSetting
});
} else {
res.redirect("/");
}
});
}
}
} else {
if (gLogging) console.log("Invalid Input rejected");
res.status(503);
res.send();
}
} else {
next();
}
});
route.get("/user/setting/:settingPage", function (req, res, next) {
var page;
var loadSettingPage = function () {
res.render("user/setting", {
helpers: {
controlPannelPage: function () {
if (req.session.userAccess.Serverconfiguration) {
return "configuration";
} else if (req.session.userAccess.userControl) {
return "userAccess";
} else {
return "";
}
},
settingPage: function () {
return page;
}
},
name: req.session.userData.name,
config: config,
userAccess: req.session.userAccess
});
};
switch (req.params.settingPage) {
case "privacy":
page = "user/privacy";
loadSettingPage();
break;
case "security":
page = "user/security";
loadSettingPage();
break;
case "notification":
page = "user/notification";
loadSettingPage();
break;
default:
next();
break;
}
});
route.get("/user/createRepo", function (req, res) {
if (req.session.userAccess.createRepo) {
res.render("user/createRepo", {
helpers: {
controlPannelPage: function () {
if (req.session.userAccess.Serverconfiguration) {
return "configuration";
} else if (req.session.userAccess.userControl) {
return "userAccess";
} else {
return "";
}
}
},
name: req.session.userData.name,
config: config,
userAccess: req.session.userAccess
});
} else {
if (gLogging) console.log("Un-Authorized zone redirected");
res.redirect("/");
}
});
route.get("/user/controlPannel/:settingPage", function (req, res, next) {
if (req.session.userAccess.ServerControlPannel || req.session.userAccess.userControl) {
var page;
var loadControlPannelPage = function (req, res, config) {
res.render("user/controlPannel", {
helpers: {
getPage: function () {
return page;
},
controlPannelPage: function () {
if (req.session.userAccess.Serverconfiguration) {
return "configuration";
} else if (req.session.userAccess.userControl) {
return "userAccess";
} else {
return "";
}
},
currentUser: function (userName) {
if (userName == req.session.userData.userName) {
return "disabled";
}
}
},
name: req.session.userData.name,
config: config,
userAccess: req.session.userAccess,
user: config.userResult
});
};
switch (req.params.settingPage) {
case "configuration":
page = "controlPannel/configuration";
loadControlPannelPage(req, res, config);
break;
case "userAccess":
var user = require("../dbSchema/user");
user.getAllUsers(req, res, config, function (req, res, config) {
loadControlPannelPage(req, res, config);
});
page = "controlPannel/userAccess";
break;
default:
next();
break;
}
} else {
if (gLogging) console.log("Un-Authorized zone redirected");
res.redirect("/");
}
});
route.get("/user/:userPage", function (req, res, next) {
var page;
var loadUserControlPage = function () {
res.render(page, {
helpers: {
controlPannelPage: function () {
if (req.session.userAccess.Serverconfiguration) {
return "configuration";
} else if (req.session.userAccess.userControl) {
return "userAccess";
} else {
return "";
}
}
},
name: req.session.userData.name,
config: config,
userAccess: req.session.userAccess
});
};
switch (req.params.userPage) {
case "setting":
//Removed as the page will be redired to security page on empty page setting call
// page = "user/setting";
// loadUserControlPage();
res.redirect("/user/setting/security");
break;
case "profile":
page = "user/profile";
loadUserControlPage();
break;
default:
next();
break;
}
if (req.body.opti) {
//TODO : Front End Partial Load
}
});
route.get("/logout", function (req, res) {
if (req.cookies[config.advProperties.cookieChecksumName]) {
res.clearCookie(config.advProperties.sessionName);
res.clearCookie(config.advProperties.cookieChecksumName);
req.session.destroy(function (err) {
if (err) {
if (gLogging) console.log(err);
}
res.redirect("/");
});
} else {
res.redirect("/");
}
});
return route;
};
/**
* Handles the Post request made to the server
* @param {object} route Express Route object
* @param {JSON} config Master configuration JSON
*/
exports.post = function (route, config) {
var gitAction = require("./gitAction");
var validate = require("./validation");
route.post("/login", function (req, res) {
var userDB = require("../dbSchema/user");
var data = {
eMail: req.body.eMail, //or userName
password: req.body.password
};
userDB.loginUser(req, res, data, config, function (req, res, config) {
if (config.valid) {
req.session.regenerate(function (err) {
if (err) {
if (gLogging) console.log(err);
res.status(403);
res.send();
} else {
var accessData = {
ServerControlPannel: true,
userControl: true,
};
req.session.active = true;
req.session.access = accessData;
req.session.userData = {
name: config.result.name,
userName: config.result.userName,
userNameDisplay: config.result.userNameDisplay,
eMail: config.result.eMail,
};
validate().loginInitialisation(req, res, config);
res.redirect("/");
}
});
} else {
res.render("pages/login", {
layout: "public",
failure: true,
config: config
});
}
});
});
route.post("/signup", function (req, res) {
var userDB = require("../dbSchema/user");
var data = {
name: req.body.name,
userName: req.body.userName,
eMail: req.body.eMail,
password: req.body.password,
rPassword: req.body.rPassword,
appName: config.appName
};
var message = "";
if (data.password === data.rPassword) {
userDB.createUser(req, res, data, config, function (req, res, config) {
if (config.exist) {
message = '<div class="alert alert-warning" data-test="signupMessage" role="alert"><strong>User already exist!</strong></div>';
res.render("pages/signup", {
layout: "public",
message: message,
config: config
});
} else {
message = '<div class="alert alert-success" data-test="signupMessage" role="alert"><strong>User registration successful</strong></div>';
res.render("pages/login", {
layout: "public",
message: message,
config: config
});
var accessCntrl = require("../dbSchema/accessCntrl");
accessCntrl.createUser(req, data, config);
}
});
} else {
message = '<div class="alert alert-info" data-test="signupMessage" role="alert"><strong>Password Mis-Match</strong></div>';
res.render("pages/signup", {
layout: "public",
name: req.body.name,
userName: req.body.userName,
eMail: req.body.eMail,
message: message,
config: config
});
}
});
route.post("/forgot", function (req, res) {
res.render("page/forgotPass", {
layout: "public",
config: config
});
});
route.post("/user/createRepo", function (req, res) {
gitAction.gitInit(req, res, config);
});
route.post(config.gitURL + "/:repoName/setting/:repoBranch", function (req, res) {
if (req.body.repoName) {
gitAction.deleteRepo(req, res, config);
}
});
return route;
};
/**
* Handles Git related requests
* @param {object} route Express Route object
* @param {JSON} config Master configuration JSON
*/
exports.gitRequest = function (route, config) {
var gitAction = require("./gitAction");
route.get(config.gitURL + '/:repoName.git/info/refs', function (req, res) {
gitAction.getInfoRefs(req, res, config);
});
route.post(config.gitURL + '/:repoName.git/git-receive-pack', function (req, res) {
gitAction.postReceivePack(req, res, config);
});
route.post(config.gitURL + '/:repoName.git/git-upload-pack', function (req, res) {
gitAction.postUploadPack(req, res, config);
});
return route;
};
function unAuthorisedRequest(config, res) {
if (gLogging)
console.log("Un-Authorised access request redirected");
res.redirect("/");
}