diff options
Diffstat (limited to 'includes/filetransfer/filetransfer.inc')
-rw-r--r-- | includes/filetransfer/filetransfer.inc | 145 |
1 files changed, 123 insertions, 22 deletions
diff --git a/includes/filetransfer/filetransfer.inc b/includes/filetransfer/filetransfer.inc index 2fb769913..66e0f5787 100644 --- a/includes/filetransfer/filetransfer.inc +++ b/includes/filetransfer/filetransfer.inc @@ -2,28 +2,34 @@ // $Id$ /* - * Connection class. + * Base FileTransfer class. * - * This class does file operations on directories not writeable by the - * webserver. It connects back to the server using some backend (for example - * FTP or SSH). To keep security the password should always be asked from the - * user and never stored. + * Classes extending this class perform file operations on directories not + * writeable by the webserver. To achieve this, the class should connect back + * to the server using some backend (for example FTP or SSH). To keep security, + * the password should always be asked from the user and never stored. For + * safety, all methods operate only inside a "jail", by default the Drupal root. */ abstract class FileTransfer { + protected $username; + protected $password; + protected $hostname = 'localhost'; + protected $port; /** * The constructer for the UpdateConnection class. This method is also called * from the classes that extend this class and override this method. */ - function __construct($settings) { - $this->username = $settings['username']; - $this->password = $settings['password']; - $this->hostname = isset($settings['hostname']) ? $settings['hostname'] : 'localhost'; - if (isset($settings['port'])) { - $this->port = $settings['port']; - } + function __construct($jail, $username, $password, $hostname, $port) { + $this->username = $username; + $this->password = $password; + $this->hostname = $hostname; + $this->port = $port; + $this->jail = $jail; } + abstract static function factory($jail, $settings); + /** * Implementation of the magic __get() method. If the connection isn't set to * anything, this will call the connect() method and set it to and return the @@ -31,25 +37,105 @@ abstract class FileTransfer { * this method. */ function __get($name) { - static $connection; if ($name == 'connection') { - $this->connection = $this->connect(); + $this->connect(); return $this->connection; } } /** + * Connect to the server. + */ + abstract protected function connect(); + + /** + * Copies a directory. + * + * @param $source + * The source path. + * @param $destination + * The destination path. + */ + public final function copyDirectory($source, $destination) { + $this->checkPath($destination); + $this->copyDirectoryJailed($source, $destination); + } + + /** + * Creates a directory. + * + * @param $directory + * The directory to be created. + */ + public final function createDirectory($directory) { + $this->checkPath($directory); + $this->createDirectoryJailed($directory); + } + + /** + * Removes a directory. + * + * @param $directory + * The directory to be removed. + */ + public final function removeDirectory($directory) { + $this->checkPath($directory); + $this->removeDirectoryJailed($directory); + } + + /** + * Copies a file. + * + * @param $source + * The source file. + * @param $destination + * The destination file. + */ + public final function copyFile($source, $destination) { + $this->checkPath($destination); + $this->copyFileJailed($source, $destination); + } + + /** + * Removes a file. + * + * @param $destination + * The destination file to be removed. + */ + public final function removeFile($destination) { + $this->checkPath($destination); + $this->removeFileJailed($destination); + } + + /** + * Checks that the path is inside the jail and throws an exception if not. + * + * @param $path + * A path to check against the jail. + */ + protected final function checkPath($path) { + if (realpath(substr($path, 0, strlen($this->jail))) !== $this->jail) { + throw new FileTransferException('@directory is outside of the @jail', NULL, array('@directory' => $path, '@jail' => $this->jail)); + } + } + + /** * Copies a directory. * + * We need a separate method to make the $destination is in the jail. + * * @param $source * The source path. * @param $destination * The destination path. */ - protected function copyDirectory($source, $destination) { - $this->createDirectory($destination . basename($source)); + protected function copyDirectoryJailed($source, $destination) { + if ($this->isDirectory($destination)) { + $destination = $destination . '/' . basename($source); + } + $this->createDirectory($destination); foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) { - $relative_path = basename($source) . substr($filename, strlen($source)); + $relative_path = substr($filename, strlen($source)); if ($file->isDir()) { $this->createDirectory($destination . $relative_path); } @@ -65,7 +151,7 @@ abstract class FileTransfer { * @param $directory * The directory to be created. */ - abstract function createDirectory($directory); + abstract protected function createDirectoryJailed($directory); /** * Removes a directory. @@ -73,7 +159,7 @@ abstract class FileTransfer { * @param $directory * The directory to be removed. */ - abstract function removeDirectory($directory); + abstract protected function removeDirectoryJailed($directory); /** * Copies a file. @@ -83,8 +169,7 @@ abstract class FileTransfer { * @param $destination * The destination file. */ - abstract function copyFile($source, $destination); - + abstract protected function copyFileJailed($source, $destination); /** * Removes a file. @@ -92,11 +177,27 @@ abstract class FileTransfer { * @param $destination * The destination file to be removed. */ - abstract function removeFile($destination); + abstract protected function removeFileJailed($destination); + + /** + * Checks if a particular path is a directory + * + * @param $path + * The path to check + * + * @return boolean + */ + abstract public function isDirectory($path); } /** * FileTransferException class. */ class FileTransferException extends Exception { + public $arguments; + + function __construct($message, $code = 0, $arguments = array()) { + parent::__construct($message, $code); + $this->arguments = $arguments; + } } |