Telegram SMS-bridge via twilio

And here we go again. Even though my old project is still running nicely, the disappointing part it the need to regularly reboot the system as usb umts sticks seem to freeze after a week or so.

There is also the problem of running the system at home or whereever, but not on my servers in the computing center, so I had a look into various sms-gateway provider and decided to build a solution around twilio.

Even though twilio is nicely documented for the REST-API and provides you with many code examples anything handling responses is basically aimed at forwarding incomming replies to a webservice you would set up. No, I don’t want that ūüėČ .

Luckily, the API allows exactly what is needed – it is just not the kind of code example popping up if you search for ‘receiving SMS’.

Thus: here is the modification of the telepot-bot to use twilio instead of local hardware:

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import telepot
import re
from twilio.rest import TwilioRestClient 

class twsmsbot(telepot.Bot):
    
    def __init__ (self, uid, token, twacc, twauth, twsndr):
        super().__init__(token)
        self._mode = 0
        self._recipient = ""
        self._active = 1
        self._user = uid
        self.message_loop(self.handle)
        self._twclient = TwilioRestClient(twacc, twauth) 
        self._txsndr = twsndr
    
    def handle (self, msg):
        chat_id = msg['chat']['id']
        command = msg['text']
        if chat_id != self._user:
            self.sendMessage( chat_id, "unauthorized user")
            return 0
        res = re.match("^/(\w+)(\s[\+\w\d]+)*\Z", command, flags=0)
        if res:
            if      res.group(1) == "status":
                self.status()
            elif    res.group(1) == "setrcpt":
                self._recipient = res.group(2)
                self.sendMessage( chat_id, "recipient set to: %s" % self._recipient)
            elif    res.group(1) == "open":
                if self._recipient != "":
                    self._mode = 1
                    self.sendMessage( chat_id, "relay active")
                else:
                    self.sendMessage( chat_id, "set recipient first!")
            elif    res.group(1) == "close":
                self.sendMessage( chat_id, "relay deactived")
                self._mode = 0
            elif    res.group(1) == "terminate":
                self._active = 0
            else:
                self.sendMessage( chat_id, "unrecognized command!")
        else:
            if self._mode == 1 and self._recipient != "":
                self.sendsm ( command )
            else:
                self.sendMessage( chat_id, "relay not enabled")

    def status (self):
        self.sendMessage( self._user , "recipient: %s, relay status: %d" % (self._recipient, self._mode))
    
    def sendsm (self, msg):
        self._twclient.messages.create(to=self._recipient, from_=self._txsndr, 
        body=msg)

    def recvsm (self ):
        l = self._twclient.messages.list()
        for i in l:
            m = self._twclient.messages.get(i.name)
            self.sendMessage(self._user, "From: %s \n at: %s \n %s" % (m.from_,m.date_created,m.body))
            m.delete()

    
    def run (self ):
        while self._active == 1:
            self.recvsm ()
            time.sleep(5)
    
    
mybot = twsmsbot (<adminuid>, "bot-token", 
        "twilio-acc-token", 
        "twilio-auth-token", "sender")
mybot.run()

 

 

Telegram SMS bridge/gateway

Once in a while I am just considering doing things just because ¬†they can be done ūüėČ

Actually, the topic of this article might be helpful for others if they depend on SMS to control devices or refrain from carrying more than one phone around.

So, for this new weekend project, what do we need?

  • a UMTS stick (available on ebay starting at 5 EUR ūüėČ ), old phone with USB or serial connection or similar
  • a telegram bot (telepot)
  • a simcard which is active and can send SMs

Expected outcome: a bot that will relay SMs to a given cellphone number and print incoming SMs to a private telegram channel.

right now there are five commands:

  1. \setrcpt <number> (to set a receipient number we want to chat to obviously)
  2. \open (enable relay)
  3. \close (disable relay)
  4. \status  (if you are not certain which number is set or to retrieve other information)
  5. \terminate (terminate the script)

setting up smstools on ubuntu can be done as described here

so, as soon as you got sms tools running, all we need is some python script-foo ūüėÄ

required software:

apt install python-pip
pip install telepot
import sys
import time
import telepot
import re
import string
import random
import os

class smsbot(telepot.Bot):
    
    def __init__ (self, uid, token, spooldir):
        super(smsbot, self).__init__(token)
        self._mode = 0
        self._recipient = ""
        self._active = 1
        self._user = uid
        self._spooldir = spooldir
        self.notifyOnMessage(self.handle)
    
    def handle (self, msg):
        chat_id = msg['chat']['id']
        command = msg['text']
        if chat_id != self._user:
            self.sendMessage( chat_id, "unauthorized user")
            return 0
        res = re.match(r'^\\(\w+)\s?([\w\d]*)$', command, flags=0)
        if res:
            if      res.group(1) == "status":
                self.status()
            elif    res.group(1) == "setrcpt":
                self._receipient = res.group(2)
                self.sendMessage( chat_id, "recipient set to: %s" % self._recipient)
            elif    res.group(1) == "open":
                if self._recipient != "":
                    self._mode = 1
                    self.sendMessage( chat_id, "relay active")
                else:
                    self.sendMessage( chat_id, "set recipient first!")
            elif    res.group(1) == "close":
                self.sendMessage( chat_id, "relay deactived")
                self._mode = 0
            elif    res.group(1) == "terminate":
                self._active = 0
            else:
                self.sendMessage( chat_id, "unrecognized command!")
        else:
            if self._mode == 1 and self._recipient != "":
                self.sendsm ( command )
            else:
                self.sendMessage( chat_id, "relay not enabled")
    
    def id_generator(self, size=8, chars=string.ascii_uppercase + string.digits):
        return ''.join(random.choice(chars) for _ in range(size))
    
    def status (self): # needs some improvement
        self.sendMessage( self._user , "status")
    
    def sendsm (self, msg):
        output = "To: %s \n\n%s" % (self._recipient, msg)
        filename = os.path.join (self._spooldir, "outgoing", self.id_generator())
        fh = open (filename, "w")
        fh.write (output)
        fh.close()
    
    def recvsm (self ):
        for x in os.listdir(self._spooldir+"incoming/"):
            f = open(self._spooldir+"incoming/"+x, 'r')
            cont = []
            for line in f:
                cont.append(line)
            self.sendMessage(self._user, cont[0]+"\n"+cont[3]+"\n"+cont[12])
            f.close()
            os.remove(self._spooldir+"incoming/"+x)

    
    def checkerr ( self ): #some more work here
        for x in os.listdir(self._spooldir+"failed/"):
            self.sendMessage(self._user, "FAILED:")
            f = open(self._spooldir+"failed/"+x, 'r')
            ln=0
            for line in f:
                self.sendMessage(self._user, str(ln)+line)
                ln=ln+1
            f.close()
            os.remove(self._spooldir+"failed/"+x)
    
    def run (self ):
        while self._active == 1:
            self.recvsm ()
            self.checkerr ()
            time.sleep(5)
    
    
mybot = smsbot (<your_uid_here>, "<telepot_token_here", "/var/spool/sms/")
mybot.run()

run that script and enjoy ūüėČ

smsrelay

IPFire versus SSLCerts

so I decided to purchase a ‘real’ SSL certificate for my IPFire installation and as it was the cheapest one I could find I went with ssls.com… so far so good.

But, if you follow the instructions, one problem remains: if you chose to upload the verification file any confirmation will fail as IPFire uses ports 81 and 444 for the webinterface. To resolve that issue, at least temporarily we will excute the following steps:

(1) if you contact the firewall from the ‘outside world’ make sure you add exceptions for ports 80 and 443

(2) upload the provided file to /srv/web/ipfire/html/

now the fun starts…

modify the ports in

/etc/httpd/conf.d/vhosts.d/ipfire-interface.conf and ipfire-interface-ssl.conf

now our apache would not know, which ports it is configured for, however, unless you change the

/etc/httpd/conf/listen.conf

as well nothing will happen…

Now execute a /etc/init.d/apache restart

once your certificate is ready, replace the certs in /etc/httpd, change back the ports and reload the service… your purchased cert should now be used.

 

Update: IPfire seems to replace der server.crt sometimes when being updated… in that case you might have to overwrite the certificate again and restart apache.