diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index d58a97e295617953fb8855929920fd57f3f50745..68f33d94995bdec65b735eba7677826a67ace7ff 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -1,4 +1,5 @@
 <?php
+
 /** @var $this \OCP\Route\IRouter */
 $this->create('core_ajax_public_preview', '/publicpreview')->action(
 	function() {
diff --git a/apps/files_sharing/application.php b/apps/files_sharing/application.php
new file mode 100644
index 0000000000000000000000000000000000000000..089ed6afbdaecb946cff9ee18798d7388de37455
--- /dev/null
+++ b/apps/files_sharing/application.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @author Lukas Reschke
+ * @copyright 2014 Lukas Reschke lukas@owncloud.com
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_Sharing;
+
+use OC\AppFramework\Utility\SimpleContainer;
+use OCA\Files_Sharing\Controllers\ShareController;
+use OCA\Files_Sharing\Middleware\SharingCheckMiddleware;
+use \OCP\AppFramework\App;
+
+/**
+ * @package OCA\Files_Sharing
+ */
+class Application extends App {
+
+
+	/**
+	 * @param array $urlParams
+	 */
+	public function __construct(array $urlParams=array()){
+		parent::__construct('files_sharing', $urlParams);
+
+		$container = $this->getContainer();
+
+		/**
+		 * Controllers
+		 */
+		$container->registerService('ShareController', function(SimpleContainer $c) {
+			return new ShareController(
+				$c->query('AppName'),
+				$c->query('Request'),
+				$c->query('UserSession'),
+				$c->query('ServerContainer')->getAppConfig(),
+				$c->query('ServerContainer')->getConfig(),
+				$c->query('URLGenerator'),
+				$c->query('ServerContainer')->getUserManager(),
+				$c->query('ServerContainer')->getLogger()
+			);
+		});
+
+		/**
+		 * Core class wrappers
+		 */
+		$container->registerService('UserSession', function(SimpleContainer $c) {
+			return $c->query('ServerContainer')->getUserSession();
+		});
+		$container->registerService('URLGenerator', function(SimpleContainer $c) {
+			return $c->query('ServerContainer')->getUrlGenerator();
+		});
+
+		/**
+		 * Middleware
+		 */
+		$container->registerService('SharingCheckMiddleware', function(SimpleContainer $c){
+			return new SharingCheckMiddleware(
+				$c->query('AppName'),
+				$c->query('ServerContainer')->getAppConfig(),
+				$c->getCoreApi()
+			);
+		});
+
+		// Execute middlewares
+		$container->registerMiddleware('SharingCheckMiddleware');
+	}
+
+}
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 52679a7158d09c1ccd722c723f059c5a23198d0d..0627ed6ab54dbcaabf45e7148bd654d9e7fed476 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -109,14 +109,12 @@ OCA.Sharing.PublicApp = {
 					filename = JSON.stringify(filename);
 				}
 				var path = dir || FileList.getCurrentDirectory();
+				var token = $('#sharingToken').val();
 				var params = {
-					service: 'files',
-					t: $('#sharingToken').val(),
 					path: path,
-					files: filename,
-					download: null
+					files: filename
 				};
-				return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
+				return OC.generateUrl('/s/'+token+'/download') + '?' + OC.buildQueryString(params);
 			};
 
 			this.fileList.getAjaxUrl = function (action, params) {
@@ -126,12 +124,11 @@ OCA.Sharing.PublicApp = {
 			};
 
 			this.fileList.linkTo = function (dir) {
+				var token = $('#sharingToken').val();
 				var params = {
-					service: 'files',
-					t: $('#sharingToken').val(),
 					dir: dir
 				};
-				return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
+				return OC.generateUrl('/s/'+token+'') + '?' + OC.buildQueryString(params);
 			};
 
 			this.fileList.generatePreviewUrl = function (urlSpec) {
@@ -193,8 +190,6 @@ OCA.Sharing.PublicApp = {
 
 	_onDirectoryChanged: function (e) {
 		OC.Util.History.pushState({
-			service: 'files',
-			t: $('#sharingToken').val(),
 			// arghhhh, why is this not called "dir" !?
 			path: e.dir
 		});
diff --git a/apps/files_sharing/lib/controllers/sharecontroller.php b/apps/files_sharing/lib/controllers/sharecontroller.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec99b93826f740b540b0f3eadfa5e0fe04fb3657
--- /dev/null
+++ b/apps/files_sharing/lib/controllers/sharecontroller.php
@@ -0,0 +1,271 @@
+<?php
+/**
+ * @author Clark Tomlinson <clark@owncloud.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @copyright 2014 Clark Tomlinson & Lukas Reschke
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_Sharing\Controllers;
+
+use OC;
+use OC\Files\Filesystem;
+use OC_Files;
+use OC_Util;
+use OCP;
+use OCP\Template;
+use OCP\JSON;
+use OCP\Share;
+use OCP\AppFramework\Controller;
+use OCP\IRequest;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\IApi;
+use OC\URLGenerator;
+use OC\AppConfig;
+use OCP\ILogger;
+use OCA\Files_Sharing\Helper;
+use OCP\User;
+use OCP\Util;
+
+/**
+ * Class ShareController
+ *
+ * @package OCA\Files_Sharing\Controllers
+ */
+class ShareController extends Controller {
+
+	/** @var \OC\User\Session */
+	protected $userSession;
+	/** @var \OC\AppConfig */
+	protected $appConfig;
+	/** @var \OCP\IConfig */
+	protected $config;
+	/** @var \OC\URLGenerator */
+	protected $urlGenerator;
+	/** @var \OC\User\Manager */
+	protected $userManager;
+	/** @var \OCP\ILogger */
+	protected $logger;
+
+	/**
+	 * @param string $appName
+	 * @param IRequest $request
+	 * @param OC\User\Session $userSession
+	 * @param AppConfig $appConfig
+	 * @param OCP\IConfig $config
+	 * @param URLGenerator $urlGenerator
+	 * @param OC\User\Manager $userManager
+	 * @param ILogger $logger
+	 */
+	public function __construct($appName,
+								IRequest $request,
+								OC\User\Session $userSession,
+								AppConfig $appConfig,
+								OCP\IConfig $config,
+								URLGenerator $urlGenerator,
+								OC\User\Manager $userManager,
+								ILogger $logger) {
+		parent::__construct($appName, $request);
+
+		$this->userSession = $userSession;
+		$this->appConfig = $appConfig;
+		$this->config = $config;
+		$this->urlGenerator = $urlGenerator;
+		$this->userManager = $userManager;
+		$this->logger = $logger;
+	}
+
+	/**
+	 * @PublicPage
+	 * @NoCSRFRequired
+	 *
+	 * @param string $token
+	 *
+	 * @return TemplateResponse|RedirectResponse
+	 */
+	public function showAuthenticate($token) {
+		$linkItem = Share::getShareByToken($token, false);
+
+		if(Helper::authenticate($linkItem)) {
+			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
+		}
+
+		return new TemplateResponse($this->appName, 'authenticate', array(), 'guest');
+	}
+
+	/**
+	 * @PublicPage
+	 *
+	 * Authenticates against password-protected shares
+	 * @param $token
+	 * @param string $password
+	 * @return RedirectResponse|TemplateResponse
+	 */
+	public function authenticate($token, $password = '') {
+		$linkItem = Share::getShareByToken($token, false);
+		if($linkItem === false) {
+			return new TemplateResponse('core', '404', array(), 'guest');
+		}
+
+		$authenticate = Helper::authenticate($linkItem, $password);
+
+		if($authenticate === true) {
+			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
+		}
+
+		return new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
+	}
+
+	/**
+	 * @PublicPage
+	 * @NoCSRFRequired
+	 *
+	 * @param string $token
+	 * @param string $path
+	 *
+	 * @return TemplateResponse
+	 */
+	public function showShare($token, $path = '') {
+		\OC_User::setIncognitoMode(true);
+
+		// Check whether share exists
+		$linkItem = Share::getShareByToken($token, false);
+		if($linkItem === false) {
+			return new TemplateResponse('core', '404', array(), 'guest');
+		}
+
+		$linkItem = OCP\Share::getShareByToken($token, false);
+		$shareOwner = $linkItem['uid_owner'];
+		$originalSharePath = null;
+		$rootLinkItem = OCP\Share::resolveReShare($linkItem);
+		if (isset($rootLinkItem['uid_owner'])) {
+			OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
+			OC_Util::tearDownFS();
+			OC_Util::setupFS($rootLinkItem['uid_owner']);
+			$originalSharePath = Filesystem::getPath($linkItem['file_source']);
+		}
+
+		// Share is password protected - check whether the user is permitted to access the share
+		if (isset($linkItem['share_with']) && !Helper::authenticate($linkItem)) {
+			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
+				array('token' => $token)));
+		}
+
+		if (Filesystem::isReadable($originalSharePath . $path)) {
+			$getPath = Filesystem::normalizePath($path);
+			$originalSharePath .= $path;
+		}
+
+		$dir = dirname($originalSharePath);
+		$file = basename($originalSharePath);
+
+		$shareTmpl = array();
+		$shareTmpl['displayName'] = User::getDisplayName($shareOwner);
+		$shareTmpl['filename'] = $file;
+		$shareTmpl['directory_path'] = $linkItem['file_target'];
+		$shareTmpl['mimetype'] = Filesystem::getMimeType($originalSharePath);
+		$shareTmpl['dirToken'] = $linkItem['token'];
+		$shareTmpl['sharingToken'] = $token;
+		$shareTmpl['server2serversharing'] = Helper::isOutgoingServer2serverShareEnabled();
+		$shareTmpl['protected'] = isset($linkItem['share_with']) ? 'true' : 'false';
+		$shareTmpl['dir'] = $dir;
+
+		// Show file list
+		if (Filesystem::is_dir($originalSharePath)) {
+			$shareTmpl['dir'] = $getPath;
+			$files = array();
+			$maxUploadFilesize = Util::maxUploadFilesize($originalSharePath);
+			$freeSpace = Util::freeSpace($originalSharePath);
+			$uploadLimit = Util::uploadLimit();
+			$folder = new Template('files', 'list', '');
+			$folder->assign('dir', $getPath);
+			$folder->assign('dirToken', $linkItem['token']);
+			$folder->assign('permissions', OCP\PERMISSION_READ);
+			$folder->assign('isPublic', true);
+			$folder->assign('publicUploadEnabled', 'no');
+			$folder->assign('files', $files);
+			$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
+			$folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
+			$folder->assign('freeSpace', $freeSpace);
+			$folder->assign('uploadLimit', $uploadLimit); // PHP upload limit
+			$folder->assign('usedSpacePercent', 0);
+			$folder->assign('trash', false);
+			$shareTmpl['folder'] = $folder->fetchPage();
+		}
+
+		$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', array('token' => $token));
+
+		return new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
+	}
+
+	/**
+	 * @PublicPage
+	 * @NoCSRFRequired
+	 * @param string $token
+	 * @param string $files
+	 * @param string $path
+	 * @return void|RedirectResponse
+	 */
+	public function downloadShare($token, $files = null, $path = '') {
+		\OC_User::setIncognitoMode(true);
+
+		$linkItem = OCP\Share::getShareByToken($token, false);
+
+		// Share is password protected - check whether the user is permitted to access the share
+		if (isset($linkItem['share_with'])) {
+			if(!Helper::authenticate($linkItem)) {
+				return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
+					array('token' => $token)));
+			}
+		}
+
+		$originalSharePath = self::getPath($token);
+
+		if (isset($originalSharePath) && Filesystem::isReadable($originalSharePath . $path)) {
+				$getPath = Filesystem::normalizePath($path);
+				$originalSharePath .= $getPath;
+		}
+
+		if (!is_null($files)) { // download selected files
+			$files_list = json_decode($files);
+			// in case we get only a single file
+			if ($files_list === NULL ) {
+				$files_list = array($files);
+			}
+
+			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
+			// after dispatching the request which results in a "Cannot modify header information" notice. 
+			OC_Files::get($originalSharePath, $files_list, $_SERVER['REQUEST_METHOD'] == 'HEAD');
+			exit();
+		} else {
+			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
+			// after dispatching the request which results in a "Cannot modify header information" notice.
+			OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $_SERVER['REQUEST_METHOD'] == 'HEAD');
+			exit();
+		}
+	}
+
+	/**
+	 * @param $token
+	 * @return null|string
+	 */
+	private function getPath($token) {
+		$linkItem = Share::getShareByToken($token, false);
+		$path = null;
+		if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
+			// seems to be a valid share
+			$rootLinkItem = Share::resolveReShare($linkItem);
+			if (isset($rootLinkItem['uid_owner'])) {
+				JSON::checkUserExists($rootLinkItem['uid_owner']);
+				OC_Util::tearDownFS();
+				OC_Util::setupFS($rootLinkItem['uid_owner']);
+				$path = Filesystem::getPath($linkItem['file_source']);
+			}
+		}
+		return $path;
+	}
+}
diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php
index e7ca4fcccd4e25f9e765af3ba561b0b2ffd36f1a..3a2d51cddb7f21b1900ed5b4cc717ef0be4cb162 100644
--- a/apps/files_sharing/lib/helper.php
+++ b/apps/files_sharing/lib/helper.php
@@ -95,7 +95,7 @@ class Helper {
 	 *
 	 * @return boolean true if authorized, false otherwise
 	 */
-	public static function authenticate($linkItem, $password) {
+	public static function authenticate($linkItem, $password = null) {
 		if ($password !== null) {
 			if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) {
 				// Check Password
diff --git a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php
new file mode 100644
index 0000000000000000000000000000000000000000..af79cd9e94aa4ca397a9bad86bcd94e075a4686f
--- /dev/null
+++ b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * @author Lukas Reschke
+ * @copyright 2014 Lukas Reschke lukas@owncloud.com
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_Sharing\Middleware;
+
+use OCP\AppFramework\IApi;
+use \OCP\AppFramework\Middleware;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\IAppConfig;
+
+/**
+ * Checks whether the "sharing check" is enabled
+ *
+ * @package OCA\Files_Sharing\Middleware
+ */
+class SharingCheckMiddleware extends Middleware {
+
+	/** @var string */
+	protected $appName;
+	/** @var IAppConfig */
+	protected $appConfig;
+	/** @var IApi */
+	protected $api;
+
+	/***
+	 * @param string $appName
+	 * @param IAppConfig $appConfig
+	 * @param IApi $api
+	 */
+	public function __construct($appName,
+								IAppConfig $appConfig,
+								IApi $api) {
+		$this->appName = $appName;
+		$this->appConfig = $appConfig;
+		$this->api = $api;
+	}
+
+	/**
+	 * Check if sharing is enabled before the controllers is executed
+	 */
+	public function beforeController($controller, $methodName) {
+		if(!$this->isSharingEnabled()) {
+			throw new \Exception('Sharing is disabled.');
+		}
+	}
+
+	/**
+	 * Return 404 page in case of an exception
+	 * @param \OCP\AppFramework\Controller $controller
+	 * @param string $methodName
+	 * @param \Exception $exception
+	 * @return TemplateResponse
+	 */
+	public function afterException($controller, $methodName, \Exception $exception){
+		return new TemplateResponse('core', '404', array(), 'guest');
+	}
+
+	/**
+	 * Check whether sharing is enabled
+	 * @return bool
+	 */
+	private function isSharingEnabled() {
+		// FIXME: This check is done here since the route is globally defined and not inside the files_sharing app
+		// Check whether the sharing application is enabled
+		if(!$this->api->isAppEnabled($this->appName)) {
+			return false;
+		}
+
+		// Check whether public sharing is enabled
+		if($this->appConfig->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
+			return false;
+		}
+
+		return true;
+	}
+
+}
diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php
index 4320c105103c48662acf1da234bb1e0821127d19..d9b8f0f4f303b69928467be958839b476d358169 100644
--- a/apps/files_sharing/public.php
+++ b/apps/files_sharing/public.php
@@ -1,205 +1,17 @@
 <?php
-// Load other apps for file previews
-use OCA\Files_Sharing\Helper;
-
-OC_App::loadApps();
-
-$appConfig = \OC::$server->getAppConfig();
-
-if ($appConfig->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
-	header('HTTP/1.0 404 Not Found');
-	$tmpl = new OCP\Template('', '404', 'guest');
-	$tmpl->printPage();
-	exit();
-}
-
-// Legacy sharing links via public.php have the token in $GET['t']
-if (isset($_GET['t'])) {
-	$token = $_GET['t'];
-}
-
-if (isset($token)) {
-	$linkItem = OCP\Share::getShareByToken($token, false);
-	if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
-		// seems to be a valid share
-		$type = $linkItem['item_type'];
-		$fileSource = $linkItem['file_source'];
-		$shareOwner = $linkItem['uid_owner'];
-		$path = null;
-		$rootLinkItem = OCP\Share::resolveReShare($linkItem);
-		if (isset($rootLinkItem['uid_owner'])) {
-			OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
-			OC_Util::tearDownFS();
-			OC_Util::setupFS($rootLinkItem['uid_owner']);
-			$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
-		}
-	}
-}
-if (isset($path)) {
-	if (!isset($linkItem['item_type'])) {
-		OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR);
-		header('HTTP/1.0 404 Not Found');
-		$tmpl = new OCP\Template('', '404', 'guest');
-		$tmpl->printPage();
-		exit();
-	}
-	if (isset($linkItem['share_with'])) {
-		// Authenticate share_with
-		$url = OCP\Util::linkToPublic('files') . '&t=' . $token;
-		if (isset($_GET['file'])) {
-			$url .= '&file=' . urlencode($_GET['file']);
-		} else {
-			if (isset($_GET['dir'])) {
-				$url .= '&dir=' . urlencode($_GET['dir']);
-			}
-		}
-		if (isset($_POST['password'])) {
-			$password = $_POST['password'];
-			if ($linkItem['share_type'] == OCP\Share::SHARE_TYPE_LINK) {
-				// Check Password
-				$forcePortable = (CRYPT_BLOWFISH != 1);
-				$hasher = new PasswordHash(8, $forcePortable);
-				if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''),
-											 $linkItem['share_with']))) {
-					OCP\Util::addStyle('files_sharing', 'authenticate');
-					$tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
-					$tmpl->assign('URL', $url);
-					$tmpl->assign('wrongpw', true);
-					$tmpl->printPage();
-					exit();
-				} else {
-					// Save item id in session for future requests
-					\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
-				}
-			} else {
-				OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type']
-										   .' for share id '.$linkItem['id'], \OCP\Util::ERROR);
-				header('HTTP/1.0 404 Not Found');
-				$tmpl = new OCP\Template('', '404', 'guest');
-				$tmpl->printPage();
-				exit();
-			}
-
-		} else {
-			// Check if item id is set in session
-			if ( ! \OC::$server->getSession()->exists('public_link_authenticated')
-				|| \OC::$server->getSession()->get('public_link_authenticated') !== $linkItem['id']
-			) {
-				// Prompt for password
-				OCP\Util::addStyle('files_sharing', 'authenticate');
-				$tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
-				$tmpl->assign('URL', $url);
-				$tmpl->printPage();
-				exit();
-			}
-		}
-	}
-	$basePath = $path;
-	$rootName = \OC_Util::basename($path);
-	if (isset($_GET['path']) && \OC\Files\Filesystem::isReadable($basePath . $_GET['path'])) {
-		$getPath = \OC\Files\Filesystem::normalizePath($_GET['path']);
-		$path .= $getPath;
-	} else {
-		$getPath = '';
-	}
-	$dir = dirname($path);
-	$file = basename($path);
-	// Download the file
-	if (isset($_GET['download'])) {
-		if (!\OCP\App::isEnabled('files_encryption')) {
-			// encryption app requires the session to store the keys in
-			\OC::$server->getSession()->close();
-		}
-		if (isset($_GET['files'])) { // download selected files
-			$files = $_GET['files'];
-			$files_list = json_decode($files);
-			// in case we get only a single file
-			if (!is_array($files_list)) {
-				$files_list = array($files);
-			}
-			OC_Files::get($path, $files_list, $_SERVER['REQUEST_METHOD'] == 'HEAD');
-		} else {
-			OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD');
-		}
-		exit();
-	} else {
-		OCP\Util::addScript('files', 'file-upload');
-		OCP\Util::addStyle('files_sharing', 'public');
-		OCP\Util::addStyle('files_sharing', 'mobile');
-		OCP\Util::addScript('files_sharing', 'public');
-		OCP\Util::addScript('files', 'fileactions');
-		OCP\Util::addScript('files', 'jquery.iframe-transport');
-		OCP\Util::addScript('files', 'jquery.fileupload');
-		$maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
-		$tmpl = new OCP\Template('files_sharing', 'public', 'base');
-		$tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner));
-		$tmpl->assign('filename', $file);
-		$tmpl->assign('directory_path', $linkItem['file_target']);
-		$tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path));
-		$tmpl->assign('dirToken', $linkItem['token']);
-		$tmpl->assign('sharingToken', $token);
-		$tmpl->assign('server2serversharing', Helper::isOutgoingServer2serverShareEnabled());
-		$tmpl->assign('protected', isset($linkItem['share_with']) ? 'true' : 'false');
-
-		$urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
-							.(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
-							.(isset($_GET['file'])?'&file='.$_GET['file']:'');
-		// Show file list
-		if (\OC\Files\Filesystem::is_dir($path)) {
-			$tmpl->assign('dir', $getPath);
-
-			OCP\Util::addStyle('files', 'files');
-			OCP\Util::addStyle('files', 'upload');
-			OCP\Util::addScript('files', 'filesummary');
-			OCP\Util::addScript('files', 'breadcrumb');
-			OCP\Util::addScript('files', 'files');
-			OCP\Util::addScript('files', 'filelist');
-			OCP\Util::addscript('files', 'keyboardshortcuts');
-			$files = array();
-			$rootLength = strlen($basePath) + 1;
-			$maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
-
-			$freeSpace=OCP\Util::freeSpace($path);
-			$uploadLimit=OCP\Util::uploadLimit();
-			$folder = new OCP\Template('files', 'list', '');
-			$folder->assign('dir', $getPath);
-			$folder->assign('dirToken', $linkItem['token']);
-			$folder->assign('permissions', OCP\PERMISSION_READ);
-			$folder->assign('isPublic', true);
-			$folder->assign('publicUploadEnabled', 'no');
-			$folder->assign('files', $files);
-			$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
-			$folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
-			$folder->assign('freeSpace', $freeSpace);
-			$folder->assign('uploadLimit', $uploadLimit); // PHP upload limit
-			$folder->assign('usedSpacePercent', 0);
-			$folder->assign('trash', false);
-			$tmpl->assign('folder', $folder->fetchPage());
-			$tmpl->assign('downloadURL',
-				OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=' . urlencode($getPath));
-		} else {
-			$tmpl->assign('dir', $dir);
-
-			// Show file preview if viewer is available
-			if ($type == 'file') {
-				$tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download');
-			} else {
-				$tmpl->assign('downloadURL', OCP\Util::linkToPublic('files')
-										.$urlLinkIdentifiers.'&download&path='.urlencode($getPath));
-			}
-		}
-		$tmpl->printPage();
-	}
-	exit();
-} else {
-	OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
-}
-
-$errorTemplate = new OCP\Template('files_sharing', 'part.404', '');
-$errorContent = $errorTemplate->fetchPage();
-
-header('HTTP/1.0 404 Not Found');
-OCP\Util::addStyle('files_sharing', '404');
-$tmpl = new OCP\Template('', '404', 'guest');
-$tmpl->assign('content', $errorContent);
-$tmpl->printPage();
+/**
+ * @author Lukas Reschke
+ * @copyright 2014 Lukas Reschke lukas@owncloud.com
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+// This file is just used to redirect the legacy sharing URLs (< ownCloud 8) to the new ones
+
+$urlGenerator = new \OC\URLGenerator(\OC::$server->getConfig());
+$token = isset($_GET['t']) ? $_GET['t'] : '';
+$route = isset($_GET['download']) ? 'files_sharing.sharecontroller.downloadshare' : 'files_sharing.sharecontroller.showshare';
+
+OC_Response::redirect($urlGenerator->linkToRoute($route, array('token' => $token)));
diff --git a/apps/files_sharing/templates/authenticate.php b/apps/files_sharing/templates/authenticate.php
index 0c4ac6ca44537975961f459f8d9250ee0834a1ab..e3aa62b9eced716b8ac338be40ecec7b5d4cf255 100644
--- a/apps/files_sharing/templates/authenticate.php
+++ b/apps/files_sharing/templates/authenticate.php
@@ -1,4 +1,9 @@
-<form action="<?php p($_['URL']); ?>" method="post">
+<?php
+	/** @var $_ array */
+	/** @var $l OC_L10N */
+	style('files_sharing', 'authenticate');
+?>
+<form method="post">
 	<fieldset>
 		<?php if (!isset($_['wrongpw'])): ?>
 			<div class="warning-info"><?php p($l->t('This share is password-protected')); ?></div>
@@ -8,6 +13,7 @@
 		<?php endif; ?>
 		<p>
 			<label for="password" class="infield"><?php p($l->t('Password')); ?></label>
+			<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
 			<input type="password" name="password" id="password"
 				placeholder="<?php p($l->t('Password')); ?>" value=""
 				autocomplete="off" autocapitalize="off" autocorrect="off"
diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php
index 46bf90b1b4128e587f0378528ff2248c86334f4c..6b875d3c2b76df0abfce4a8879755853b15ba9fe 100644
--- a/apps/files_sharing/templates/public.php
+++ b/apps/files_sharing/templates/public.php
@@ -1,8 +1,28 @@
-<?php /** @var $l OC_L10N */ ?>
 <?php
+/** @var $l OC_L10N */
+/** @var $_ array */
+
+OCP\Util::addScript('files', 'file-upload');
+OCP\Util::addStyle('files_sharing', 'public');
+OCP\Util::addStyle('files_sharing', 'mobile');
+OCP\Util::addScript('files_sharing', 'public');
+OCP\Util::addScript('files', 'fileactions');
+OCP\Util::addScript('files', 'jquery.iframe-transport');
+OCP\Util::addScript('files', 'jquery.fileupload');
+
+// JS required for folders
+OCP\Util::addStyle('files', 'files');
+OCP\Util::addStyle('files', 'upload');
+OCP\Util::addScript('files', 'filesummary');
+OCP\Util::addScript('files', 'breadcrumb');
+OCP\Util::addScript('files', 'files');
+OCP\Util::addScript('files', 'filelist');
+OCP\Util::addscript('files', 'keyboardshortcuts');
+
 $thumbSize=1024;
 $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'false';
 ?>
+
 <?php if ( \OC\Preview::isMimeSupported($_['mimetype'])): /* This enables preview images for links (e.g. on Facebook, Google+, ...)*/?>
 	<link rel="image_src" href="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $thumbSize, 'y' => $thumbSize, 'file' => $_['directory_path'], 't' => $_['dirToken']))); ?>" />
 <?php endif; ?>
@@ -24,7 +44,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
 
 <header><div id="header" class="<?php p((isset($_['folder']) ? 'share-folder' : 'share-file')) ?>">
 		<a href="<?php print_unescaped(link_to('', 'index.php')); ?>"
-			title="" id="owncloud">
+		   title="" id="owncloud">
 			<div class="logo-wide svg"></div>
 		</a>
 		<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
@@ -48,7 +68,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
 				</a>
 			</span>
 		</div>
-</div></header>
+	</div></header>
 <div id="content">
 	<div id="preview">
 		<?php if (isset($_['folder'])): ?>
diff --git a/apps/files_sharing/tests/controller/sharecontroller.php b/apps/files_sharing/tests/controller/sharecontroller.php
new file mode 100644
index 0000000000000000000000000000000000000000..357184ba6923c18511f3be188fc2b103d05aee9b
--- /dev/null
+++ b/apps/files_sharing/tests/controller/sharecontroller.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @copyright 2014 Lukas Reschke
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_Sharing\Controllers;
+
+use OC\Files\Filesystem;
+use OCA\Files_Sharing\Application;
+use OCP\AppFramework\IAppContainer;
+use OCP\Files;
+use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\Security\ISecureRandom;
+use OC\Files\View;
+use OCP\Share;
+use OC\URLGenerator;
+
+/**
+ * @package OCA\Files_Sharing\Controllers
+ */
+class ShareControllerTest extends \PHPUnit_Framework_TestCase {
+
+	/** @var IAppContainer */
+	private $container;
+	/** @var string */
+	private $user;
+	/** @var string */
+	private $token;
+	/** @var string */
+	private $oldUser;
+	/** @var ShareController */
+	private $shareController;
+	/** @var URLGenerator */
+	private $urlGenerator;
+
+	protected function setUp() {
+		$app = new Application();
+		$this->container = $app->getContainer();
+		$this->container['Config'] = $this->getMockBuilder('\OCP\IConfig')
+			->disableOriginalConstructor()->getMock();
+		$this->container['AppName'] = 'files_sharing';
+		$this->container['UserSession'] = $this->getMockBuilder('\OC\User\Session')
+			->disableOriginalConstructor()->getMock();
+		$this->container['URLGenerator'] = $this->getMockBuilder('\OC\URLGenerator')
+			->disableOriginalConstructor()->getMock();
+		$this->urlGenerator = $this->container['URLGenerator'];
+		$this->shareController = $this->container['ShareController'];
+
+		// Store current user
+		$this->oldUser = \OC_User::getUser();
+
+		// Create a dummy user
+		$this->user = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(12, ISecureRandom::CHAR_LOWER);
+
+		\OC_User::createUser($this->user, $this->user);
+		\OC_Util::tearDownFS();
+		\OC_User::setUserId('');
+		Filesystem::tearDown();
+		\OC_User::setUserId($this->user);
+		\OC_Util::setupFS($this->user);
+
+		// Create a dummy shared file
+		$view = new View('/'. $this->user . '/files');
+		$view->file_put_contents('file1.txt', 'I am such an awesome shared file!');
+		$this->token = \OCP\Share::shareItem(
+			Filesystem::getFileInfo('file1.txt')->getType(),
+			Filesystem::getFileInfo('file1.txt')->getId(),
+			\OCP\Share::SHARE_TYPE_LINK,
+			'IAmPasswordProtected!',
+			1
+		);
+	}
+
+	protected function tearDown() {
+		\OC_Util::tearDownFS();
+		\OC_User::setUserId('');
+		Filesystem::tearDown();
+		\OC_User::deleteUser($this->user);
+		\OC_User::setIncognitoMode(false);
+
+		\OC::$server->getSession()->set('public_link_authenticated', '');
+
+		// Set old user
+		\OC_User::setUserId($this->oldUser);
+		\OC_Util::setupFS($this->oldUser);
+	}
+
+	public function testShowAuthenticate() {
+		$linkItem = \OCP\Share::getShareByToken($this->token, false);
+
+		// Test without being authenticated
+		$response = $this->shareController->showAuthenticate($this->token);
+		$expectedResponse =  new TemplateResponse($this->container['AppName'], 'authenticate', array(), 'guest');
+		$this->assertEquals($expectedResponse, $response);
+
+		// Test with being authenticated for another file
+		\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']-1);
+		$response = $this->shareController->showAuthenticate($this->token);
+		$expectedResponse =  new TemplateResponse($this->container['AppName'], 'authenticate', array(), 'guest');
+		$this->assertEquals($expectedResponse, $response);
+
+		// Test with being authenticated for the correct file
+		\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
+		$response = $this->shareController->showAuthenticate($this->token);
+		$expectedResponse =  new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $this->token)));
+		$this->assertEquals($expectedResponse, $response);
+	}
+
+	public function testAuthenticate() {
+		// Test without a not existing token
+		$response = $this->shareController->authenticate('ThisTokenShouldHopefullyNeverExistSoThatTheUnitTestWillAlwaysPass :)');
+		$expectedResponse =  new TemplateResponse('core', '404', array(), 'guest');
+		$this->assertEquals($expectedResponse, $response);
+
+		// Test with a valid password
+		$response = $this->shareController->authenticate($this->token, 'IAmPasswordProtected!');
+		$expectedResponse =  new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $this->token)));
+		$this->assertEquals($expectedResponse, $response);
+
+		// Test with a invalid password
+		$response = $this->shareController->authenticate($this->token, 'WrongPw!');
+		$expectedResponse =  new TemplateResponse($this->container['AppName'], 'authenticate', array('wrongpw' => true), 'guest');
+		$this->assertEquals($expectedResponse, $response);
+	}
+
+	public function testShowShare() {
+		// Test without a not existing token
+		$response = $this->shareController->showShare('ThisTokenShouldHopefullyNeverExistSoThatTheUnitTestWillAlwaysPass :)');
+		$expectedResponse =  new TemplateResponse('core', '404', array(), 'guest');
+		$this->assertEquals($expectedResponse, $response);
+
+		// Test with a password protected share and no authentication
+		$response = $this->shareController->showShare($this->token);
+		$expectedResponse = new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate', array('token' => $this->token)));
+		$this->assertEquals($expectedResponse, $response);
+
+		// Test with password protected share and authentication
+		$linkItem = Share::getShareByToken($this->token, false);
+		\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
+		$response = $this->shareController->showShare($this->token);
+		$sharedTmplParams = array(
+			'displayName' => $this->user,
+			'filename' => 'file1.txt',
+			'directory_path' => '/file1.txt',
+			'mimetype' => 'text/plain',
+			'dirToken' => $this->token,
+			'sharingToken' => $this->token,
+			'server2serversharing' => true,
+			'protected' => 'true',
+			'dir' => '/',
+			'downloadURL' => null
+		);
+		$expectedResponse = new TemplateResponse($this->container['AppName'], 'public', $sharedTmplParams, 'base');
+		$this->assertEquals($expectedResponse, $response);
+	}
+
+	public function testDownloadShare() {
+		// Test with a password protected share and no authentication
+		$response = $this->shareController->downloadShare($this->token);
+		$expectedResponse = new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
+			array('token' => $this->token)));
+		$this->assertEquals($expectedResponse, $response);
+	}
+}
diff --git a/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php b/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php
new file mode 100644
index 0000000000000000000000000000000000000000..90c9a7bba1074fb51b9e61454a15810b86f940e1
--- /dev/null
+++ b/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @copyright 2014 Lukas Reschke
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_Sharing\Middleware;
+
+
+/**
+ * @package OCA\Files_Sharing\Middleware\SharingCheckMiddleware
+ */
+class SharingCheckMiddlewareTest extends \PHPUnit_Framework_TestCase {
+
+	/** @var \OCP\IAppConfig */
+	private $appConfig;
+	/** @var \OCP\AppFramework\IApi */
+	private $api;
+	/** @var SharingCheckMiddleware */
+	private $sharingCheckMiddleware;
+
+	protected function setUp() {
+		$this->appConfig = $this->getMockBuilder('\OCP\IAppConfig')
+			->disableOriginalConstructor()->getMock();
+		$this->api = $this->getMockBuilder('\OCP\AppFramework\IApi')
+			->disableOriginalConstructor()->getMock();
+
+		$this->sharingCheckMiddleware = new SharingCheckMiddleware('files_sharing', $this->appConfig, $this->api);
+	}
+
+	public function testIsSharingEnabledWithEverythingEnabled() {
+		$this->api
+			->expects($this->once())
+			->method('isAppEnabled')
+			->with('files_sharing')
+			->will($this->returnValue(true));
+
+		$this->appConfig
+			->expects($this->once())
+			->method('getValue')
+			->with('core', 'shareapi_allow_links', 'yes')
+			->will($this->returnValue('yes'));
+
+		$this->assertTrue(\Test_Helper::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
+	}
+
+	public function testIsSharingEnabledWithAppDisabled() {
+		$this->api
+			->expects($this->once())
+			->method('isAppEnabled')
+			->with('files_sharing')
+			->will($this->returnValue(false));
+
+		$this->assertFalse(\Test_Helper::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
+	}
+
+	public function testIsSharingEnabledWithSharingDisabled() {
+		$this->api
+			->expects($this->once())
+			->method('isAppEnabled')
+			->with('files_sharing')
+			->will($this->returnValue(true));
+
+		$this->appConfig
+			->expects($this->once())
+			->method('getValue')
+			->with('core', 'shareapi_allow_links', 'yes')
+			->will($this->returnValue('no'));
+
+		$this->assertFalse(\Test_Helper::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
+	}
+}
diff --git a/apps/files_sharing/tests/testcase.php b/apps/files_sharing/tests/testcase.php
index 78277dc907f0512adf8696eab37dd1dee626c4cc..034baa785da218e20ac3de9539ed4785f7959365 100644
--- a/apps/files_sharing/tests/testcase.php
+++ b/apps/files_sharing/tests/testcase.php
@@ -22,6 +22,7 @@
 
 namespace OCA\Files_Sharing\Tests;
 
+use OC\Files\Filesystem;
 use OCA\Files\Share;
 
 /**
@@ -115,6 +116,10 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
 		} else {
 			\OC_App::disable('files_encryption');
 		}
+
+		\OC_Util::tearDownFS();
+		\OC_User::setUserId('');
+		Filesystem::tearDown();
 	}
 
 	/**
diff --git a/core/routes.php b/core/routes.php
index 92545d0322ee5fa39ba2c72047b4e967c1a6320e..ced70898f501ce973d239aacf40e446b6d7bfdfe 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -95,9 +95,22 @@ $this->create('core_avatar_post_cropped', '/avatar/cropped')
 	->action('OC\Core\Avatar\Controller', 'postCroppedAvatar');
 
 // Sharing routes
-$this->create('core_share_show_share', '/s/{token}')
-	->get()
-	->action('OC\Core\Share\Controller', 'showShare');
+$this->create('files_sharing.sharecontroller.showShare', '/s/{token}')->action(function($urlParams) {
+	$app = new \OCA\Files_Sharing\Application($urlParams);
+	$app->dispatch('ShareController', 'showShare');
+});
+$this->create('files_sharing.sharecontroller.authenticate', '/s/{token}/authenticate')->post()->action(function($urlParams) {
+	$app = new \OCA\Files_Sharing\Application($urlParams);
+	$app->dispatch('ShareController', 'authenticate');
+});
+$this->create('files_sharing.sharecontroller.showAuthenticate', '/s/{token}/authenticate')->get()->action(function($urlParams) {
+	$app = new \OCA\Files_Sharing\Application($urlParams);
+	$app->dispatch('ShareController', 'showAuthenticate');
+});
+$this->create('files_sharing.sharecontroller.downloadShare', '/s/{token}/download')->get()->action(function($urlParams) {
+	$app = new \OCA\Files_Sharing\Application($urlParams);
+	$app->dispatch('ShareController', 'downloadShare');
+});
 
 // used for heartbeat
 $this->create('heartbeat', '/heartbeat')->action(function(){
diff --git a/core/share/controller.php b/core/share/controller.php
deleted file mode 100644
index c1741af0d982e2c572b8bf1dd6d8c515e1439405..0000000000000000000000000000000000000000
--- a/core/share/controller.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Christopher Schäpers <christopher@schaepers.it>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-namespace OC\Core\Share;
-
-class Controller {
-	public static function showShare($args) {
-		\OC_Util::checkAppEnabled('files_sharing');
-
-		$token = $args['token'];
-
-		\OC_App::loadApp('files_sharing');
-		\OC_User::setIncognitoMode(true);
-
-		require_once \OC_App::getAppPath('files_sharing') .'/public.php';
-	}
-}
-?>