Open1

google firebaseとか

tomozosantomozosan

Google Cloud Storageのmd5 hashについて

自分の手元のファイルとhashが一致するのか確かめたいときどうするのか?

結構ややこしいぞ.

  • Cloud Storageのオブジェクトのmd5_hash属性はbase64 encode されている

MD5 hash of the data, encoded using base64. This field is not present for composite objects. For more information about using the MD5 hash, see Hashes and ETags: Best Practices. 
参考

結論: binascii.hexlify(base64.urlsafe_b64decode(blob.md5_hash)).decode("utf-8")
を利用する(手元のhex_digest()した値との比較方法).

pythonで hex_digestしたmd5と比較するには結構めんどい処理が必要.

import base64
import hashlib


def generate_md5(file_path: Path | str, chunk_size=1024) -> str:
    """手元のファイルのmd5_hashを計算する関数
    ファイルの内容を少しずつ読み込んでmd5ハッシュを生成する
    :param file_path: ファイルパス
    :param chunk_size: ファイルを読み込むバイト数
    :return: md5ハッシュ
    """
    md5_hash = hashlib.md5()

    def read_chunk(file: BinaryIO):
        _chunk = file.read(chunk_size)
        # ファイルの終端に到達したら b''を返すが, iter()の第2引数で明示的にNoneを返すようにするため.
        return _chunk if _chunk else None

    with open(file_path, "rb") as f:
        for chunk in iter(lambda: read_chunk(f), None):
            md5_hash.update(chunk)
    return md5_hash.hexdigest()

Firebaseのpython sdkを利用した例

from firebase_admin import credentials
from firebase_admin import storage
from firebase_admin import App
from google.cloud.storage import Blob

def initialize_firebase_admin(
    account_key_json_file: str | Path,
) -> App:
    cred = credentials.Certificate(account_key_json_file)
    app = firebase_admin.initialize_app(cred)
    return app

def get_blob(bucket_name: str,  blob_name: str,  app: App) -> Optional[Blob]:
    bucket = storage.bucket(bucket_name, app=app)
    blob = bucket.get_blob(blob_name=blob_name)
    if blob is None:
        print(f"Blob is not found.{blob_name}")
         return
    return blob

def md5_hex_digest_from_blob(blob: Blob) -> str:
    return binascii.hexlify(base64.urlsafe_b64decode(blob.md5_hash)).decode("utf-8")

def test_myfile_match_with_gcs_blob():
    app = initialize_firebase_admin("secret.json")  # Firestore からjsonファイルダウンロードする.
    bucket_name = "my_bucket"
    blob_name = "gcs.jpeg"
    maybe_blob = get_blob(bucket_name, blob_name, app)
    if maybe_blob is None:
       return
    md5_gcs = md5_hex_digest_from_blob(maybe_blob)
    
    my_file = "input.jpeg"
    local_md5 = generate_md5(my_file)
    assert md5_gcs == local_md5