modules/file/file.module | 69 ++++++++++++++++++++++++++++----------------- modules/node/node.module | 9 ++++++ modules/user/user.module | 9 ++++++ 3 files changed, 61 insertions(+), 26 deletions(-) diff --git modules/file/file.module modules/file/file.module index cfdb212..ccff9ef 100644 --- modules/file/file.module +++ modules/file/file.module @@ -134,46 +134,63 @@ function file_file_download($uri, $field_type = 'file') { // Find out which (if any) file fields contain this file. $references = file_get_file_references($file, NULL, FIELD_LOAD_REVISION, $field_type); - // TODO: Check field-level access if available here. - - $denied = $file->status ? NULL : FALSE; + // By default, allow access. + $denied = FALSE; // Check access to content containing the file fields. If access is allowed // to any of this content, allow the download. foreach ($references as $field_name => $field_references) { foreach ($field_references as $entity_type => $type_references) { - foreach ($type_references as $reference) { - // If access is allowed to any object, immediately stop and grant - // access. If access is denied, continue through in case another object - // grants access. - // TODO: Switch this to a universal access check mechanism if available. - if ($entity_type == 'node' && ($node = node_load($reference->nid))) { - if (node_access('view', $node)) { - $denied = FALSE; - break 3; + foreach ($type_references as $id => $reference) { + // Try to load $entity and $field. + $entity = reset(entity_load($entity_type, array($id))); + $field = NULL; + if ($entity) { + // Load all fields for that entity. + $field_items = field_get_items($entity_type, $entity, $field_name); + + // Find the field item with the matching URI. + foreach ($field_items as $field_item) { + if ($field_item['uri'] == $uri) { + $field = $field_item; + break; + } } - else { + } + + // If both $entity and $field could be loaded, call field_access(). + // This can only deny access as it defaults to TRUE. + if ($entity && $field && !field_access('view', $field, $entity_type, $entity)) { + $denied = TRUE; + // If access is denied for entity, further checks are not required but + // other entities might still allow access. + break; + } + + // If access is not denied to this field, check if the user can view + // the entity. + foreach (module_implements('file_download_access') as $module) { + $function = $module . '_file_download_access'; + $return = $function($field, $entity_type, $entity); + // If an implementation returns FALSE, access to this entity is denied + // but the file could belong to another entity to which the user might + // have access. Continue with these. + if ($return === FALSE) { $denied = TRUE; + break 2; } - } - if ($entity_type == 'user') { - if (user_access('access user profiles') || $user->uid == $reference->uid) { + // If TRUE is returned, access is granted and no further checks are + // necessary. + if ($return === TRUE) { $denied = FALSE; - break 3; - } - else { - $denied = TRUE; + break 4; } } } } } - // No access was denied or granted. - if (!isset($denied)) { - return; - } - // Access specifically denied and not granted elsewhere. - elseif ($denied == TRUE) { + // Access specifically denied. + if ($denied) { return -1; } diff --git modules/node/node.module modules/node/node.module index 1497e62..69a7379 100644 --- modules/node/node.module +++ modules/node/node.module @@ -3686,3 +3686,12 @@ class NodeController extends DrupalDefaultEntityController { return $query; } } + +/** + * Implements hook_file_download_access(). + */ +function node_file_download_access($field, $entity_type, $entity) { + if ($entity_type == 'node') { + return node_access('view', $entity); + } +} diff --git modules/user/user.module modules/user/user.module index 887be0a..4b08df0 100644 --- modules/user/user.module +++ modules/user/user.module @@ -3678,3 +3678,12 @@ function user_rdf_mapping() { ), ); } + +/** + * Implements hook_file_download_access(). + */ +function user_file_download_access($field, $entity_type, $entity) { + if ($entity_type == 'user') { + return user_view_access($entity); + } +} \ No newline at end of file