From 69046ab5d27ef831c093e3d6127bddffab9135bc Mon Sep 17 00:00:00 2001 From: Sam Machin Date: Wed, 7 Jan 2026 13:01:44 +0000 Subject: [PATCH] Feat/admin numbers carriers (#532) * add JAMBONES_ADMIN_CARRIER check to limit creating carriers and numbers * fix logic --- lib/routes/api/accounts.js | 9 +++++++++ lib/routes/api/phone-numbers.js | 5 +++++ lib/routes/api/sip-gateways.js | 6 ++++++ lib/routes/api/voip-carriers.js | 11 +++++++++++ 4 files changed, 31 insertions(+) diff --git a/lib/routes/api/accounts.js b/lib/routes/api/accounts.js index 0683b43..f3d02c6 100644 --- a/lib/routes/api/accounts.js +++ b/lib/routes/api/accounts.js @@ -140,6 +140,11 @@ router.put('/:sid/VoipCarriers/:voip_carrier_sid', async(req, res) => { const logger = req.app.locals.logger; try { + if (process.env.JAMBONES_ADMIN_CARRIER == 1 && (!req.user.hasScope('service_provider') + && !req.user.hasScope('admin'))) { + throw new DbErrorBadRequest('insufficient privileges'); + } + const sid = parseVoipCarrierSid(req); const account_sid = parseAccountSid(req); await validateRequest(req, account_sid); @@ -159,6 +164,10 @@ router.post('/:sid/VoipCarriers', async(req, res) => { const logger = req.app.locals.logger; const payload = req.body; try { + if (process.env.JAMBONES_ADMIN_CARRIER == 1 && (!req.user.hasScope('service_provider') + || !!req.user.hasScope('admin'))) { + throw new DbErrorBadRequest('insufficient privileges'); + } const account_sid = parseAccountSid(req); await validateRequest(req, account_sid); // Set the service_provder_sid to the relevent value for the account diff --git a/lib/routes/api/phone-numbers.js b/lib/routes/api/phone-numbers.js index a87d75a..3d22869 100644 --- a/lib/routes/api/phone-numbers.js +++ b/lib/routes/api/phone-numbers.js @@ -19,6 +19,11 @@ const hasWhitespace = (str) => /\s/.test(str); /* check for required fields when adding */ async function validateAdd(req) { try { + if (process.env.JAMBONES_ADMIN_CARRIER == 1 && (!req.user.hasScope('service_provider') + && !req.user.hasScope('admin'))) { + throw new DbErrorBadRequest('insufficient privileges'); + } + /* account level user can only act on carriers associated to his/her account */ if (req.user.hasAccountAuth) { req.body.account_sid = req.user.account_sid; diff --git a/lib/routes/api/sip-gateways.js b/lib/routes/api/sip-gateways.js index 1246270..199b2da 100644 --- a/lib/routes/api/sip-gateways.js +++ b/lib/routes/api/sip-gateways.js @@ -45,6 +45,12 @@ const validate = async(req, sid) => { const {netmask, ipv4, inbound, outbound} = req.body; let voip_carrier_sid; + if (process.env.JAMBONES_ADMIN_CARRIER == 1 && (!req.user.hasScope('service_provider') + && !req.user.hasScope('admin'))) { + throw new DbErrorBadRequest('insufficient privileges'); + } + + if (sid) { const gateway = await lookupSipGatewayBySid(sid); if (!gateway) throw new DbErrorBadRequest('invalid sip_gateway_sid'); diff --git a/lib/routes/api/voip-carriers.js b/lib/routes/api/voip-carriers.js index f1e8753..a94b3a7 100644 --- a/lib/routes/api/voip-carriers.js +++ b/lib/routes/api/voip-carriers.js @@ -9,6 +9,11 @@ const { parseVoipCarrierSid } = require('./utils'); const validate = async(req) => { const {lookupAppBySid, lookupAccountBySid} = req.app.locals; + if (process.env.JAMBONES_ADMIN_CARRIER == 1 && (!req.user.hasScope('service_provider') + && !req.user.hasScope('admin'))) { + throw new DbErrorBadRequest('insufficient privileges'); + } + /* account level user can only act on carriers associated to his/her account */ if (req.user.hasAccountAuth) { req.body.account_sid = req.user.account_sid; @@ -45,6 +50,12 @@ const validateUpdate = async(req, sid) => { const validateDelete = async(req, sid) => { const {lookupCarrierBySid} = req.app.locals; + if (process.env.JAMBONES_ADMIN_CARRIER == 1 && (!req.user.hasScope('service_provider') + && !req.user.hasScope('admin'))) { + throw new DbErrorBadRequest('insufficient privileges'); + } + + if (req.user.hasAccountAuth) { /* can only update carriers for the user's account */ const carrier = await lookupCarrierBySid(sid);