2025-01-06 21:12:27 +01:00
|
|
|
from pathlib import Path
|
2018-05-27 23:20:33 +01:00
|
|
|
|
|
|
|
|
from django.conf import settings
|
2022-03-11 10:55:51 -08:00
|
|
|
from django.core.management.base import BaseCommand
|
|
|
|
|
from django.core.management.base import CommandError
|
2023-04-20 08:10:17 -07:00
|
|
|
|
2018-05-27 23:20:33 +01:00
|
|
|
from documents.models import Document
|
|
|
|
|
from paperless.db import GnuPG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Command(BaseCommand):
|
|
|
|
|
help = (
|
|
|
|
|
"This is how you migrate your stored documents from an encrypted "
|
|
|
|
|
"state to an unencrypted one (or vice-versa)"
|
|
|
|
|
)
|
|
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
def add_arguments(self, parser) -> None:
|
2018-05-27 23:20:33 +01:00
|
|
|
parser.add_argument(
|
|
|
|
|
"--passphrase",
|
2023-11-09 11:46:37 -08:00
|
|
|
help=(
|
|
|
|
|
"If PAPERLESS_PASSPHRASE isn't set already, you need to "
|
|
|
|
|
"specify it here"
|
|
|
|
|
),
|
2018-05-27 23:20:33 +01:00
|
|
|
)
|
|
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
def handle(self, *args, **options) -> None:
|
2018-05-27 23:20:33 +01:00
|
|
|
try:
|
2023-11-09 11:46:37 -08:00
|
|
|
self.stdout.write(
|
|
|
|
|
self.style.WARNING(
|
|
|
|
|
"\n\n"
|
|
|
|
|
"WARNING: This script is going to work directly on your "
|
|
|
|
|
"document originals, so\n"
|
|
|
|
|
"WARNING: you probably shouldn't run "
|
|
|
|
|
"this unless you've got a recent backup\n"
|
|
|
|
|
"WARNING: handy. It "
|
|
|
|
|
"*should* work without a hitch, but be safe and backup your\n"
|
|
|
|
|
"WARNING: stuff first.\n\n"
|
|
|
|
|
"Hit Ctrl+C to exit now, or Enter to "
|
|
|
|
|
"continue.\n\n",
|
|
|
|
|
),
|
2020-12-16 19:50:38 +01:00
|
|
|
)
|
2022-03-11 10:55:51 -08:00
|
|
|
_ = input()
|
2018-05-27 23:20:33 +01:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
passphrase = options["passphrase"] or settings.PASSPHRASE
|
|
|
|
|
if not passphrase:
|
|
|
|
|
raise CommandError(
|
|
|
|
|
"Passphrase not defined. Please set it with --passphrase or "
|
2022-03-11 10:55:51 -08:00
|
|
|
"by declaring it in your environment or your config.",
|
2018-05-27 23:20:33 +01:00
|
|
|
)
|
|
|
|
|
|
2020-11-25 20:22:56 +01:00
|
|
|
self.__gpg_to_unencrypted(passphrase)
|
2018-05-27 23:20:33 +01:00
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
def __gpg_to_unencrypted(self, passphrase: str) -> None:
|
2018-05-27 23:20:33 +01:00
|
|
|
encrypted_files = Document.objects.filter(
|
2022-03-11 10:55:51 -08:00
|
|
|
storage_type=Document.STORAGE_TYPE_GPG,
|
2022-02-27 15:26:41 +01:00
|
|
|
)
|
2018-05-27 23:20:33 +01:00
|
|
|
|
|
|
|
|
for document in encrypted_files:
|
2023-11-09 11:46:37 -08:00
|
|
|
self.stdout.write(f"Decrypting {document}")
|
2018-05-27 23:20:33 +01:00
|
|
|
|
|
|
|
|
old_paths = [document.source_path, document.thumbnail_path]
|
2020-11-25 21:10:50 +01:00
|
|
|
|
2022-03-07 16:13:20 -08:00
|
|
|
with document.source_file as file_handle:
|
|
|
|
|
raw_document = GnuPG.decrypted(file_handle, passphrase)
|
|
|
|
|
with document.thumbnail_file as file_handle:
|
|
|
|
|
raw_thumb = GnuPG.decrypted(file_handle, passphrase)
|
2018-05-27 23:20:33 +01:00
|
|
|
|
|
|
|
|
document.storage_type = Document.STORAGE_TYPE_UNENCRYPTED
|
|
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
ext: str = Path(document.filename).suffix
|
2020-11-25 21:10:50 +01:00
|
|
|
|
2022-02-27 15:26:41 +01:00
|
|
|
if not ext == ".gpg":
|
2020-11-25 21:10:50 +01:00
|
|
|
raise CommandError(
|
|
|
|
|
f"Abort: encrypted file {document.source_path} does not "
|
2022-03-11 10:55:51 -08:00
|
|
|
f"end with .gpg",
|
2022-02-27 15:26:41 +01:00
|
|
|
)
|
2020-11-25 21:10:50 +01:00
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
document.filename = Path(document.filename).stem
|
2020-11-25 21:10:50 +01:00
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
with document.source_path.open("wb") as f:
|
2018-05-27 23:20:33 +01:00
|
|
|
f.write(raw_document)
|
|
|
|
|
|
2025-01-06 21:12:27 +01:00
|
|
|
with document.thumbnail_path.open("wb") as f:
|
2018-05-27 23:20:33 +01:00
|
|
|
f.write(raw_thumb)
|
|
|
|
|
|
2020-12-09 13:27:02 +01:00
|
|
|
Document.objects.filter(id=document.id).update(
|
2022-03-11 10:55:51 -08:00
|
|
|
storage_type=document.storage_type,
|
|
|
|
|
filename=document.filename,
|
2022-02-27 15:26:41 +01:00
|
|
|
)
|
2018-05-27 23:20:33 +01:00
|
|
|
|
|
|
|
|
for path in old_paths:
|
2025-01-06 21:12:27 +01:00
|
|
|
path.unlink()
|