Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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