diff --git a/masked-number/.env b/masked-number/.env deleted file mode 100644 index fb964af7..00000000 --- a/masked-number/.env +++ /dev/null @@ -1,9 +0,0 @@ -# description: Messages sent to your Twilio number will get forwarded to this E.164-formatted phone number -# format: phone_number -# required: true -# link: https://www.twilio.com/docs/glossary/what-e164 -MY_PHONE_NUMBER=+12223334444 - -# description: The path to the webhook -# configurable: false -TWILIO_SMS_WEBHOOK_URL=/relay-sms diff --git a/masked-number/masked-number-demo/.gitignore b/masked-number/masked-number-demo/.gitignore new file mode 100644 index 00000000..ca7e037f --- /dev/null +++ b/masked-number/masked-number-demo/.gitignore @@ -0,0 +1,133 @@ +# Twilio Serverless +.twiliodeployinfo + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/masked-number/masked-number-demo/.nvmrc b/masked-number/masked-number-demo/.nvmrc new file mode 100644 index 00000000..25bf17fc --- /dev/null +++ b/masked-number/masked-number-demo/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/masked-number/masked-number-demo/.twilioserverlessrc b/masked-number/masked-number-demo/.twilioserverlessrc new file mode 100644 index 00000000..a7f5a1cb --- /dev/null +++ b/masked-number/masked-number-demo/.twilioserverlessrc @@ -0,0 +1,42 @@ +{ + "commands": {}, + "environments": {}, + "projects": {}, + // "assets": true /* Upload assets. Can be turned off with --no-assets */, + // "assetsFolder": null /* Specific folder name to be used for static assets */, + // "buildSid": null /* An existing Build SID to deploy to the new environment */, + // "createEnvironment": false /* Creates environment if it couldn't find it. */, + // "cwd": null /* Sets the directory of your existing Serverless project. Defaults to current directory */, + // "detailedLogs": false /* Toggles detailed request logging by showing request body and query params */, + // "edge": null /* Twilio API Region */, + // "env": null /* Path to .env file for environment variables that should be installed */, + // "environment": "dev" /* The environment name (domain suffix) you want to use for your deployment. Alternatively you can specify an environment SID starting with ZE. */, + // "extendedOutput": false /* Show an extended set of properties on the output */, + // "force": false /* Will run deployment in force mode. Can be dangerous. */, + // "forkProcess": true /* Disable forking function processes to emulate production environment */, + // "functionSid": null /* Specific Function SID to retrieve logs for */, + // "functions": true /* Upload functions. Can be turned off with --no-functions */, + // "functionsFolder": null /* Specific folder name to be used for static functions */, + // "inspect": null /* Enables Node.js debugging protocol */, + // "inspectBrk": null /* Enables Node.js debugging protocol, stops execution until debugger is attached */, + // "legacyMode": false /* Enables legacy mode, it will prefix your asset paths with /assets */, + // "live": true /* Always serve from the current functions (no caching) */, + // "loadLocalEnv": false /* Includes the local environment variables */, + // "loadSystemEnv": false /* Uses system environment variables as fallback for variables specified in your .env file. Needs to be used with --env explicitly specified. */, + // "logCacheSize": null /* Tailing the log endpoint will cache previously seen entries to avoid duplicates. The cache is topped at a maximum of 1000 by default. This option can change that. */, + // "logLevel": "info" /* Level of logging messages. */, + // "logs": true /* Toggles request logging */, + // "ngrok": null /* Uses ngrok to create a public url. Pass a string to set the subdomain (requires a paid-for ngrok account). */, + // "outputFormat": "" /* Output the results in a different format */, + // "overrideExistingProject": false /* Deploys Serverless project to existing service if a naming conflict has been found. */, + // "port": "3000" /* Override default port of 3000 */, + // "production": false /* Promote build to the production environment (no domain suffix). Overrides environment flag */, + // "properties": null /* Specify the output properties you want to see. Works best on single types */, + // "region": null /* Twilio API Region */, + "runtime": "node18" /* The version of Node.js to deploy the build to. (node18) */, + // "serviceName": null /* Overrides the name of the Serverless project. Default: the name field in your package.json */, + // "serviceSid": null /* SID of the Twilio Serverless Service to deploy to */, + // "sourceEnvironment": null /* SID or suffix of an existing environment you want to deploy from. */, + // "tail": false /* Continuously stream the logs */, + // "template": null /* undefined */, +} \ No newline at end of file diff --git a/masked-number/masked-number-demo/assets/index.html b/masked-number/masked-number-demo/assets/index.html new file mode 100644 index 00000000..1e172050 --- /dev/null +++ b/masked-number/masked-number-demo/assets/index.html @@ -0,0 +1,105 @@ + + + + + + + Get started with your Twilio Functions! + + + + + + + + +
+
+ + +
+
+
+
+

+ +
+

Welcome!

+

Your live application with Twilio is ready to use!

+
+

+
+

Get started with your application

+

+ Follow these steps to try out your new app: +

+

+ This app masks your phone number for SMS messages by relaying them through a + Twilio phone number. +

+
    +
  1. + Text your Twilio phone number with a recipient phone number, a + :, and a message. For example, to send the message "hello" to + the number "+12223334444", text your Twilio phone number with: + +12223334444: hello. +
  2. +
  3. Your recipient should receive your message from your Twilio phone number.
  4. +
  5. + When that recipient sends a reply to your Twilio phone number, it will be + relayed to your personal phone number. +
  6. +
+
+ +
+ +
+
+

Troubleshooting

+
    +
  • + Check the + + phone number configuration + + and make sure the Twilio phone number you want for your app has a SMS webhook + configured to point at the following URL +
    + + +
    +
  • +
  • + Ensure that MY_PHONE_NUMBER is set to the phone number you want + to relay messages to, in + + E.164 format + . +
  • +
+
+
+
+ + + diff --git a/masked-number/masked-number-demo/functions/relay-sms.protected.js b/masked-number/masked-number-demo/functions/relay-sms.protected.js new file mode 100644 index 00000000..38658c8b --- /dev/null +++ b/masked-number/masked-number-demo/functions/relay-sms.protected.js @@ -0,0 +1,95 @@ +/* + * Masking your phone number for SMS Forwarding and Responding + * + * Description: + * This function acts as a message-forwarding service + * If the message comes from the user, it forwards the message to another number. + * If it comes from someone else, it forwards it to the user. + * + * Contents: + * 1. Initialize Client and Response + * 2. Sender Check + * 3. Extracting Recipient and Message + * 4. Sending the Message + * 5. Handling Messages from Other Senders + */ + +/* + * 1. Initialize client and response + * + * Here you can initialize a Twilio client (client) to interact with Twilio's API. + * + * A twiml object is created to generate TwiML (Twilio Markup Language) responses, + * which are instructions that tell Twilio how to respond to an incoming message. + */ + +// Defines the main function handler for the Twilio Function. +exports.handler = async function (context, event, callback) { + const client = context.getTwilioClient(); + const twiml = new Twilio.twiml.MessagingResponse(); + +/* + * 2. Checking the Sender + * + * Here you can checks if the message came from a specific number. + * This condition ensures that only the user with this phone number can send outgoing messages. + */ + if (event.From === context.MY_PHONE_NUMBER) { + // Looks for a : in the message body to separate the recipient's phone number from the message text. + const separatorPosition = event.Body.indexOf(':'); + + // If there is no :, a response is sent to the sender with a message explaining the required format: recipientPhoneNumber: message. + if (separatorPosition < 1) { + twiml.message( + 'You need to specify a recipient number and a ":" before the message. For example, "+12223334444: message".' + ); + + /* + * 3. Extracting Recipient and Message + * + * Here you can processes the incoming message body + * to extract the recipient's phone number and the actual message content + */ + + } else { + // Extracts the recipient's phone number from the part of the message before the : and removes any extra whitespace. + const recipientNumber = event.Body.substr(0, separatorPosition).trim(); + // Extracts the actual message from the part of the message after the ':' + const messageBody = event.Body.substr(separatorPosition + 1).trim(); + + /* + * 4. Sending the Message + * + * Here a try-catch block attempts to send an SMS message using the Twilio API + */ + try { + // Sends the SMS to recipientNumber with the message messageBody. + await client.messages.create({ + to: recipientNumber, + from: event.To, + body: messageBody, + }); + // If successful, callback(null) is called to signal that the function executed successfully without returning any TwiML. + return callback(null); + // If there is an error (e.g., an invalid phone number), a failure message is sent to the sender explaining that the phone number might be incorrect. + } catch (err) { + twiml.message( + 'There was an issue with the phone number you entered; please verify it is correct and try again.' + ); + } + } + /* + * 5. Handling Messages from Other Senders + * + * If the message is not from context.MY_PHONE_NUMBER, + * the function forwards it to the number stored in context.MY_PHONE_NUMBER, + */ + } else { + twiml.message( + { to: context.MY_PHONE_NUMBER }, + `${event.From}: ${event.Body}` + ); + } + + return callback(null, twiml); +}; diff --git a/masked-number/masked-number-demo/package.json b/masked-number/masked-number-demo/package.json new file mode 100644 index 00000000..f511c8a2 --- /dev/null +++ b/masked-number/masked-number-demo/package.json @@ -0,0 +1,20 @@ +{ + "name": "masked-number-demo", + "version": "0.0.0", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "twilio-run", + "deploy": "twilio-run deploy" + }, + "dependencies": { + "twilio": "5.0.3", + "@twilio/runtime-handler": "2.0.3" + }, + "devDependencies": { + "twilio-run": "^4.0.3" + }, + "engines": { + "node": "18" + } +} \ No newline at end of file diff --git a/masked-number/masked-number-demo/readmes/masked-number.md b/masked-number/masked-number-demo/readmes/masked-number.md new file mode 100644 index 00000000..4f855268 --- /dev/null +++ b/masked-number/masked-number-demo/readmes/masked-number.md @@ -0,0 +1,50 @@ +# Masked Number + +Uses a Twilio phone number to relay SMS messages to and from your phone; since the other party only sees your Twilio number, this effectively allows you to mask your phone number for privacy purposes. + +## Pre-requisites + +### Environment variables + +This project requires some environment variables to be set. To keep your tokens and secrets secure, make sure to not commit the `.env` file in git. When setting up the project with `twilio serverless:init ...` the Twilio CLI will create a `.gitignore` file that excludes `.env` from the version history. + +In your `.env` file, set the following values: + +| Variable | Description | Required | +| :-------------- | :------------------------------------------------- | :------- | +| MY_PHONE_NUMBER | The phone number which SMS messages get relayed to | Yes | + +## Create a new project with the template + +1. Install the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart#install-twilio-cli) +2. Install the [serverless toolkit](https://www.twilio.com/docs/labs/serverless-toolkit/getting-started) + +```shell +twilio plugins:install @twilio-labs/plugin-serverless +``` + +3. Initiate a new project + +``` +twilio serverless:init example --template=masked-number && cd example +``` + +4. Start the server with the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart): + +``` +twilio serverless:start +``` + +5. Open the web page at https://localhost:3000/index.html and enter your phone number to test + +ℹ️ Check the developer console and terminal for any errors, make sure you've set your environment variables. + +## Deploying + +Deploy your functions and assets with either of the following commands. Note: you must run these commands from inside your project folder. [More details in the docs.](https://www.twilio.com/docs/labs/serverless-toolkit) + +With the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart): + +``` +twilio serverless:deploy +``` diff --git a/masked-number/package.json b/masked-number/package.json index 249bce8d..4366bcb2 100644 --- a/masked-number/package.json +++ b/masked-number/package.json @@ -1,6 +1,14 @@ { "name": "masked-number", "version": "1.0.0", - "private": true, - "dependencies": {} + "description": "Uses a Twilio phone number to relay SMS messages to and from your phone; since the other party only sees your Twilio number, this effectively allows you to mask your phone number for privacy purposes.", + "main": "index.js", + "directories": { + "test": "tests" + }, + "scripts": { + "test": "jest" + }, + "author": "", + "license": "ISC" } diff --git a/masked-number/package.json.backup b/masked-number/package.json.backup new file mode 100644 index 00000000..691b6e73 --- /dev/null +++ b/masked-number/package.json.backup @@ -0,0 +1,8 @@ +{ + "name": "masked-number", + "version": "1.0.0", + "private": true, + "devDependencies": { + "jest": "^29.7.0" + } +}