示例#1
0
文件: main.py 项目: killbus/SamFetch
async def get_binary_details(region: str, model: str, firmware: str):
    """
    Gets the binary details such as filename and decrypt key.\n
    `firmware` is the firmware code of the device that you got from `/latest` endpoint.\n\n
    `decrypt_key` is used for decrypting the file after downloading. It presents a hex string. Pass it to `/download` endpoint.
    """
    # Create new session.
    key = Session.from_response(
        requests.post(Constants.NONCE_URL, headers=Constants.HEADERS()))
    # Make the request.
    req = requests.post(url=Constants.BINARY_INFO_URL,
                        data=Constants.BINARY_INFO(firmware, region, model,
                                                   key.logic_check(firmware)),
                        headers=Constants.HEADERS(key.encrypted_nonce,
                                                  key.auth),
                        cookies=Constants.COOKIES(key.session_id))
    # Read the request.
    if req.status_code == 200:
        data = KiesData(req.text)
        # Return error when binary couldn't be found.
        if data.status_code != "200":
            raise HTTPException(400, "Firmware couldn't be found.")
        # If file extension ends with .enc4 that means it is using version 4 encryption, otherwise 2 (.enc2).
        ENCRYPT_VERSION = 4 if str(
            data.body["BINARY_NAME"]).endswith("4") else 2
        # Get binary details
        return {
            "display_name": data.body["DEVICE_MODEL_DISPLAYNAME"],
            "size": int(data.body["BINARY_BYTE_SIZE"]),
            "filename": data.body["BINARY_NAME"],
            "path": data.body["MODEL_PATH"],
            "version": data.body["CURRENT_OS_VERSION"].replace("(", " ("),
            "encrypt_version": ENCRYPT_VERSION,
            # Convert bytes to GB, so it will be more readable for an end-user.
            "size_readable": "{:.2f} GB".format(float(data.body["BINARY_BYTE_SIZE"]) / 1024 / 1024 / 1024),
            # Generate decrypted key for decrypting the file after downloading.
            # Decrypt key gives a list of bytes, but as it is not possible to send as query parameter,
            # we are converting it to a single HEX value.
            "decrypt_key": \
                key.getv2key(firmware, model, region).hex() if ENCRYPT_VERSION == 2 else \
                key.getv4key(data.body["LATEST_FW_VERSION"], data.body["LOGIC_VALUE_FACTORY"]).hex(),
            # A URL of samsungmobile that includes release changelogs.
            # Not available for every device.
            "firmware_changelog_url": data.body["DESCRIPTION"],
            "platform": data.body["DEVICE_PLATFORM"]
        }
    # Raise HTTPException when status is not 200.
    raise HTTPException(
        500, "Something went wrong when sending request to Kies servers.")
示例#2
0
文件: main.py 项目: killbus/SamFetch
async def download_binary(filename: str, path: str, decrypt_key: str,
                          request: Request):
    """
    Downloads the firmware and decrypts the file during download automatically.\n
    **Do not try the endpoint in the interactive API docs, because as it returns a file, it doesn't work in OpenAPI.** 
    """
    # Create new session.
    key = Session.from_response(
        requests.post(Constants.NONCE_URL, headers=Constants.HEADERS()))
    # Make the request.
    req = requests.post(url=Constants.BINARY_FILE_URL,
                        data=Constants.BINARY_FILE(
                            filename,
                            key.logic_check(filename.split(".")[0][-16:])),
                        headers=Constants.HEADERS(key.encrypted_nonce,
                                                  key.auth),
                        cookies=Constants.COOKIES(key.session_id))
    # Refresh session.
    key.refresh_session(req)
    # Read the request.
    if req.status_code == 200:
        data = KiesData(req.text)
        # Return error when binary couldn't be found.
        if data.status_code != "200":
            raise HTTPException(
                int(data.status_code),
                f"The service returned {data.status_code}. Maybe parameters are invalid?"
            )
        # Else, make another request to get the binary.
        else:
            # Check and parse the range header.
            START_RANGE, END_RANGE = (
                0, 0
            ) if "Range" not in request.headers else Constants.parse_range_header(
                request.headers["Range"])
            # Check if range is invalid.
            if START_RANGE == -1 or END_RANGE == -1:
                raise HTTPException(
                    416,
                    "Range is invalid. If you didn't meant input a 'Range' header, remove it from request."
                )
            # Create headers.
            _headers = Constants.HEADERS(key.encrypted_nonce, key.auth)
            # If incoming request contains a Range header, directly pass it to request.
            if "Range" in _headers:
                _headers["Range"] = "bytes=" + Constants.make_range_header(
                    START_RANGE, END_RANGE)
            # Another request for streaming the firmware.
            req2 = requests.get(url=Constants.BINARY_DOWNLOAD_URL,
                                params="file=" + path + filename,
                                headers=_headers,
                                cookies=Constants.COOKIES(key.session_id),
                                stream=True)
            # Check if status code is not 200 or 206.
            if req2.status_code not in [200, 206]:
                # Raise HTTPException when status is not success.
                raise HTTPException(
                    req2.status_code,
                    f"The service returned {req2.status_code}. Maybe parameters are invalid?"
                )
            # Get the total size of binary.
            CONTENT_LENGTH = int(req2.headers["Content-Length"])
            # Decrypt bytes while downloading the file.
            # So this way, we can directly serve the bytes to the client without downloading to the disk.
            return StreamingResponse(
                Decryptor(req2, bytes.fromhex(decrypt_key)),
                media_type="application/zip",
                headers={
                    "Content-Disposition":
                    "attachment;filename=" +
                    filename.replace(".enc4", "").replace(".enc2", ""),
                    "Content-Length":
                    str(CONTENT_LENGTH),
                    "Accept-Ranges":
                    "bytes",
                    "Content-Range":
                    f"bytes {Constants.make_range_header(START_RANGE, END_RANGE)}"
                },
                status_code=200 if not START_RANGE else 206)
    # Raise HTTPException when status is not 200.
    raise HTTPException(
        500, "Something went wrong when sending request to Kies servers.")