예제 #1
0
def character_knife():
    """Start a new knife run for a character."""

    if "access_token" in request.args and "state" in request.args:
        # verify token/start knife process for character
        # do this all out of band, we might be error limited right now
        if CACHE.get("authstate.{}".format(request.args["state"])):
            CACHE.delete("authstate.{}".format(request.args["state"]))
            token = uuid.uuid4()
            CACHE.set("new.{}".format(token), request.args["access_token"])
            return redirect("/view/{}/".format(token))

    # start sso flow
    state = uuid.uuid4()
    CACHE.set("authstate.{}".format(state), "1", timeout=300)

    return redirect(
        ("https://login.eveonline.com/oauth/authorize?response_type=token"
         "&redirect_uri={callback}&client_id={client}"
         "&scope={scopes}&state={state}").format(
             callback=CALLBACK_URL,
             client=CLIENT_ID,
             scopes=SCOPES,
             state=state,
         ))
예제 #2
0
def rate_limit():
    """Apply a rate limit."""

    key = "".join((Keys.rate_limit.value, get_ip()))
    reqs = CACHE.get(key) or 0
    if reqs >= 20:
        return True

    CACHE.set(key, reqs + 1, timeout=60)
    return False
예제 #3
0
def process_new():
    """Process all new tokens, verify or we're done early."""

    for new_key in utils.list_keys(Keys.new.value):
        uuid = new_key.split(".")[-1]
        LOG.warning("processing new uuid: %r", uuid)

        token = CACHE.get(new_key)
        CACHE.delete(new_key)

        if not token:
            LOG.warning("no token stored for uuid: %r", uuid)
            continue

        pending_key = "{}{}".format(Keys.pending.value, uuid)
        CACHE.set(
            pending_key,
            "1",
            timeout=70,
        )
        headers = {"Authorization": "Bearer {}".format(token)}
        _, res = utils.request_or_wait(
            "{}/verify/".format(ESI),
            headers=headers,
        )

        failed = False
        if isinstance(res, str) or "CharacterID" not in res:
            utils.write_data(uuid, {"auth failure": res})
            failed = True
        else:
            _, roles = utils.request_or_wait(
                "{}/latest/characters/{}/roles/".format(
                    ESI,
                    res["CharacterID"],
                ),
                headers=headers,
            )
            if isinstance(roles, str):
                utils.write_data(uuid, {"roles failure": roles})
                failed = True

        CACHE.delete(pending_key)

        if not failed:
            CACHE.set(
                "{}{}".format(Keys.processing.value, uuid),
                res["CharacterID"],
                timeout=7200,
            )

            WORKERS.append(
                gevent.spawn(knife, uuid, token, res, roles)
            )
예제 #4
0
def metrics_index():
    """Display some metrics."""

    return render_template(
        "metrics.html",
        new=len(utils.list_keys(Keys.new.value)),
        pending=len(utils.list_keys(Keys.pending.value)),
        processing=len(utils.list_keys(Keys.processing.value)),
        completed=len(utils.list_keys(Keys.complete.value)),
        alltime=CACHE.get(Keys.alltime.value) or 0,
        worker=not APP.knife_worker.dead,
        error_limited=APP.error_limited,
        now=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
    )
예제 #5
0
def refresh_spec():
    """Refresh the ESI spec.

    Returns:
        dictionary: JSON loaded swagger spec
    """

    try:
        spec_details = CACHE.get(Keys.spec.value)
    except redis.exceptions.ConnectionError:
        spec_details = None
        save_results = False
    else:
        save_results = True

    if spec_details is None:
        spec_details = {"timestamp": 0}

    if time.time() - spec_details["timestamp"] > 300:
        headers = {}
        if spec_details.get("etag"):
            headers["If-None-Match"] = spec_details["etag"]

        _, _, res = request_or_wait(
            "{}/latest/swagger.json".format(ESI),
            _as_res=True,
            headers=headers,
        )

        if isinstance(res, str):
            LOG.warning("failed to refresh spec: %s", res)
            return spec_details.get("spec", {})

        spec_details["timestamp"] = time.time()

        if res.status_code != 304:
            spec_details["etag"] = res.headers.get("ETag")
            spec_details["spec"] = JsonDeref().deref(res.json())

        if save_results:
            CACHE.set(Keys.spec.value, spec_details, timeout=3600)

    return spec_details["spec"]
예제 #6
0
def get_data(uuid):
    """Open and return the character's data."""

    cache_key = "{}{}".format(Keys.complete.value, uuid)
    try:
        content = CACHE.get(cache_key)
    except Exception as error:
        LOG.warning("failed to get %s: %r", cache_key, error)
    else:
        if content is None:
            return None

        try:
            return ujson.loads(gzip.decompress(base64.b64decode(content)))
        except Exception as error:
            LOG.warning("failed to decode %s: %r", content, error)
        else:
            CACHE.cache._client.expire(  # pylint: disable=protected-access
                cache_key,
                EXPIRY,
            )

    return None