Twilio - change SIP trunk through API - api

Is it possible to change the Twilio SIP trunk of a phone number through Twilio API?
Ex: Move a number from Trunk 1 to Trunk 2

Yes, that should work with these two parts of the API:
Remove number from old trunk
// Download the helper library from https://www.twilio.com/docs/node/install
// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);
client.trunking.v1.trunks('TKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.phoneNumbers('PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.remove();
Add number to new trunk
// Download the helper library from https://www.twilio.com/docs/node/install
// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);
client.trunking.v1.trunks('TKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.phoneNumbers
.create({
phoneNumberSid: 'PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
})
.then(phone_number => console.log(phone_number.sid));

Related

#shopify/shopify-api nodejs - Set permanent access token for private app installed on only one store

The shopifyApi reference does not have a private app permanent access token property. I have a custom private app that is installed on only one store and I have the permanent access token so I don't need to oAuth every time I'm calling the REST API. Would be great to have a documented straight forward example of how to do this. The docs are hairy, IMO.
#shopify/shopify-api version: 6.1.0
Is the following close? I'm looking at the Session object and trying to understand how to load an offline session and set the Session with correct SessionParams.
import '#shopify/shopify-api/adapters/node'
import { shopifyApi, LATEST_API_VERSION, Session } from '#shopify/shopify-api'
const shopify = shopifyApi({
apiKey: 'myprivateappkey',
apiSecretKey: 'myprivateappsecret',
apiVersion: LATEST_API_VERSION,
isPrivateApp: true,
scopes: ['read_products'],
isEmbeddedApp: false,
hostName: 'shop.myshopify.com',
})
const sessionId = shopify.session.getOfflineId('shop.myshopify.com')
const session = new Session({
id: sessionId,
shop: 'shop.myshopify.com',
state: 'state',
isOnline: false,
accessToken: 'permanentAccessToken',
})
const client = new shopify.clients.Rest({ session: session })
On older v5 version of shopify-api, with two lines I could access any REST API, but I see this is now deprecated, So I'm trying to unravel offline sessions, but it doesn't make sense to provide the api key and api secret and then create a session using the permanent access token.
import Shopify from '#shopify/shopify-api'
const client = new Shopify.Clients.Rest(
'mystore.myshopify.com',
'permanentAccessTokenString',
)
See answer from Shopify here.
When creating the client in a private app, a dummy session can be created like so
const session = new Session({
id: 'not-a-real-session-id',
shop: 'shop.myshopify.com,
state: 'state',
isOnline: false,
});
const client = new shopify.clients.Rest({ session: session })
When config.isPrivateApp is set to true only the shop property is used by the client - the other three (id, state, isOnline) properties are ignored (but are required when creating a Session object).
config.apiSecretKey is used as the access token, and is read directly from the config (no need to set the accessToken property of the dummy session as it will be ignored).
Essentially, config.apiSecretKey is the permanent access token for a private app.
The scopes can be omitted, as it defaults to an empty scopes array internally anyway and (from a quick search through the library code) is only used when doing OAuth, validating sessions, etc., which won't apply to private apps.
As for the apiKey, while it's mostly used as part of the OAuth process, it is also used in a few other places (e.g., shopify.auth.getEmbeddedAppUrl()), so I'd recommend setting the apiKey to be that of your private app.
However, in my testing, scopes, even when isPrivateApp, are currently required. If you leave the array empty for scopes it will have a config error.
Also, my shopifyApi config mounts rest resources so that when you're in Shopify REST docs on the nodejs tab, you can easily use the REST resources examples on the nodejs to make calls, rather than creating a REST client and use standard post, etc.
Complete code to setup a private app connection to Shopify:
import '#shopify/shopify-api/adapters/node'
import { shopifyApi, LATEST_API_VERSION, Session } from '#shopify/shopify-api'
import { restResources } from '#shopify/shopify-api/rest/admin/2023-01'
const debug = process.env.FUNCTIONS_EMULATOR === 'true'
const shopify = shopifyApi({
apiKey: 'myprivateAppApiKey',
apiSecretKey: 'myPermanentAccessToken',
apiVersion: LATEST_API_VERSION,
isPrivateApp: true,
scopes: [
'read_customers',
'write_customers',
'read_fulfillments',
'write_fulfillments',
'read_inventory',
'write_inventory',
'write_order_edits',
'read_order_edits',
'write_orders',
'read_orders',
'write_products',
'read_products',
],
isEmbeddedApp: false,
hostName: debug ? '127.0.0.1:5001' : 'shop.myshopify.com',
// Mount REST resources.
restResources,
})
// Create a sanitized "fake" sessionId. E.g.
// "offline_my.myshopify.com".
const sessionId = shopify.session.getOfflineId('shop.myshopify.com')
const session = new Session({
id: sessionId,
shop: 'shop.myshopify.com,
state: 'state',
isOnline: false,
})
// Use mounted REST resources to make calls.
const transactions = await shopify.rest.Transaction.all({
session,
order_id: 123456789,
})
// Alternatively, if not using mounted REST resources
// you could create a standard REST client.
const client = new shopify.clients.Rest({ session })

How can I download a file from frontend with Authorization Header

Here is my backend code. It has 2 protected routes. Authorization Header is needed (Bearer token).
These routes allows you to download your photo and your cv.
I have no issue with my backend. It is working with postman and mobile applications. I think there is a limitation for frontend.
I do NOT want
I don't want to use fetch to download these files as blob. Because it doesn't allow to browser to show its progress bar.
I don't want to change my authentication method from Bearer token to cookie. I can already do this with cookie.
I wonder why Bearer token is more popular than cookie If I have to use cookie to make this happen.
Backend
// other imports .....
const path = require('path');
const fs = require('fs');
const express = require('express');
const app = express();
app.use((req, res, next) => {
try {
const token = req.get('Authorization');
if(!token) {
throw new Error('401');
}
const userId = getIdFromToken(token);
if(!userId) {
throw new Error('401');
}
res.locals.userId = userId;
next();
} catch (error) {
next(error);
}
})
app.get('/api/me/photo', (req, res) => {
const userId = res.locals.userId;
const imagePath = path.resolve(process.env.DISC_PATH, 'images', `${userId}.png`);
res.attachment('me.png');
res.set('Content-Type', 'image/png');
const stream = fs.createReadStream(imagePath);
res.pipe(stream);
})
app.get('/api/me/cv', (req, res) => {
const userId = res.locals.userId;
const pdfPath = path.resolve(process.env.DISC_PATH, 'cv', `${userId}.png`);
res.attachment('my-cv.pdf');
res.set('Content-Type', 'application/pdf');
const stream = fs.createReadStream(pdfPath);
res.pipe(stream);
})
...
// error handling, etc...
Frontend
<html>
<body>
<!-- How can I send the Authorization header here -->
<img src="/api/me/photo" />
<!-- How can I send the Authorization header here -->
Download My CV
<!-- How can I send the Authorization header here -->
<button id="btn"> Download My CV (V2) </button>
<script>
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
// How can I send the Authorization header here
window.open('/api/me/cv');
});
</script>
</body>
</html>
I wonder why Bearer token is more popular than cookie If I have to use cookie to make this happen.
One advantage of an Authorization: Bearer header over cookie-based authentication is precisely that the browser does not automatically include the header in a request to the given URL. So you cannot be tricked into clicking on a link that would trigger an authenticated request that you did not intend.
In other words: With Authorization: Bearer as authentication mechanism you are safe from "cross-site request forgery" (CSRF) attacks.
Backends that use cookie-based authentication have to implement extra countermeasures against CSRF.
For your problem, this means that the two don't go together. If you want the convenience of a "normal" browser request (with its progress bar), you expose the user to CSRF, unless you take said countermeasures. (This may not be a serious threat if the request only downloads something. But an attacker could at least measure the running time of the CV download request and deduce something from that.)
Possible workaround:
Implement an API (authenticated with Authorization: Bearer header) that generates a download URL which includes a short-lived token, and have the browser download the desired document with a normal request to that URL. The second request is technically unauthenticated, but the token makes the URL unguessable.
If the token is a JWT, you need not even store it on your server but can simply write the username and expiry time in it and sign it with the server's private key. If you prefer you can also put the token in a cookie rather than in the URL.

Cognito Auth.sendCustomChallengeAnswer gives "AuthClass - Failed to get the signed in user No current user"

I am trying to make API (Lambda and API gateway) for sign in and verify auth using OTP for password-less authentication. The target is to make front end using angular and mobile application using Flutter but there is no support of AWS Amplify for flutter. So going through to create those API to serve my purpose. The frontend code(Auth.signIn and Auth.sendCustomChallengeAnswer) works great but using same code the verify auth API is not working. Sharing my code.
Sign In API:
await Auth.signIn(phone);
Verify Auth API: (Returned c['Session'] from DynamoDB which is stored in during signIn)
let otp = body['otp'];
const poolData = {
UserPoolId: '------ pool id -------',
ClientId: '------ client id -------'
};
const userPool = new CognitoUserPool(poolData);
const userData = {
Username: '+12014222656',
Pool: userPool
};
this.cognitoUser1 = new CognitoUser(userData);
this.cognitoUser1['Session'] = c['Session'];
await Auth.sendCustomChallengeAnswer(this.cognitoUser1, otp);
const tokenDetails = await Auth.currentSession()
response = {
'statusCode': 201,
'body': JSON.stringify({
message: 'Verification successful',
body:tokenDetails
})
}
After debugging frontend Auth.signIn response and Lambda API Auth.signIn response i investigated that an extra "storage" object returned when signing in from frontend and appended on this.cognitoUser1 before sending through Auth.sendCustomChallengeAnswer . See the attached screenshot below:
Is this the reason for successful verifying OTP from frontend? If so, what about making API (using Lambda and API gateway) and where it stores this storage object. Stuck here. Any suggestion and help will be appreciated.
You can set your own storage: https://docs.amplify.aws/lib/auth/manageusers/q/platform/js#managing-security-tokens

Run custom functions in express-gateway

I have this configuration in the gateway.config.yml (Express-Gateway api):
- bo
policies:
- jwt:
- action:
secretOrPublicKeyFile: './key.pem'
checkCredentialExistence: false
Everything works fine, but I want the client to encode/encrypt a token that it is being sent to make sure even if I have the token storage on the localstorage no one can use it because it will need to be signed by the client.
The only problem with this is, how can I run a code to decode/decrypt the token before Express-Gateway jwt policy try to validate the token?
Because express-gateway can use middlewares like any other express application I think this is possible, but not an idea on how to do it.
I created this policy that will help me, but how can I integrate it with the express-gateway api:
const cryptojs = require("crypto-js");
module.exports = {
name: 'decode',
policy: (actionParams) => {
return (req, res, next) => {
const tokenHeader = req.header('Authorization');
const tokenArray = tokenHeader.split(' ');
const tokenCifer = tokenArray[1];
const bytes = cryptojs.AES.decrypt(tokenCifer, 'superkeyperm'); //CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123');
var token = bytes.toString(cryptojs.enc.Utf8);
req.headers.authorization = `Bearer ${token}`;
next() // calling next policy
};
}
};
I think what you're interested is writing a plugin which is nothing more than a collection of additional middleware and condition you can stack in Express Gateway, where you can put your own logic.
Check out the docs at https://www.express-gateway.io/docs/plugins/

Botkit slackbot error "Could not load team while processing webhook"

I have created a simple express server and added a /slack/receive route to handle webhook requests from the Slack events API:
// routes.js (which is used by my app defined in server.js)
...
let slack = require('./controllers/slack');
router.post('/slack/receive', slack.receive);
...
I then use Botkit to create a simple Slack application:
// controllers/slack.js
'use strict';
const logger = require('../config/winston');
// initialise firebase storage for botkit
const admin = require('firebase-admin');
var serviceAccount = require('../config/firebase.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
var db = admin.firestore();
db.settings({
timestampsInSnapshots: true
})
// initialise botkit for slack
const botkit = require('botkit');
const controller = botkit.slackbot({
storage: require('botkit-storage-firestore')({ database: db }),
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
clientSigningSecret: process.env.SLACK_SIGNING_SECRET,
redirectUri: process.env.SLACK_REDIRECT,
disable_startup_messages: true,
send_via_rtm: false,
debug: true,
scopes: ['bot', 'chat:write:bot'],
})
controller.hears('Hello', 'direct_mention,direct_message', (bot, message) => {
logger.info(message);
bot.reply(message, 'I heard a message!');
})
exports.receive = (req, res, next) => {
res.sendStatus(200);
logger.debug(req.body);
controller.handleWebhookPayload(req, res);
};
The server initialises correctly, but as soon as the slack webhook receives a request the following error happens:
Could not load team while processing webhook: Error: could not find team T5VDRMWKX
at E:\Documents\upper-revolutions\node_modules\botkit\lib\SlackBot.js:169:24
at firebaseRef.doc.get.then.catch.err (E:\Documents\upper-revolutions\node_modules\botkit-storage-firestore\src\index.js:86:13)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:118:7)
So far I have found that:
Having/not having storage in the botkit slackbot makes no difference
The error happens within the handleWebhookPayload method as code within controller.hears() does not get executed
This error occurs because botkit needs some form of storage where it can store all the teams (channels and users too) and retrive it later on.
So, When your method handleWebhookPayload gets executed it calls another method called
findAppropriateTeam that will query for the specified team record in the storage provided by you (It might be mongoDB or a JSON file or other). The error is saying that you do not have any record in the storage with the id provided.
So this might implicate two things:
You did not provide a storage for botkit to work
You did not save the team id in the storage
The solution to the first problem is quite simple. You just need to install mongodb in your machine and then pass to botkit the MONGO_URL.
NOTE: I see that you are using the botkit simple storage and this might be the problem since I also have experieced some troubles with this kind of storage not saving records.
const controller = botkit.slackbot({
storage: 'mongodb//localhost:27017:/yourdb',
})
//OR
const controller = botkit.slackbot({
storage: process.env.MONGO_URL,
})
The possible solution to the second problem:
I will assume you are using botkit locally, so you must be using some tunneling like ngrok or localtunnel. In that case make sure:
You provided the redirect URL to Slack (Ex, https://your_url/oauth)
You accessed the https://your_url/login page
Botkit saves your team id on the provided storage when you access the /login route and authorizes the app. So if you skipped that part then botkit won't save your team id and therfore will throw an error when you receive events later on.
Check this like [https://github.com/howdyai/botkit/issues/938] for discutions on the topic
I hope this helps!