def decodeAES(ciphertext): from Crypto.Cipher import AES import base64 PADDING = '{' abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) key = cfg.getvalue('key', '7D8FAA235238F8C2') cipher = AES.new(key) def decAES(c, e): try: ret = c.decrypt(base64.b64decode(e.encode("ASCII"))).decode("UTF-8") \ .rstrip(PADDING) except AttributeError: ret = c.decrypt(base64.b64decode(e)).decode("UTF-8") \ .rstrip(PADDING) return ret # DecodeAES = lambda c, e: # c.decrypt(base64.b64decode(e)).decode("UTF-8").rstrip(PADDING) decoded = decAES(cipher, ciphertext) try: ciphertextbase64 = base64.b64decode(decoded.encode("ASCII")).decode('utf-8') except AttributeError: ciphertextbase64 = base64.b64decode(decoded).decode('utf-8') return ciphertextbase64
def encodeAES(plaintext): from Crypto.Cipher import AES import base64 BLOCK_SIZE = 32 PADDING = '{' abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) key = cfg.getvalue('key', '7D8FAA235238F8C2') cipher = AES.new(key) # in AES the plaintext has to be padded to fit the blocksize # therefore create a pad plaintextbase64 = \ base64.b64encode(plaintext.encode('utf-8')).decode('utf-8') def pad(s): return s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING # pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING def encAES(c, s): return base64.b64encode(c.encrypt(pad(s))) # EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s))) encoded = encAES(cipher, plaintextbase64) return encoded
def checkrouting(): # check if directly connected wis is # still alive, if not, mark all of # its routes obsolete # get conf peers abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/../conf/smsgw.conf' cfg = SmsConfig(configfile) peersjson = cfg.getvalue('peers', '[{}]', 'wis') smsgwglobals.wislogger.debug(peersjson) peers = json.loads(peersjson) smsgwglobals.wislogger.debug("HELPER: Routes to check " + str(len(peers))) for p in peers: try: if "url" not in p: continue smsgwglobals.wislogger.debug(p["url"] + "/smsgateway") request = \ urllib.request.Request(p["url"] + "/smsgateway") f = urllib.request.urlopen(request, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) if f.getcode() != 200: smsgwglobals.wislogger.debug("XXX WIS DELETE") wisglobals.rdb.delete_routing_wisurl(p["url"]) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) wisglobals.rdb.delete_routing_wisurl(p["url"]) except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug( "HELPER: ceckrouting socket connection timeout") # check routing table entries routes = wisglobals.rdb.read_routing() for route in routes: try: smsgwglobals.wislogger.debug(route["wisurl"] + "/smsgateway") request = \ urllib.request.Request(route["wisurl"] + "/smsgateway") f = urllib.request.urlopen(request, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) if f.getcode() != 200: smsgwglobals.wislogger.debug("XXX WIS DELETE") wisglobals.rdb.delete_routing_wisurl(p["url"]) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) wisglobals.rdb.delete_routing_wisurl(p["url"]) except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug( "HELPER: checkrouting socket connection timeout")
def __init__(self, token): configfile = wisglobals.smsgatewayabspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) self.logstashstatstoken = cfg.getvalue('logstashstatstoken', '', 'wis') self.logstashstatsserver = cfg.getvalue('logstashserver', '', 'wis') if not self.logstashstatstoken: smsgwglobals.wislogger.debug("STATS: Logstash token not configured") raise RuntimeError('Logstash token not configured') if not self.logstashstatsserver: smsgwglobals.wislogger.debug("STATS: Logstash server not configured") raise RuntimeError('Logstash server not configured') if not (token == self.logstashstatstoken): smsgwglobals.wislogger.debug("STATS: Logstash server token not valid") raise RuntimeError('Logstash server token not valid')
def __init__(self, token): configfile = wisglobals.smsgatewayabspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) self.logstashstatstoken = cfg.getvalue('logstashstatstoken', '', 'wis') self.logstashstatsserver = cfg.getvalue('logstashserver', '', 'wis') if not self.logstashstatstoken: smsgwglobals.wislogger.debug( "STATS: Logstash token not configured") raise RuntimeError('Logstash token not configured') if not self.logstashstatsserver: smsgwglobals.wislogger.debug( "STATS: Logstash server not configured") raise RuntimeError('Logstash server not configured') if not (token == self.logstashstatstoken): smsgwglobals.wislogger.debug( "STATS: Logstash server token not valid") raise RuntimeError('Logstash server token not valid')
def requestrouting(peers=None, initial=False): def getUrl(url): try: data = GlobalHelper.encodeAES('{"get": "peers"}') request = \ urllib.request.Request(url + "/smsgateway/api/requestrouting") request.add_header("Content-Type", "application/json;charset=utf-8") f = urllib.request.urlopen(request, data, timeout=5) if f.getcode() != 200: smsgwglobals.wislogger.debug("Get peers NOTOK," + " Error Code: ", f.getcode()) return smsgwglobals.wislogger.debug("Get peers OK") rawbody = f.read().decode('utf-8') plaintext = GlobalHelper.decodeAES(rawbody) routelist = json.loads(plaintext) smsgwglobals.wislogger.debug(routelist) wisglobals.rdb.merge_routing(routelist) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("Get peers NOTOK") except error.DatabaseError as e: smsgwglobals.wislogger.debug(e.message) except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("HELPER: requestrouting socket connection timeout") if initial is True: abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/../conf/smsgw.conf' cfg = SmsConfig(configfile) peersjson = cfg.getvalue('peers', '[{}]', 'wis') smsgwglobals.wislogger.debug(peersjson) peers = json.loads(peersjson) for peer in peers: if "url" not in peer: continue smsgwglobals.wislogger.debug(peer["url"]) getUrl(peer["url"])
def requestrouting(peers=None, initial=False): def getUrl(url): try: data = GlobalHelper.encodeAES('{"get": "peers"}') request = \ urllib.request.Request(url + "/api/requestrouting") request.add_header("Content-Type", "application/json;charset=utf-8") f = urllib.request.urlopen(request, data, timeout=5) if f.getcode() != 200: smsgwglobals.wislogger.debug("Get peers NOTOK," + " Error Code: ", f.getcode()) return smsgwglobals.wislogger.debug("Get peers OK") rawbody = f.read().decode('utf-8') plaintext = GlobalHelper.decodeAES(rawbody) routelist = json.loads(plaintext) smsgwglobals.wislogger.debug(routelist) wisglobals.rdb.merge_routing(routelist) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("Get peers NOTOK") except error.DatabaseError as e: smsgwglobals.wislogger.debug(e.message) except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("HELPER: requestrouting socket connection timeout") if initial is True: abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/../conf/smsgw.conf' cfg = SmsConfig(configfile) peersjson = cfg.getvalue('peers', '[{}]', 'wis') smsgwglobals.wislogger.debug(peersjson) peers = json.loads(peersjson) for peer in peers: if "url" not in peer: continue smsgwglobals.wislogger.debug(peer["url"]) getUrl(peer["url"])
def run(self): # load the configuration abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) pisglobals.pisid = cfg.getvalue('pisid', 'pis-dummy', 'pis') ipaddress = cfg.getvalue('ipaddress', '127.0.0.1', 'pis') pisport = cfg.getvalue('port', '7788', 'pis') pisglobals.pisurl = ("http://" + ipaddress + ":" + pisport) wisurlcfg = cfg.getvalue('wisurllist', '[{"url": "http://127.0.0.1:7777"}]', 'pis') # convert json to list of dictionary entriesi pisglobals.wisurllist = json.loads(wisurlcfg) pisglobals.maxwaitpid = int(cfg.getvalue('maxwaitpid', '10', 'pis')) pisglobals.retrywisurl = int(cfg.getvalue('retrywisurl', '2', 'pis')) pisglobals.retrywait = int(cfg.getvalue('retrywait', '5', 'pis')) # prepare ws4py cherrypy.config.update({'server.socket_host': ipaddress}) cherrypy.config.update({'server.socket_port': int(pisport)}) cherrypy.config.update( {'engine.autoreload_on': cfg.getvalue('autoreload', False, 'pis')}) MyWebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() # come back to config as dictionary as i was not able to bind web # socket class unsing the pis-web-conf file cfg = { '/': {}, '/ws': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': WebSocketHandler } } cherrypy.quickstart(Root(), '/', cfg)
def run(self): # load the configuration abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) pisglobals.pisid = cfg.getvalue('pisid', 'pis-dummy', 'pis') ipaddress = cfg.getvalue('ipaddress', '127.0.0.1', 'pis') pisport = cfg.getvalue('port', '7788', 'pis') pisglobals.pisurl = ("http://" + ipaddress + ":" + pisport) wisurlcfg = cfg.getvalue('wisurllist', '[{"url": "http://127.0.0.1:7777"}]', 'pis') # convert json to list of dictionary entriesi pisglobals.wisurllist = json.loads(wisurlcfg) pisglobals.maxwaitpid = int(cfg.getvalue('maxwaitpid', '10', 'pis')) pisglobals.retrywisurl = int(cfg.getvalue('retrywisurl', '2', 'pis')) pisglobals.retrywait = int(cfg.getvalue('retrywait', '5', 'pis')) # prepare ws4py cherrypy.config.update({'server.socket_host': ipaddress}) cherrypy.config.update({'server.socket_port': int(pisport)}) cherrypy.config.update({'engine.autoreload_on': cfg.getvalue('autoreload', False, 'pis')}) MyWebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() # come back to config as dictionary as i was not able to bind web # socket class unsing the pis-web-conf file cfg = {'/': {}, '/ws': {'tools.websocket.on': True, 'tools.websocket.handler_cls': WebSocketHandler} } cherrypy.quickstart(Root(), '/', cfg)
def run(self): # load the configuration # Create default root user db = Database() abspath = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir)) # store the abspath in globals for easier handling wisglobals.smsgatewayabspath = abspath configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) readme = open(abspath + '/README.md', 'r') readmecontent = readme.read() version = re.compile(r"(?<=## Version)(.*v.\..*)", re.S).findall(readmecontent) wisglobals.version = version[0].strip( '\n') if version else "version not specified" smsgwglobals.wislogger.debug("WIS: Version: " + str(wisglobals.version)) wisglobals.wisid = cfg.getvalue('wisid', 'nowisid', 'wis') wisglobals.wisipaddress = cfg.getvalue('ipaddress', '127.0.0.1', 'wis') wisglobals.wisport = cfg.getvalue('port', '7777', 'wis') wisglobals.cleanupseconds = cfg.getvalue('cleanupseconds', '315569520', 'wis') wisglobals.validusernameregex = cfg.getvalue('validusernameregex', '([^a-zA-Z0-9])', 'wis') wisglobals.validusernamelength = cfg.getvalue('validusernamelength', 30, 'wis') wisglobals.ldapserver = cfg.getvalue('ldapserver', None, 'wis') wisglobals.ldapbasedn = cfg.getvalue('ldapbasedn', None, 'wis') wisglobals.ldapenabled = cfg.getvalue('ldapenabled', None, 'wis') ldapusers = cfg.getvalue('ldapusers', '[]', 'wis') wisglobals.ldapusers = json.loads(ldapusers) wisglobals.ldapusers = [item.lower() for item in wisglobals.ldapusers] smsgwglobals.wislogger.debug("WIS:" + str(wisglobals.ldapusers)) wis_env_root_password_hash = os.getenv("ROOT_PASSWORD_HASH") password_from_config = cfg.getvalue( 'password', '20778ba41791cdc8ac54b4f1dab8cf7602a81f256cbeb9e782263e8bb00e01794d47651351e5873f9ac82868ede75aa6719160e624f02bba4df1f94324025058', 'wis') password = wis_env_root_password_hash if wis_env_root_password_hash else password_from_config salt = cfg.getvalue('salt', 'changeme', 'wis') # write the default user on startup db.write_users('root', password, salt) # read pissendtimeout wisglobals.pissendtimeout = int( cfg.getvalue('pissendtimeout', '20', 'wis')) # Read allowed mobile prefixes to process mobile_prefixes_raw = cfg.getvalue('allowedmobileprefixes', '.*', 'wis').split(",") wisglobals.allowedmobileprefixes = set( sorted([d.strip() for d in mobile_prefixes_raw if d != ""])) # Read allowed timeframe for sending start/finish time wisglobals.allowedstarttime = cfg.getvalue('allowedstarttime', '01:00', 'wis') wisglobals.allowedfinishtime = cfg.getvalue('allowedfinishtime', '23:30', 'wis') # Read resend scheduler start/finish timeframe wisglobals.resendstarttime = cfg.getvalue('resendstarttime', '09:00', 'wis') wisglobals.resendfinishtime = cfg.getvalue('resendfinishtime', '18:00', 'wis') wisglobals.resendinterval = int( cfg.getvalue('resendinterval', '30', 'wis')) # Set own start time to use in resend flow wisglobals.scriptstarttime = datetime.utcnow() # check if ssl is enabled wisglobals.sslenabled = cfg.getvalue('sslenabled', None, 'wis') wisglobals.sslcertificate = cfg.getvalue('sslcertificate', None, 'wis') wisglobals.sslprivatekey = cfg.getvalue('sslprivatekey', None, 'wis') wisglobals.sslcertificatechain = cfg.getvalue('sslcertificatechain', None, 'wis') smsgwglobals.wislogger.debug("WIS: SSL " + str(wisglobals.sslenabled)) if wisglobals.sslenabled is not None and 'true' in wisglobals.sslenabled.lower( ): smsgwglobals.wislogger.debug("WIS: STARTING SSL") cherrypy.config.update({'server.ssl_module': 'builtin'}) cherrypy.config.update( {'server.ssl_certificate': wisglobals.sslcertificate}) cherrypy.config.update( {'server.ssl_private_key': wisglobals.sslprivatekey}) if wisglobals.sslcertificatechain is not None: cherrypy.config.update({ 'server.ssl_certificate_chain': wisglobals.sslcertificatechain }) cherrypy.config.update({'server.socket_host': wisglobals.wisipaddress}) cherrypy.config.update({'server.socket_port': int(wisglobals.wisport)}) cherrypy.tree.mount( StatsLogstash(), '/api/stats/logstash', {'/': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher() }}) # Start scheduler for sms resending and other maintenance operations Watchdog_Scheduler() cherrypy.quickstart(Root(), '/', 'wis-web.conf')
def run(self): # load the configuration abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) pid_env_config_id = os.getenv("PID_ID") configfile = abspath + '/conf/smsgw_' + str(pid_env_config_id) + '.conf' if pid_env_config_id else '/conf/smsgw.conf' cfg = SmsConfig(configfile) smsgwglobals.pidlogger.debug("PID Env ID: " + str(pid_env_config_id)) smsgwglobals.pidlogger.debug("PID Config file: " + configfile) pidglobals.pidid = cfg.getvalue('pidid', 'pid-dummy', 'pid') smsgwglobals.pidlogger.debug("PidID: " + pidglobals.pidid) # Gammu Debug on/off gammudebug = cfg.getvalue('gammudebug', 'Off', 'pid') if gammudebug == "On": pidglobals.gammudebug = True todir = cfg.getvalue('logdirectory', abspath + '/logs/', 'pid') tofile = cfg.getvalue('gammudebugfile', 'gammu.log', 'pid') gammudebugfile = todir + tofile pidglobals.gammudebugfile = gammudebugfile smsgwglobals.pidlogger.debug("Gammu Debug on! Will log to " + str(pidglobals.gammudebugfile)) else: pidglobals.gammudebug = False # Wrapping Gammu or not wrapgammu = cfg.getvalue('wrapgammu', 'Off', 'pid') if wrapgammu == "On": pidglobals.wrapgammu = True gammucmd = cfg.getvalue('gammucmd', 'Blank', 'pid') smsgwglobals.pidlogger.debug("Gammucmd: " + str(gammucmd)) if gammucmd == "Blank": option = "gammucmd - is not set!" cfg.errorandexit(option) if path.isfile(gammucmd) or path.islink(gammucmd): # file or link exists all fine pidglobals.gammucmd = gammucmd else: # exit PID here as not Modem connection will work! option = "gammucmd - Command given not found!" cfg.errorandexit(option) else: pidglobals.wrapgammu = False smsgwglobals.pidlogger.debug("WrapGammu: " + str(pidglobals.wrapgammu)) testmode = cfg.getvalue('testmode', 'Off', 'pid') if testmode == "On": # set testmode - content "ERROR" "SUCCESS" and "LONGWAIT" is # handled in a special way now pidglobals.testmode = True else: pidglobals.testmode = False smsgwglobals.pidlogger.debug("TestMode: " + str(pidglobals.testmode)) retrypisurl = cfg.getvalue('retrypisurl', '2', 'pid') smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "RetryPisUrl: " + retrypisurl) retrywait = cfg.getvalue('retrywait', '5', 'pid') smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "RetryWait: " + retrywait) modemcfg = cfg.getvalue('modemlist', '[{}]', 'pid') try: # convert json to list of dictionary entries modemlist = json.loads(modemcfg) except: cfg.errorandexit("modemlist - not a valid JSON structure!") #Get carriers config carriercfg = cfg.getvalue('carrierscfg', '{}', 'pid') try: # convert json to list of dictionary entries pidglobals.carriersconfig = json.loads(carriercfg) except: cfg.errorandexit("carrierscfg - not a valid JSON structure!") # check if modemcfg is set if 'modemid' not in modemlist[0]: # if len(modemlist) == 0: cfg.errorandexit("modemlist - not set!!!") else: # validate modem settings for modem in modemlist: try: re.compile(modem['regex']) except: cfg.errorandexit("modemlist - at " + modem['modemid'] + " - invalid regex!") # connect to USBModems and persist in pidglobals Modem.connectmodems(modemlist) smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "ModemList: " + str(pidglobals.modemlist)) if len(pidglobals.modemlist) == 0: errortext = "at any configured modem." cfg.errorandexit(errortext, 2) pisurlcfg = cfg.getvalue('pisurllist', '[{"url": "ws://127.0.0.1:7788"}]', 'pid') # convert json to list of dictionary entries pisurllist = json.loads(pisurlcfg) smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "PisUrlList: " + str(pisurllist)) # endless try to connect to configured PIS # error: wait for some secs, then 1 retry, then next PID in list curpis = 0 tries = 1 while True: try: if pidglobals.closingcode: raise baseurl = pisurllist[curpis]['url'] pisurl = baseurl + "/ws" smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Try " + str(tries) + ": " + "Connecting to: " + pisurl) # init websocket client with heartbeat, 30 is fixed in all # modules wis/pis/pid ws = PidWsClient(pisurl, protocols=['http-only', 'chat'], heartbeat_freq=30) ws.connect() # set values for primary check in Websocket connection! # trim ws out of ws:/.. and add http:/ pidglobals.curpisurl = "http" + baseurl[2:] pidglobals.primpisurl = "http" + pisurllist[0]['url'][2:] ws.run_forever() except KeyboardInterrupt: ws.close() # leave while loop break except Exception as e: # do retry except there is no more modem to communicate if (pidglobals.closingcode is None or pidglobals.closingcode < 4000): # try to reconnect smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Got a problem will reconnect " "in " + retrywait + " seconds.") smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "Problem is: " + str(e)) try: time.sleep(int(retrywait)) except: break if tries < int(retrypisurl): tries = tries + 1 else: tries = 1 curpis = curpis + 1 if curpis == len(pisurllist): curpis = 0 pidglobals.closingcode = None elif pidglobals.closingcode == 4001: # go back to inital PID # reset while parameter for pis and retries smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Going back to Prim PID") curpis = 0 tries = 1 pidglobals.closingcode = None elif pidglobals.closingcode == 4000: # leave while loop # no connection to modem found! smsgwglobals.pidlogger.debug(pidglobals.pidid + ": Sleep 45 seconds before shutdown..." ) sleep(45) break elif pidglobals.closingcode == 4005: # leave while loop # pid restart requested break elif pidglobals.closingcode == 4010: # leave while loop # pid lost connection to the modem. Probably sim card ejected # Or HEARTBEAT failed break
def run(self): # load the configuration # Create default root user db = Database() abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) wisglobals.wisid = cfg.getvalue('wisid', 'nowisid', 'wis') wisglobals.wisipaddress = cfg.getvalue('ipaddress', '127.0.0.1', 'wis') wisglobals.wisport = cfg.getvalue('port', '7777', 'wis') wisglobals.cleanupseconds = cfg.getvalue('cleanupseconds', '86400', 'wis') wisglobals.ldapserver = cfg.getvalue('ldapserver', None, 'wis') wisglobals.ldapbasedn = cfg.getvalue('ldapbasedn', None, 'wis') wisglobals.ldapenabled = cfg.getvalue('ldapenabled', None, 'wis') ldapusers = cfg.getvalue('ldapusers', '[]', 'wis') wisglobals.ldapusers = json.loads(ldapusers) wisglobals.ldapusers = [item.lower() for item in wisglobals.ldapusers] smsgwglobals.wislogger.debug("WIS:" + str(wisglobals.ldapusers)) password = cfg.getvalue('password', '20778ba41791cdc8ac54b4f1dab8cf7602a81f256cbeb9e782263e8bb00e01794d47651351e5873f9ac82868ede75aa6719160e624f02bba4df1f94324025058', 'wis') salt = cfg.getvalue('salt', 'changeme', 'wis') # write the default user on startup db.write_users('root', password, salt) # check if ssl is enabled wisglobals.sslenabled = cfg.getvalue('sslenabled', None, 'wis') wisglobals.sslcertificate = cfg.getvalue('sslcertificate', None, 'wis') wisglobals.sslprivatekey = cfg.getvalue('sslprivatekey', None, 'wis') wisglobals.sslcertificatechain = cfg.getvalue('sslcertificatechain', None, 'wis') smsgwglobals.wislogger.debug("WIS: SSL " + str(wisglobals.sslenabled)) if wisglobals.sslenabled is not None and 'true' in wisglobals.sslenabled.lower(): smsgwglobals.wislogger.debug("WIS: STARTING SSL") cherrypy.config.update({'server.ssl_module': 'builtin'}) cherrypy.config.update({'server.ssl_certificate': wisglobals.sslcertificate}) cherrypy.config.update({'server.ssl_private_key': wisglobals.sslprivatekey}) if wisglobals.sslcertificatechain is not None: cherrypy.config.update({'server.ssl_certificate_chain': wisglobals.sslcertificatechain}) cherrypy.config.update({'server.socket_host': wisglobals.wisipaddress}) cherrypy.config.update({'server.socket_port': int(wisglobals.wisport)}) cherrypy.quickstart(Root(), '/smsgateway', 'wis-web.conf')
class SmsLogger(object): """Base class for Log handling. Creates a log-handler for each section in config file. Attributes: configfile -- absolut path to configuration file to read relevant optionsi out of all sections.. loglevel = CRITICAL | ERROR | WARNING | INFO | DEBUG logdirectory = absolut path to log directory fallback is local \logs directory logfile = smsgw.log """ __smsconfig = None __abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) # Constructor def __init__(self, configfile=__abspath + '/conf/smsgw.conf'): # read SmsConfigs self.__smsconfig = SmsConfig(configfile) sections = self.__smsconfig.getsections() # print (type(sections)) # print (sections) # prepare inital logger for each section in config file for section in sections: # print (section) # configer logger per section # handler values are -> 'console' # -> 'file' self.addHandler(section, 'console') self.addHandler(section, 'file') def addHandler(self, section, forhandler='console'): # set logger per section smslogger = logging.getLogger(section) # prepare format logFormatter = logging.Formatter("%(asctime)s [%(name)s:%(levelname)-5.5s] %(message)s") # choose the right handler if forhandler == 'file': todir = self.__smsconfig.getvalue('logdirectory', self.__abspath + '/logs/', section) fbacktofile = section + '.log' tofile = self.__smsconfig.getvalue('logfile', fbacktofile, section) logfile = todir + tofile daysback = int(self.__smsconfig.getvalue('logfiledaysback', 7, section)) handler = logging.handlers.TimedRotatingFileHandler(logfile, when='midnight', backupCount=daysback, encoding='utf-8', utc=True) # handler = logging.FileHandler(logfile, 'a', 'utf-8') # double ensure that default handler is StreamHandler else: handler = logging.StreamHandler() # set the format to the Handler handler.setFormatter(logFormatter) # add handler smslogger.addHandler(handler) # set log level loglevel = self.__smsconfig.getvalue('loglevel', 'WARNING', section) try: nummeric_level = getattr(logging, loglevel) smslogger.setLevel(nummeric_level) smslogger.debug('addHandler for (%s) handler (%s) done!', section, forhandler) except Exception: self.__smsconfig.errorandexit('loglevel')
def run(self): # load the configuration # Create default root user db = Database() abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) # store the abspath in globals for easier handling wisglobals.smsgatewayabspath = abspath configfile = abspath + '/conf/smsgw.conf' cfg = SmsConfig(configfile) readme = open(abspath + '/README.md', 'r') readmecontent = readme.read() version = re.compile(r"(?<=## Version)(.*v.\..*)", re.S).findall(readmecontent) if version: wisglobals.version = version[0].strip('\n') smsgwglobals.wislogger.debug("WIS: Version: " + str(wisglobals.version)) wisglobals.wisid = cfg.getvalue('wisid', 'nowisid', 'wis') wisglobals.wisipaddress = cfg.getvalue('ipaddress', '127.0.0.1', 'wis') wisglobals.wisport = cfg.getvalue('port', '7777', 'wis') wisglobals.cleanupseconds = cfg.getvalue('cleanupseconds', '86400', 'wis') wisglobals.validusernameregex = cfg.getvalue('validusernameregex', '([^a-zA-Z0-9])', 'wis') wisglobals.validusernamelength = cfg.getvalue('validusernamelength', 30, 'wis') wisglobals.ldapserver = cfg.getvalue('ldapserver', None, 'wis') wisglobals.ldapbasedn = cfg.getvalue('ldapbasedn', None, 'wis') wisglobals.ldapenabled = cfg.getvalue('ldapenabled', None, 'wis') ldapusers = cfg.getvalue('ldapusers', '[]', 'wis') wisglobals.ldapusers = json.loads(ldapusers) wisglobals.ldapusers = [item.lower() for item in wisglobals.ldapusers] smsgwglobals.wislogger.debug("WIS:" + str(wisglobals.ldapusers)) password = cfg.getvalue('password', '20778ba41791cdc8ac54b4f1dab8cf7602a81f256cbeb9e782263e8bb00e01794d47651351e5873f9ac82868ede75aa6719160e624f02bba4df1f94324025058', 'wis') salt = cfg.getvalue('salt', 'changeme', 'wis') # write the default user on startup db.write_users('root', password, salt) # read pissendtimeout wisglobals.pissendtimeout = int(cfg.getvalue('pissendtimeout', '20', 'wis')) # check if ssl is enabled wisglobals.sslenabled = cfg.getvalue('sslenabled', None, 'wis') wisglobals.sslcertificate = cfg.getvalue('sslcertificate', None, 'wis') wisglobals.sslprivatekey = cfg.getvalue('sslprivatekey', None, 'wis') wisglobals.sslcertificatechain = cfg.getvalue('sslcertificatechain', None, 'wis') smsgwglobals.wislogger.debug("WIS: SSL " + str(wisglobals.sslenabled)) if wisglobals.sslenabled is not None and 'true' in wisglobals.sslenabled.lower(): smsgwglobals.wislogger.debug("WIS: STARTING SSL") cherrypy.config.update({'server.ssl_module': 'builtin'}) cherrypy.config.update({'server.ssl_certificate': wisglobals.sslcertificate}) cherrypy.config.update({'server.ssl_private_key': wisglobals.sslprivatekey}) if wisglobals.sslcertificatechain is not None: cherrypy.config.update({'server.ssl_certificate_chain': wisglobals.sslcertificatechain}) cherrypy.config.update({'server.socket_host': wisglobals.wisipaddress}) cherrypy.config.update({'server.socket_port': int(wisglobals.wisport)}) cherrypy.tree.mount(StatsLogstash(), '/smsgateway/api/stats/logstash', {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}) cherrypy.quickstart(Root(), '/smsgateway', 'wis-web.conf')
def receiverouting(): # get conf peers abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/../conf/smsgw.conf' cfg = SmsConfig(configfile) peersjson = cfg.getvalue('peers', '[{}]', 'wis') smsgwglobals.wislogger.debug(peersjson) peers = json.loads(peersjson) # read all active routes try: routes = wisglobals.rdb.read_routing() except error.DatabaseError as e: smsgwglobals.wislogger.debug(e.message) # if we have an empty rounting table, # try to get one from our direct connected # neighbor = backup if len(routes) == 0 or routes is None: Helper.requestrouting(initial=True) # for all routes but myself # send the full table for route in routes: # remove route von conf routes # if exist for p in list(peers): if "url" not in p: continue if route["wisurl"] == p["url"]: peers.remove(p) if route["wisid"] != wisglobals.wisid: smsgwglobals.wislogger.debug("Sending to " + route["wisurl"]) # encode to json jdata = json.dumps(routes) data = GlobalHelper.encodeAES(jdata) request = \ urllib.request.Request( route["wisurl"] + "/smsgateway/api/receiverouting") request.add_header("Content-Type", "application/json;charset=utf-8") try: f = urllib.request.urlopen(request, data, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("Get peers NOTOK") except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug( "HELPER: receiverouting socket connection timeout") # check if there are remaining peers which # are not recognized by routing table to send # routing table to if len(peers) != 0: for p in peers: if "url" not in p: continue jdata = json.dumps(routes) data = GlobalHelper.encodeAES(jdata) request = \ urllib.request.Request( p["url"] + "/smsgateway/api/receiverouting") request.add_header("Content-Type", "application/json;charset=utf-8") try: f = urllib.request.urlopen(request, data, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) smsgwglobals.wislogger.debug("HELPER: " + "sending to " + p["url"]) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("Get peers NOTOK") pass except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug( "HELPER: receiverouting socket connection timeout") except socket.error as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug( "HELPER: receiverouting socket connection error")
def checkrouting(): # check if directly connected wis is # still alive, if not, mark all of # its routes obsolete # get conf peers abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/../conf/smsgw.conf' cfg = SmsConfig(configfile) peersjson = cfg.getvalue('peers', '[{}]', 'wis') smsgwglobals.wislogger.debug(peersjson) peers = json.loads(peersjson) smsgwglobals.wislogger.debug("HELPER: Routes to check " + str(len(peers))) for p in peers: try: if "url" not in p: continue smsgwglobals.wislogger.debug(p["url"] + "/smsgateway") request = \ urllib.request.Request(p["url"] + "/smsgateway") f = urllib.request.urlopen(request, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) if f.getcode() != 200: smsgwglobals.wislogger.debug("XXX WIS DELETE") wisglobals.rdb.delete_routing_wisurl( p["url"]) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) wisglobals.rdb.delete_routing_wisurl( p["url"]) except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("HELPER: ceckrouting socket connection timeout") # check routing table entries routes = wisglobals.rdb.read_routing() for route in routes: try: smsgwglobals.wislogger.debug(route["wisurl"] + "/smsgateway") request = \ urllib.request.Request(route["wisurl"] + "/smsgateway") f = urllib.request.urlopen(request, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) if f.getcode() != 200: smsgwglobals.wislogger.debug("XXX WIS DELETE") wisglobals.rdb.delete_routing_wisurl( p["url"]) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) wisglobals.rdb.delete_routing_wisurl( p["url"]) except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("HELPER: checkrouting socket connection timeout")
def receiverouting(): # get conf peers abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/../conf/smsgw.conf' cfg = SmsConfig(configfile) peersjson = cfg.getvalue('peers', '[{}]', 'wis') smsgwglobals.wislogger.debug(peersjson) peers = json.loads(peersjson) # read all active routes try: routes = wisglobals.rdb.read_routing() except error.DatabaseError as e: smsgwglobals.wislogger.debug(e.message) # if we have an empty rounting table, # try to get one from our direct connected # neighbor = backup if len(routes) == 0 or routes is None: Helper.requestrouting(initial=True) # for all routes but myself # send the full table for route in routes: # remove route von conf routes # if exist for p in list(peers): if "url" not in p: continue if route["wisurl"] == p["url"]: peers.remove(p) if route["wisid"] != wisglobals.wisid: smsgwglobals.wislogger.debug("Sending to " + route["wisurl"]) # encode to json jdata = json.dumps(routes) data = GlobalHelper.encodeAES(jdata) request = \ urllib.request.Request( route["wisurl"] + "/smsgateway/api/receiverouting") request.add_header("Content-Type", "application/json;charset=utf-8") try: f = urllib.request.urlopen(request, data, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("Get peers NOTOK") except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("HELPER: receiverouting socket connection timeout") # check if there are remaining peers which # are not recognized by routing table to send # routing table to if len(peers) != 0: for p in peers: if "url" not in p: continue jdata = json.dumps(routes) data = GlobalHelper.encodeAES(jdata) request = \ urllib.request.Request( p["url"] + "/smsgateway/api/receiverouting") request.add_header("Content-Type", "application/json;charset=utf-8") try: f = urllib.request.urlopen(request, data, timeout=5) smsgwglobals.wislogger.debug(f.getcode()) smsgwglobals.wislogger.debug("HELPER: " + "sending to " + p["url"]) except urllib.error.URLError as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("Get peers NOTOK") pass except socket.timeout as e: smsgwglobals.wislogger.debug(e) smsgwglobals.wislogger.debug("HELPER: receiverouting socket connection timeout")
def run(self): # load the configuration abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' gammucfg = abspath + '/conf/gammu.conf' cfg = SmsConfig(configfile) pidglobals.pidid = cfg.getvalue('pidid', 'pid-dummy', 'pid') smsgwglobals.pidlogger.debug("PisID: " + pidglobals.pidid) # Gammu Debug on/off gammudebug = cfg.getvalue('gammudebug', 'Off', 'pid') if gammudebug == "On": pidglobals.gammudebug = True todir = cfg.getvalue('logdirectory', abspath + '/logs/', 'pid') tofile = cfg.getvalue('gammudebugfile', 'gammu.log', 'pid') gammudebugfile = todir + tofile pidglobals.gammudebugfile = gammudebugfile smsgwglobals.pidlogger.debug("Gammu Debug on! Will log to " + str(pidglobals.gammudebugfile)) else: pidglobals.gammudebug = False # Wrapping Gammu or not wrapgammu = cfg.getvalue('wrapgammu', 'Off', 'pid') if wrapgammu == "On": pidglobals.wrapgammu = True gammucmd = cfg.getvalue('gammucmd', 'Blank', 'pid') smsgwglobals.pidlogger.debug("Gammucmd: " + str(gammucmd)) if gammucmd == "Blank": option = "gammucmd - is not set!" cfg.errorandexit(option) if path.isfile(gammucmd) or path.islink(gammucmd): # file or link exists all fine pidglobals.gammucmd = gammucmd else: # exit PID here as not Modem connection will work! option = "gammucmd - Command given not found!" cfg.errorandexit(option) else: pidglobals.wrapgammu = False smsgwglobals.pidlogger.debug("WrapGammu: " + str(pidglobals.wrapgammu)) testmode = cfg.getvalue('testmode', 'Off', 'pid') if testmode == "On": # set testmode - content "ERROR" "SUCCESS" and "LONGWAIT" is # handled in a special way now pidglobals.testmode = True else: pidglobals.testmode = False smsgwglobals.pidlogger.debug("TestMode: " + str(pidglobals.testmode)) retrypisurl = cfg.getvalue('retrypisurl', '2', 'pid') smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "RetryPisUrl: " + retrypisurl) retrywait = cfg.getvalue('retrywait', '5', 'pid') smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "RetryWait: " + retrywait) modemcfg = cfg.getvalue('modemlist', '[{}]', 'pid') try: # convert json to list of dictionary entries modemlist = json.loads(modemcfg) except: cfg.errorandexit("modemlist - not a valid JSON structure!") # check if modemcfg is set if 'modemid' not in modemlist[0]: # if len(modemlist) == 0: cfg.errorandexit("modemlist - not set!!!") else: # validate modem settings for modem in modemlist: try: re.compile(modem['regex']) except: cfg.errorandexit("modemlist - at " + modem['modemid'] + " - invalid regex!") # connect to USBModems and persist in pidglobals Modem.connectmodems(modemlist, gammucfg) smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "ModemList: " + str(pidglobals.modemlist)) if len(pidglobals.modemlist) == 0: errortext = "at any configured modem." cfg.errorandexit(errortext, 2) pisurlcfg = cfg.getvalue('pisurllist', '[{"url": "ws://127.0.0.1:7788"}]', 'pid') # convert json to list of dictionary entries pisurllist = json.loads(pisurlcfg) smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "PisUrlList: " + str(pisurllist)) # endless try to connect to configured PIS # error: wait for some secs, then 1 retry, then next PID in list curpis = 0 tries = 1 while True: try: if pidglobals.closingcode: raise baseurl = pisurllist[curpis]['url'] pisurl = baseurl + "/ws" smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Try " + str(tries) + ": " + "Connecting to: " + pisurl) # init websocket client with heartbeat, 30 is fixed in all # modules wis/pis/pid ws = PidWsClient(pisurl, protocols=['http-only', 'chat'], heartbeat_freq=30) ws.connect() # set values for primary check in Websocket connection! # trim ws out of ws:/.. and add http:/ pidglobals.curpisurl = "http" + baseurl[2:] pidglobals.primpisurl = "http" + pisurllist[0]['url'][2:] ws.run_forever() except KeyboardInterrupt: ws.close() # leave while loop break except Exception as e: # do retry except there is no more modem to communicate if (pidglobals.closingcode is None or pidglobals.closingcode < 4000): # try to reconnect smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Got a problem will reconnect " "in " + retrywait + " seconds.") smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "Problem is: " + str(e)) try: time.sleep(int(retrywait)) except: break if tries < int(retrypisurl): tries = tries + 1 else: tries = 1 curpis = curpis + 1 if curpis == len(pisurllist): curpis = 0 pidglobals.closingcode = None elif pidglobals.closingcode == 4001: # go back to inital PID # reset while parameter for pis and retries smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Going back to Prim PID") curpis = 0 tries = 1 pidglobals.closingcode = None elif pidglobals.closingcode == 4000: # leave while loop # no connection to modem found! break
def run(self): # load the configuration abspath = path.abspath(path.join(path.dirname(__file__), path.pardir)) configfile = abspath + '/conf/smsgw.conf' gammucfg = abspath + '/conf/gammu.conf' print(configfile) cfg = SmsConfig(configfile) pidglobals.pidid = cfg.getvalue('pidid', 'pid-dummy', 'pid') smsgwglobals.pidlogger.debug("PisID: " + pidglobals.pidid) testmode = cfg.getvalue('testmode', 'Off', 'pid') if testmode == "On": # set testmode - content "ERROR" "SUCCESS" and "LONGWAIT" is # handled in a special way now pidglobals.testmode = True else: pidglobals.testmode = False smsgwglobals.pidlogger.debug("TestMode: " + str(pidglobals.testmode)) retrypisurl = cfg.getvalue('retrypisurl', '2', 'pid') smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "RetryPisUrl: " + retrypisurl) retrywait = cfg.getvalue('retrywait', '5', 'pid') smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "RetryWait: " + retrywait) modemcfg = cfg.getvalue('modemlist', '[{}]', 'pid') # convert json to list of dictionary entries modemlist = json.loads(modemcfg) # check if modemcfg is set if not 'modemid' in modemlist[0]: #if len(modemlist) == 0: cfg.errorandexit("modemlist - not set!!!") # connect to USBModems and persist in pidglobals Modem.connectmodems(modemlist, gammucfg) smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "ModemList: " + str(pidglobals.modemlist)) pisurlcfg = cfg.getvalue('pisurllist', '[{"url": "ws://127.0.0.1:7788"}]', 'pid') # convert json to list of dictionary entries pisurllist = json.loads(pisurlcfg) smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "PisUrlList: " + str(pisurllist)) # endless try to connect to configured PIS # error: wait for some secs, then 1 retry, then next PID in list curpis = 0 tries = 1 while True: try: if pidglobals.closingcode: raise baseurl = pisurllist[curpis]['url'] pisurl = baseurl + "/ws" smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Try " + str(tries) + ": " + "Connecting to: " + pisurl) # init websocket client with heartbeat, 30 is fixed in all # modules wis/pis/pid ws = PidWsClient(pisurl, protocols=['http-only', 'chat'], heartbeat_freq=30) ws.connect() # set values for primary check in Websocket connection! # trim ws out of ws:/.. and add http:/ pidglobals.curpisurl = "http" + baseurl[2:] pidglobals.primpisurl = "http" + pisurllist[0]['url'][2:] ws.run_forever() except KeyboardInterrupt: ws.close() # leave while loop break except Exception as e: # do retry except there is no more modem to communicate if (pidglobals.closingcode is None or pidglobals.closingcode < 4000): # try to reconnect smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Got a problem will reconnect " "in " + retrywait + " seconds.") smsgwglobals.pidlogger.debug(pidglobals.pidid + ": " + "Problem is: " + str(e)) try: time.sleep(int(retrywait)) except: break if tries < int(retrypisurl): tries = tries + 1 else: tries = 1 curpis = curpis + 1 if curpis == len(pisurllist): curpis = 0 pidglobals.closingcode = None elif pidglobals.closingcode == 4001: # go back to inital PID # reset while parameter for pis and retries smsgwglobals.pidlogger.info(pidglobals.pidid + ": " + "Going back to Prim PID") curpis = 0 tries = 1 pidglobals.closingcode = None elif pidglobals.closingcode == 4000: # leave while loop # no connection to modem found! break