Skip to content
Snippets Groups Projects
Commit 28d6b09f authored by michael.minelli's avatar michael.minelli
Browse files

Sonar => Resolve issues

parent 9a059fef
No related branches found
No related tags found
No related merge requests found
......@@ -38,9 +38,7 @@ class API implements WorkerTask {
private initBaseMiddlewares() {
this.backend.use(multer({
limits: {
fieldSize: 15728640 // 15MB
}
limits: { fieldSize: 100 * 1024 * 1024 }
}).none()); //Used for extract params from body with format "form-data", The none is for say that we do not wait a file in params
this.backend.use(morganMiddleware); //Log API accesses
this.backend.use(helmet()); //Help to secure express, https://helmetjs.github.io/
......
......@@ -26,7 +26,7 @@ export default Prisma.defineExtension(client => {
},
gitlabProfile : {
compute(user) {
return new LazyVal<Gitlab.UserSchema | undefined>(() => GitlabManager.getUserById(user.id));
return new LazyVal<Gitlab.UserSchema | undefined>(() => GlobalHelper.sharedGitlabManager.getUserById(user.id));
}
}
}
......
......@@ -7,6 +7,7 @@ import { CommitSchema, ExpandedUserSchema, Gitlab, MemberSchema, ProjectBadgeSch
import logger from '../shared/logging/WinstonLogger';
import { AccessLevel, EditProjectOptions, ProjectVariableSchema, ProtectedBranchAccessLevel, ProtectedBranchSchema } from '@gitbeaker/core';
import GlobalHelper from '../helpers/GlobalHelper';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
class GitlabManager {
......@@ -29,11 +30,11 @@ class GitlabManager {
}
async getRepositoryMembers(idOrNamespace: string): Promise<Array<MemberSchema>> {
return await this.api.ProjectMembers.all(idOrNamespace, { includeInherited: true });
return this.api.ProjectMembers.all(idOrNamespace, { includeInherited: true });
}
async getRepositoryReleases(repoId: number): Promise<Array<ReleaseSchema>> {
return await this.api.ProjectReleases.all(repoId);
return this.api.ProjectReleases.all(repoId);
}
async getRepositoryLastCommit(repoId: number, branch: string = 'main'): Promise<CommitSchema | undefined> {
......@@ -52,7 +53,7 @@ class GitlabManager {
}
async createRepository(name: string, description: string, visibility: 'public' | 'internal' | 'private', initializeWithReadme: boolean, namespace: number, sharedRunnersEnabled: boolean, wikiEnabled: boolean, import_url: string): Promise<ProjectSchema> {
return await this.api.Projects.create({
return this.api.Projects.create({
name : name,
description : description,
importUrl : import_url,
......@@ -65,11 +66,11 @@ class GitlabManager {
}
async deleteRepository(repoId: number): Promise<void> {
return await this.api.Projects.remove(repoId);
return this.api.Projects.remove(repoId);
}
async forkRepository(forkId: number, name: string, path: string, description: string, visibility: 'public' | 'internal' | 'private', namespace: number): Promise<ProjectSchema> {
return await this.api.Projects.fork(forkId, {
return this.api.Projects.fork(forkId, {
name : name,
path : path,
description: description,
......@@ -79,19 +80,19 @@ class GitlabManager {
}
async editRepository(repoId: number, newAttributes: EditProjectOptions): Promise<ProjectSchema> {
return await this.api.Projects.edit(repoId, newAttributes);
return this.api.Projects.edit(repoId, newAttributes);
}
async changeRepositoryVisibility(repoId: number, visibility: GitlabVisibility): Promise<ProjectSchema> {
return await this.editRepository(repoId, { visibility: visibility });
return this.editRepository(repoId, { visibility: visibility });
}
async addRepositoryMember(repoId: number, userId: number, accessLevel: Exclude<AccessLevel, AccessLevel.ADMIN>): Promise<MemberSchema> {
return await this.api.ProjectMembers.add(repoId, userId, accessLevel);
return this.api.ProjectMembers.add(repoId, userId, accessLevel);
}
async addRepositoryVariable(repoId: number, key: string, value: string, isProtected: boolean, isMasked: boolean): Promise<ProjectVariableSchema> {
return await this.api.ProjectVariables.create(repoId, key, value, {
return this.api.ProjectVariables.create(repoId, key, value, {
variableType: 'env_var',
protected : isProtected,
masked : isMasked
......@@ -99,7 +100,7 @@ class GitlabManager {
}
async addRepositoryBadge(repoId: number, linkUrl: string, imageUrl: string, name: string): Promise<ProjectBadgeSchema> {
return await this.api.ProjectBadges.add(repoId, linkUrl, imageUrl, {
return this.api.ProjectBadges.add(repoId, linkUrl, imageUrl, {
name: name
});
}
......@@ -110,7 +111,8 @@ class GitlabManager {
const project: ProjectSchema = await GlobalHelper.sharedGitlabManager.getRepository(projectIdOrNamespace);
if ( [ 'public', 'internal' ].includes(project.visibility) ) {
return StatusCodes.OK;
req.session.sendResponse(res, StatusCodes.OK);
return true;
}
} catch ( e ) {
req.session.sendResponse(res, StatusCodes.NOT_FOUND, undefined, 'Template not found', DojoStatusCode.GITLAB_TEMPLATE_NOT_FOUND);
......@@ -143,7 +145,7 @@ class GitlabManager {
}
async protectBranch(repoId: number, branchName: string, allowForcePush: boolean, allowedToMerge: ProtectedBranchAccessLevel, allowedToPush: ProtectedBranchAccessLevel, allowedToUnprotect: ProtectedBranchAccessLevel): Promise<ProtectedBranchSchema> {
return await this.api.ProtectedBranches.protect(repoId, branchName, {
return this.api.ProtectedBranches.protect(repoId, branchName, {
allowForcePush : allowForcePush,
mergeAccessLevel : allowedToMerge,
pushAccessLevel : allowedToPush,
......@@ -152,20 +154,20 @@ class GitlabManager {
}
async getRepositoryTree(repoId: number, recursive: boolean = true, branch: string = 'main'): Promise<Array<RepositoryTreeSchema>> {
return await this.api.Repositories.allRepositoryTrees(repoId, {
return this.api.Repositories.allRepositoryTrees(repoId, {
recursive: recursive,
ref : branch
});
}
async getFile(repoId: number, filePath: string, branch: string = 'main'): Promise<RepositoryFileExpandedSchema> {
return await this.api.RepositoryFiles.show(repoId, filePath, branch);
return this.api.RepositoryFiles.show(repoId, filePath, branch);
}
private async createUpdateFile(create: boolean, repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined): Promise<RepositoryFileSchema> {
const gitFunction = create ? this.api.RepositoryFiles.create : this.api.RepositoryFiles.edit;
return await gitFunction(repoId, filePath, branch, fileBase64, commitMessage, {
return gitFunction(repoId, filePath, branch, fileBase64, commitMessage, {
encoding : 'base64',
authorName : authorName,
authorEmail: authorMail
......
......@@ -6,41 +6,39 @@ import AssignmentManager from '../managers/AssignmentManager';
class SecurityMiddleware {
// First check if connected then check if at least ONE rule match. It's NOT an AND but it's a OR function.
check(checkIfConnected: boolean, ...checkTypes: Array<SecurityCheckType>): (req: express.Request, res: express.Response, next: express.NextFunction) => void {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
if ( checkIfConnected && (req.session.profile === null || req.session.profile === undefined) ) {
return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED);
private isConnected(checkIfConnected: boolean, req: express.Request): boolean {
return checkIfConnected && req.session.profile !== null && req.session.profile !== undefined;
}
let isAllowed = checkTypes.length === 0;
if ( !isAllowed ) {
for ( const checkType of checkTypes ) {
private async checkType(checkType: SecurityCheckType, req: express.Request): Promise<boolean> {
try {
switch ( String(checkType) ) {
case SecurityCheckType.TEACHING_STAFF:
isAllowed = isAllowed || req.session.profile.isTeachingStaff;
break;
return req.session.profile.isTeachingStaff;
case SecurityCheckType.ASSIGNMENT_STAFF:
isAllowed = isAllowed || await AssignmentManager.isUserAllowedToAccessAssignment(req.boundParams.assignment!, req.session.profile);
break;
return await AssignmentManager.isUserAllowedToAccessAssignment(req.boundParams.assignment!, req.session.profile);
case SecurityCheckType.ASSIGNMENT_IS_PUBLISHED:
isAllowed = isAllowed || (req.boundParams.assignment?.published ?? false);
break;
return req.boundParams.assignment?.published ?? false;
case SecurityCheckType.EXERCISE_SECRET:
isAllowed = isAllowed || (req.headers.exercisesecret as string | undefined) === req.boundParams.exercise!.secret;
break;
return (req.headers.exercisesecret as string | undefined) === req.boundParams.exercise!.secret;
default:
break;
return false;
}
} catch ( e ) {
logger.error('Security check failed !!! => ' + e);
isAllowed = isAllowed || false;
return false;
}
}
// First check if connected then check if at least ONE rule match. It's NOT an AND but it's a OR function.
check(checkIfConnected: boolean, ...checkTypes: Array<SecurityCheckType>): (req: express.Request, res: express.Response, next: express.NextFunction) => void {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
if ( !this.isConnected(checkIfConnected, req) ) {
return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED);
}
const isAllowed: boolean = checkTypes.length === 0 ? true : checkTypes.find(async (checkType) => this.checkType(checkType, req)) !== undefined;
if ( !isAllowed ) {
return req.session.sendResponse(res, StatusCodes.FORBIDDEN);
}
......
......@@ -103,7 +103,7 @@ class ExerciseRoutes implements RoutesManager {
let suffix: number = 0;
do {
try {
repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as Gitlab.ProjectSchema).id, this.getExerciseName(assignment, params.members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises);
repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as Gitlab.ProjectSchema).id, this.getExerciseName(assignment, members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises);
break;
} catch ( error ) {
logger.error('Repo creation error');
......@@ -133,12 +133,12 @@ class ExerciseRoutes implements RoutesManager {
}
private async createExercise(req: express.Request, res: express.Response) {
const params: { members: Array<GitlabUser> } = req.body;
const params: { members: Array<Gitlab.UserSchema> } = req.body;
params.members = [ await req.session.profile.gitlabProfile.value, ...params.members ].removeObjectDuplicates(gitlabUser => gitlabUser.id);
const assignment: Assignment = req.boundParams.assignment!;
const reachedLimitUsers: Array<GitlabUser> = await this.checkExerciseLimit(assignment, params.members);
const reachedLimitUsers: Array<Gitlab.UserSchema> = await this.checkExerciseLimit(assignment, params.members);
if ( reachedLimitUsers.length > 0 ) {
req.session.sendResponse(res, StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE, reachedLimitUsers, 'Max exercise per assignment reached', DojoStatusCode.MAX_EXERCISE_PER_ASSIGNMENT_REACHED);
return;
......@@ -147,7 +147,7 @@ class ExerciseRoutes implements RoutesManager {
const exerciseId: string = uuidv4();
const secret: string = uuidv4();
const repository: GitlabRepository | undefined = await this.createExerciseRepository(assignment, params.members, exerciseId, req, res);
const repository: Gitlab.ProjectSchema | undefined = await this.createExerciseRepository(assignment, params.members, exerciseId, req, res);
if ( !repository ) {
return;
......@@ -164,14 +164,14 @@ class ExerciseRoutes implements RoutesManager {
await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
} catch ( error ) {
GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
await GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
return;
}
try {
await GitlabManager.updateFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)');
} catch ( error ) {
GlobalHelper.repositoryCreationError('CI file update error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
await GlobalHelper.repositoryCreationError('CI file update error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
return;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment