diff --git a/API.py b/API.py index 68af08d..d138010 100644 --- a/API.py +++ b/API.py @@ -1,62 +1,85 @@ -from xmlrpc.client import Fault - -from twisted.web import xmlrpc from hashlib import blake2b - -class FD_API_HELPERS(): - def __init__(self,CONFIG,APIQUEUE): - self._CONFIG = CONFIG - self._APIQUEUE = APIQUEUE - - def connected(self,_id): - for system in self._CONFIG['SYSTEMS']: - for peerid in self._CONFIG['SYSTEMS'][self._system]['PEERS']: - if peerid == _id: - return(system) - return(False) - - - def validateHMAC(_hmac,_system): - self._config = self._CONFIG['SYSTEMS'][_system] - _h = blake2b(key=self._config['_opt_key'], digest_size=16) - _h.update('validate') - _hash = _h.digest() - if _hash == _hmac: - return(True) +from spyne import ServiceBase, rpc, Integer, Decimal, UnsignedInteger32, Unicode, Iterable, error +from dmr_utils3.utils import bytes_3 + + +class FD_APIUserDefinedContext(object): + def __init__(self,CONFIG,APIQUEUE,BRIDGES): + self.CONFIG = CONFIG + self.APIQUEUE = APIQUEUE + self.BRIDGES = BRIDGES + + def getconfig(self): + return self.CONFIG + + def getapiqueue(self): + return self.APIQUEUE + + def getbridges(self): + return self.BRIDGES + + def validateKey(self,dmrid,key): + systems = self.CONFIG['SYSTEMS'] + dmrid = bytes_3(dmrid) + for system in systems: + for peerid in systems[system]['PEERS']: + if peerid == dmrid: + if key == _hash: + return(systems[system]['_opt_key']) + else: + return(False) + + def reset(self,system): + self.CONFIG['SYSTEMS'][system]['_reset'] = True + + def queue(self,system,options): + self.APIQUEUE.append((system,options)) + + +class FD_API(ServiceBase): + _version = 0.1 + + #def validateHMAC(_hmac,_system): + # self._config = self._CONFIG['SYSTEMS'][_system] + # _h = blake2b(key=self._config['_opt_key'], digest_size=16) + # _h.update('validate') + # _hash = _h.digest() + # if _hash == _hmac: + # return(True) + # else: + # return(False) + + + #return API version + @rpc(Unicode, _returns=Decimal()) + def version(ctx, sessionid): + return(FD_API._version) + + @rpc(Unicode,Unicode, _returns=Unicode()) + def reset(ctx,dmrid,key): + system = ctx.udc.validateKey(dmrid,key) + if system: + ctx.udc.reset(system) else: - return(False) - - -class FD_API(xmlrpc.XMLRPC(allow_none=True)): + raise error.InvalidCredentialsError() - def __init__(self,CONFIG,APIQUEUE): - self._CONFIG = CONFIG - self._APIQUEUE = APIQUEUE - self.helpers = FD_API_HELPERS(self._CONFIG,self._APIQUEUE) - - def reset(self,_id,_hmac): - return('') - system = self.helpers.connected(_id) - if result: - if self.helpers.validateHMAC(_hmac,_system): - self._CONFIG['SYSTEMS'][system]['_reset'] = True - else: - return Fault(2, "Authentication failed") + @rpc(UnsignedInteger32,UnsignedInteger32,Unicode,_returns=Unicode()) + def setoptions(ctx,dmrid,key,options): + system = ctx.udc.validateKey(dmrid,key) + if system: + ctx.udc.queue(system,options) else: - return Fault(1, "ID not connected to this server") - - return('Z') - - -def main(): - from twisted.internet import reactor - from twisted.web import server + raise error.InvalidCredentialsError() - r = FD_API({},{}) - reactor.listenTCP(7080, server.Site(r)) - reactor.run() + @rpc(UnsignedInteger32,_returns=(Unicode())) + def killserver(ctx,killkey): + pass + @rpc(_returns=Unicode()) + def getconfig(ctx): + return ctx.udc.getconfig() -if __name__ == "__main__": - main() + @rpc(_returns=Unicode()) + def getbridges(ctx): + return ctx.udc.getbridges() diff --git a/bridge_master.py b/bridge_master.py index 5a9159f..fefcb92 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -50,7 +50,15 @@ from hashlib import blake2b from twisted.internet.protocol import Factory, Protocol from twisted.protocols.basic import NetstringReceiver from twisted.internet import reactor, task -from twisted.web import server +from twisted.web.server import Site + +from spyne import Application +from spyne.server.twisted import TwistedWebResource +from spyne.protocol.http import HttpRpc +from spyne.protocol.json import JsonDocument + + + # Things we import from the main hblink module from hblink import HBSYSTEM, OPENBRIDGE, systems, hblink_handler, reportFactory, REPORT_OPCODES, mk_aliases, acl_check @@ -81,8 +89,7 @@ import re from binascii import b2a_hex as ahex from AMI import AMI -from API import FD_API - +from API import FD_API, FD_APIUserDefinedContext # Does anybody read this stuff? There's a PEP somewhere that says I should do this. __author__ = 'Cortney T. Buffington, N0MJS, Forked by Simon Adlem - G7RZU' @@ -137,12 +144,25 @@ def config_reports(_config, _factory): return report_server # Start API server -def config_API(_config, _apiqueue): +def config_API(_config, _apiqueu, _bridges): + - r = FD_API(_config,_apiqueue) - reactor.listenTCP(7080, server.Site(r)) + application = Application([FD_API], + tns='freedmr.api', + in_protocol=HttpRpc(validator='soft'), + out_protocol=JsonDocument() + ) - return r + def _on_method_call(ctx): + ctx.udc = FD_APIUserDefinedContext(CONFIG,APIQUEUE,_bridges) + + application.event_manager.add_listener('method_call', _on_method_call) + + resource = TwistedWebResource(application) + site = Site(resource) + + r = reactor.listenTCP(8000, site, interface='0.0.0.0') + return(r) # Import Bridging rules @@ -821,6 +841,13 @@ def options_config(): prohibitedTGs = [0,1,2,3,4,5,9,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999] + try: + for (system,options) in APIQUEUE.pop(1): + if not CONFIG['SYSTEMS'][_system]['_reset']: + CONFIG['SYSTEMS'][system][OPTIONS] = options + except IndexError: + pass + for _system in CONFIG['SYSTEMS']: try: if CONFIG['SYSTEMS'][_system]['MODE'] != 'MASTER': @@ -2613,6 +2640,9 @@ if __name__ == '__main__': import sys import os import signal + + global CONFIG + global APIQUEUE # Higheset peer ID permitted by HBP PEER_MAX = 4294967295 @@ -2856,8 +2886,8 @@ if __name__ == '__main__': #Initialize API - APIQUEUE = {} - api = config_API(CONFIG,APIQUEUE) + APIQUEUE = [] + api = config_API(CONFIG,APIQUEUE,BRIDGES) if api: logger.info('(API) API running') else: diff --git a/requirements.txt b/requirements.txt index 69123e4..de11f31 100755 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ configparser>=3.0.0 resettabletimer>=0.7.0 setproctitle Pyro5 +spyne