Repository: freedomofpress/securedrop

Issue:
Tails 3.0 does not restore the original filename when uncompressing a file
# Bug

Tails 3.0 does not preserve the filename when extracting an archive.

## Description

When extracting an archive, Tails 3.0 will rename the file inside the archive to _data_.

## Steps to Reproduce

Download a SecureDrop submission, decrypt the submission and extract the archive.

## Expected Behavior

Tails should preserve the filename and leave you with, say, _code_name.pdf_.

## Actual Behavior

Tails 3.0 leaves you with a file called _data_ instead.

## Comments

I suspect this is an issue with Tails 3.0 and not the way SecureDrop creates the archive in the first place. Filing here just in case.


Discussion:
related to #1551 ? 
I'm not able to reproduce the problem, it would be great if you could confirm that you are able to correctly extract the archive with an older version of tails. Is this a [zip](https://en.wikipedia.org/wiki/Zip_(file_format)) archive that you extract with unzip ? (for the record tails 3.0 has unzip 6.0-21).
Try to reproduce using the following steps:

- Upload a .pdf to SecureDrop
- Download the encrypted submission
- Using Tails 3.0, double-click to decrypt and extract
- The resulting file will be named _data_

It appears this only happens if (1) the submission is an upload, **and** (2) the archive is extracted simply by double-clicking. We have been able to retain the filename with the steps below:

- Right click on the archive
- Select _Open With Other Application_
- Click _Select_ (the default, and only option, will be _Archive Manager_)
- Another window will appear where you can see a list of the files to be extracted
- Click _Extract_ in the top left corner

I was able to reproduce the behavior described. I don't think it's a Tails issue necessarily, but rather a SecureDrop one.

If you run `gpg --decrypt --verbose` on a single-document submission (plz redirect STDOUT), it shows that the original filename is just a blank string. This is perhaps expected, because the contents are always going to be a gzip archive named by the source codename. It's that archive which should have the original named file within it. In the function [save_file_submission()](https://github.com/freedomofpress/securedrop/blob/develop/securedrop/store.py#L96-L128), there is a comment which explains that gzip is explicitly being used for this purpose of preserving the filename (and due to Tor slowness).

It is not working though... While the filename is supposed to be "sanitized" by passing it through Werkzeug's [secure_filename](http://werkzeug.pocoo.org/docs/0.12/utils/#werkzeug.utils.secure_filename), in practice this does not alter it. It seems like the original filename is being lost somewhere within either `SecureTemporaryFile()` or `gzip.GzipFile()`.

Normally, in both symmetric and regular modes, GnuPG is able to retain the original filename by using the `--set-filename` option (see the manual... `--use-embedded-filename` per decryption), which would eliminate one of the justifications for using gzip. However, this option is unfortunately not implemented by the python-gnupg library.
> If you run gpg --decrypt --verbose on a single-document submission (plz redirect STDOUT), it shows that the original filename is just a blank string. This is perhaps expected, because the contents are always going to be a gzip archive named by the source codename. It's that archive which should have the original named file within it. In the function save_file_submission(), there is a comment which explains that gzip is explicitly being used for this purpose of preserving the filename (and due to Tor slowness).

So anytime you encrypt anything with GPG that filename field will be a null string unless you use the `--set-filename <string>` option. This is not specific to the fact we're encrypting a compressed file. Note: `save_file_submission()` and `gzip` both compress files, they do not compress archives; archives are created by tools like `tar`, which supports transparent compression using tools like gzip under the hood to create `.tar.gz` files.

> It is not working though... While the filename is supposed to be "sanitized" by passing it through Werkzeug's secure_filename, in practice this does not alter it. It seems like the original filename is being lost somewhere within either SecureTemporaryFile() or gzip.GzipFile().

`secure_filename` does work as intended (see [this test](https://github.com/freedomofpress/securedrop/blob/develop/securedrop/tests/test_source.py#L252)). The original filename is in fact not being lost as you can confirm by running the follow command:

```
% gzip -l --name 1-frightful_micronutrient-doc.gz
         compressed        uncompressed  ratio uncompressed_name
              11324               11316   0.4% 220px-ParkChanwookCannesMay09.jpg
```

The behavior that's changed is when you double-click a compressed file in Tails, its original name is no longer restored. The mimetype of gzip compressed files is `application/x-gzip` and by looking at `/etc/xdg/gnome-mimeapps.list` we can see the default application to open this `org.gnome.FileRoller.desktop`, more recently known as "Archive Manager." So the workaround that @runasand describes actually involves using the same application that is invoked when double clicking.

To give the command-line equivalents, double-clicking is the same as `file-roller --extract-here archive.gz`, and the workaround Runa describes is the same as `file-roller archive.gz`. Unfortunately, the `.desktop` file did not provide any clues as to why `file-roller` was being run with the `--extract-here` option by default, as this is an overriding behavior of Gnome and Nautilus (in any other file manager it would open the way we want).

Peeking in the `dconf` settings, I found the command `dconf write /org/gnome/nautilus/preferences/automatic-decompression false` changes the way Nautilus handles double-clicking compressed files so it opens with `file-roller archive.gz`. This could be added to our boot-time persistence hooks, but of course risks regressions without a proper testing story. Nonetheless, this seems like the best solution.

> Normally, in both symmetric and regular modes, GnuPG is able to retain the original filename by using the --set-filename option (see the manual... --use-embedded-filename per decryption), which would eliminate one of the justifications for using gzip. However, this option is unfortunately not implemented by the python-gnupg library.

These option [are](https://github.com/isislovecruft/python-gnupg/blob/master/gnupg/_parsers.py#L747) [available](https://github.com/isislovecruft/python-gnupg/blob/master/gnupg/_parsers.py#L783) in the `python-gnupg` library fwiw, but I don't think we should be using them.

...

Before my journey into uncharted GNOME configuration territories (being a tiling window manager hipster myself) I wrote out some thoughts on how we should change the app code to solve this problem. I thought it would be good to include this for future reference and consideration, even though I think the solution proposed above is vastly more simple and certainly more appropriate for the 0.4 release. Anyway here are those thoughts:

...

I believe the correct way to solve this is by saving submissions as an encrypted, compressed archive; a `.tar.gz.gpg`:

1. Santize submission filename `santized_filename`.
2. Create a secure temporary tar archive `stta`. This will mean rewriting the `SecureTemporaryFile` class to create an ephemeral tar archive that is written to using on-the-fly encryption instead of a file.
3. Write the submission to this secure temporary tar archive as it is uploaded using the sanitized filename.
4. Encrypt the secure temporary tar archive as it comes using the sanitized filename, and output to `1-falafel_bigly-doc.tar.gz.gpg`.

Any approaches involving storing the original filename in either the GPG or gzip headers should be considered unsafe (that includes the one we've been using this whole time) because we have no way to guarantee that when the original filename is restored it won't overwrite existing files.

...

The only thing I would add to this is that I can confirm that `file-roller archive.gz` prompts before clobbering. It does not put the original file in a folder under the same name as the compressed file sans extension as does `file-roller --extract-here`. So there is room for confusion, but I believe this may be an existing problem that journalists are probably compensating for by creating their own organizational structures for submissions. I think this problem of organization cannot be solved well with the current architecture, and is best addressed by the reading room.

Resolving patch:
diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py
--- a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py
+++ b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py
@@ -41,6 +41,13 @@
 except subprocess.CalledProcessError:
     sys.exit('Error reloading Tor')
 
+# Turn off "automatic-decompression" in Nautilus to ensure the original
+# submission filename is restored (see
+# https://github.com/freedomofpress/securedrop/issues/1862#issuecomment-311519750).
+subprocess.call(['/usr/bin/dconf', 'write',
+                 '/org/gnome/nautilus/preferences/automatic-decompression',
+                 'false'])
+
 # notify the user
 subprocess.call(['tails-notify-user',
                  'SecureDrop successfully auto-configured!',


Test patch: