<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Robert Svensson</title>
    <description>The latest articles on Forem by Robert Svensson (@robertsvensson).</description>
    <link>https://forem.com/robertsvensson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F25930%2Ff97c6c98-9f57-42ec-b08d-5aba14e8e205.png</url>
      <title>Forem: Robert Svensson</title>
      <link>https://forem.com/robertsvensson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/robertsvensson"/>
    <language>en</language>
    <item>
      <title>You might need a Web Application Security Scanner - but which one?</title>
      <dc:creator>Robert Svensson</dc:creator>
      <pubDate>Mon, 13 Aug 2018 11:50:26 +0000</pubDate>
      <link>https://forem.com/robertsvensson/you-might-need-a-web-application-security-scanner-but-whichone-16ii</link>
      <guid>https://forem.com/robertsvensson/you-might-need-a-web-application-security-scanner-but-whichone-16ii</guid>
      <description>&lt;p&gt;If you have a website, then chances are that your website is vulnerable to all sorts of attacks. And the bigger and more complex your site is, it's harder to keep track of potential security glitches.&lt;/p&gt;

&lt;p&gt;This is why you need a Web Application Security Scanner, or just a Scanner. At first sight, the Scanner's job is easy. It scans your web app and generates a report highlighting the security complications it found so that you can mitigate them.&lt;/p&gt;

&lt;p&gt;The problem is that since custom web apps can be put together in a million different ways, finding security issues with a Scanner is not always reliable. Sometimes the Scanner will find and report a vulnerability within your web app, and sometimes it won't.&lt;/p&gt;

&lt;p&gt;So just how good are some of the Scanners out there - and how can you know if you're getting your money's worth?&lt;/p&gt;

&lt;p&gt;To find out, I created a web app that has three big security flaws. These imperfections should ideally be detected and reported by all Scanners.&lt;/p&gt;

&lt;p&gt;The three flaws in the web app are:&lt;/p&gt;

&lt;h4&gt;
  
  
  One - Sensitive information as source code comment:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;!--the username for our most sensitive data is Summer2018 with the password MegaSecret--&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Two-Sensitive data exposure:
&lt;/h4&gt;

&lt;p&gt;The root folder has a file called passwd with the following content:&lt;br&gt;
&lt;code&gt;tom:x:1000:1000:Vivek Gite:/home/vivek:/bin/bash&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Three-Code injection:
&lt;/h4&gt;

&lt;p&gt;The website has a form where the user can fill in her e-mail address and press submit - and the e-mail address will be echoed below the submit button like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HT-NDNrT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AHSct9oJ4QAxF4wHE" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HT-NDNrT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AHSct9oJ4QAxF4wHE" alt="Unfiltered input" title="Unfiltered input"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is that the user input is not sanitized. So if anyone was to enter &lt;code&gt;&lt;h1&gt;Hello!!!&lt;/h1&gt;&lt;/code&gt; instead of their e-mail address we would get the rendered HTML like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ivmqa-k---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AAj3Fr42iWKeT6DpS" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ivmqa-k---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AAj3Fr42iWKeT6DpS" alt="Unfiltered input h1" title="Unfiltered input h1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it's also possible to insert JavaScript and all sorts of other unpleasant stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet the scanners
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Patronus.io&lt;/strong&gt;: They claim to be an -"automated security solution for your website". Sounds good to me but let's see if it's true shall we?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detectify&lt;/strong&gt;: Say that they "scan your website for security issues crowdsourced by 150+ white-hat hackers". Sounds pretty underground and cool doesn't it? But is it all talk?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tenable&lt;/strong&gt;: -They "…safely, accurately and automatically scan your web applications, providing deep visibility into vulnerabilities and valuable context to prioritize remediation". Great, but does it work?&lt;/p&gt;

&lt;h3&gt;
  
  
  Round one - Discovering sensitive information as source code comment
&lt;/h3&gt;

&lt;p&gt;No -Patronus.io&lt;br&gt;
Yes - Detectify&lt;br&gt;
No -Tenable&lt;/p&gt;

&lt;h3&gt;
  
  
  Round two - Discovering sensitive data exposure
&lt;/h3&gt;

&lt;p&gt;No - Patronus.io&lt;br&gt;
No - Detectify&lt;br&gt;
Yes - Tenable&lt;/p&gt;

&lt;h3&gt;
  
  
  Round three - Discovering Code injection
&lt;/h3&gt;

&lt;p&gt;No - Patronus.io&lt;br&gt;
Yes - Detectify&lt;br&gt;
No - Tenable&lt;/p&gt;

&lt;h2&gt;
  
  
  So who won?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The winner
&lt;/h3&gt;

&lt;p&gt;The Detectify scan took by far the longest to complete. But it sure was worth the wait. Detectify managed to find both the code injection vulnerability and the source code comment containing the username and the password. Detectify failed to find the passwd file but I can live with that shortcomming&lt;/p&gt;

&lt;h3&gt;
  
  
  Runner-up
&lt;/h3&gt;

&lt;p&gt;Tenable had no problem finding the passwd file in the root directory. However, the code injection vulnerability flew under the radar as did the username and password exposed in the HTML source code&lt;/p&gt;

&lt;h3&gt;
  
  
  Dead last
&lt;/h3&gt;

&lt;p&gt;Patronus on the other hand is surprisingly week. Their scanner did not find any of the three vulnerabilities. I suggest you take your money elsewhere as this product is only going to give you a false sense of security. Security tools that are this weak should be banned altogether - we simply deserve better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Automated scanner aren't very good. Sure, they can catch a low hanging fruit or two - but they are still way behind manual penetration testing. Scanners should therefore only be seen as a small piece of your security puzzle. Because if you rely on scanners alone for your web app security posture you might be in for a nasty surprise.&lt;/p&gt;

</description>
      <category>web</category>
      <category>security</category>
    </item>
    <item>
      <title>Running a serverless voter campaign with Contentful and Twilio</title>
      <dc:creator>Robert Svensson</dc:creator>
      <pubDate>Tue, 08 May 2018 14:43:52 +0000</pubDate>
      <link>https://forem.com/robertsvensson/running-a-serverless-voter-campaign-with-contentful-and-twilio-4332</link>
      <guid>https://forem.com/robertsvensson/running-a-serverless-voter-campaign-with-contentful-and-twilio-4332</guid>
      <description>

&lt;p&gt;Polly Politician is looking to get voted into office. She has teamed up with Selly Celebrity, and together they are running an SMS voter campaign.&lt;/p&gt;

&lt;p&gt;This article will explain how to integrate &lt;a href="https://www.contentful.com/why-contentful/?utm_campaign=devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&amp;amp;utm_medium=referral&amp;amp;utm_source=devto&amp;amp;utm_content=devto-running-a-serverless-voter-campaign-with-contentful-and-twilio" rel="noopener noreferrer"&gt;Contentful&lt;/a&gt; and the &lt;a href="https://www.twilio.com/sms/" rel="noopener noreferrer"&gt;Twilio Programmable SMS API&lt;/a&gt; with the Flask microframework for Python. The article will also highlight how to set up webhooks in Contentful, and how to deploy it all to &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; to make the app genuinely serverless — all in the name of getting Polly Politician as many votes as possible. &lt;/p&gt;

&lt;p&gt;Note: This article assumes that you have user accounts for &lt;a href="https://www.contentful.com/sign-up/?utm_campaign=devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&amp;amp;utm_medium=referral&amp;amp;utm_source=devto&amp;amp;utm_content=devto-running-a-serverless-voter-campaign-with-contentful-and-twilio" rel="noopener noreferrer"&gt;Contentful&lt;/a&gt;, &lt;a href="https://www.twilio.com/try-twilio" rel="noopener noreferrer"&gt;Twilio&lt;/a&gt; and &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;Amazon AWS&lt;/a&gt; — using their respective free tiers will do just fine.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we’ll be building
&lt;/h3&gt;

&lt;p&gt;We’re putting together a Python Flask app that will send campaign messages like "Vote for Polly — she’s the best" to potential voters via SMS. &lt;/p&gt;

&lt;p&gt;This will work by grabbing content from Contentful using the &lt;a href="https://www.contentful.com/developers/docs/references/content-delivery-api/?utm_campaign=devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&amp;amp;utm_medium=referral&amp;amp;utm_source=devto&amp;amp;utm_content=devto-running-a-serverless-voter-campaign-with-contentful-and-twilio" rel="noopener noreferrer"&gt;Contentful content delivery API&lt;/a&gt;, and then connect to Twilio’s &lt;a href="https://www.twilio.com/sms/" rel="noopener noreferrer"&gt;Programmable SMS API&lt;/a&gt; to get the messages delivered.&lt;/p&gt;

&lt;p&gt;We’ll also configure webhooks to make sure that whenever the campaign manager publishes a new campaign message, that message will be sent to Twilio’s &lt;a href="https://www.twilio.com/sms/" rel="noopener noreferrer"&gt;Programmable SMS API&lt;/a&gt; and subsequently delivered to voters.   &lt;/p&gt;

&lt;p&gt;By reading this article you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get started with Contentful&lt;/li&gt;
&lt;li&gt;Use the Contentful Python SDK&lt;/li&gt;
&lt;li&gt;Integrate Contentful and Twilio&lt;/li&gt;
&lt;li&gt;Set up webhooks in Contentful&lt;/li&gt;
&lt;li&gt;Deploy to Amazon AWS using Zappa&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install dependencies and set up a minimal Flask app
&lt;/h3&gt;

&lt;p&gt;We start by installing the packages for Flask, Contentful and Twilio like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;flask contentful twilio
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

And to make sure that we have debugging &lt;span class="k"&gt;in &lt;/span&gt;place, and to point out our soon-to-be-created Flask app, we’ll run:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~bash
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FLASK_DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app.py
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

The flask app will have a single &lt;span class="k"&gt;function &lt;/span&gt;called &lt;span class="k"&gt;**&lt;/span&gt;runVoterCampaign&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;**&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; So the initial version of our Flask app will look like so:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt; 

~~~python
from contentful import Client as contentfulClient
from twilio.rest import Client as twilioClient
from flask import Flask
app &lt;span class="o"&gt;=&lt;/span&gt; Flask&lt;span class="o"&gt;(&lt;/span&gt;__name__&lt;span class="o"&gt;)&lt;/span&gt;
@app.route&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
def runVoterCampaign&lt;span class="o"&gt;()&lt;/span&gt;:
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello World!"&lt;/span&gt;
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;### Getting started with Contentful&lt;/span&gt;

In short - &lt;span class="o"&gt;[&lt;/span&gt;Contentful is content infrastructure]&lt;span class="o"&gt;(&lt;/span&gt;https://www.contentful.com/r/knowledgebase/content-infrastructure/?utm_campaign&lt;span class="o"&gt;=&lt;/span&gt;devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&amp;amp;utm_medium&lt;span class="o"&gt;=&lt;/span&gt;referral&amp;amp;utm_source&lt;span class="o"&gt;=&lt;/span&gt;devto&amp;amp;utm_content&lt;span class="o"&gt;=&lt;/span&gt;devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; So &lt;span class="k"&gt;if &lt;/span&gt;you have text, images or any other kind of digital assets that you want to serve to your &lt;span class="nb"&gt;users&lt;/span&gt;, you can use Contentful to edit, manage and deliver content via Contentful’s WebApp and through API-calls.

Contentful stores your data &lt;span class="k"&gt;in &lt;/span&gt;so-called spaces. You can think of spaces like a project-specific bucket that you fill up with all sorts of assets belonging to your project.

&lt;span class="c"&gt;#### Creating a space &lt;/span&gt;

When you create your free Contentful account you will be asked to create a space. While there are examples to get you started, we’re going to create an empty space called &lt;span class="k"&gt;**&lt;/span&gt;Getting More Votes&lt;span class="k"&gt;**&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/4DnnUw0L5uAi64cwW2yowG/3f215a4265ec1fbd3b626b7c0dd92ce5/1_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;#### Creating content types&lt;/span&gt;

With our Contentful space &lt;span class="k"&gt;in &lt;/span&gt;place, the next step is to create content types that go into that space. 

For this implementation to work we need to create two content types: voterMessage and voterNumbers.

Let’s start with creating a voterMessage content &lt;span class="nb"&gt;type&lt;/span&gt;:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/6R1LKYKK2cwWqCiYSkAaiq/b76fde8c931f15d9dc88ab0543997cb8/2_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

Once the content &lt;span class="nb"&gt;type &lt;/span&gt;has been created, we will need to add a field to hold our information:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/4hhV7DUGhqCEOGGMsCkg4a/7a6c919de1941da7bb85012e663ad575/3_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

We’ll go with a single text field:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/CyG29aiPGoEM4GQcqymUE/c14ebc5426dbb859900c62d5dee93869/4_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

And name it messageToVoters like so:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/5D4UGyTHZSs4Oi88wqIImQ/e5209b427cf3d53f940ff1fa1cec1e3d/5_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

With the content &lt;span class="nb"&gt;type &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;place, &lt;span class="nb"&gt;let&lt;/span&gt;’s add the message that will be sent out to potential voters by selecting &lt;span class="k"&gt;**&lt;/span&gt;Content/Add entry/voterMessage&lt;span class="k"&gt;**&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

The message that Polly Politician wants to send out is — &lt;span class="s2"&gt;"Selly Celebrity supports Polly Politician — you should too"&lt;/span&gt;, so &lt;span class="nb"&gt;let&lt;/span&gt;’s add just that:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/1kWHO1ImoYEYmsUmCwya0y/13c7937c0f2d95c794fc120ee04bae46/6_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

Once we hit the green publish button, Polly’s voter message will get a unique entry ID. We’ll use this entry ID when retrieving the entry via &lt;span class="o"&gt;[&lt;/span&gt;Contentful’s &lt;span class="o"&gt;](&lt;/span&gt;https://www.contentful.com/developers/docs/references/content-delivery-api/?utm_campaign&lt;span class="o"&gt;=&lt;/span&gt;devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&amp;amp;utm_medium&lt;span class="o"&gt;=&lt;/span&gt;referral&amp;amp;utm_source&lt;span class="o"&gt;=&lt;/span&gt;devto&amp;amp;utm_content&lt;span class="o"&gt;=&lt;/span&gt;devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&lt;span class="o"&gt;)[&lt;/span&gt;Content &lt;span class="o"&gt;](&lt;/span&gt;https://www.contentful.com/developers/docs/references/content-delivery-api/&lt;span class="o"&gt;)[&lt;/span&gt;Delivery API]&lt;span class="o"&gt;(&lt;/span&gt;https://www.contentful.com/developers/docs/references/content-delivery-api/?utm_campaign&lt;span class="o"&gt;=&lt;/span&gt;devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&amp;amp;utm_medium&lt;span class="o"&gt;=&lt;/span&gt;referral&amp;amp;utm_source&lt;span class="o"&gt;=&lt;/span&gt;devto&amp;amp;utm_content&lt;span class="o"&gt;=&lt;/span&gt;devto-running-a-serverless-voter-campaign-with-contentful-and-twilio&lt;span class="o"&gt;)&lt;/span&gt;, or CDA.

To view the entry ID, click the info button:



&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/3a09Sj3Qc8Q2kcGAKIYmaa/00211ab37dba74956afba11bdda97f1d/7_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

Our entry is &lt;span class="k"&gt;**&lt;/span&gt;Ykt2v3ixYQwwAekwSKg0A&lt;span class="k"&gt;**&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;### Connecting our app to Contentful&lt;/span&gt;

To authenticate against the CDA, we’ll need to create an API key — &lt;span class="k"&gt;do &lt;/span&gt;this by navigating to &lt;span class="k"&gt;**&lt;/span&gt;Space settings&lt;span class="k"&gt;**&lt;/span&gt; and &lt;span class="k"&gt;**&lt;/span&gt;API Keys&lt;span class="k"&gt;**&lt;/span&gt;:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/4I7aQNew3uSI8AuUqCWg4k/4fbdcd477bd2d2ebef0ca75ccc6c2bab/8_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

Then click &lt;span class="k"&gt;**&lt;/span&gt;Add API key&lt;span class="k"&gt;**&lt;/span&gt; and give your key a suitable name:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/69u6Z4BQPeiMosOsq604os/e606d6c9724a0d2daa03fefdd36ef255/9_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

Now that we have our API key, &lt;span class="nb"&gt;let&lt;/span&gt;’s create a &lt;span class="k"&gt;function &lt;/span&gt;called &lt;span class="k"&gt;**&lt;/span&gt;getVoterMessage&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;**&lt;/span&gt; that utilizes this API key to grab content from Contentful.&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~python
def getVoterMessage&lt;span class="o"&gt;()&lt;/span&gt;:
    SPACE_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'1476xanqlrah'&lt;/span&gt;
    CONTENT_DELIVERY_API_KEY &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'dae35c068382427841441c61a6370d57101ba94a0f6e6e7cb22ca655c16b7f67'&lt;/span&gt;
    ENTRY_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Ykt2v3ixYQwwAekwSKg0A'&lt;/span&gt;
    client &lt;span class="o"&gt;=&lt;/span&gt; contentfulClient&lt;span class="o"&gt;(&lt;/span&gt;SPACE_ID, CONTENT_DELIVERY_API_KEY&lt;span class="o"&gt;)&lt;/span&gt;
    entry &lt;span class="o"&gt;=&lt;/span&gt; client.entry&lt;span class="o"&gt;(&lt;/span&gt;ENTRY_ID&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;entry.message_to_voters
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

Note that Contentful’s Python SDK will convert field names to snake &lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; That’s why our &lt;span class="k"&gt;**&lt;/span&gt;messageToVoters&lt;span class="k"&gt;**&lt;/span&gt; field is addressed as &lt;span class="k"&gt;**&lt;/span&gt;entry.message_to_voters&lt;span class="k"&gt;**&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;the snippet above. All &lt;span class="k"&gt;in &lt;/span&gt;the name of PEP 8 compliance.

And &lt;span class="k"&gt;if &lt;/span&gt;we temporarily change our Flask route to &lt;span class="nb"&gt;echo &lt;/span&gt;the content, we would get from Contentful like this:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~python
@app.route&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
def runVoterCampaign&lt;span class="o"&gt;()&lt;/span&gt;:
    voterMessage &lt;span class="o"&gt;=&lt;/span&gt; getVoterMessage&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;voterMessage
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

We would get:

&lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/2HEmDOaZ04e8ewsmYK0yay/c8c9bef2ed146a519a0fb2dab2bb0593/10_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

The next step is to connect our app to Twilio’s Programmable SMS API.

&lt;span class="c"&gt;### Connecting to Twilio’s Programmable SMS API&lt;/span&gt;

So we’ve written the &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;getVoterMessage&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;**&lt;/span&gt; to get our voter message from Contentful. Let’s write another &lt;span class="k"&gt;function &lt;/span&gt;that takes this message and sends it out as an SMS:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~python
def sendMessageToVoter&lt;span class="o"&gt;(&lt;/span&gt;voterMessage&lt;span class="o"&gt;)&lt;/span&gt;:
    ACCOUNT_SID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'AC046db3e3b2dd0……..'&lt;/span&gt;
    AUTH_TOKEN &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'88572d13934ee1a5……….'&lt;/span&gt;
    client &lt;span class="o"&gt;=&lt;/span&gt; twilioClient&lt;span class="o"&gt;(&lt;/span&gt;ACCOUNT_SID, AUTH_TOKEN&lt;span class="o"&gt;)&lt;/span&gt;
    client.api.account.messages.create&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"+15552395"&lt;/span&gt;,
        &lt;span class="nv"&gt;from_&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"+4915375998263"&lt;/span&gt;,
        &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;voterMessage&lt;span class="o"&gt;)&lt;/span&gt;
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

To get the &lt;span class="k"&gt;function &lt;/span&gt;to execute, we’ll change the Flask route to the following:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~python
@app.route&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
def runVoterCampaign&lt;span class="o"&gt;()&lt;/span&gt;:
    voterMessage &lt;span class="o"&gt;=&lt;/span&gt; getVoterMessage&lt;span class="o"&gt;()&lt;/span&gt;
    sendMessageToVoter&lt;span class="o"&gt;(&lt;/span&gt;voterMessage&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'Message sent to voter'&lt;/span&gt;
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

Seconds after the &lt;span class="k"&gt;function &lt;/span&gt;executes, the receiver will see the following SMS:

 &lt;span class="o"&gt;![&lt;/span&gt;image alt text]&lt;span class="o"&gt;(&lt;/span&gt;https://images.ctfassets.net/fo9twyrwpveg/1cBc9pSu4k8QM2acwAAioi/6a117b98e6eb15940c5359fe48de7153/11_twilio_contentful.png&lt;span class="o"&gt;)&lt;/span&gt;

With the app’s core functionality &lt;span class="k"&gt;in &lt;/span&gt;place, &lt;span class="nb"&gt;let&lt;/span&gt;’s make our app serverless by deploying it to AWS lambda.

&lt;span class="c"&gt;### Deploying our local app to AWS Lambda using Zappa&lt;/span&gt;

AWS Lambda lets you run code without provisioning or managing servers.
So far we’ve only been running our Flask app locally. 

To deploy the app to AWS, we’ll be using &lt;span class="o"&gt;[&lt;/span&gt;Zappa]&lt;span class="o"&gt;(&lt;/span&gt;https://www.zappa.io/&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Install Zappa like so:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~bash
pip &lt;span class="nb"&gt;install &lt;/span&gt;zappa 
~~~&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

We’ll &lt;span class="k"&gt;then &lt;/span&gt;run &lt;span class="k"&gt;**&lt;/span&gt;zappa init&lt;span class="k"&gt;**&lt;/span&gt; to generate a configuration file:&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;

~~~bash

Welcome to Zappa!

Zappa is a system &lt;span class="k"&gt;for &lt;/span&gt;running server-less Python web applications on AWS Lambda and AWS API Gateway.
This &lt;span class="sb"&gt;`&lt;/span&gt;init&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="nb"&gt;command &lt;/span&gt;will &lt;span class="nb"&gt;help &lt;/span&gt;you create and configure your new Zappa deployment.

Let&lt;span class="s1"&gt;'s get started!
Your Zappa configuration can support multiple production stages, like '&lt;/span&gt;dev&lt;span class="s1"&gt;', '&lt;/span&gt;staging&lt;span class="s1"&gt;', and '&lt;/span&gt;production&lt;span class="s1"&gt;'.

What do you want to call this environment (default '&lt;/span&gt;dev&lt;span class="s1"&gt;'): 

AWS Lambda and API Gateway are only available in certain regions. Let'&lt;/span&gt;s check to make sure you have a profile &lt;span class="nb"&gt;set &lt;/span&gt;up &lt;span class="k"&gt;in &lt;/span&gt;one that will work.

Okay, using profile default!

Your Zappa deployments will need to be uploaded to a private S3 bucket.
If you don&lt;span class="s1"&gt;'t have a bucket yet, we'&lt;/span&gt;ll create one &lt;span class="k"&gt;for &lt;/span&gt;you too.
What &lt;span class="k"&gt;do &lt;/span&gt;you want to call your bucket? &lt;span class="o"&gt;(&lt;/span&gt;default &lt;span class="s1"&gt;'zappa-w57kc2zrw'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;: 
It looks like this is a Flask application.
What&lt;span class="s1"&gt;'s the modular path to your app'&lt;/span&gt;s &lt;span class="k"&gt;function&lt;/span&gt;?
This will likely be something like &lt;span class="s1"&gt;'your_module.app'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
We discovered: app.app
Where is your app&lt;span class="s1"&gt;'s function? (default '&lt;/span&gt;app.app&lt;span class="s1"&gt;'): 
You can optionally deploy to all available regions in order to provide fast global service.
If you are using Zappa for the first time, you probably don'&lt;/span&gt;t want to &lt;span class="k"&gt;do &lt;/span&gt;this!

Would you like to deploy this application globally? &lt;span class="o"&gt;(&lt;/span&gt;default &lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;y/n/&lt;span class="o"&gt;(&lt;/span&gt;p&lt;span class="o"&gt;)&lt;/span&gt;rimary]: 

Okay, here&lt;span class="s1"&gt;'s your zappa_settings.json:

{
    "dev": {
        "app_function": "app.app",
        "aws_region": "us-east-1",
        "profile_name": "default",
        "project_name": "twiliocontentfu",
        "runtime": "python3.6",
        "s3_bucket": "zappa-w57kc2zrw"
    }
}

Does this look okay? (default '&lt;/span&gt;y&lt;span class="s1"&gt;') [y/n]: 
~~~

Now run **zappa deploy dev** to deploy the app to AWS Lambda:

~~~bash

Calling **deploy** for stage **dev**..
Creating twiliocontentfu-dev-ZappaLambdaExecutionRole IAM Role..
Creating zappa-permissions policy on twiliocontentfu-dev-ZappaLambdaExecutionRole IAM Role.

Warning! Your project and virtualenv have the same name! You may want to re-create your venv with a new name, or explicitly define a '&lt;/span&gt;project_name&lt;span class="s1"&gt;', as this may cause errors.

Downloading and installing dependencies..

 - sqlite==python36: Using precompiled lambda package

Packaging project as zip.

Uploading twiliocontentfu-dev-1523880262.zip (16.2MiB)..

100%|███████████████████████████████████████| 17.0M/17.0M [00:32&amp;lt;00:00, 362KB/s]

Scheduling..

Scheduled twiliocontentfu-dev-zappa-keep-warm-handler.keep_warm_callback with expression rate(4 minutes)!

Uploading twiliocontentfu-dev-template-1523880329.json (1.6KiB)..

100%|██████████████████████████████████████| 1.64K/1.64K [00:01&amp;lt;00:00, 1.30KB/s]

Waiting for stack twiliocontentfu-dev to create (this can take a bit)..

100%|████████████████████████████████████████████| 4/4 [00:10&amp;lt;00:00,  2.61s/res]

Deploying API Gateway..

**Deployment complete**!: https://bz9zie872.execute-api.us-east-1.amazonaws.com/dev

~~~

The deploy was successful and our Flask app now runs serverless at hxxps://bz9zie872.execute-api.us-east-1.amazonaws.com/dev. 

The next step is to configure webhooks in Contentful so that whenever a new campaign message gets published.

### Setting up webhooks in Contentful

We want to set up a webhook so that every time the campaign message changes and the campaign manager pushes the publish button, an HTTP POST requests gets sent to our serverless AWS Lambda app — which in turn will send out a text message.

To configure a webhook we’ll navigate to **Space settings** and **webhooks**:



![image alt text](https://images.ctfassets.net/fo9twyrwpveg/4H9wD5jC5ayWK64KySqOKg/8cffe3da16a437dffb4cc28e168204d8/12_twilio_contentful.png)

And then click **Add webhook**.

We’ll configure the target of our webhook to be our AWS lambda function at hxxps://bz9zie872.execute-api.us-east-1.amazonaws.com/dev.

Also, we’ll set up the webhook to trigger we hit the publish button:

![image alt text](https://images.ctfassets.net/fo9twyrwpveg/4xJ79ZpyMU8EYc04yGacWa/ca8278741c0d74f16a5f21d4de0bcfad/13_twilio_contentful.png)

The idea is now that when we change our campaign message and hit publish. The updated message will be delivered to voters via SMS with the push of a button. But before that can happen, we’ll need to return to our **runVoterCampaign** function.

Contentful’s webhooks are sent as **HTTP POST**. This means that we’ll have to add **POST** method support:

~~~python
@app.route("/", methods=['&lt;/span&gt;GET&lt;span class="s1"&gt;', '&lt;/span&gt;POST&lt;span class="s1"&gt;'])
def runVoterCampaign():
    voterMessage = getVoterMessage()
    sendMessageToVoter(voterMessage)
    return '&lt;/span&gt;Message sent to voter&lt;span class="s1"&gt;'
~~~

Now let’s update our serverless app using Zappa 

~~~bash
zappa update dev
~~~~

To test our new webhook we’ll update the campaign message like so:

![image alt text](https://images.ctfassets.net/fo9twyrwpveg/5iq8BIvzFYUwy4AKQWqAGS/bf97587bb92d811c38161869f64e61e1/14_twilio_contentful.png)

Hit the big green publish button, and no time later we’ll have the following message on our phone:

![image alt text](https://images.ctfassets.net/fo9twyrwpveg/1vj1YUpy8wwSui0w42EgkK/e7656e38b165a7dfc137b2d289b2afe9/15_twilio_contentful.png)

Yes!!! It works. Pretty easy right :)

### Summary

Without too much effort, we’ve built a solution that grabs data from Contentful and sends it to users via Twilio’s programmable SMS API — all while running serverless.

We’ve also seen how webhooks can be configured to trigger on changes made to content stored with Contentful. Webhooks that in turn call AWS Lambda functions.

In this article, we built a Flask app. Now, Getting code deployed to AWS Lambda can be surprisingly complex — but using Zappa makes sending Flask apps to the cloud easier than ever.

A logic flow of what we’ve created looks like so:

![Logic flow chart](https://images.ctfassets.net/fo9twyrwpveg/1QWmCEzEGwESEqwk2KAmE4/ee4c53c046794270427c569af457897a/16_twilio_contentful.png)

### What lies ahead?

Serverless is the way to go. No more having to worry about keeping servers patched — not to mention the burden of keeping perhaps thousands of servers up and running. Going serverless means that you can focus on code, and not on maintenance.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>flask</category>
      <category>python</category>
      <category>twilio</category>
      <category>contentful</category>
    </item>
  </channel>
</rss>
