Jump to:

10845 Posts in 2513 Topics by 1792 members

All other Modules

SilverStripe Forums » All other Modules » Secure Files: securing personal files

Discuss all other Modules here.

Moderators: martimiz, Sean, biapar, Willr, Ingo, swaiba, simon_w

Page: 1 2 3
Go to End
Author Topic: 2434 Views
  • Hamish
    Avatar
    Community Member
    712 Posts

    Re: Secure Files: securing personal files Link to this post

    Hi,

    It might be a bit risky trying to replicate the behaviour of CanViewSecured - better just to call it directly, but the solution will depend on a few things, like how many files there are and how much traffic you're likely to get.

    The easiest way would be to simply return an object with all Files to the template and call CanView (CanViewSecured is really an internal API method), eg (these examples are untested):

    // MODEL:
    <?php
    function getAllFiles() {
       return DataObject::get('File');
    }
    ?>

    // TEMPLATE:
    <% if AllFiles %>
       <% control AllFiles %>
          <% if CanView %>
             <p>Download <a href="$URL">$Name</a></p>
          <% end_if %>
       <% end_control %>
    <% end_if %>

    However this is going to be database intensive, especially if you have lots of files or folders.

    Another solution would be to test Folders instead of Files, then return the Files in Folders that the current Member can view:

    // MODEL:
    function getViewableFiles() {
       $files = new DataObjectSet();
       $folders = DataObject::get('Folder');
       if(!$folders) return $files;
       foreach($folders as $folder)
          if($folder->CanView())
             if($subFiles = DataObject::get('File', "ClassName != 'Folder' && ParentID = {$folder->ID}"))
                $files->merge($subFiles);
       return $files; // Should contain all files that the member can view.
    }

    This will be more efficient that the first option, but it's still pretty hard on the database if there are a lot of folders.

    The best option would probably be an extension that cached view permissions somehow, but that would be an advanced option if the above options were not suitable.

    Hope this helps.

    Hamish

  • klikhier
    Avatar
    Community Member
    150 Posts

    Re: Secure Files: securing personal files Link to this post

    Hamish, second solution didn't work (haven't tried first one). Something goes wrong with if($folder->canView()), because all available files in the Uploads folder are added tot $files. Have tried canView, CanView and canViewSecured.

  • Hamish
    Avatar
    Community Member
    712 Posts

    Re: Secure Files: securing personal files Link to this post

    Ah, well you can use the property Secured to check if the current folder is marked secure and the method "InheritSecured()" to test if the and parent is secured, so modify:

    ...
    foreach($folders as $folder)
       if(!$folder->Secured && !$folder->InheritSecured())
          continue;
       if($folder->CanView())
          ....

  • Cano
    Avatar
    Community Member
    14 Posts

    Re: Secure Files: securing personal files Link to this post

    Jumping into this thread as it seems right up my alley. (Thanks for the link Hamish)

    I have uncommented the line below:

    // Assign file security by individual member:
    DataObject::add_extension('File', 'SecureFileMemberPermissionDecorator');

    I have then gone into the backend and assigned the appropriate user permissions to the files. So far so good.

    Then in my template I inserted this (InvestorPage.ss):

    <% if AllFiles %>
    <% control AllFiles %>
    <% if CanView %>
    <p>Download <a href="$URL">$Name</a></p>
    <% end_if %>
    <% end_control %>
    <% end_if %>

    And into my php file i now have:

    <?php
    /**
    * Defines the InvestorPage page type
    */
       class InvestorPage extends Page {
          static $db = array(
          );
          static $has_one = array(
             'BannerImage' => 'Image',
          );
          static $has_many = array (
             'File' => 'File',
          );
          function getAllFiles() {
          return DataObject::get('File');
          }
          function getCMSFields() {
             $fields = parent::getCMSFields();
             $fields->removeFieldFromTab('Root.Content.Main','PagePhoto');
             $fields->removeFieldFromTab('Root.Content.Main','Content');
          return $fields;
          }
       }
       class InvestorPage_Controller extends Page_Controller {
       }

    It does sucessfully filter out other users files, but it shows every other file uploaded included site imagery etc. How can i remove all the excess and just show the contents of files within certain (secured) folders?

    Sorry this is a Noob question, but im really learning quite rapidly here (bear with me!!!)

    Thanks
    Cano

  • Cano
    Avatar
    Community Member
    14 Posts

    Re: Secure Files: securing personal files Link to this post

    I have a feeling it has something to do with the CanView element...

    <div class="typography">
          <% if AllFiles %>
    <% control AllFiles %>
    <% if CanView %>
    <p>Download <a href="$URL">$Name</a></p>
    <% end_if %>
    <% end_control %>
    <% end_if %>
    </div>

    Should it be...

    <% if canViewSecured %>

    rather than...???

    <% if CanView %>

    Cheers,
    Hope this extra info shows that I'm at least trying!

  • Hamish
    Avatar
    Community Member
    712 Posts

    Re: Secure Files: securing personal files Link to this post

    canView just calls canViewSecured (they operate slightly differently when extended, hence the seperation). Sounds like a solution be to additionally filter by files that are in secure folders, e.g. building on what you already have:

    <% if AllFiles %>
       <% control AllFiles %>
          <% if InheritSecured %><% if CanView %>
             <p>Download <a href="$URL">$Name</a></p>
          <% end_if %><% end_if %>
       <% end_control %>
    <% end_if %>

    Basically it just checks the folder stack to see if it is in a tree that has been marked secure. That should filter out any other site assets that are sitting around in other folders.

  • Cano
    Avatar
    Community Member
    14 Posts

    Re: Secure Files: securing personal files Link to this post

    Perfect, you genuinly made me jump for joy with that one!

    One last thing...if the files that the user has access to are in a variety of folders, is there a way to orgainse the files by these different folders? i.e. the attatched/linked screenshot? http://screencast.com/t/ouG5IX0LN

    Here is my Investor Page...

    class InvestorPage extends Page {
          static $db = array(
          );
          static $has_one = array(
             'BannerImage' => 'Image',
          );
          static $has_many = array (
             'File' => 'File',
          );
          function getAllFiles() {
             return DataObject::get('File');
          }
          function getCMSFields() {
             $fields = parent::getCMSFields();
             $fields->removeFieldFromTab('Root.Content.Main','PagePhoto');
             $fields->removeFieldFromTab('Root.Content.Main','Content');
          return $fields;
          }
       }
       class InvestorPage_Controller extends Page_Controller {
       }

    And the template (thanks to you!)...

    <% if AllFiles %>
    <% control AllFiles %>
    <% if InheritSecured %><% if CanView %>
       <p><a href="$URL">$Name</a></p>
    <% end_if %><% end_if %>
    <% end_control %>
    <% end_if %>

    My file heirarchy is also attached.

    Is there a way to say if in x folder - show files?

    Ideally, the client may wish to add other folders so it would be good if the solution didnt rely on absolute paths (which is the method ive been trying)

  • Hamish
    Avatar
    Community Member
    712 Posts

    Re: Secure Files: securing personal files Link to this post

    You should probably build the data before pushing it to your template if you need sorting / nesting etc. Ie, a method on the page that does similar checks to those described above, but returns files in DataObjectSets that have the name of the folder. Something like:

    function getFilesUserCanAccess() {
       $result = new DataObjectSet();
       $folders = array();
       $files = DataObject::get('Files');
       foreach($files as $file) {
          if(empty($folders[$file->ParentID]))
             $folders[$file->ParentID] = array(
                'Folder' => $file->Parent(), // I think Parent() gets the file folder?
                'Files' => array()
             );
          if($file->canView() && $file->InheritSecured())
             $folders[$file->ParentID]['Files'][] = $file;
       }
       foreach($folders as $folder) {
          $files = new DataObjectSet();
          foreach($folder['Files'] as $file)
             $files->push($file);
          $result->push(new ArrayData(array('Folder' => $folder['Folder'], $files => $files));
       }
       return $result;
    }

    Should be able to use it a template like:

    <% control FilesUSerCanAccess %>
       <p>$Folder.Name</p>
       <% control Files %>
          <p>$URL</p> // etc
       <% end_if %>
    <% end_control %>

    None of the above is tested.

    2434 Views
Page: 1 2 3
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.