|
| 1 | + |
| 2 | +# Masked Communications App |
1 | 3 | [](https://github.com/aymenn/masked-comms-app/actions/workflows/test.yml) |
2 | 4 |
|
3 | | -# About |
4 | | -This is an example masked communicaiton application that demonstrates how build it by using [Conversations API](https://twilio.com/docs/conversations) and [Programmable Voice](https://twilio.com/docs/voice). |
| 5 | +This is an open-source version of [Twilio Proxy](https://www.twilio.com/docs/proxy), built on top of the [Twilio Conversations API](https://www.twilio.com/docs/conversations). It adds the following features to conversations: |
| 6 | + |
| 7 | +- 🤿 Add 2-50 SMS participants to a conversation with masked numbers |
| 8 | +- 🔀 Automatic proxy number selection from a number pool |
| 9 | +- ☎️ Supports 1:1 and conference calling via the Conversations proxy number. |
5 | 10 |
|
6 | | -This application supports masking communicaitons between SMS, WhatsApp, and voice participants |
| 11 | +Reasons you might use this app: |
| 12 | +- 🏠 You're a real estate company that wants to connect realtors with prospective buyers over a masked number. |
| 13 | +- 🚗 You're a rideshare service that wants to give riders a temporary number to call their driver. |
| 14 | +- 🎁 You're a personal shopper platform that wants to connect shoppers with customers over a private number and log all conversation messages. |
| 15 | + |
| 16 | +Using the underlying Twilio Conversations platform, you also have the capability to do things like: |
| 17 | +- 🚫 Block messages from going out based on their content. |
| 18 | +- 🗃 Store messages to a database for analysis. |
| 19 | +- 🏁 Receive webhooks from the Conversations event framework. |
7 | 20 |
|
8 | 21 | # Prerequisites |
9 | | -- Twilio Account |
10 | | -- 1 or more Twilio phone numbers (either bought or verified) to mask SMS and voice communications |
| 22 | +- A Twilio Account, you can get a free one [by signing up here](https://twilio.com/try-twilio) |
| 23 | +- 1 or [more](https://www.twilio.com/docs/proxy/phone-numbers-needed) Twilio phone numbers to mask SMS and voice communications |
11 | 24 | - Node.js v14 or higher |
12 | | -- ngrok if running a local server |
| 25 | +- Yarn or NPM |
| 26 | +- If you're running the app locally, you'll need a tool like [ngrok](https://ngrok.com/) so that Twilio can send webhooks to your app. |
13 | 27 |
|
14 | 28 | # Getting Started |
15 | | -1. Copy .env.template to .env |
16 | | -2. Set your account sid and auth token in the corresponding variables |
17 | | -3. Set NUMBER_POOL to an array of phone number(s) e.g. |
18 | | -> NUMBER_POOL=["+19255551111","+19257775555"] |
19 | | -1. If using ngrok, start ngrok for port 9000 |
20 | | -> ngrok http 9000 |
21 | | -5. Configure your phone number's inbound call handler with the url *https://your_ngrok_server/proxypoc/inboundCall* |
22 | | -6. Install the app dependency packages |
23 | | -> npm install |
24 | | -7. Start your npm server |
25 | | -> npm start |
26 | | -
|
27 | | -# Authorization |
28 | | -This app protects API calls to /sessions with basic auth. You can set your basic auth username and password in the .env file. |
29 | | - |
30 | | -# Using |
31 | | -This application provides an endpoint to create a conversation for participants to communicate and a landing page to simplify getting started. |
32 | | - |
33 | | -1. Navigate your browser to *http://localhost:9000/* |
34 | | -2. You will see the configured phone numbers and a section titled *Create a new proxy session* |
35 | | -3. Enter the numbers of two participant that you wish to connect anonymously |
36 | | -4. Click *Submit* |
37 | | -5. A JSON string is presented which contains an array of the participants added to the conversation. Each participant will have a messaging_binding.proxy_address. This is the address that the participants will send and receive numbers to and from |
38 | | -6. Have participant A send a message to their proxy_number |
39 | | -7. Participant B should receive the message from the Participant A's proxy_number |
40 | | -8. You can also have participant A call the proxy_number. This should set up a call to Participant B and participant B should see Participant A's proxy phone number |
41 | | - |
42 | | -# Endpoint |
43 | | -## /sessions |
44 | | -The sessions endpoint accepts one or more addresses. It creates a Conversation, finds a Proxy number for each participant and adds them to the conversation |
45 | | - |
46 | | -## /inboundCall |
47 | | -This endpoint receives inbound call events. It will query Twilio Conversations for a matching participant address and connect the other participant to the caller |
48 | | - |
49 | | -# Number Choosing |
50 | | -The number chooser included is a simple algorithm that picks a number from NUMBER_POOL that isnt used by the given participant's address. |
| 29 | +Begin by cloning the repository, installing dependencies, and setting environment variables: |
| 30 | + |
| 31 | +```bash |
| 32 | +# Clone the repository: |
| 33 | +$ git clone [email protected]:aymenn/masked-comms-app.git |
| 34 | + |
| 35 | +# Make the repository your working directory: |
| 36 | +$ cd masked-comms-app |
| 37 | + |
| 38 | +# Install dependencies: |
| 39 | +$ yarn install |
| 40 | + |
| 41 | +# Copy the example envrionment variable file: |
| 42 | +$ cp .env.example .env |
| 43 | +``` |
| 44 | + |
| 45 | +| Variable Name | Description | Example | |
| 46 | +|---------------------------------|-------------------------------------------------------------------------------|------------------------------------------------------------| |
| 47 | +| TWILIO_ACCOUNT_SID | The identifier for your Twilio Account. | ACXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
| 48 | +| TWILIO_AUTH_TOKEN | The auth token for accessing the Twilio API. | ****************************** | |
| 49 | +| NUMBER_POOL | An array of phone numbers to use as your number pool in e164 format. | ["+141512345678", "+14230509876"] | |
| 50 | +| CALL_ANNOUCEMENT_VOICE | The type of voice to use for speech to text announcements. | "man", "woman", "alice", or any of the [Amazon Polly voices](https://www.twilio.com/docs/voice/twiml/say/text-speech#polly-standard-and-neural-voices). | |
| 51 | +| CALL_ANNOUCEMENT_LANGUAGE | The language to speak announcements in. | "en" or any of the [supported languages](https://www.twilio.com/docs/voice/twiml/say#attributes-language). | |
| 52 | +| OUT_OF_SESSION_MESSAGE_FOR_CALL | A message to play if someone calls the number pool without an active session. | "Your session is no longer active. Goodbye." | |
| 53 | +| CONNECTING_CALL_ANNOUCEMENT | A message to play when a caller is being connected to the other party. | "We're connecting you to your agent now." | |
| 54 | +| DOMAIN | The domain where the application will be hosted. | "mysite.com" or "https://your-domain.ngrok.io" | |
| 55 | + |
| 56 | + |
| 57 | +Once you have your environment variables set, you can start the app with this command: |
| 58 | + |
| 59 | +```bash |
| 60 | +$ yarn dev |
| 61 | + |
| 62 | +# or |
| 63 | + |
| 64 | +$ npm run dev |
| 65 | +``` |
| 66 | + |
| 67 | +To open a tunnel to your localhost that Twilio can send webhooks to, you can use ngrok: |
| 68 | + |
| 69 | +```bash |
| 70 | +$ ngrok http 3000 |
| 71 | +``` |
| 72 | + |
| 73 | +# Configuring Webhooks |
| 74 | +Two webhooks can be configured in the Twilio Console: |
| 75 | + |
| 76 | +1. Incoming call webhook: receives a request whenever a user makes an inbound call and connects them to the right people. |
| 77 | +- Go to Twilio Console > Phone Numbers > Manage > Active Numbers > Click on the number to configure. |
| 78 | +- Scroll down to the "Voice & Fax" configuration section to "A Call Comes In". |
| 79 | +- Select "Webhook" from the dropdown and paste in your webhook: `https://[your-domain]/inbound-call`. |
| 80 | + |
| 81 | +2. Conversation post-event webhook: this webhook can receive "conversation closed" events from Twilio Conversations and automatically delete the closed conversation. Keeping the pool of conversations small improves app performance and reduces cost. |
| 82 | + |
| 83 | +- Go to Twilio Console > Conversations > Manage > Services > Your Service > Webhooks. |
| 84 | +- Check the `onConversationStateUpdated` box. |
| 85 | +- Paste your webhook (`https://[your-domain]/conversations-post-event`) into the Post-Event URL input box. |
| 86 | +- Click "save" at the bottom of the page. |
| 87 | + |
| 88 | + |
| 89 | +# Usage |
| 90 | +You can create a new masked-number session between multiple users by making a post request to the `/sessions` endpoint: |
| 91 | + |
| 92 | +```bash |
| 93 | +curl --location --request POST 'localhost:3000/sessions' \ |
| 94 | +--header 'Authorization: Basic 123XYZ==' \ |
| 95 | +--header 'Content-Type: application/json' \ |
| 96 | +--data-raw '{ |
| 97 | + "addresses": [ |
| 98 | + "+1234567890", |
| 99 | + "+0123456789" |
| 100 | + ], |
| 101 | + "friendlyName": "My First Conversation" |
| 102 | +}' |
| 103 | +``` |
| 104 | +- The app supports basic auth, which can be configured in the .env file. |
| 105 | +- Addresses is an array of e164 formatted phone numbers. You can add between 1-50 participants to a conversation at a time. |
| 106 | +- The app also accepts all [conversations CREATE properties](https://www.twilio.com/docs/conversations/api/conversation-resource#conversation-properties), e.g. `friendlyName`. |
| 107 | + |
| 108 | +The app will respond with the JSON from a typical Create Converation API call: |
| 109 | + |
| 110 | +```json |
| 111 | +{ |
| 112 | + "accountSid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |
| 113 | + "chatServiceSid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |
| 114 | + "messagingServiceSid": "MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |
| 115 | + "sid": "CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |
| 116 | + "friendlyName": "My First Conversation", |
| 117 | + "uniqueName": null, |
| 118 | + "attributes": "{}", |
| 119 | + "state": "active", |
| 120 | + "dateCreated": "2022-07-22T05:41:18.000Z", |
| 121 | + "dateUpdated": "2022-07-22T05:41:18.000Z", |
| 122 | + "timers": {}, |
| 123 | + "url": "https://conversations.twilio.com/v1/Conversations/CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |
| 124 | + "links": { |
| 125 | + "participants": "https://conversations.twilio.com/v1/Conversations/CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Participants", |
| 126 | + "messages": "https://conversations.twilio.com/v1/Conversations/CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages", |
| 127 | + "webhooks": "https://conversations.twilio.com/v1/Conversations/CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Webhooks" |
| 128 | + }, |
| 129 | + "bindings": null |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +# Errors and Retries |
| 134 | +- The app will retry requests to Twilio when it recieves a `429 - Too many requests` error code. You can configure the retry behavior in `src/config/retry.config.ts`. |
| 135 | + |
| 136 | +- If you don't have enough phone numbers in your number pool, you'll receive a 500 response with the message `Not enough numbers available in pool for [phone_number]`. |
| 137 | + |
| 138 | +# Running Tests |
| 139 | +To execute unit tests, run: |
| 140 | + |
| 141 | +```bash |
| 142 | +$ yarn test |
| 143 | +``` |
| 144 | + |
| 145 | +To conduct a load test on the app, run: |
| 146 | +```bash |
| 147 | +$ yarn loadtest |
| 148 | +``` |
| 149 | +This will generate 300 conversations in 20ms intervals against the app. |
0 commit comments