git-webserver
Version:
Web Server Integrated GIT Version Control System
298 lines (293 loc) • 12.1 kB
JavaScript
/**
* User object cretaion function
* @param {JSON} user Git Authentication user details
*/
exports.User = function (user) {
this.username = user.username;
this.password = user.password;
};
/**
* Check the authentication of incomming request
* @param {object} req Request Object
* @param {object} res Response Object
* @param {function} next Callback function(req, res, config)
* @param {JSON} config Master Configuration JSON
*/
exports.checkAuth = function (req, res, next, config) {
var auth = require('http-auth');
var basic = auth.basic({
realm: "Web."
}, function (userId, password, callback) {
var data = {
eMail: userId,
password: password
};
var user = require("../dbSchema/user");
config.git = true;
user.loginUser(req, res, data, config, callback);
});
auth.connect(basic)(req, res, next);
};
/**
* Git clone request handling (Get method)
* @param {object} req Request Object
* @param {object} res Response Object
* @param {JSON} config Master Configuration JSON
*/
exports.getInfoRefs = function (req, res, config) {
var childProcess = require('child_process');
var spawn = childProcess.spawn;
var service = req.query.service;
var repoName = req.params.repoName;
if (gLogging) console.log('GET ' + service + ' / ' + repoName);
res.setHeader('Expires', new Date(Date.now() + 2592000000).toUTCString());
res.setHeader('Pragma', 'no-cache');
res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate');
res.setHeader('Content-Type', 'application/x-' + service + '-advertisement');
var packet = "# service=" + service + "\n";
var length = packet.length + 4;
var hex = "0123456789abcdef";
var prefix = hex.charAt(length >> 12 & 0xf);
prefix = prefix + hex.charAt(length >> 8 & 0xf);
prefix = prefix + hex.charAt(length >> 4 & 0xf);
prefix = prefix + hex.charAt(length & 0xf);
res.write(prefix + packet + '0000');
if (service == "git-upload-pack") {
service = "gitUpload";
} else {
service = "gitReceive";
}
var git;
if (process.platform === "win32") {
git = spawn(config.dirname + "/scripts/" + service + ".cmd", ['--stateless-rpc', '--advertise-refs', config.repoDir + "/" + repoName + ".git"]);
} else if (process.platform === "linux") {
git = spawn(config.dirname + "/scripts/" + service + ".sh", ["--stateless-rpc", "--advertise-refs", config.appRoutePath + "/" + config.repoDir + "/" + repoName + ".git"]);
} else {
res.status(503);
res.send();
}
git.stdout.pipe(res);
git.stderr.on('data', function (data) {
if (gLogging) console.log("stderr: " + data);
});
git.on('exit', function () {
res.end();
});
};
/**
* Git Push code handling (Post Method)
* @param {object} req Request Object
* @param {object} res Response Object
* @param {JSON} config Master Configuration JSON
*/
exports.postReceivePack = function (req, res, config) {
var childProcess = require('child_process');
var spawn = childProcess.spawn;
var repoName = req.params.repoName;
if (gLogging) console.log('POST git-receive-pack / ' + repoName);
res.setHeader('Expires', new Date(Date.now() + 2592000000).toUTCString());
res.setHeader('Pragma', 'no-cache');
res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate');
res.setHeader('Content-Type', 'application/x-git-receive-pack-result');
var git;
if (process.platform === "win32") {
git = spawn(config.dirname + "/scripts/" + "gitReceive.cmd", ['--stateless-rpc', config.repoDir + "/" + repoName + ".git"]);
} else if (process.platform === "linux") {
git = spawn(config.dirname + "/scripts/" + "gitReceive.sh", ["--stateless-rpc", config.appRoutePath + "/" + config.repoDir + "/" + repoName + ".git"]);
} else {
res.status(503);
res.send();
}
if (req.headers['content-encoding'] == 'gzip') {
req.pipe(zlib.createGunzip()).pipe(git.stdin);
} else {
req.pipe(git.stdin);
}
git.stdout.pipe(res);
git.stderr.on('data', function (data) {
if (gLogging) console.log("stderr: " + data);
});
git.on('exit', function () {
res.end();
exports.syncRepo(req, res, {
repo: repoName
}, config);
});
};
/**
* Git clone request handling (Post method)
* @param {object} req Request Object
* @param {object} res Response Object
* @param {JSON} config Master Configuration JSON
*/
exports.postUploadPack = function (req, res, config) {
var childProcess = require('child_process');
var spawn = childProcess.spawn;
var repoName = req.params.repoName;
if (gLogging) console.log('POST git-upload-pack / ' + repoName);
res.setHeader('Expires', new Date(Date.now() + 2592000000).toUTCString());
res.setHeader('Pragma', 'no-cache');
res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate');
res.setHeader('Content-Type', 'application/x-git-upload-pack-result');
var git;
//TODO : Remove Script Files
if (process.platform === "win32") {
git = spawn(config.dirname + "/scripts/" + "gitUpload.cmd", ['--stateless-rpc', config.repoDir + "/" + repoName + ".git"]);
} else if (process.platform === "linux") {
git = spawn(config.dirname + "/scripts/" + "gitUpload.sh", ["--stateless-rpc", config.appRoutePath + "/" + config.repoDir + "/" + repoName + ".git"]);
} else {
res.status(503);
res.send();
}
if (req.headers['content-encoding'] == 'gzip') {
req.pipe(zlib.createGunzip()).pipe(git.stdin);
} else {
req.pipe(git.stdin);
}
git.stdout.pipe(res);
git.stderr.on('data', function (data) {
if (gLogging) console.log("stderr: " + data);
});
};
/**
* Function to create and initialise Git repository in DB and File system
* @param {object} req Request Object
* @param {object} res Response Object
* @param {JSON} config Master Configuration JSON
*/
exports.gitInit = function (req, res, config) {
var validate = require("./validation");
if (validate(req.body.repo).isNotEmpty().boolResult()) {
var gitDB = require("../dbSchema/gitRepo");
var privateRepo = false;
if (req.body.type == "private") privateRepo = true;
var data = {
repo: req.body.repo,
createdUser: req.session.userData.userNameDisplay,
url: req.protocol + "://" + req.hostname + config.gitURL + "/" + req.body.repo + ".git",
private: privateRepo,
description: req.body.repoDescription
};
gitDB.gitRepoCreate(req, res, data, config, function (req, res, config) {
var fileSystem = require("fs");
if (!fileSystem.existsSync(config.repoDir + "/" + data.repo + ".git")) {
fileSystem.mkdirSync(config.repoDir + "/" + data.repo + ".git");
}
if (fileSystem.existsSync(config.repoDir + "/" + data.repo)) {
fileSystem.rmdirSync(config.repoDir + "/" + data.repo);
}
var simpleGit = require('simple-git')(config.repoDir + "/" + data.repo + ".git" + "/");
simpleGit.init(true, function (err) {
if (err) {
if (gLogging) {
console.log(err);
res.status(403);
res.send();
}
} else {
res.redirect(config.gitURL + "/" + config.gitRepo.repo + "/readme");
}
});
});
} else {
if (gLogging) console.log("Error : No Repo name received in Init");
res.status(403);
res.send();
}
};
/**
* Delete the Git repository from DB and File System
* @param {object} req Request Object
* @param {object} res Response Object
* @param {JSON} config Master Configuration JSON
*/
exports.deleteRepo = function (req, res, config) {
var validate = require("./validation");
if (validate(req.params.repoName).isNotEmpty().boolResult()) {
var gitDB = require("../dbSchema/gitRepo");
var data = {
repo: req.params.repoName
};
gitDB.gitRepoDelete(req, res, data, config, function () {
var fileSystem = require("fs");
var rimraf = require('rimraf');
if (fileSystem.existsSync(config.dirname + "/" + config.repoDir + "/" + data.repo)) {
if (gLogging) console.log("Clone repo deletion started");
rimraf(config.dirname + "/" + config.repoDir + "/" + data.repo, function (err) {
if (err) {
if (gLogging) console.log(err);
}
});
} else {
if (gLogging) console.log("Repo clone directory not found");
}
if (fileSystem.existsSync(config.appRoutePath + "/" + config.repoDir + "/" + data.repo + ".git")) {
if (gLogging) console.log("Repo deletion started");
rimraf(config.appRoutePath + "/" + config.repoDir + "/" + data.repo + ".git", function (err) {
if (err) {
if (gLogging) console.log(err);
} else {
if (gLogging) console.log("Repository deleted successfully");
}
});
} else {
if (gLogging) console.log("Repo directory not found");
}
//TODO : Repo deletion msg feedback
res.redirect("/");
//TODO : Error handling
});
} else {
if (gLogging) console.log("Error : No Repo name received in delete");
res.status(403);
res.send();
}
};
/**
* Delete the Git repository from DB and File System
* @param {object} req Request Object
* @param {object} res Response Object
* @param {JSON} config Master Configuration JSON
* @param {{repo:String,outputFile:String}} data Required data
* @param {object} next Execute at sucessful execution functuin(res,data,config)
*/
exports.syncRepo = function (req, res, data, config, next) {
var fullGitHistory = require('full-git-history'),
checkHistory = require('full-git-history/test/check-history');
data.outputFile = data.outputFile || "history.json";
fullGitHistory([config.repoDir + "/" + data.repo + ".git/", '-o', config.repoDir + "/" + data.repo + ".git/" + data.outputFile], function (error) {
if (error) {
if (gLogging) console.error("Cannot read history: " + error.message);
} else {
if (next) {
next(req, res, config);
}
}
});
};
/**
*
* @param {object} config Repository Name
* @param {String} repoName Repository Name
* @param {String} repoBranch Branch Name in that Repository
*/
exports.getRepoFile = function (config, repoName, repoBranch, repoFile) {
var execSync = require('child_process').execSync;
//TODO : Branch,repoName sanitisation
//Git Command to get the file structure of specific branch
var cmd = "git archive " + repoBranch + " " + repoFile;
//Recives the return string list and split it to array,removing the last empty entry
var fileText;
try {
fileText = execSync(cmd, {
encoding: 'utf8',
cwd: config.dirname + "/" + config.repoDir + "/" + repoName
});
} catch (err) {
if (gLogging) {
console.log(err);
console.log("Git file read Error");
}
}
return fileText;
};