host.js |
|
Generated by CoffeeScript 1.6.1 GOAL: A simple to setup and run, multi-tenant Git Server written in NodeJS. This was initially created to be used as a multi-tenant git server with powerful event triggers. |
var GitServer, async, fs, http, https, pushover,
_this = this,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
pushover = require('pushover');
http = require('http');
https = require('https');
async = require('async');
fs = require('fs');
GitServer = (function() {
|
Constructor function for each instance of GitServer Params
repos
Array
List of repositories
repoLocation
String
Location where the repo's are/will be stored
port
Int
Port on which to run this server.
certs
Object
Object of 'key' and 'cert' with the location of the certs (only used for HTTPS)
|
function GitServer(repos, logging, repoLocation, port, certs) {
var _this = this;
this.repos = repos != null ? repos : [];
this.logging = logging != null ? logging : false;
this.repoLocation = repoLocation != null ? repoLocation : '/tmp/repos';
this.port = port != null ? port : 7000;
this.certs = certs;
this.getRepo = function(repoName) {
return GitServer.prototype.getRepo.apply(_this, arguments);
};
this.getUser = function(username, password, repo) {
return GitServer.prototype.getUser.apply(_this, arguments);
};
this.checkTriggers = function(method, repo) {
return GitServer.prototype.checkTriggers.apply(_this, arguments);
};
this.onPush = function(push) {
return GitServer.prototype.onPush.apply(_this, arguments);
};
this.onFetch = function(fetch) {
return GitServer.prototype.onFetch.apply(_this, arguments);
};
this.makeReposIfNull = function(callback) {
return GitServer.prototype.makeReposIfNull.apply(_this, arguments);
};
this.gitListeners = function() {
return GitServer.prototype.gitListeners.apply(_this, arguments);
};
this.permissableMethod = function(username, password, method, repo, gitObject) {
return GitServer.prototype.permissableMethod.apply(_this, arguments);
};
this.processSecurity = function(gitObject, method, repo) {
return GitServer.prototype.processSecurity.apply(_this, arguments);
};
this.log = function() {
return GitServer.prototype.log.apply(_this, arguments);
};
this.createRepo = function(repo, callback) {
return GitServer.prototype.createRepo.apply(_this, arguments);
};
this.git = pushover(this.repoLocation, {
autoCreate: false
});
this.permMap = {
fetch: 'R',
push: 'W'
};
this.gitListeners();
this.makeReposIfNull(function() {
var message, red, reset;
if (_this.certs != null) {
_this.server = https.createServer(_this.certs, _this.git.handle.bind(_this.git));
} else {
red = '\033[31m';
reset = '\033[0m';
message = "WARNING: No SSL certs passed in. Running as HTTP and not HTTPS.\nBe careful, without HTTPS your user/pass will not be encrypted";
console.log(red + message + reset);
_this.server = http.createServer(_this.git.handle.bind(_this.git));
}
return _this.server.listen(_this.port, function() {
return _this.log('Server listening on ', _this.port, '\r');
});
});
}
|
Create a repo on the fly Params
repoName
Object
Name of the repo we are creating.
|
GitServer.prototype.createRepo = function(repo, callback) {
if ((repo.name == null) || (repo.anonRead == null)) {
this.log('Not enough details, need atleast .name and .anonRead');
false;
}
if (!this.getRepo(repo.name)) {
this.log('Creating repo', repo.name);
this.repos.push(repo);
return this.git.create(repo.name, callback);
} else {
return this.log('This repo already exists');
}
};
GitServer.prototype.log = function() {
var args, key, value;
args = (function() {
var _results;
_results = [];
for (key in arguments) {
value = arguments[key];
_results.push("" + value);
}
return _results;
}).apply(this, arguments);
if (this.logging) {
return console.log("LOG: ", args.join(' '));
}
};
|
Process the request and check for basic authentication. Params
gitObject
Object
Git object from the pushover module
method
String
Method we are getting security for ['fetch','push']
repo
Object
Repo object that we are doing this method on
|
GitServer.prototype.processSecurity = function(gitObject, method, repo) {
var auth, creds, plain_auth, req, res;
req = gitObject.request;
res = gitObject.response;
auth = req.headers['authorization'];
if (auth === void 0) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
return res.end('<html><body>Need some creds son</body></html>');
} else {
plain_auth = (new Buffer(auth.split(' ')[1], 'base64')).toString();
creds = plain_auth.split(':');
return this.permissableMethod(creds[0], creds[1], method, repo, gitObject);
}
};
|
Check to see if: return Username and password match return This user has permission to do this method on this repo Params
username
String
Username of the requesting user
password
String
Password of the requesting user
method
String
Method we are checking against ['fetch','push']
gitObject
Object
Git object from pushover module
|
GitServer.prototype.permissableMethod = function(username, password, method, repo, gitObject) {
var user, _ref;
this.log(username, 'is trying to', method, 'on repo:', repo.name, '...');
user = this.getUser(username, password, repo);
if (user === false) {
this.log(username, 'was rejected as this user doesnt exist, or password is wrong');
return gitObject.reject(500, 'Wrong username or password');
} else {
if (_ref = this.permMap[method], __indexOf.call(user.permissions, _ref) >= 0) {
this.log(username, 'Successfully did a', method, 'on', repo.name);
this.checkTriggers(method, repo);
return gitObject.accept();
} else {
this.log(username, 'was rejected, no permission to', method, 'on', repo.name);
return gitObject.reject(500, "You dont have these permissions");
}
}
};
GitServer.prototype.gitListeners = function() {
this.git.on('push', this.onPush);
this.git.on('fetch', this.onFetch);
return this.git.on('info', this.onFetch);
};
|
Checks all the passed in repo's to make sure they all have a real .git directory. |
GitServer.prototype.makeReposIfNull = function(callback) {
var repo, repoNames, _i, _len, _ref,
_this = this;
this.log('Making repos if they dont exist');
repoNames = [];
_ref = this.repos;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
repo = _ref[_i];
if ((repo.name != null) && (repo.anonRead != null) && (repo.users != null)) {
repoNames.push("" + repo.name + ".git");
} else {
console.log('Bad Repo', repo.name, 'is missing an attribute..');
}
}
return async.reject(repoNames, this.git.exists.bind(this.git), function(results) {
var _j, _len1;
if (results.length > 0) {
for (_j = 0, _len1 = results.length; _j < _len1; _j++) {
repo = results[_j];
console.log('Creating repo directory: ', repo);
}
return async.map(results, _this.git.create.bind(_this.git), callback);
} else {
return callback();
}
});
};
|
When the git fetch command is triggered, this is fired. Params
fetch
Object
Git object from pushover module.
|
GitServer.prototype.onFetch = function(fetch) {
var repo;
this.log('Got a FETCH call for', fetch.repo);
repo = this.getRepo(fetch.repo);
if (repo !== false) {
if (repo.anonRead === true) {
this.checkTriggers('fetch', repo);
return fetch.accept();
} else {
return this.processSecurity(fetch, 'fetch', repo);
}
} else {
this.log('Rejected - Repo', fetch.repo, 'doesnt exist');
return fetch.reject(500, 'This repo doesnt exist');
}
};
|
When the git push command is triggered, this is fired. Params
push
Object
Git object from pushover module.
|
GitServer.prototype.onPush = function(push) {
var repo;
this.log('Got a PUSH call for', push.repo);
repo = this.getRepo(push.repo);
if (repo !== false) {
return this.processSecurity(push, 'push', repo);
} else {
this.log('Rejected - Repo', push.repo, 'doesnt exist');
return push.reject(500, 'This repo doesnt exist');
}
};
|
Check if this repo has onSuccessful triggers Params
method
String
fetch|push
repo
Object
Repo object we are checking
|
GitServer.prototype.checkTriggers = function(method, repo) {
var _base;
if (repo.onSuccessful != null) {
if (repo.onSuccessful[method] != null) {
this.log('On successful triggered: ', method, 'on', repo.name);
return typeof (_base = repo.onSuccessful)[method] === "function" ? _base[method](repo, method) : void 0;
}
}
};
|
Get the user object, check user/pass is correct and it exists in this repo. Params
username
String
Username to find
password
String
Password of the Username
repo
Object
Repo object this user should be in.
|
GitServer.prototype.getUser = function(username, password, repo) {
var userObject, _i, _len, _ref;
_ref = repo.users;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
userObject = _ref[_i];
if (userObject.user.username === username && userObject.user.password === password) {
return userObject;
}
}
return false;
};
|
Get the repo from the array of repos Params
repoName
String
Name of the repo we are trying to find
|
GitServer.prototype.getRepo = function(repoName) {
var repo, _i, _len, _ref;
_ref = this.repos;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
repo = _ref[_i];
if (repo.name + '.git' === repoName) {
return repo;
}
}
return false;
};
return GitServer;
})();
module.exports = GitServer;
|