Compare commits

...

8 Commits

Author SHA1 Message Date
Dave Horton
ac4ea4b265 reset_admin_password - add option for specifying initial password 2021-07-01 13:55:04 -04:00
Dave Horton
ec6d2d310a lint fix 2021-06-28 13:03:10 -04:00
Dave Horton
7b9390be50 bugfix: prevent an account level api key from creating an admin-level api key 2021-06-28 13:00:35 -04:00
Dave Horton
0589328f24 when provisioning a new account on hosted system, automatically add hello-world and dial-time apps 2021-06-28 10:03:54 -04:00
Dave Horton
f66814fff2 bugfix: reset admin password 2021-06-26 19:29:54 -04:00
Dave Horton
a79f77934e fix bug with seeding predefined carriers 2021-06-26 17:55:57 -04:00
Dave Horton
7325512ab4 add apis for ServiceProvider to get related entities 2021-06-18 13:35:39 -04:00
Dave Horton
0786ad7ea2 handle PUT of VoipCarrier that is associated to a service provider 2021-06-18 12:20:39 -04:00
8 changed files with 137 additions and 74 deletions

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env node
const crypto = require('crypto');
const {promisePool} = require('../lib/db');
const sql = 'INSERT INTO beta_invite_codes (invite_code) VALUES (?);';
const rand_string = (n) => {
if (n <= 0) {
return '';
}
var rs = '';
try {
rs = crypto.randomBytes(Math.ceil(n/2)).toString('hex').slice(0,n);
/* note: could do this non-blocking, but still might fail */
}
catch (ex) {
/* known exception cause: depletion of entropy info for randomBytes */
console.error('Exception generating random string: ' + ex);
/* weaker random fallback */
rs = '';
var r = n % 8, q = (n - r) / 8, i;
for (i = 0; i < q; i++) {
rs += Math.random().toString(16).slice(2);
}
if (r > 0) {
rs += Math.random().toString(16).slice(2, i);
}
}
return rs;
};
const doIt = async(len) => {
for (let i = 0; i < 50; i++) {
const val = rand_string(len).toUpperCase();
await promisePool.execute(sql, [val]);
}
process.exit(0);
};
doIt(6);

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env node
console.log('reset_admin_password');
const {promisePool} = require('../lib/db');
const uuidv4 = require('uuid/v4');
const {generateHashedPassword} = require('../lib/utils/password-utils');
@@ -7,18 +6,22 @@ const sqlInsert = `INSERT into users
(user_sid, name, email, hashed_password, force_change, provider, email_validated)
values (?, ?, ?, ?, ?, ?, ?)
`;
const sqlChangeAdminToken = `UPDATE api_keys set token = ?
WHERE account_sid IS NULL
AND service_provider_sid IS NULL`;
const sqlQueryAccount = 'SELECT * from accounts LIMIT 1';
const sqlAddAccountAdminToken = `INSERT into api_keys (api_key_sid, token, account_sid)
const sqlInsertAdminToken = `INSERT into api_keys
(api_key_sid, token)
values (?, ?)`;
const sqlQueryAccount = 'SELECT * from accounts LEFT JOIN api_keys ON api_keys.account_sid = accounts.account_sid';
const sqlAddAccountToken = `INSERT into api_keys (api_key_sid, token, account_sid)
VALUES (?, ?, ?)`;
const password = process.env.JAMBONES_ADMIN_INITIAL_PASSWORD || 'admin';
console.log(`reset_admin_password, initial admin password is ${password}`);
const doIt = async() => {
const passwordHash = await generateHashedPassword('admin');
const passwordHash = await generateHashedPassword(password);
const sid = uuidv4();
await promisePool.execute('DELETE from users where name = "admin"');
await promisePool.execute(sqlInsert,
await promisePool.execute('DELETE from api_keys where account_sid is null and service_provider_sid is null');
await promisePool.execute(sqlInsert,
[
sid,
'admin',
@@ -29,16 +32,16 @@ const doIt = async() => {
1
]
);
/* reset admin token */
const uuid = uuidv4();
await promisePool.query(sqlChangeAdminToken, [uuid]);
await promisePool.execute(sqlInsertAdminToken, [uuidv4(), uuidv4()]);
/* create admin token for single account */
const api_key_sid = uuidv4();
const token = uuidv4();
const [r] = await promisePool.query(sqlQueryAccount);
await promisePool.execute(sqlAddAccountAdminToken, [api_key_sid, token, r[0].account_sid]);
const [r] = await promisePool.query({sql: sqlQueryAccount, nestTables: true});
if (1 === r.length && r[0].api_keys.api_key_sid === null) {
const api_key_sid = uuidv4();
const token = uuidv4();
const {account_sid} = r[0].accounts;
await promisePool.execute(sqlAddAccountToken, [api_key_sid, token, account_sid]);
}
process.exit(0);
};

View File

@@ -73,19 +73,6 @@ VALUES
('7bae60b3-4237-4baa-a711-30ea3bce19d8', '032d90d5-39e8-41c0-b807-9c88cffba65c', '185.47.148.45', 32, 5060, 1, 0),
('bc933522-18a2-47d8-9ae4-9faa8de4e927', '032d90d5-39e8-41c0-b807-9c88cffba65c', 'outbound.voxbone.com', 32, 5060, 0, 1);
-- Peerless gateways
insert into predefined_sip_gateways (predefined_sip_gateway_sid, predefined_carrier_sid, ipv4, netmask, port, inbound, outbound)
VALUES
('4e23f698-a70a-4616-9bf0-c9dd5ab123af', '17479288-bb9f-421a-89d1-f4ac57af1dca', '208.79.54.182', 32, 5060, 1, 0),
('e5c71c18-0511-41b8-bed9-1ba061bbcf10', '17479288-bb9f-421a-89d1-f4ac57af1dca', '208.79.52.192', 32, 5060, 0, 1),
('226c7471-2f4f-440f-8525-37fd0512bd8b', '17479288-bb9f-421a-89d1-f4ac57af1dca', '208.79.54.185', 32, 5060, 0, 1);
-- 382com gateways
insert into predefined_sip_gateways (predefined_sip_gateway_sid, predefined_carrier_sid, ipv4, netmask, port, inbound, outbound)
VALUES
('23e4c250-8578-4d88-99b5-a7941a58e26f', 'bdf70650-5328-47aa-b3d0-47cb219d9c6e', '64.125.111.10', 32, 5060, 1, 0),
('c726d435-c9a7-4c37-b891-775990a54638', 'bdf70650-5328-47aa-b3d0-47cb219d9c6e', '64.124.67.11', 32, 5060, 0, 1);
-- simwood gateways
insert into predefined_sip_gateways (predefined_sip_gateway_sid, predefined_carrier_sid, ipv4, netmask, port, inbound, outbound)
VALUES

View File

@@ -51,19 +51,6 @@ VALUES
('7bae60b3-4237-4baa-a711-30ea3bce19d8', '032d90d5-39e8-41c0-b807-9c88cffba65c', '185.47.148.45', 32, 5060, 1, 0),
('bc933522-18a2-47d8-9ae4-9faa8de4e927', '032d90d5-39e8-41c0-b807-9c88cffba65c', 'outbound.voxbone.com', 32, 5060, 0, 1);
-- Peerless gateways
insert into predefined_sip_gateways (predefined_sip_gateway_sid, predefined_carrier_sid, ipv4, netmask, port, inbound, outbound)
VALUES
('4e23f698-a70a-4616-9bf0-c9dd5ab123af', '17479288-bb9f-421a-89d1-f4ac57af1dca', '208.79.54.182', 32, 5060, 1, 0),
('e5c71c18-0511-41b8-bed9-1ba061bbcf10', '17479288-bb9f-421a-89d1-f4ac57af1dca', '208.79.52.192', 32, 5060, 0, 1),
('226c7471-2f4f-440f-8525-37fd0512bd8b', '17479288-bb9f-421a-89d1-f4ac57af1dca', '208.79.54.185', 32, 5060, 0, 1);
-- 382com gateways
insert into predefined_sip_gateways (predefined_sip_gateway_sid, predefined_carrier_sid, ipv4, netmask, port, inbound, outbound)
VALUES
('23e4c250-8578-4d88-99b5-a7941a58e26f', 'bdf70650-5328-47aa-b3d0-47cb219d9c6e', '64.125.111.10', 32, 5060, 1, 0),
('c726d435-c9a7-4c37-b891-775990a54638', 'bdf70650-5328-47aa-b3d0-47cb219d9c6e', '64.124.67.11', 32, 5060, 0, 1);
-- simwood gateways
insert into predefined_sip_gateways (predefined_sip_gateway_sid, predefined_carrier_sid, ipv4, netmask, port, inbound, outbound)
VALUES

View File

@@ -1,45 +1,38 @@
const Model = require('./model');
const {getMysqlConnection} = require('../db');
const {promisePool} = require('../db');
const sql = 'SELECT * from phone_numbers WHERE account_sid = ?';
const sqlSP = `SELECT *
FROM phone_numbers
WHERE account_sid IN
(
SELECT account_sid
FROM accounts
WHERE service_provider_sid = ?
)`;
class PhoneNumber extends Model {
constructor() {
super();
}
static retrieveAll(account_sid) {
static async retrieveAll(account_sid) {
if (!account_sid) return super.retrieveAll();
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query(sql, account_sid, (err, results, fields) => {
conn.release();
if (err) return reject(err);
resolve(results);
});
});
});
const [rows] = await promisePool.query(sql, account_sid);
return rows;
}
static async retrieveAllForSP(service_provider_sid) {
const [rows] = await promisePool.query(sqlSP, service_provider_sid);
return rows;
}
/**
* retrieve an application
* retrieve a phone number
*/
static retrieve(sid, account_sid) {
static async retrieve(sid, account_sid) {
if (!account_sid) return super.retrieve(sid);
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query(`${sql} AND phone_number_sid = ?`, [account_sid, sid], (err, results, fields) => {
conn.release();
if (err) return reject(err);
resolve(results);
});
});
});
const [rows] = await promisePool.query(`${sql} AND phone_number_sid = ?`, [account_sid, sid]);
return rows;
}
}
PhoneNumber.table = 'phone_numbers';

View File

@@ -4,7 +4,6 @@ const ApiKey = require('../../models/api-key');
const Account = require('../../models/account');
const decorate = require('./decorate');
const uuidv4 = require('uuid/v4');
const assert = require('assert');
const sysError = require('../error');
const preconditions = {
'add': validateAddToken,
@@ -71,10 +70,7 @@ async function validateDeleteToken(req, sid) {
router.post('/', async(req, res) => {
const logger = req.app.locals.logger;
try {
if ('add' in preconditions) {
assert(typeof preconditions.add === 'function');
await preconditions.add(req);
}
await validateAddToken(req);
const uuid = await ApiKey.make(req.body);
res.status(201).json({sid: uuid, token: req.body.token});
} catch (err) {

View File

@@ -20,6 +20,13 @@ values (?, ?, ?, ?, ?, 0, 'local', ?)`;
const insertAccountSql = `INSERT into accounts
(account_sid, service_provider_sid, name, is_active, webhook_secret, trial_end_date)
values (?, ?, ?, ?, ?, CURDATE() + INTERVAL 21 DAY)`;
const insertWebookSql = `INSERT INTO webhooks (webhook_sid, url, method)
VALUES (?, ?, ?)`;
const insertApplicationSql = `INSERT INTO applications
(application_sid, account_sid, name, call_hook_sid, call_status_hook_sid,
speech_synthesis_vendor, speech_synthesis_language, speech_synthesis_voice,
speech_recognizer_vendor, speech_recognizer_language)
VALUES (?,?,?,?,?,?,?,?,?,?)`;
const queryRootDomainSql = `SELECT root_domain
FROM service_providers
WHERE service_providers.service_provider_sid = ?`;
@@ -281,6 +288,22 @@ router.post('/', async(req, res) => {
userProfile.provider_userid);
}
/* add hello-world and dial-time as starter applications */
const callStatusSid = uuid();
const helloWordSid = uuid();
const dialTimeSid = uuid();
/* 3 webhooks */
await promisePool.execute(insertWebookSql, [callStatusSid, 'https://public-apps.jambonz.us/call-status', 'POST']);
await promisePool.execute(insertWebookSql, [helloWordSid, 'https://public-apps.jambonz.us/hello-world', 'POST']);
await promisePool.execute(insertWebookSql, [dialTimeSid, 'https://public-apps.jambonz.us/dial-time', 'POST']);
/* 2 applications */
await promisePool.execute(insertApplicationSql, [uuid(), userProfile.account_sid, 'hello world',
helloWordSid, callStatusSid, 'google', 'en-US', 'en-US-Wavenet-C', 'google', 'en-US']);
await promisePool.execute(insertApplicationSql, [uuid(), userProfile.account_sid, 'dial time clock',
dialTimeSid, callStatusSid, 'google', 'en-US', 'en-US-Wavenet-C', 'google', 'en-US']);
Object.assign(userProfile, {
pristine: true,
is_active: req.body.provider !== 'local',

View File

@@ -4,6 +4,8 @@ const Webhook = require('../../models/webhook');
const ServiceProvider = require('../../models/service-provider');
const Account = require('../../models/account');
const VoipCarrier = require('../../models/voip-carrier');
const Application = require('../../models/application');
const PhoneNumber = require('../../models/phone-number');
const {hasServiceProviderPermissions, parseServiceProviderSid} = require('./utils');
const sysError = require('../error');
const decorate = require('./decorate');
@@ -31,6 +33,26 @@ router.get('/:sid/Accounts', async(req, res) => {
sysError(logger, res, err);
}
});
router.get('/:sid/Applications', async(req, res) => {
const logger = req.app.locals.logger;
try {
const service_provider_sid = parseServiceProviderSid(req);
const results = await Application.retrieveAll(service_provider_sid);
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid/PhoneNumbers', async(req, res) => {
const logger = req.app.locals.logger;
try {
const service_provider_sid = parseServiceProviderSid(req);
const results = await PhoneNumber.retrieveAllForSP(service_provider_sid);
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid/VoipCarriers', async(req, res) => {
const logger = req.app.locals.logger;
try {
@@ -51,6 +73,18 @@ router.post('/:sid/VoipCarriers', async(req, res) => {
sysError(logger, res, err);
}
});
router.put('/:sid/VoipCarriers/:voip_carrier_sid', async(req, res) => {
const logger = req.app.locals.logger;
try {
const rowsAffected = await VoipCarrier.update(req.params.voip_carrier_sid, req.body);
if (rowsAffected === 0) {
return res.sendStatus(404);
}
res.status(204).end();
} catch (err) {
sysError(logger, res, err);
}
});
router.get(':sid/Acccounts', async(req, res) => {
const logger = req.app.locals.logger;
try {