Python script to reveal an unlocked file for encrypted files in a vault (and vice versa!)

Update: It works in both directions now :star_struck: For more info, see my new Github repository

Orginal Post:

Warning upfront: this post is only relevant for power users on Windows who know what they’re doing. I’m quite reluctant to guide non-programmers through the process of installing all prerequisites to run this script and deal with the consequences when something goes wrong. So: use at your own risk!

Background: after doing a sync between two PCs yesterday I got a sync error on an encrypted vault file. Apparently the file was modified on both PCs before the sync. To solve it, I’d need to know which decrypted file it represents, so I can inspect the file on both ends to fix the conflict manually.

However, since there is no way to map encrypted files in a vault to their decrypted file paths, that’s a dead stop in fixing such issues. I’ve been hit by this issue a couple of times in the past already. So far I resorted to a manual procedure to find out which file(s) were involved;

  • unlock the vault on one PC,
  • open a command prompt and write a recursive dir listing for the unlocked vault into a text file,
  • browse to the conflicting encrypted file in Cryptomator’s encrypted storage folder,
  • move the file over to e.g. the desktop,
  • re-do the dir listing to another text file,
  • restore the encrypted file back to it’s proper location,
  • diff the two dir listing text files to see which file is absent in one of them.

Quite a tedious procedure, especially since the dir command also lists the special ‘.’ and ‘…’ folder entries, but uses the current time as their time stamp. Since the two dir listing files are not created at exactly the same time, all these entries cause false positives in the diff. So for large vaults I also preprocessed the text files to strip out these lines with a regex.

And yesterday was the time I decided “enough is enough - this can be scripted”. So, see below the Python script that does this process for you. You need to have Python 3 installed with the win32com and wx packages. See the source code for the full instructions on how to use the script.

Edit: Script see GitHub Link

5 Likes

Thank you for that script.
Out of curiosity:
What you describe is a classic sync conflict that is usually treated by the storage provider by creating 2 files so one can check both files and decide which one to keep, or merge them.
According to this post, Cryptomator can detect this and should also show 2 unencrypted files so one can choose/merge.
Is this not working in your scenario?
Or did I get the purpose of your script wrong?

No, I don’t use Cryptomator in the classic sense with a single vault located directly in a cloud synced location. I instead use it to keep confidential data from my freelance projects safe from data theft by having them always in ‘cold storage’ until I need to work on a specific project, at which time I specifically unlock only that project’s vault. So all data is always encrypted 99% of the time, even on my own computer. But I also use it in that way to manage vaults with private data, and these vaults get cross-synced over the internal lan to other PCs in this household. And so I sometimes run into issues when some files get modified on more than one PC between syncs. Knowing which files are in conflict is then crucial to resolve the issue; hence the script :slight_smile:

But to come back to your link: that seems very useful in my situation! If I can augment the sync script to just keep both files but rename one of them instead of skipping them and issuing a conflict afterwards, I can then just do a search afterwards for files with the (Conflict …) indicator in their filename, which makes this script unnecessary.

1 Like

And I’m back :slight_smile: This time I needed the reverse of what the script does; I lost a single file and needed to restore it from backup, while not restoring the rest of the vault from backup too. Since the mechanism for revealing an encrypted file given a decrypted file is rather similar, I upgraded the script to be used in both directions.

I’ve also decided to host the new script on GitHub; that way this post won’t get overly long with inlined scripts, plus future updates will be at a known location. You can find it at Cryptomator-Vault-File-Revealer!

3 Likes

Hi @CarlColijn ,

Thanks for the great idea!!

I wrote another version of this idea if that can help (works on macos with python 3.10):

from pathlib import Path
from contextlib import contextmanager
from tempfile import TemporaryDirectory
import shutil

from tqdm import tqdm


@contextmanager
def temporary_move_file(path):
    with TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir) / path.name
        shutil.move(path, temp_path)
        yield
        shutil.move(temp_path, path)


def get_encrypted_path(unencrypted_path, encrypted_dir):
    """Given an unencrypted path, it will return the path to its encrypted version.

    `get_encrypted_path("my_unencrypted_file.txt", "my_encrypted_cryptomator_dir")`
    
    """
    unencrypted_path = Path(unencrypted_path)
    encrypted_dir = Path(encrypted_dir)
    original_encrypted_files = list(tqdm(encrypted_dir.rglob("*"), desc="Listing encrypted files"))
    with temporary_move_file(unencrypted_path):
        encrypted_files_with_file_removed = list(tqdm(encrypted_dir.rglob("*"), desc=f"Listing encrypted files with {unencrypted_path.name} removed"))
    [encrypted_path] = set(original_encrypted_files) - set(encrypted_files_with_file_removed)
    return encrypted_path
1 Like

Thanks for that! I didn’t find a use for tqdm since my script is GUI based and I try to avoid extra external modules, but I happily took over your use of pathlib.Path.rglob (didn’t know it existed) and a context manager instead of my try/finally.

For everyone interested: I took some time to upgrade the Python script a bit more and make it both more efficient and more user friendly. Credits go to my wife that found it too clunky to work with :slight_smile:

I’ve updated the script on GitHub for anyone interested; the inlined script in the OP is the old version, but I can’t edit that post anymore.

2 Likes

Hi. Thank you.
Don’t know why you cant edit your own post, but I deleted the old script in your post.
Your GitHub repository is linked anyway.