class TestAPIClient(unittest.TestCase): """ Unit tests for the APIClient object. """ def setUp(self): self.client = APIClient(reactor, '9001', 'somesecret') self.client.api_url = 'http://localhost:8080/' def test_generate_url(self): """ See if URL generation works properly. """ url = self.client.url('user', 'whoami') if url == 'http://localhost:8080/api/draft15/user/whoami': return self.fail('APIClient generated url incorrectly: {0}'.format(url)) def test_request_without_token(self): """ Make sure certain requests fail when no token is present. """ try: self.client.user_whoami() except ValueError: return self.fail('Client sent request without a token') def test_request_correct(self): """ Make sure this succeeds! """ # dummy server self.proc = subprocess.Popen([ sys.executable, os.path.abspath( os.path.join(os.path.dirname(__file__), 'dummy/dapi.py') ) ]) time.sleep(2) d = self.client.user_whoami(token='23534') def handle(response): self.delayed.cancel() self.proc.terminate() if response.data is None or not 'username' in response.data: self.fail('Failed to process response{0}'.format( '' if not response.raw_data else ' from "{0}"'.format(response.raw_data))) d.addCallback(handle) def timeout(): self.proc.terminate() self.fail('No response received') self.delayed = reactor.callLater(10, timeout) return d
def __init__(self, _reactor, id='198', secret='f1e3ec71552293b5b82509c90836778d', file='./storage/config.bsv', port=8080, agent='slate/1 (dAmnViper 2)', option=None, state=None, stdout=None, stddebug=None, cache='./storage/api.cache'): def default_write(msg, *args): pass self.stdout = stdout or default_write self._debug = stddebug or default_write self.d = None self.file = file self.cachef = cache if not os.path.exists('./storage'): os.mkdir('./storage', 0o755) self.write('** Welcome to the configuration file!') self.data = Settings(self.file) self.api = APIClient(_reactor, id, secret, self.data.api.code, self.data.api.token, agent) self.port = port self.state = state self._reactor = reactor if option is None or not self.data.api.username: self.run_all('http://localhost:{0}'.format(port)) else: self.menu()
def __init__(self, _reactor, id, secret, file='./storage/config.bsv', port=8080, agent='slate/1 (dAmnViper 2)', option=None, state=None, stdout=None, stddebug=None, cache='./storage/api.cache'): def default_write(msg, *args): pass self.stdout = stdout or default_write self._debug = stddebug or default_write self.d = None self.file = file self.cachef = cache if not os.path.exists('./storage'): os.mkdir('./storage', 0o755) self.write('** Welcome to the configuration file!') self.data = Settings(self.file) self.api = APIClient(_reactor, id, secret, self.data.api.code, self.data.api.token, agent) self.port = port self.state = state self._reactor = reactor if option is None or not self.data.api.username: self.run_all('http://localhost:{0}'.format(port)) else: self.menu()
def setUp(self): self.client = APIClient(reactor, '9001', 'somesecret') self.client.api_url = 'http://localhost:8080/'
class Configure: # slate client id and secret # - id: 110 # - secret: 605c4a06216380fbdff26228c53cf610 file = './storage/config.bsv' def __init__(self, _reactor, id='198', secret='f1e3ec71552293b5b82509c90836778d', file='./storage/config.bsv', port=8080, agent='slate/1 (dAmnViper 2)', option=None, state=None, stdout=None, stddebug=None, cache='./storage/api.cache'): def default_write(msg, *args): pass self.stdout = stdout or default_write self._debug = stddebug or default_write self.d = None self.file = file self.cachef = cache if not os.path.exists('./storage'): os.mkdir('./storage', 0o755) self.write('** Welcome to the configuration file!') self.data = Settings(self.file) self.api = APIClient(_reactor, id, secret, self.data.api.code, self.data.api.token, agent) self.port = port self.state = state self._reactor = reactor if option is None or not self.data.api.username: self.run_all('http://localhost:{0}'.format(port)) else: self.menu() def write(self, msg): self.stdout(msg, showns=False) def debug(self, msg): self._debug(msg, showns=False) def menu(self): while True: self.data.load() self.write('** Current configuration:') # Display config data! info = self.data.api self.write('** Bot {0} = {1}'.format('username', info.username)) self.write('** Bot {0} = {1}'.format('owner', self.data.owner)) self.write('** Bot {0} = {1}'.format('trigger', self.data.trigger)) self.write('** Autojoin:') self.write(', '.join(self.data.autojoin)) self.write('') self.write('** Choose one of the following options:') self.write('*** user - authorize the bot with a different account.') self.write('*** info - Set the bot\'s owner and trigger.') self.write('*** autojoin - Set the bot\'s autojoin list.') self.write('*** all - Set all configuration data.') self.write('*** exit - Leave the configuration file.') ins = '' while not ins in ('all', 'autojoin', 'exit', 'info', 'user'): ins = get_input('>> ').lower() if ins == 'exit': return if ins == 'all': self.run_all('http://localhost:{0}'.format(self.port)) continue if ins == 'info': self.get_info() self.save() continue if ins == 'autojoin': self.get_autojoin() self.save() if ins == 'user': self.get_user('http://localhost:{0}'.format(self.port)) ''' if self.d is not None: def stop(obj): try: self._reactor.stop() except: pass self.d = None self.d.addCallback(stop)''' def run_all(self, redirect): self.write('** Please fill in the following appropriately') self.get_info() self.get_autojoin() self.write('** Ok! Now we need to authorize!') return self.get_user(redirect) def get_user(self, redirect): try: file = open(self.cachef, 'r') cache = json.loads(file.read()) file.close() except IOError: self.debug('>> No cache data stored') self.d = defer.Deferred() self.start_auth(redirect) return self.d user = get_input('> Bot account username: '******'username'] self.data.api.symbol = data['symbol'] self.data.api.code = data['code'] self.data.api.token = data['token'] self.data.api.refresh = data['refresh'] self.data.api.damntoken = data['damntoken'] self.debug('** Found cached data for {0}{1}.'.format(data['symbol'], data['username'])) self.save() except KeyError: self.write('>> No cached data stored for \'{0}\''.format(user)) self.write('>> Requires authorization') self.d = defer.Deferred() self.start_auth(redirect) return self.d return None def start_auth(self, redirect): """ Start the auth application. All this really does is start the auth server and then display a url on screen. The user should visit this url to authorize the app. """ d = self.api.auth_app(self.port) d.addCallback(self.authResponse) # Make a url url = self.api.url('authorize', api='oauth2', client_id=self.api.client_id, client_secret=self.api.client_secret, redirect_uri=redirect, response_type='code', state=self.state ) # Send user there, somehow... self.write('** Please visit the following URL to authorize this app:') sys.stdout.write('{0}\n'.format(url)) sys.stdout.flush() # Now we wait for the user's webbrowser to be redirected to our server. def authResponse(self, response): """ Called when the app is successfully authorized. """ if not response['status']: resp = response['data'] if 'error' in resp.args: self.write('>> Auth failed: {0}\n'.format(resp.args['error_description'][0])) else: self.write('>> Authorization failed.\n') self.debug('>> {0}\n'.format(response['data'])) self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response self.write('** Application authorized. Retrieving access token') self.data.api.code = self.api.auth_code self.data.save() d = self.api.grant(req_state=self.state) d.addCallbacks(self.grantResponse, self.grantFailure) return response def grantResponse(self, response): """ Called when the app is granted access to the API. """ if not response['status']: self.write('>> Failed to get an access token.\n') try: self.write('>> {0}\n'.format(response['data'].data['error_description'])) except KeyError: pass self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response self.write('** Got an access token!') self.data.api.token = self.api.token self.data.api.refresh = self.api.refresh_token self.data.save() # whoami? self.api.user_whoami().addCallback(self.whoami) return response def grantFailure(self, response): """ Called when the app is refused access to the API. """ self.write('>> Failed to get an access token.') self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response def whoami(self, response): """ Handle the response to whoami API call. """ if not 'username' in response.data: self.write('>> Whoami failed.') self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response symbol = response.data['symbol'] username = response.data['username'] self.data.api.symbol = symbol self.data.api.username = username self.data.save() self.write('** Authorized account {0}{1}'.format(symbol, username)) self.api.user_damntoken().addCallback(self.damntoken) def damntoken(self, response): """ Handle the response to whoami API call. """ if response.data is None: self.write('>> damntoken failed.') self.debug('>> debug data:') self.debug(response) self.d.callback({'status': False, 'response': response}) return response self.data.api.damntoken = response.data['damntoken'] self.write('** Retrieved authtoken') self.save() self.cache() self.d.callback({'status': True, 'response': response}) def get_info(self): for option in ['owner', 'trigger']: setattr(self.data, option, get_input('> Bot ' + option + ': ')) def get_autojoin(self): self.write( '** Next we need to know which channels you want your' ) self.write( '** bot to join on startup. Please enter a list of' ) self.write( '** channels below, separated by commas. Each channel' ) self.write( '** must begin with a hash (#) or chat:. Leave blank' ) self.write( '** to use the default (#Botdom).' ) aj = get_input('> ', True) if aj: aj = aj.split(',') if aj: self.data.autojoin = [ns.strip() for ns in aj if ns.strip()] if not self.data.autojoin: self.data.autojoin.append('#Botdom') def save(self): self.data.save() self.write( '** Configuration file saved!' ) def cache(self): try: file = open(self.cachef, 'r') cache = json.loads(file.read()) file.close() except IOError: cache = {} cache[self.data.api.username.lower()] = { 'username': self.data.api.username, 'symbol': self.data.api.symbol, 'code': self.data.api.code, 'token': self.data.api.token, 'refresh': self.data.api.refresh, 'damntoken': self.data.api.damntoken } try: file = open(self.cachef, 'w') file.write(export_struct(cache)) file.close() except IOError: pass
class Configure: # slate client id and secret # - id: 110 # - secret: 605c4a06216380fbdff26228c53cf610 file = './storage/config.bsv' def __init__(self, _reactor, id, secret, file='./storage/config.bsv', port=8080, agent='slate/1 (dAmnViper 2)', option=None, state=None, stdout=None, stddebug=None, cache='./storage/api.cache'): def default_write(msg, *args): pass self.stdout = stdout or default_write self._debug = stddebug or default_write self.d = None self.file = file self.cachef = cache if not os.path.exists('./storage'): os.mkdir('./storage', 0o755) self.write('** Welcome to the configuration file!') self.data = Settings(self.file) self.api = APIClient(_reactor, id, secret, self.data.api.code, self.data.api.token, agent) self.port = port self.state = state self._reactor = reactor if option is None or not self.data.api.username: self.run_all('http://localhost:{0}'.format(port)) else: self.menu() def write(self, msg): self.stdout(msg, showns=False) def debug(self, msg): self._debug(msg, showns=False) def menu(self): while True: self.data.load() self.write('** Current configuration:') # Display config data! info = self.data.api self.write('** Bot {0} = {1}'.format('username', info.username)) self.write('** Bot {0} = {1}'.format('owner', self.data.owner)) self.write('** Bot {0} = {1}'.format('trigger', self.data.trigger)) self.write('** Autojoin:') self.write(', '.join(self.data.autojoin)) self.write('') self.write('** Choose one of the following options:') self.write( '*** user - authorize the bot with a different account.') self.write('*** info - Set the bot\'s owner and trigger.') self.write('*** autojoin - Set the bot\'s autojoin list.') self.write('*** all - Set all configuration data.') self.write('*** exit - Leave the configuration file.') ins = '' while not ins in ('all', 'autojoin', 'exit', 'info', 'user'): ins = get_input('>> ').lower() if ins == 'exit': return if ins == 'all': self.run_all('http://localhost:{0}'.format(self.port)) continue if ins == 'info': self.get_info() self.save() continue if ins == 'autojoin': self.get_autojoin() self.save() if ins == 'user': self.get_user('http://localhost:{0}'.format(self.port)) ''' if self.d is not None: def stop(obj): try: self._reactor.stop() except: pass self.d = None self.d.addCallback(stop)''' def run_all(self, redirect): self.write('** Please fill in the following appropriately') self.get_info() self.get_autojoin() self.write('** Ok! Now we need to authorize!') return self.get_user(redirect) def get_user(self, redirect): try: file = open(self.cachef, 'r') cache = json.loads(file.read()) file.close() except IOError: self.debug('>> No cache data stored') self.d = defer.Deferred() self.start_auth(redirect) return self.d user = get_input('> Bot account username: '******'username'] self.data.api.symbol = data['symbol'] self.data.api.code = data['code'] self.data.api.token = data['token'] self.data.api.refresh = data['refresh'] self.data.api.damntoken = data['damntoken'] self.debug('** Found cached data for {0}{1}.'.format( data['symbol'], data['username'])) self.save() except KeyError: self.write('>> No cached data stored for \'{0}\''.format(user)) self.write('>> Requires authorization') self.d = defer.Deferred() self.start_auth(redirect) return self.d return None def start_auth(self, redirect): """ Start the auth application. All this really does is start the auth server and then display a url on screen. The user should visit this url to authorize the app. """ d = self.api.auth_app(self.port) d.addCallback(self.authResponse) # Make a url url = self.api.url('authorize', api='oauth2', client_id=self.api.client_id, client_secret=self.api.client_secret, redirect_uri=redirect, response_type='code', state=self.state) # Send user there, somehow... self.write('** Please visit the following URL to authorize this app:') sys.stdout.write('{0}\n'.format(url)) sys.stdout.flush() # Now we wait for the user's webbrowser to be redirected to our server. def authResponse(self, response): """ Called when the app is successfully authorized. """ if not response['status']: resp = response['data'] if 'error' in resp.args: self.write('>> Auth failed: {0}\n'.format( resp.args['error_description'][0])) else: self.write('>> Authorization failed.\n') self.debug('>> {0}\n'.format(response['data'])) self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response self.write('** Application authorized. Retrieving access token') self.data.api.code = self.api.auth_code self.data.save() d = self.api.grant(req_state=self.state) d.addCallbacks(self.grantResponse, self.grantFailure) return response def grantResponse(self, response): """ Called when the app is granted access to the API. """ if not response['status']: self.write('>> Failed to get an access token.\n') try: self.write('>> {0}\n'.format( response['data'].data['error_description'])) except KeyError: pass self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response self.write('** Got an access token!') self.data.api.token = self.api.token self.data.api.refresh = self.api.refresh_token self.data.save() # whoami? self.api.user_whoami().addCallback(self.whoami) return response def grantFailure(self, response): """ Called when the app is refused access to the API. """ self.write('>> Failed to get an access token.') self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response def whoami(self, response): """ Handle the response to whoami API call. """ if not 'username' in response.data: self.write('>> Whoami failed.') self._reactor.stop() self.d.callback({'status': False, 'response': response}) return response symbol = response.data['symbol'] username = response.data['username'] self.data.api.symbol = symbol self.data.api.username = username self.data.save() self.write('** Authorized account {0}{1}'.format(symbol, username)) self.api.user_damntoken().addCallback(self.damntoken) def damntoken(self, response): """ Handle the response to whoami API call. """ if response.data is None: self.write('>> damntoken failed.') self.debug('>> debug data:') self.debug(response) self.d.callback({'status': False, 'response': response}) return response self.data.api.damntoken = response.data['damntoken'] self.write('** Retrieved authtoken') self.save() self.cache() self.d.callback({'status': True, 'response': response}) def get_info(self): for option in ['owner', 'trigger']: setattr(self.data, option, get_input('> Bot ' + option + ': ')) def get_autojoin(self): self.write('** Next we need to know which channels you want your') self.write('** bot to join on startup. Please enter a list of') self.write('** channels below, separated by commas. Each channel') self.write('** must begin with a hash (#) or chat:. Leave blank') self.write('** to use the default (#Botdom).') aj = get_input('> ', True) if aj: aj = aj.split(',') if aj: self.data.autojoin = [ns.strip() for ns in aj if ns.strip()] if not self.data.autojoin: self.data.autojoin.append('#Botdom') def save(self): self.data.save() self.write('** Configuration file saved!') def cache(self): try: file = open(self.cachef, 'r') cache = json.loads(file.read()) file.close() except IOError: cache = {} cache[self.data.api.username.lower()] = { 'username': self.data.api.username, 'symbol': self.data.api.symbol, 'code': self.data.api.code, 'token': self.data.api.token, 'refresh': self.data.api.refresh, 'damntoken': self.data.api.damntoken } try: file = open(self.cachef, 'w') file.write(export_struct(cache)) file.close() except IOError: pass