From ffda2398f4ae0404cc59771d3080780151e06b2d Mon Sep 17 00:00:00 2001 From: Hoan Luu Huu <110280845+xquanluu@users.noreply.github.com> Date: Thu, 24 Apr 2025 17:50:15 +0700 Subject: [PATCH] replace bent by native node fetch (#401) * replace bent by native node fetch * wip * wip * wip --- lib/routes/api/accounts.js | 77 +++---- lib/routes/api/sms-inbound.js | 29 +-- lib/routes/api/utils.js | 56 ++--- lib/utils/dns-utils.js | 57 +++--- lib/utils/email-utils.js | 28 +-- lib/utils/homer-utils.js | 145 +++++++------ lib/utils/jaeger-utils.js | 10 +- lib/utils/oauth-utils.js | 100 ++++++--- lib/utils/speech-utils.js | 165 +++++++++------ lib/utils/stripe-utils.js | 46 ++++- package-lock.json | 338 ------------------------------- package.json | 3 - test/accounts.js | 7 +- test/applications.js | 3 +- test/auth.js | 4 +- test/call-test.js | 11 +- test/clients.js | 3 +- test/email_utils.js | 4 +- test/forgot-password.js | 3 +- test/http-client.js | 172 ++++++++++++++++ test/lcr-carriers-set-entries.js | 3 +- test/lcr-routes.js | 3 +- test/lcrs.js | 3 +- test/login.js | 13 +- test/ms-teams.js | 3 +- test/oauth/gh-get-user.js | 7 +- test/password-settings.js | 3 +- test/phone-numbers.js | 3 +- test/recent-calls.js | 3 +- test/sbcs.js | 3 +- test/service-providers.js | 4 +- test/sip-gateways.js | 3 +- test/smpp-gateways.js | 4 +- test/speech-credentials.js | 4 +- test/system-information.js | 3 +- test/tts-cache.js | 3 +- test/users-view-only.js | 4 +- test/users.js | 5 +- test/utils.js | 3 +- test/voip-carriers.js | 4 +- test/webapp_tests.js | 3 +- 41 files changed, 678 insertions(+), 667 deletions(-) create mode 100644 test/http-client.js diff --git a/lib/routes/api/accounts.js b/lib/routes/api/accounts.js index 7a39c21..0da203c 100644 --- a/lib/routes/api/accounts.js +++ b/lib/routes/api/accounts.js @@ -1,6 +1,5 @@ const router = require('express').Router(); const assert = require('assert'); -const request = require('request'); const {DbErrorBadRequest, DbErrorForbidden, DbErrorUnprocessableRequest} = require('../../utils/errors'); const Account = require('../../models/account'); const Application = require('../../models/application'); @@ -940,24 +939,25 @@ router.post('/:sid/Calls', async(req, res) => { await validateCreateCall(logger, sid, req); updateLastUsed(logger, sid, req).catch((err) => {}); - request({ - url: serviceUrl, + const response = await fetch(serviceUrl, { method: 'POST', - json: true, - body: Object.assign(req.body, {account_sid: sid}) - }, (err, response, body) => { - if (err) { - logger.error(err, `Error sending createCall POST to ${serviceUrl}`); - return res.sendStatus(500); - } - - if (response.statusCode !== 201) { - logger.error({statusCode: response.statusCode}, `Non-success response returned by createCall ${serviceUrl}`); - return res.sendStatus(500); - } - - return res.status(201).json(body); + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(Object.assign(req.body, {account_sid: sid})) }); + + if (!response.ok) { + logger.error(`Error sending createCall POST to ${serviceUrl}`); + return res.sendStatus(500); + } + + if (response.status !== 201) { + logger.error(`Non-success response returned by createCall ${serviceUrl}`); + return res.sendStatus(500); + } + const body = await response.json(); + return res.status(201).json(body); } catch (err) { sysError(logger, res, err); } @@ -1052,12 +1052,20 @@ const updateCall = async(req, res) => { if (call) { const url = `${call.serviceUrl}/${process.env.JAMBONES_API_VERSION || 'v1'}/updateCall/${callSid}`; logger.debug({call, url, payload: req.body}, `updateCall: retrieved call info for call sid ${callSid}`); - request({ - url: url, + const response = await fetch(url, { method: 'POST', - json: true, - body: req.body - }).pipe(res); + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(req.body) + }); + + if (!response.ok) { + logger.error(`Error sending updateCall POST to ${url}`); + return res.sendStatus(500); + } + const body = await response.json(); + return res.status(200).json(body); } else { logger.debug(`updateCall: call not found for call sid ${callSid}`); @@ -1100,22 +1108,19 @@ router.post('/:sid/Messages', async(req, res) => { }; logger.debug({payload}, `sending createMessage API request to to ${serviceUrl}`); updateLastUsed(logger, account_sid, req).catch(() => {}); - request({ - url: serviceUrl, + const response = await fetch(serviceUrl, { method: 'POST', - json: true, - body: payload - }, (err, response, body) => { - if (err) { - logger.error(err, `Error sending createMessage POST to ${serviceUrl}`); - return res.sendStatus(500); - } - if (response.statusCode !== 200) { - logger.error({statusCode: response.statusCode}, `Non-success response returned by createMessage ${serviceUrl}`); - return body ? res.status(response.statusCode).json(body) : res.sendStatus(response.statusCode); - } - res.status(201).json(body); + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) }); + if (!response.ok) { + logger.error(`Error sending createMessage POST to ${serviceUrl}`); + return res.sendStatus(500); + } + const body = await response.json(); + return res.status(response.status).json(body); } catch (err) { sysError(logger, res, err); } diff --git a/lib/routes/api/sms-inbound.js b/lib/routes/api/sms-inbound.js index 792beba..1f79559 100644 --- a/lib/routes/api/sms-inbound.js +++ b/lib/routes/api/sms-inbound.js @@ -1,5 +1,4 @@ const router = require('express').Router(); -const request = require('request'); const getProvider = require('../../utils/sms-provider'); const { v4: uuidv4 } = require('uuid'); const sysError = require('../error'); @@ -122,25 +121,19 @@ router.post('/:provider', async(req, res) => { logger.info({payload, url: serviceUrl}, `sending incomingSms API request to FS at ${serviceUrl}`); - request({ - url: serviceUrl, + const response = await fetch(serviceUrl, { method: 'POST', - json: true, - body: payload, - }, - async(err, response, body) => { - if (err) { - logger.error(err, `Error sending incomingSms POST to ${serviceUrl}`); - return res.sendStatus(500); - } - if (200 === response.statusCode) { - // success - logger.info({body}, 'sending response to provider for incomingSMS'); - return doSendResponse(res, respondFn, body); - } - logger.error({statusCode: response.statusCode}, `Non-success response returned by incomingSms ${serviceUrl}`); - return res.sendStatus(500); + body: JSON.stringify(payload), + headers: {'Content-Type': 'application/json'}, }); + + if (!response.ok) { + logger.error({response}, `Error sending incomingSms POST to ${serviceUrl}`); + return res.sendStatus(500); + } + const body = await response.json(); + logger.info({body}, 'sending response to provider for incomingSMS'); + return doSendResponse(res, respondFn, body); } catch (err) { sysError(logger, res, err); } diff --git a/lib/routes/api/utils.js b/lib/routes/api/utils.js index b9d7a22..4cd4a7d 100644 --- a/lib/routes/api/utils.js +++ b/lib/routes/api/utils.js @@ -1,5 +1,4 @@ const { v4: uuid, validate } = require('uuid'); -const bent = require('bent'); const Account = require('../../models/account'); const {promisePool} = require('../../db'); const {cancelSubscription, detachPaymentMethod} = require('../../utils/stripe-utils'); @@ -11,8 +10,6 @@ values (?, ?)`; const replaceOldSubscriptionSql = `UPDATE account_subscriptions SET effective_end_date = CURRENT_TIMESTAMP, change_reason = ? WHERE account_subscription_sid = ?`; -//const request = require('request'); -//require('request-debug')(request); const setupFreeTrial = async(logger, account_sid, isReturningUser) => { const sid = uuid(); @@ -370,35 +367,44 @@ const checkLimits = async(req, res, next) => { }; const getSubspaceJWT = async(id, secret) => { - const postJwt = bent('https://id.subspace.com', 'POST', 'json', 200); - const jwt = await postJwt('/oauth/token', - { + const response = await fetch('https://id.subspace.com/oauth/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ client_id: id, client_secret: secret, audience: 'https://api.subspace.com/', grant_type: 'client_credentials', - } - ); + }) + }); + if (!response.ok) { + throw new Error(`Failed to get JWT: ${response.status} ${response.statusText}`); + } + const jwt = await response.json(); return jwt.access_token; }; const enableSubspace = async(opts) => { const {subspace_client_id, subspace_client_secret, destination} = opts; const accessToken = await getSubspaceJWT(subspace_client_id, subspace_client_secret); - const postTeleport = bent('https://api.subspace.com', 'POST', 'json', 200); - - const teleport = await postTeleport('/v1/sipteleport', - { + const response = await fetch('https://api.subspace.com/v1/sipteleport', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken}` + }, + body: JSON.stringify({ name: 'Jambonz', destination, status: 'ENABLED' - }, - { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}` - } - ); - + }) + }); + if (!response.ok) { + throw new Error(`Failed to enable teleport: ${response.status} ${response.statusText}`); + } + const teleport = await response.json(); return teleport; }; @@ -406,13 +412,15 @@ const disableSubspace = async(opts) => { const {subspace_client_id, subspace_client_secret, subspace_sip_teleport_id} = opts; const accessToken = await getSubspaceJWT(subspace_client_id, subspace_client_secret); const relativeUrl = `/v1/sipteleport/${subspace_sip_teleport_id}`; - const deleteTeleport = bent('https://api.subspace.com', 'DELETE', 'json', 200); - await deleteTeleport(relativeUrl, {}, - { + const response = await fetch(`https://api.subspace.com${relativeUrl}`, { + method: 'DELETE', + headers: { Authorization: `Bearer ${accessToken}` } - ); - return; + }); + if (!response.ok) { + throw new Error(`Failed to delete teleport: ${response.status} ${response.statusText}`); + } }; const validatePasswordSettings = async(password) => { diff --git a/lib/utils/dns-utils.js b/lib/utils/dns-utils.js index 85afdbc..08174f2 100644 --- a/lib/utils/dns-utils.js +++ b/lib/utils/dns-utils.js @@ -1,6 +1,5 @@ if (!process.env.JAMBONES_HOSTING) return; -const bent = require('bent'); const crypto = require('crypto'); const assert = require('assert'); const domains = new Map(); @@ -26,17 +25,20 @@ const createAuthHeaders = () => { const getDnsDomainId = async(logger, name) => { checkAsserts(); const headers = createAuthHeaders(); - const get = bent(process.env.DME_BASE_URL, 'GET', 'json', headers); - try { - const result = await get('/dns/managed'); - debug(result, 'getDnsDomainId: all domains'); - if (Array.isArray(result.data)) { - const domain = result.data.find((o) => o.name === name); - if (domain) return domain.id; - debug(`getDnsDomainId: failed to find domain ${name}`); - } - } catch (err) { - logger.error({err}, 'Error retrieving domains'); + const response = await fetch(`${process.env.DME_BASE_URL}/dns/managed`, { + method: 'GET', + headers + }); + if (!response.ok) { + logger.error({response}, 'Error retrieving domains'); + return; + } + const result = await response.json(); + debug(result, 'getDnsDomainId: all domains'); + if (Array.isArray(result.data)) { + const domain = result.data.find((o) => o.name === name); + if (domain) return domain.id; + debug(`getDnsDomainId: failed to find domain ${name}`); } }; @@ -80,21 +82,20 @@ const createDnsRecords = async(logger, domain, name, value, ttl = 3600) => { ]; const headers = createAuthHeaders(); const records = [...a_records, ...srv_records]; - const post = bent(process.env.DME_BASE_URL, 'POST', 201, 400, headers); - logger.debug({records}, 'Attemting to create dns records'); - const res = await post(`/dns/managed/${domainId}/records/createMulti`, - [...a_records, ...srv_records]); - - if (201 === res.statusCode) { - const str = await res.text(); - return JSON.parse(str); + const response = await fetch(`${process.env.DME_BASE_URL}/dns/managed/${domainId}/records/createMulti`, { + method: 'POST', + headers, + body: JSON.stringify(records) + }); + if (!response.ok) { + logger.error({response}, 'Error creating records'); + return; } - let body; - try { - body = await res.json(); - } catch (err) { + const result = await response.json(); + logger.debug({result}, 'createDnsRecords: created records'); + if (201 === response.status) { + return result; } - logger.error({headers: res.headers, body}, `Error creating records, status ${res.statusCode}`); } catch (err) { logger.error({err}, 'Error retrieving domains'); } @@ -103,7 +104,6 @@ const createDnsRecords = async(logger, domain, name, value, ttl = 3600) => { const deleteDnsRecords = async(logger, domain, recIds) => { checkAsserts(); const headers = createAuthHeaders(); - const del = bent(process.env.DME_BASE_URL, 'DELETE', 200, headers); try { if (!domains.has(domain)) { const domainId = await getDnsDomainId(logger, domain); @@ -112,7 +112,10 @@ const deleteDnsRecords = async(logger, domain, recIds) => { } const domainId = domains.get(domain); const url = `/dns/managed/${domainId}/records?${recIds.map((r) => `ids=${r}`).join('&')}`; - await del(url); + await fetch(`${process.env.DME_BASE_URL}${url}`, { + method: 'DELETE', + headers + }); return true; } catch (err) { console.error(err); diff --git a/lib/utils/email-utils.js b/lib/utils/email-utils.js index 829e0be..46c879e 100644 --- a/lib/utils/email-utils.js +++ b/lib/utils/email-utils.js @@ -1,7 +1,6 @@ const formData = require('form-data'); const Mailgun = require('mailgun.js'); const mailgun = new Mailgun(formData); -const bent = require('bent'); const validateEmail = (email) => { // eslint-disable-next-line max-len const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; @@ -19,8 +18,9 @@ const emailSimpleText = async(logger, to, subject, text) => { }; const sendEmailByCustomVendor = async(logger, from, to, subject, text) => { - try { - const post = bent('POST', { + const response = await fetch(process.env.CUSTOM_EMAIL_VENDOR_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json', ...((process.env.CUSTOM_EMAIL_VENDOR_USERNAME && process.env.CUSTOM_EMAIL_VENDOR_PASSWORD) && ({ @@ -28,22 +28,22 @@ const sendEmailByCustomVendor = async(logger, from, to, subject, text) => { `${process.env.CUSTOM_EMAIL_VENDOR_USERNAME}:${process.env.CUSTOM_EMAIL_VENDOR_PASSWORD}` ).toString('base64')}` })) - }); - - const res = await post(process.env.CUSTOM_EMAIL_VENDOR_URL, { + }, + body: JSON.stringify({ from, to, subject, text - }); - logger.debug({ - res - }, 'sent email to custom vendor.'); - } catch (err) { - logger.info({ - err - }, 'Error sending email From Custom email vendor'); + }) + }); + if (!response.ok) { + logger.error({response}, 'Error sending email to custom vendor'); + return; } + const res = await response.json(); + logger.debug({ + res + }, 'sent email to custom vendor.'); }; const sendEmailByMailgun = async(logger, from, to, subject, text) => { diff --git a/lib/utils/homer-utils.js b/lib/utils/homer-utils.js index 3932a69..1cfc164 100644 --- a/lib/utils/homer-utils.js +++ b/lib/utils/homer-utils.js @@ -1,15 +1,11 @@ const debug = require('debug')('jambonz:api-server'); -const bent = require('bent'); const basicAuth = (apiKey) => { const header = `Bearer ${apiKey}`; return {Authorization: header}; }; -const postJSON = bent(process.env.HOMER_BASE_URL || 'http://127.0.0.1', 'POST', 'json', 200, 201); -const postPcap = bent(process.env.HOMER_BASE_URL || 'http://127.0.0.1', 'POST', 200, { - 'Content-Type': 'application/json', - 'Accept': 'application/json, text/plain, */*', -}); + const SEVEN_DAYS_IN_MS = (1000 * 3600 * 24 * 7); +const HOMER_BASE_URL = process.env.HOMER_BASE_URL || 'http://127.0.0.1'; const getHomerApiKey = async(logger) => { if (!process.env.HOMER_BASE_URL || !process.env.HOMER_USERNAME || !process.env.HOMER_PASSWORD) { @@ -17,11 +13,21 @@ const getHomerApiKey = async(logger) => { } try { - const obj = await postJSON('/api/v3/auth', { - username: process.env.HOMER_USERNAME, - password: process.env.HOMER_PASSWORD + const response = await fetch(`${HOMER_BASE_URL}/api/v3/auth`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + username: process.env.HOMER_USERNAME, + password: process.env.HOMER_PASSWORD + }) }); - debug(obj); + if (!response.ok) { + logger.error({response}, 'Error retrieving apikey'); + return; + } + const obj = await response.json(); logger.debug({obj}, `getHomerApiKey for user ${process.env.HOMER_USERNAME}`); return obj.token; } catch (err) { @@ -36,28 +42,40 @@ const getHomerSipTrace = async(logger, apiKey, callId) => { } try { const now = Date.now(); - const obj = await postJSON('/api/v3/call/transaction', { - param: { - transaction: { - call: true, - registration: true, - rest: false - }, - orlogic: true, - search: { - '1_call': { - callid: [callId] - }, - '1_registration': { - callid: [callId] - } - }, + const response = await fetch(`${HOMER_BASE_URL}/api/v3/call/transaction`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...basicAuth(apiKey) }, - timestamp: { - from: now - SEVEN_DAYS_IN_MS, - to: now - } - }, basicAuth(apiKey)); + body: JSON.stringify({ + param: { + transaction: { + call: true, + registration: true, + rest: false + }, + orlogic: true, + search: { + '1_call': { + callid: [callId] + }, + '1_registration': { + callid: [callId] + } + }, + }, + timestamp: { + from: now - SEVEN_DAYS_IN_MS, + to: now + } + }) + }); + if (!response.ok) { + logger.error({response}, 'Error retrieving messages'); + return; + } + const obj = await response.json(); return obj; } catch (err) { logger.info({err}, `getHomerSipTrace: Error retrieving messages for callid ${callId}`); @@ -70,34 +88,45 @@ const getHomerPcap = async(logger, apiKey, callIds, method) => { } try { const now = Date.now(); - const stream = await postPcap('/api/v3/export/call/messages/pcap', { - param: { - transaction: { - call: method === 'invite', - registration: method === 'register', - rest: false - }, - orlogic: true, - search: { - ...(method === 'invite' && { - '1_call': { - callid: callIds - } - }) - , - ...(method === 'register' && { - '1_registration': { - callid: callIds - } - }) - }, + const response = await fetch(`${HOMER_BASE_URL}/api/v3/export/call/messages/pcap`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...basicAuth(apiKey) }, - timestamp: { - from: now - SEVEN_DAYS_IN_MS, - to: now - } - }, basicAuth(apiKey)); - return stream; + body: JSON.stringify({ + param: { + transaction: { + call: method === 'invite', + registration: method === 'register', + rest: false + }, + orlogic: true, + search: { + ...(method === 'invite' && { + '1_call': { + callid: callIds + } + }) + , + ...(method === 'register' && { + '1_registration': { + callid: callIds + } + }) + }, + }, + timestamp: { + from: now - SEVEN_DAYS_IN_MS, + to: now + } + }) + }); + if (!response.ok) { + logger.error({response}, 'Error retrieving messages'); + return; + } + return response.body; } catch (err) { logger.info({err}, `getHomerPcap: Error retrieving messages for callid ${callIds}`); } diff --git a/lib/utils/jaeger-utils.js b/lib/utils/jaeger-utils.js index ef9114d..f97ceef 100644 --- a/lib/utils/jaeger-utils.js +++ b/lib/utils/jaeger-utils.js @@ -1,5 +1,4 @@ -const bent = require('bent'); -const getJSON = bent(process.env.JAEGER_BASE_URL || 'http://127.0.0.1', 'GET', 'json', 200); +const JAEGER_BASE_URL = process.env.JAEGER_BASE_URL || 'http://127.0.0.1'; const getJaegerTrace = async(logger, traceId) => { if (!process.env.JAEGER_BASE_URL) { @@ -7,7 +6,12 @@ const getJaegerTrace = async(logger, traceId) => { return null; } try { - return await getJSON(`/api/v3/traces/${traceId}`); + const response = await fetch(`${JAEGER_BASE_URL}/api/traces/${traceId}`); + if (!response.ok) { + logger.error({response}, 'Error retrieving spans'); + return; + } + return await response.json(); } catch (err) { const url = `${process.env.JAEGER_BASE_URL}/api/traces/${traceId}`; logger.error({err, traceId}, `getJaegerTrace: Error retrieving spans from ${url}`); diff --git a/lib/utils/oauth-utils.js b/lib/utils/oauth-utils.js index 2bb16f2..4a98688 100644 --- a/lib/utils/oauth-utils.js +++ b/lib/utils/oauth-utils.js @@ -1,7 +1,4 @@ const assert = require('assert'); -const bent = require('bent'); -const postJSON = bent('POST', 'json', 200); -const getJSON = bent('GET', 'json', 200); const {emailSimpleText} = require('./email-utils'); const {DbErrorForbidden} = require('../utils/errors'); @@ -10,13 +7,26 @@ const doGithubAuth = async(logger, payload) => { try { /* exchange the code for an access token */ - const obj = await postJSON('https://github.com/login/oauth/access_token', { - client_id: payload.oauth2_client_id, - client_secret: process.env.GITHUB_CLIENT_SECRET, - code: payload.oauth2_code, - state: payload.oauth2_state, - redirect_uri: payload.oauth2_redirect_uri + const response = await fetch('https://github.com/login/oauth/access_token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json' + }, + body: JSON.stringify({ + client_id: payload.oauth2_client_id, + client_secret: process.env.GITHUB_CLIENT_SECRET, + code: payload.oauth2_code, + state: payload.oauth2_state, + redirect_uri: payload.oauth2_redirect_uri + }) }); + if (!response.ok) { + logger.error({response}, 'Error retrieving access_token from github'); + throw new DbErrorForbidden(await response.text()); + } + + const obj = await response.json(); if (!obj.access_token) { logger.error({obj}, 'Error retrieving access_token from github'); if (obj.error === 'bad_verification_code') throw new Error('bad verification code'); @@ -25,17 +35,31 @@ const doGithubAuth = async(logger, payload) => { logger.debug({obj}, 'got response from github for access_token'); /* use the access token to get basic public info as well as primary email */ - const userDetails = await getJSON('https://api.github.com/user', null, { - Authorization: `Bearer ${obj.access_token}`, - Accept: 'application/json', - 'User-Agent': 'jambonz 1.0' + const userResponse = await fetch('https://api.github.com/user', { + headers: { + Authorization: `Bearer ${obj.access_token}`, + Accept: 'application/json', + 'User-Agent': 'jambonz 1.0' + } }); + if (!userResponse.ok) { + logger.error({userResponse}, 'Error retrieving user details from github'); + throw new DbErrorForbidden(await userResponse.text()); + } + const userDetails = await userResponse.json(); - const emails = await getJSON('https://api.github.com/user/emails', null, { - Authorization: `Bearer ${obj.access_token}`, - Accept: 'application/json', - 'User-Agent': 'jambonz 1.0' + const emailsResponse = await fetch('https://api.github.com/user/emails', { + headers: { + Authorization: `Bearer ${obj.access_token}`, + Accept: 'application/json', + 'User-Agent': 'jambonz 1.0' + } }); + if (!emailsResponse.ok) { + logger.error({emailsResponse}, 'Error retrieving emails from github'); + throw new DbErrorForbidden(await emailsResponse.text()); + } + const emails = await emailsResponse.json(); const primary = emails.find((e) => e.primary); if (primary) Object.assign(userDetails, { email: primary.email, @@ -55,14 +79,26 @@ const doGoogleAuth = async(logger, payload) => { try { /* exchange the code for an access token */ - const obj = await postJSON('https://oauth2.googleapis.com/token', { - client_id: payload.oauth2_client_id, - client_secret: process.env.GOOGLE_OAUTH_CLIENT_SECRET, - code: payload.oauth2_code, - state: payload.oauth2_state, - redirect_uri: payload.oauth2_redirect_uri, - grant_type: 'authorization_code' + const response = await fetch('https://oauth2.googleapis.com/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json' + }, + body: JSON.stringify({ + client_id: payload.oauth2_client_id, + client_secret: process.env.GOOGLE_OAUTH_CLIENT_SECRET, + code: payload.oauth2_code, + state: payload.oauth2_state, + redirect_uri: payload.oauth2_redirect_uri, + grant_type: 'authorization_code' + }) }); + if (!response.ok) { + logger.error({response}, 'Error retrieving access_token from google'); + throw new DbErrorForbidden(await response.text()); + } + const obj = await response.json(); if (!obj.access_token) { logger.error({obj}, 'Error retrieving access_token from github'); if (obj.error === 'bad_verification_code') throw new Error('bad verification code'); @@ -71,12 +107,18 @@ const doGoogleAuth = async(logger, payload) => { logger.debug({obj}, 'got response from google for access_token'); /* use the access token to get basic public info as well as primary email */ - const userDetails = await getJSON('https://www.googleapis.com/oauth2/v2/userinfo', null, { - Authorization: `Bearer ${obj.access_token}`, - Accept: 'application/json', - 'User-Agent': 'jambonz 1.0' + const userDetailsResponse = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', { + headers: { + Authorization: `Bearer ${obj.access_token}`, + Accept: 'application/json', + 'User-Agent': 'jambonz 1.0' + } }); - + if (!userDetailsResponse.ok) { + logger.error({userDetailsResponse}, 'Error retrieving user details from google'); + throw new DbErrorForbidden(await userDetailsResponse.text()); + } + const userDetails = await userDetailsResponse.json(); logger.info({userDetails}, 'retrieved user details from google'); return userDetails; } catch (err) { diff --git a/lib/utils/speech-utils.js b/lib/utils/speech-utils.js index 60866bf..9974b70 100644 --- a/lib/utils/speech-utils.js +++ b/lib/utils/speech-utils.js @@ -3,7 +3,6 @@ const { TranscribeClient, ListVocabulariesCommand } = require('@aws-sdk/client-t const { Deepgram } = require('@deepgram/sdk'); const sdk = require('microsoft-cognitiveservices-speech-sdk'); const { SpeechClient } = require('@soniox/soniox-node'); -const bent = require('bent'); const fs = require('fs'); const { AssemblyAI } = require('assemblyai'); const {decrypt, obscureKey} = require('./encrypt-decrypt'); @@ -288,44 +287,46 @@ const testMicrosoftTts = async(logger, synthAudio, credentials) => { const testWellSaidTts = async(logger, credentials) => { const {api_key} = credentials; - try { - const post = bent('https://api.wellsaidlabs.com', 'POST', 'buffer', { + const response = await fetch('https://api.wellsaidlabs.com/v1/tts/stream', { + method: 'POST', + headers: { 'X-Api-Key': api_key, 'Accept': 'audio/mpeg', 'Content-Type': 'application/json' - }); - const mp3 = await post('/v1/tts/stream', { + }, + body: JSON.stringify({ text: 'Hello, world', speaker_id: '3' - }); - return mp3; - } catch (err) { - logger.info({err}, 'testWellSaidTts returned error'); - throw err; + }) + }); + if (!response.ok) { + throw new Error('failed to synthesize speech'); } + return response.body; }; const testElevenlabs = async(logger, credentials) => { const {api_key, model_id} = credentials; - try { - const post = bent('https://api.elevenlabs.io', 'POST', 'buffer', { + const response = await fetch('https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM', { + method: 'POST', + headers: { 'xi-api-key': api_key, 'Accept': 'audio/mpeg', 'Content-Type': 'application/json' - }); - const mp3 = await post('/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM', { + }, + body: JSON.stringify({ text: 'Hello', model_id, voice_settings: { stability: 0.5, similarity_boost: 0.5 } - }); - return mp3; - } catch (err) { - logger.info({err}, 'synthEvenlabs returned error'); - throw err; + }) + }); + if (!response.ok) { + throw new Error('failed to synthesize speech'); } + return response.body; }; const testPlayHT = async(logger, synthAudio, credentials) => { @@ -466,18 +467,18 @@ const testVerbioTts = async(logger, synthAudio, credentials) => { }; const testVerbioStt = async(logger, getVerbioAccessToken, credentials) => { const token = await getVerbioAccessToken(credentials); - try { - const post = bent('https://us.rest.speechcenter.verbio.com', 'POST', 'json', { + const response = await fetch('https://us.rest.speechcenter.verbio.com/api/v1/recognize?language=en-US&version=V1', { + method: 'POST', + headers: { 'Authorization': `Bearer ${token.access_token}`, 'User-Agent': 'jambonz', 'Content-Type': 'audio/wav' - }); - const json = await post('/api/v1/recognize?language=en-US&version=V1', - fs.readFileSync(`${__dirname}/../../data/test_audio.wav`)); - logger.debug({json}, 'successfully speech to text from verbio'); - } catch (err) { - logger.info({err}, 'testWellSaidTts returned error'); - throw err; + }, + body: fs.readFileSync(`${__dirname}/../../data/test_audio.wav`) + }); + if (!response.ok) { + logger.error({Error: await response.text()}, 'Error transcribing speech'); + throw new Error('failed to transcribe speech'); } }; @@ -546,16 +547,17 @@ const testAssemblyStt = async(logger, credentials) => { const testVoxistStt = async(logger, credentials) => { const {api_key} = credentials; - try { - const get = bent('https://api-asr.voxist.com', 'GET', 'json', { + const response = await fetch('https://api-asr.voxist.com/clients', { + headers: { 'Accept': 'application/json', 'x-lvl-key': api_key - }); - await get('/clients'); - } catch (err) { - logger.info({err}, 'failed to get clients from Voxist'); - throw err; + } + }); + if (!response.ok) { + logger.error({response}, 'Error retrieving clients'); + throw new Error('failed to get clients'); } + return response.json(); }; const getSpeechCredential = (credential, logger) => { @@ -812,17 +814,18 @@ async function getLanguagesVoicesForAws(credential, getTtsVoices, logger) { async function getLanguagesVoicesForMicrosoft(credential, getTtsVoices, logger) { if (credential) { - try { - const get = bent('https://westus.tts.speech.microsoft.com', 'GET', 'json', { - 'Ocp-Apim-Subscription-Key' : credential.api_key - }); - - const voices = await get('/cognitiveservices/voices/list'); - const tts = parseMicrosoftLanguagesVoices(voices); - return tranform(tts, SttMicrosoftLanguagesVoices); - } catch (err) { - logger.info('Error while fetching Microsoft languages, voices, return predefined values', err); + const response = await fetch('https://westus.tts.speech.microsoft.com/cognitiveservices/voices/list', { + headers: { + 'Ocp-Apim-Subscription-Key': credential.api_key + } + }); + if (!response.ok) { + logger.error({response}, 'Error fetching Microsoft voices'); + throw new Error('failed to list voices'); } + const voices = await response.json(); + const tts = parseMicrosoftLanguagesVoices(voices); + return tranform(tts, SttMicrosoftLanguagesVoices); } return tranform(TtsMicrosoftLanguagesVoices, SttMicrosoftLanguagesVoices); } @@ -885,14 +888,27 @@ async function getLanguagesVoicesForSpeechmatics(credential) { async function getLanguagesVoicesForElevenlabs(credential) { if (credential) { - const get = bent('https://api.elevenlabs.io', 'GET', 'json', { - 'xi-api-key' : credential.api_key + const headers = { + 'xi-api-key': credential.api_key + }; + + const getModelPromise = fetch('https://api.elevenlabs.io/v1/models', { + headers }); + const getVoicePromise = fetch('https://api.elevenlabs.io/v1/voices', { + headers + }); + const [langResp, voiceResp] = await Promise.all([getModelPromise, getVoicePromise]); - const [langResp, voiceResp] = await Promise.all([get('/v1/models'), get('/v1/voices')]); + if (!langResp.ok || !voiceResp.ok) { + throw new Error('failed to list voices'); + } - const model = langResp.find((m) => m.model_id === credential.model_id); - const models = langResp.map((m) => { + const langs = await langResp.json(); + const voicesR = await voiceResp.json(); + + const model = langs.find((m) => m.model_id === credential.model_id); + const models = langs.map((m) => { return { value: m.model_id, name: m.name @@ -908,7 +924,7 @@ async function getLanguagesVoicesForElevenlabs(credential) { if (languages && languages.length > 0) { // using if condition to avoid \n character in name - const voices = voiceResp ? voiceResp.voices.map((v) => { + const voices = voicesR ? voicesR.voices.map((v) => { let name = `${v.name}${v.category !== 'premade' ? ` (${v.category.trim()})` : ''} - (`; if (v.labels.accent) name += `${v.labels.accent}, `; if (v.labels.description) name += `${v.labels.description}, `; @@ -946,18 +962,28 @@ const concat = (a) => { const fetchLayHTVoices = async(credential) => { if (credential) { - const get = bent('https://api.play.ht', 'GET', 'json', { - 'AUTHORIZATION' : credential.api_key, + const headers = { + 'AUTHORIZATION': credential.api_key, 'X-USER-ID': credential.user_id, 'Accept': 'application/json' + }; + const response = await fetch('https://api.play.ht/api/v2/voices', { + headers }); - - const voices = await get('/api/v2/voices'); + if (!response.ok) { + throw new Error('failed to list voices'); + } + const voices = await response.json(); let clone_voices = []; try { // try if the account has permission to cloned voice //otherwise ignore this. - clone_voices = await get('/api/v2/cloned-voices'); + const clone_voices_Response = await fetch('https://api.play.ht/api/v2/cloned-voices', { + headers + }); + if (clone_voices_Response.ok) { + clone_voices = await clone_voices_Response.json(); + } } catch {} return [clone_voices, voices]; } @@ -1032,10 +1058,15 @@ async function getLanguagesVoicesForPlayHT(credential) { async function getLanguagesVoicesForRimelabs(credential) { const model_id = credential ? credential.model_id : null; - const get = bent('https://users.rime.ai', 'GET', 'json', { - 'Accept': 'application/json' + const response = await fetch('https://users.rime.ai//data/voices/all-v2.json', { + headers: { + 'Accept': 'application/json' + } }); - const voices = await get('/data/voices/all-v2.json'); + if (!response.ok) { + throw new Error('failed to list models'); + } + const voices = await response.json(); const modelVoices = model_id ? voices[model_id] : Object.keys(voices).length > 0 ? voices[Object.keys(voices)[0]] : []; const ttsVoices = Object.entries(modelVoices).map(([key, voices]) => ({ @@ -1238,14 +1269,18 @@ function parseVerbioLanguagesVoices(data) { const fetchCartesiaVoices = async(credential) => { if (credential) { - const get = bent('https://api.cartesia.ai', 'GET', 'json', { - 'X-API-Key' : credential.api_key, - 'Cartesia-Version': '2024-06-10', - 'Accept': 'application/json' + const response = await fetch('https://api.cartesia.ai/voices', { + headers: { + 'X-API-Key': credential.api_key, + 'Cartesia-Version': '2024-06-10', + 'Accept': 'application/json' + } }); + if (!response.ok) { + throw new Error('failed to list voices'); + } - const voices = await get('/voices'); - return voices; + return await response.json(); } }; diff --git a/lib/utils/stripe-utils.js b/lib/utils/stripe-utils.js index 9630893..35df523 100644 --- a/lib/utils/stripe-utils.js +++ b/lib/utils/stripe-utils.js @@ -6,7 +6,6 @@ assert.ok(process.env.STRIPE_API_KEY || process.env.NODE_ENV === 'test', assert.ok(process.env.STRIPE_BASE_URL || process.env.NODE_ENV === 'test', 'missing env STRIPE_BASE_URL for billing operations'); -const bent = require('bent'); const formurlencoded = require('form-urlencoded'); const qs = require('qs'); const toBase64 = (str) => Buffer.from(str || '', 'utf8').toString('base64'); @@ -14,10 +13,47 @@ const basicAuth = () => { const header = `Basic ${toBase64(process.env.STRIPE_API_KEY)}`; return {Authorization: header}; }; -const postForm = bent(process.env.STRIPE_BASE_URL || 'http://127.0.0.1', 'POST', 'string', - Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, basicAuth()), 200); -const getJSON = bent(process.env.STRIPE_BASE_URL || 'http://127.0.0.1', 'GET', 'json', basicAuth(), 200); -const deleteJSON = bent(process.env.STRIPE_BASE_URL || 'http://127.0.0.1', 'DELETE', 'json', basicAuth(), 200); +const STRIPE_BASE_URL = process.env.STRIPE_BASE_URL || 'http://127.0.0.1'; +const getJSON = async(path) => { + const response = await fetch(`${STRIPE_BASE_URL}${path}`, { + headers: { + 'Content-Type': 'application/json', + ...basicAuth() + } + }); + if (!response.ok) { + throw new Error(`Error retrieving ${path} from stripe: ${response.status}`); + } + return await response.json(); +}; + +const postForm = async(path, body) => { + const response = await fetch(`${STRIPE_BASE_URL}${path}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + ...basicAuth() + }, + body + }); + if (!response.ok) { + throw new Error(`Error posting to ${path} from stripe: ${response.status}`); + } + return await response.text(); +}; +const deleteJSON = async(path) => { + const response = await fetch(`${STRIPE_BASE_URL}${path}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + ...basicAuth() + } + }); + if (!response.ok) { + throw new Error(`Error deleting ${path} from stripe: ${response.status}`); + } + return await response.json(); +}; //const debug = require('debug')('jambonz:api-server'); const listProducts = async(logger) => await getJSON('/products?active=true'); diff --git a/package-lock.json b/package-lock.json index eacb610..9a739f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,6 @@ "@soniox/soniox-node": "^1.2.2", "argon2": "^0.40.1", "assemblyai": "^4.3.4", - "bent": "^7.3.12", "cors": "^2.8.5", "debug": "^4.3.4", "express": "^4.19.2", @@ -58,8 +57,6 @@ "eslint-plugin-promise": "^6.1.1", "husky": "9.0.11", "nyc": "^15.1.0", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "tape": "^5.7.5" } }, @@ -5771,15 +5768,6 @@ "node": ">=8" } }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, "node_modules/assemblyai": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/assemblyai/-/assemblyai-4.3.4.tgz", @@ -5840,15 +5828,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/aws-ssl-profiles": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", @@ -5858,12 +5837,6 @@ "node": ">= 6.0.0" } }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, "node_modules/axios": { "version": "1.7.7", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", @@ -5903,15 +5876,6 @@ } ] }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/bent": { "version": "7.3.12", "resolved": "https://registry.npmjs.org/bent/-/bent-7.3.12.tgz", @@ -6425,18 +6389,6 @@ "node": ">=0.12" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -6695,16 +6647,6 @@ "stream-shift": "^1.0.2" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -7513,15 +7455,6 @@ "node": ">=8.0.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -7737,15 +7670,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -7884,29 +7808,6 @@ "node": ">=14.0.0" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -8066,36 +7967,6 @@ "node": ">= 6" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/http-signature/node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/https-proxy-agent": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", @@ -8927,12 +8798,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -8976,12 +8841,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -9104,12 +8963,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -9761,15 +9614,6 @@ "node": ">=6" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -10083,12 +9927,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -10531,130 +10369,6 @@ "node": ">=4" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -11143,31 +10857,6 @@ "node": ">= 0.6" } }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -11200,15 +10889,6 @@ "node": ">= 0.8" } }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -11620,24 +11300,6 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "node_modules/type": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", diff --git a/package.json b/package.json index c200340..fe85430 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "@soniox/soniox-node": "^1.2.2", "argon2": "^0.40.1", "assemblyai": "^4.3.4", - "bent": "^7.3.12", "cors": "^2.8.5", "debug": "^4.3.4", "express": "^4.19.2", @@ -69,8 +68,6 @@ "eslint-plugin-promise": "^6.1.1", "husky": "9.0.11", "nyc": "^15.1.0", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "tape": "^5.7.5" } } diff --git a/test/accounts.js b/test/accounts.js index bba8e84..0e657fb 100644 --- a/test/accounts.js +++ b/test/accounts.js @@ -1,11 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const SP_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734ds'; -const authSP = {bearer: ADMIN_TOKEN}; -const ACC_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734da'; -const authAcc = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const { diff --git a/test/applications.js b/test/applications.js index d43e00e..3ff6f47 100644 --- a/test/applications.js +++ b/test/applications.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createVoipCarrier, createServiceProvider, diff --git a/test/auth.js b/test/auth.js index 1f90af3..454d6b7 100644 --- a/test/auth.js +++ b/test/auth.js @@ -1,11 +1,13 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createVoipCarrier, createServiceProvider, createPhoneNumber, createAccount, deleteObjectBySid} = require('./utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); diff --git a/test/call-test.js b/test/call-test.js index 22baba8..faf4bf5 100644 --- a/test/call-test.js +++ b/test/call-test.js @@ -1,6 +1,7 @@ const test = require('tape'); const jwt = require('jsonwebtoken'); -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const consoleLogger = { debug: console.log, info: console.log, error: console.error } @@ -47,8 +48,7 @@ test('Create Call Success With Synthesizer in Payload', async (t) => { }); // THEN t.ok(result.statusCode === 201, 'successfully created Call without Synthesizer && application_sid'); - const fs_request = await getLastRequestFromFeatureServer('15083778299_createCall'); - const obj = JSON.parse(fs_request); + const obj = await getLastRequestFromFeatureServer('15083778299_createCall'); t.ok(obj.body.speech_synthesis_vendor == 'google', 'speech synthesizer successfully added') t.ok(obj.body.speech_recognizer_vendor == 'google', 'speech recognizer successfully added') }); @@ -82,7 +82,7 @@ test('Create Call Success Without Synthesizer in Payload', async (t) => { } } }).then(data => { t.ok(false, 'Create Call should not be success') }) - .catch(error => { t.ok(error.response.statusCode === 400, 'Call failed for no synthesizer') }); + .catch(error => { t.ok(error.statusCode === 400, 'Call failed for no synthesizer') }); }); test("Create call with application sid and app_json", async(t) => { @@ -150,7 +150,6 @@ result = await request.post(`/Accounts/${account_sid}/Calls`, { }); // THEN t.ok(result.statusCode === 201, 'successfully created Call without Synthesizer && application_sid'); -const fs_request = await getLastRequestFromFeatureServer('15083778299_createCall'); -const obj = JSON.parse(fs_request); +const obj = await getLastRequestFromFeatureServer('15083778299_createCall'); t.ok(obj.body.app_json == app_json, 'app_json successfully added') }); \ No newline at end of file diff --git a/test/clients.js b/test/clients.js index 7494c9b..7130e2d 100644 --- a/test/clients.js +++ b/test/clients.js @@ -1,7 +1,8 @@ const test = require('tape') ; +const { createClient } = require('./http-client'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); diff --git a/test/email_utils.js b/test/email_utils.js index 149e991..52a69e0 100644 --- a/test/email_utils.js +++ b/test/email_utils.js @@ -1,7 +1,5 @@ const test = require('tape'); const {emailSimpleText} = require('../lib/utils/email-utils'); -const bent = require('bent'); -const getJSON = bent('json') const logger = { debug: () =>{}, info: () => {} @@ -15,7 +13,7 @@ test('email-test', async(t) => { await emailSimpleText(logger, 'test@gmail.com', 'subject', 'body text'); - const obj = await getJSON(`http://127.0.0.1:3101/lastRequest/custom_email_vendor`); + const obj = await (await fetch(`http://127.0.0.1:3101/lastRequest/custom_email_vendor`)).json(); t.ok(obj.headers['Content-Type'] == 'application/json'); t.ok(obj.headers.Authorization == 'Basic VVNFUk5BTUU6UEFTU1dPUkQ='); t.ok(obj.body.from == 'jambonz Support '); diff --git a/test/forgot-password.js b/test/forgot-password.js index b51c762..dd32b52 100644 --- a/test/forgot-password.js +++ b/test/forgot-password.js @@ -1,5 +1,6 @@ const test = require('tape'); -const request = require("request-promise-native").defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: "http://127.0.0.1:3000/v1", }); diff --git a/test/http-client.js b/test/http-client.js new file mode 100644 index 0000000..b1625c5 --- /dev/null +++ b/test/http-client.js @@ -0,0 +1,172 @@ +/** + * Fetch-based HTTP client that mimics the request-promise-native API + */ + +class HttpClient { + constructor(defaults = {}) { + this.defaults = defaults; + this.baseUrl = defaults.baseUrl || ''; + } + + /** + * Make an HTTP GET request + */ + async get(url, options = {}) { + return this._makeRequest(url, 'GET', options); + } + + /** + * Make an HTTP POST request + */ + async post(url, options = {}) { + return this._makeRequest(url, 'POST', options); + } + + /** + * Make an HTTP PUT request + */ + async put(url, options = {}) { + return this._makeRequest(url, 'PUT', options); + } + + /** + * Make an HTTP DELETE request + */ + async delete(url, options = {}) { + return this._makeRequest(url, 'DELETE', options); + } + + /** + * Private method to handle all HTTP requests + */ + async _makeRequest(url, method, options = {}) { + const { + auth, + body, + json = true, // Changed default to true since most API calls expect JSON + qs = {}, + simple = true, + resolveWithFullResponse = false + } = options; + + // Build full URL with query parameters + const fullUrl = this._buildUrl(url, qs); + + // Set up headers + const headers = {}; + if (auth?.bearer) { + headers['Authorization'] = `Bearer ${auth.bearer}`; + } + + // Set JSON headers for all requests when json is true + if (json) { + headers['Accept'] = 'application/json'; + + // Only set Content-Type when sending data + if (['POST', 'PUT', 'PATCH'].includes(method) && body) { + headers['Content-Type'] = 'application/json'; + } + } + + // Build request options + const fetchOptions = { + method, + headers + }; + + // Add request body if needed + if (body && ['POST', 'PUT', 'PATCH'].includes(method)) { + fetchOptions.body = json ? JSON.stringify(body) : body; + } + + try { + // Make the request + const response = await fetch(fullUrl, fetchOptions); + + // Clone the response before consuming it + // This allows us to use the body in error handling if needed + const clonedResponse = response.clone(); + + // Parse response body based on content type - only once + let responseBody = null; + if (response.status !== 204) { // No content + if (json) { + try { + responseBody = await response.json(); + } catch (e) { + // If can't parse JSON, get text + responseBody = await clonedResponse.text(); + } + } else { + responseBody = await response.text(); + } + } + + // Handle errors if simple mode is enabled + if (simple && !response.ok) { + const error = new Error(`Request failed with status code ${response.status}`); + error.statusCode = response.status; + error.body = responseBody; // Include the already parsed body + throw error; + } + + // Return full response object or just body based on options + if (resolveWithFullResponse) { + return { + statusCode: response.status, + body: responseBody, + headers: Object.fromEntries(response.headers.entries()) + }; + } + + return responseBody; + } catch (error) { + if (!simple) { + // If simple=false, return error response instead of throwing + return { + statusCode: error.statusCode || 500, + body: error.body || { message: error.message } + }; + } + throw error; + } + } + /** + * Build URL with query parameters + */ + _buildUrl(url, qs) { + // Start with base URL + let fullUrl = this.baseUrl + url; + + // Add query parameters + if (Object.keys(qs).length > 0) { + const params = new URLSearchParams(); + Object.entries(qs).forEach(([key, value]) => { + params.append(key, value); + }); + fullUrl += `?${params.toString()}`; + } + + return fullUrl; + } +} + +/** + * Create a client with default options + */ +function createClient(defaults = {}) { + const client = new HttpClient(defaults); + + // Return the methods directly for API compatibility + return { + get: (url, options) => client.get(url, options), + post: (url, options) => client.post(url, options), + put: (url, options) => client.put(url, options), + delete: (url, options) => client.delete(url, options), + defaults: client.defaults + }; +} + +module.exports = { + createClient +}; \ No newline at end of file diff --git a/test/lcr-carriers-set-entries.js b/test/lcr-carriers-set-entries.js index 69b6cb5..bf5fef3 100644 --- a/test/lcr-carriers-set-entries.js +++ b/test/lcr-carriers-set-entries.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); diff --git a/test/lcr-routes.js b/test/lcr-routes.js index 6d7511d..c25a1b5 100644 --- a/test/lcr-routes.js +++ b/test/lcr-routes.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); diff --git a/test/lcrs.js b/test/lcrs.js index 0e6654c..78b6470 100644 --- a/test/lcrs.js +++ b/test/lcrs.js @@ -1,7 +1,8 @@ const test = require('tape') ; +const { createClient } = require('./http-client'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); diff --git a/test/login.js b/test/login.js index c42e324..efaa032 100644 --- a/test/login.js +++ b/test/login.js @@ -1,12 +1,14 @@ const test = require('tape') ; const jwt = require('jsonwebtoken'); -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const exec = require('child_process').exec ; const {generateHashedPassword} = require('../lib/utils/password-utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); @@ -52,7 +54,7 @@ test('login tests', async(t) => { password: 'adm', } }).catch(error => { - t.ok(error.response.statusCode === 403, `Maximum login attempts reached. Please try again in ${attempTime} seconds.`) + t.ok(error.statusCode === 403, `Maximum login attempts reached. Please try again in ${attempTime} seconds.`) }); } else if (index < maxAttempts) { attemptResult = await request.post('/login', { @@ -62,7 +64,10 @@ test('login tests', async(t) => { username: 'admin', password: 'adm', } - }).catch(error => t.ok(error.response.statusCode === 403)); + }).catch(error => { + console.log(JSON.stringify(error)); + t.ok(error.statusCode === 403); + }); } else { attemptResult = await request.post('/login', { resolveWithFullResponse: true, @@ -71,7 +76,7 @@ test('login tests', async(t) => { username: 'admin', password: 'adm', } - }).catch(error => t.ok(error.response.statusCode === 403, 'Maximum login attempts reached. Please try again later or reset your password.')); + }).catch(error => t.ok(error.statusCode === 403, 'Maximum login attempts reached. Please try again later or reset your password.')); } } diff --git a/test/ms-teams.js b/test/ms-teams.js index 3be6a46..2a7bd3d 100644 --- a/test/ms-teams.js +++ b/test/ms-teams.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createServiceProvider, createAccount, deleteObjectBySid} = require('./utils'); diff --git a/test/oauth/gh-get-user.js b/test/oauth/gh-get-user.js index 6c20346..976ff04 100644 --- a/test/oauth/gh-get-user.js +++ b/test/oauth/gh-get-user.js @@ -1,9 +1,6 @@ -const bent = require('bent'); -const getJSON = bent('GET', 200); -const request = require('request'); - const test = async() => { - request.get('https://api.github.com/user', { + fetch('https://api.github.com/user', { + method: 'GET', headers: { Authorization: `Bearer ${process.env.GH_CODE}`, Accept: 'application/json', diff --git a/test/password-settings.js b/test/password-settings.js index a1a0c05..d1784cf 100644 --- a/test/password-settings.js +++ b/test/password-settings.js @@ -1,7 +1,8 @@ const test = require('tape') ; +const { createClient } = require('./http-client'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); diff --git a/test/phone-numbers.js b/test/phone-numbers.js index 71d4e18..e6f26c2 100644 --- a/test/phone-numbers.js +++ b/test/phone-numbers.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createVoipCarrier, deleteObjectBySid} = require('./utils'); diff --git a/test/recent-calls.js b/test/recent-calls.js index 0c3116b..0e9e811 100644 --- a/test/recent-calls.js +++ b/test/recent-calls.js @@ -3,7 +3,8 @@ const fs = require('fs'); const jwt = require('jsonwebtoken'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const consoleLogger = {debug: console.log, info: console.log, error: console.error} diff --git a/test/sbcs.js b/test/sbcs.js index dc52e4a..034f1a9 100644 --- a/test/sbcs.js +++ b/test/sbcs.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createServiceProvider, deleteObjectBySid} = require('./utils'); diff --git a/test/service-providers.js b/test/service-providers.js index 5bf4cd0..79a6c97 100644 --- a/test/service-providers.js +++ b/test/service-providers.js @@ -1,11 +1,13 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {deleteObjectBySid} = require('./utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); diff --git a/test/sip-gateways.js b/test/sip-gateways.js index 97ac8b4..ad2d988 100644 --- a/test/sip-gateways.js +++ b/test/sip-gateways.js @@ -1,7 +1,8 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createVoipCarrier, deleteObjectBySid} = require('./utils'); diff --git a/test/smpp-gateways.js b/test/smpp-gateways.js index 2d44fb2..493549a 100644 --- a/test/smpp-gateways.js +++ b/test/smpp-gateways.js @@ -1,11 +1,13 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createVoipCarrier, deleteObjectBySid} = require('./utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); diff --git a/test/speech-credentials.js b/test/speech-credentials.js index 7c9a7fb..b0a00da 100644 --- a/test/speech-credentials.js +++ b/test/speech-credentials.js @@ -3,12 +3,14 @@ const fs = require('fs'); const jwt = require('jsonwebtoken'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createServiceProvider, createAccount, deleteObjectBySid} = require('./utils'); const { noopLogger } = require('@jambonz/realtimedb-helpers/lib/utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); diff --git a/test/system-information.js b/test/system-information.js index 6e53934..a8686d5 100644 --- a/test/system-information.js +++ b/test/system-information.js @@ -1,8 +1,9 @@ const test = require('tape') ; const jwt = require('jsonwebtoken'); +const { createClient } = require('./http-client'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); diff --git a/test/tts-cache.js b/test/tts-cache.js index 71c5cda..b0c0cad 100644 --- a/test/tts-cache.js +++ b/test/tts-cache.js @@ -2,7 +2,8 @@ const test = require('tape') ; const jwt = require('jsonwebtoken'); const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const crypto = require('crypto'); diff --git a/test/users-view-only.js b/test/users-view-only.js index 989076d..157dbc9 100644 --- a/test/users-view-only.js +++ b/test/users-view-only.js @@ -1,10 +1,12 @@ const test = require('tape') ; const jwt = require('jsonwebtoken'); -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const exec = require('child_process').exec ; const {generateHashedPassword} = require('../lib/utils/password-utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); diff --git a/test/users.js b/test/users.js index deeee4d..26eff2d 100644 --- a/test/users.js +++ b/test/users.js @@ -1,10 +1,11 @@ const test = require('tape') ; const jwt = require('jsonwebtoken'); -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const exec = require('child_process').exec ; -const {generateHashedPassword} = require('../lib/utils/password-utils'); + process.on('unhandledRejection', (reason, p) => { diff --git a/test/utils.js b/test/utils.js index c9d39bc..97a1b0c 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,6 +1,7 @@ const { v4: uuid } = require('uuid'); const fs = require('fs'); -const request_fs_mock = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request_fs_mock = createClient({ baseUrl: 'http://127.0.0.1:3100' }); diff --git a/test/voip-carriers.js b/test/voip-carriers.js index d1e3d8f..fbf7136 100644 --- a/test/voip-carriers.js +++ b/test/voip-carriers.js @@ -1,11 +1,13 @@ const test = require('tape') ; const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de'; const authAdmin = {bearer: ADMIN_TOKEN}; -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const {createServiceProvider, createAccount, createApplication, deleteObjectBySid} = require('./utils'); + process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); diff --git a/test/webapp_tests.js b/test/webapp_tests.js index b655df4..e9ed319 100644 --- a/test/webapp_tests.js +++ b/test/webapp_tests.js @@ -1,7 +1,8 @@ const test = require('tape') ; const exec = require('child_process').exec ; const Account = require('../lib/models/account'); -const request = require('request-promise-native').defaults({ +const { createClient } = require('./http-client'); +const request = createClient({ baseUrl: 'http://127.0.0.1:3000/v1' }); const theOneAndOnlyServiceProviderSid = '2708b1b3-2736-40ea-b502-c53d8396247f';