Skip to content
This repository has been archived by the owner on Mar 24, 2020. It is now read-only.

Fixes #467 - Disable file downloading for localDisplay videos/audios and metadataDisplay objects. #473

Merged
merged 3 commits into from
Jun 29, 2018

Conversation

lsitu
Copy link
Member

@lsitu lsitu commented Jun 27, 2018

Fixes #467

Local Checklist

  • Tests written and passing locally?
  • Code style checked?
  • QA-ed locally?
  • Rebased with master branch?
  • Configuration updated (if needed)?
  • Documentation updated (if needed)?

What does this PR do?

Disable file downloading for localDisplay videos/audios and metadataDisplay objects, while allowing campus users to download localDisplay images.

Why are we doing this? Any context of related work?

References #466, #467

@ucsdlib/developers - please review

Copy link
Member

@mcritchlow mcritchlow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really great, and a complex set of use cases to keep track of. I have only a few questions/comments to get your thoughts on. Overall this is 💯

@@ -44,6 +44,9 @@ def show
authorize! :edit, @solr_doc
elsif !@solr_doc['read_access_group_ssim'].include?("public")
authorize! :show, @solr_doc
unless can? :edit, @solr_doc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little torn on how I feel about the nested unless checks here. After a second read through it makes sense though. But part of me wonders if this is easier to read if we flip the checks and use || instead. Something like:

unless can_download?(@solr_doc) || can?(:edit, @solr_doc) 
  CanCan::AccessDenied, "User is not allowed to download file: #{field}"

Would that logic work? I may be missing an example where this wouldn't be acceptable. It also might have its own readability issues..

local_license = document['license_tesim'] && document['license_tesim'].first.to_s.include?('localDisplay') ? true : false
license = document['license_tesim']
other_rights = document['otherRights_tesim']
return false if streaming_media_type?(document['resource_type_tesim']) && (local_display?(license) || local_display?(other_rights))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot going on here with these conditionals. I know there are many cases to test, but i wonder if we could shrink them doing at all by breaking the returns apart? Like off the top, if the file is not a streaming type, we could presumably return true immediately? And/or maybe the local_display and metadata_only_display checks could be individual conditionals?

The individual supporting methods are great, it's just that the conditional combination here is long.

Maybe some comments are necessary here to provide the narrative for what we're doing here, given the complexity? Curious what you think. Basically I'm thinking this might be easy to forget or understand in a few months if/when we have to port this to DAMS5.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sound good. I'll refactor it for the conditional combination, and I see it more complicated with those UCSD IP/metadata-only collections that won't allow local download but need VPN/campus view.

end

def streaming_media_type?(resource_types)
resource_types.each do |t|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these support methods you might be able to use the .any? Enumerable method to avoid the explicit returns. Something like:

def streaming_media_type?(resource_types)
  resource_types.any? { |t| t.include?('video') || t.include?('sound') }
end

@@ -0,0 +1,516 @@
# frozen_string_literal: true

require 'spec_helper'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great test setup 👏 I'll have to tweak this once we fold in the send_file code, but I already have a pattern in place for that. And these are an excellent set of comprehensive tests.

@mcritchlow
Copy link
Member

mcritchlow commented Jun 27, 2018

@lsitu - Here's another idea, just to put out there. What if we made can_download? an actual cancan method?

So instead of doing the edit check and then our custom method, we ideally do something like this in the file controller, or even use authorize!:

unless can? :download_file, @solr_doc
  <raise 403 error>
end

We could possibly borrow some ideas from Hydra::Ability and this custom actions page?

I think this would mostly involve moving code into ability.rb. The nice part, if this works, is it would let us use CanCan, which it kinda feels like we ideally should be for something like this. Although the context of the @solr_doc might be a bit confusing, since one isn't trying to download that, but rather a file the doc references. But I suppose we could make the same argument about the other actions to some extent..

That said, if you think it's too much of a change to make, or a bad idea for other reasons, then feel free to ignore :)

@lsitu
Copy link
Member Author

lsitu commented Jun 27, 2018

@mcritchlow Good point! I was thinking about it but it seem like we may need to add the file_id parameter to the can_download? method to support the specs in #466 that need those UCSD IP/metadata collections to be viewable from campus or through VPN (UCSD IP restriction).
In this case, we may need to disallow the downloading of files like _2.jpg, as well as other _1.* service files. So it seem like we should keep it as a method. What do you think? Do you think if we make a simple check with the filename will be enough, or need to look up and parse the data for all the files o check the file use property, which is not so efficient for a match?

@mcritchlow
Copy link
Member

@lsitu - Yeah i suspect it might be best to just leave your existing implementation as proposed in this PR as-is, because there's enough complexity in this that it's probably not worth it. it was just a thought that occurred to me :) hopefully next time we do this, in dams5, we'll have more rational metadata for making this decision. we'll see..

@lsitu
Copy link
Member Author

lsitu commented Jun 28, 2018

@mcritchlow Yep. It sounds good. I was thinking whether we should at least filter those _2.jpg from downloading or not. Thanks.

@@ -44,6 +44,9 @@ def show
authorize! :edit, @solr_doc
elsif !@solr_doc['read_access_group_ssim'].include?("public")
authorize! :show, @solr_doc
unless can?(:edit, @solr_doc) || can_download?(@solr_doc, fileid)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/IfUnlessModifier: Favor modifier unless usage when having a single-line body. Another good alternative is the usage of control flow &&/||.

@coveralls
Copy link

coveralls commented Jun 28, 2018

Coverage Status

Coverage increased (+0.06%) to 65.98% when pulling af720b8 on feature/file_downloading into 1eb8d3c on develop.

@VivianChu
Copy link
Member

👍

end
!local_other_rights && !local_license
def restricted_file?(fileid)
fileid && fileid.include?('_2.jpg')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is specific to an _2.jpg being a restricted file? I don't think I understand the meaning behind this one.

return result unless data
data.each do |datum|
result = true if datum.include?('localDisplay') || datum.include?('metadataDisplay')
def metadata_display?(data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we already have this metadata_display? method, and it appears to be used in the catalog_helper and dams_resource_controller, do we need the local_display? and metadata_only_display? methods? Could we use this instead? This one seems to just check both (though it could be rewritten to use any? also like the others. Just a thought.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcritchlow I think we may need to a separate method for metadata_only_display? to determine the different behavior with localDisplay and metadataDisplay objects. For localDisplay objects, they allow downloading of files (video/audio excluded) while metadataDisplay won't allow file download for any files.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lsitu - Ok, thanks for clarifying. Perhaps I misunderstood what Greg said. I thought he said if either were filled in then one could not download derivatives. But yeah if there are distinctions then I guess that's another issue. Poorly named properties it turns out, because they don't actually describe what they do :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcritchlow Yes, it's confusing to me too. So I asked Greg to clarify the localDisplay thing earlier since the access control issue is always sensitive to us. Do you want to rename it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lsitu - I'm not sure. Honestly, all your tests pass and I think it's a pretty comprehensive test suite. I don't want to slow this down more than necessary. I just think the data model implications and application to these access control scenarios is unsustainable, very fragile at the least. But that's hopefully an issue we can address in the next system. Perhaps unless @hweng or @VivianChu have any other concerns, I'll just merge this and we can move on? (Thanks for all your awesome work on this complicated ticket)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcritchlow Could you hold on? I'll refactor it a little bit. Thanks.

@lsitu
Copy link
Member Author

lsitu commented Jun 29, 2018

@mcritchlow Good question!
To support UCSD IP/metadata-only collections with camps/VPN access behavior, we need to disable the download button and the downloading of the files, but we also need the objects to be viewable, which requires file download for the object viewers. Those _2.jpeg full screen resolution images are linking to the download button so I just restrict them from downloading at this time. I think we can add any other restricted file types from downloading when necessary. Just let me know what we want to start with and I think we can adjust it now or later. Thanks.

@mcritchlow
Copy link
Member

mcritchlow commented Jun 29, 2018

@lsitu - Ok, I think I understand. This is just really messy. Not your code, just the very custom conditions we're allowing, or not allowing here. I wonder if this method needs to be named more specific to the context. Because on its own, a 2.jpg is usually not restricted, as you know.

At this point in the conditional checking in can_download?, do we need to limit the file to 2.jpg? Basically, if we're in a metadata-only situation, I'm curious what files a user is allowed to download? Thumbnail? Can they even see that? I guess if I think "metadata only", that makes me think "no files can be downloaded". But perhaps that's not true?

@lsitu
Copy link
Member Author

lsitu commented Jun 29, 2018

Yep, good questions again. I think "metadata only" is only for public users, things become complicated/confusing for campus /VPN (UCSD IP restricted) users. The issue is that why the download button need to be removed from the viewer for those UCSD IP/metadata-only collections. And as you noted, does those images link to the download button a matter? If the answer is no, then removing of the download button seems to be a question.

@lsitu
Copy link
Member Author

lsitu commented Jun 29, 2018

@mcritchlow I've refactored the metadata_display? codes to use it to include audio/video download controlling for the UCSD IP/metadata-only collections with the additional tests added.

@mcritchlow
Copy link
Member

LGTM

@VivianChu VivianChu merged commit fdb14d0 into develop Jun 29, 2018
@VivianChu VivianChu deleted the feature/file_downloading branch June 29, 2018 19:13
@hweng
Copy link
Contributor

hweng commented Jun 29, 2018

👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants