[Bps-public-commit] rt-extension-smswebhook-twilio branch master updated. 561e0f83520c544c58b84d2bae5647e880cbfbd3

BPS Git Server git at git.bestpractical.com
Wed Jun 29 02:42:36 UTC 2022


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt-extension-smswebhook-twilio".

The branch, master has been updated
  discards  b8144f0e273d48468efe04a65cf06d572f3d094d (commit)
  discards  7a4c247a19e22f6628b31f2beceea78f49ff6d58 (commit)
  discards  98f0337fb1dcbad3d2441ae3ed6c550994fbcfbd (commit)
  discards  faee06fb530423ce6bf3e45266552e39b6c35a6b (commit)
  discards  4a4283488cdd9f96e5664d1d1832c15c8f7813c4 (commit)
       via  561e0f83520c544c58b84d2bae5647e880cbfbd3 (commit)
       via  8894812e2e7a40e7d4570bdc26be249bf86941ef (commit)
       via  a2495c55c08c34d630c662a78ba699ff5c78406c (commit)
       via  9061c72bb5743f7aaf82e3e8e885a1905109da97 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (b8144f0e273d48468efe04a65cf06d572f3d094d)
            \
             N -- N -- N (561e0f83520c544c58b84d2bae5647e880cbfbd3)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 561e0f83520c544c58b84d2bae5647e880cbfbd3
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Apr 3 11:55:45 2022 -0700

    Prep for first release: version 0.01

diff --git a/Changes b/Changes
new file mode 100644
index 0000000..37bd214
--- /dev/null
+++ b/Changes
@@ -0,0 +1,4 @@
+Revision history for RT-Extension-SMSWebhook-Twilio
+
+0.01 [Release Date]
+ - Initial version
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..5254a63
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,29 @@
+---
+abstract: 'RT-Extension-SMSWebhook-Twilio Extension'
+author:
+  - 'Best Practical Solutions, LLC <modules at bestpractical.com>'
+build_requires:
+  ExtUtils::MakeMaker: 6.59
+configure_requires:
+  ExtUtils::MakeMaker: 6.59
+distribution_type: module
+dynamic_config: 1
+generated_by: 'Module::Install version 1.19'
+license: gpl_2
+meta-spec:
+  url: http://module-build.sourceforge.net/META-spec-v1.4.html
+  version: 1.4
+name: RT-Extension-SMSWebhook-Twilio
+no_index:
+  directory:
+    - html
+    - inc
+requires:
+  perl: 5.10.1
+resources:
+  license: http://opensource.org/licenses/gpl-license.php
+  repository: https://github.com/bestpractical/rt-extension-smswebhook-twilio
+version: '0.01'
+x_module_install_rtx_version: '0.43'
+x_requires_rt: 5.0.0
+x_rt_too_new: 5.2.0
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..291449d
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,12 @@
+use lib '.';
+use inc::Module::Install;
+
+RTx     'RT-Extension-SMSWebhook-Twilio';
+license 'gpl_2';
+repository 'https://github.com/bestpractical/rt-extension-smswebhook-twilio';
+
+requires_rt '5.0.0';
+rt_too_new '5.2.0';
+
+sign;
+WriteAll;
diff --git a/README b/README
new file mode 100644
index 0000000..95d0c11
--- /dev/null
+++ b/README
@@ -0,0 +1,123 @@
+NAME
+    RT-Extension-SMSWebhook-Twilio - Add a webhook to receive SMS from
+    Twilio
+
+DESCRIPTION
+    A Twilio SMS number can be configured to call a webhook anytime it
+    receives a text.
+
+    This RT extension adds a webhook to your RT install to receive the
+    webhook call and either create a new ticket or add a comment to an
+    existing ticket.
+
+RT VERSION
+    Works with RT 5.
+
+INSTALLATION
+    perl Makefile.PL
+    make
+    make install
+        May need root permissions
+
+    Edit your /opt/rt5/etc/RT_SiteConfig.pm
+        Add this line:
+
+            Plugin('RT::Extension::SMSWebhook::Twilio');
+
+        To allow Twilio to send data to RT without a referrer:
+
+            Set( %ReferrerComponents,
+                '/SMSWebhook/Twilio.html' => 1,
+            );
+
+        To define the interactions between RT and Twilio:
+
+            Set(
+                $SMSWebhookTwilio,
+                {
+                    url   => 'https://YourRTServer.com/SMSWebhook/Twilio.html',
+                    token => 'twilio auth token',
+                    queue => 'General',
+                }
+            );
+
+        The url value is the full url for the webhook, without the username
+        and password portion used for web server basic authorization as
+        described next.
+
+        The token is the Twilio auth token. See
+        <https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-
+        and-How-to-Change-Them> for details on finding your auth token.
+
+        The url and token values are used to validate the signature of the
+        call made to the webhook to ensure it is coming from Twilio. If the
+        signature is failing to validate make sure both of these values are
+        correct.
+
+        The queue value is an optional value to specify which queue new
+        tickets should be created in when receiving an SMS. It defaults to
+        General if not specified.
+
+    Configure your web server to require Basic Authorization for the
+    location $WebPath/SMSWebhook/Twilio.html. This is *very important*
+    because this plugin does not do any authentication and must be used with
+    HTTP Basic Authorization.
+        For example:
+
+            <Location /SMSWebhook/Twilio.html>
+                AuthType Basic
+                AuthName "Twilio WebHook"
+                AuthUserFile "/etc/apache2/twiliopass"
+                Require valid-user
+            </Location>
+
+        /etc/apache2/twiliopass could be generated by command htpasswd:
+
+            htpasswd -c /etc/apache2/twiliopass twilio
+
+    Clear your mason cache
+            rm -rf /opt/rt5/var/mason_data/obj
+
+    Restart your webserver
+
+    Set up a webhook in Twilio
+        See the video at
+        <https://www.twilio.com/docs/usage/webhooks/getting-started-twilio-w
+        ebhooks> to learn how to set a Messaging webhook for your Twilio
+        phone number.
+
+        When setting the webhook url include the username and password you
+        are using in the web server basic authorization as described
+        previously:
+
+            https://username:password@YourRTServer.com/SMSWebhook/Twilio.html
+
+WEBHOOK LOGIC
+    When the Twilio webhook receives a call from Twilio it searches for a
+    user with a Pager number that matches the from number of the SMS.
+
+    If it does not find a user it creates a new one with the name
+    'SMS-###-###-####' using the from number in place of the number signs.
+    It then creates a new ticket with the new user as the requestor.
+
+    If it does find a user it then looks for active tickets where that user
+    has any role on a ticket. If it finds one active ticket it adds a
+    comment to that ticket with the content of the SMS. If it finds zero or
+    more than one active ticket it creates a new ticket with the user as the
+    requestor.
+
+AUTHOR
+    Best Practical Solutions, LLC <modules at bestpractical.com>
+
+BUGS
+    All bugs should be reported via email to
+        bug-RT-Extension-SMSWebhook-Twilio at rt.cpan.org
+    or via the web at
+        http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-SMSWebhook-Twilio
+LICENSE AND COPYRIGHT
+    This software is Copyright (c) 2022 by BPS
+
+    This is free software, licensed under:
+
+      The GNU General Public License, Version 2, June 1991
+
commit 8894812e2e7a40e7d4570bdc26be249bf86941ef
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Apr 3 11:54:13 2022 -0700

    Add Twilio Webhook

diff --git a/html/SMSWebhook/Twilio.html b/html/SMSWebhook/Twilio.html
new file mode 100644
index 0000000..fbc3c4a
--- /dev/null
+++ b/html/SMSWebhook/Twilio.html
@@ -0,0 +1,105 @@
+<%init>
+use JSON;
+use Data::Dumper;
+use Digest::SHA qw(hmac_sha1_base64);
+
+RT->Logger->debug( 'twilio webhook got args: ' . Dumper( \%ARGS ) );
+
+my $from = $ARGS{From};
+my $to   = $ARGS{To};
+my $body = $ARGS{Body};
+my $sig  = RT::Interface::Web::RequestENV('HTTP_X_TWILIO_SIGNATURE');
+
+if ( !( $from && $to && $body && $sig ) ) {
+    RT->Logger->error('twilio webhook failed: missing args');
+    $m->abort(400);
+}
+
+# validate the signature
+# see: https://www.twilio.com/docs/usage/security#validating-requests
+my $config      = RT::Config->Get('SMSWebhookTwilio') // {};
+my $webhook_url = $config->{url};
+my $token       = $config->{token};
+
+if ( !( $webhook_url && $token ) ) {
+    RT->Logger->error('twilio webhook failed: missing config');
+    $m->abort(400);
+}
+
+for my $post_arg ( sort keys %ARGS ) {
+    $webhook_url .= $post_arg . $ARGS{$post_arg};
+}
+
+my $calc_sig = hmac_sha1_base64( $webhook_url, $token );
+
+# need to pad the digest: https://metacpan.org/pod/Digest::SHA#PADDING-OF-BASE64-DIGESTS
+while ( length($calc_sig) % 4 ) {
+    $calc_sig .= '=';
+}
+
+if ( $sig ne $calc_sig ) {
+    RT->Logger->error(
+        'twilio webhook failed: cannot validate twilio signature');
+    $m->abort(400);
+}
+
+my $user_obj = $session{CurrentUser};
+unless ($user_obj) {
+    RT->Logger->error('twilio webhook failed: no current user');
+    $m->abort(401);
+}
+
+my $User = RT::User->new($user_obj);
+my ( $id, $msg ) = $User->LoadOrCreateByPagerPhone($from);
+unless ($id) {
+    RT->Logger->error(
+        "twilio webhook failed: could not load or create user - $msg");
+    $m->abort(400);
+}
+
+my $current_user = RT::CurrentUser->new($id);
+RT->Logger->debug( 'twilio webhook found user: ' . $current_user->Name );
+
+# find all active tickets for the user sending the sms
+my $tickets = RT::Tickets->new($current_user);
+$tickets->FromSQL( "Watcher.id = " . $id . " AND Status = '__Active__'" );
+RT->Logger->debug(
+    'twilio webhook # of active tickets for user: ' . $tickets->Count );
+
+if ( $tickets->Count == 1 ) {
+
+    # only one active ticket so add a comment to it
+    my $ticket = $tickets->First;
+    my ( $ret, $msg )
+        = $ticket->Comment( Content => "To: $to\nFrom: $from\n\n$body" );
+    unless ($ret) {
+        RT->Logger->error("twilio webhook could not add comment: $msg");
+    }
+} else {
+
+    # either zero or more than one active tickets
+    # don't know which one the text relates to so create a new ticket
+    my $mime = HTML::Mason::Commands::MakeMIMEEntity(
+        Body => "To: $to\nFrom: $from\n\n$body",
+        Type => 'text/plain',
+    );
+    my $Ticket = RT::Ticket->new($current_user);
+    my ( $id, $Trans, $ErrMsg ) = $Ticket->Create(
+        Requestor => $current_user->Name,
+        Type      => 'ticket',
+        Queue     => $config->{queue} // 'General',
+        Subject   => "SMS Message from "
+            . ( $current_user->RealName // $current_user->Name ),
+        MIMEObj => $mime,
+    );
+
+    if ($id) {
+        RT::Logger->debug("twilio webhook created new ticket: $id");
+    } else {
+        RT::Logger->error(
+            "twilio webhook failed to create new ticket: $ErrMsg");
+    }
+}
+</%init>
+<Response></Response>
+% $m->abort;
commit a2495c55c08c34d630c662a78ba699ff5c78406c
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Apr 3 12:01:42 2022 -0700

    Add RT::User Local overlay
    
    Added two methods to RT::User for Twilio webhook: LoadOrCreateByPagerPhone and LoadByPagerPhone

diff --git a/lib/RT/User_Local.pm b/lib/RT/User_Local.pm
new file mode 100644
index 0000000..b046da5
--- /dev/null
+++ b/lib/RT/User_Local.pm
@@ -0,0 +1,86 @@
+use strict;
+use warnings;
+
+no warnings qw(redefine);
+
+package RT::User;
+
+=head2 LoadOrCreateByPagerPhone NUMBER
+
+Attempts to find a user who has the provided pager phone number. If that fails,
+creates an unprivileged user with the provided pager phone number and loads them.
+
+Returns a tuple of the user's id and a status message.
+0 will be returned in place of the user's id in case of failure.
+
+=cut
+
+sub LoadOrCreateByPagerPhone {
+    my $self  = shift;
+    my $pager = shift;
+
+    # find the user with the phone number sending the sms
+    my $users
+        = RT::Users->new( $HTML::Mason::Commands::session{CurrentUser} );
+    $users->Limit(
+        FIELD    => 'PagerPhone',
+        VALUE    => $pager,
+        OPERATOR => '=',
+    );
+    # XXX - should we check if there is more than one user with same pager?
+    if ( $users->Count > 0 ) {
+        $self->Load( $users->First->Id );
+    }
+
+    return wantarray ? ( $self->Id, $self->loc("User loaded") ) : $self->Id
+        if $self->Id;
+
+    # strip off country code and format pager into account name
+    ( my $name = $pager ) =~ s/\+\d*?(\d{3})(\d{3})(\d{4})$/SMS-$1-$2-$3/;
+
+    my ( $val, $message ) = $self->Create(
+        Name       => $name,
+        PagerPhone => $pager,
+        Privileged => 0,
+        Comments   => 'Autocreated when creating ticket from SMS',
+    );
+    return wantarray ? ( $self->Id, $self->loc("User loaded") ) : $self->Id
+        if $self->Id;
+
+    # Deal with the race condition of two account creations at once
+    $self->LoadByPagerPhone($pager);
+    unless ( $self->Id ) {
+        sleep 5;
+        $self->LoadByPagerPhone($pager);
+    }
+
+    if ( $self->Id ) {
+        $RT::Logger->error(
+            "Recovered from creation failure due to race condition");
+        return
+            wantarray ? ( $self->Id, $self->loc("User loaded") ) : $self->Id;
+    } else {
+        $RT::Logger->crit("Failed to create user SMS-$pager: $message");
+        return wantarray ? ( 0, $message ) : 0 unless $self->id;
+    }
+}
+
+=head2 LoadByPagerPhone
+
+Tries to load this user object from the database by the user's pager phone number.
+
+=cut
+
+sub LoadByPagerPhone {
+    my $self  = shift;
+    my $pager = shift;
+
+    # Never load an empty pager.
+    unless ($pager) {
+        return (undef);
+    }
+
+    return $self->LoadByCol( "PagerPhone", $pager );
+}
+
+1;
commit 9061c72bb5743f7aaf82e3e8e885a1905109da97
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Apr 3 12:01:02 2022 -0700

    Add RT::Extension::SMSWebhook::Twilio POD

diff --git a/lib/RT/Extension/SMSWebhook/Twilio.pm b/lib/RT/Extension/SMSWebhook/Twilio.pm
new file mode 100644
index 0000000..cf8ffad
--- /dev/null
+++ b/lib/RT/Extension/SMSWebhook/Twilio.pm
@@ -0,0 +1,152 @@
+use strict;
+use warnings;
+
+package RT::Extension::SMSWebhook::Twilio;
+
+our $VERSION = '0.01';
+
+=head1 NAME
+
+RT-Extension-SMSWebhook-Twilio - Add a webhook to receive SMS from Twilio
+
+=head1 DESCRIPTION
+
+A Twilio SMS number can be configured to call a webhook anytime it receives a
+text.
+
+This RT extension adds a webhook to your RT install to receive the webhook call
+and either create a new ticket or add a comment to an existing ticket.
+
+=head1 RT VERSION
+
+Works with RT 5.
+
+=head1 INSTALLATION
+
+=over
+
+=item C<perl Makefile.PL>
+
+=item C<make>
+
+=item C<make install>
+
+May need root permissions
+
+=item Edit your F</opt/rt5/etc/RT_SiteConfig.pm>
+
+Add this line:
+
+    Plugin('RT::Extension::SMSWebhook::Twilio');
+
+To allow Twilio to send data to RT without a referrer:
+
+    Set( %ReferrerComponents,
+        '/SMSWebhook/Twilio.html' => 1,
+    );
+
+To define the interactions between RT and Twilio:
+
+    Set(
+        $SMSWebhookTwilio,
+        {
+            url   => 'https://YourRTServer.com/SMSWebhook/Twilio.html',
+            token => 'twilio auth token',
+            queue => 'General',
+        }
+    );
+
+The C<url> value is the full url for the webhook, without the username and
+password portion used for web server basic authorization as described next.
+
+The C<token> is the Twilio auth token. See L<https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them>
+for details on finding your auth token.
+
+The C<url> and C<token> values are used to validate the signature of the call
+made to the webhook to ensure it is coming from Twilio. If the signature is
+failing to validate make sure both of these values are correct.
+
+The C<queue> value is an optional value to specify which queue new tickets
+should be created in when receiving an SMS. It defaults to General if not
+specified.
+
+=item Configure your web server to require Basic Authorization for the
+location $WebPath/SMSWebhook/Twilio.html.  This is I<very important> because
+this plugin does not do any authentication and must be used with HTTP Basic
+Authorization.
+
+For example:
+
+    <Location /SMSWebhook/Twilio.html>
+        AuthType Basic
+        AuthName "Twilio WebHook"
+        AuthUserFile "/etc/apache2/twiliopass"
+        Require valid-user
+    </Location>
+
+F</etc/apache2/twiliopass> could be generated by command C<htpasswd>:
+
+    htpasswd -c /etc/apache2/twiliopass twilio
+
+=item Clear your mason cache
+
+    rm -rf /opt/rt5/var/mason_data/obj
+
+=item Restart your webserver
+
+Z<>
+
+=item Set up a webhook in Twilio
+
+See the video at L<https://www.twilio.com/docs/usage/webhooks/getting-started-twilio-webhooks>
+to learn how to set a Messaging webhook for your Twilio phone number.
+
+When setting the webhook url include the username and password you are using in
+the web server basic authorization as described previously:
+
+    https://username:password@YourRTServer.com/SMSWebhook/Twilio.html
+
+=back
+
+=head1 WEBHOOK LOGIC
+
+When the Twilio webhook receives a call from Twilio it searches for a user with
+a Pager number that matches the from number of the SMS.
+
+If it does not find a user it creates a new one with the name 'SMS-###-###-####'
+using the from number in place of the number signs. It then creates a new ticket
+with the new user as the requestor.
+
+If it does find a user it then looks for active tickets where that user has any
+role on a ticket. If it finds one active ticket it adds a comment to that ticket
+with the content of the SMS. If it finds zero or more than one active ticket it
+creates a new ticket with the user as the requestor.
+
+=head1 AUTHOR
+
+Best Practical Solutions, LLC E<lt>modules at bestpractical.comE<gt>
+
+=head1 BUGS
+
+=for html <p>All bugs should be reported via email to <a
+href="mailto:bug-RT-Extension-SMSWebhook-Twilio at rt.cpan.org">bug-RT-Extension-SMSWebhook-Twilio at rt.cpan.org</a>
+or via the web at <a
+href="http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-SMSWebhook-Twilio">rt.cpan.org</a>.</p>
+
+=for text
+    All bugs should be reported via email to
+        bug-RT-Extension-SMSWebhook-Twilio at rt.cpan.org
+    or via the web at
+        http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-SMSWebhook-Twilio
+
+=head1 LICENSE AND COPYRIGHT
+
+This software is Copyright (c) 2022 by BPS
+
+This is free software, licensed under:
+
+  The GNU General Public License, Version 2, June 1991
+
+=cut
+
+1;
-----------------------------------------------------------------------

Summary of changes:
 README                                | 11 ++---------
 html/SMSWebhook/Twilio.html           |  9 +++------
 lib/RT/Extension/SMSWebhook/Twilio.pm |  6 +++---
 lib/RT/User_Local.pm                  |  4 +---
 4 files changed, 9 insertions(+), 21 deletions(-)


hooks/post-receive
-- 
rt-extension-smswebhook-twilio


More information about the Bps-public-commit mailing list