@@ -0,0 +1,97 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework; | |||
use OC\AppFramework\DependencyInjection\DIContainer; | |||
/** | |||
* Entry point for every request in your app. You can consider this as your | |||
* public static void main() method | |||
* | |||
* Handles all the dependency injection, controllers and output flow | |||
*/ | |||
class App { | |||
/** | |||
* Shortcut for calling a controller method and printing the result | |||
* @param string $controllerName the name of the controller under which it is | |||
* stored in the DI container | |||
* @param string $methodName the method that you want to call | |||
* @param array $urlParams an array with variables extracted from the routes | |||
* @param DIContainer $container an instance of a pimple container. | |||
*/ | |||
public static function main($controllerName, $methodName, array $urlParams, | |||
DIContainer $container) { | |||
$container['urlParams'] = $urlParams; | |||
$controller = $container[$controllerName]; | |||
// initialize the dispatcher and run all the middleware before the controller | |||
$dispatcher = $container['Dispatcher']; | |||
list($httpHeaders, $responseHeaders, $output) = | |||
$dispatcher->dispatch($controller, $methodName); | |||
if(!is_null($httpHeaders)) { | |||
header($httpHeaders); | |||
} | |||
foreach($responseHeaders as $name => $value) { | |||
header($name . ': ' . $value); | |||
} | |||
if(!is_null($output)) { | |||
header('Content-Length: ' . strlen($output)); | |||
print($output); | |||
} | |||
} | |||
/** | |||
* Shortcut for calling a controller method and printing the result. | |||
* Similar to App:main except that no headers will be sent. | |||
* This should be used for example when registering sections via | |||
* \OC\AppFramework\Core\API::registerAdmin() | |||
* | |||
* @param string $controllerName the name of the controller under which it is | |||
* stored in the DI container | |||
* @param string $methodName the method that you want to call | |||
* @param array $urlParams an array with variables extracted from the routes | |||
* @param DIContainer $container an instance of a pimple container. | |||
*/ | |||
public static function part($controllerName, $methodName, array $urlParams, | |||
DIContainer $container){ | |||
$container['urlParams'] = $urlParams; | |||
$controller = $container[$controllerName]; | |||
$dispatcher = $container['Dispatcher']; | |||
list(, , $output) = $dispatcher->dispatch($controller, $methodName); | |||
return $output; | |||
} | |||
} |
@@ -0,0 +1,154 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Controller; | |||
use OC\AppFramework\Http\TemplateResponse; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Core\API; | |||
/** | |||
* Base class to inherit your controllers from | |||
*/ | |||
abstract class Controller { | |||
/** | |||
* @var API instance of the api layer | |||
*/ | |||
protected $api; | |||
protected $request; | |||
/** | |||
* @param API $api an api wrapper instance | |||
* @param Request $request an instance of the request | |||
*/ | |||
public function __construct(API $api, Request $request){ | |||
$this->api = $api; | |||
$this->request = $request; | |||
} | |||
/** | |||
* Lets you access post and get parameters by the index | |||
* @param string $key the key which you want to access in the URL Parameter | |||
* placeholder, $_POST or $_GET array. | |||
* The priority how they're returned is the following: | |||
* 1. URL parameters | |||
* 2. POST parameters | |||
* 3. GET parameters | |||
* @param mixed $default If the key is not found, this value will be returned | |||
* @return mixed the content of the array | |||
*/ | |||
public function params($key, $default=null){ | |||
return isset($this->request->parameters[$key]) | |||
? $this->request->parameters[$key] | |||
: $default; | |||
} | |||
/** | |||
* Returns all params that were received, be it from the request | |||
* (as GET or POST) or throuh the URL by the route | |||
* @return array the array with all parameters | |||
*/ | |||
public function getParams() { | |||
return $this->request->parameters; | |||
} | |||
/** | |||
* Returns the method of the request | |||
* @return string the method of the request (POST, GET, etc) | |||
*/ | |||
public function method() { | |||
return $this->request->method; | |||
} | |||
/** | |||
* Shortcut for accessing an uploaded file through the $_FILES array | |||
* @param string $key the key that will be taken from the $_FILES array | |||
* @return array the file in the $_FILES element | |||
*/ | |||
public function getUploadedFile($key) { | |||
return isset($this->request->files[$key]) ? $this->request->files[$key] : null; | |||
} | |||
/** | |||
* Shortcut for getting env variables | |||
* @param string $key the key that will be taken from the $_ENV array | |||
* @return array the value in the $_ENV element | |||
*/ | |||
public function env($key) { | |||
return isset($this->request->env[$key]) ? $this->request->env[$key] : null; | |||
} | |||
/** | |||
* Shortcut for getting session variables | |||
* @param string $key the key that will be taken from the $_SESSION array | |||
* @return array the value in the $_SESSION element | |||
*/ | |||
public function session($key) { | |||
return isset($this->request->session[$key]) ? $this->request->session[$key] : null; | |||
} | |||
/** | |||
* Shortcut for getting cookie variables | |||
* @param string $key the key that will be taken from the $_COOKIE array | |||
* @return array the value in the $_COOKIE element | |||
*/ | |||
public function cookie($key) { | |||
return isset($this->request->cookies[$key]) ? $this->request->cookies[$key] : null; | |||
} | |||
/** | |||
* Shortcut for rendering a template | |||
* @param string $templateName the name of the template | |||
* @param array $params the template parameters in key => value structure | |||
* @param string $renderAs user renders a full page, blank only your template | |||
* admin an entry in the admin settings | |||
* @param array $headers set additional headers in name/value pairs | |||
* @return \OC\AppFramework\Http\TemplateResponse containing the page | |||
*/ | |||
public function render($templateName, array $params=array(), | |||
$renderAs='user', array $headers=array()){ | |||
$response = new TemplateResponse($this->api, $templateName); | |||
$response->setParams($params); | |||
$response->renderAs($renderAs); | |||
foreach($headers as $name => $value){ | |||
$response->addHeader($name, $value); | |||
} | |||
return $response; | |||
} | |||
} |
@@ -0,0 +1,524 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Core; | |||
/** | |||
* This is used to wrap the owncloud static api calls into an object to make the | |||
* code better abstractable for use in the dependency injection container | |||
* | |||
* Should you find yourself in need for more methods, simply inherit from this | |||
* class and add your methods | |||
*/ | |||
class API { | |||
private $appName; | |||
/** | |||
* constructor | |||
* @param string $appName the name of your application | |||
*/ | |||
public function __construct($appName){ | |||
$this->appName = $appName; | |||
} | |||
/** | |||
* used to return the appname of the set application | |||
* @return string the name of your application | |||
*/ | |||
public function getAppName(){ | |||
return $this->appName; | |||
} | |||
/** | |||
* Creates a new navigation entry | |||
* @param array $entry containing: id, name, order, icon and href key | |||
*/ | |||
public function addNavigationEntry(array $entry){ | |||
\OCP\App::addNavigationEntry($entry); | |||
} | |||
/** | |||
* Gets the userid of the current user | |||
* @return string the user id of the current user | |||
*/ | |||
public function getUserId(){ | |||
return \OCP\User::getUser(); | |||
} | |||
/** | |||
* Sets the current navigation entry to the currently running app | |||
*/ | |||
public function activateNavigationEntry(){ | |||
\OCP\App::setActiveNavigationEntry($this->appName); | |||
} | |||
/** | |||
* Adds a new javascript file | |||
* @param string $scriptName the name of the javascript in js/ without the suffix | |||
* @param string $appName the name of the app, defaults to the current one | |||
*/ | |||
public function addScript($scriptName, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
\OCP\Util::addScript($appName, $scriptName); | |||
} | |||
/** | |||
* Adds a new css file | |||
* @param string $styleName the name of the css file in css/without the suffix | |||
* @param string $appName the name of the app, defaults to the current one | |||
*/ | |||
public function addStyle($styleName, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
\OCP\Util::addStyle($appName, $styleName); | |||
} | |||
/** | |||
* shorthand for addScript for files in the 3rdparty directory | |||
* @param string $name the name of the file without the suffix | |||
*/ | |||
public function add3rdPartyScript($name){ | |||
\OCP\Util::addScript($this->appName . '/3rdparty', $name); | |||
} | |||
/** | |||
* shorthand for addStyle for files in the 3rdparty directory | |||
* @param string $name the name of the file without the suffix | |||
*/ | |||
public function add3rdPartyStyle($name){ | |||
\OCP\Util::addStyle($this->appName . '/3rdparty', $name); | |||
} | |||
/** | |||
* Looks up a systemwide defined value | |||
* @param string $key the key of the value, under which it was saved | |||
* @return string the saved value | |||
*/ | |||
public function getSystemValue($key){ | |||
return \OCP\Config::getSystemValue($key, ''); | |||
} | |||
/** | |||
* Sets a new systemwide value | |||
* @param string $key the key of the value, under which will be saved | |||
* @param string $value the value that should be stored | |||
*/ | |||
public function setSystemValue($key, $value){ | |||
return \OCP\Config::setSystemValue($key, $value); | |||
} | |||
/** | |||
* Looks up an appwide defined value | |||
* @param string $key the key of the value, under which it was saved | |||
* @return string the saved value | |||
*/ | |||
public function getAppValue($key, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
return \OCP\Config::getAppValue($appName, $key, ''); | |||
} | |||
/** | |||
* Writes a new appwide value | |||
* @param string $key the key of the value, under which will be saved | |||
* @param string $value the value that should be stored | |||
*/ | |||
public function setAppValue($key, $value, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
return \OCP\Config::setAppValue($appName, $key, $value); | |||
} | |||
/** | |||
* Shortcut for setting a user defined value | |||
* @param string $key the key under which the value is being stored | |||
* @param string $value the value that you want to store | |||
* @param string $userId the userId of the user that we want to store the value under, defaults to the current one | |||
*/ | |||
public function setUserValue($key, $value, $userId=null){ | |||
if($userId === null){ | |||
$userId = $this->getUserId(); | |||
} | |||
\OCP\Config::setUserValue($userId, $this->appName, $key, $value); | |||
} | |||
/** | |||
* Shortcut for getting a user defined value | |||
* @param string $key the key under which the value is being stored | |||
* @param string $userId the userId of the user that we want to store the value under, defaults to the current one | |||
*/ | |||
public function getUserValue($key, $userId=null){ | |||
if($userId === null){ | |||
$userId = $this->getUserId(); | |||
} | |||
return \OCP\Config::getUserValue($userId, $this->appName, $key); | |||
} | |||
/** | |||
* Returns the translation object | |||
* @return \OC_L10N the translation object | |||
*/ | |||
public function getTrans(){ | |||
# TODO: use public api | |||
return \OC_L10N::get($this->appName); | |||
} | |||
/** | |||
* Used to abstract the owncloud database access away | |||
* @param string $sql the sql query with ? placeholder for params | |||
* @param int $limit the maximum number of rows | |||
* @param int $offset from which row we want to start | |||
* @return \OCP\DB a query object | |||
*/ | |||
public function prepareQuery($sql, $limit=null, $offset=null){ | |||
return \OCP\DB::prepare($sql, $limit, $offset); | |||
} | |||
/** | |||
* Used to get the id of the just inserted element | |||
* @param string $tableName the name of the table where we inserted the item | |||
* @return int the id of the inserted element | |||
*/ | |||
public function getInsertId($tableName){ | |||
return \OCP\DB::insertid($tableName); | |||
} | |||
/** | |||
* Returns the URL for a route | |||
* @param string $routeName the name of the route | |||
* @param array $arguments an array with arguments which will be filled into the url | |||
* @return string the url | |||
*/ | |||
public function linkToRoute($routeName, $arguments=array()){ | |||
return \OCP\Util::linkToRoute($routeName, $arguments); | |||
} | |||
/** | |||
* Returns an URL for an image or file | |||
* @param string $file the name of the file | |||
* @param string $appName the name of the app, defaults to the current one | |||
*/ | |||
public function linkTo($file, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
return \OCP\Util::linkTo($appName, $file); | |||
} | |||
/** | |||
* Returns the link to an image, like link to but only with prepending img/ | |||
* @param string $file the name of the file | |||
* @param string $appName the name of the app, defaults to the current one | |||
*/ | |||
public function imagePath($file, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
return \OCP\Util::imagePath($appName, $file); | |||
} | |||
/** | |||
* Makes an URL absolute | |||
* @param string $url the url | |||
* @return string the absolute url | |||
*/ | |||
public function getAbsoluteURL($url){ | |||
# TODO: use public api | |||
return \OC_Helper::makeURLAbsolute($url); | |||
} | |||
/** | |||
* links to a file | |||
* @param string $file the name of the file | |||
* @param string $appName the name of the app, defaults to the current one | |||
* @deprecated replaced with linkToRoute() | |||
* @return string the url | |||
*/ | |||
public function linkToAbsolute($file, $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
return \OCP\Util::linkToAbsolute($appName, $file); | |||
} | |||
/** | |||
* Checks if the current user is logged in | |||
* @return bool true if logged in | |||
*/ | |||
public function isLoggedIn(){ | |||
return \OCP\User::isLoggedIn(); | |||
} | |||
/** | |||
* Checks if a user is an admin | |||
* @param string $userId the id of the user | |||
* @return bool true if admin | |||
*/ | |||
public function isAdminUser($userId){ | |||
# TODO: use public api | |||
return \OC_User::isAdminUser($userId); | |||
} | |||
/** | |||
* Checks if a user is an subadmin | |||
* @param string $userId the id of the user | |||
* @return bool true if subadmin | |||
*/ | |||
public function isSubAdminUser($userId){ | |||
# TODO: use public api | |||
return \OC_SubAdmin::isSubAdmin($userId); | |||
} | |||
/** | |||
* Checks if the CSRF check was correct | |||
* @return bool true if CSRF check passed | |||
*/ | |||
public function passesCSRFCheck(){ | |||
# TODO: use public api | |||
return \OC_Util::isCallRegistered(); | |||
} | |||
/** | |||
* Checks if an app is enabled | |||
* @param string $appName the name of an app | |||
* @return bool true if app is enabled | |||
*/ | |||
public function isAppEnabled($appName){ | |||
return \OCP\App::isEnabled($appName); | |||
} | |||
/** | |||
* Writes a function into the error log | |||
* @param string $msg the error message to be logged | |||
* @param int $level the error level | |||
*/ | |||
public function log($msg, $level=null){ | |||
switch($level){ | |||
case 'debug': | |||
$level = \OCP\Util::DEBUG; | |||
break; | |||
case 'info': | |||
$level = \OCP\Util::INFO; | |||
break; | |||
case 'warn': | |||
$level = \OCP\Util::WARN; | |||
break; | |||
case 'fatal': | |||
$level = \OCP\Util::FATAL; | |||
break; | |||
default: | |||
$level = \OCP\Util::ERROR; | |||
break; | |||
} | |||
\OCP\Util::writeLog($this->appName, $msg, $level); | |||
} | |||
/** | |||
* Returns a template | |||
* @param string $templateName the name of the template | |||
* @param string $renderAs how it should be rendered | |||
* @param string $appName the name of the app | |||
* @return \OCP\Template a new template | |||
*/ | |||
public function getTemplate($templateName, $renderAs='user', $appName=null){ | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
if($renderAs === 'blank'){ | |||
return new \OCP\Template($appName, $templateName); | |||
} else { | |||
return new \OCP\Template($appName, $templateName, $renderAs); | |||
} | |||
} | |||
/** | |||
* turns an owncloud path into a path on the filesystem | |||
* @param string path the path to the file on the oc filesystem | |||
* @return string the filepath in the filesystem | |||
*/ | |||
public function getLocalFilePath($path){ | |||
# TODO: use public api | |||
return \OC_Filesystem::getLocalFile($path); | |||
} | |||
/** | |||
* used to return and open a new eventsource | |||
* @return \OC_EventSource a new open EventSource class | |||
*/ | |||
public function openEventSource(){ | |||
# TODO: use public api | |||
return new \OC_EventSource(); | |||
} | |||
/** | |||
* @brief connects a function to a hook | |||
* @param string $signalClass class name of emitter | |||
* @param string $signalName name of signal | |||
* @param string $slotClass class name of slot | |||
* @param string $slotName name of slot, in another word, this is the | |||
* name of the method that will be called when registered | |||
* signal is emitted. | |||
* @return bool, always true | |||
*/ | |||
public function connectHook($signalClass, $signalName, $slotClass, $slotName) { | |||
return \OCP\Util::connectHook($signalClass, $signalName, $slotClass, $slotName); | |||
} | |||
/** | |||
* @brief Emits a signal. To get data from the slot use references! | |||
* @param string $signalClass class name of emitter | |||
* @param string $signalName name of signal | |||
* @param array $params defautl: array() array with additional data | |||
* @return bool, true if slots exists or false if not | |||
*/ | |||
public function emitHook($signalClass, $signalName, $params = array()) { | |||
return \OCP\Util::emitHook($signalClass, $signalName, $params); | |||
} | |||
/** | |||
* @brief clear hooks | |||
* @param string $signalClass | |||
* @param string $signalName | |||
*/ | |||
public function clearHook($signalClass=false, $signalName=false) { | |||
if ($signalClass) { | |||
\OC_Hook::clear($signalClass, $signalName); | |||
} | |||
} | |||
/** | |||
* Gets the content of an URL by using CURL or a fallback if it is not | |||
* installed | |||
* @param string $url the url that should be fetched | |||
* @return string the content of the webpage | |||
*/ | |||
public function getUrlContent($url) { | |||
return \OC_Util::getUrlContent($url); | |||
} | |||
/** | |||
* Register a backgroundjob task | |||
* @param string $className full namespace and class name of the class | |||
* @param string $methodName the name of the static method that should be | |||
* called | |||
*/ | |||
public function addRegularTask($className, $methodName) { | |||
\OCP\Backgroundjob::addRegularTask($className, $methodName); | |||
} | |||
/** | |||
* Tells ownCloud to include a template in the admin overview | |||
* @param string $mainPath the path to the main php file without the php | |||
* suffix, relative to your apps directory! not the template directory | |||
* @param string $appName the name of the app, defaults to the current one | |||
*/ | |||
public function registerAdmin($mainPath, $appName=null) { | |||
if($appName === null){ | |||
$appName = $this->appName; | |||
} | |||
\OCP\App::registerAdmin($appName, $mainPath); | |||
} | |||
/** | |||
* Do a user login | |||
* @param string $user the username | |||
* @param string $password the password | |||
* @return bool true if successful | |||
*/ | |||
public function login($user, $password) { | |||
return \OC_User::login($user, $password); | |||
} | |||
/** | |||
* @brief Loggs the user out including all the session data | |||
* Logout, destroys session | |||
*/ | |||
public function logout() { | |||
return \OCP\User::logout(); | |||
} | |||
/** | |||
* get the filesystem info | |||
* | |||
* @param string $path | |||
* @return array with the following keys: | |||
* - size | |||
* - mtime | |||
* - mimetype | |||
* - encrypted | |||
* - versioned | |||
*/ | |||
public function getFileInfo($path) { | |||
return \OC\Files\Filesystem::getFileInfo($path); | |||
} | |||
/** | |||
* get the view | |||
* | |||
* @return OC\Files\View instance | |||
*/ | |||
public function getView() { | |||
return \OC\Files\Filesystem::getView(); | |||
} | |||
} |
@@ -0,0 +1,125 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\DependencyInjection; | |||
use OC\AppFramework\Http\Http; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Http\Dispatcher; | |||
use OC\AppFramework\Core\API; | |||
use OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
use OC\AppFramework\Middleware\Http\HttpMiddleware; | |||
use OC\AppFramework\Middleware\Security\SecurityMiddleware; | |||
use OC\AppFramework\Utility\TimeFactory; | |||
// register 3rdparty autoloaders | |||
require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; | |||
/** | |||
* This class extends Pimple (http://pimple.sensiolabs.org/) for reusability | |||
* To use this class, extend your own container from this. Should you require it | |||
* you can overwrite the dependencies with your own classes by simply redefining | |||
* a dependency | |||
*/ | |||
class DIContainer extends \Pimple { | |||
/** | |||
* Put your class dependencies in here | |||
* @param string $appName the name of the app | |||
*/ | |||
public function __construct($appName){ | |||
$this['AppName'] = $appName; | |||
$this['API'] = $this->share(function($c){ | |||
return new API($c['AppName']); | |||
}); | |||
/** | |||
* Http | |||
*/ | |||
$this['Request'] = $this->share(function($c) { | |||
$params = json_decode(file_get_contents('php://input'), true); | |||
$params = is_array($params) ? $params: array(); | |||
return new Request( | |||
array( | |||
'get' => $_GET, | |||
'post' => $_POST, | |||
'files' => $_FILES, | |||
'server' => $_SERVER, | |||
'env' => $_ENV, | |||
'session' => $_SESSION, | |||
'cookies' => $_COOKIE, | |||
'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) | |||
? $_SERVER['REQUEST_METHOD'] | |||
: null, | |||
'params' => $params, | |||
'urlParams' => $c['urlParams'] | |||
) | |||
); | |||
}); | |||
$this['Protocol'] = $this->share(function($c){ | |||
if(isset($_SERVER['SERVER_PROTOCOL'])) { | |||
return new Http($_SERVER, $_SERVER['SERVER_PROTOCOL']); | |||
} else { | |||
return new Http($_SERVER); | |||
} | |||
}); | |||
$this['Dispatcher'] = $this->share(function($c) { | |||
return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']); | |||
}); | |||
/** | |||
* Middleware | |||
*/ | |||
$this['SecurityMiddleware'] = $this->share(function($c){ | |||
return new SecurityMiddleware($c['API'], $c['Request']); | |||
}); | |||
$this['MiddlewareDispatcher'] = $this->share(function($c){ | |||
$dispatcher = new MiddlewareDispatcher(); | |||
$dispatcher->registerMiddleware($c['SecurityMiddleware']); | |||
return $dispatcher; | |||
}); | |||
/** | |||
* Utilities | |||
*/ | |||
$this['TimeFactory'] = $this->share(function($c){ | |||
return new TimeFactory(); | |||
}); | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
use \OC\AppFramework\Controller\Controller; | |||
use \OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
/** | |||
* Class to dispatch the request to the middleware disptacher | |||
*/ | |||
class Dispatcher { | |||
private $middlewareDispatcher; | |||
private $protocol; | |||
/** | |||
* @param Http $protocol the http protocol with contains all status headers | |||
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which | |||
* runs the middleware | |||
*/ | |||
public function __construct(Http $protocol, | |||
MiddlewareDispatcher $middlewareDispatcher) { | |||
$this->protocol = $protocol; | |||
$this->middlewareDispatcher = $middlewareDispatcher; | |||
} | |||
/** | |||
* Handles a request and calls the dispatcher on the controller | |||
* @param Controller $controller the controller which will be called | |||
* @param string $methodName the method name which will be called on | |||
* the controller | |||
* @return array $array[0] contains a string with the http main header, | |||
* $array[1] contains headers in the form: $key => value, $array[2] contains | |||
* the response output | |||
*/ | |||
public function dispatch(Controller $controller, $methodName) { | |||
$out = array(null, array(), null); | |||
try { | |||
$this->middlewareDispatcher->beforeController($controller, | |||
$methodName); | |||
$response = $controller->$methodName(); | |||
// if an exception appears, the middleware checks if it can handle the | |||
// exception and creates a response. If no response is created, it is | |||
// assumed that theres no middleware who can handle it and the error is | |||
// thrown again | |||
} catch(\Exception $exception){ | |||
$response = $this->middlewareDispatcher->afterException( | |||
$controller, $methodName, $exception); | |||
} | |||
$response = $this->middlewareDispatcher->afterController( | |||
$controller, $methodName, $response); | |||
// get the output which should be printed and run the after output | |||
// middleware to modify the response | |||
$output = $response->render(); | |||
$out[2] = $this->middlewareDispatcher->beforeOutput( | |||
$controller, $methodName, $output); | |||
// depending on the cache object the headers need to be changed | |||
$out[0] = $this->protocol->getStatusHeader($response->getStatus(), | |||
$response->getLastModified(), $response->getETag()); | |||
$out[1] = $response->getHeaders(); | |||
return $out; | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
/** | |||
* Prompts the user to download the a file | |||
*/ | |||
abstract class DownloadResponse extends Response { | |||
private $content; | |||
private $filename; | |||
private $contentType; | |||
/** | |||
* Creates a response that prompts the user to download the file | |||
* @param string $filename the name that the downloaded file should have | |||
* @param string $contentType the mimetype that the downloaded file should have | |||
*/ | |||
public function __construct($filename, $contentType) { | |||
$this->filename = $filename; | |||
$this->contentType = $contentType; | |||
$this->addHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); | |||
$this->addHeader('Content-Type', $contentType); | |||
} | |||
} |
@@ -0,0 +1,208 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
class Http { | |||
const STATUS_CONTINUE = 100; | |||
const STATUS_SWITCHING_PROTOCOLS = 101; | |||
const STATUS_PROCESSING = 102; | |||
const STATUS_OK = 200; | |||
const STATUS_CREATED = 201; | |||
const STATUS_ACCEPTED = 202; | |||
const STATUS_NON_AUTHORATIVE_INFORMATION = 203; | |||
const STATUS_NO_CONTENT = 204; | |||
const STATUS_RESET_CONTENT = 205; | |||
const STATUS_PARTIAL_CONTENT = 206; | |||
const STATUS_MULTI_STATUS = 207; | |||
const STATUS_ALREADY_REPORTED = 208; | |||
const STATUS_IM_USED = 226; | |||
const STATUS_MULTIPLE_CHOICES = 300; | |||
const STATUS_MOVED_PERMANENTLY = 301; | |||
const STATUS_FOUND = 302; | |||
const STATUS_SEE_OTHER = 303; | |||
const STATUS_NOT_MODIFIED = 304; | |||
const STATUS_USE_PROXY = 305; | |||
const STATUS_RESERVED = 306; | |||
const STATUS_TEMPORARY_REDIRECT = 307; | |||
const STATUS_BAD_REQUEST = 400; | |||
const STATUS_UNAUTHORIZED = 401; | |||
const STATUS_PAYMENT_REQUIRED = 402; | |||
const STATUS_FORBIDDEN = 403; | |||
const STATUS_NOT_FOUND = 404; | |||
const STATUS_METHOD_NOT_ALLOWED = 405; | |||
const STATUS_NOT_ACCEPTABLE = 406; | |||
const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; | |||
const STATUS_REQUEST_TIMEOUT = 408; | |||
const STATUS_CONFLICT = 409; | |||
const STATUS_GONE = 410; | |||
const STATUS_LENGTH_REQUIRED = 411; | |||
const STATUS_PRECONDITION_FAILED = 412; | |||
const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; | |||
const STATUS_REQUEST_URI_TOO_LONG = 414; | |||
const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; | |||
const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; | |||
const STATUS_EXPECTATION_FAILED = 417; | |||
const STATUS_IM_A_TEAPOT = 418; | |||
const STATUS_UNPROCESSABLE_ENTITY = 422; | |||
const STATUS_LOCKED = 423; | |||
const STATUS_FAILED_DEPENDENCY = 424; | |||
const STATUS_UPGRADE_REQUIRED = 426; | |||
const STATUS_PRECONDITION_REQUIRED = 428; | |||
const STATUS_TOO_MANY_REQUESTS = 429; | |||
const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; | |||
const STATUS_INTERNAL_SERVER_ERROR = 500; | |||
const STATUS_NOT_IMPLEMENTED = 501; | |||
const STATUS_BAD_GATEWAY = 502; | |||
const STATUS_SERVICE_UNAVAILABLE = 503; | |||
const STATUS_GATEWAY_TIMEOUT = 504; | |||
const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; | |||
const STATUS_VARIANT_ALSO_NEGOTIATES = 506; | |||
const STATUS_INSUFFICIENT_STORAGE = 507; | |||
const STATUS_LOOP_DETECTED = 508; | |||
const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; | |||
const STATUS_NOT_EXTENDED = 510; | |||
const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; | |||
private $server; | |||
private $protocolVersion; | |||
protected $headers; | |||
/** | |||
* @param $_SERVER $server | |||
* @param string $protocolVersion the http version to use defaults to HTTP/1.1 | |||
*/ | |||
public function __construct($server, $protocolVersion='HTTP/1.1') { | |||
$this->server = $server; | |||
$this->protocolVersion = $protocolVersion; | |||
$this->headers = array( | |||
self::STATUS_CONTINUE => 'Continue', | |||
self::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols', | |||
self::STATUS_PROCESSING => 'Processing', | |||
self::STATUS_OK => 'OK', | |||
self::STATUS_CREATED => 'Created', | |||
self::STATUS_ACCEPTED => 'Accepted', | |||
self::STATUS_NON_AUTHORATIVE_INFORMATION => 'Non-Authorative Information', | |||
self::STATUS_NO_CONTENT => 'No Content', | |||
self::STATUS_RESET_CONTENT => 'Reset Content', | |||
self::STATUS_PARTIAL_CONTENT => 'Partial Content', | |||
self::STATUS_MULTI_STATUS => 'Multi-Status', // RFC 4918 | |||
self::STATUS_ALREADY_REPORTED => 'Already Reported', // RFC 5842 | |||
self::STATUS_IM_USED => 'IM Used', // RFC 3229 | |||
self::STATUS_MULTIPLE_CHOICES => 'Multiple Choices', | |||
self::STATUS_MOVED_PERMANENTLY => 'Moved Permanently', | |||
self::STATUS_FOUND => 'Found', | |||
self::STATUS_SEE_OTHER => 'See Other', | |||
self::STATUS_NOT_MODIFIED => 'Not Modified', | |||
self::STATUS_USE_PROXY => 'Use Proxy', | |||
self::STATUS_RESERVED => 'Reserved', | |||
self::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect', | |||
self::STATUS_BAD_REQUEST => 'Bad request', | |||
self::STATUS_UNAUTHORIZED => 'Unauthorized', | |||
self::STATUS_PAYMENT_REQUIRED => 'Payment Required', | |||
self::STATUS_FORBIDDEN => 'Forbidden', | |||
self::STATUS_NOT_FOUND => 'Not Found', | |||
self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed', | |||
self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable', | |||
self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required', | |||
self::STATUS_REQUEST_TIMEOUT => 'Request Timeout', | |||
self::STATUS_CONFLICT => 'Conflict', | |||
self::STATUS_GONE => 'Gone', | |||
self::STATUS_LENGTH_REQUIRED => 'Length Required', | |||
self::STATUS_PRECONDITION_FAILED => 'Precondition failed', | |||
self::STATUS_REQUEST_ENTITY_TOO_LARGE => 'Request Entity Too Large', | |||
self::STATUS_REQUEST_URI_TOO_LONG => 'Request-URI Too Long', | |||
self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type', | |||
self::STATUS_REQUEST_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable', | |||
self::STATUS_EXPECTATION_FAILED => 'Expectation Failed', | |||
self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', // RFC 2324 | |||
self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', // RFC 4918 | |||
self::STATUS_LOCKED => 'Locked', // RFC 4918 | |||
self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', // RFC 4918 | |||
self::STATUS_UPGRADE_REQUIRED => 'Upgrade required', | |||
self::STATUS_PRECONDITION_REQUIRED => 'Precondition required', // draft-nottingham-http-new-status | |||
self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', // draft-nottingham-http-new-status | |||
self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', // draft-nottingham-http-new-status | |||
self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error', | |||
self::STATUS_NOT_IMPLEMENTED => 'Not Implemented', | |||
self::STATUS_BAD_GATEWAY => 'Bad Gateway', | |||
self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable', | |||
self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout', | |||
self::STATUS_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version not supported', | |||
self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates', | |||
self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', // RFC 4918 | |||
self::STATUS_LOOP_DETECTED => 'Loop Detected', // RFC 5842 | |||
self::STATUS_BANDWIDTH_LIMIT_EXCEEDED => 'Bandwidth Limit Exceeded', // non-standard | |||
self::STATUS_NOT_EXTENDED => 'Not extended', | |||
self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', // draft-nottingham-http-new-status | |||
); | |||
} | |||
/** | |||
* Gets the correct header | |||
* @param Http::CONSTANT $status the constant from the Http class | |||
* @param \DateTime $lastModified formatted last modified date | |||
* @param string $Etag the etag | |||
*/ | |||
public function getStatusHeader($status, \DateTime $lastModified=null, | |||
$ETag=null) { | |||
if(!is_null($lastModified)) { | |||
$lastModified = $lastModified->format(\DateTime::RFC2822); | |||
} | |||
// if etag or lastmodified have not changed, return a not modified | |||
if ((isset($this->server['HTTP_IF_NONE_MATCH']) | |||
&& trim($this->server['HTTP_IF_NONE_MATCH']) === $ETag) | |||
|| | |||
(isset($this->server['HTTP_IF_MODIFIED_SINCE']) | |||
&& trim($this->server['HTTP_IF_MODIFIED_SINCE']) === | |||
$lastModified)) { | |||
$status = self::STATUS_NOT_MODIFIED; | |||
} | |||
// we have one change currently for the http 1.0 header that differs | |||
// from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND | |||
// if this differs any more, we want to create childclasses for this | |||
if($status === self::STATUS_TEMPORARY_REDIRECT | |||
&& $this->protocolVersion === 'HTTP/1.0') { | |||
$status = self::STATUS_FOUND; | |||
} | |||
return $this->protocolVersion . ' ' . $status . ' ' . | |||
$this->headers[$status]; | |||
} | |||
} | |||
@@ -0,0 +1,74 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
/** | |||
* A renderer for JSON calls | |||
*/ | |||
class JSONResponse extends Response { | |||
protected $data; | |||
/** | |||
* @param array|object $data the object or array that should be transformed | |||
* @param int $statusCode the Http status code, defaults to 200 | |||
*/ | |||
public function __construct($data=array(), $statusCode=Http::STATUS_OK) { | |||
$this->data = $data; | |||
$this->setStatus($statusCode); | |||
$this->addHeader('X-Content-Type-Options', 'nosniff'); | |||
$this->addHeader('Content-type', 'application/json; charset=utf-8'); | |||
} | |||
/** | |||
* Returns the rendered json | |||
* @return string the rendered json | |||
*/ | |||
public function render(){ | |||
return json_encode($this->data); | |||
} | |||
/** | |||
* Sets values in the data json array | |||
* @param array|object $params an array or object which will be transformed | |||
* to JSON | |||
*/ | |||
public function setData($data){ | |||
$this->data = $data; | |||
} | |||
/** | |||
* Used to get the set parameters | |||
* @return array the data | |||
*/ | |||
public function getData(){ | |||
return $this->data; | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
/** | |||
* Redirects to a different URL | |||
*/ | |||
class RedirectResponse extends Response { | |||
private $redirectURL; | |||
/** | |||
* Creates a response that redirects to a url | |||
* @param string $redirectURL the url to redirect to | |||
*/ | |||
public function __construct($redirectURL) { | |||
$this->redirectURL = $redirectURL; | |||
$this->setStatus(Http::STATUS_TEMPORARY_REDIRECT); | |||
$this->addHeader('Location', $redirectURL); | |||
} | |||
/** | |||
* @return string the url to redirect | |||
*/ | |||
public function getRedirectURL() { | |||
return $this->redirectURL; | |||
} | |||
} |
@@ -0,0 +1,217 @@ | |||
<?php | |||
/** | |||
* ownCloud - Request | |||
* | |||
* @author Thomas Tanghus | |||
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net) | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
/** | |||
* Class for accessing variables in the request. | |||
* This class provides an immutable object with request variables. | |||
*/ | |||
class Request implements \ArrayAccess, \Countable { | |||
protected $items = array(); | |||
protected $allowedKeys = array( | |||
'get', | |||
'post', | |||
'files', | |||
'server', | |||
'env', | |||
'session', | |||
'cookies', | |||
'urlParams', | |||
'params', | |||
'parameters', | |||
'method' | |||
); | |||
/** | |||
* @param array $vars An associative array with the following optional values: | |||
* @param array 'params' the parsed json array | |||
* @param array 'urlParams' the parameters which were matched from the URL | |||
* @param array 'get' the $_GET array | |||
* @param array 'post' the $_POST array | |||
* @param array 'files' the $_FILES array | |||
* @param array 'server' the $_SERVER array | |||
* @param array 'env' the $_ENV array | |||
* @param array 'session' the $_SESSION array | |||
* @param array 'cookies' the $_COOKIE array | |||
* @param string 'method' the request method (GET, POST etc) | |||
* @see http://www.php.net/manual/en/reserved.variables.php | |||
*/ | |||
public function __construct(array $vars=array()) { | |||
foreach($this->allowedKeys as $name) { | |||
$this->items[$name] = isset($vars[$name]) | |||
? $vars[$name] | |||
: array(); | |||
} | |||
$this->items['parameters'] = array_merge( | |||
$this->items['params'], | |||
$this->items['get'], | |||
$this->items['post'], | |||
$this->items['urlParams'] | |||
); | |||
} | |||
// Countable method. | |||
public function count() { | |||
return count(array_keys($this->items['parameters'])); | |||
} | |||
/** | |||
* ArrayAccess methods | |||
* | |||
* Gives access to the combined GET, POST and urlParams arrays | |||
* | |||
* Examples: | |||
* | |||
* $var = $request['myvar']; | |||
* | |||
* or | |||
* | |||
* if(!isset($request['myvar']) { | |||
* // Do something | |||
* } | |||
* | |||
* $request['myvar'] = 'something'; // This throws an exception. | |||
* | |||
* @param string $offset The key to lookup | |||
* @return string|null | |||
*/ | |||
public function offsetExists($offset) { | |||
return isset($this->items['parameters'][$offset]); | |||
} | |||
/** | |||
* @see offsetExists | |||
*/ | |||
public function offsetGet($offset) { | |||
return isset($this->items['parameters'][$offset]) | |||
? $this->items['parameters'][$offset] | |||
: null; | |||
} | |||
/** | |||
* @see offsetExists | |||
*/ | |||
public function offsetSet($offset, $value) { | |||
throw new \RuntimeException('You cannot change the contents of the request object'); | |||
} | |||
/** | |||
* @see offsetExists | |||
*/ | |||
public function offsetUnset($offset) { | |||
throw new \RuntimeException('You cannot change the contents of the request object'); | |||
} | |||
// Magic property accessors | |||
public function __set($name, $value) { | |||
throw new \RuntimeException('You cannot change the contents of the request object'); | |||
} | |||
/** | |||
* Access request variables by method and name. | |||
* Examples: | |||
* | |||
* $request->post['myvar']; // Only look for POST variables | |||
* $request->myvar; or $request->{'myvar'}; or $request->{$myvar} | |||
* Looks in the combined GET, POST and urlParams array. | |||
* | |||
* if($request->method !== 'POST') { | |||
* throw new Exception('This function can only be invoked using POST'); | |||
* } | |||
* | |||
* @param string $name The key to look for. | |||
* @return mixed|null | |||
*/ | |||
public function __get($name) { | |||
switch($name) { | |||
case 'get': | |||
case 'post': | |||
case 'files': | |||
case 'server': | |||
case 'env': | |||
case 'session': | |||
case 'cookies': | |||
case 'parameters': | |||
case 'params': | |||
case 'urlParams': | |||
return isset($this->items[$name]) | |||
? $this->items[$name] | |||
: null; | |||
break; | |||
case 'method': | |||
return $this->items['method']; | |||
break; | |||
default; | |||
return isset($this[$name]) | |||
? $this[$name] | |||
: null; | |||
break; | |||
} | |||
} | |||
public function __isset($name) { | |||
return isset($this->items['parameters'][$name]); | |||
} | |||
public function __unset($id) { | |||
throw new \RunTimeException('You cannot change the contents of the request object'); | |||
} | |||
/** | |||
* Returns the value for a specific http header. | |||
* | |||
* This method returns null if the header did not exist. | |||
* | |||
* @param string $name | |||
* @return string | |||
*/ | |||
public function getHeader($name) { | |||
$name = strtoupper(str_replace(array('-'),array('_'),$name)); | |||
if (isset($this->server['HTTP_' . $name])) { | |||
return $this->server['HTTP_' . $name]; | |||
} | |||
// There's a few headers that seem to end up in the top-level | |||
// server array. | |||
switch($name) { | |||
case 'CONTENT_TYPE' : | |||
case 'CONTENT_LENGTH' : | |||
if (isset($this->server[$name])) { | |||
return $this->server[$name]; | |||
} | |||
break; | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,169 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
/** | |||
* Base class for responses. Also used to just send headers | |||
*/ | |||
class Response { | |||
/** | |||
* @var array default headers | |||
*/ | |||
private $headers = array( | |||
'Cache-Control' => 'no-cache, must-revalidate' | |||
); | |||
/** | |||
* @var string | |||
*/ | |||
private $status = Http::STATUS_OK; | |||
/** | |||
* @var \DateTime | |||
*/ | |||
private $lastModified; | |||
/** | |||
* @var string | |||
*/ | |||
private $ETag; | |||
/** | |||
* Caches the response | |||
* @param int $cacheSeconds the amount of seconds that should be cached | |||
* if 0 then caching will be disabled | |||
*/ | |||
public function cacheFor($cacheSeconds) { | |||
if($cacheSeconds > 0) { | |||
$this->addHeader('Cache-Control', 'max-age=' . $cacheSeconds . | |||
', must-revalidate'); | |||
} else { | |||
$this->addHeader('Cache-Control', 'no-cache, must-revalidate'); | |||
} | |||
} | |||
/** | |||
* Adds a new header to the response that will be called before the render | |||
* function | |||
* @param string $name The name of the HTTP header | |||
* @param string $value The value, null will delete it | |||
*/ | |||
public function addHeader($name, $value) { | |||
if(is_null($value)) { | |||
unset($this->headers[$name]); | |||
} else { | |||
$this->headers[$name] = $value; | |||
} | |||
} | |||
/** | |||
* Returns the set headers | |||
* @return array the headers | |||
*/ | |||
public function getHeaders() { | |||
$mergeWith = array(); | |||
if($this->lastModified) { | |||
$mergeWith['Last-Modified'] = | |||
$this->lastModified->format(\DateTime::RFC2822); | |||
} | |||
if($this->ETag) { | |||
$mergeWith['ETag'] = '"' . $this->ETag . '"'; | |||
} | |||
return array_merge($mergeWith, $this->headers); | |||
} | |||
/** | |||
* By default renders no output | |||
* @return null | |||
*/ | |||
public function render() { | |||
return null; | |||
} | |||
/** | |||
* Set response status | |||
* @param int $status a HTTP status code, see also the STATUS constants | |||
*/ | |||
public function setStatus($status) { | |||
$this->status = $status; | |||
} | |||
/** | |||
* Get response status | |||
*/ | |||
public function getStatus() { | |||
return $this->status; | |||
} | |||
/** | |||
* @return string the etag | |||
*/ | |||
public function getETag() { | |||
return $this->ETag; | |||
} | |||
/** | |||
* @return string RFC2822 formatted last modified date | |||
*/ | |||
public function getLastModified() { | |||
return $this->lastModified; | |||
} | |||
/** | |||
* @param string $ETag | |||
*/ | |||
public function setETag($ETag) { | |||
$this->ETag = $ETag; | |||
} | |||
/** | |||
* @param \DateTime $lastModified | |||
*/ | |||
public function setLastModified($lastModified) { | |||
$this->lastModified = $lastModified; | |||
} | |||
} |
@@ -0,0 +1,126 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
use OC\AppFramework\Core\API; | |||
/** | |||
* Response for a normal template | |||
*/ | |||
class TemplateResponse extends Response { | |||
protected $templateName; | |||
protected $params; | |||
protected $api; | |||
protected $renderAs; | |||
protected $appName; | |||
/** | |||
* @param API $api an API instance | |||
* @param string $templateName the name of the template | |||
* @param string $appName optional if you want to include a template from | |||
* a different app | |||
*/ | |||
public function __construct(API $api, $templateName, $appName=null) { | |||
$this->templateName = $templateName; | |||
$this->appName = $appName; | |||
$this->api = $api; | |||
$this->params = array(); | |||
$this->renderAs = 'user'; | |||
} | |||
/** | |||
* Sets template parameters | |||
* @param array $params an array with key => value structure which sets template | |||
* variables | |||
*/ | |||
public function setParams(array $params){ | |||
$this->params = $params; | |||
} | |||
/** | |||
* Used for accessing the set parameters | |||
* @return array the params | |||
*/ | |||
public function getParams(){ | |||
return $this->params; | |||
} | |||
/** | |||
* Used for accessing the name of the set template | |||
* @return string the name of the used template | |||
*/ | |||
public function getTemplateName(){ | |||
return $this->templateName; | |||
} | |||
/** | |||
* Sets the template page | |||
* @param string $renderAs admin, user or blank. Admin also prints the admin | |||
* settings header and footer, user renders the normal | |||
* normal page including footer and header and blank | |||
* just renders the plain template | |||
*/ | |||
public function renderAs($renderAs){ | |||
$this->renderAs = $renderAs; | |||
} | |||
/** | |||
* Returns the set renderAs | |||
* @return string the renderAs value | |||
*/ | |||
public function getRenderAs(){ | |||
return $this->renderAs; | |||
} | |||
/** | |||
* Returns the rendered html | |||
* @return string the rendered html | |||
*/ | |||
public function render(){ | |||
if($this->appName !== null){ | |||
$appName = $this->appName; | |||
} else { | |||
$appName = $this->api->getAppName(); | |||
} | |||
$template = $this->api->getTemplate($this->templateName, $this->renderAs, $appName); | |||
foreach($this->params as $key => $value){ | |||
$template->assign($key, $value); | |||
} | |||
return $template->fetchPage(); | |||
} | |||
} |
@@ -0,0 +1,100 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Middleware; | |||
use OC\AppFramework\Http\Response; | |||
/** | |||
* Middleware is used to provide hooks before or after controller methods and | |||
* deal with possible exceptions raised in the controller methods. | |||
* They're modeled after Django's middleware system: | |||
* https://docs.djangoproject.com/en/dev/topics/http/middleware/ | |||
*/ | |||
abstract class Middleware { | |||
/** | |||
* This is being run in normal order before the controller is being | |||
* called which allows several modifications and checks | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
*/ | |||
public function beforeController($controller, $methodName){ | |||
} | |||
/** | |||
* This is being run when either the beforeController method or the | |||
* controller method itself is throwing an exception. The middleware is | |||
* asked in reverse order to handle the exception and to return a response. | |||
* If the response is null, it is assumed that the exception could not be | |||
* handled and the error will be thrown again | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param \Exception $exception the thrown exception | |||
* @throws \Exception the passed in exception if it cant handle it | |||
* @return Response a Response object in case that the exception was handled | |||
*/ | |||
public function afterException($controller, $methodName, \Exception $exception){ | |||
throw $exception; | |||
} | |||
/** | |||
* This is being run after a successful controllermethod call and allows | |||
* the manipulation of a Response object. The middleware is run in reverse order | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param Response $response the generated response from the controller | |||
* @return Response a Response object | |||
*/ | |||
public function afterController($controller, $methodName, Response $response){ | |||
return $response; | |||
} | |||
/** | |||
* This is being run after the response object has been rendered and | |||
* allows the manipulation of the output. The middleware is run in reverse order | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param string $output the generated output from a response | |||
* @return string the output that should be printed | |||
*/ | |||
public function beforeOutput($controller, $methodName, $output){ | |||
return $output; | |||
} | |||
} |
@@ -0,0 +1,159 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Middleware; | |||
use OC\AppFramework\Controller\Controller; | |||
use OC\AppFramework\Http\Response; | |||
/** | |||
* This class is used to store and run all the middleware in correct order | |||
*/ | |||
class MiddlewareDispatcher { | |||
/** | |||
* @var array array containing all the middlewares | |||
*/ | |||
private $middlewares; | |||
/** | |||
* @var int counter which tells us what middlware was executed once an | |||
* exception occurs | |||
*/ | |||
private $middlewareCounter; | |||
/** | |||
* Constructor | |||
*/ | |||
public function __construct(){ | |||
$this->middlewares = array(); | |||
$this->middlewareCounter = 0; | |||
} | |||
/** | |||
* Adds a new middleware | |||
* @param Middleware $middleware the middleware which will be added | |||
*/ | |||
public function registerMiddleware(Middleware $middleWare){ | |||
array_push($this->middlewares, $middleWare); | |||
} | |||
/** | |||
* returns an array with all middleware elements | |||
* @return array the middlewares | |||
*/ | |||
public function getMiddlewares(){ | |||
return $this->middlewares; | |||
} | |||
/** | |||
* This is being run in normal order before the controller is being | |||
* called which allows several modifications and checks | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
*/ | |||
public function beforeController(Controller $controller, $methodName){ | |||
// we need to count so that we know which middlewares we have to ask in | |||
// case theres an exception | |||
for($i=0; $i<count($this->middlewares); $i++){ | |||
$this->middlewareCounter++; | |||
$middleware = $this->middlewares[$i]; | |||
$middleware->beforeController($controller, $methodName); | |||
} | |||
} | |||
/** | |||
* This is being run when either the beforeController method or the | |||
* controller method itself is throwing an exception. The middleware is asked | |||
* in reverse order to handle the exception and to return a response. | |||
* If the response is null, it is assumed that the exception could not be | |||
* handled and the error will be thrown again | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param \Exception $exception the thrown exception | |||
* @return Response a Response object if the middleware can handle the | |||
* exception | |||
* @throws \Exception the passed in exception if it cant handle it | |||
*/ | |||
public function afterException(Controller $controller, $methodName, \Exception $exception){ | |||
for($i=$this->middlewareCounter-1; $i>=0; $i--){ | |||
$middleware = $this->middlewares[$i]; | |||
try { | |||
return $middleware->afterException($controller, $methodName, $exception); | |||
} catch(\Exception $exception){ | |||
continue; | |||
} | |||
} | |||
throw $exception; | |||
} | |||
/** | |||
* This is being run after a successful controllermethod call and allows | |||
* the manipulation of a Response object. The middleware is run in reverse order | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param Response $response the generated response from the controller | |||
* @return Response a Response object | |||
*/ | |||
public function afterController(Controller $controller, $methodName, Response $response){ | |||
for($i=count($this->middlewares)-1; $i>=0; $i--){ | |||
$middleware = $this->middlewares[$i]; | |||
$response = $middleware->afterController($controller, $methodName, $response); | |||
} | |||
return $response; | |||
} | |||
/** | |||
* This is being run after the response object has been rendered and | |||
* allows the manipulation of the output. The middleware is run in reverse order | |||
* | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param string $output the generated output from a response | |||
* @return string the output that should be printed | |||
*/ | |||
public function beforeOutput(Controller $controller, $methodName, $output){ | |||
for($i=count($this->middlewares)-1; $i>=0; $i--){ | |||
$middleware = $this->middlewares[$i]; | |||
$output = $middleware->beforeOutput($controller, $methodName, $output); | |||
} | |||
return $output; | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Middleware\Security; | |||
/** | |||
* Thrown when the security middleware encounters a security problem | |||
*/ | |||
class SecurityException extends \Exception { | |||
/** | |||
* @param string $msg the security error message | |||
* @param bool $ajax true if it resulted because of an ajax request | |||
*/ | |||
public function __construct($msg, $code = 0) { | |||
parent::__construct($msg, $code); | |||
} | |||
} |
@@ -0,0 +1,141 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Middleware\Security; | |||
use OC\AppFramework\Controller\Controller; | |||
use OC\AppFramework\Http\Http; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Http\Response; | |||
use OC\AppFramework\Http\JSONResponse; | |||
use OC\AppFramework\Http\RedirectResponse; | |||
use OC\AppFramework\Utility\MethodAnnotationReader; | |||
use OC\AppFramework\Middleware\Middleware; | |||
use OC\AppFramework\Core\API; | |||
/** | |||
* Used to do all the authentication and checking stuff for a controller method | |||
* It reads out the annotations of a controller method and checks which if | |||
* security things should be checked and also handles errors in case a security | |||
* check fails | |||
*/ | |||
class SecurityMiddleware extends Middleware { | |||
private $api; | |||
/** | |||
* @var \OC\AppFramework\Http\Request | |||
*/ | |||
private $request; | |||
/** | |||
* @param API $api an instance of the api | |||
*/ | |||
public function __construct(API $api, Request $request){ | |||
$this->api = $api; | |||
$this->request = $request; | |||
} | |||
/** | |||
* This runs all the security checks before a method call. The | |||
* security checks are determined by inspecting the controller method | |||
* annotations | |||
* @param string/Controller $controller the controllername or string | |||
* @param string $methodName the name of the method | |||
* @throws SecurityException when a security check fails | |||
*/ | |||
public function beforeController($controller, $methodName){ | |||
// get annotations from comments | |||
$annotationReader = new MethodAnnotationReader($controller, $methodName); | |||
// this will set the current navigation entry of the app, use this only | |||
// for normal HTML requests and not for AJAX requests | |||
$this->api->activateNavigationEntry(); | |||
// security checks | |||
if(!$annotationReader->hasAnnotation('IsLoggedInExemption')) { | |||
if(!$this->api->isLoggedIn()) { | |||
throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); | |||
} | |||
} | |||
if(!$annotationReader->hasAnnotation('IsAdminExemption')) { | |||
if(!$this->api->isAdminUser($this->api->getUserId())) { | |||
throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); | |||
} | |||
} | |||
if(!$annotationReader->hasAnnotation('IsSubAdminExemption')) { | |||
if(!$this->api->isSubAdminUser($this->api->getUserId())) { | |||
throw new SecurityException('Logged in user must be a subadmin', Http::STATUS_FORBIDDEN); | |||
} | |||
} | |||
if(!$annotationReader->hasAnnotation('CSRFExemption')) { | |||
if(!$this->api->passesCSRFCheck()) { | |||
throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); | |||
} | |||
} | |||
} | |||
/** | |||
* If an SecurityException is being caught, ajax requests return a JSON error | |||
* response and non ajax requests redirect to the index | |||
* @param Controller $controller the controller that is being called | |||
* @param string $methodName the name of the method that will be called on | |||
* the controller | |||
* @param \Exception $exception the thrown exception | |||
* @throws \Exception the passed in exception if it cant handle it | |||
* @return Response a Response object or null in case that the exception could not be handled | |||
*/ | |||
public function afterException($controller, $methodName, \Exception $exception){ | |||
if($exception instanceof SecurityException){ | |||
if (stripos($this->request->getHeader('Accept'),'html')===false) { | |||
$response = new JSONResponse( | |||
array('message' => $exception->getMessage()), | |||
$exception->getCode() | |||
); | |||
$this->api->log($exception->getMessage(), 'debug'); | |||
} else { | |||
$url = $this->api->linkToAbsolute('index.php', ''); // TODO: replace with link to route | |||
$response = new RedirectResponse($url); | |||
$this->api->log($exception->getMessage(), 'debug'); | |||
} | |||
return $response; | |||
} | |||
throw $exception; | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Thomas Müller | |||
* @copyright 2013 Thomas Müller thomas.mueller@tmit.eu | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\routing; | |||
use \OC\AppFramework\App; | |||
use \OC\AppFramework\DependencyInjection\DIContainer; | |||
class RouteActionHandler { | |||
private $controllerName; | |||
private $actionName; | |||
private $container; | |||
public function __construct(DIContainer $container, $controllerName, $actionName) { | |||
$this->controllerName = $controllerName; | |||
$this->actionName = $actionName; | |||
$this->container = $container; | |||
} | |||
public function __invoke($params) { | |||
App::main($this->controllerName, $this->actionName, $params, $this->container); | |||
} | |||
} |
@@ -0,0 +1,186 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Thomas Müller | |||
* @copyright 2013 Thomas Müller thomas.mueller@tmit.eu | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\routing; | |||
use OC\AppFramework\DependencyInjection\DIContainer; | |||
/** | |||
* Class RouteConfig | |||
* @package OC\AppFramework\routing | |||
*/ | |||
class RouteConfig { | |||
private $container; | |||
private $router; | |||
private $routes; | |||
private $appName; | |||
/** | |||
* @param \OC\AppFramework\DependencyInjection\DIContainer $container | |||
* @param \OC_Router $router | |||
* @param string $pathToYml | |||
* @internal param $appName | |||
*/ | |||
public function __construct(DIContainer $container, \OC_Router $router, $routes) { | |||
$this->routes = $routes; | |||
$this->container = $container; | |||
$this->router = $router; | |||
$this->appName = $container['AppName']; | |||
} | |||
/** | |||
* The routes and resource will be registered to the \OC_Router | |||
*/ | |||
public function register() { | |||
// parse simple | |||
$this->processSimpleRoutes($this->routes); | |||
// parse resources | |||
$this->processResources($this->routes); | |||
} | |||
/** | |||
* Creates one route base on the give configuration | |||
* @param $routes | |||
* @throws \UnexpectedValueException | |||
*/ | |||
private function processSimpleRoutes($routes) | |||
{ | |||
$simpleRoutes = isset($routes['routes']) ? $routes['routes'] : array(); | |||
foreach ($simpleRoutes as $simpleRoute) { | |||
$name = $simpleRoute['name']; | |||
$url = $simpleRoute['url']; | |||
$verb = isset($simpleRoute['verb']) ? strtoupper($simpleRoute['verb']) : 'GET'; | |||
$split = explode('#', $name, 2); | |||
if (count($split) != 2) { | |||
throw new \UnexpectedValueException('Invalid route name'); | |||
} | |||
$controller = $split[0]; | |||
$action = $split[1]; | |||
$controllerName = $this->buildControllerName($controller); | |||
$actionName = $this->buildActionName($action); | |||
// register the route | |||
$handler = new RouteActionHandler($this->container, $controllerName, $actionName); | |||
$this->router->create($this->appName.'.'.$controller.'.'.$action, $url)->method($verb)->action($handler); | |||
} | |||
} | |||
/** | |||
* For a given name and url restful routes are created: | |||
* - index | |||
* - show | |||
* - new | |||
* - create | |||
* - update | |||
* - destroy | |||
* | |||
* @param $routes | |||
*/ | |||
private function processResources($routes) | |||
{ | |||
// declaration of all restful actions | |||
$actions = array( | |||
array('name' => 'index', 'verb' => 'GET', 'on-collection' => true), | |||
array('name' => 'show', 'verb' => 'GET'), | |||
array('name' => 'create', 'verb' => 'POST', 'on-collection' => true), | |||
array('name' => 'update', 'verb' => 'PUT'), | |||
array('name' => 'destroy', 'verb' => 'DELETE'), | |||
); | |||
$resources = isset($routes['resources']) ? $routes['resources'] : array(); | |||
foreach ($resources as $resource => $config) { | |||
// the url parameter used as id to the resource | |||
$resourceId = $this->buildResourceId($resource); | |||
foreach($actions as $action) { | |||
$url = $config['url']; | |||
$method = $action['name']; | |||
$verb = isset($action['verb']) ? strtoupper($action['verb']) : 'GET'; | |||
$collectionAction = isset($action['on-collection']) ? $action['on-collection'] : false; | |||
if (!$collectionAction) { | |||
$url = $url . '/' . $resourceId; | |||
} | |||
if (isset($action['url-postfix'])) { | |||
$url = $url . '/' . $action['url-postfix']; | |||
} | |||
$controller = $resource; | |||
$controllerName = $this->buildControllerName($controller); | |||
$actionName = $this->buildActionName($method); | |||
$routeName = $this->appName . '.' . strtolower($resource) . '.' . strtolower($method); | |||
$this->router->create($routeName, $url)->method($verb)->action( | |||
new RouteActionHandler($this->container, $controllerName, $actionName) | |||
); | |||
} | |||
} | |||
} | |||
/** | |||
* Based on a given route name the controller name is generated | |||
* @param $controller | |||
* @return string | |||
*/ | |||
private function buildControllerName($controller) | |||
{ | |||
return $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller'; | |||
} | |||
/** | |||
* Based on the action part of the route name the controller method name is generated | |||
* @param $action | |||
* @return string | |||
*/ | |||
private function buildActionName($action) { | |||
return $this->underScoreToCamelCase($action); | |||
} | |||
/** | |||
* Generates the id used in the url part o the route url | |||
* @param $resource | |||
* @return string | |||
*/ | |||
private function buildResourceId($resource) { | |||
return '{'.$this->underScoreToCamelCase(rtrim($resource, 's')).'Id}'; | |||
} | |||
/** | |||
* Underscored strings are converted to camel case strings | |||
* @param $str string | |||
* @return string | |||
*/ | |||
private function underScoreToCamelCase($str) { | |||
$pattern = "/_[a-z]?/"; | |||
return preg_replace_callback( | |||
$pattern, | |||
function ($matches) { | |||
return strtoupper(ltrim($matches[0], "_")); | |||
}, | |||
$str); | |||
} | |||
} |
@@ -0,0 +1,61 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Utility; | |||
/** | |||
* Reads and parses annotations from doc comments | |||
*/ | |||
class MethodAnnotationReader { | |||
private $annotations; | |||
/** | |||
* @param object $object an object or classname | |||
* @param string $method the method which we want to inspect for annotations | |||
*/ | |||
public function __construct($object, $method){ | |||
$this->annotations = array(); | |||
$reflection = new \ReflectionMethod($object, $method); | |||
$docs = $reflection->getDocComment(); | |||
// extract everything prefixed by @ and first letter uppercase | |||
preg_match_all('/@([A-Z]\w+)/', $docs, $matches); | |||
$this->annotations = $matches[1]; | |||
} | |||
/** | |||
* Check if a method contains an annotation | |||
* @param string $name the name of the annotation | |||
* @return bool true if the annotation is found | |||
*/ | |||
public function hasAnnotation($name){ | |||
return in_array($name, $this->annotations); | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Utility; | |||
/** | |||
* Needed to mock calls to time() | |||
*/ | |||
class TimeFactory { | |||
/** | |||
* @return int the result of a call to time() | |||
*/ | |||
public function getTime() { | |||
return time(); | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Core\API; | |||
use OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
// FIXME: loading pimpl correctly from 3rdparty repo | |||
require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; | |||
require_once __DIR__ . "/classloader.php"; | |||
class AppTest extends \PHPUnit_Framework_TestCase { | |||
private $container; | |||
private $api; | |||
private $controller; | |||
private $dispatcher; | |||
private $params; | |||
private $headers; | |||
private $output; | |||
private $controllerName; | |||
private $controllerMethod; | |||
protected function setUp() { | |||
$this->container = new \Pimple(); | |||
$this->controller = $this->getMockBuilder( | |||
'OC\AppFramework\Controller\Controller') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->dispatcher = $this->getMockBuilder( | |||
'OC\AppFramework\Http\Dispatcher') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->headers = array('key' => 'value'); | |||
$this->output = 'hi'; | |||
$this->controllerName = 'Controller'; | |||
$this->controllerMethod = 'method'; | |||
$this->container[$this->controllerName] = $this->controller; | |||
$this->container['Dispatcher'] = $this->dispatcher; | |||
} | |||
public function testControllerNameAndMethodAreBeingPassed(){ | |||
$return = array(null, array(), null); | |||
$this->dispatcher->expects($this->once()) | |||
->method('dispatch') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod)) | |||
->will($this->returnValue($return)); | |||
$this->expectOutputString(''); | |||
App::main($this->controllerName, $this->controllerMethod, array(), | |||
$this->container); | |||
} | |||
/* | |||
FIXME: this complains about shit headers which are already sent because | |||
of the content length. Would be cool if someone could fix this | |||
public function testOutputIsPrinted(){ | |||
$return = array(null, array(), $this->output); | |||
$this->dispatcher->expects($this->once()) | |||
->method('dispatch') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod)) | |||
->will($this->returnValue($return)); | |||
$this->expectOutputString($this->output); | |||
App::main($this->controllerName, $this->controllerMethod, array(), | |||
$this->container); | |||
} | |||
*/ | |||
// FIXME: if someone manages to test the headers output, I'd be grateful | |||
} |
@@ -0,0 +1,45 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
// to execute without ownCloud, we need to create our own class loader | |||
spl_autoload_register(function ($className){ | |||
if (strpos($className, 'OC\\AppFramework') === 0) { | |||
$path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); | |||
$relPath = __DIR__ . '/../../../lib/' . $path; | |||
if(file_exists($relPath)){ | |||
require_once $relPath; | |||
} | |||
} | |||
// FIXME: this will most probably not work anymore | |||
if (strpos($className, 'OCA\\') === 0) { | |||
$path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); | |||
$relPath = __DIR__ . '/../..' . $path; | |||
if(file_exists($relPath)){ | |||
require_once $relPath; | |||
} | |||
} | |||
}); |
@@ -0,0 +1,161 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace Test\AppFramework\Controller; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Http\JSONResponse; | |||
use OC\AppFramework\Http\TemplateResponse; | |||
use OC\AppFramework\Controller\Controller; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class ChildController extends Controller {}; | |||
class ControllerTest extends \PHPUnit_Framework_TestCase { | |||
/** | |||
* @var Controller | |||
*/ | |||
private $controller; | |||
private $api; | |||
protected function setUp(){ | |||
$request = new Request( | |||
array( | |||
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), | |||
'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), | |||
'urlParams' => array('name' => 'Johnny Weissmüller'), | |||
'files' => array('file' => 'filevalue'), | |||
'env' => array('PATH' => 'daheim'), | |||
'session' => array('sezession' => 'kein'), | |||
'method' => 'hi', | |||
) | |||
); | |||
$this->api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName'), array('test')); | |||
$this->api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('apptemplate_advanced')); | |||
$this->controller = new ChildController($this->api, $request); | |||
} | |||
public function testParamsGet(){ | |||
$this->assertEquals('Johnny Weissmüller', $this->controller->params('name', 'Tarzan')); | |||
} | |||
public function testParamsGetDefault(){ | |||
$this->assertEquals('Tarzan', $this->controller->params('Ape Man', 'Tarzan')); | |||
} | |||
public function testParamsFile(){ | |||
$this->assertEquals('filevalue', $this->controller->params('file', 'filevalue')); | |||
} | |||
public function testGetUploadedFile(){ | |||
$this->assertEquals('filevalue', $this->controller->getUploadedFile('file')); | |||
} | |||
public function testGetUploadedFileDefault(){ | |||
$this->assertEquals('default', $this->controller->params('files', 'default')); | |||
} | |||
public function testGetParams(){ | |||
$params = array( | |||
'name' => 'Johnny Weissmüller', | |||
'nickname' => 'Janey', | |||
); | |||
$this->assertEquals($params, $this->controller->getParams()); | |||
} | |||
public function testRender(){ | |||
$this->assertTrue($this->controller->render('') instanceof TemplateResponse); | |||
} | |||
public function testSetParams(){ | |||
$params = array('john' => 'foo'); | |||
$response = $this->controller->render('home', $params); | |||
$this->assertEquals($params, $response->getParams()); | |||
} | |||
public function testRenderRenderAs(){ | |||
$ocTpl = $this->getMock('Template', array('fetchPage')); | |||
$ocTpl->expects($this->once()) | |||
->method('fetchPage'); | |||
$api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName', 'getTemplate'), array('app')); | |||
$api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('app')); | |||
$api->expects($this->once()) | |||
->method('getTemplate') | |||
->with($this->equalTo('home'), $this->equalTo('admin'), $this->equalTo('app')) | |||
->will($this->returnValue($ocTpl)); | |||
$this->controller = new ChildController($api, new Request()); | |||
$this->controller->render('home', array(), 'admin')->render(); | |||
} | |||
public function testRenderHeaders(){ | |||
$headers = array('one', 'two'); | |||
$response = $this->controller->render('', array(), '', $headers); | |||
$this->assertTrue(in_array($headers[0], $response->getHeaders())); | |||
$this->assertTrue(in_array($headers[1], $response->getHeaders())); | |||
} | |||
public function testGetRequestMethod(){ | |||
$this->assertEquals('hi', $this->controller->method()); | |||
} | |||
public function testGetEnvVariable(){ | |||
$this->assertEquals('daheim', $this->controller->env('PATH')); | |||
} | |||
public function testGetSessionVariable(){ | |||
$this->assertEquals('kein', $this->controller->session('sezession')); | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @author Morris Jobke | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* @copyright 2013 Morris Jobke morris.jobke@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\DependencyInjection; | |||
use \OC\AppFramework\Http\Request; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class DIContainerTest extends \PHPUnit_Framework_TestCase { | |||
private $container; | |||
protected function setUp(){ | |||
$this->container = new DIContainer('name'); | |||
$this->api = $this->getMock('OC\AppFramework\Core\API', array('getTrans'), array('hi')); | |||
} | |||
private function exchangeAPI(){ | |||
$this->api->expects($this->any()) | |||
->method('getTrans') | |||
->will($this->returnValue('yo')); | |||
$this->container['API'] = $this->api; | |||
} | |||
public function testProvidesAPI(){ | |||
$this->assertTrue(isset($this->container['API'])); | |||
} | |||
public function testProvidesRequest(){ | |||
$this->assertTrue(isset($this->container['Request'])); | |||
} | |||
public function testProvidesSecurityMiddleware(){ | |||
$this->assertTrue(isset($this->container['SecurityMiddleware'])); | |||
} | |||
public function testProvidesMiddlewareDispatcher(){ | |||
$this->assertTrue(isset($this->container['MiddlewareDispatcher'])); | |||
} | |||
public function testProvidesAppName(){ | |||
$this->assertTrue(isset($this->container['AppName'])); | |||
} | |||
public function testAppNameIsSetCorrectly(){ | |||
$this->assertEquals('name', $this->container['AppName']); | |||
} | |||
public function testMiddlewareDispatcherIncludesSecurityMiddleware(){ | |||
$this->container['Request'] = new Request(); | |||
$security = $this->container['SecurityMiddleware']; | |||
$dispatcher = $this->container['MiddlewareDispatcher']; | |||
$this->assertContains($security, $dispatcher->getMiddlewares()); | |||
} | |||
public function testMiddlewareDispatcherDoesNotIncludeTwigWhenTplDirectoryNotSet(){ | |||
$this->container['Request'] = new Request(); | |||
$this->exchangeAPI(); | |||
$dispatcher = $this->container['MiddlewareDispatcher']; | |||
$this->assertEquals(1, count($dispatcher->getMiddlewares())); | |||
} | |||
} |
@@ -0,0 +1,218 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
use OC\AppFramework\Core\API; | |||
use OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
private $middlewareDispatcher; | |||
private $dispatcher; | |||
private $controllerMethod; | |||
private $response; | |||
private $lastModified; | |||
private $etag; | |||
private $http; | |||
protected function setUp() { | |||
$this->controllerMethod = 'test'; | |||
$api = $this->getMockBuilder( | |||
'\OC\AppFramework\Core\API') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$request = $this->getMockBuilder( | |||
'\OC\AppFramework\Http\Request') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->http = $this->getMockBuilder( | |||
'\OC\AppFramework\Http\Http') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->middlewareDispatcher = $this->getMockBuilder( | |||
'\OC\AppFramework\Middleware\MiddlewareDispatcher') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->controller = $this->getMock( | |||
'\OC\AppFramework\Controller\Controller', | |||
array($this->controllerMethod), array($api, $request)); | |||
$this->dispatcher = new Dispatcher( | |||
$this->http, $this->middlewareDispatcher); | |||
$this->response = $this->getMockBuilder( | |||
'\OC\AppFramework\Http\Response') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->lastModified = new \DateTime(null, new \DateTimeZone('GMT')); | |||
$this->etag = 'hi'; | |||
} | |||
private function setMiddlewareExpections($out=null, | |||
$httpHeaders=null, $responseHeaders=array(), | |||
$ex=false, $catchEx=true) { | |||
if($ex) { | |||
$exception = new \Exception(); | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('beforeController') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod)) | |||
->will($this->throwException($exception)); | |||
if($catchEx) { | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('afterException') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod), | |||
$this->equalTo($exception)) | |||
->will($this->returnValue($this->response)); | |||
} else { | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('afterException') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod), | |||
$this->equalTo($exception)) | |||
->will($this->returnValue(null)); | |||
return; | |||
} | |||
} else { | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('beforeController') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod)); | |||
$this->controller->expects($this->once()) | |||
->method($this->controllerMethod) | |||
->will($this->returnValue($this->response)); | |||
} | |||
$this->response->expects($this->once()) | |||
->method('render') | |||
->will($this->returnValue($out)); | |||
$this->response->expects($this->once()) | |||
->method('getStatus') | |||
->will($this->returnValue(Http::STATUS_OK)); | |||
$this->response->expects($this->once()) | |||
->method('getLastModified') | |||
->will($this->returnValue($this->lastModified)); | |||
$this->response->expects($this->once()) | |||
->method('getETag') | |||
->will($this->returnValue($this->etag)); | |||
$this->response->expects($this->once()) | |||
->method('getHeaders') | |||
->will($this->returnValue($responseHeaders)); | |||
$this->http->expects($this->once()) | |||
->method('getStatusHeader') | |||
->with($this->equalTo(Http::STATUS_OK), | |||
$this->equalTo($this->lastModified), | |||
$this->equalTo($this->etag)) | |||
->will($this->returnValue($httpHeaders)); | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('afterController') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod), | |||
$this->equalTo($this->response)) | |||
->will($this->returnValue($this->response)); | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('afterController') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod), | |||
$this->equalTo($this->response)) | |||
->will($this->returnValue($this->response)); | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('beforeOutput') | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod), | |||
$this->equalTo($out)) | |||
->will($this->returnValue($out)); | |||
} | |||
public function testDispatcherReturnsArrayWith2Entries() { | |||
$this->setMiddlewareExpections(); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
$this->assertNull($response[0]); | |||
$this->assertEquals(array(), $response[1]); | |||
$this->assertNull($response[2]); | |||
} | |||
public function testHeadersAndOutputAreReturned(){ | |||
$out = 'yo'; | |||
$httpHeaders = 'Http'; | |||
$responseHeaders = array('hell' => 'yeah'); | |||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
$this->assertEquals($httpHeaders, $response[0]); | |||
$this->assertEquals($responseHeaders, $response[1]); | |||
$this->assertEquals($out, $response[2]); | |||
} | |||
public function testExceptionCallsAfterException() { | |||
$out = 'yo'; | |||
$httpHeaders = 'Http'; | |||
$responseHeaders = array('hell' => 'yeah'); | |||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
$this->assertEquals($httpHeaders, $response[0]); | |||
$this->assertEquals($responseHeaders, $response[1]); | |||
$this->assertEquals($out, $response[2]); | |||
} | |||
public function testExceptionThrowsIfCanNotBeHandledByAfterException() { | |||
$out = 'yo'; | |||
$httpHeaders = 'Http'; | |||
$responseHeaders = array('hell' => 'yeah'); | |||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); | |||
$this->setExpectedException('\Exception'); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class ChildDownloadResponse extends DownloadResponse {}; | |||
class DownloadResponseTest extends \PHPUnit_Framework_TestCase { | |||
protected $response; | |||
protected function setUp(){ | |||
$this->response = new ChildDownloadResponse('file', 'content'); | |||
} | |||
public function testHeaders() { | |||
$headers = $this->response->getHeaders(); | |||
$this->assertContains('attachment; filename="file"', $headers['Content-Disposition']); | |||
$this->assertContains('content', $headers['Content-Type']); | |||
} | |||
} |
@@ -0,0 +1,87 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class HttpTest extends \PHPUnit_Framework_TestCase { | |||
private $server; | |||
private $http; | |||
protected function setUp(){ | |||
$this->server = array(); | |||
$this->http = new Http($this->server); | |||
} | |||
public function testProtocol() { | |||
$header = $this->http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); | |||
$this->assertEquals('HTTP/1.1 307 Temporary Redirect', $header); | |||
} | |||
public function testProtocol10() { | |||
$this->http = new Http($this->server, 'HTTP/1.0'); | |||
$header = $this->http->getStatusHeader(Http::STATUS_OK); | |||
$this->assertEquals('HTTP/1.0 200 OK', $header); | |||
} | |||
public function testEtagMatchReturnsNotModified() { | |||
$http = new Http(array('HTTP_IF_NONE_MATCH' => 'hi')); | |||
$header = $http->getStatusHeader(Http::STATUS_OK, null, 'hi'); | |||
$this->assertEquals('HTTP/1.1 304 Not Modified', $header); | |||
} | |||
public function testLastModifiedMatchReturnsNotModified() { | |||
$dateTime = new \DateTime(null, new \DateTimeZone('GMT')); | |||
$dateTime->setTimestamp('12'); | |||
$http = new Http( | |||
array( | |||
'HTTP_IF_MODIFIED_SINCE' => 'Thu, 01 Jan 1970 00:00:12 +0000') | |||
); | |||
$header = $http->getStatusHeader(Http::STATUS_OK, $dateTime); | |||
$this->assertEquals('HTTP/1.1 304 Not Modified', $header); | |||
} | |||
public function testTempRedirectBecomesFoundInHttp10() { | |||
$http = new Http(array(), 'HTTP/1.0'); | |||
$header = $http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); | |||
$this->assertEquals('HTTP/1.0 302 Found', $header); | |||
} | |||
// TODO: write unittests for http codes | |||
} |
@@ -0,0 +1,96 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @author Morris Jobke | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* @copyright 2013 Morris Jobke morris.jobke@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class JSONResponseTest extends \PHPUnit_Framework_TestCase { | |||
/** | |||
* @var JSONResponse | |||
*/ | |||
private $json; | |||
protected function setUp() { | |||
$this->json = new JSONResponse(); | |||
} | |||
public function testHeader() { | |||
$headers = $this->json->getHeaders(); | |||
$this->assertEquals('application/json; charset=utf-8', $headers['Content-type']); | |||
} | |||
public function testSetData() { | |||
$params = array('hi', 'yo'); | |||
$this->json->setData($params); | |||
$this->assertEquals(array('hi', 'yo'), $this->json->getData()); | |||
} | |||
public function testSetRender() { | |||
$params = array('test' => 'hi'); | |||
$this->json->setData($params); | |||
$expected = '{"test":"hi"}'; | |||
$this->assertEquals($expected, $this->json->render()); | |||
} | |||
public function testRender() { | |||
$params = array('test' => 'hi'); | |||
$this->json->setData($params); | |||
$expected = '{"test":"hi"}'; | |||
$this->assertEquals($expected, $this->json->render()); | |||
} | |||
public function testShouldHaveXContentHeaderByDefault() { | |||
$headers = $this->json->getHeaders(); | |||
$this->assertEquals('nosniff', $headers['X-Content-Type-Options']); | |||
} | |||
public function testConstructorAllowsToSetData() { | |||
$data = array('hi'); | |||
$code = 300; | |||
$response = new JSONResponse($data, $code); | |||
$expected = '["hi"]'; | |||
$this->assertEquals($expected, $response->render()); | |||
$this->assertEquals($code, $response->getStatus()); | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class RedirectResponseTest extends \PHPUnit_Framework_TestCase { | |||
protected $response; | |||
protected function setUp(){ | |||
$this->response = new RedirectResponse('/url'); | |||
} | |||
public function testHeaders() { | |||
$headers = $this->response->getHeaders(); | |||
$this->assertEquals('/url', $headers['Location']); | |||
$this->assertEquals(Http::STATUS_TEMPORARY_REDIRECT, | |||
$this->response->getStatus()); | |||
} | |||
public function testGetRedirectUrl(){ | |||
$this->assertEquals('/url', $this->response->getRedirectUrl()); | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net) | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class RequestTest extends \PHPUnit_Framework_TestCase { | |||
public function testRequestAccessors() { | |||
$vars = array( | |||
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), | |||
); | |||
$request = new Request($vars); | |||
// Countable | |||
$this->assertEquals(2, count($request)); | |||
// Array access | |||
$this->assertEquals('Joey', $request['nickname']); | |||
// "Magic" accessors | |||
$this->assertEquals('Joey', $request->{'nickname'}); | |||
$this->assertTrue(isset($request['nickname'])); | |||
$this->assertTrue(isset($request->{'nickname'})); | |||
$this->assertEquals(false, isset($request->{'flickname'})); | |||
// Only testing 'get', but same approach for post, files etc. | |||
$this->assertEquals('Joey', $request->get['nickname']); | |||
// Always returns null if variable not set. | |||
$this->assertEquals(null, $request->{'flickname'}); | |||
} | |||
// urlParams has precedence over POST which has precedence over GET | |||
public function testPrecedence() { | |||
$vars = array( | |||
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), | |||
'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), | |||
'urlParams' => array('user' => 'jw', 'name' => 'Johnny Weissmüller'), | |||
); | |||
$request = new Request($vars); | |||
$this->assertEquals(3, count($request)); | |||
$this->assertEquals('Janey', $request->{'nickname'}); | |||
$this->assertEquals('Johnny Weissmüller', $request->{'name'}); | |||
} | |||
/** | |||
* @expectedException RuntimeException | |||
*/ | |||
public function testImmutableArrayAccess() { | |||
$vars = array( | |||
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), | |||
); | |||
$request = new Request($vars); | |||
$request['nickname'] = 'Janey'; | |||
} | |||
/** | |||
* @expectedException RuntimeException | |||
*/ | |||
public function testImmutableMagicAccess() { | |||
$vars = array( | |||
'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), | |||
); | |||
$request = new Request($vars); | |||
$request->{'nickname'} = 'Janey'; | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class ResponseTest extends \PHPUnit_Framework_TestCase { | |||
private $childResponse; | |||
protected function setUp(){ | |||
$this->childResponse = new Response(); | |||
} | |||
public function testAddHeader(){ | |||
$this->childResponse->addHeader('hello', 'world'); | |||
$headers = $this->childResponse->getHeaders(); | |||
$this->assertEquals('world', $headers['hello']); | |||
} | |||
public function testAddHeaderValueNullDeletesIt(){ | |||
$this->childResponse->addHeader('hello', 'world'); | |||
$this->childResponse->addHeader('hello', null); | |||
$this->assertEquals(1, count($this->childResponse->getHeaders())); | |||
} | |||
public function testCacheHeadersAreDisabledByDefault(){ | |||
$headers = $this->childResponse->getHeaders(); | |||
$this->assertEquals('no-cache, must-revalidate', $headers['Cache-Control']); | |||
} | |||
public function testRenderReturnNullByDefault(){ | |||
$this->assertEquals(null, $this->childResponse->render()); | |||
} | |||
public function testGetStatus() { | |||
$default = $this->childResponse->getStatus(); | |||
$this->childResponse->setStatus(Http::STATUS_NOT_FOUND); | |||
$this->assertEquals(Http::STATUS_OK, $default); | |||
$this->assertEquals(Http::STATUS_NOT_FOUND, $this->childResponse->getStatus()); | |||
} | |||
public function testGetEtag() { | |||
$this->childResponse->setEtag('hi'); | |||
$this->assertEquals('hi', $this->childResponse->getEtag()); | |||
} | |||
public function testGetLastModified() { | |||
$lastModified = new \DateTime(null, new \DateTimeZone('GMT')); | |||
$lastModified->setTimestamp(1); | |||
$this->childResponse->setLastModified($lastModified); | |||
$this->assertEquals($lastModified, $this->childResponse->getLastModified()); | |||
} | |||
public function testCacheSecondsZero() { | |||
$this->childResponse->cacheFor(0); | |||
$headers = $this->childResponse->getHeaders(); | |||
$this->assertEquals('no-cache, must-revalidate', $headers['Cache-Control']); | |||
} | |||
public function testCacheSeconds() { | |||
$this->childResponse->cacheFor(33); | |||
$headers = $this->childResponse->getHeaders(); | |||
$this->assertEquals('max-age=33, must-revalidate', | |||
$headers['Cache-Control']); | |||
} | |||
public function testEtagLastModifiedHeaders() { | |||
$lastModified = new \DateTime(null, new \DateTimeZone('GMT')); | |||
$lastModified->setTimestamp(1); | |||
$this->childResponse->setLastModified($lastModified); | |||
$headers = $this->childResponse->getHeaders(); | |||
$this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); | |||
} | |||
} |
@@ -0,0 +1,157 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Http; | |||
use OC\AppFramework\Core\API; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class TemplateResponseTest extends \PHPUnit_Framework_TestCase { | |||
private $tpl; | |||
private $api; | |||
protected function setUp() { | |||
$this->api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName'), array('test')); | |||
$this->api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('app')); | |||
$this->tpl = new TemplateResponse($this->api, 'home'); | |||
} | |||
public function testSetParams(){ | |||
$params = array('hi' => 'yo'); | |||
$this->tpl->setParams($params); | |||
$this->assertEquals(array('hi' => 'yo'), $this->tpl->getParams()); | |||
} | |||
public function testGetTemplateName(){ | |||
$this->assertEquals('home', $this->tpl->getTemplateName()); | |||
} | |||
public function testRender(){ | |||
$ocTpl = $this->getMock('Template', array('fetchPage')); | |||
$ocTpl->expects($this->once()) | |||
->method('fetchPage'); | |||
$api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName', 'getTemplate'), array('app')); | |||
$api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('app')); | |||
$api->expects($this->once()) | |||
->method('getTemplate') | |||
->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app')) | |||
->will($this->returnValue($ocTpl)); | |||
$tpl = new TemplateResponse($api, 'home'); | |||
$tpl->render(); | |||
} | |||
public function testRenderAssignsParams(){ | |||
$params = array('john' => 'doe'); | |||
$ocTpl = $this->getMock('Template', array('assign', 'fetchPage')); | |||
$ocTpl->expects($this->once()) | |||
->method('assign') | |||
->with($this->equalTo('john'), $this->equalTo('doe')); | |||
$api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName', 'getTemplate'), array('app')); | |||
$api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('app')); | |||
$api->expects($this->once()) | |||
->method('getTemplate') | |||
->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app')) | |||
->will($this->returnValue($ocTpl)); | |||
$tpl = new TemplateResponse($api, 'home'); | |||
$tpl->setParams($params); | |||
$tpl->render(); | |||
} | |||
public function testRenderDifferentApp(){ | |||
$ocTpl = $this->getMock('Template', array('fetchPage')); | |||
$ocTpl->expects($this->once()) | |||
->method('fetchPage'); | |||
$api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName', 'getTemplate'), array('app')); | |||
$api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('app')); | |||
$api->expects($this->once()) | |||
->method('getTemplate') | |||
->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app2')) | |||
->will($this->returnValue($ocTpl)); | |||
$tpl = new TemplateResponse($api, 'home', 'app2'); | |||
$tpl->render(); | |||
} | |||
public function testRenderDifferentRenderAs(){ | |||
$ocTpl = $this->getMock('Template', array('fetchPage')); | |||
$ocTpl->expects($this->once()) | |||
->method('fetchPage'); | |||
$api = $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName', 'getTemplate'), array('app')); | |||
$api->expects($this->any()) | |||
->method('getAppName') | |||
->will($this->returnValue('app')); | |||
$api->expects($this->once()) | |||
->method('getTemplate') | |||
->with($this->equalTo('home'), $this->equalTo('admin'), $this->equalTo('app')) | |||
->will($this->returnValue($ocTpl)); | |||
$tpl = new TemplateResponse($api, 'home'); | |||
$tpl->renderAs('admin'); | |||
$tpl->render(); | |||
} | |||
public function testGetRenderAs(){ | |||
$render = 'myrender'; | |||
$this->tpl->renderAs($render); | |||
$this->assertEquals($render, $this->tpl->getRenderAs()); | |||
} | |||
} |
@@ -0,0 +1,280 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework; | |||
use OC\AppFramework\Controller\Controller; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Http\Response; | |||
use OC\AppFramework\Middleware\Middleware; | |||
use OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
// needed to test ordering | |||
class TestMiddleware extends Middleware { | |||
public static $beforeControllerCalled = 0; | |||
public static $afterControllerCalled = 0; | |||
public static $afterExceptionCalled = 0; | |||
public static $beforeOutputCalled = 0; | |||
public $beforeControllerOrder = 0; | |||
public $afterControllerOrder = 0; | |||
public $afterExceptionOrder = 0; | |||
public $beforeOutputOrder = 0; | |||
public $controller; | |||
public $methodName; | |||
public $exception; | |||
public $response; | |||
public $output; | |||
private $beforeControllerThrowsEx; | |||
public function __construct($beforeControllerThrowsEx) { | |||
self::$beforeControllerCalled = 0; | |||
self::$afterControllerCalled = 0; | |||
self::$afterExceptionCalled = 0; | |||
self::$beforeOutputCalled = 0; | |||
$this->beforeControllerThrowsEx = $beforeControllerThrowsEx; | |||
} | |||
public function beforeController($controller, $methodName){ | |||
self::$beforeControllerCalled++; | |||
$this->beforeControllerOrder = self::$beforeControllerCalled; | |||
$this->controller = $controller; | |||
$this->methodName = $methodName; | |||
if($this->beforeControllerThrowsEx){ | |||
throw new \Exception(); | |||
} | |||
} | |||
public function afterException($controller, $methodName, \Exception $exception){ | |||
self::$afterExceptionCalled++; | |||
$this->afterExceptionOrder = self::$afterExceptionCalled; | |||
$this->controller = $controller; | |||
$this->methodName = $methodName; | |||
$this->exception = $exception; | |||
parent::afterException($controller, $methodName, $exception); | |||
} | |||
public function afterController($controller, $methodName, Response $response){ | |||
self::$afterControllerCalled++; | |||
$this->afterControllerOrder = self::$afterControllerCalled; | |||
$this->controller = $controller; | |||
$this->methodName = $methodName; | |||
$this->response = $response; | |||
return parent::afterController($controller, $methodName, $response); | |||
} | |||
public function beforeOutput($controller, $methodName, $output){ | |||
self::$beforeOutputCalled++; | |||
$this->beforeOutputOrder = self::$beforeOutputCalled; | |||
$this->controller = $controller; | |||
$this->methodName = $methodName; | |||
$this->output = $output; | |||
return parent::beforeOutput($controller, $methodName, $output); | |||
} | |||
} | |||
class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { | |||
private $dispatcher; | |||
public function setUp() { | |||
$this->dispatcher = new MiddlewareDispatcher(); | |||
$this->controller = $this->getControllerMock(); | |||
$this->method = 'method'; | |||
$this->response = new Response(); | |||
$this->output = 'hi'; | |||
$this->exception = new \Exception(); | |||
} | |||
private function getAPIMock(){ | |||
return $this->getMock('OC\AppFramework\Core\API', | |||
array('getAppName'), array('app')); | |||
} | |||
private function getControllerMock(){ | |||
return $this->getMock('OC\AppFramework\Controller\Controller', array('method'), | |||
array($this->getAPIMock(), new Request())); | |||
} | |||
private function getMiddleware($beforeControllerThrowsEx=false){ | |||
$m1 = new TestMiddleware($beforeControllerThrowsEx); | |||
$this->dispatcher->registerMiddleware($m1); | |||
return $m1; | |||
} | |||
public function testAfterExceptionShouldReturnResponseOfMiddleware(){ | |||
$response = new Response(); | |||
$m1 = $this->getMock('\OC\AppFramework\Middleware\Middleware', | |||
array('afterException', 'beforeController')); | |||
$m1->expects($this->never()) | |||
->method('afterException'); | |||
$m2 = $this->getMock('OC\AppFramework\Middleware\Middleware', | |||
array('afterException', 'beforeController')); | |||
$m2->expects($this->once()) | |||
->method('afterException') | |||
->will($this->returnValue($response)); | |||
$this->dispatcher->registerMiddleware($m1); | |||
$this->dispatcher->registerMiddleware($m2); | |||
$this->dispatcher->beforeController($this->controller, $this->method); | |||
$this->assertEquals($response, $this->dispatcher->afterException($this->controller, $this->method, $this->exception)); | |||
} | |||
public function testAfterExceptionShouldThrowAgainWhenNotHandled(){ | |||
$m1 = new TestMiddleware(false); | |||
$m2 = new TestMiddleware(true); | |||
$this->dispatcher->registerMiddleware($m1); | |||
$this->dispatcher->registerMiddleware($m2); | |||
$this->setExpectedException('\Exception'); | |||
$this->dispatcher->beforeController($this->controller, $this->method); | |||
$this->dispatcher->afterException($this->controller, $this->method, $this->exception); | |||
} | |||
public function testBeforeControllerCorrectArguments(){ | |||
$m1 = $this->getMiddleware(); | |||
$this->dispatcher->beforeController($this->controller, $this->method); | |||
$this->assertEquals($this->controller, $m1->controller); | |||
$this->assertEquals($this->method, $m1->methodName); | |||
} | |||
public function testAfterControllerCorrectArguments(){ | |||
$m1 = $this->getMiddleware(); | |||
$this->dispatcher->afterController($this->controller, $this->method, $this->response); | |||
$this->assertEquals($this->controller, $m1->controller); | |||
$this->assertEquals($this->method, $m1->methodName); | |||
$this->assertEquals($this->response, $m1->response); | |||
} | |||
public function testAfterExceptionCorrectArguments(){ | |||
$m1 = $this->getMiddleware(); | |||
$this->setExpectedException('\Exception'); | |||
$this->dispatcher->beforeController($this->controller, $this->method); | |||
$this->dispatcher->afterException($this->controller, $this->method, $this->exception); | |||
$this->assertEquals($this->controller, $m1->controller); | |||
$this->assertEquals($this->method, $m1->methodName); | |||
$this->assertEquals($this->exception, $m1->exception); | |||
} | |||
public function testBeforeOutputCorrectArguments(){ | |||
$m1 = $this->getMiddleware(); | |||
$this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); | |||
$this->assertEquals($this->controller, $m1->controller); | |||
$this->assertEquals($this->method, $m1->methodName); | |||
$this->assertEquals($this->output, $m1->output); | |||
} | |||
public function testBeforeControllerOrder(){ | |||
$m1 = $this->getMiddleware(); | |||
$m2 = $this->getMiddleware(); | |||
$this->dispatcher->beforeController($this->controller, $this->method); | |||
$this->assertEquals(1, $m1->beforeControllerOrder); | |||
$this->assertEquals(2, $m2->beforeControllerOrder); | |||
} | |||
public function testAfterControllerOrder(){ | |||
$m1 = $this->getMiddleware(); | |||
$m2 = $this->getMiddleware(); | |||
$this->dispatcher->afterController($this->controller, $this->method, $this->response); | |||
$this->assertEquals(2, $m1->afterControllerOrder); | |||
$this->assertEquals(1, $m2->afterControllerOrder); | |||
} | |||
public function testAfterExceptionOrder(){ | |||
$m1 = $this->getMiddleware(); | |||
$m2 = $this->getMiddleware(); | |||
$this->setExpectedException('\Exception'); | |||
$this->dispatcher->beforeController($this->controller, $this->method); | |||
$this->dispatcher->afterException($this->controller, $this->method, $this->exception); | |||
$this->assertEquals(1, $m1->afterExceptionOrder); | |||
$this->assertEquals(1, $m2->afterExceptionOrder); | |||
} | |||
public function testBeforeOutputOrder(){ | |||
$m1 = $this->getMiddleware(); | |||
$m2 = $this->getMiddleware(); | |||
$this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); | |||
$this->assertEquals(2, $m1->beforeOutputOrder); | |||
$this->assertEquals(1, $m2->beforeOutputOrder); | |||
} | |||
public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(){ | |||
$m1 = $this->getMiddleware(); | |||
$m2 = $this->getMiddleware(true); | |||
$m3 = $this->getMock('\OC\AppFramework\Middleware\Middleware'); | |||
$m3->expects($this->never()) | |||
->method('afterException'); | |||
$m3->expects($this->never()) | |||
->method('beforeController'); | |||
$m3->expects($this->never()) | |||
->method('afterController'); | |||
$this->dispatcher->registerMiddleware($m3); | |||
$this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); | |||
$this->assertEquals(2, $m1->beforeOutputOrder); | |||
$this->assertEquals(1, $m2->beforeOutputOrder); | |||
} | |||
} |
@@ -0,0 +1,82 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Middleware\Middleware; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class ChildMiddleware extends Middleware {}; | |||
class MiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
private $middleware; | |||
private $controller; | |||
private $exception; | |||
private $api; | |||
protected function setUp(){ | |||
$this->middleware = new ChildMiddleware(); | |||
$this->api = $this->getMock('OC\AppFramework\Core\API', | |||
array(), array('test')); | |||
$this->controller = $this->getMock('OC\AppFramework\Controller\Controller', | |||
array(), array($this->api, new Request())); | |||
$this->exception = new \Exception(); | |||
$this->response = $this->getMock('OC\AppFramework\Http\Response'); | |||
} | |||
public function testBeforeController() { | |||
$this->middleware->beforeController($this->controller, null, $this->exception); | |||
} | |||
public function testAfterExceptionRaiseAgainWhenUnhandled() { | |||
$this->setExpectedException('Exception'); | |||
$afterEx = $this->middleware->afterException($this->controller, null, $this->exception); | |||
} | |||
public function testAfterControllerReturnResponseWhenUnhandled() { | |||
$response = $this->middleware->afterController($this->controller, null, $this->response); | |||
$this->assertEquals($this->response, $response); | |||
} | |||
public function testBeforeOutputReturnOutputhenUnhandled() { | |||
$output = $this->middleware->beforeOutput($this->controller, null, 'test'); | |||
$this->assertEquals('test', $output); | |||
} | |||
} |
@@ -0,0 +1,388 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Middleware\Security; | |||
use OC\AppFramework\Http\Http; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Http\RedirectResponse; | |||
use OC\AppFramework\Http\JSONResponse; | |||
use OC\AppFramework\Middleware\Middleware; | |||
require_once(__DIR__ . "/../../classloader.php"); | |||
class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
private $middleware; | |||
private $controller; | |||
private $secException; | |||
private $secAjaxException; | |||
private $request; | |||
public function setUp() { | |||
$api = $this->getMock('OC\AppFramework\Core\API', array(), array('test')); | |||
$this->controller = $this->getMock('OC\AppFramework\Controller\Controller', | |||
array(), array($api, new Request())); | |||
$this->request = new Request(); | |||
$this->middleware = new SecurityMiddleware($api, $this->request); | |||
$this->secException = new SecurityException('hey', false); | |||
$this->secAjaxException = new SecurityException('hey', true); | |||
} | |||
private function getAPI(){ | |||
return $this->getMock('OC\AppFramework\Core\API', | |||
array('isLoggedIn', 'passesCSRFCheck', 'isAdminUser', | |||
'isSubAdminUser', 'activateNavigationEntry', | |||
'getUserId'), | |||
array('app')); | |||
} | |||
private function checkNavEntry($method, $shouldBeActivated=false){ | |||
$api = $this->getAPI(); | |||
if($shouldBeActivated){ | |||
$api->expects($this->once()) | |||
->method('activateNavigationEntry'); | |||
} else { | |||
$api->expects($this->never()) | |||
->method('activateNavigationEntry'); | |||
} | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testSetNavigationEntry(){ | |||
$this->checkNavEntry('testSetNavigationEntry', true); | |||
} | |||
private function ajaxExceptionCheck($method, $shouldBeAjax=false){ | |||
$api = $this->getAPI(); | |||
$api->expects($this->any()) | |||
->method('passesCSRFCheck') | |||
->will($this->returnValue(false)); | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
try { | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', | |||
$method); | |||
} catch (SecurityException $ex){ | |||
if($shouldBeAjax){ | |||
$this->assertTrue($ex->isAjax()); | |||
} else { | |||
$this->assertFalse($ex->isAjax()); | |||
} | |||
} | |||
} | |||
/** | |||
* @Ajax | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testAjaxException(){ | |||
$this->ajaxExceptionCheck('testAjaxException'); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testNoAjaxException(){ | |||
$this->ajaxExceptionCheck('testNoAjaxException'); | |||
} | |||
private function ajaxExceptionStatus($method, $test, $status) { | |||
$api = $this->getAPI(); | |||
$api->expects($this->any()) | |||
->method($test) | |||
->will($this->returnValue(false)); | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
try { | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', | |||
$method); | |||
} catch (SecurityException $ex){ | |||
$this->assertEquals($status, $ex->getCode()); | |||
} | |||
} | |||
/** | |||
* @Ajax | |||
*/ | |||
public function testAjaxStatusLoggedInCheck() { | |||
$this->ajaxExceptionStatus( | |||
'testAjaxStatusLoggedInCheck', | |||
'isLoggedIn', | |||
Http::STATUS_UNAUTHORIZED | |||
); | |||
} | |||
/** | |||
* @Ajax | |||
* @IsLoggedInExemption | |||
*/ | |||
public function testAjaxNotAdminCheck() { | |||
$this->ajaxExceptionStatus( | |||
'testAjaxNotAdminCheck', | |||
'isAdminUser', | |||
Http::STATUS_FORBIDDEN | |||
); | |||
} | |||
/** | |||
* @Ajax | |||
* @IsLoggedInExemption | |||
* @IsAdminExemption | |||
*/ | |||
public function testAjaxNotSubAdminCheck() { | |||
$this->ajaxExceptionStatus( | |||
'testAjaxNotSubAdminCheck', | |||
'isSubAdminUser', | |||
Http::STATUS_FORBIDDEN | |||
); | |||
} | |||
/** | |||
* @Ajax | |||
* @IsLoggedInExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testAjaxStatusCSRFCheck() { | |||
$this->ajaxExceptionStatus( | |||
'testAjaxStatusCSRFCheck', | |||
'passesCSRFCheck', | |||
Http::STATUS_PRECONDITION_FAILED | |||
); | |||
} | |||
/** | |||
* @Ajax | |||
* @CSRFExemption | |||
* @IsLoggedInExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testAjaxStatusAllGood() { | |||
$this->ajaxExceptionStatus( | |||
'testAjaxStatusAllGood', | |||
'isLoggedIn', | |||
0 | |||
); | |||
$this->ajaxExceptionStatus( | |||
'testAjaxStatusAllGood', | |||
'isAdminUser', | |||
0 | |||
); | |||
$this->ajaxExceptionStatus( | |||
'testAjaxStatusAllGood', | |||
'isSubAdminUser', | |||
0 | |||
); | |||
$this->ajaxExceptionStatus( | |||
'testAjaxStatusAllGood', | |||
'passesCSRFCheck', | |||
0 | |||
); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testNoChecks(){ | |||
$api = $this->getAPI(); | |||
$api->expects($this->never()) | |||
->method('passesCSRFCheck') | |||
->will($this->returnValue(true)); | |||
$api->expects($this->never()) | |||
->method('isAdminUser') | |||
->will($this->returnValue(true)); | |||
$api->expects($this->never()) | |||
->method('isSubAdminUser') | |||
->will($this->returnValue(true)); | |||
$api->expects($this->never()) | |||
->method('isLoggedIn') | |||
->will($this->returnValue(true)); | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', | |||
'testNoChecks'); | |||
} | |||
private function securityCheck($method, $expects, $shouldFail=false){ | |||
$api = $this->getAPI(); | |||
$api->expects($this->once()) | |||
->method($expects) | |||
->will($this->returnValue(!$shouldFail)); | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
if($shouldFail){ | |||
$this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException'); | |||
} | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testCsrfCheck(){ | |||
$this->securityCheck('testCsrfCheck', 'passesCSRFCheck'); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testFailCsrfCheck(){ | |||
$this->securityCheck('testFailCsrfCheck', 'passesCSRFCheck', true); | |||
} | |||
/** | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testLoggedInCheck(){ | |||
$this->securityCheck('testLoggedInCheck', 'isLoggedIn'); | |||
} | |||
/** | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testFailLoggedInCheck(){ | |||
$this->securityCheck('testFailLoggedInCheck', 'isLoggedIn', true); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testIsAdminCheck(){ | |||
$this->securityCheck('testIsAdminCheck', 'isAdminUser'); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsSubAdminExemption | |||
*/ | |||
public function testFailIsAdminCheck(){ | |||
$this->securityCheck('testFailIsAdminCheck', 'isAdminUser', true); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
*/ | |||
public function testIsSubAdminCheck(){ | |||
$this->securityCheck('testIsSubAdminCheck', 'isSubAdminUser'); | |||
} | |||
/** | |||
* @IsLoggedInExemption | |||
* @CSRFExemption | |||
* @IsAdminExemption | |||
*/ | |||
public function testFailIsSubAdminCheck(){ | |||
$this->securityCheck('testFailIsSubAdminCheck', 'isSubAdminUser', true); | |||
} | |||
public function testAfterExceptionNotCaughtThrowsItAgain(){ | |||
$ex = new \Exception(); | |||
$this->setExpectedException('\Exception'); | |||
$this->middleware->afterException($this->controller, 'test', $ex); | |||
} | |||
public function testAfterExceptionReturnsRedirect(){ | |||
$api = $this->getMock('OC\AppFramework\Core\API', array(), array('test')); | |||
$this->controller = $this->getMock('OC\AppFramework\Controller\Controller', | |||
array(), array($api, new Request())); | |||
$this->request = new Request( | |||
array('server' => array('HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'))); | |||
$this->middleware = new SecurityMiddleware($api, $this->request); | |||
$response = $this->middleware->afterException($this->controller, 'test', | |||
$this->secException); | |||
$this->assertTrue($response instanceof RedirectResponse); | |||
} | |||
public function testAfterAjaxExceptionReturnsJSONError(){ | |||
$response = $this->middleware->afterException($this->controller, 'test', | |||
$this->secAjaxException); | |||
$this->assertTrue($response instanceof JSONResponse); | |||
} | |||
} |
@@ -0,0 +1,214 @@ | |||
<?php | |||
namespace OC\AppFramework\Routing; | |||
use OC\AppFramework\DependencyInjection\DIContainer; | |||
use OC\AppFramework\routing\RouteConfig; | |||
require_once(__DIR__ . "/../classloader.php"); | |||
class RouteConfigTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
public function testSimpleRoute() | |||
{ | |||
$routes = array('routes' => array( | |||
array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'GET') | |||
)); | |||
$this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); | |||
} | |||
public function testSimpleRouteWithMissingVerb() | |||
{ | |||
$routes = array('routes' => array( | |||
array('name' => 'folders#open', 'url' => '/folders/{folderId}/open') | |||
)); | |||
$this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); | |||
} | |||
public function testSimpleRouteWithLowercaseVerb() | |||
{ | |||
$routes = array('routes' => array( | |||
array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') | |||
)); | |||
$this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open'); | |||
} | |||
/** | |||
* @expectedException \UnexpectedValueException | |||
*/ | |||
public function testSimpleRouteWithBrokenName() | |||
{ | |||
$routes = array('routes' => array( | |||
array('name' => 'folders_open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') | |||
)); | |||
// router mock | |||
$router = $this->getMock("\OC_Router", array('create')); | |||
// load route configuration | |||
$container = new DIContainer('app1'); | |||
$config = new RouteConfig($container, $router, $routes); | |||
$config->register(); | |||
} | |||
public function testSimpleRouteWithUnderScoreNames() | |||
{ | |||
$routes = array('routes' => array( | |||
array('name' => 'admin_folders#open_current', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') | |||
)); | |||
$this->assertSimpleRoute($routes, 'admin_folders.open_current', 'DELETE', '/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); | |||
} | |||
public function testResource() | |||
{ | |||
$routes = array('resources' => array('accounts' => array('url' => '/accounts'))); | |||
$this->assertResource($routes, 'accounts', '/accounts', 'AccountsController', 'accountId'); | |||
} | |||
public function testResourceWithUnderScoreName() | |||
{ | |||
$routes = array('resources' => array('admin_accounts' => array('url' => '/admin/accounts'))); | |||
$this->assertResource($routes, 'admin_accounts', '/admin/accounts', 'AdminAccountsController', 'adminAccountId'); | |||
} | |||
private function assertSimpleRoute($routes, $name, $verb, $url, $controllerName, $actionName) | |||
{ | |||
// route mocks | |||
$route = $this->mockRoute($verb, $controllerName, $actionName); | |||
// router mock | |||
$router = $this->getMock("\OC_Router", array('create')); | |||
// we expect create to be called once: | |||
$router | |||
->expects($this->once()) | |||
->method('create') | |||
->with($this->equalTo('app1.' . $name), $this->equalTo($url)) | |||
->will($this->returnValue($route)); | |||
// load route configuration | |||
$container = new DIContainer('app1'); | |||
$config = new RouteConfig($container, $router, $routes); | |||
$config->register(); | |||
} | |||
private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName) | |||
{ | |||
// router mock | |||
$router = $this->getMock("\OC_Router", array('create')); | |||
// route mocks | |||
$indexRoute = $this->mockRoute('GET', $controllerName, 'index'); | |||
$showRoute = $this->mockRoute('GET', $controllerName, 'show'); | |||
$createRoute = $this->mockRoute('POST', $controllerName, 'create'); | |||
$updateRoute = $this->mockRoute('PUT', $controllerName, 'update'); | |||
$destroyRoute = $this->mockRoute('DELETE', $controllerName, 'destroy'); | |||
$urlWithParam = $url . '/{' . $paramName . '}'; | |||
// we expect create to be called once: | |||
$router | |||
->expects($this->at(0)) | |||
->method('create') | |||
->with($this->equalTo('app1.' . $resourceName . '.index'), $this->equalTo($url)) | |||
->will($this->returnValue($indexRoute)); | |||
$router | |||
->expects($this->at(1)) | |||
->method('create') | |||
->with($this->equalTo('app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam)) | |||
->will($this->returnValue($showRoute)); | |||
$router | |||
->expects($this->at(2)) | |||
->method('create') | |||
->with($this->equalTo('app1.' . $resourceName . '.create'), $this->equalTo($url)) | |||
->will($this->returnValue($createRoute)); | |||
$router | |||
->expects($this->at(3)) | |||
->method('create') | |||
->with($this->equalTo('app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam)) | |||
->will($this->returnValue($updateRoute)); | |||
$router | |||
->expects($this->at(4)) | |||
->method('create') | |||
->with($this->equalTo('app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam)) | |||
->will($this->returnValue($destroyRoute)); | |||
// load route configuration | |||
$container = new DIContainer('app1'); | |||
$config = new RouteConfig($container, $router, $yaml); | |||
$config->register(); | |||
} | |||
/** | |||
* @param $verb | |||
* @param $controllerName | |||
* @param $actionName | |||
* @return \PHPUnit_Framework_MockObject_MockObject | |||
*/ | |||
private function mockRoute($verb, $controllerName, $actionName) | |||
{ | |||
$container = new DIContainer('app1'); | |||
$route = $this->getMock("\OC_Route", array('method', 'action'), array(), '', false); | |||
$route | |||
->expects($this->exactly(1)) | |||
->method('method') | |||
->with($this->equalTo($verb)) | |||
->will($this->returnValue($route)); | |||
$route | |||
->expects($this->exactly(1)) | |||
->method('action') | |||
->with($this->equalTo(new RouteActionHandler($container, $controllerName, $actionName))) | |||
->will($this->returnValue($route)); | |||
return $route; | |||
} | |||
} | |||
/* | |||
# | |||
# sample routes.yaml for ownCloud | |||
# | |||
# the section simple describes one route | |||
routes: | |||
- name: folders#open | |||
url: /folders/{folderId}/open | |||
verb: GET | |||
# controller: name.split()[0] | |||
# action: name.split()[1] | |||
# for a resource following actions will be generated: | |||
# - index | |||
# - create | |||
# - show | |||
# - update | |||
# - destroy | |||
# - new | |||
resources: | |||
accounts: | |||
url: /accounts | |||
folders: | |||
url: /accounts/{accountId}/folders | |||
# actions can be used to define additional actions on the resource | |||
actions: | |||
- name: validate | |||
verb: GET | |||
on-collection: false | |||
* */ |
@@ -0,0 +1,58 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
* @author Bernhard Posselt | |||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\AppFramework\Utility; | |||
require_once __DIR__ . "/../classloader.php"; | |||
class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase { | |||
/** | |||
* @Annotation | |||
*/ | |||
public function testReadAnnotation(){ | |||
$reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', | |||
'testReadAnnotation'); | |||
$this->assertTrue($reader->hasAnnotation('Annotation')); | |||
} | |||
/** | |||
* @Annotation | |||
* @param test | |||
*/ | |||
public function testReadAnnotationNoLowercase(){ | |||
$reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', | |||
'testReadAnnotationNoLowercase'); | |||
$this->assertTrue($reader->hasAnnotation('Annotation')); | |||
$this->assertFalse($reader->hasAnnotation('param')); | |||
} | |||
} |