Exemple #1
0
 def as_str(self) -> str:
     try:
         b = bitpacking.pack_value(self)
         b += bytes([single_byte_hash(b)])
         return base64.b64encode(b).decode("utf-8")
     except ValueError as e:
         return "Unable to create Permalink: {}".format(e)
Exemple #2
0
 def as_str(self) -> str:
     cached_result = object.__getattribute__(self, "__cached_as_str")
     if cached_result is not None:
         return cached_result
     try:
         b = bitpacking.pack_value(self)
         b += bytes([single_byte_hash(b)])
         result = base64.b64encode(b).decode("utf-8")
         object.__setattr__(self, "__cached_as_str", result)
         return result
     except ValueError as e:
         return "Unable to create Permalink: {}".format(e)
Exemple #3
0
    def from_bytes(cls, b: bytes) -> "Permalink":
        Permalink.validate_version(b)

        byte_hash = b[-1]
        new_bytes = [b[0]]
        new_bytes.extend(rotate_bytes(b[1:-1], byte_hash, byte_hash, inverse=True))

        decoded = bytes(new_bytes)
        if single_byte_hash(decoded) != byte_hash:
            raise ValueError("Incorrect checksum")

        decoder = BitPackDecoder(decoded)
        return Permalink.bit_pack_unpack(decoder, {})
Exemple #4
0
    def from_str(cls, param: str) -> "Permalink":
        try:
            b = base64.b64decode(param.encode("utf-8"), validate=True)
            if len(b) < 2:
                raise ValueError("Data too small")

            decoder = BitPackDecoder(b)
            Permalink.validate_version(decoder)

            checksum = single_byte_hash(b[:-1])
            if checksum != b[-1]:
                raise ValueError("Incorrect checksum")

            return Permalink.bit_pack_unpack(decoder)

        except binascii.Error as e:
            raise ValueError("Unable to base64 decode: {}".format(e))
Exemple #5
0
    def as_bytes(self) -> bytes:
        cached_result = object.__getattribute__(self, "__cached_as_bytes")
        if cached_result is not None:
            return cached_result

        encoded = bitpacking.pack_value(self)
        # Add extra bytes so the base64 encoding never uses == at the end
        encoded += b"\x00" * (3 - (len(encoded) + 1) % 3)

        # Rotate bytes, so the slightest change causes a cascading effect.
        # But skip the first byte so the version check can be done early in decoding.
        byte_hash = single_byte_hash(encoded)
        new_bytes = [encoded[0]]
        new_bytes.extend(rotate_bytes(encoded[1:], byte_hash, byte_hash, inverse=False))

        # Append the hash, so the rotation can be reversed and the checksum verified
        new_bytes.append(byte_hash)

        result = bytes(new_bytes)
        object.__setattr__(self, "__cached_as_bytes", result)
        return result
Exemple #6
0
def _dictionary_byte_hash(data: dict) -> int:
    return single_byte_hash(json.dumps(data, separators=(',', ':')).encode("UTF-8"))
Exemple #7
0
                     inverse))


PermalinkBinary = construct.FocusedSeq(
    "fields",
    schema_version=construct.Const(_CURRENT_SCHEMA_VERSION, construct.Byte),
    fields=construct.RawCopy(
        construct.Aligned(
            3,
            construct.Struct(
                header=construct.BitStruct(
                    has_seed_hash=construct.Rebuild(
                        construct.Flag, construct.this._.seed_hash != None),
                    bytes_rotation=construct.Rebuild(
                        construct.BitsInteger(7),
                        lambda ctx: single_byte_hash(ctx._.generator_params) >>
                        1,
                    )),
                seed_hash=construct.If(construct.this.header.has_seed_hash,
                                       construct.Bytes(5)),
                randovania_version=construct.Bytes(4),  # short git hash
                generator_params=construct.ExprAdapter(
                    construct.Prefixed(construct.VarInt,
                                       construct.GreedyBytes),
                    # parsing
                    decoder=create_rotator(inverse=True),
                    # building
                    encoder=create_rotator(inverse=False),
                ),
            ))),
    permalink_checksum=construct.Checksum(
Exemple #8
0
def _game_db_hash(game: RandovaniaGame) -> int:
    data = default_data.read_json_then_binary(game)[1]
    return bitpacking.single_byte_hash(json.dumps(data, separators=(',', ':')).encode("UTF-8"))