diff --git a/models/Project.js b/models/Project.js index d169594..ba12cc7 100755 --- a/models/Project.js +++ b/models/Project.js @@ -23,11 +23,6 @@ const schema = new Schema({ type: Number, required: true }, - repoUrls: { - type: [String], - required: true - }, - repoId: {type: String, required: false}, rocketChatWebhook: {type: String, required: false}, rocketChatChannelName: {type: String, required: false}, archived: {type: String, required: true}, diff --git a/models/Repository.js b/models/Repository.js new file mode 100644 index 0000000..e9a8f1a --- /dev/null +++ b/models/Repository.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 TopCoder, Inc. All rights reserved. + */ +'use strict'; + +/** + * Schema for project and repository mapping. + * @author TCSCODER + * @version 1.0 + */ +const dynamoose = require('dynamoose'); + +const Schema = dynamoose.Schema; + +const schema = new Schema({ + id: { + type: String, + hashKey: true, + required: true + }, + projectId: { + type: String, + required: true, + index: { + global: true, + project: true, + name: 'ProjectIdIndex' + } + }, + url: { + type: String, + required: true, + index: { + global: true, + project: true, + rangKey: 'archived', + name: 'URLIndex' + } + }, + archived: {type: String, required: true}, + repoId: {type: String, required: false}, + registeredWebhookId: {type: String, required: false} +}); + +module.exports = schema; diff --git a/models/index.js b/models/index.js index d7e0cae..598ba73 100755 --- a/models/index.js +++ b/models/index.js @@ -46,6 +46,7 @@ const PullRequestCreatedEvent = require('./PullRequestCreatedEvent'); const PullRequestClosedEvent = require('./PullRequestClosedEvent'); const LabelUpdatedEvent = require('./LabelUpdatedEvent'); const Project = require('./Project'); +const Repository = require('./Repository'); module.exports = { IssueCreatedEvent, @@ -58,5 +59,6 @@ module.exports = { PullRequestClosedEvent, LabelUpdatedEvent, Project: dynamoose.model('Topcoder_X.Project', Project), + Repository: dynamoose.model('Topcoder_X.Repository', Repository), IssueClosedEvent }; diff --git a/routes/middlewares/RepositoryFilter.js b/routes/middlewares/RepositoryFilter.js index 4e7de47..324c767 100755 --- a/routes/middlewares/RepositoryFilter.js +++ b/routes/middlewares/RepositoryFilter.js @@ -8,10 +8,9 @@ * @version 1.0 */ 'use strict'; -const _ = require('lodash'); const logger = require('../../utils/logger'); -const Project = require('../../models').Project; +const Repository = require('../../models').Repository; const dbHelper = require('../../utils/db-helper'); module.exports = (provider) => async (req, res, next) => { @@ -23,12 +22,10 @@ module.exports = (provider) => async (req, res, next) => { const repo = req.body.project || {}; repoNames = [repo.homepage, repo.http_url, repo.url, repo.ssh_url, repo.web_url]; } - const projects = await dbHelper.scan(Project, { - archived: 'false' - }); - const found = _.some(projects, (project) => _.intersection(repoNames, project.repoUrls).length > 0); - if (found) { - return next(); + for (const repoName of repoNames) { //eslint-disable-line + if (await dbHelper.queryOneActiveRepository(Repository, repoName)) { + return next(); + } } // ignore this repo diff --git a/routes/middlewares/SecurityChecker.js b/routes/middlewares/SecurityChecker.js index 51f16a4..3b47bc8 100755 --- a/routes/middlewares/SecurityChecker.js +++ b/routes/middlewares/SecurityChecker.js @@ -9,33 +9,31 @@ */ 'use strict'; const crypto = require('crypto'); -const _ = require('lodash'); const logger = require('../../utils/logger'); const Project = require('../../models').Project; +const Repository = require('../../models').Repository; const dbHelper = require('../../utils/db-helper'); module.exports = (provider) => async (req, res, next) => { let isValid = false; const params = req.body; if (provider === 'github') { - const projectDetails = await dbHelper.scan(Project, { - repoUrls: { contains: params.repository.html_url } - }); - _.forEach(projectDetails, (projectDetail) => { + const repositories = await dbHelper.queryRepositories(Repository, params.repository.html_url); + for (const repository of repositories) { // eslint-disable-line + const projectDetail = await dbHelper.queryOneProject(Project, repository.projectId); const hash = crypto.createHmac('sha1', projectDetail.secretWebhookKey).update(req.rawBody).digest('hex'); if (`sha1=${hash}` === req.header('X-Hub-Signature')) { isValid = true; } - }); + } } else if (provider === 'gitlab') { - const projectDetails = await dbHelper.scan(Project, { - repoUrls: { contains: params.project.web_url } - }); - _.forEach(projectDetails, (projectDetail) => { // eslint-disable-line lodash/prefer-filter + const repositories = await dbHelper.queryRepositories(Repository, params.project.web_url); + for (const repository of repositories) { // eslint-disable-line + const projectDetail = await dbHelper.queryOneProject(Project, repository.projectId); if (projectDetail.secretWebhookKey === req.header('X-Gitlab-Token')) { isValid = true; } - }); + } } else { // unknown provider return next(); diff --git a/utils/db-helper.js b/utils/db-helper.js index f67ae4e..44902df 100644 --- a/utils/db-helper.js +++ b/utils/db-helper.js @@ -26,6 +26,72 @@ async function scan(model, scanParams) { }); } +/** + * Query active repositories + * @param {Object} model the dynamoose model + * @param {String} url the repository url + * @returns {Promise} + */ +async function queryRepositories(model, url) { + return await new Promise((resolve, reject) => { + model.query({ + url + }) + .all() + .exec((err, result) => { + if (err) { + return reject(err); + } + return resolve(result); + }); + }); +} + +/** + * Query one active repository + * @param {Object} model the dynamoose model + * @param {String} url the repository url + * @returns {Promise} + */ +async function queryOneActiveRepository(model, url) { + return await new Promise((resolve, reject) => { + model.queryOne({ + url, + archived: 'false' + }) + .all() + .exec((err, result) => { + if (err) { + return reject(err); + } + return resolve(result); + }); + }); +} + +/** + * Query one project + * @param {Object} model the dynamoose model + * @param {String} projectId the project id + * @returns {Promise} + */ +async function queryOneProject(model, projectId) { + return await new Promise((resolve, reject) => { + model.queryOne('id') + .eq(projectId) + .all() + .exec((err, result) => { + if (err) { + return reject(err); + } + return resolve(result); + }); + }); +} + module.exports = { - scan + scan, + queryRepositories, + queryOneActiveRepository, + queryOneProject };