mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-02-15 02:39:35 +00:00
Add schema validation to create-call req.body, validate app_json via verb-specifications (#488)
* Add schema for create-call, validate app_json via verb-specifications * trigger new build --------- Co-authored-by: Markus Frindt <m.frindt@cognigy.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# jambones-feature-server 
|
# jambonz-feature-server 
|
||||||
|
|
||||||
This application implements the core feature server of the jambones platform.
|
This application implements the core feature server of the jambones platform.
|
||||||
|
|
||||||
|
|||||||
@@ -5,27 +5,47 @@ const CallInfo = require('../../session/call-info');
|
|||||||
const {CallDirection, CallStatus} = require('../../utils/constants');
|
const {CallDirection, CallStatus} = require('../../utils/constants');
|
||||||
const uuidv4 = require('uuid-random');
|
const uuidv4 = require('uuid-random');
|
||||||
const SipError = require('drachtio-srf').SipError;
|
const SipError = require('drachtio-srf').SipError;
|
||||||
|
const { validationResult } = require('express-validator');
|
||||||
|
const { validate } = require('@jambonz/verb-specifications');
|
||||||
const sysError = require('./error');
|
const sysError = require('./error');
|
||||||
const HttpRequestor = require('../../utils/http-requestor');
|
const HttpRequestor = require('../../utils/http-requestor');
|
||||||
const WsRequestor = require('../../utils/ws-requestor');
|
const WsRequestor = require('../../utils/ws-requestor');
|
||||||
const RootSpan = require('../../utils/call-tracer');
|
const RootSpan = require('../../utils/call-tracer');
|
||||||
const dbUtils = require('../../utils/db-utils');
|
const dbUtils = require('../../utils/db-utils');
|
||||||
const { mergeSdpMedia, extractSdpMedia } = require('../../utils/sdp-utils');
|
const { mergeSdpMedia, extractSdpMedia } = require('../../utils/sdp-utils');
|
||||||
|
const { createCallSchema } = require('../schemas/create-call');
|
||||||
|
|
||||||
router.post('/', async(req, res) => {
|
router.post('/',
|
||||||
|
createCallSchema,
|
||||||
|
async(req, res) => {
|
||||||
|
const errors = validationResult(req);
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
return res.status(400).json({ errors: errors.array() });
|
||||||
|
}
|
||||||
const {logger} = req.app.locals;
|
const {logger} = req.app.locals;
|
||||||
const accountSid = req.body.account_sid;
|
const accountSid = req.body.account_sid;
|
||||||
const {srf} = require('../../..');
|
const {srf} = require('../../..');
|
||||||
|
|
||||||
|
const app_json = req.body['app_json'];
|
||||||
|
try {
|
||||||
|
// app_json is created only by api-server.
|
||||||
|
if (app_json) {
|
||||||
|
// if available, delete from req before creating task
|
||||||
|
delete req.body.app_json;
|
||||||
|
// validate possible app_json via verb-specifications
|
||||||
|
validate(logger, JSON.parse(app_json));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug({ err }, `invalid app_json: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug({body: req.body}, 'got createCall request');
|
logger.debug({body: req.body}, 'got createCall request');
|
||||||
try {
|
try {
|
||||||
let uri, cs, to;
|
let uri, cs, to;
|
||||||
// app_json is creaeted by only api-server.
|
|
||||||
// if it available, take it and delete before creating task
|
|
||||||
const app_json = req.body.app_json;
|
|
||||||
delete req.body.app_json;
|
|
||||||
const restDial = makeTask(logger, { 'rest:dial': req.body });
|
const restDial = makeTask(logger, { 'rest:dial': req.body });
|
||||||
restDial.appJson = app_json;
|
restDial.appJson = app_json;
|
||||||
|
|
||||||
const {lookupAccountDetails, lookupCarrierByPhoneNumber, lookupCarrier} = dbUtils(logger, srf);
|
const {lookupAccountDetails, lookupCarrierByPhoneNumber, lookupCarrier} = dbUtils(logger, srf);
|
||||||
const {
|
const {
|
||||||
lookupAppBySid
|
lookupAppBySid
|
||||||
|
|||||||
114
lib/http-routes/schemas/create-call.js
Normal file
114
lib/http-routes/schemas/create-call.js
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
const { checkSchema } = require('express-validator');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @path api-server {{base_url}}/v1/Accounts/:account_sid/Calls
|
||||||
|
* @see https://api.jambonz.org/#243a2edd-7999-41db-bd0d-08082bbab401
|
||||||
|
*/
|
||||||
|
const createCallSchema = checkSchema({
|
||||||
|
application_sid: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
isLength: { options: { min: 36, max: 36 } },
|
||||||
|
errorMessage: 'Invalid application_sid',
|
||||||
|
},
|
||||||
|
answerOnBridge: {
|
||||||
|
isBoolean: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid answerOnBridge',
|
||||||
|
},
|
||||||
|
from: {
|
||||||
|
errorMessage: 'Invalid from',
|
||||||
|
isString: true,
|
||||||
|
isLength: {
|
||||||
|
options: { min: 1, max: 256 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fromHost: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid fromHost',
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
errorMessage: 'Invalid to',
|
||||||
|
isObject: true,
|
||||||
|
},
|
||||||
|
callerName: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid callerName',
|
||||||
|
},
|
||||||
|
amd: {
|
||||||
|
isObject: true,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
isObject: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid tag',
|
||||||
|
},
|
||||||
|
'tag.*': {
|
||||||
|
trim: true,
|
||||||
|
escape: true,
|
||||||
|
stripLow: true,
|
||||||
|
},
|
||||||
|
app_json: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid app_json',
|
||||||
|
},
|
||||||
|
account_sid: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid account_sid',
|
||||||
|
isLength: { options: { min: 36, max: 36 } },
|
||||||
|
},
|
||||||
|
timeout: {
|
||||||
|
isInt: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid timeout',
|
||||||
|
},
|
||||||
|
timeLimit: {
|
||||||
|
isInt: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid timeLimit',
|
||||||
|
},
|
||||||
|
call_hook: {
|
||||||
|
isObject: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid call_hook',
|
||||||
|
},
|
||||||
|
call_status_hook: {
|
||||||
|
isObject: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid call_status_hook',
|
||||||
|
},
|
||||||
|
speech_synthesis_vendor: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid speech_synthesis_vendor',
|
||||||
|
},
|
||||||
|
speech_synthesis_language: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid speech_synthesis_language',
|
||||||
|
},
|
||||||
|
speech_synthesis_voice: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid speech_synthesis_voice',
|
||||||
|
},
|
||||||
|
speech_recognizer_vendor: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid speech_recognizer_vendor',
|
||||||
|
},
|
||||||
|
speech_recognizer_language: {
|
||||||
|
isString: true,
|
||||||
|
optional: true,
|
||||||
|
errorMessage: 'Invalid speech_recognizer_language',
|
||||||
|
}
|
||||||
|
}, ['body']);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createCallSchema
|
||||||
|
};
|
||||||
35
package-lock.json
generated
35
package-lock.json
generated
@@ -33,6 +33,7 @@
|
|||||||
"drachtio-fsmrf": "^3.0.27",
|
"drachtio-fsmrf": "^3.0.27",
|
||||||
"drachtio-srf": "^4.5.29",
|
"drachtio-srf": "^4.5.29",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"express-validator": "^7.0.1",
|
||||||
"ip": "^1.1.8",
|
"ip": "^1.1.8",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"parse-url": "^8.1.0",
|
"parse-url": "^8.1.0",
|
||||||
@@ -5836,6 +5837,18 @@
|
|||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-validator": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"validator": "^13.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express/node_modules/debug": {
|
"node_modules/express/node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
@@ -10238,6 +10251,14 @@
|
|||||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/validator": {
|
||||||
|
"version": "13.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
|
||||||
|
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@@ -15184,6 +15205,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"express-validator": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==",
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"validator": "^13.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ext": {
|
"ext": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
|
||||||
@@ -18478,6 +18508,11 @@
|
|||||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"validator": {
|
||||||
|
"version": "13.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
|
||||||
|
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ=="
|
||||||
|
},
|
||||||
"vary": {
|
"vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
"drachtio-fsmrf": "^3.0.27",
|
"drachtio-fsmrf": "^3.0.27",
|
||||||
"drachtio-srf": "^4.5.29",
|
"drachtio-srf": "^4.5.29",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"express-validator": "^7.0.1",
|
||||||
"ip": "^1.1.8",
|
"ip": "^1.1.8",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"parse-url": "^8.1.0",
|
"parse-url": "^8.1.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user