Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
There's a few threads over on the jPlayer Google Group about this, but File above web root? has the most useful information.
I think we can implement something similar to this. My initial research / thoughts are:
- The filefield (or site file system in Drupal 6) would need to be set to Private.
- We can add a jQuery behavior to the player such that when the file needs to be downloaded, an AJAX request is first sent that includes the path to the file and the current time. We may have to do different code for the Flash player, but since it's controlled by JavaScript we should be able to hook into the file download action the same way. That timestamp can be saved in $_SESSION.
- In hook_file_download(), we can compare the timestamp to the current time, and allow access if the time passed is less than some specified period (like 5 seconds).
- If the timestamp isn't present or if it's expired, we can deny access. The 403 could be logged to the watchdog, or perhaps even a separate table for authenticated users. That way, should be easy to track users who are attempting to download the file directly.
I need this for Drupal 6, but I might write it for D7 first and backport. I'm filing this against 7.x-2.x due to #1173678: Add 6.x-1.x-dev release.
Comments
Comment #1
deviantintegral CreditAttribution: deviantintegral commentedHere's a patch against 6.x-1.x withe the following commits:
Comment #2
deviantintegral CreditAttribution: deviantintegral commentedHere's a new patch with a few more commits. We now prevent clients from setting their clock to be too far in the future, increased the default window to 30 seconds, and only allow access to a file once.
Comment #3
deviantintegral CreditAttribution: deviantintegral commentedNew commits:
Also, it looks like there is an issue with Chrome where it double-requests audio files. The second request is denied (since the token has expired) breaking the player. It works fine in other browsers, or if the flash player is used. I'm going to look into this some more, but I'm thinking that if the browser is chrome, download protection is on, and flash is available, that the flash player should be forced.
Comment #4
deviantintegral CreditAttribution: deviantintegral commentedHere's a new patch that fixes the issue with Chrome requesting a file multiple times.
Comment #5
deviantintegral CreditAttribution: deviantintegral commentedHere should hopefully be a final patch that adds logging for when files are blocked and provides a table of the top-denied users. That way, admins can contact or block users who are trying to download files (or be aware of any possible browser issues).
Comment #6
deviantintegral CreditAttribution: deviantintegral commentedComment #7
deviantintegral CreditAttribution: deviantintegral commentedTwo more. The big change is that private downloading can be enabled even if the access is public, in case a custom .htaccess rule is redirecting access to system/files.
Comment #8
deviantintegral CreditAttribution: deviantintegral commentedImplementing hook_install() and uninstalling our variables in hook_uninstall().
Comment #9
deviantintegral CreditAttribution: deviantintegral commentedHere's an additional fix that cleans up detecting when the "playlist" player is in use. Otherwise, the wrong file path is sent to the server. This adds a playerType variable to the player that can easily be used by other JS functions.
Comment #10
deviantintegral CreditAttribution: deviantintegral commentedI curse IE to as much pain as it has caused me.
Comment #11
izmeez CreditAttribution: izmeez commentedsubscribing
Comment #12
deviantintegral CreditAttribution: deviantintegral commentedThis needs to be ported to 7.x-2.x. It's large enough that I'm hesitant to commit it to 6.x-1.x by itself.
Comment #13
deviantintegral CreditAttribution: deviantintegral commentedHere's an untested reroll against the latest 6.x-1.x. Once I've tested that the rebase didn't break anything, I'll start porting to 7.x-2.x.
Comment #14
deviantintegral CreditAttribution: deviantintegral commentedI've attached a patch porting all of the changes to 7.x-2.x. I've posted it here for reference, but I'll be committing a squashed version of it along with the 6.x-1.x version.
Everything works in the 7.x-2.x version, but there are still some TODOs left. I'm going to file separate issues for everything else left to be done.