Skip to content

File Mode / Permissions Interface #49

Open

Description

@tristanlins

Currently we do not work around different permission systems.
How about to introduce an interface and some classes to handle this problem.

interface FileMode // or FilePermissions
{
    const TYPE = 'unknown';

    /**
     * Check if file modes are supported by the fs.
     *
     * @return bool
     */
    public function isSupported();

    /**
     * Test if file is readable for the current user.
     * Which "user" is referenced, depends on the implementation
     * and have to be automatically detected.
     *
     * @return bool
     */
    public function isReadable();

    /**
     * Test if file is writeable for the current user.
     * Which "user" is referenced, depends on the implementation
     * and have to be automatically detected.
     *
     * @return bool
     */
    public function isWriteable();

    /**
     * Test if file is executeable for the current user.
     * Which "user" is referenced, depends on the implementation
     * and have to be automatically detected.
     *
     * @return bool
     */
    public function isExecuteable();

    /**
     * For stacked file permission systems, get the next hop.
     *
     * @return FileMode
     */
    public function nextFileMode();
}

Then we have multiple classes with specific methods.
The UnsupportedFileMode class that indicate that file permissions are not supported.

class UnsupportedFileMode implements FileMode
{
    const TYPE = 'unsupported';

    public function isSupported()
    {
        return false;
    }
}

The PrimitiveFileMode only know read, write, executeable. It does not know owner, groups or complex acl rules.

class PrimitiveFileMode implements FileMode
{
    const TYPE = 'primitive';

    public function isSupported()
    {
        return true;
    }
    public function isReadable();
    public function isWriteable();
    public function isExecuteable();
}

The UnixFileMode only know read, write, executeable for owner, groups and others.

class UnixFileMode implements FileMode
{
    const TYPE = 'unix';

    public function isSupported()
    {
        return true;
    }
    public function isOwnerReadable();
    public function isOwnerWriteable();
    public function isOwnerExecuteable();
    public function isGroupReadable();
    public function isGroupWriteable();
    public function isGroupExecuteable();
    public function isOthersReadable();
    public function isOthersWriteable();
    public function isOthersExecuteable();
    public function isSticky();
    // maybe more
}

As you expected, the ACLFileMode will allow access to acl rules.

An interface system like this allow us to respect the different permission system.
The FileMode::isSupported is mandatory, because in mounted or merged filesystem I don't have access to the underlaying filesystem to check the "file permissions" ability. The UnsupportedFileMode prevents File::getMode from returning null.

Also other systems are allowed to implement there own permission system. For example Contao could implement it's own ContaoPermissionsFileMode for example.

class ContaoPermissionsFileMode implements FileMode
{
    const TYPE = 'contao';

    public function isSupported()
    {
        return true;
    }
    public function isUserReadable($backendUserId);
    public function isUserWriteable($backendUserId);
    public function isMemberReadable($memberId);
    public function isMemberWriteable($memberId);
}

To allow access to different permission systems, for example the ContaoPermissionsFileMode is just an overlay over UnixFileMode, the File::getMode should be extended with a type parameter:

interface File
{
    /**
     * Get permission access object for this file.
     *
     * @param string $type The permission system to access.
     * If null the filesystem default permission system will be returned.
     *
     * @throw UnsupportedPermissionSystemException will be thrown if the requested permission system is not available.
     */
    public function getMode($type = null);
}

To access different permission systems just use the TYPE constant:

/** @var ContaoFilesystem $fs */
$file = $fs->getFile('foo');

/** @var ContaoPermissionsFileMode $contaoPerms */
$contaoPerms = $file->getMode();

// forcing a permission system (not good)
try {
    /** @var UnixFileMode $unixPerms */
    $unixPerms = $file->getMode(UnixFileMode::TYPE);
} catch (UnsupportedPermissionSystemException $e) {
    // unix unsupported, maybe it is a linked in remote share like dropbox or amazon S3
}

// get the next permission system (good way)
/** @var UnixFileMode|DropboxFileMode|AmazonS3FileMode|... $nextPerms */
$nextPerms = $contaoPerms->nextFileMode();

This allow us to transparent add file permission systems, nobody knows about it, but it will protect the files. The File::isReadable, File::isWriteable and File::isExecuteable should be shortcuts to the FileMode::isReadable, FileMode::isWriteable, FileMode::isExecuteable methods.

Activity

  1. tristanlins commented on May 27, 2013

    @tristanlins
    MemberAuthor

    The method

        /**
         * For stacked file permission systems, get the next hop.
         *
         * @return FileMode
         */
        public function nextFileMode();
    

    will be dropped. The adapter have to check its own native permissions and then check permission - if available - against an extended permission manager.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions