def current_ship(charid): # fetch the current ship typeID charid is flying # check if ship scope is available test_scopes = ['esi-location.read_ship_type.v1'] result = check_scope(charid, test_scopes) if not result: # does not have proper scopes msg = 'character {0} missing ESI scopes: {1}'.format(charid, result) _logger.log('[' + __name__ + '] ' + msg, _logger.LogLevel.WARNING) return False, None # fetch current ship request_ship_url = 'characters/{}/ship/'.format(charid) esi_ship_code, esi_ship_result = common.request_esi.esi(__name__, request_ship_url, version='v1', method='get', charid=charid) _logger.log( '[' + __name__ + '] /characters output: {}'.format(esi_ship_result), _logger.LogLevel.DEBUG) if esi_ship_code != 200: # something broke severely _logger.log( '[' + __name__ + '] /characters/ship API error {0}: {1}'.format( esi_ship_code, esi_ship_result), _logger.LogLevel.WARNING) return False, None return True, esi_ship_result
def find_types(charid, types): # look through character assets to find matching typeids # check if ship scope is available test_scopes = ['esi-assets.read_assets.v1'] result = check_scope(charid, test_scopes) if not result: # does not have proper scopes msg = 'character {0} missing ESI scopes: {1}'.format(charid, result) _logger.log('[' + __name__ + '] ' + msg, _logger.LogLevel.WARNING) return False, None request_assets_url = 'characters/{}/assets/'.format(charid) esi_assets_code, esi_assets_result = common.request_esi.esi( __name__, request_assets_url, version='v3', method='get', charid=charid) _logger.log( '[' + __name__ + '] /characters output: {}'.format(esi_assets_result), _logger.LogLevel.DEBUG) if esi_assets_code != 200: _logger.log( '[' + __name__ + '] /characters/assets API error {0}: {1}'.format( esi_assets_code, esi_assets_result), _logger.LogLevel.WARNING) return False, None # locate the typeids in question asset_result = [] for asset in esi_assets_result: if asset['type_id'] in types: asset_result.append(asset) return True, asset_result
def fetch_chardetails(info): from common.check_scope import check_scope from common.request_esi import esi from tri_core.common.scopes import scope from json import dumps import common.logger as _logger import common.ldaphelpers as _ldaphelpers new_entry = dict() alt_charid = info['uid'] alt_charname = info['characterName'] new_entry['character_id'] = alt_charid new_entry['character_name'] = alt_charname new_entry['corporation_id'] = info['corporation'] new_entry['corporation_name'] = info['corporationName'] new_entry['authgroups'] = info['authGroup'] if 'alliance' in info: new_entry['alliance_id'] = info['alliance'] new_entry['alliance_name'] = info['allianceName'] else: new_entry['alliance_id'] = None new_entry['alliance_name'] = None # set some defaults new_entry['skill_training_id'] = 'Unknown' new_entry['skill_training_level'] = 'Unknown' new_entry['skill_training'] = 'Unknown' new_entry['skill_finish'] = 'Unknown' new_entry['location'] = 'Unknown' new_entry['esi_token_valid'] = False # determine token status. everything past this requires a live token token = info.get('esiAccessToken') if token == None: new_entry['esi_token'] = False new_entry['esi_token_valid'] = False else: new_entry['esi_token'] = True if token == None: # we're done with this char return new_entry else: # valid token. check scopes. result = check_scope(alt_charid, scope) # the default is already 'false' if result: new_entry['esi_token_valid'] = True # we'll let the token scope status fall where it may and try to get other details # fetch skill queue if check_scope(alt_charid, ['esi-skills.read_skillqueue.v1']): request_url = 'characters/' + str(alt_charid) + '/skillqueue/' code, result = esi(__name__, request_url, 'get', charid=alt_charid, version='v2') _logger.log('[' + __name__ + '] /characters output: {}'.format(result), _logger.LogLevel.DEBUG) if not code == 200: _logger.log( '[' + __name__ + '] /characters skillqueue API error {0}: {1}'.format( code, result['error']), _logger.LogLevel.ERROR) skill_training_id = None if len(result) == 0: skill_training_id = None current_skill = None if len(result) > 0: try: current_skill = result[0] except Exception as e: skill_training_id = None current_skill = None if not current_skill == None: new_entry['skill_training_id'] = current_skill['skill_id'] new_entry['skill_training_level'] = current_skill['finished_level'] try: new_entry['skill_finish'] = current_skill['finish_date'] except Exception as e: new_entry['skill_finish'] = 'N/A' skill_training_id = current_skill['skill_id'] if not skill_training_id == None: # map the skill id to a name request_url = 'universe/names/' data = '[{}]'.format(skill_training_id) code, result = esi(__name__, request_url, data=data, method='post', version='v2') _logger.log( '[' + __name__ + '] /universe output: {}'.format(result), _logger.LogLevel.DEBUG) if not code == 200: _logger.log( '[' + __name__ + '] /universe API error {0}: {1}'.format( code, result['error']), _logger.LogLevel.ERROR) new_entry['skill_training'] = 'Unknown' else: new_entry['skill_training'] = result[0]['name'] else: pass # fetch alt location if check_scope(alt_charid, ['esi-location.read_location.v1']): request_url = 'characters/{0}/location/'.format(alt_charid) code, result = esi(__name__, request_url, method='get', charid=alt_charid, version='v1') _logger.log('[' + __name__ + '] /characters output: {}'.format(result), _logger.LogLevel.DEBUG) if not code == 200: _logger.log( '[' + __name__ + '] /characters location API error {0}: {1}'.format( code, result['error']), _logger.LogLevel.ERROR) location = None else: location = result['solar_system_id'] new_entry['location_id'] = location # map the location to a name if location == None: new_entry['location'] = 'Unknown' else: request_url = 'universe/systems/{0}/'.format(location) code, result = esi(__name__, request_url, 'get', version='v4') if not code == 200: _logger.log( '[' + __name__ + '] /universe/systems API error ' + str(code) + ': ' + str(data['error']), _logger.LogLevel.INFO) new_entry['location'] = 'Unknown' else: new_entry['location'] = result['name'] else: new_entry['location'] = 'Unknown' return new_entry
def char_location(charid): # check if location scope is available test_scopes = ['esi-location.read_online.v1'] result = check_scope(charid, test_scopes) if not result: # does not have proper scopes msg = 'character {0} missing ESI scopes: {1}'.format(charid, result) _logger.log('[' + __name__ + '] ' + msg, _logger.LogLevel.WARNING) return False, None # fetch character location request_url = 'characters/{0}/location/'.format(charid) code, result = common.request_esi.esi(__name__, request_url, method='get', charid=charid, version='v1') _logger.log('[' + __name__ + '] /characters output: {}'.format(result), _logger.LogLevel.DEBUG) if not code == 200: _logger.log( '[' + __name__ + '] /characters location API error {0}: {1}'.format(code, result), _logger.LogLevel.WARNING) return False, None location_id = result.get('solar_system_id') structure_id = result.get('structure_id') station_id = result.get('station_id') # map the solar system to a name location_info = solar_system_info(location_id) location_name = location_info.get('solar_system_name') # map the structure to a name if structure_id is not None: # resolve a structure name request_url = 'universe/structures/{}/'.format(structure_id) code, result = common.request_esi.esi(__name__, request_url, method='get', version='v2', charid=charid) _logger.log( '[' + __name__ + '] /universe/structures output: {}'.format(result), _logger.LogLevel.DEBUG) if code == 200: structure_name = result['name'] elif code == 403: # unable to resolve structure name if the character has no ACL structure_name = 'UNAUTHORIZED STRUCTURE' else: _logger.log( '[' + __name__ + '] /universe/structures API error {0}: {1}'.format( code, result), _logger.LogLevel.WARNING) structure_name = 'Unknown' if station_id is not None: request_url = 'universe/names/' data = '[{}]'.format(station_id) code, result = common.request_esi.esi(__name__, request_url, method='post', version='v2', data=data) _logger.log( '[' + __name__ + '] /universe/structures output: {}'.format(result), _logger.LogLevel.DEBUG) if code == 200: structure_name = result[0]['name'] else: print(station_id) print(result) _logger.log( '[' + __name__ + '] /universe/structures API error {0}: {1}'.format( code, result), _logger.LogLevel.WARNING) structure_name = 'Unknown' else: structure_name = None char_location = dict() char_location['location_id'] = location_id char_location['location'] = location_name char_location['structure_id'] = structure_id char_location['structure_name'] = structure_name char_location['station_id'] = station_id return True, char_location
def auth_evesso_callback(): logger = getlogger('core.sso.callback') client_id = _eve.client_id client_secret = _eve.client_secret redirect_url = _eve.redirect_url base_url = 'https://login.eveonline.com' token_url = base_url + '/v2/oauth/token' # the user has (ostensibly) authenticated with the application, now # the access token can be fetched altof = session.get('altof') isalt = session.get('isalt') tempblue = session.get('tempblue') renter = session.get('renter') state = session.get('oauth2_state') ipaddress = request.headers['X-Real-Ip'] # security logging if isalt == True: detail = 'alt of {}'.format(altof) auth_scopes = scope elif tempblue == True: detail = 'temp blue' # make sure we only check for the blue scope list auth_scopes = blue_scope elif renter == True: detail = 'renter' auth_scopes = renter_scope else: detail = None auth_scopes = scope action = 'SSO callback' securitylog(action=action, ipaddress=ipaddress, detail=detail) # handle oauth token manipulation oauth_session = OAuth2Session( client_id=client_id, state=state, redirect_uri=redirect_url, auto_refresh_kwargs={ 'client_id': client_id, 'client_secret': client_secret, }, auto_refresh_url=token_url, ) headers = {'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' } try: atoken = oauth_session.fetch_token( token_url, client_secret=client_secret, authorization_response=request.url, headers=headers, ) except Exception as error: msg = 'unable to fetch eve sso access token: {0}'.format(error) logger.error(msg) return('ERROR: ' + str(error)) access_token = atoken['access_token'] refresh_token = atoken['refresh_token'] expires_at = atoken['expires_at'] try: charid, charname, scopes = verify(access_token) except Exception as e: # this ought to never happen msg = 'unable to verify eve sso access token: {0}'.format(error) logger.error(msg) message = 'SORRY, internal error. Try again.' response = make_response(message) return response # full ESI affiliations affilliations = _esihelpers.esi_affiliations(charid) if affilliations.get('error'): msg = 'error in fetching affiliations for {0}: {1}'.format(charid, affilliations.get('error')) logger.error(msg) message = 'SORRY, internal error. Try again.' response = make_response(message) return response allianceid = affilliations.get('allianceid') alliancename = affilliations.get('alliancename') corpid = affilliations.get('corpid') # ldap, if any userinfo = _ldaphelpers.ldap_userinfo(charid) # get alt status, if any, from ldap if userinfo and not isalt: altof = userinfo.get('altOf') if altof is not None: isalt = True # what the f**k is going on # this is a check that _shouldnt_ trigger anymore if isalt: if altof == None or altof == 'None': msg = 'is an alt but altof = None? wtf. charid {0} altof {1} {2}'.format(charid, altof, type(altof)) logger.error(msg) msg = 'error in fetching alt information. please poke saeka.' response = make_response(msg) return response # fix authgroup to an empty array in case nothing if not userinfo: authgroups = [] else: authgroups = userinfo.get('authGroup') if authgroups is None: authgroups = [] # verify that the atoken we get actually has the correct scopes that we requested # just in case someone got cute and peeled some off. if not check_scope(charid, auth_scopes, atoken=access_token): # the user peeled something off the scope list. naughty. msg = 'user {0} modified scope list'.format(charid) logger.warning(msg) securitylog(action='core login scope modification', charid=charid, ipaddress=ipaddress) message = "Don't tinker with the scope list, please.<br>" message += "If you have an issue with it, talk to triumvirate leadership." response = make_response(message) return response else: # scopes validate msg = 'user {0} has expected scopes'.format(charid) logger.debug(msg) # register the user, store the tokens registeruser(charid, access_token, refresh_token, tempblue=tempblue, isalt=isalt, altof=altof, renter=renter) storetokens(charid, access_token, refresh_token, expires=expires_at) ## TESTS ## ## check affiliations and for bans # check to see if the user is banned if 'banned' in authgroups: # banned users not allowed under any conditions message = 'nope.avi' if isalt == True: msg = 'banned user {0} ({1}) tried to register alt {2}'.format(charid, charname, altof) logger.warning(msg) securitylog(action='banned user tried to register', charid=charid, ipaddress=ipaddress, detail='alt of {0}'.format(altof)) else: msg = 'banned user {0} ({1}) tried to register'.format(charid, charname) logger.warning(msg) securitylog(action='banned user tried to register', charid=charid, ipaddress=ipaddress) return make_response(message) # only tri & blues are allowed to use auth if allianceid not in vg_blues() and allianceid not in vg_alliances() and allianceid not in vg_renters(): if not isalt: # not an alt, not a blue. not a renter. go away. msg = 'please contact a recruiter if you are interested in joining triumvirate' logmsg = 'non-blue user {0} ({1}) tried to register'.format(charid, charname) logger.warning(logmsg) securitylog(action='non-blue user tried to register', charid=charid, ipaddress=ipaddress) return make_response(msg) else: # someone is registering a non-blue alt, nbd pass # make sure the temp blue endpoint not being used by tri proper if tempblue: # this is a tri blue, but not tri proper. # ...or at least ought to be. if allianceid in vg_alliances(): # naughty! but not worth logging msg = 'please use the other login endpoint. <br>' msg += 'this is a lower privileged one for blues <b>ONLY</b>' return make_response(msg) # is this a temp blue trying to login with the wrong endpoint? if allianceid in vg_blues(): if not tempblue: # no big deal. we got extra scopes for it. tempblue = True # the user has passed the various exclusions, gg # security logging action = 'SSO callback completed' detail = None if isalt == True: detail='alt of {0}'.format(altof) elif tempblue == True: detail='blue from {0}'.format(alliancename) elif renter == True: detail='renter from {0}'.format(alliancename) securitylog(action=action, charid=charid, ipaddress=ipaddress, detail=detail) expire_date = datetime.datetime.now() + datetime.timedelta(days=14) # build the cookie and construct the http response if isalt == True: # if the character being logged in is an alt, make a session for the main. if userinfo: # the alt is alredy registered. go to homepage. response = make_response(redirect('https://www.triumvirate.rocks')) else: # go to alt registration page to show update. response = make_response(redirect('https://www.triumvirate.rocks/altregistration')) cookie = _session.makesession(altof) msg = 'created session for user: {0} (alt of {1})'.format(charname, altof) logger.info(msg) else: # proceed normally otherwise response = make_response(redirect('https://www.triumvirate.rocks')) cookie = _session.makesession(charid) msg = 'created session for user: {0} (charid {1})'.format(charname, charid) logger.info(msg) response.set_cookie('tri_core', cookie, domain='.triumvirate.rocks', expires=expire_date) if cookie == False: # unable to construct session cookie msg = 'error in creating session cookie for user {0}'.format(charid) logger.error(msg) message = 'SORRY, internal error. Try again.' return make_response(message) # handle registered users if userinfo is not None: # already in ldap, and not banned action = 'core login' if isalt: # is a registered alt msg = 'alt user {0} (alt of {1}) already registered'.format(charname, altof) logger.info(msg) securitylog(action=action, charid=charid, ipaddress=ipaddress, detail='via alt {0}'.format(altof)) code, result = _ldaphelpers.ldap_altupdate(__name__, altof, charid) return response else: if tempblue: # registered blue main. msg = 'user {0} ({1}) already registered'.format(charid, charname) logger.info(msg) securitylog(action=action, charid=charid, ipaddress=ipaddress, detail='blue from {0}'.format(alliancename)) code, result = _ldaphelpers.ldap_altupdate(__name__, altof, charid) return response else: # registered character msg = 'user {0} ({1}) already registered'.format(charid, charname) logger.info(msg) securitylog(action=action, charid=charid, ipaddress=ipaddress) code, result = _ldaphelpers.ldap_altupdate(__name__, altof, charid) return response # after this point, the only folks that are left are unregistered users # handle new temp blues if tempblue: msg = 'user {0} ({1}) not registered'.format(charid, charname) logger.info(msg) securitylog(action='core user registered', charid=charid, ipaddress=ipaddress, detail='blue from {0}'.format(alliancename)) return response # handle new renters if renter: msg = 'user {0} ({1}) not registered'.format(charid, charname) logger.info(msg) securitylog(action='core user registered', charid=charid, ipaddress=ipaddress, detail='renter from {0}'.format(alliancename)) return response # handle new alts if isalt: msg = 'alt user {0} (alt of {1}) not registered'.format(charname, altof) logger.info(msg) securitylog(action='alt user registered', charid=charid, ipaddress=ipaddress, detail='alt of {0}'.format(altof)) return response else: msg = 'user {0} ({1}) not registered'.format(charid, charname) logger.info(msg) securitylog(action='core user registered', charid=charid, ipaddress=ipaddress) return response