Skip to content

Commit

Permalink
Bug 1209924 - Implement a general filtering mechanism for Directory::…
Browse files Browse the repository at this point in the history
…GetFilesAndDirectories, and add filtering of sensitive files/directories. r=baku
  • Loading branch information
jwatt committed Oct 9, 2015
1 parent 97e7557 commit 0f70d91
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 6 deletions.
4 changes: 3 additions & 1 deletion dom/events/DataTransfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,9 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
nsDependentSubstring basename = Substring(path, leafSeparatorIndex);
fs = MakeOrReuseFileSystem(dirname, fs, window);
filesAndDirsSeq[i].SetAsDirectory() = new Directory(fs, basename);
RefPtr<Directory> directory = new Directory(fs, basename);
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
filesAndDirsSeq[i].SetAsDirectory() = directory;
} else {
filesAndDirsSeq[i].SetAsFile() = mFiles->Item(i);
}
Expand Down
8 changes: 7 additions & 1 deletion dom/filesystem/Directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ Directory::GetFilesAndDirectories()
nsString realPath;
ErrorResult rv;
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(mFileSystem, mPath, rv);
new GetDirectoryListingTask(mFileSystem, mPath, mFilters, rv);
if (NS_WARN_IF(rv.Failed())) {
return nullptr;
}
Expand All @@ -251,6 +251,12 @@ Directory::GetFilesAndDirectories()
return task->GetPromise();
}

void
Directory::SetContentFilters(const nsAString& aFilters)
{
mFilters = aFilters;
}

FileSystemBase*
Directory::GetFileSystem() const
{
Expand Down
26 changes: 26 additions & 0 deletions dom/filesystem/Directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,31 @@ class Directory final

// =========== End WebIDL bindings.============

/**
* Sets a semi-colon separated list of filters to filter-in or filter-out
* certain types of files when the contents of this directory are requested
* via a GetFilesAndDirectories() call.
*
* Currently supported keywords:
*
* * filter-out-sensitive
* This keyword filters out files or directories that we don't wish to
* make available to Web content because we are concerned that there is
* a risk that users may unwittingly give Web content access to them
* and suffer undesirable consequences. The details of what is
* filtered out can be found in GetDirectoryListingTask::Work.
*
* In future, we will likely support filtering based on filename extensions
* (for example, aFilters could be "*.jpg; *.jpeg; *.gif"), but that isn't
* supported yet. Once supported, files that don't match a specified
* extension (if any are specified) would be filtered out. This
* functionality would allow us to apply the 'accept' attribute from
* <input type=file directory accept="..."> to the results of a directory
* picker operation.
*/
void
SetContentFilters(const nsAString& aFilters);

FileSystemBase*
GetFileSystem() const;
private:
Expand All @@ -108,6 +133,7 @@ class Directory final

RefPtr<FileSystemBase> mFileSystem;
nsString mPath;
nsString mFilters;
};

} // namespace dom
Expand Down
43 changes: 40 additions & 3 deletions dom/filesystem/GetDirectoryListingTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "GetDirectoryListingTask.h"

#include "HTMLSplitOnSpacesTokenizer.h"
#include "js/Value.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
Expand All @@ -22,9 +23,11 @@ namespace dom {

GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
const nsAString& aFilters,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aTargetPath)
, mFilters(aFilters)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
Expand All @@ -40,12 +43,13 @@ GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mTargetRealPath(aParam.realPath())
, mFilters(aParam.filters())
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mTargetRealPath = aParam.realPath();
}

GetDirectoryListingTask::~GetDirectoryListingTask()
Expand All @@ -65,7 +69,8 @@ FileSystemParams
GetDirectoryListingTask::GetRequestParams(const nsString& aFileSystem) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemGetDirectoryListingParams(aFileSystem, mTargetRealPath);
return FileSystemGetDirectoryListingParams(aFileSystem, mTargetRealPath,
mFilters);
}

FileSystemResponseValue
Expand Down Expand Up @@ -155,6 +160,20 @@ GetDirectoryListingTask::Work()
return rv;
}

bool filterOutSensitive = false;
{
HTMLSplitOnSpacesTokenizer tokenizer(mFilters, ';');
nsAutoString token;
while (tokenizer.hasMoreTokens()) {
token = tokenizer.nextToken();
if (token.EqualsLiteral("filter-out-sensitive")) {
filterOutSensitive = true;
} else {
MOZ_CRASH("Unrecognized filter");
}
}
}

for (;;) {
bool hasMore = false;
if (NS_WARN_IF(NS_FAILED(entries->HasMoreElements(&hasMore))) || !hasMore) {
Expand All @@ -179,6 +198,21 @@ GetDirectoryListingTask::Work()
!(isFile || isDir)) {
continue;
}

if (filterOutSensitive) {
bool isHidden;
if (NS_WARN_IF(NS_FAILED(currFile->IsHidden(&isHidden))) || isHidden) {
continue;
}
nsAutoString leafName;
if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
continue;
}
if (leafName[0] == char16_t('.')) {
continue;
}
}

BlobImplFile* impl = new BlobImplFile(currFile);
impl->LookupAndCacheIsDirectory();
mTargetBlobImpls.AppendElement(impl);
Expand Down Expand Up @@ -226,7 +260,10 @@ GetDirectoryListingTask::HandlerCallback()
MOZ_ASSERT(exist);
}
#endif
listing[i].SetAsDirectory() = new Directory(mFileSystem, path);
RefPtr<Directory> directory = new Directory(mFileSystem, path);
// Propogate mFilter onto sub-Directory object:
directory->SetContentFilters(mFilters);
listing[i].SetAsDirectory() = directory;
} else {
listing[i].SetAsFile() = File::Create(mFileSystem->GetWindow(), mTargetBlobImpls[i]);
}
Expand Down
2 changes: 2 additions & 0 deletions dom/filesystem/GetDirectoryListingTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class GetDirectoryListingTask final
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
const nsAString& aFilters,
ErrorResult& aRv);
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
Expand Down Expand Up @@ -55,6 +56,7 @@ class GetDirectoryListingTask final
private:
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsString mFilters;

// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
Expand Down
8 changes: 7 additions & 1 deletion dom/html/HTMLInputElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4934,8 +4934,14 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
fs = MakeOrReuseFileSystem(dirname, fs, window);
nsAutoString dompath(NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR));
dompath.Append(Substring(path, leafSeparatorIndex + 1));
filesAndDirsSeq[i].SetAsDirectory() = new Directory(fs, dompath);
RefPtr<Directory> directory = new Directory(fs, dompath);
// In future we could refactor SetFilePickerFiltersFromAccept to return a
// semicolon separated list of file extensions and include that in the
// filter string passed here.
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
filesAndDirsSeq[i].SetAsDirectory() = directory;
} else {
// This file was directly selected by the user, so don't filter it.
filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i];
}
}
Expand Down
10 changes: 10 additions & 0 deletions dom/ipc/PContent.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,16 @@ struct FileSystemGetDirectoryListingParams
{
nsString filesystem;
nsString realPath;
// 'filters' could be an array rather than a semicolon separated string
// (we'd then use InfallibleTArray<nsString> internally), but that is
// wasteful. E10s requires us to pass the filters over as a string anyway,
// so avoiding using an array avoids serialization on the side passing the
// filters. Since an nsString can share its buffer when copied,
// using that instead of InfallibleTArray<nsString> makes copying the filters
// around in any given process a bit more efficient too, since copying a
// single nsString is cheaper than copying InfallibleTArray member data and
// each nsString that it contains.
nsString filters;
};

struct FileSystemGetFileOrDirectoryParams
Expand Down

0 comments on commit 0f70d91

Please sign in to comment.