Minimize boilerplate and new method of saving services source with yaml. Basic testing also done

pull/1/head
Orion Stark 5 years ago
parent f3f13a3fae
commit 43890c342e
  1. 22
      app/gateway_conf.yml
  2. 4
      app/src/core/index.js
  3. 13
      app/src/core/request_forwarding.js
  4. 102
      app/src/core/request_resolver.js
  5. 4
      app/src/data/models/index.js
  6. 2
      app/src/data/models/logs/schema.js
  7. 5
      app/src/helpers/index.js
  8. 3
      app/src/helpers/validation/ip_whitelist.js
  9. 0
      app/src/middlewares/gateway_management_middleware.js
  10. 8
      app/src/middlewares/gateway_middleware.js
  11. 1
      app/utils/database.js
  12. 21
      package-lock.json
  13. 3
      package.json

@ -0,0 +1,22 @@
services:
main-services:
port: 3422
base_url: http://localhost
endpoints:
get:
- /user
- /item
- /testing
put:
- /user/*/*/fdf
- /item/:query/:query
delete:
- /user/
- /item/
post:
- /user/create
- /item/create
enable_auth: false
ip_blacklist:
- "103.77.77.91"
- "103.77.78.111"

@ -1,7 +1,7 @@
const mongoose = require('mongoose') const mongoose = require('mongoose')
const { forwardRequest } = require('./request_forwarding') const { forwardRequest } = require('./request_forwarding')
const { logModel, serviceModel } = require('../data/models/index')(mongoose) const { logModel } = require('../data/models/index')(mongoose)
const { resolveRequest } = require('./request_resolver')(logModel, serviceModel) const { resolveRequest } = require('./request_resolver')(logModel)
const { resolveResponse } = require('./response_resolver') const { resolveResponse } = require('./response_resolver')
module.exports = { module.exports = {

@ -1,37 +1,34 @@
const axios = require('axios').default const axios = require('axios').default
function forwardRequest(request) { function forwardRequest(request, service) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const method = request.method.toLowerCase() const method = request.method.toLowerCase()
if ( method === 'get' ) { if ( method === 'get' ) {
axios({ axios({
method: method, method: method,
baseURL: request.host, baseURL: service.base_url + ':' + service.port,
url: request.path, url: request.path,
responseType: 'json' responseType: 'json'
}) })
.then(response => { .then(response => {
console.log(response)
resolve(response) resolve(response)
}) })
.catch(err => { .catch(err => {
console.log(err)
reject(err) reject(err)
}) })
} else { } else {
axios({ axios({
method: method, method: method,
baseURL: request.host, baseURL: service.base_url + ':' + service.port,
url: request.path, url: request.path,
responseType: 'json', responseType: 'json',
data: request.body data: request.body,
params: request.params
}) })
.then(response => { .then(response => {
console.log(response)
resolve(response) resolve(response)
}) })
.catch(err => { .catch(err => {
console.log(err)
reject(err) reject(err)
}) })
} }

@ -1,65 +1,83 @@
const {validateAPIKey, grabRequest} = require('../helpers/index') // Helpers const {validateAPIKey, grabRequest} = require('../helpers/index') // Helpers
const fs = require('fs')
const yaml = require('yaml')
function __resolveRequest(req, logModel, serviceModel, callback) {
function __getServiceInformation(service_name) {
return new Promise((resolve, reject) => {
const file = fs.readFileSync('./app/gateway_conf.yml', 'utf8')
const conf = yaml.parse(file)
if ( conf.services.hasOwnProperty(service_name) ) {
resolve(conf.services[service_name])
} else {
const err = {
type: 'NOT_FOUND',
module_source: 'request_resolver',
message: 'Service method is not found.'
}
reject(err)
}
})
}
function __resolveRequest(req, logModel, callback) {
let request = grabRequest(req) let request = grabRequest(req)
if ( validateAPIKey(request.api_key) ) { __getServiceInformation(request.app_id || '')
serviceModel.getByID(request.app_id) .then(service => {
.then(result => { let flag = false
if ( result ) { const availableEndPoints = service.endpoints[request.method.toLowerCase()] || []
let flag = false const splittedRequestPath = request.path.replace(/^\/|\/$/g, '').split('/')
for ( let i = 0; i < result.resourcePaths.length; i++ ) { for ( let i = 0; i < availableEndPoints.length; i++ ) {
if ( request.path === result.resourcePaths[i].path let splittedEndPointPath = availableEndPoints[i].replace(/^\/|\/$/g, '').split('/')
&& request.method == result.resourcePaths[i].method) { if ( splittedRequestPath.length === splittedEndPointPath.length ) {
flag = true let fractalCheckFlag = true
for ( let j = 0; j < splittedEndPointPath.length; j++ ) {
if ( splittedEndPointPath[j] !== splittedRequestPath[j] && splittedEndPointPath[j] !== '*' ) {
fractalCheckFlag = false
break break
} }
} }
if ( flag ) { if ( fractalCheckFlag ) {
logModel.addLog(new logModel({ flag = true
path: request.path, break
service: request.app_id,
ip_address: request.ip_address
}))
callback(result, request, null)
} else {
const err = {
type: 'UNAUTHORIZED',
module_source: 'request_resolver',
message: 'Request method is not found.'
}
callback(null, null, err)
} }
}
}
if ( service.enable_auth && !validateAPIKey(request.api_key) ) {
const err = {
type: 'UNAUTHORIZED',
module_source: 'request_resolver',
message: 'You\'re not allowed to do this action.'
}
callback(null, null, err)
} else {
if ( flag ) {
logModel.addLog(new logModel({
path: request.path,
service: request.app_id,
ip_address: request.ip_address
}))
callback(request, service, null)
} else { } else {
const err = { const err = {
type: 'NOT_FOUND', type: 'NOT_FOUND',
module_source: 'request_resolver', module_source: 'request_resolver',
message: 'Host not found in the database' message: 'Request method is not found.'
} }
callback(null, null, err) callback(null, null, err)
} }
})
.catch(_ => {
const err = {
type: 'SERVER_ERROR',
module_source: 'request_resolver',
message: 'Internal server Error. Please back later.'
}
callback(null, null, err)
})
} else {
const err = {
type: 'UNAUTHORIZED',
module_source: 'request_resolver',
message: 'You\'re not allowed to do this action.'
} }
})
.catch(err => {
console.log(err)
callback(null, null, err) callback(null, null, err)
} })
} }
module.exports = (logModel, serviceModel) => { module.exports = (logModel) => {
return { return {
resolveRequest: (req, callback) => { resolveRequest: (req, callback) => {
return __resolveRequest(req, logModel, serviceModel, callback) return __resolveRequest(req, logModel, callback)
} }
} }

@ -1,12 +1,10 @@
const logModel = require('./logs/index') const logModel = require('./logs/index')
const serviceModel = require('./services/index')
function __getLogModel(mongoose) { return logModel(mongoose) } function __getLogModel(mongoose) { return logModel(mongoose) }
function __getServiceModel(mongoose) { return serviceModel(mongoose) } function __getServiceModel(mongoose) { return serviceModel(mongoose) }
module.exports = (mongoose) => { module.exports = (mongoose) => {
return { return {
logModel: __getLogModel(mongoose), logModel: __getLogModel(mongoose)
serviceModel: __getServiceModel(mongoose)
} }
} }

@ -2,7 +2,7 @@ module.exports = (mongoose) => {
return new mongoose.Schema({ return new mongoose.Schema({
request_time: {type: Date, default: new Date()}, request_time: {type: Date, default: new Date()},
path: {type: String, required: true}, path: {type: String, required: true},
service: {type: mongoose.Schema.Types.ObjectId, ref: 'services', required: true}, service: {type: String, required: true},
ip_address: {type: String, required: true} ip_address: {type: String, required: true}
}, {collection: 'logs'}) }, {collection: 'logs'})
} }

@ -1,6 +1,3 @@
const { validateAPIKey } = require('./validation/http_signature_validation') const { validateAPIKey } = require('./validation/http_signature_validation')
const { grabRequest } = require('./webhooks/http_headers_grab') const { grabRequest } = require('./webhooks/http_headers_grab')
module.exports = { validateAPIKey, grabRequest }
module.exports = {
validateAPIKey, grabRequest
}

@ -1,3 +0,0 @@
/**
* IP whitelist module
*/

@ -3,9 +3,9 @@ const { forwardRequest,
resolveResponse } = require('../core/index') resolveResponse } = require('../core/index')
const router = require('express').Router() const router = require('express').Router()
router.all('/api/*', (req, res, next) => { router.all('*', (req, res) => {
resolveResponse(res) resolveRequest(req, (request, service, error) => {
resolveRequest(req, (result, request, error) => { resolveResponse(res)
if ( error ) { if ( error ) {
let status_code let status_code
if ( error.hasOwnProperty('type') ) { if ( error.hasOwnProperty('type') ) {
@ -21,7 +21,7 @@ router.all('/api/*', (req, res, next) => {
} }
res.status(status_code).json(error) res.status(status_code).json(error)
} else { } else {
forwardRequest(request) forwardRequest(request, service)
.then(response => { .then(response => {
res.json(response) res.json(response)
}) })

@ -7,7 +7,6 @@ module.exports = {
console.log('Connecting to database') console.log('Connecting to database')
mongoose.connect(`mongodb://localhost:27017/${DB_NAME}`, { useNewUrlParser: true, useUnifiedTopology: true }) mongoose.connect(`mongodb://localhost:27017/${DB_NAME}`, { useNewUrlParser: true, useUnifiedTopology: true })
.then(result => { .then(result => {
console.log(result)
console.log('Connected to database') console.log('Connected to database')
}) })
.catch(err => { .catch(err => {

21
package-lock.json generated

@ -4,6 +4,14 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@babel/runtime": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz",
"integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
},
"accepts": { "accepts": {
"version": "1.3.7", "version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@ -602,6 +610,11 @@
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
"integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==" "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA=="
}, },
"regenerator-runtime": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
},
"regexp-clone": { "regexp-clone": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
@ -745,6 +758,14 @@
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz", "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz",
"integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==" "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg=="
},
"yaml": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz",
"integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==",
"requires": {
"@babel/runtime": "^7.6.3"
}
} }
} }
} }

@ -19,6 +19,7 @@
"helmet": "^3.21.2", "helmet": "^3.21.2",
"mongoose": "^5.8.7", "mongoose": "^5.8.7",
"morgan": "^1.9.1", "morgan": "^1.9.1",
"redis": "^2.8.0" "redis": "^2.8.0",
"yaml": "^1.7.2"
} }
} }

Loading…
Cancel
Save