Follow up for #1776796: Provide a better UX for creating, editing & managing draft revisions.
Problem/Motivation
When access workflow is in place, the fixed public / private sorage configuration is a problem:
- If site owner chooses public file storage, they suffer from PSA-2016-003
- If site owner chooses private file storage, they suffer from performance penalty. For example, on a campaign page with 50ish anonymous-user-submitted-and-reviewed testimonial photos, serving the page needs 51 Drupal bootstraps
Because of the performance cost of private files, a lot of websites use public files by default and sometimes involuntarily expose files.
Proposed resolution
These contrib modules implement a solution as a POC:
The basic idea is to check if a file can be accessed by anonymous users and move accordingly.
This could be implemented as a third option on file fields. (We probably should keep allowing to force public or private file storage.)
Comments
Comment #1
tstoecklerIn theory I agree that this would make lots of sense. The problem is that idea of "published"/"unpublished" is not common among all entity types but specific to nodes. File handling on nodes is managed by the file field, though, which is entity-type agnostic.
Now node.module *could* alter the file field form and hook into the field behavior, but...
Comment #2
agentrickardThis idea comes up a lot in our D7 projects, but I'm not sure how feasible it actually is. Some of the moving parts are:
Given the state of D8 feature freeze, I would suggest that the best we can do is allow this behavior to be defined in contrib, which means attacking only the garbage collection and possibly the WYSIWYG in this issue.
Comment #3
hass commentedWell this are some good questions.
I mainly think about the following critical issues:
If an attachment is already public in other content, it makes not sense to move around :-). I'm sure with some brainstorming we will find more examples why we need this. Adding a .htaccess files cannot really solve the issue as it does not work on IIS out of the box.
Comment #4
agentrickardRight, and I think a contrib workflow module can handle that if we solve problem 1 (bad garbage collection) and problem 2 (actually moving files from private:// to public://) and possibly problem 7 (WYSIWYG).
Comment #5
hass commented#2. Just a copy/move :-)
#7. Looks likely to be solved with UUIDs in D8 core if I remember correctly.
Comment #12
technikh commentedAny solution for this? I am looking for a solution in my D8 site.
Comment #13
szato commentedOur working D8 solution for the mentioned problem:
1) Move public files to private - to be able to manage file access.
2) Add entity_usage module with "Track file/image fields" patch to track images, files too. It works for WYSIWYG files too.
3) Implement your custom file access management based on entity_usage data with hooks: hook_file_access() (hook_ENTITY_TYPE_access) for referenced files and hook_file_download() for WYSIWYG files.
In 3) we are checking entity (node) view access to nodes from which is the file referenced. If at least one node view access is granted, we return AccessResult::allowed(), otherwise AccessResult::forbidden().
Comment #14
szato commentedIf you need tracking non-linked images added with CKEditor Image plugin, add "Add plugin for tracking (non linked) images inserted with WYSIWYG Image" patch.
Comment #20
claudiu.cristea@szato, your solution works but files in the private file system are expensive. Each file download requires PHP processing. A public file is just served by the webserver or frontend cache and that's a relief for Drupal/PHP
Comment #21
berdirYou can combine that with moving files between private and public, so you only need to do access checks as long as there is no public content using them. Not saying it's trivial to do that, at least not in a generic way, but it's... possible.
Comment #22
claudiu.cristea@Berdir, yes, I was thinking on a solution which combines both. I'm wondering whether such a feature could be made generic enough to create a contrib module.
Comment #23
berdirMaybe, if you check for access on any referenced entity for an anonymous user? And you probably also want to specifically handle media entities, so check the nodes/entities using the media, not just the media entity. Which means you need to depend on the entity_usage module as mentioned above (although possible a combination of both file usage and entity usage, to not require that patch).
Comment #24
claudiu.cristea@Berdir, it would be great if you have some time to review a first approach at https://www.drupal.org/project/unpublished_fileNot yet done: "check the nodes/entities using the media, not just the media entity" not implemented yet.EDIT: See #26
Comment #26
claudiu.cristeaOK, I have a complete solution but in an early stage of development, the File Visibility module.
Solution from #24 is abandoned.
Comment #28
geek-merlinComing from #3087660: Automatically move files to public / private storage, depending on referencing entities' access and #2904842: Make private file access handling respect the full entity reference chain, which lived for quite some time as a dup of this issue.
Maybe the title of this issue is not really perfect. Updating it accordingly (ymmv).
@claudiu, kudos for the file_visibility module!
It looks far more feature-rich and elaborated than my file_access_fix that i created some time ago and roughly corresponds to your unpublished_file POC.
So i am deprecating my module in favor of yours.
Comment #29
prudloff commentedCopying some info from #3087660: Automatically move files to public / private storage, depending on referencing entities' access.
Comment #30
dqdI think the new issue title is a little bit blurry now. From a UX point of view a "file" can not be set "(un)published" in Drupal core yet in the same sense like content, but an entity holding a file, like media or nodes with image fields, or nodes with body embedded images can.
There is another issue with unpublished (media) entities holding files not being 100% unpublished in references. Which is another issue in core, but out of the scope of this issue.
From my understanding this issue here is about the file accessibility in connection with unpublished entities referencing the file, where files (not media) keep being accessible even if unused or being part of unpublished content (references). The title should follow this a little bit clearer to distinguish between these both issues. The later isn't probably even not documented yet (I will take a look next days).
Another contrib project not mentioned yet in this scope: https://www.drupal.org/project/file_unpublish
Comment #31
dalemoore commentedWe're dealing with this issue related to meeting digital accessibility requirements related to the DOJ rule. Even though a media entity may be unpublished, or even deleted, the file remains on the server. So if we have for example a lot of non-WCAG 2.1 AA compliant PDFs, and someone goes in there and deletes them from the Media Library, they assume that those files are gone and we no longer have to worry about them. Nope! They're still there on the server. I'm not sure why you would ever want to delete a Media entity but still leave the file on the server? I'm sure there must be a reason for it to be built that way. I'm currently going to be testing the Media File Delete contrib module to see if it will solve part of the problem, but it won't solve the issue of us temporarily wanting to unpublish Media that we may be working to remediate and then later replace it with the remediated file. This would help with us not having to go in and update links with a new file if that file may have references throughout the site.
Comment #32
berdirThat's not related to this issue. You're looking for https://www.drupal.org/node/2891902. Note that this will not delete any files that are already unreferenced, but it will delete any files when you delete the medias going forward after switching that setting. And there are modules mentioned in the comments there that can help with existing leftovers.
Comment #33
dalemoore commentedIs this issue not about having files that are initially in the public directory moved to the private one when the related Media entity is unpublished? That's how I was reading it. I kind of interjected/lead with a separate issue we're also having (which your link seems to probably fix, thanks, I wasn't aware of that setting).
The part that I felt was relevant here was: "... won't solve the issue of us temporarily wanting to unpublish Media that we may be working to remediate and then later replace it with the remediated file. This would help with us not having to go in and update links with a new file if that file may have references throughout the site."
Basically, we want those files to remain on the site, but when we unpublish them they get shifted to the private directory and are inaccessible for anon users, until we can fix them. All the Entity References to them throughout the site would remain (but only work for signed in admins or those w/ permission to see unpublished media).
Comment #34
berdir> Is this issue not about having files that are initially in the public directory moved to the private one when the related Media entity is unpublished?
Fair enough, I overlooked unpublished in the "*unpublished* or even deleted" part. The issue/topic I referenced is deleted.
This kind of makes sense, but there are many really complicated edge cases. For example revisions, if a file is no longer used on the default revision, it would need to be moved to private as well, what if a file is used in more than one place and only some of those are not public? what does public even mean, you can have access control on published media entities. What about direct links to files, files indexed by google and so on.
If you primarily care about documents, the easy solution is to just make the file field on your document media type always private. If you use something like https://drupal.org/project/media_entity_download to avoid direct links to files then requests all go through Drupal/PHP anyway. Of course, you kind of have to do that from the start to avoid some of the issues and some kind of conversion of existing files.