1import os 2 3from django.conf import settings 4from django.core.management.base import BaseCommand, CommandError 5from termcolor import colored as coloured 6 7from documents.models import Document 8from paperless.db import GnuPG 9 10 11class Command(BaseCommand): 12 13 help = ( 14 "This is how you migrate your stored documents from an encrypted " 15 "state to an unencrypted one (or vice-versa)" 16 ) 17 18 def add_arguments(self, parser): 19 20 parser.add_argument( 21 "from", 22 choices=("gpg", "unencrypted"), 23 help="The state you want to change your documents from" 24 ) 25 parser.add_argument( 26 "to", 27 choices=("gpg", "unencrypted"), 28 help="The state you want to change your documents to" 29 ) 30 parser.add_argument( 31 "--passphrase", 32 help="If PAPERLESS_PASSPHRASE isn't set already, you need to " 33 "specify it here" 34 ) 35 36 def handle(self, *args, **options): 37 38 try: 39 print(coloured( 40 "\n\nWARNING: This script is going to work directly on your " 41 "document originals, so\nWARNING: you probably shouldn't run " 42 "this unless you've got a recent backup\nWARNING: handy. It " 43 "*should* work without a hitch, but be safe and backup your\n" 44 "WARNING: stuff first.\n\nHit Ctrl+C to exit now, or Enter to " 45 "continue.\n\n", 46 "yellow", 47 attrs=("bold",) 48 )) 49 __ = input() 50 except KeyboardInterrupt: 51 return 52 53 if options["from"] == options["to"]: 54 raise CommandError( 55 'The "from" and "to" values can\'t be the same.' 56 ) 57 58 passphrase = options["passphrase"] or settings.PASSPHRASE 59 if not passphrase: 60 raise CommandError( 61 "Passphrase not defined. Please set it with --passphrase or " 62 "by declaring it in your environment or your config." 63 ) 64 65 if options["from"] == "gpg" and options["to"] == "unencrypted": 66 self.__gpg_to_unencrypted(passphrase) 67 elif options["from"] == "unencrypted" and options["to"] == "gpg": 68 self.__unencrypted_to_gpg(passphrase) 69 70 @staticmethod 71 def __gpg_to_unencrypted(passphrase): 72 73 encrypted_files = Document.objects.filter( 74 storage_type=Document.STORAGE_TYPE_GPG) 75 76 for document in encrypted_files: 77 78 print(coloured("Decrypting {}".format(document), "green")) 79 80 old_paths = [document.source_path, document.thumbnail_path] 81 raw_document = GnuPG.decrypted(document.source_file, passphrase) 82 raw_thumb = GnuPG.decrypted(document.thumbnail_file, passphrase) 83 84 document.storage_type = Document.STORAGE_TYPE_UNENCRYPTED 85 86 with open(document.source_path, "wb") as f: 87 f.write(raw_document) 88 89 with open(document.thumbnail_path, "wb") as f: 90 f.write(raw_thumb) 91 92 document.save(update_fields=("storage_type",)) 93 94 for path in old_paths: 95 os.unlink(path) 96 97 @staticmethod 98 def __unencrypted_to_gpg(passphrase): 99 100 unencrypted_files = Document.objects.filter( 101 storage_type=Document.STORAGE_TYPE_UNENCRYPTED) 102 103 for document in unencrypted_files: 104 105 print(coloured("Encrypting {}".format(document), "green")) 106 107 old_paths = [document.source_path, document.thumbnail_path] 108 with open(document.source_path, "rb") as raw_document: 109 with open(document.thumbnail_path, "rb") as raw_thumb: 110 document.storage_type = Document.STORAGE_TYPE_GPG 111 with open(document.source_path, "wb") as f: 112 f.write(GnuPG.encrypted(raw_document, passphrase)) 113 with open(document.thumbnail_path, "wb") as f: 114 f.write(GnuPG.encrypted(raw_thumb, passphrase)) 115 116 document.save(update_fields=("storage_type",)) 117 118 for path in old_paths: 119 os.unlink(path) 120