#!/usr/bin/env python from twisted.internet import reactor from twisted.internet.ssl import DefaultOpenSSLContextFactory from twisted.internet.protocol import Protocol, Factory from json import load, dump from sys import exit listener = None connections = {} def log(data): print("[LOG]", data) def debug(data): print("[DEBUG]", data) def warn(data): print("[WARNING]", data) def error(data): print("[ERROR]", data) exit(1) def sendData(addr, data): connections[addr].send(data) def sendSuccess(addr, data): sendData(addr, "[y] " + data) def sendFailure(addr, data): sendData(addr, "[n] " + data) def sendInfo(addr, data): sendData(addr, "[i] " + data) class Base(Protocol): def __init__(self, addr): self.addr = addr self.authed = False def send(self, data): data += "\r\n" data = data.encode("utf-8", "replace") self.transport.write(data) def dataReceived(self, data): data = data.decode("utf-8", "replace") log("Data received from %s:%s -- %s" % (self.addr.host, self.addr.port, repr(data))) helper.parseCommand(self.addr, self.authed, data) def connectionMade(self): log("Connection from %s:%s" % (self.addr.host, self.addr.port)) self.send("Hello.") def connectionLost(self, reason): global connections log("Connection lost from %s:%s -- %s" % (self.addr.host, self.addr.port, reason.getErrorMessage())) if not listener == None: if self.addr in connections.keys(): del connections[self.addr] else: warn("Tried to remove a non-existant connection.") else: warn("Tried to remove a connection from a listener that wasn't running.") class BaseFactory(Factory): def buildProtocol(self, addr): global connections entry = Base(addr) connections[addr] = entry return entry def send(self, addr, data): global connections if addr in connections.keys(): connection = connections[addr] connection.send(data) else: return class Helper(object): def getConfig(self): with open("config.json", "r") as f: config = load(f) if set(["port", "bind", "usessl", "usepassword"]).issubset(set(config.keys())): if config["usessl"] == True: if not set(["cert", "key"]).issubset(set(config.keys())): error("SSL is on but certificate or key is not defined") if config["usepassword"] == True: if not "password" in config.keys(): error("Password authentication is on but password is not defined") return config else: error("Mandatory values missing from config") def parseCommand(self, addr, authed, data): data = data.strip() spl = data.split() obj = connections[addr] success = lambda data: sendSuccess(addr, data) failure = lambda data: sendFailure(addr, data) info = lambda data: sendInfo(addr, data) incUsage = lambda: sendFailure(addr, "Incorrect usage") length = len(spl) if len(spl) > 0: cmd = spl[0] else: send("No text was sent") return if authed == True: if cmd == "pass": info("You are already authenticated") return elif cmd == "logout": obj.authed = False success("Logged out") return else: incUsage() return else: if cmd == "pass": if length == 2: if spl[1] == config["password"]: success("Authenticated successfully") obj.authed = True return else: failure("Password incorrect") obj.transport.loseConnection() return else: incUsage() return else: incUsage() return if __name__ == "__main__": helper = Helper() config = helper.getConfig() listener = BaseFactory() if config["usessl"] == True: reactor.listenSSL(config["port"], listener, DefaultOpenSSLContextFactory(config["key"], config["cert"]), interface=config["bind"]) log("Threshold running with SSL on %s:%s" % (config["bind"], config["port"])) else: reactor.listenTCP(config["port"], listener, interface=config["bind"]) log("Threshold running on %s:%s" % (config["bind"], config["port"])) reactor.run()