diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css
new file mode 100644
index 0000000000000000000000000000000000000000..aa76c06175bdc662e3f6d8a284db14ae640741bc
--- /dev/null
+++ b/apps/files_sharing/css/public.css
@@ -0,0 +1,2 @@
+#content { position:relative; }
+#preview p { text-align: center; }
\ No newline at end of file
diff --git a/apps/files_sharing/get.php b/apps/files_sharing/get.php
deleted file mode 100644
index bcbe5985fb6f2b80fc88becb03e0dee9d590de65..0000000000000000000000000000000000000000
--- a/apps/files_sharing/get.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// only need authentication apps
-$RUNTIME_APPTYPES=array('authentication');
-OC_App::loadApps($RUNTIME_APPTYPES);
-
-OCP\JSON::checkAppEnabled('files_sharing');
-//FIXME lib_share / OC_Share no longer exists
-require_once 'lib_share.php';
-
-//get the path of the shared file
-if (isset($_GET['token']) && $source = OC_Share::getSource($_GET['token'])) {
-	$token = $_GET['token'];
-	// TODO Manipulating the string may not be the best choice. Is there an alternative?
-	$user = substr($source, 1, strpos($source, "/", 1) - 1);
-	OC_Util::setupFS($user);
-	$source = substr($source, strlen("/".$user."/files"));
-	$subPath = isset( $_GET['path'] ) ? $_GET['path'] : '';
-	$root = $source;
-	$source .= $subPath;
-	if (!OC_Filesystem::file_exists($source)) {
-		header("HTTP/1.0 404 Not Found");
-		$tmpl = new OCP\Template("", "404", "guest");
-		$tmpl->assign("file", $subPath);
-		$tmpl->printPage();
-		exit;
-	}
-	if (OC_Filesystem::is_dir($source)) {
-		$files = array();
-		$rootLength = strlen($root);
-		foreach (OC_Files::getdirectorycontent($source) as $i) {
-			$i['date'] = OCP\Util::formatDate($i['mtime'] );
-			if ($i['type'] == 'file') {
-				$fileinfo = pathinfo($i['name']);
-				$i['basename'] = $fileinfo['filename'];
-				$i['extension'] = isset($fileinfo['extension']) ? ('.'.$fileinfo['extension']) : '';
-			}
-			$i['directory'] = substr($i['directory'], $rootLength);
-			if ($i['directory'] == "/") {
-				$i['directory'] = "";
-			}
-			$files[] = $i;
-		}
-		// Make breadcrumb
-		$breadcrumb = array();
-		$pathtohere = "";
-		foreach (explode("/", $subPath) as $i) {
-			if ($i != "") {
-				$pathtohere .= "/$i";
-				$breadcrumb[] = array("dir" => $pathtohere, "name" => $i);
-			}
-		}
-		// Load the files we need
-		OCP\Util::addStyle("files", "files");
-		$breadcrumbNav = new OCP\Template("files", "part.breadcrumb", "");
-		$breadcrumbNav->assign("breadcrumb", $breadcrumb);
-		$breadcrumbNav->assign("baseURL", OCP\Util::linkTo("", "public.php")."?service=files&token=".$token."&path=");
-		$list = new OCP\Template("files", "part.list", "");
-		$list->assign("files", $files);
-		$list->assign("baseURL", OCP\Util::linkTo("", "public.php")."?service=files&token=".$token."&path=");
-		$list->assign("downloadURL", OCP\Util::linkTo("", "public.php")."?service=files&token=".$token."&path=");
-		$list->assign("readonly", true);
-		$tmpl = new OCP\Template("files", "index", "user");
-		$tmpl->assign("fileList", $list->fetchPage(), false);
-		$tmpl->assign("breadcrumb", $breadcrumbNav->fetchPage());
-		$tmpl->assign("readonly", true);
-		$tmpl->assign("allowZipDownload", false);
-		$tmpl->assign("dir", 'shared dir');
-		$tmpl->printPage();
-	} else {
-		//get time mimetype and set the headers
-		$mimetype = OC_Filesystem::getMimeType($source);
-		header("Content-Transfer-Encoding: binary");
-		OCP\Response::disableCaching();
-		header('Content-Disposition: attachment; filename="'.basename($source).'"');
-		header("Content-Type: " . $mimetype);
-		header("Content-Length: " . OC_Filesystem::filesize($source));
-		//download the file
-		@ob_clean();
-		//FIXME OC_Share no longer exists
-		OCP\Util::emitHook('OC_Share', 'public-download', array('source'=>$source, 'token'=>$token));
-		OC_Filesystem::readfile($source);
-	}
-} else {
-	header("HTTP/1.0 404 Not Found");
-	$tmpl = new OCP\Template("", "404", "guest");
-	$tmpl->printPage();
-	die();
-}
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
new file mode 100644
index 0000000000000000000000000000000000000000..755382e073648c503117b77546734b5a5110404d
--- /dev/null
+++ b/apps/files_sharing/js/public.js
@@ -0,0 +1,18 @@
+// Override download path to files_sharing/public.php
+function fileDownloadPath(dir, file) {
+	return $('#downloadURL').val();
+}
+
+$(document).ready(function() {
+
+	if (typeof FileActions !== 'undefined') {
+		var mimetype = $('#mimetype').val();
+		// Show file preview if previewer is available, images are already handled by the template
+		if (mimetype.substr(0, mimetype.indexOf('/')) != 'image') {
+			// Trigger default action if not download TODO
+			var action = FileActions.getDefault(mimetype, 'file', FileActions.PERMISSION_READ);
+			action($('#filename').val());
+		}
+	}
+
+});
\ No newline at end of file
diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php
new file mode 100644
index 0000000000000000000000000000000000000000..15dac576d98ae22138a367d475866220809904c0
--- /dev/null
+++ b/apps/files_sharing/public.php
@@ -0,0 +1,69 @@
+<?php
+// Load other apps for file previews
+OC_App::loadApps();
+if (isset($_GET['file'])) {
+	$pos = strpos($_GET['file'], '/', 1);
+	$uidOwner = substr($_GET['file'], 1, $pos - 1);
+	if (OCP\User::userExists($uidOwner)) {
+		OC_Util::setupFS($uidOwner);
+		$file = substr($_GET['file'], $pos);
+		$fileSource = OC_Filecache::getId($_GET['file'], '');
+		if ($linkItem = OCP\Share::getItemSharedWithByLink('file', $fileSource, $uidOwner)) {
+			if (isset($linkItem['share_with'])) {
+				// Check password
+				if (isset($_POST['password'])) {
+					$password = $_POST['password'];
+					$storedHash = $linkItem['share_with'];
+					$forcePortable = (CRYPT_BLOWFISH != 1);
+					$hasher = new PasswordHash(8, $forcePortable);
+					if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), $storedHash))) {
+						$tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
+						$tmpl->assign('error', true);
+						$tmpl->printPage();
+						exit();
+					}
+					// Continue on if password is valid
+				} else {
+					// Prompt for password
+					$tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
+					$tmpl->printPage();
+					exit();
+				}
+			}
+			$path = $linkItem['path'];
+			// Download the file
+			if (isset($_GET['download'])) {
+				$mimetype = OC_Filesystem::getMimeType($path);
+				header('Content-Transfer-Encoding: binary');
+				header('Content-Disposition: attachment; filename="'.basename($path).'"');
+				header('Content-Type: '.$mimetype);
+				header('Content-Length: '.OC_Filesystem::filesize($path));
+				OCP\Response::disableCaching();
+				@ob_clean();
+				OC_Filesystem::readfile($path);
+			} else {
+				OCP\Util::addStyle('files_sharing', 'public');
+				OCP\Util::addScript('files_sharing', 'public');
+				OCP\Util::addScript('files', 'fileactions');
+				$tmpl = new OCP\Template('files_sharing', 'public', 'guest');
+				$tmpl->assign('owner', $uidOwner);
+				$tmpl->assign('name', basename($path));
+				// Show file list
+				if (OC_Filesystem::is_dir($path)) {
+					// TODO
+				} else {
+					// Show file preview if viewer is available
+					$tmpl->assign('dir', dirname($path));
+					$tmpl->assign('filename', basename($path));
+					$tmpl->assign('mimetype', OC_Filesystem::getMimeType($path));
+					$tmpl->assign('downloadURL', OCP\Util::linkToPublic('files').'&file='.$_GET['file'].'&download');
+				}
+				$tmpl->printPage();
+			}
+			exit();
+		}
+	}
+}
+header('HTTP/1.0 404 Not Found');
+$tmpl = new OCP\Template('', '404', 'guest');
+$tmpl->printPage();
\ No newline at end of file
diff --git a/apps/files_sharing/templates/authenticate.php b/apps/files_sharing/templates/authenticate.php
new file mode 100644
index 0000000000000000000000000000000000000000..41064d5146495598f55d52b65e2d118d360cc669
--- /dev/null
+++ b/apps/files_sharing/templates/authenticate.php
@@ -0,0 +1,9 @@
+<form action="index.php" method="post">
+	<fieldset>
+		<p>
+			<label for="password" class="infield"><?php echo $l->t('Password'); ?></label>
+			<input type="password" name="password" id="password" value="" />
+			<input type="submit" value="<?php echo $l->t('Submit'); ?>" />
+		</p>
+	</fieldset>
+</form>
\ No newline at end of file
diff --git a/apps/files_sharing/templates/get.php b/apps/files_sharing/templates/get.php
deleted file mode 100755
index 57275f07a3d6db68f32042cbd802934aab183ce8..0000000000000000000000000000000000000000
--- a/apps/files_sharing/templates/get.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<table>
-	<thead>
-		<tr>
-			<th id="headerSize"><?php echo $l->t( 'Size' ); ?></th>
-			<th id="headerDate"><span id="modified"><?php echo $l->t( 'Modified' ); ?></span><span class="selectedActions"><a href="" class="delete"><?php echo $l->t('Delete all')?> <img class="svg" alt="<?php echo $l->t('Delete')?>" src="<?php echo OCP\image_path("core", "actions/delete.svg"); ?>" /></a></span></th>
-		</tr>
-	</thead>
-	<tbody id="fileList" data-readonly="<?php echo $_['readonly'];?>">
-		<?php echo($_['fileList']); ?>
-	</tbody>
-</table>
\ No newline at end of file
diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php
new file mode 100755
index 0000000000000000000000000000000000000000..065818c2200e5b77337df8caeb7c84d36ecc4f97
--- /dev/null
+++ b/apps/files_sharing/templates/public.php
@@ -0,0 +1,13 @@
+<input type="hidden" name="dir" value="<?php echo $_['dir'] ?>" id="dir">
+<input type="hidden" name="downloadURL" value="<?php echo $_['downloadURL'] ?>" id="downloadURL">
+<input type="hidden" name="filename" value="<?php echo $_['filename'] ?>" id="filename">
+<input type="hidden" name="mimetype" value="<?php echo $_['mimetype'] ?>" id="mimetype">
+<div id="preview">
+	<p><?php echo $_['owner']; ?> shared the file <?php echo $_['name'] ?> with you</p>
+</div>
+<div id="content">
+	<?php if (substr($_['mimetype'], 0 , strpos($_['mimetype'], '/')) == 'image'): ?>
+		<img src="<?php echo $_['downloadURL']; ?>" />
+	<?php endif; ?>
+</div>
+<a href="<?php echo $_['downloadURL']; ?>">Download</a>
\ No newline at end of file
diff --git a/core/js/js.js b/core/js/js.js
index 86e802cd3483907a48d12847c48618a896970b8b..0c842f05593289513ef371733b36c279ab74877f 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -29,6 +29,16 @@ function t(app,text){
 }
 t.cache={};
 
+/**
+* Get the path to download a file
+* @param file The filename
+* @param dir The directory the file is in - e.g. $('#dir').val()
+* @return string
+*/
+function fileDownloadPath(dir, file) {
+	return OC.filePath('files', 'ajax', 'download.php')+encodeURIComponent('?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir));
+}
+
 OC={
 	webroot:oc_webroot,
 	appswebroots:oc_appswebroots,
diff --git a/lib/helper.php b/lib/helper.php
index 8c362747a27f9859642cf11a1ff254d14d9dd9ef..3cf464dfa7bf617f97a5f4fdb6bea888b5f51863 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -100,6 +100,17 @@ class OC_Helper {
 		return self::linkToAbsolute( '', 'remote.php') . '/' . $service . (($add_slash && $service[strlen($service)-1]!='/')?'/':'');
 	}
 
+	/**
+	 * @brief Creates an absolute url for public use
+	 * @param $service id
+	 * @returns the url
+	 *
+	 * Returns a absolute url to the given service.
+	 */
+	public static function linkToPublic($service, $add_slash = false) {
+		return self::linkToAbsolute( '', 'public.php') . '?service=' . $service . (($add_slash && $service[strlen($service)-1]!='/')?'/':'');
+	}
+
 	/**
 	 * @brief Creates path to an image
 	 * @param $app app
diff --git a/lib/public/share.php b/lib/public/share.php
index 9ee7ef0516baafd5f3e6b6357c254189e602186f..15fb73d8d88a09e19838b597402fa5b466b86c92 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -32,7 +32,7 @@ class Share {
 
 	const SHARE_TYPE_USER = 0;
 	const SHARE_TYPE_GROUP = 1;
-	const SHARE_TYPE_PRIVATE_LINK = 3;
+	const SHARE_TYPE_LINK = 3;
 	const SHARE_TYPE_EMAIL = 4;
 	const SHARE_TYPE_CONTACT = 5;
 	const SHARE_TYPE_REMOTE = 6;
@@ -112,6 +112,17 @@ class Share {
 		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections, true);
 	}
 
+	/**
+	* @brief Get the item of item type shared by a link
+	* @param string Item type
+	* @param string Item source
+	* @param string Owner of link
+	* @return Item
+	*/
+	public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
+		return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1);
+	}
+
 	/**
 	* @brief Get the shared items of item type owned by the current user
 	* @param string Item type
@@ -138,7 +149,7 @@ class Share {
 	* @brief Share an item with a user, group, or via private link
 	* @param string Item type
 	* @param string Item source
-	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_PRIVATE_LINK
+	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
 	* @param string User or group the item is being shared with
 	* @param int CRUDS permissions
 	* @return bool Returns true on success or false on failure
@@ -198,9 +209,14 @@ class Share {
 			$shareWith = array();
 			$shareWith['group'] = $group;
 			$shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner));
-		} else if ($shareType === self::SHARE_TYPE_PRIVATE_LINK) {
-				$shareWith = md5(uniqid($itemSource, true));
-				return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions);
+		} else if ($shareType === self::SHARE_TYPE_LINK) {
+			// Generate hash of password - same method as user passwords
+			if (isset($shareWith)) {
+				$forcePortable = (CRYPT_BLOWFISH != 1);
+				$hasher = new \PasswordHash(8, $forcePortable);
+				$shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', ''));
+			}
+			return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions);
 		} else if ($shareType === self::SHARE_TYPE_CONTACT) {
 			if (!\OC_App::isEnabled('contacts')) {
 				$message = 'Sharing '.$itemSource.' failed, because the contacts app is not enabled';
@@ -262,7 +278,7 @@ class Share {
 	* @brief Unshare an item from a user, group, or delete a private link
 	* @param string Item type
 	* @param string Item source
-	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_PRIVATE_LINK
+	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
 	* @param string User or group the item is being shared with
 	* @return Returns true on success or false on failure
 	*/
@@ -298,7 +314,7 @@ class Share {
 	* @brief Set the permissions of an item for a specific user or group
 	* @param string Item type
 	* @param string Item source
-	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_PRIVATE_LINK
+	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
 	* @param string User or group the item is being shared with
 	* @param int CRUDS permissions
 	* @return Returns true on success or false on failure
@@ -407,7 +423,7 @@ class Share {
 	* @brief Get shared items from the database
 	* @param string Item type
 	* @param string Item source or target (optional)
-	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_PRIVATE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
+	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
 	* @param string User or group the item is being shared with
 	* @param string User that is the owner of shared items (optional)
 	* @param int Format to convert items to with formatItems()
@@ -444,9 +460,9 @@ class Share {
 				$queryArgs = array($itemType);
 			}
 		}
-		if (isset($shareType) && isset($shareWith)) {
+		if (isset($shareType)) {
 			// Include all user and group items
-			if ($shareType == self::$shareTypeUserAndGroups) {
+			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
 				$where .= ' AND `share_type` IN (?,?,?)';
 				$queryArgs[] = self::SHARE_TYPE_USER;
 				$queryArgs[] = self::SHARE_TYPE_GROUP;
@@ -459,9 +475,12 @@ class Share {
 				$where .= ' AND `uid_owner` != ?';
 				$queryArgs[] = $shareWith;
 			} else {
-				$where .= ' AND `share_type` = ? AND `share_with` = ?';
+				$where .= ' AND `share_type` = ?';
 				$queryArgs[] = $shareType;
-				$queryArgs[] = $shareWith;
+				if (isset($shareWith)) {
+					$where .= ' AND `share_with` = ?';
+					$queryArgs[] = $shareWith;
+				}
 			}
 		}
 		if (isset($uidOwner)) {
@@ -650,7 +669,7 @@ class Share {
 					$column = 'path';
 				}
 				foreach ($items as $item) {
-					if ($item['share_type'] == self::SHARE_TYPE_PRIVATE_LINK) {
+					if ($item['share_type'] == self::SHARE_TYPE_LINK) {
 						$statuses[$item[$column]] = true;
 					} else if (!isset($statuses[$item[$column]])) {
 						$statuses[$item[$column]] = false;
@@ -670,7 +689,7 @@ class Share {
 	* @brief Put shared item into the database
 	* @param string Item type
 	* @param string Item source
-	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_PRIVATE_LINK
+	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
 	* @param string User or group the item is being shared with
 	* @param int CRUDS permissions
 	* @param bool|array Parent folder target (optional)
@@ -827,7 +846,7 @@ class Share {
 	* @brief Generate a unique target for the item
 	* @param string Item type
 	* @param string Item source
-	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_PRIVATE_LINK
+	* @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
 	* @param string User or group the item is being shared with
 	* @return string Item target
 	*
@@ -836,7 +855,7 @@ class Share {
 	*/
 	private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner) {
 		$backend = self::getBackend($itemType);
-		if ($shareType == self::SHARE_TYPE_PRIVATE_LINK) {
+		if ($shareType == self::SHARE_TYPE_LINK) {
 			return $backend->generateTarget($itemSource, false);
 		} else {
 			if ($itemType == 'file' || $itemType == 'folder') {
diff --git a/lib/public/util.php b/lib/public/util.php
index 9f6f6f32e1e2d7117f60736fab4d2032c0ef59b4..8d7303bf7a4eba130170efccc749c30610e62579 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -144,6 +144,17 @@ class Util {
 		return(\OC_Helper::linkToRemote( $service ));
 	}
 
+	/**
+	 * @brief Creates an absolute url for public use
+	 * @param $service id
+	 * @returns the url
+	 *
+	 * Returns a absolute url to the given app and file.
+	 */
+	public static function linkToPublic($service) {
+		return \OC_Helper::linkToPublic($service);
+	}
+
 
 	/**
 	* @brief Creates an url