aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2021-05-27 21:46:44 +0200
committerHampusM <hampus@hampusmat.com>2021-05-27 21:46:44 +0200
commitbdfc5d2d092fdce8fb4149ae8acb86b63c14c642 (patch)
tree64fd18534f7f6cfb0f204065c2d40b9bf6146d85
parentdf806dda764ff722742301042ab88b3d91f472c5 (diff)
Implemented cloning in backend
-rw-r--r--package-lock.json115
-rw-r--r--package.json3
-rw-r--r--src/api/git.js74
-rw-r--r--src/app.js47
4 files changed, 121 insertions, 118 deletions
diff --git a/package-lock.json b/package-lock.json
index c73238e..2f28bfe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,8 @@
"nodegit": "^0.27.0",
"vue": "^3.0.11",
"vue-loading-overlay": "^4.0.2",
- "vue-router": "^4.0.8"
+ "vue-router": "^4.0.8",
+ "whatwg-url": "^7.1.0"
},
"devDependencies": {
"@parcel/transformer-sass": "^2.0.0-beta.2",
@@ -4585,15 +4586,6 @@
"node": ">= 0.10.0"
}
},
- "node_modules/connect/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
"node_modules/console-browserify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
@@ -6680,15 +6672,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/expand-brackets/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
"node_modules/expand-brackets/node_modules/define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -7124,15 +7107,6 @@
"node": ">= 0.8"
}
},
- "node_modules/finalhandler/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
"node_modules/find-my-way": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.1.0.tgz",
@@ -8844,8 +8818,7 @@
"node_modules/lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
- "dev": true
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
},
"node_modules/lodash.truncate": {
"version": "4.4.2",
@@ -15244,15 +15217,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/snapdragon/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
"node_modules/snapdragon/node_modules/define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -16322,7 +16286,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
- "dev": true,
"dependencies": {
"punycode": "^2.1.0"
}
@@ -16561,15 +16524,6 @@
"debug": "^2.2.0"
}
},
- "node_modules/undefsafe/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@@ -17042,8 +16996,7 @@
"node_modules/webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
},
"node_modules/whatwg-encoding": {
"version": "1.0.5",
@@ -17064,7 +17017,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
- "dev": true,
"dependencies": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
@@ -21375,17 +21327,6 @@
"finalhandler": "1.1.2",
"parseurl": "~1.3.3",
"utils-merge": "1.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- }
}
},
"console-browserify": {
@@ -23105,15 +23046,6 @@
"to-regex": "^3.0.1"
},
"dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -23480,17 +23412,6 @@
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- }
}
},
"find-my-way": {
@@ -24901,8 +24822,7 @@
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
- "dev": true
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
},
"lodash.truncate": {
"version": "4.4.2",
@@ -30139,15 +30059,6 @@
"use": "^3.1.0"
},
"dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -31086,7 +30997,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
- "dev": true,
"requires": {
"punycode": "^2.1.0"
}
@@ -31282,17 +31192,6 @@
"dev": true,
"requires": {
"debug": "^2.2.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- }
}
},
"unicode-canonical-property-names-ecmascript": {
@@ -31695,8 +31594,7 @@
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
},
"whatwg-encoding": {
"version": "1.0.5",
@@ -31717,7 +31615,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
- "dev": true,
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
diff --git a/package.json b/package.json
index 0e206ff..e69341c 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,8 @@
"nodegit": "^0.27.0",
"vue": "^3.0.11",
"vue-loading-overlay": "^4.0.2",
- "vue-router": "^4.0.8"
+ "vue-router": "^4.0.8",
+ "whatwg-url": "^7.1.0"
},
"devDependencies": {
"@parcel/transformer-sass": "^2.0.0-beta.2",
diff --git a/src/api/git.js b/src/api/git.js
index 756136b..3697f98 100644
--- a/src/api/git.js
+++ b/src/api/git.js
@@ -1,6 +1,10 @@
const { formatDistance } = require('date-fns');
const fs = require('fs');
const git = require("nodegit");
+const zlib = require("zlib");
+const { spawn } = require('child_process');
+const whatwg = require("whatwg-url");
+const path = require("path");
function addRepoDirSuffix(repo_name)
{
@@ -244,8 +248,76 @@ async function doesCommitExist(base_dir, repo_name, commit_oid)
}
}
+function connectToGitHTTPBackend(base_dir, req, reply)
+{
+ const url_path = req.url.replace(req.params.repo, req.params.repo + ".git");
+ const repo = req.params.repo + ".git";
+ const repo_path = path.join(base_dir, repo);
+
+ req = req.headers['Content-Encoding'] == 'gzip' ? req.pipe(zlib.createGunzip()) : req;
+
+ const parsed_url = new whatwg.URL(`${req.protocol}://${req.hostname}${url_path}`);
+ const url_path_parts = parsed_url.pathname.split('/');
+
+ let service;
+ let info = false;
+
+ if(/\/info\/refs$/.test(parsed_url.pathname)) {
+ service = parsed_url.searchParams.get("service");
+ info = true;
+ }
+ else {
+ service = url_path_parts[url_path_parts.length-1];
+ }
+
+ const content_type = `application/x-${service}-${info ? "advertisement" : "result"}`;
+
+ if(/\.\/|\.\./.test(parsed_url.pathname)) {
+ reply.header("Content-Type", content_type);
+ reply.code(404).send("Git repository not found!\n");
+ return;
+ }
+
+ if(service !== 'git-upload-pack') {
+ reply.header("Content-Type", content_type);
+ reply.code(403).send("Access denied!\n");
+ return;
+ }
+
+ reply.raw.writeHead(200, { "Content-Type": content_type });
+
+ const spawn_args = [ "--stateless-rpc", repo_path ];
+
+ if(info) {
+ spawn_args.push("--advertise-refs");
+ }
+
+ const git_pack = spawn(service, spawn_args);
+
+ if(info) {
+ const s = '# service=' + service + '\n';
+ const n = (4 + s.length).toString(16);
+ reply.raw.write(Buffer.from((Array(4 - n.length + 1).join('0') + n + s) + '0000'));
+ }
+ else {
+ req.body.on("data", (data) => git_pack.stdin.write(data));
+ req.body.on("close", () => git_pack.stdin.end());
+ }
+
+ git_pack.on("error", (err) => console.log(err))
+ git_pack.stderr.on("data", (stderr) => console.log(stderr));
+
+ git_pack.stdout.on("data", (data) =>
+ {
+ reply.raw.write(data);
+ });
+
+ git_pack.on("close", () => reply.raw.end());
+}
+
module.exports.getLog = getLog;
module.exports.getRepos = getRepos;
module.exports.getRepoFile = getRepoFile;
module.exports.getCommit = getCommit;
-module.exports.doesCommitExist = doesCommitExist; \ No newline at end of file
+module.exports.doesCommitExist = doesCommitExist;
+module.exports.connectToGitHTTPBackend = connectToGitHTTPBackend; \ No newline at end of file
diff --git a/src/app.js b/src/app.js
index 14b8188..57f0ca1 100644
--- a/src/app.js
+++ b/src/app.js
@@ -6,6 +6,7 @@ const fs = require('fs');
const { exit } = require("process");
const path = require("path");
const util = require("./api/util");
+const git = require("./api/git");
const settings = yaml.load(fs.readFileSync(__dirname + "/../settings.yml", 'utf8'));
const settings_keys = Object.keys(settings);
@@ -44,12 +45,9 @@ fastify.setNotFoundHandler({
reply.send("404: Not found");
});
-fastify.route({
- method: "GET",
- path: "/app.html",
- handler: (req, reply) => reply.redirect("/")
-});
+fastify.addContentTypeParser("application/x-git-upload-pack-request", (req, payload, done) => done(null, payload));
+
fastify.register(fastify_static, { root: dist_dir })
fastify.register(api, { prefix: "/api/v1", config: { settings: settings } });
@@ -64,6 +62,12 @@ fastify.route({
}
});
+fastify.route({
+ method: "GET",
+ path: "/app.html",
+ handler: (req, reply) => reply.redirect("/")
+});
+
fastify.register((fastify_repo, opts, done) =>
{
fastify_repo.setNotFoundHandler({
@@ -79,10 +83,10 @@ fastify.register((fastify_repo, opts, done) =>
const repo_verification = await util.verifyRepoName(req.params.repo, settings.base_dir);
if(repo_verification !== true) {
if(repo_verification === "ERR_REPO_REGEX") {
- reply.code(400).send("Error: Unacceptable git repository name!");
+ reply.code(400).send("Unacceptable git repository name!\n");
}
else if(repo_verification === "ERR_REPO_NOT_FOUND") {
- reply.code(404).send("Error: Git repository not found!");
+ reply.code(404).send("Git repository not found!\n");
}
}
});
@@ -113,6 +117,35 @@ fastify.register((fastify_repo, opts, done) =>
}
});
+ fastify_repo.route({
+ method: "GET",
+ path: "/info/refs",
+ handler: (req, reply) =>
+ {
+ if(!req.query.service) {
+ reply.code(403).send("Missing service query parameter\n");
+ return
+ }
+ else if(req.query.service !== "git-upload-pack") {
+ reply.code(403).send("Access denied!\n");
+ return;
+ }
+ else if(Object.keys(req.query).length !== 1) {
+ reply.header("Content-Type", "application/x-git-upload-pack-advertisement");
+ reply.code(403).send("Too many query parameters!\n");
+ return;
+ }
+
+ git.connectToGitHTTPBackend(settings["base_dir"], req, reply);
+ }
+ });
+
+ fastify_repo.route({
+ method: "POST",
+ path: "/git-upload-pack",
+ handler: (req, reply) => git.connectToGitHTTPBackend(settings["base_dir"], req, reply)
+ });
+
done();
}, { prefix: "/:repo" });