예제 #1
0
async def root_client(request: Request) -> bytes:
    start = time.time()
    headers = (
        request.headers
    )  # request headers, used for things such as user ip and agent

    if (
        "User-Agent" not in headers
        or headers["User-Agent"] != "osu!"
        or request.type == "GET"
    ):
        # request isn't sent from osu client, return html
        return root_web()

    if (
        "osu-token" not in headers
    ):  # sometimes a login request will be a re-connect attempt, in which case they will already have a token, if not: login the user
        data = (
            request.body
        )  # request data, used to get base_info such as username to login the user
        if (
            len(base_info := data.decode().split("\n")[:-1]) != 3
        ):  # format data so we can use it easier & also ensure it is valid at the same time
            request.resp_headers[
                "cho-token"
            ] = "no"  # client knows there is something up if we set token to 'no'
            return writer.userID(-2)

        if (
            len(cinfo := base_info[2].split("|")) != 5
        ):  # format client data (hash, utc etc.) & ensure it is valid
            request.resp_headers[
                "cho-token"
            ] = "no"  # client knows there is something up if we set token to 'no'
            return writer.userID(-2)
예제 #2
0
파일: avatars.py 프로젝트: cmyui/Asahi
async def avatar(req: Request, uid: str) -> bytes:
    user = ava_path / f'{uid}'
    if user.exists():
        req.resp_headers['Content-Type'] = 'image/png'
        return user.read_bytes()
    else:
        default = ava_path / 'default.png'
        req.resp_headers['Content-Type'] = 'image/png'
        return default.read_bytes()
예제 #3
0
파일: avatars.py 프로젝트: tsunyoku/Asahi
async def avatar(req: Request, uid: str) -> bytes:
    user = ava_path / f"{uid}"
    if user.exists():
        req.resp_headers["Content-Type"] = "image/png"
        return user.read_bytes()
    else:
        default = ava_path / "default.png"
        req.resp_headers["Content-Type"] = "image/png"
        return default.read_bytes()
예제 #4
0
파일: assets.py 프로젝트: cmyui/Asahi
async def ingameAchievements(request: Request,
                             medal: str) -> Union[tuple, bytes]:
    name = medal.split('.')[0]
    if name not in custom:
        request.resp_headers[
            'Location'] = f'https://assets.ppy.sh/medals/client/{medal}'  # redirect regular achievements
        return (301, b'')
    else:
        request.resp_headers['Content-Type'] = 'image/png'
        return (
            Path.cwd() /
            f'resources/achievements/{medal.replace("@2x", "")}').read_bytes()
예제 #5
0
파일: bancho.py 프로젝트: cmyui/Asahi
async def root_client(request: Request) -> bytes:
    start = time.time()
    headers = request.headers # request headers, used for things such as user ip and agent

    if 'User-Agent' not in headers or headers['User-Agent'] != 'osu!' or request.type == 'GET':
        # request isn't sent from osu client, return html
        return root_web()

    if 'osu-token' not in headers: # sometimes a login request will be a re-connect attempt, in which case they will already have a token, if not: login the user
        data = request.body # request data, used to get info such as username to login the user
        if len(info := data.decode().split('\n')[:-1]) != 3: # format data so we can use it easier & also ensure it is valid at the same time
            request.resp_headers['cho-token'] = 'no' # client knows there is something up if we set token to 'no'
            return writer.userID(-2)

        if len(cinfo := info[2].split('|')) != 5: # format client data (hash, utc etc.) & ensure it is valid
            request.resp_headers['cho-token'] = 'no' # client knows there is something up if we set token to 'no'
            return writer.userID(-2)
예제 #6
0
async def getScreenshot(request: Request, scr: str) -> bytes:
    ss = ss_path / scr
    _type = scr.split('.')[1]

    if ss.exists():
        ssb = ss.read_bytes()
        request.resp_headers['Content-Type'] = f'image/{_type}'
        return ssb
    else:
        return b'could not find screenshot'
예제 #7
0
async def getScreenshot(request: Request, scr: str) -> bytes:
    ss = ss_path / scr
    _type = scr.split(".")[1]

    if ss.exists():
        ssb = ss.read_bytes()
        request.resp_headers["Content-Type"] = f"image/{_type}"
        return ssb
    else:
        return b"could not find screenshot"
예제 #8
0
파일: avatars.py 프로젝트: cmyui/Asahi
async def default_avatar(req: Request) -> bytes:
    file = ava_path / 'default.png'

    req.resp_headers['Content-Type'] = 'image/png'
    return file.read_bytes()
예제 #9
0
async def mapDownload(request: Request, mid: str) -> tuple[int, bytes]:
    request.resp_headers['Location'] = f'{glob.config.map_api}/d/{mid}'
    return (301, b'')  # redirect
예제 #10
0
파일: api.py 프로젝트: tsunyoku/Asahi
async def getReplay(request: Request) -> Union[tuple, bytes]:
    args = request.args

    sid = int(args.get("id", 0))
    rx = int(args.get("rx", 0))

    if not sid:
        return (400, {"message": "please specify a score id!"})

    BASE_DIR = Path.cwd() / "resources"

    if not 0 <= rx < 3:
        return (400, {"message": "invalid relax value (must be 0, 1 or 2)"})

    if rx == 0:
        REPLAY_PATH = BASE_DIR / "replays"
        table = "scores"
    elif rx == 1:
        REPLAY_PATH = BASE_DIR / "replays_rx"
        table = "scores_rx"
    elif rx == 2:
        REPLAY_PATH = BASE_DIR / "replays_ap"
        table = "scores_ap"

    file = REPLAY_PATH / f"{sid}.osr"

    if not file.exists():
        return (
            400,
            {
                "message":
                "replay couldn't be found. please check the score id and try again!",
            },
        )

    raw_replay = file.read_bytes()

    # get score from sql
    score = await glob.db.fetchrow(
        f"SELECT t.*, t.mode m, users.name, maps.* FROM {table} t "
        "LEFT OUTER JOIN users ON users.id = t.uid LEFT OUTER JOIN maps ON maps.md5 = t.md5 WHERE t.id = %s",
        [sid],
    )

    # when im not lazy ill use Score.sql to get score object so we can implement rank and shit
    replay_hash = hashlib.md5(
        (f'{score["n100"] + score["n300"]}p{score["n50"]}o'
         f'{score["geki"]}o{score["katu"]}t'
         f'{score["miss"]}a{score["md5"]}r'
         f'{score["combo"]}e{score["fc"] == 1}y'
         f'{score["name"]}o{score["score"]}u'
         f'0{score["mods"]}True').encode(), ).hexdigest()

    buffer = bytearray()  # headers timeee

    # not all scores will have osuver so lets just send latest (as of this code) version
    buffer += struct.pack("<Bi", score["m"], score["osuver"] or 2021_05_20)
    buffer += writer.write_string(score["md5"])

    buffer += writer.write_string(score["name"])
    buffer += writer.write_string(replay_hash)

    buffer += struct.pack(
        "<hhhhhhihBi",
        score["n300"],
        score["n100"],
        score["n50"],
        score["geki"],
        score["katu"],
        score["miss"],
        score["score"],
        score["combo"],
        score["fc"],
        score["mods"],
    )

    buffer += b"\x00"  # graph probably NEVER

    buffer += struct.pack("<q", score["time"] * 1_000_000 + DATETIME_OFFSET)

    buffer += struct.pack("<i", len(raw_replay))
    buffer += raw_replay
    buffer += struct.pack("<q", sid)

    name = (
        f'{score["name"]} ~ {score["artist"]} - {score["title"]} [{score["diff"]}] '
        f'+{score["readable_mods"]} ({datetime.fromtimestamp(score["time"]):%Y/%m/%d})'
    )

    request.resp_headers["Content-Type"] = "application/octet-stream"
    request.resp_headers["Content-Description"] = "File Transfer"
    request.resp_headers[
        "Content-Disposition"] = f"attachment; filename={name}.osr"

    return bytes(buffer)
예제 #11
0
async def mapDownload(request: Request, mid: str) -> tuple[int, bytes]:
    request.resp_headers["Location"] = f"{glob.config.map_api}/d/{mid}"
    return (301, b"")  # redirect
예제 #12
0
파일: avatars.py 프로젝트: tsunyoku/Asahi
async def default_avatar(req: Request) -> bytes:
    file = ava_path / "default.png"

    req.resp_headers["Content-Type"] = "image/png"
    return file.read_bytes()