allow admin to enforce passwords for public link shares

This commit is contained in:
Bjoern Schiessle 2014-05-12 12:19:07 +02:00
parent dab3cb65cf
commit b6e14af861
9 changed files with 135 additions and 32 deletions

View File

@ -418,13 +418,18 @@ class Api {
return new \OC_OCS_Result(null, 404, "share doesn't exists, can't change password"); return new \OC_OCS_Result(null, 404, "share doesn't exists, can't change password");
} }
$result = \OCP\Share::shareItem( try {
$itemType, $result = \OCP\Share::shareItem(
$itemSource, $itemType,
\OCP\Share::SHARE_TYPE_LINK, $itemSource,
$shareWith, \OCP\Share::SHARE_TYPE_LINK,
$permissions $shareWith,
); $permissions
);
} catch (\Exception $e) {
return new \OC_OCS_Result(null, 403, $e->getMessage());
}
if($result) { if($result) {
return new \OC_OCS_Result(); return new \OC_OCS_Result();
} }

View File

@ -113,11 +113,65 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
$fileinfo = $this->view->getFileInfo($this->folder); $fileinfo = $this->view->getFileInfo($this->folder);
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
} }
function testEnfoceLinkPassword() {
$appConfig = \OC::$server->getAppConfig();
$appConfig->setValue('core', 'shareapi_enforce_links_password', 'yes');
// don't allow to share link without a password
$_POST['path'] = $this->folder;
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
$result = Share\Api::createShare(array());
$this->assertFalse($result->succeeded());
// don't allow to share link without a empty password
$_POST['path'] = $this->folder;
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
$_POST['password'] = '';
$result = Share\Api::createShare(array());
$this->assertFalse($result->succeeded());
// share with password should succeed
$_POST['path'] = $this->folder;
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
$_POST['password'] = 'foo';
$result = Share\Api::createShare(array());
$this->assertTrue($result->succeeded());
$data = $result->getData();
// setting new password should succeed
$params = array();
$params['id'] = $data['id'];
$params['_put'] = array();
$params['_put']['password'] = 'bar';
$result = Share\Api::updateShare($params);
$this->assertTrue($result->succeeded());
// removing password should fail
$params = array();
$params['id'] = $data['id'];
$params['_put'] = array();
$params['_put']['password'] = '';
$result = Share\Api::updateShare($params);
$this->assertFalse($result->succeeded());
// cleanup
$fileinfo = $this->view->getFileInfo($this->folder);
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
$appConfig->setValue('core', 'shareapi_enforce_links_password', 'no');
}
/** /**
* @medium * @medium
* @depends testCreateShare * @depends testCreateShare

View File

@ -79,6 +79,7 @@ $array = array(
'defaultExpireDateEnabled' => $defaultExpireDateEnabled, 'defaultExpireDateEnabled' => $defaultExpireDateEnabled,
'defaultExpireDate' => $defaultExpireDate, 'defaultExpireDate' => $defaultExpireDate,
'defaultExpireDateEnforced' => $enforceDefaultExpireDate, 'defaultExpireDateEnforced' => $enforceDefaultExpireDate,
'enforcePasswordForPublicLink' => \OCP\Util::isPublicLinkPasswordRequired(),
) )
) )
), ),

View File

@ -230,11 +230,11 @@ OC.Share={
} }
html += '<input id="linkText" type="text" readonly="readonly" />'; html += '<input id="linkText" type="text" readonly="readonly" />';
html += '<input type="checkbox" name="showPassword" id="showPassword" value="1" style="display:none;" /><label for="showPassword" style="display:none;">'+t('core', 'Password protect')+'</label>'; html += '<input type="checkbox" name="showPassword" id="showPassword" value="1" style="display:none;" /><label for="showPassword" style="display:none;">'+t('core', 'Password protect')+'</label>';
html += '<div id="linkPass">'; html += '<div id="linkPass">';
html += '<input id="linkPassText" type="password" placeholder="'+t('core', 'Password')+'" />'; html += '<input id="linkPassText" type="password" placeholder="'+t('core', 'Choose a password for the public link')+'" />';
html += '</div>'; html += '</div>';
if (itemType === 'folder' && (possiblePermissions & OC.PERMISSION_CREATE) && publicUploadEnabled === 'yes') { if (itemType === 'folder' && (possiblePermissions & OC.PERMISSION_CREATE) && publicUploadEnabled === 'yes') {
html += '<div id="allowPublicUploadWrapper" style="display:none;">'; html += '<div id="allowPublicUploadWrapper" style="display:none;">';
html += '<input type="checkbox" value="1" name="allowPublicUpload" id="sharingDialogAllowPublicUpload"' + ((allowPublicUploadStatus) ? 'checked="checked"' : '') + ' />'; html += '<input type="checkbox" value="1" name="allowPublicUpload" id="sharingDialogAllowPublicUpload"' + ((allowPublicUploadStatus) ? 'checked="checked"' : '') + ' />';
@ -494,8 +494,10 @@ OC.Share={
$('#linkText').val(link); $('#linkText').val(link);
$('#linkText').show('blind'); $('#linkText').show('blind');
$('#linkText').css('display','block'); $('#linkText').css('display','block');
$('#showPassword').show(); if (oc_appconfig.core.enforcePasswordForPublicLink === false || password === null) {
$('#showPassword+label').show(); $('#showPassword').show();
$('#showPassword+label').show();
}
if (password != null) { if (password != null) {
$('#linkPass').show('blind'); $('#linkPass').show('blind');
$('#showPassword').attr('checked', true); $('#showPassword').attr('checked', true);
@ -512,7 +514,7 @@ OC.Share={
$('#defaultExpireMessage').hide(); $('#defaultExpireMessage').hide();
$('#showPassword').hide(); $('#showPassword').hide();
$('#showPassword+label').hide(); $('#showPassword+label').hide();
$('#linkPass').hide(); $('#linkPass').hide('blind');
$('#emailPrivateLink #email').hide(); $('#emailPrivateLink #email').hide();
$('#emailPrivateLink #emailButton').hide(); $('#emailPrivateLink #emailButton').hide();
$('#allowPublicUploadWrapper').hide(); $('#allowPublicUploadWrapper').hide();
@ -643,20 +645,27 @@ $(document).ready(function() {
var itemSourceName = $('#dropdown').data('item-source-name'); var itemSourceName = $('#dropdown').data('item-source-name');
if (this.checked) { if (this.checked) {
// Create a link // Create a link
OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', OC.PERMISSION_READ, itemSourceName, function(data) { if (oc_appconfig.core.enforcePasswordForPublicLink === false) {
OC.Share.showLink(data.token, null, itemSource); OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', OC.PERMISSION_READ, itemSourceName, function(data) {
OC.Share.updateIcon(itemType, itemSource); OC.Share.showLink(data.token, null, itemSource);
}); OC.Share.updateIcon(itemType, itemSource);
});
} else {
$('#linkPass').toggle('blind');
$('#linkPassText').focus();
}
} else { } else {
// Delete private link // Delete private link
OC.Share.unshare(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', function() { OC.Share.hideLink();
OC.Share.hideLink(); if ($('#linkText').val() !== '') {
OC.Share.itemShares[OC.Share.SHARE_TYPE_LINK] = false; OC.Share.unshare(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', function() {
OC.Share.updateIcon(itemType, itemSource); OC.Share.itemShares[OC.Share.SHARE_TYPE_LINK] = false;
if (typeof OC.Share.statuses[itemSource] === 'undefined') { OC.Share.updateIcon(itemType, itemSource);
$('#expiration').hide('blind'); if (typeof OC.Share.statuses[itemSource] === 'undefined') {
} $('#expiration').hide('blind');
}); }
});
}
} }
}); });
@ -728,11 +737,16 @@ $(document).ready(function() {
permissions = OC.PERMISSION_READ; permissions = OC.PERMISSION_READ;
} }
OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, function() { OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, function(data) {
console.log("password set to: '" + linkPassText.val() +"' by event: " + event.type);
linkPassText.val(''); linkPassText.val('');
linkPassText.attr('placeholder', t('core', 'Password protected')); linkPassText.attr('placeholder', t('core', 'Password protected'));
if (oc_appconfig.core.enforcePasswordForPublicLink) {
OC.Share.showLink(data.token, "password set", itemSource);
OC.Share.updateIcon(itemType, itemSource);
}
}); });
} }
}); });

View File

@ -588,7 +588,9 @@ class Share extends \OC\Share\Constants {
$shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner)); $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner));
} else if ($shareType === self::SHARE_TYPE_LINK) { } else if ($shareType === self::SHARE_TYPE_LINK) {
if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') { if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
// when updating a link share // when updating a link share
// FIXME Don't delete link if we update it
if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
$uidOwner, self::FORMAT_NONE, null, 1)) { $uidOwner, self::FORMAT_NONE, null, 1)) {
// remember old token // remember old token
@ -599,7 +601,7 @@ class Share extends \OC\Share\Constants {
} }
// Generate hash of password - same method as user passwords // Generate hash of password - same method as user passwords
if (isset($shareWith)) { if (!empty($shareWith)) {
$forcePortable = (CRYPT_BLOWFISH != 1); $forcePortable = (CRYPT_BLOWFISH != 1);
$hasher = new \PasswordHash(8, $forcePortable); $hasher = new \PasswordHash(8, $forcePortable);
$shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', '')); $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', ''));
@ -611,6 +613,13 @@ class Share extends \OC\Share\Constants {
} }
} }
if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
$message = 'You need to provide a password to create a public link, only protected links are allowed';
$message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
\OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
throw new \Exception($message_t);
}
// Generate token // Generate token
if (isset($oldToken)) { if (isset($oldToken)) {
$token = $oldToken; $token = $oldToken;

View File

@ -86,6 +86,16 @@ class OC_Util {
return true; return true;
} }
/**
* @brief check if a password is required for each public link
* @return boolean
*/
public static function isPublicLinkPasswordRequired() {
$appConfig = \OC::$server->getAppConfig();
$enforcePassword = $appConfig->getValue('core', 'shareapi_enforce_links_password', 'no');
return ($enforcePassword === 'yes') ? true : false;
}
/** /**
* Get the quota of a user * Get the quota of a user
* @param string $user * @param string $user

View File

@ -499,4 +499,12 @@ class Util {
public static function generateRandomBytes($length = 30) { public static function generateRandomBytes($length = 30) {
return \OC_Util::generateRandomBytes($length); return \OC_Util::generateRandomBytes($length);
} }
/**
* @brief check if a password is required for each public link
* @return boolean
*/
public static function isPublicLinkPasswordRequired() {
return \OC_Util::isPublicLinkPasswordRequired();
}
} }

View File

@ -60,6 +60,7 @@ $tmpl->assign('isConnectedViaHTTPS', $connectedHTTPS);
$tmpl->assign('enforceHTTPSEnabled', OC_Config::getValue( "forcessl", false)); $tmpl->assign('enforceHTTPSEnabled', OC_Config::getValue( "forcessl", false));
$tmpl->assign('allowLinks', OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes')); $tmpl->assign('allowLinks', OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes'));
$tmpl->assign('enforceLinkPassword', \OCP\Util::isPublicLinkPasswordRequired());
$tmpl->assign('allowPublicUpload', OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes')); $tmpl->assign('allowPublicUpload', OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'));
$tmpl->assign('allowResharing', OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes')); $tmpl->assign('allowResharing', OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes'));
$tmpl->assign('allowMailNotification', OC_Appconfig::getValue('core', 'shareapi_allow_mail_notification', 'yes')); $tmpl->assign('allowMailNotification', OC_Appconfig::getValue('core', 'shareapi_allow_mail_notification', 'yes'));

View File

@ -217,9 +217,10 @@ if (!$_['internetconnectionworking']) {
<input type="checkbox" name="shareapi_allow_links" id="allowLinks" <input type="checkbox" name="shareapi_allow_links" id="allowLinks"
value="1" <?php if ($_['allowLinks'] === 'yes') print_unescaped('checked="checked"'); ?> /> value="1" <?php if ($_['allowLinks'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="allowLinks"><?php p($l->t('Allow links'));?></label><br/> <label for="allowLinks"><?php p($l->t('Allow links'));?></label><br/>
<div <?php ($_['allowLinks'] === 'yes') ? print_unescaped('class="indent"') : print_unescaped('class="hidden indent"');?> id="publicLinkSettings"> <div <?php ($_['allowLinks'] === 'yes') ? print_unescaped('class="indent"') : print_unescaped('class="hidden indent"');?> id="publicLinkSettings">
<input type="checkbox" name="shareapi_enforce_links_password" id="enforceLinkPassword"
value="1" <?php if ($_['enforceLinkPassword']) print_unescaped('checked="checked"'); ?> />
<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection'));?></label><br/>
<input type="checkbox" name="shareapi_allow_public_upload" id="allowPublicUpload" <input type="checkbox" name="shareapi_allow_public_upload" id="allowPublicUpload"
value="1" <?php if ($_['allowPublicUpload'] == 'yes') print_unescaped('checked="checked"'); ?> /> value="1" <?php if ($_['allowPublicUpload'] == 'yes') print_unescaped('checked="checked"'); ?> />
<label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/> <label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/>