mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-07-08 22:57:48 +02:00
feat: improve error message
This commit is contained in:
Generated
+14
@@ -33,6 +33,7 @@
|
|||||||
"redis": "^3.1.2",
|
"redis": "^3.1.2",
|
||||||
"tar-fs": "^2.1.1",
|
"tar-fs": "^2.1.1",
|
||||||
"textextensions": "^5.12.0",
|
"textextensions": "^5.12.0",
|
||||||
|
"ts-custom-error": "^3.2.0",
|
||||||
"xml-flow": "^1.0.4"
|
"xml-flow": "^1.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -4463,6 +4464,14 @@
|
|||||||
"nodetouch": "bin/nodetouch.js"
|
"nodetouch": "bin/nodetouch.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-custom-error": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ts-node": {
|
"node_modules/ts-node": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz",
|
||||||
@@ -8496,6 +8505,11 @@
|
|||||||
"nopt": "~1.0.10"
|
"nopt": "~1.0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ts-custom-error": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A=="
|
||||||
|
},
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
"redis": "^3.1.2",
|
"redis": "^3.1.2",
|
||||||
"tar-fs": "^2.1.1",
|
"tar-fs": "^2.1.1",
|
||||||
"textextensions": "^5.12.0",
|
"textextensions": "^5.12.0",
|
||||||
|
"ts-custom-error": "^3.2.0",
|
||||||
"xml-flow": "^1.0.4"
|
"xml-flow": "^1.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Tree, TreeElement, TreeFile } from "./types";
|
|||||||
import storage from "./storage";
|
import storage from "./storage";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
import { anonymizePath, anonymizeStream } from "./anonymize-utils";
|
import { anonymizePath, anonymizeStream } from "./anonymize-utils";
|
||||||
|
import AnonymousError from "./AnonymousError";
|
||||||
|
|
||||||
function tree2sha(
|
function tree2sha(
|
||||||
tree: any,
|
tree: any,
|
||||||
@@ -39,7 +40,8 @@ export default class AnonymizedFile {
|
|||||||
|
|
||||||
constructor(data: { repository: Repository; anonymizedPath: string }) {
|
constructor(data: { repository: Repository; anonymizedPath: string }) {
|
||||||
this.repository = data.repository;
|
this.repository = data.repository;
|
||||||
if (!this.repository.options.terms) throw new Error("terms_not_specified");
|
if (!this.repository.options.terms)
|
||||||
|
throw new AnonymousError("terms_not_specified");
|
||||||
this.anonymizedPath = data.anonymizedPath;
|
this.anonymizedPath = data.anonymizedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +51,8 @@ export default class AnonymizedFile {
|
|||||||
* @returns the origin relative path of the file
|
* @returns the origin relative path of the file
|
||||||
*/
|
*/
|
||||||
async originalPath(): Promise<string> {
|
async originalPath(): Promise<string> {
|
||||||
// console.log(new Error().stack);
|
|
||||||
if (this._originalPath) return this._originalPath;
|
if (this._originalPath) return this._originalPath;
|
||||||
if (!this.anonymizedPath) throw new Error("path_not_specified");
|
if (!this.anonymizedPath) throw new AnonymousError("path_not_specified");
|
||||||
|
|
||||||
const paths = this.anonymizedPath.trim().split("/");
|
const paths = this.anonymizedPath.trim().split("/");
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ export default class AnonymizedFile {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!currentAnonymized[fileName]) {
|
if (!currentAnonymized[fileName]) {
|
||||||
throw new Error("file_not_found");
|
throw new AnonymousError("file_not_found", this);
|
||||||
}
|
}
|
||||||
currentAnonymized = currentAnonymized[fileName];
|
currentAnonymized = currentAnonymized[fileName];
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ export default class AnonymizedFile {
|
|||||||
currentAnonymized.sha === undefined ||
|
currentAnonymized.sha === undefined ||
|
||||||
currentAnonymized.size === undefined
|
currentAnonymized.size === undefined
|
||||||
) {
|
) {
|
||||||
throw new Error("folder_not_supported");
|
throw new AnonymousError("folder_not_supported", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const file: TreeFile = currentAnonymized as TreeFile;
|
const file: TreeFile = currentAnonymized as TreeFile;
|
||||||
@@ -111,7 +112,7 @@ export default class AnonymizedFile {
|
|||||||
// it should never happen
|
// it should never happen
|
||||||
const shaTree = tree2sha(currentOriginal);
|
const shaTree = tree2sha(currentOriginal);
|
||||||
if (!currentAnonymized.sha || !shaTree[file.sha]) {
|
if (!currentAnonymized.sha || !shaTree[file.sha]) {
|
||||||
throw new Error("file_not_found");
|
throw new AnonymousError("file_not_found", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._originalPath = path.join(currentOriginalPath, shaTree[file.sha]);
|
this._originalPath = path.join(currentOriginalPath, shaTree[file.sha]);
|
||||||
@@ -144,7 +145,7 @@ export default class AnonymizedFile {
|
|||||||
|
|
||||||
async content(): Promise<stream.Readable> {
|
async content(): Promise<stream.Readable> {
|
||||||
if (this.fileSize && this.fileSize > config.MAX_FILE_SIZE) {
|
if (this.fileSize && this.fileSize > config.MAX_FILE_SIZE) {
|
||||||
throw new Error("file_too_big");
|
throw new AnonymousError("file_too_big", this);
|
||||||
}
|
}
|
||||||
if (await storage.exists(this.originalCachePath)) {
|
if (await storage.exists(this.originalCachePath)) {
|
||||||
return storage.read(this.originalCachePath);
|
return storage.read(this.originalCachePath);
|
||||||
@@ -160,7 +161,7 @@ export default class AnonymizedFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get originalCachePath() {
|
get originalCachePath() {
|
||||||
if (!this.originalPath) throw new Error("path_not_defined");
|
if (!this.originalPath) throw new AnonymousError("path_not_defined");
|
||||||
return path.join(this.repository.originalCachePath, this._originalPath);
|
return path.join(this.repository.originalCachePath, this._originalPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { CustomError } from 'ts-custom-error'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom error message
|
||||||
|
*/
|
||||||
|
export default class AnonymousError extends CustomError {
|
||||||
|
|
||||||
|
value: any;
|
||||||
|
|
||||||
|
constructor(message: string, value?: any) {
|
||||||
|
super(message);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-6
@@ -13,6 +13,7 @@ import { anonymizeStream } from "./anonymize-utils";
|
|||||||
import GitHubBase from "./source/GitHubBase";
|
import GitHubBase from "./source/GitHubBase";
|
||||||
import Conference from "./Conference";
|
import Conference from "./Conference";
|
||||||
import ConferenceModel from "./database/conference/conferences.model";
|
import ConferenceModel from "./database/conference/conferences.model";
|
||||||
|
import AnonymousError from "./AnonymousError";
|
||||||
|
|
||||||
export default class Repository {
|
export default class Repository {
|
||||||
private _model: IAnonymizedRepositoryDocument;
|
private _model: IAnonymizedRepositoryDocument;
|
||||||
@@ -32,7 +33,7 @@ export default class Repository {
|
|||||||
this.source = new Zip(data.source, this);
|
this.source = new Zip(data.source, this);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("unsupported_source");
|
throw new AnonymousError("unsupported_source", data.source.type);
|
||||||
}
|
}
|
||||||
this.owner = new User(new UserModel({ _id: data.owner }));
|
this.owner = new User(new UserModel({ _id: data.owner }));
|
||||||
}
|
}
|
||||||
@@ -103,13 +104,13 @@ export default class Repository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this._model.status == "expired") {
|
if (this._model.status == "expired") {
|
||||||
throw new Error("repository_expired");
|
throw new AnonymousError("repository_expired", this);
|
||||||
}
|
}
|
||||||
if (this._model.status == "removed") {
|
if (this._model.status == "removed") {
|
||||||
throw new Error("repository_expired");
|
throw new AnonymousError("repository_expired", this);
|
||||||
}
|
}
|
||||||
if (this._model.status != "ready") {
|
if (this._model.status != "ready") {
|
||||||
throw new Error("repository_not_ready");
|
throw new AnonymousError("repository_not_ready", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ export default class Repository {
|
|||||||
|
|
||||||
if (this._model.options.update && this._model.lastView < yesterday) {
|
if (this._model.options.update && this._model.lastView < yesterday) {
|
||||||
if (this._model.status != "ready") {
|
if (this._model.status != "ready") {
|
||||||
throw new Error("repo_not_ready");
|
throw new AnonymousError("repository_not_ready", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only GitHubBase can be update for the moment
|
// Only GitHubBase can be update for the moment
|
||||||
@@ -162,7 +163,7 @@ export default class Repository {
|
|||||||
console.error(
|
console.error(
|
||||||
`${branch.name} for ${this.source.githubRepository.fullName} is not found`
|
`${branch.name} for ${this.source.githubRepository.fullName} is not found`
|
||||||
);
|
);
|
||||||
throw new Error("branch_not_found");
|
throw new AnonymousError("branch_not_found", this);
|
||||||
}
|
}
|
||||||
this._model.anonymizeDate = new Date();
|
this._model.anonymizeDate = new Date();
|
||||||
console.log(
|
console.log(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as mongoose from "mongoose";
|
|||||||
import Repository from "../Repository";
|
import Repository from "../Repository";
|
||||||
import config from "../../config";
|
import config from "../../config";
|
||||||
import AnonymizedRepositoryModel from "./anonymizedRepositories/anonymizedRepositories.model";
|
import AnonymizedRepositoryModel from "./anonymizedRepositories/anonymizedRepositories.model";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
const MONGO_URL = `mongodb://${config.DB_USERNAME}:${config.DB_PASSWORD}@${config.DB_HOSTNAME}:27017/`;
|
const MONGO_URL = `mongodb://${config.DB_USERNAME}:${config.DB_PASSWORD}@${config.DB_HOSTNAME}:27017/`;
|
||||||
|
|
||||||
@@ -23,6 +24,6 @@ export async function connect() {
|
|||||||
|
|
||||||
export async function getRepository(repoId: string) {
|
export async function getRepository(repoId: string) {
|
||||||
const data = await AnonymizedRepositoryModel.findOne({ repoId });
|
const data = await AnonymizedRepositoryModel.findOne({ repoId });
|
||||||
if (!data) throw new Error("repo_not_found");
|
if (!data) throw new AnonymousError("repo_not_found", repoId);
|
||||||
return new Repository(data);
|
return new Repository(data);
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-23
@@ -1,9 +1,7 @@
|
|||||||
import * as express from "express";
|
import * as express from "express";
|
||||||
import config from "../../config";
|
import AnonymousError from "../AnonymousError";
|
||||||
import Conference from "../Conference";
|
import Conference from "../Conference";
|
||||||
import AnonymizedRepositoryModel from "../database/anonymizedRepositories/anonymizedRepositories.model";
|
|
||||||
import ConferenceModel from "../database/conference/conferences.model";
|
import ConferenceModel from "../database/conference/conferences.model";
|
||||||
import Repository from "../Repository";
|
|
||||||
import { ensureAuthenticated } from "./connection";
|
import { ensureAuthenticated } from "./connection";
|
||||||
import { handleError, getUser } from "./route-utils";
|
import { handleError, getUser } from "./route-utils";
|
||||||
|
|
||||||
@@ -69,26 +67,26 @@ router.get("/", async (req: express.Request, res: express.Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function validateConferenceForm(conf) {
|
function validateConferenceForm(conf) {
|
||||||
if (!conf.name) throw new Error("conf_name_missing");
|
if (!conf.name) throw new AnonymousError("conf_name_missing");
|
||||||
if (!conf.conferenceID) throw new Error("conf_id_missing");
|
if (!conf.conferenceID) throw new AnonymousError("conf_id_missing");
|
||||||
if (!conf.startDate) throw new Error("conf_start_date_missing");
|
if (!conf.startDate) throw new AnonymousError("conf_start_date_missing");
|
||||||
if (!conf.endDate) throw new Error("conf_end_date_missing");
|
if (!conf.endDate) throw new AnonymousError("conf_end_date_missing");
|
||||||
if (new Date(conf.startDate) > new Date(conf.endDate))
|
if (new Date(conf.startDate) > new Date(conf.endDate))
|
||||||
throw new Error("conf_start_date_invalid");
|
throw new AnonymousError("conf_start_date_invalid");
|
||||||
if (new Date() > new Date(conf.endDate))
|
if (new Date() > new Date(conf.endDate))
|
||||||
throw new Error("conf_end_date_invalid");
|
throw new AnonymousError("conf_end_date_invalid");
|
||||||
if (plans.filter((p) => p.id == conf.plan.planID).length != 1)
|
if (plans.filter((p) => p.id == conf.plan.planID).length != 1)
|
||||||
throw new Error("invalid_plan");
|
throw new AnonymousError("invalid_plan");
|
||||||
const plan = plans.filter((p) => p.id == conf.plan.planID)[0];
|
const plan = plans.filter((p) => p.id == conf.plan.planID)[0];
|
||||||
if (plan.pricePerRepo > 0) {
|
if (plan.pricePerRepo > 0) {
|
||||||
const billing = conf.billing;
|
const billing = conf.billing;
|
||||||
if (!billing) throw new Error("billing_missing");
|
if (!billing) throw new AnonymousError("billing_missing");
|
||||||
if (!billing.name) throw new Error("billing_name_missing");
|
if (!billing.name) throw new AnonymousError("billing_name_missing");
|
||||||
if (!billing.email) throw new Error("billing_email_missing");
|
if (!billing.email) throw new AnonymousError("billing_email_missing");
|
||||||
if (!billing.address) throw new Error("billing_address_missing");
|
if (!billing.address) throw new AnonymousError("billing_address_missing");
|
||||||
if (!billing.city) throw new Error("billing_city_missing");
|
if (!billing.city) throw new AnonymousError("billing_city_missing");
|
||||||
if (!billing.zip) throw new Error("billing_zip_missing");
|
if (!billing.zip) throw new AnonymousError("billing_zip_missing");
|
||||||
if (!billing.country) throw new Error("billing_country_missing");
|
if (!billing.country) throw new AnonymousError("billing_country_missing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +101,7 @@ router.post(
|
|||||||
conferenceID: req.params.conferenceID,
|
conferenceID: req.params.conferenceID,
|
||||||
});
|
});
|
||||||
if (model.owners.indexOf(user.model.id) == -1)
|
if (model.owners.indexOf(user.model.id) == -1)
|
||||||
throw new Error("not_authorized");
|
throw new AnonymousError("not_authorized");
|
||||||
}
|
}
|
||||||
validateConferenceForm(req.body);
|
validateConferenceForm(req.body);
|
||||||
model.name = req.body.name;
|
model.name = req.body.name;
|
||||||
@@ -148,7 +146,7 @@ router.post(
|
|||||||
res.send("ok");
|
res.send("ok");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.message?.indexOf(" duplicate key") > -1) {
|
if (error.message?.indexOf(" duplicate key") > -1) {
|
||||||
return handleError(new Error("conf_id_used"), res);
|
return handleError(new AnonymousError("conf_id_used"), res);
|
||||||
}
|
}
|
||||||
handleError(error, res);
|
handleError(error, res);
|
||||||
}
|
}
|
||||||
@@ -163,10 +161,10 @@ router.get(
|
|||||||
const data = await ConferenceModel.findOne({
|
const data = await ConferenceModel.findOne({
|
||||||
conferenceID: req.params.conferenceID,
|
conferenceID: req.params.conferenceID,
|
||||||
});
|
});
|
||||||
if (!data) throw new Error("conf_not_found");
|
if (!data) throw new AnonymousError("conf_not_found");
|
||||||
const conference = new Conference(data);
|
const conference = new Conference(data);
|
||||||
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
||||||
throw new Error("not_authorized");
|
throw new AnonymousError("not_authorized");
|
||||||
const o: any = conference.toJSON();
|
const o: any = conference.toJSON();
|
||||||
o.repositories = (await conference.repositories()).map((r) => r.toJSON());
|
o.repositories = (await conference.repositories()).map((r) => r.toJSON());
|
||||||
res.json(o);
|
res.json(o);
|
||||||
@@ -184,10 +182,10 @@ router.delete(
|
|||||||
const data = await ConferenceModel.findOne({
|
const data = await ConferenceModel.findOne({
|
||||||
conferenceID: req.params.conferenceID,
|
conferenceID: req.params.conferenceID,
|
||||||
});
|
});
|
||||||
if (!data) throw new Error("conf_not_found");
|
if (!data) throw new AnonymousError("conf_not_found");
|
||||||
const conference = new Conference(data);
|
const conference = new Conference(data);
|
||||||
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
||||||
throw new Error("not_authorized");
|
throw new AnonymousError("not_authorized");
|
||||||
await conference.remove();
|
await conference.remove();
|
||||||
res.send("ok");
|
res.send("ok");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import config from "../../config";
|
|||||||
import { IAnonymizedRepositoryDocument } from "../database/anonymizedRepositories/anonymizedRepositories.types";
|
import { IAnonymizedRepositoryDocument } from "../database/anonymizedRepositories/anonymizedRepositories.types";
|
||||||
import Repository from "../Repository";
|
import Repository from "../Repository";
|
||||||
import ConferenceModel from "../database/conference/conferences.model";
|
import ConferenceModel from "../database/conference/conferences.model";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -182,22 +183,22 @@ function validateNewRepo(repoUpdate) {
|
|||||||
!repoUpdate.repoId.match(validCharacters) ||
|
!repoUpdate.repoId.match(validCharacters) ||
|
||||||
repoUpdate.repoId.length < 3
|
repoUpdate.repoId.length < 3
|
||||||
) {
|
) {
|
||||||
throw new Error("invalid_repoId");
|
throw new AnonymousError("invalid_repoId");
|
||||||
}
|
}
|
||||||
if (!repoUpdate.source.branch) {
|
if (!repoUpdate.source.branch) {
|
||||||
throw new Error("branch_not_specified");
|
throw new AnonymousError("branch_not_specified");
|
||||||
}
|
}
|
||||||
if (!repoUpdate.source.commit) {
|
if (!repoUpdate.source.commit) {
|
||||||
throw new Error("commit_not_specified");
|
throw new AnonymousError("commit_not_specified");
|
||||||
}
|
}
|
||||||
if (!repoUpdate.options) {
|
if (!repoUpdate.options) {
|
||||||
throw new Error("options_not_provided");
|
throw new AnonymousError("options_not_provided");
|
||||||
}
|
}
|
||||||
if (!Array.isArray(repoUpdate.terms)) {
|
if (!Array.isArray(repoUpdate.terms)) {
|
||||||
throw new Error("invalid_terms_format");
|
throw new AnonymousError("invalid_terms_format");
|
||||||
}
|
}
|
||||||
if (!/^[a-f0-9]+$/.test(repoUpdate.source.commit)) {
|
if (!/^[a-f0-9]+$/.test(repoUpdate.source.commit)) {
|
||||||
throw new Error("invalid_commit_format");
|
throw new AnonymousError("invalid_commit_format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +284,7 @@ router.post(
|
|||||||
new Date() > conf.endDate ||
|
new Date() > conf.endDate ||
|
||||||
conf.status !== "ready"
|
conf.status !== "ready"
|
||||||
) {
|
) {
|
||||||
throw new Error("conf_not_activated");
|
throw new AnonymousError("conf_not_activated");
|
||||||
}
|
}
|
||||||
const f = conf.repositories.filter((r) => r.id == repo.model.id);
|
const f = conf.repositories.filter((r) => r.id == repo.model.id);
|
||||||
if (f.length) {
|
if (f.length) {
|
||||||
@@ -358,7 +359,7 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
|||||||
conf.status !== "ready"
|
conf.status !== "ready"
|
||||||
) {
|
) {
|
||||||
await repo.remove();
|
await repo.remove();
|
||||||
throw new Error("conf_not_activated");
|
throw new AnonymousError("conf_not_activated");
|
||||||
}
|
}
|
||||||
conf.repositories.push({
|
conf.repositories.push({
|
||||||
id: repo.id,
|
id: repo.id,
|
||||||
@@ -371,6 +372,9 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
|||||||
res.send("ok");
|
res.send("ok");
|
||||||
new Repository(repo).anonymize();
|
new Repository(repo).anonymize();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (error.message?.indexOf(" duplicate key") > -1) {
|
||||||
|
return handleError(new AnonymousError("repoId_already_used", repoUpdate.repoId), res);
|
||||||
|
}
|
||||||
return handleError(error, res);
|
return handleError(error, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ router.get(
|
|||||||
redirectURL = repo.source.url;
|
redirectURL = repo.source.url;
|
||||||
} else {
|
} else {
|
||||||
repo.check();
|
repo.check();
|
||||||
|
await repo.updateIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
await repo.updateIfNeeded();
|
|
||||||
|
|
||||||
let download = false;
|
let download = false;
|
||||||
const conference = await repo.conference();
|
const conference = await repo.conference();
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import * as express from "express";
|
import * as express from "express";
|
||||||
|
import AnonymizedFile from "../AnonymizedFile";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
import * as db from "../database/database";
|
import * as db from "../database/database";
|
||||||
import UserModel from "../database/users/users.model";
|
import UserModel from "../database/users/users.model";
|
||||||
|
import Repository from "../Repository";
|
||||||
|
import GitHubBase from "../source/GitHubBase";
|
||||||
|
import GitHubDownload from "../source/GitHubDownload";
|
||||||
|
import { GitHubRepository } from "../source/GitHubRepository";
|
||||||
import User from "../User";
|
import User from "../User";
|
||||||
|
|
||||||
export async function getRepo(
|
export async function getRepo(
|
||||||
@@ -31,8 +37,35 @@ export async function getRepo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function printError(error: any) {
|
||||||
|
if (error instanceof AnonymousError) {
|
||||||
|
let detail = error.value?.toString();
|
||||||
|
if (error.value instanceof Repository) {
|
||||||
|
detail = error.value.repoId;
|
||||||
|
} else if (error.value instanceof AnonymizedFile) {
|
||||||
|
detail = `/r/${error.value.repository.repoId}/${error.value.anonymizedPath}`;
|
||||||
|
} else if (error.value instanceof GitHubRepository) {
|
||||||
|
detail = `${error.value.fullName}`;
|
||||||
|
} else if (error.value instanceof User) {
|
||||||
|
detail = `${error.value.username}`;
|
||||||
|
} else if (error.value instanceof GitHubBase) {
|
||||||
|
detail = `${error.value.repository.repoId}`;
|
||||||
|
}
|
||||||
|
console.error(
|
||||||
|
"[ERROR]",
|
||||||
|
error.message,
|
||||||
|
`'${detail}'`,
|
||||||
|
error.stack.split("\n")[1].trim()
|
||||||
|
);
|
||||||
|
} else if (error instanceof Error) {
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function handleError(error: any, res: express.Response) {
|
export function handleError(error: any, res: express.Response) {
|
||||||
console.log(error);
|
printError(error);
|
||||||
let message = error;
|
let message = error;
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
message = error.message;
|
message = error.message;
|
||||||
@@ -52,12 +85,12 @@ export async function getUser(req: express.Request) {
|
|||||||
const user = (req.user as any).user;
|
const user = (req.user as any).user;
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.logout();
|
req.logout();
|
||||||
throw new Error("not_connected");
|
throw new AnonymousError("not_connected");
|
||||||
}
|
}
|
||||||
const model = await UserModel.findById(user._id);
|
const model = await UserModel.findById(user._id);
|
||||||
if (!model) {
|
if (!model) {
|
||||||
req.logout();
|
req.logout();
|
||||||
throw new Error("not_connected");
|
throw new AnonymousError("not_connected");
|
||||||
}
|
}
|
||||||
return new User(model);
|
return new User(model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { getRepo, handleError } from "./route-utils";
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import AnonymizedFile from "../AnonymizedFile";
|
import AnonymizedFile from "../AnonymizedFile";
|
||||||
import GitHubDownload from "../source/GitHubDownload";
|
import GitHubDownload from "../source/GitHubDownload";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -10,18 +11,15 @@ async function webView(req: express.Request, res: express.Response) {
|
|||||||
const repo = await getRepo(req, res);
|
const repo = await getRepo(req, res);
|
||||||
if (!repo) return;
|
if (!repo) return;
|
||||||
try {
|
try {
|
||||||
if (!repo.options.page) {
|
if (!repo.options.page || !repo.options.pageSource) {
|
||||||
throw new Error("page_not_activated");
|
throw new AnonymousError("page_not_activated");
|
||||||
}
|
|
||||||
if (!repo.options.pageSource) {
|
|
||||||
throw new Error("page_not_activated");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
repo.options.pageSource?.branch !=
|
repo.options.pageSource?.branch !=
|
||||||
(repo.source as GitHubDownload).branch.name
|
(repo.source as GitHubDownload).branch.name
|
||||||
) {
|
) {
|
||||||
throw new Error("page_not_supported_on_different_branch");
|
throw new AnonymousError("page_not_supported_on_different_branch");
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestPath = path.join(
|
let requestPath = path.join(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { OAuthApp } from "@octokit/oauth-app";
|
|||||||
import Repository from "../Repository";
|
import Repository from "../Repository";
|
||||||
import * as stream from "stream";
|
import * as stream from "stream";
|
||||||
import UserModel from "../database/users/users.model";
|
import UserModel from "../database/users/users.model";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
export default abstract class GitHubBase {
|
export default abstract class GitHubBase {
|
||||||
type: "GitHubDownload" | "GitHubStream" | "Zip";
|
type: "GitHubDownload" | "GitHubStream" | "Zip";
|
||||||
@@ -37,17 +38,18 @@ export default abstract class GitHubBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
||||||
throw new Error("Method not implemented.");
|
throw new AnonymousError("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
getFiles(): Promise<Tree> {
|
getFiles(): Promise<Tree> {
|
||||||
throw new Error("Method not implemented.");
|
throw new AnonymousError("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async getToken(owner?: string) {
|
async getToken(owner?: string) {
|
||||||
if (owner) {
|
if (owner) {
|
||||||
const user = await UserModel.findOne({ username: owner });
|
const user = await UserModel.findOne({ username: owner });
|
||||||
if (user && user.accessToken) {
|
if (user && user.accessTokens.github) {
|
||||||
return user.accessToken as string;
|
return user.accessTokens.github as string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.accessToken) {
|
if (this.accessToken) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { SourceBase } from "../types";
|
|||||||
import got from "got";
|
import got from "got";
|
||||||
import * as stream from "stream";
|
import * as stream from "stream";
|
||||||
import { OctokitResponse } from "@octokit/types";
|
import { OctokitResponse } from "@octokit/types";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
export default class GitHubDownload extends GitHubBase implements SourceBase {
|
export default class GitHubDownload extends GitHubBase implements SourceBase {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -39,7 +40,7 @@ export default class GitHubDownload extends GitHubBase implements SourceBase {
|
|||||||
|
|
||||||
async download() {
|
async download() {
|
||||||
if (this.repository.status == "download")
|
if (this.repository.status == "download")
|
||||||
throw new Error("repo_in_download");
|
throw new AnonymousError("repo_in_download", this.repository);
|
||||||
let response: OctokitResponse<unknown, number>;
|
let response: OctokitResponse<unknown, number>;
|
||||||
try {
|
try {
|
||||||
response = await this._getZipUrl(await this.getToken());
|
response = await this._getZipUrl(await this.getToken());
|
||||||
@@ -48,10 +49,10 @@ export default class GitHubDownload extends GitHubBase implements SourceBase {
|
|||||||
try {
|
try {
|
||||||
response = await this._getZipUrl(config.GITHUB_TOKEN);
|
response = await this._getZipUrl(config.GITHUB_TOKEN);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error("repo_not_accessible");
|
throw new AnonymousError("repo_not_accessible", this.repository);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("repo_not_accessible");
|
throw new AnonymousError("repo_not_accessible", this.repository);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.repository.updateStatus("download");
|
await this.repository.updateStatus("download");
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import * as gh from "parse-github-url";
|
|||||||
import { IRepositoryDocument } from "../database/repositories/repositories.types";
|
import { IRepositoryDocument } from "../database/repositories/repositories.types";
|
||||||
import { Octokit } from "@octokit/rest";
|
import { Octokit } from "@octokit/rest";
|
||||||
import RepositoryModel from "../database/repositories/repositories.model";
|
import RepositoryModel from "../database/repositories/repositories.model";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
export class GitHubRepository {
|
export class GitHubRepository {
|
||||||
private _data: Partial<
|
private _data: Partial<
|
||||||
@@ -116,7 +117,7 @@ export class GitHubRepository {
|
|||||||
selected.readme = readme;
|
selected.readme = readme;
|
||||||
await model.save();
|
await model.save();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error("readme_not_available");
|
throw new AnonymousError("readme_not_available", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ export class GitHubRepository {
|
|||||||
public get owner(): string {
|
public get owner(): string {
|
||||||
const repo = gh(this.fullName);
|
const repo = gh(this.fullName);
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
throw "invalid_repo";
|
throw new AnonymousError("invalid_repo", this);
|
||||||
}
|
}
|
||||||
return repo.owner || this.fullName;
|
return repo.owner || this.fullName;
|
||||||
}
|
}
|
||||||
@@ -134,7 +135,7 @@ export class GitHubRepository {
|
|||||||
public get repo(): string {
|
public get repo(): string {
|
||||||
const repo = gh(this.fullName);
|
const repo = gh(this.fullName);
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
throw "invalid_repo";
|
throw new AnonymousError("invalid_repo", this);
|
||||||
}
|
}
|
||||||
return repo.name || this.fullName;
|
return repo.name || this.fullName;
|
||||||
}
|
}
|
||||||
@@ -152,7 +153,7 @@ export async function getRepositoryFromGitHub(opt: {
|
|||||||
repo: opt.repo,
|
repo: opt.repo,
|
||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
if (!r) throw new Error("repo_not_found");
|
if (!r) throw new AnonymousError("repo_not_found", this);
|
||||||
let model = await RepositoryModel.findOne({ externalId: "gh_" + r.id });
|
let model = await RepositoryModel.findOne({ externalId: "gh_" + r.id });
|
||||||
if (!model) {
|
if (!model) {
|
||||||
model = new RepositoryModel({ externalId: "gh_" + r.id });
|
model = new RepositoryModel({ externalId: "gh_" + r.id });
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { SourceBase, Tree } from "../types";
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import * as stream from "stream";
|
import * as stream from "stream";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
export default class GitHubStream extends GitHubBase implements SourceBase {
|
export default class GitHubStream extends GitHubBase implements SourceBase {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -24,7 +25,7 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
||||||
if (!file.sha) throw new Error("file_sha_not_provided");
|
if (!file.sha) throw new AnonymousError("file_sha_not_provided", file);
|
||||||
const octokit = new Octokit({
|
const octokit = new Octokit({
|
||||||
auth: await this.getToken(),
|
auth: await this.getToken(),
|
||||||
});
|
});
|
||||||
@@ -36,7 +37,7 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
file_sha: file.sha,
|
file_sha: file.sha,
|
||||||
});
|
});
|
||||||
if (!ghRes.data.content && ghRes.data.size != 0) {
|
if (!ghRes.data.content && ghRes.data.size != 0) {
|
||||||
throw new Error("file_not_accessible");
|
throw new AnonymousError("file_not_accessible", file);
|
||||||
}
|
}
|
||||||
// empty file
|
// empty file
|
||||||
let content: Buffer;
|
let content: Buffer;
|
||||||
@@ -52,11 +53,11 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
return stream.Readable.from(content.toString());
|
return stream.Readable.from(content.toString());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.status == 403) {
|
if (error.status == 403) {
|
||||||
throw new Error("file_too_big");
|
throw new AnonymousError("file_too_big", file);
|
||||||
}
|
}
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
throw new Error("file_not_accessible");
|
throw new AnonymousError("file_not_accessible");
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFiles() {
|
async getFiles() {
|
||||||
|
|||||||
+2
-1
@@ -9,6 +9,7 @@ import * as flow from "xml-flow";
|
|||||||
import * as archiver from "archiver";
|
import * as archiver from "archiver";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as gunzip from "gunzip-maybe";
|
import * as gunzip from "gunzip-maybe";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
|
|
||||||
const originalArchiveStreamToS3Entry: Function = (ArchiveStreamToS3 as any)
|
const originalArchiveStreamToS3Entry: Function = (ArchiveStreamToS3 as any)
|
||||||
.prototype.onEntry;
|
.prototype.onEntry;
|
||||||
@@ -18,7 +19,7 @@ export default class S3Storage implements StorageBase {
|
|||||||
client: S3;
|
client: S3;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!config.S3_BUCKET) throw new Error("s3_config_not_provided");
|
if (!config.S3_BUCKET) throw new AnonymousError("s3_config_not_provided");
|
||||||
this.client = new S3({
|
this.client = new S3({
|
||||||
region: config.S3_REGION,
|
region: config.S3_REGION,
|
||||||
endpoint: config.S3_ENDPOINT,
|
endpoint: config.S3_ENDPOINT,
|
||||||
|
|||||||
Reference in New Issue
Block a user