# Generated by Django 4.2.13 on 2024-07-18 11:08

from io import BytesIO
from pathlib import Path

from django.core.files import File
from django.db import migrations

from simple_certmanager.utils import (
    BadPassword,
    KeyIsNotEncrypted,
    decrypted_key_to_pem,
    load_pem_x509_private_key,
)


def decrypt_encrypted_keys(apps, _):
    DigiDConfiguration = apps.get_model("digid_eherkenning", "DigiDConfiguration")
    EherkenningConfiguration = apps.get_model(
        "digid_eherkenning", "EherkenningConfiguration"
    )

    for model in (DigiDConfiguration, EherkenningConfiguration):
        config = model.objects.first()

        # check if there is something to decrypt in the first place
        if (
            # no configuration record exists
            config is None
            # key is not encrypted (or we don't have the passphrase to decrypt it)
            or not (pw := config.key_passphrase)
            or not (cert := config.certificate)
            # no private key file is uploaded
            or not (privkey := cert.private_key)
            # or the DB thinks there is a file but it's not actually there (anymore)
            or not privkey.storage.exists(privkey.name)
        ):
            continue

        with privkey.open("rb") as keyfile:
            try:
                key = load_pem_x509_private_key(keyfile.read(), password=pw)
            # key material + passphrase set up are not in a consistent state, this would
            # also affect runtime behaviour, but we opt to make our migration robust.
            except (KeyIsNotEncrypted, BadPassword):
                continue

        decrypted_data = decrypted_key_to_pem(key)
        # replace existing data
        existing_name = Path(privkey.name).name  # strip nested directories of the name
        privkey.save(name=existing_name, content=File(BytesIO(decrypted_data)))


class Migration(migrations.Migration):

    dependencies = [
        ("digid_eherkenning", "0008_update_loa_fields"),
    ]

    operations = [
        # we cannot reverse it since we may not know the encryption key anymore
        migrations.RunPython(decrypt_encrypted_keys, migrations.RunPython.noop),
    ]
