merge master into input-simplify

This commit is contained in:
Jan-Christoph Borchardt 2013-10-04 17:08:34 +03:00
commit 041837de2c
70 changed files with 2026 additions and 467 deletions

View File

@ -7,16 +7,35 @@
.actions input, .actions button, .actions .button { margin:0; float:left; }
.actions .button a { color: #555; }
.actions .button a:hover, .actions .button a:active { color: #333; }
#new {
height: 17px;
#new, #trash {
z-index: 1010;
float: left;
padding: 0 !important; /* override default control bar button padding */
}
#trash {
margin: 0 1em;
float: right;
}
#new>a, #trash>a {
padding: 14px 10px;
position: relative;
top: 7px;
}
#new.active {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: none;
}
#new.active { border-bottom-left-radius:0; border-bottom-right-radius:0; border-bottom:none; }
#new>a { padding:.5em 1.2em .3em; }
#new>ul {
display:none; position:fixed; min-width:7em; z-index:10;
padding:.5em; padding-bottom:0; margin-top:.075em; margin-left:-.5em;
display: none;
position: fixed;
min-width: 7em;
z-index: 10;
padding: .5em;
padding-bottom: 0;
margin-top: 14px;
margin-left: -1px;
text-align:left;
background: #f8f8f8;
border: 1px solid #ddd;
@ -27,58 +46,16 @@
#new>ul>li { height:36px; margin:.3em; padding-left:3em; padding-bottom:0.1em;
background-repeat:no-repeat; cursor:pointer; }
#new>ul>li>p { cursor:pointer; padding-top: 7px; padding-bottom: 7px;}
#new>ul>li>form>input {
padding: 5px;
margin: 2px 0;
}
#trash {
margin: 0 1em;
height: 17px;
z-index: 1010;
float: right;
}
#upload {
height:27px; padding:0; margin-left:0.2em; overflow:hidden;
}
#upload a {
position:relative; display:block; width:100%; height:27px;
cursor:pointer; z-index:10;
background-image:url('%webroot%/core/img/actions/upload.svg');
background-repeat:no-repeat;
background-position:7px 6px;
opacity:0.65;
}
.file_upload_target { display:none; }
.file_upload_form { display:inline; float:left; margin:0; padding:0; cursor:pointer; overflow:visible; }
#file_upload_start {
left:0; top:0; width:28px; height:27px; padding:0;
font-size:1em;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0;
z-index:20; position:relative; cursor:pointer; overflow:hidden;
}
#uploadprogresswrapper {
position: relative;
display: inline;
}
#uploadprogressbar {
position:relative;
float: left;
margin-left: 12px;
width: 130px;
height: 26px;
display:inline-block;
}
#uploadprogressbar + stop {
font-size: 13px;
}
/* FILE TABLE */
#filestable { position: relative; top:37px; width:100%; }
#filestable {
position: relative;
top: 44px;
width: 100%;
}
#filestable tbody tr { background-color:#fff; height:2.5em; }
#filestable tbody tr:hover, tbody tr:active {
background-color: rgb(240,240,240);
@ -132,9 +109,18 @@ table th#headerDate, table td.date {
/* Multiselect bar */
#filestable.multiselect {
top: 88px;
top: 95px;
}
table.multiselect thead {
position: fixed;
top: 89px;
z-index: 1;
-moz-box-sizing: border-box;
box-sizing: border-box;
left: 0;
padding-left: 80px;
width: 100%;
}
table.multiselect thead { position:fixed; top:82px; z-index:1; -moz-box-sizing: border-box; box-sizing: border-box; left: 0; padding-left: 80px; width:100%; }
table.multiselect thead th {
background-color: rgba(210,210,210,.7);
@ -335,8 +321,6 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
#scanning-message{ top:40%; left:40%; position:absolute; display:none; }
div.crumb a{ padding:0.9em 0 0.7em 0; color:#555; }
table.dragshadow {
width:auto;
}

View File

@ -1,38 +1,63 @@
#upload {
height:27px; padding:0; margin-left:0.2em; overflow:hidden;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 36px;
width: 39px;
padding: 0 !important; /* override default control bar button padding */
margin-left: .2em;
overflow: hidden;
vertical-align: top;
}
#upload a {
position:relative; display:block; width:100%; height:27px;
cursor:pointer; z-index:10;
background-image:url('%webroot%/core/img/actions/upload.svg');
background-repeat:no-repeat;
background-position:7px 6px;
opacity:0.65;
position: relative;
display: block;
width: 100%;
height: 44px;
width: 44px;
margin: -5px -3px;
cursor: pointer;
z-index: 10;
background-image: url('%webroot%/core/img/actions/upload.svg');
background-repeat: no-repeat;
background-position: center;
opacity: .65;
}
.file_upload_target { display:none; }
.file_upload_form { display:inline; float:left; margin:0; padding:0; cursor:pointer; overflow:visible; }
#file_upload_start {
float: left;
left:0; top:0; width:28px; height:27px; padding:0;
font-size:1em;
position: relative;
left: 0;
top: 0;
width: 44px;
height: 44px;
margin: -5px -3px;
padding: 0;
font-size: 1em;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0;
z-index:20; position:relative; cursor:pointer; overflow:hidden;
z-index: 20;
cursor: pointer;
overflow: hidden;
}
#uploadprogresswrapper {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
margin:0.3em;
height: 29px;
height: 36px;
box-sizing: border-box;
}
#uploadprogresswrapper > input[type='button'] {
height: 36px;
}
#uploadprogressbar {
position:relative;
float: left;
margin-left: 12px;
width: 130px;
height: 26px;
height: 36px;
display:inline-block;
}
#uploadprogressbar + stop {

View File

@ -104,8 +104,12 @@ if ($needUpgrade) {
$storageInfo=OC_Helper::getStorageInfo($dir);
$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir);
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
// if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code)
$encryptionInitStatus = 2;
if (OC_App::isEnabled('files_encryption')) {
$publicUploadEnabled = 'no';
$session = new \OCA\Encryption\Session(new \OC\Files\View('/'));
$encryptionInitStatus = $session->getInitialized();
}
$trashEnabled = \OCP\App::isEnabled('files_trashbin');
@ -113,7 +117,7 @@ if ($needUpgrade) {
if ($trashEnabled) {
$trashEmpty = \OCA\Files_Trashbin\Trashbin::isEmpty($user);
}
OCP\Util::addscript('files', 'fileactions');
OCP\Util::addscript('files', 'files');
OCP\Util::addscript('files', 'keyboardshortcuts');
@ -133,7 +137,10 @@ if ($needUpgrade) {
$tmpl->assign('isPublic', false);
$tmpl->assign('publicUploadEnabled', $publicUploadEnabled);
$tmpl->assign("encryptedFiles", \OCP\Util::encryptedFiles());
$tmpl->assign("mailNotificationEnabled", \OC_Appconfig::getValue('core', 'shareapi_allow_mail_notification', 'yes'));
$tmpl->assign("encryptionInitStatus", $encryptionInitStatus);
$tmpl->assign('disableSharing', false);
$tmpl->assign('ajaxLoad', $ajaxLoad);
$tmpl->printPage();
}

View File

@ -895,6 +895,10 @@ $(document).ready(function(){
$(window).trigger('beforeunload');
});
function decodeQuery(query){
return query.replace(/\+/g, ' ');
}
function parseHashQuery(){
var hash = window.location.hash,
pos = hash.indexOf('?'),
@ -911,11 +915,11 @@ $(document).ready(function(){
dir = '/';
// try and parse from URL hash first
if (query){
params = OC.parseQueryString(query);
params = OC.parseQueryString(decodeQuery(query));
}
// else read from query attributes
if (!params){
params = OC.parseQueryString(location.search);
params = OC.parseQueryString(decodeQuery(location.search));
}
return (params && params.dir) || '/';
}

View File

@ -63,6 +63,15 @@ Files={
}
var encryptedFiles = $('#encryptedFiles').val();
var initStatus = $('#encryptionInitStatus').val();
if (initStatus === '0') { // enc not initialized, but should be
OC.Notification.show(t('files_encryption', 'Encryption App is enabled but your keys are not initialized, please log-out and log-in again'));
return;
}
if (initStatus === '1') { // encryption tried to init but failed
OC.Notification.showHtml(t('files_encryption', 'Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files.'));
return;
}
if (encryptedFiles === '1') {
OC.Notification.show(t('files_encryption', 'Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files.'));
return;

View File

@ -116,3 +116,5 @@
<input type="hidden" name="allowZipDownload" id="allowZipDownload" value="<?php p($_['allowZipDownload']); ?>" />
<input type="hidden" name="usedSpacePercent" id="usedSpacePercent" value="<?php p($_['usedSpacePercent']); ?>" />
<input type="hidden" name="encryptedFiles" id="encryptedFiles" value="<?php $_['encryptedFiles'] ? p('1') : p('0'); ?>" />
<input type="hidden" name="encryptedInitStatus" id="encryptionInitStatus" value="<?php p($_['encryptionInitStatus']) ?>" />
<input type="hidden" name="mailNotificationEnabled" id="mailNotificationEnabled" value="<?php p($_['mailNotificationEnabled']) ?>" />

View File

@ -48,6 +48,7 @@ if ($decryptedKey) {
// success or failure
if ($return) {
$session->setInitialized(\OCA\Encryption\Session::INIT_SUCCESSFUL);
\OCP\JSON::success(array('data' => array('message' => $l->t('Private key password successfully updated.'))));
} else {
\OCP\JSON::error(array('data' => array('message' => $l->t('Could not update the private key password. Maybe the old password was not correct.'))));

View File

@ -43,23 +43,6 @@ if (!OC_Config::getValue('maintenance', false)) {
if($sessionReady) {
$session = new \OCA\Encryption\Session($view);
}
$user = \OCP\USER::getUser();
// check if user has a private key
if ($sessionReady === false
|| (!$view->file_exists('/' . $user . '/files_encryption/' . $user . '.private.key')
&& OCA\Encryption\Crypt::mode() === 'server')
) {
// Force the user to log-in again if the encryption key isn't unlocked
// (happens when a user is logged in before the encryption app is
// enabled)
OCP\User::logout();
header("Location: " . OC::$WEBROOT . '/');
exit();
}
}
} else {
// logout user if we are in maintenance to force re-login

View File

@ -1 +1 @@
0.4
0.5

View File

@ -1,23 +1,33 @@
<?php
if (!isset($_)) { //also provide standalone error page
require_once __DIR__ . '/../../../lib/base.php';
$l = OC_L10N::get('files_encryption');
$errorMsg = $l->t('Your private key is not valid! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files.');
if (isset($_GET['i']) && $_GET['i'] === '0') {
$errorMsg = $l->t('Encryption app not initialized! Maybe the encryption app was re-enabled during your session. Please try to log out and log back in to initialize the encryption app.');
$init = '0';
} else {
$errorMsg = $l->t('Your private key is not valid! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files.');
$init = '1';
}
if(isset($_GET['p']) && $_GET['p'] === '1') {
if (isset($_GET['p']) && $_GET['p'] === '1') {
header('HTTP/1.0 404 ' . $errorMsg);
}
// check if ajax request
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
// check if ajax request
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
\OCP\JSON::error(array('data' => array('message' => $errorMsg)));
} else {
header('HTTP/1.0 404 ' . $errorMsg);
$tmpl = new OC_Template('files_encryption', 'invalid_private_key', 'guest');
$tmpl->assign('message', $errorMsg);
$tmpl->assign('init', $init);
$tmpl->printPage();
}
exit;
}

View File

@ -159,7 +159,6 @@ class Hooks {
* @param array $params keys: uid, password
*/
public static function setPassphrase($params) {
// Only attempt to change passphrase if server-side encryption
// is in use (client-side encryption does not have access to
// the necessary keys)
@ -543,14 +542,18 @@ class Hooks {
}
/**
* set migration status back to '0' so that all new files get encrypted
* set migration status and the init status back to '0' so that all new files get encrypted
* if the app gets enabled again
* @param array $params contains the app ID
*/
public static function preDisable($params) {
if ($params['app'] === 'files_encryption') {
$query = \OC_DB::prepare('UPDATE `*PREFIX*encryption` SET `migration_status`=0');
$query->execute();
$setMigrationStatus = \OC_DB::prepare('UPDATE `*PREFIX*encryption` SET `migration_status`=0');
$setMigrationStatus->execute();
$session = new \OCA\Encryption\Session(new \OC\Files\View('/'));
$session->setInitialized(\OCA\Encryption\Session::NOT_INITIALIZED);
}
}

View File

@ -1,6 +1,8 @@
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>, Robin Appelman
* <icewind1991@gmail.com>
* Copyright (c) 2013
* Sam Tuke <samtuke@owncloud.com>
* Robin Appelman <icewind1991@gmail.com>
* Bjoern Schiessle <schiessle@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
@ -31,22 +33,23 @@ $(document).ready(function(){
// Trigger ajax on recoveryAdmin status change
var enabledStatus = $('#adminEnableRecovery').val();
$('input:password[name="recoveryPassword"]').keyup(function(event) {
var recoveryPassword = $( '#recoveryPassword' ).val();
$('input:password[name="encryptionRecoveryPassword"]').keyup(function(event) {
var recoveryPassword = $( '#encryptionRecoveryPassword' ).val();
var recoveryPasswordRepeated = $( '#repeatEncryptionRecoveryPassword' ).val();
var checkedButton = $('input:radio[name="adminEnableRecovery"]:checked').val();
var uncheckedValue = (1+parseInt(checkedButton)) % 2;
if (recoveryPassword != '' ) {
if (recoveryPassword !== '' && recoveryPassword === recoveryPasswordRepeated) {
$('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').removeAttr("disabled");
} else {
$('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').attr("disabled", "true");
}
});
$( 'input:radio[name="adminEnableRecovery"]' ).change(
$( 'input:radio[name="adminEnableRecovery"]' ).change(
function() {
var recoveryStatus = $( this ).val();
var oldStatus = (1+parseInt(recoveryStatus)) % 2;
var recoveryPassword = $( '#recoveryPassword' ).val();
var recoveryPassword = $( '#encryptionRecoveryPassword' ).val();
$.post(
OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' )
, { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword }
@ -57,11 +60,10 @@ $(document).ready(function(){
} else {
OC.Notification.hide();
if (recoveryStatus === "0") {
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
$('input:password[name="changeRecoveryPassword"]').attr("disabled", "true");
$('input:password[name="changeRecoveryPassword"]').val("");
$('p[name="changeRecoveryPasswordBlock"]').addClass("hidden");
} else {
$('input:password[name="changeRecoveryPassword"]').removeAttr("disabled");
$('input:password[name="changeRecoveryPassword"]').val("");
$('p[name="changeRecoveryPasswordBlock"]').removeClass("hidden");
}
}
}
@ -72,9 +74,11 @@ $(document).ready(function(){
// change recovery password
$('input:password[name="changeRecoveryPassword"]').keyup(function(event) {
var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
if (newRecoveryPassword != '' && oldRecoveryPassword != '' ) {
var oldRecoveryPassword = $('#oldEncryptionRecoveryPassword').val();
var newRecoveryPassword = $('#newEncryptionRecoveryPassword').val();
var newRecoveryPasswordRepeated = $('#repeatedNewEncryptionRecoveryPassword').val();
if (newRecoveryPassword !== '' && oldRecoveryPassword !== '' && newRecoveryPassword === newRecoveryPasswordRepeated) {
$('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled");
} else {
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
@ -83,8 +87,8 @@ $(document).ready(function(){
$('button:button[name="submitChangeRecoveryKey"]').click(function() {
var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
var oldRecoveryPassword = $('#oldEncryptionRecoveryPassword').val();
var newRecoveryPassword = $('#newEncryptionRecoveryPassword').val();
OC.msg.startSaving('#encryption .msg');
$.post(
OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' )
@ -98,5 +102,5 @@ $(document).ready(function(){
}
);
});
});

View File

@ -199,12 +199,12 @@ class Helper {
public static function stripUserFilesPath($path) {
$trimmed = ltrim($path, '/');
$split = explode('/', $trimmed);
// it is not a file relative to data/user/files
if (count($split) < 3 || $split[1] !== 'files') {
return false;
}
$sliced = array_slice($split, 2);
$relPath = implode('/', $sliced);
@ -219,30 +219,33 @@ class Helper {
public static function getPathToRealFile($path) {
$trimmed = ltrim($path, '/');
$split = explode('/', $trimmed);
if (count($split) < 3 || $split[1] !== "files_versions") {
return false;
}
$sliced = array_slice($split, 2);
$realPath = implode('/', $sliced);
//remove the last .v
$realPath = substr($realPath, 0, strrpos($realPath, '.v'));
return $realPath;
}
}
/**
* @brief redirect to a error page
*/
public static function redirectToErrorPage() {
public static function redirectToErrorPage($session) {
$init = $session->getInitialized();
$location = \OC_Helper::linkToAbsolute('apps/files_encryption/files', 'error.php');
$post = 0;
if(count($_POST) > 0) {
$post = 1;
}
header('Location: ' . $location . '?p=' . $post);
exit();
}
header('Location: ' . $location . '?p=' . $post . '&i=' . $init);
exit();
}
/**
@ -259,7 +262,7 @@ class Helper {
return (bool) $result;
}
/**
* check some common errors if the server isn't configured properly for encryption
* @return bool true if configuration seems to be OK

View File

@ -30,6 +30,11 @@ class Session {
private $view;
const NOT_INITIALIZED = '0';
const INIT_EXECUTED = '1';
const INIT_SUCCESSFUL = '2';
/**
* @brief if session is started, check if ownCloud key pair is set up, if not create it
* @param \OC_FilesystemView $view
@ -112,6 +117,36 @@ class Session {
}
/**
* @brief Sets status of encryption app
* @param string $init INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INOITIALIZED
* @return bool
*
* @note this doesn not indicate of the init was successful, we just remeber the try!
*/
public function setInitialized($init) {
\OC::$session->set('encryptionInitialized', $init);
return true;
}
/**
* @brief Gets status if we already tried to initialize the encryption app
* @returns init status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INOITIALIZED
*
* @note this doesn not indicate of the init was successful, we just remeber the try!
*/
public function getInitialized() {
if (!is_null(\OC::$session->get('encryptionInitialized'))) {
return \OC::$session->get('encryptionInitialized');
} else {
return self::NOT_INITIALIZED;
}
}
/**
* @brief Gets user or public share private key from session
* @returns string $privateKey The user's plaintext private key

View File

@ -131,7 +131,7 @@ class Stream {
if($this->privateKey === false) {
// if private key is not valid redirect user to a error page
\OCA\Encryption\Helper::redirectToErrorPage();
\OCA\Encryption\Helper::redirectToErrorPage($this->session);
}
$this->size = $this->rootView->filesize($this->rawPath, $mode);

View File

@ -37,7 +37,6 @@ class Util {
const MIGRATION_IN_PROGRESS = -1; // migration is running
const MIGRATION_OPEN = 0; // user still needs to be migrated
private $view; // OC_FilesystemView object for filesystem operations
private $userId; // ID of the currently logged-in user
private $client; // Client side encryption mode flag
@ -1752,6 +1751,11 @@ class Util {
*/
public function initEncryption($params) {
$session = new \OCA\Encryption\Session($this->view);
// we tried to initialize the encryption app for this session
$session->setInitialized(\OCA\Encryption\Session::INIT_EXECUTED);
$encryptedKey = Keymanager::getPrivateKey($this->view, $params['uid']);
$privateKey = Crypt::decryptPrivateKey($encryptedKey, $params['password']);
@ -1762,9 +1766,8 @@ class Util {
return false;
}
$session = new \OCA\Encryption\Session($this->view);
$session->setPrivateKey($privateKey);
$session->setInitialized(\OCA\Encryption\Session::INIT_SUCCESSFUL);
return $session;
}

View File

@ -16,7 +16,9 @@ $view = new \OC_FilesystemView('/');
$util = new \OCA\Encryption\Util($view, $user);
$session = new \OCA\Encryption\Session($view);
$privateKeySet = $session->getPrivateKey() !== false;
$privateKeySet = $session->getPrivateKey() !== false;
// did we tried to initialize the keys for this session?
$initialized = $session->getInitialized();
$recoveryAdminEnabled = OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled');
$recoveryEnabledForUser = $util->recoveryEnabledForUser();
@ -31,6 +33,7 @@ if ($recoveryAdminEnabled || !$privateKeySet) {
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser);
$tmpl->assign('privateKeySet', $privateKeySet);
$tmpl->assign('initialized', $initialized);
$result = $tmpl->fetchPage();
}

View File

@ -2,9 +2,11 @@
<li class='error'>
<?php $location = \OC_Helper::linkToRoute( "settings_personal" ).'#changePKPasswd' ?>
<?php p($l->t('Your private key is not valid! Maybe the your password was changed from outside.')); ?>
<?php p($_['message']); ?>
<br/>
<?php p($l->t('You can unlock your private key in your ')); ?> <a href="<?php echo $location?>"><?php p($l->t('personal settings')); ?>.</a>
<?php if($_['init']): ?>
<?php>p($l->t('Go directly to your ')); ?> <a href="<?php echo $location?>"><?php p($l->t('personal settings')); ?>.</a>
<?php endif; ?>
<br/>
</li>
</ul>

View File

@ -10,14 +10,17 @@
<?php p($l->t("Enable recovery key (allow to recover users files in case of password loss):")); ?>
<br/>
<br/>
<input type="password" name="recoveryPassword" id="recoveryPassword"/>
<input type="password" name="encryptionRecoveryPassword" id="encryptionRecoveryPassword"/>
<label for="recoveryPassword"><?php p($l->t("Recovery key password")); ?></label>
<br/>
<input type="password" name="encryptionRecoveryPassword" id="repeatEncryptionRecoveryPassword"/>
<label for="repeatEncryptionRecoveryPassword"><?php p($l->t("Repeat Recovery key password")); ?></label>
<br/>
<input
type='radio'
name='adminEnableRecovery'
value='1'
<?php echo($_["recoveryEnabled"] == 1 ? 'checked="checked"' : 'disabled'); ?> />
<?php echo($_["recoveryEnabled"] === '1' ? 'checked="checked"' : 'disabled'); ?> />
<?php p($l->t("Enabled")); ?>
<br/>
@ -25,27 +28,32 @@
type='radio'
name='adminEnableRecovery'
value='0'
<?php echo($_["recoveryEnabled"] == 0 ? 'checked="checked"' : 'disabled'); ?> />
<?php echo($_["recoveryEnabled"] === '0' ? 'checked="checked"' : 'disabled'); ?> />
<?php p($l->t("Disabled")); ?>
</p>
<br/><br/>
<p>
<p name="changeRecoveryPasswordBlock" <?php if ($_['recoveryEnabled'] === '0') print_unescaped('class="hidden"');?>>
<strong><?php p($l->t("Change recovery key password:")); ?></strong>
<br/><br/>
<input
type="password"
name="changeRecoveryPassword"
id="oldRecoveryPassword"
<?php echo($_["recoveryEnabled"] == 0 ? 'disabled' : ''); ?> />
<label for="oldRecoveryPassword"><?php p($l->t("Old Recovery key password")); ?></label>
id="oldEncryptionRecoveryPassword"
<label for="oldEncryptionRecoveryPassword"><?php p($l->t("Old Recovery key password")); ?></label>
<br/>
<br/>
<input
type="password"
name="changeRecoveryPassword"
id="newRecoveryPassword"
<?php echo($_["recoveryEnabled"] == 0 ? 'disabled' : ''); ?> />
<label for="newRecoveryPassword"><?php p($l->t("New Recovery key password")); ?></label>
id="newEncryptionRecoveryPassword"
<label for="newEncryptionRecoveryPassword"><?php p($l->t("New Recovery key password")); ?></label>
<br/>
<input
type="password"
name="changeRecoveryPassword"
id="repeatedNewEncryptionRecoveryPassword"
<label for="repeatEncryptionRecoveryPassword"><?php p($l->t("Repeat New Recovery key password")); ?></label>
<br/>
<button
type="button"

View File

@ -4,7 +4,7 @@
<?php p( $l->t( 'Encryption' ) ); ?>
</legend>
<?php if ( ! $_["privateKeySet"] ): ?>
<?php if ( ! $_["privateKeySet"] && $_["initialized"] ): ?>
<p>
<a name="changePKPasswd" />
<label for="changePrivateKeyPasswd">
@ -39,22 +39,22 @@
<?php endif; ?>
<br />
<?php if ( $_["recoveryEnabled"] && $_["privateKeySet"] ): ?>
<p>
<label for="userEnableRecovery"><?php p( $l->t( "Enable password recovery:" ) ); ?></label>
<br />
<em><?php p( $l->t( "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" ) ); ?></em>
<br />
<input
<input
type='radio'
name='userEnableRecovery'
value='1'
<?php echo ( $_["recoveryEnabledForUser"] == 1 ? 'checked="checked"' : '' ); ?> />
<?php p( $l->t( "Enabled" ) ); ?>
<br />
<input
<input
type='radio'
name='userEnableRecovery'
value='0'

View File

@ -0,0 +1,43 @@
<?php
/**
* Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
\OC_Util::checkLoggedIn();
if(!\OC_App::isEnabled('files_versions')){
exit;
}
$file = array_key_exists('file', $_GET) ? (string) urldecode($_GET['file']) : '';
$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : 44;
$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : 44;
$version = array_key_exists('version', $_GET) ? $_GET['version'] : '';
$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
if($file === '' && $version === '') {
\OC_Response::setStatus(400); //400 Bad Request
\OC_Log::write('core-preview', 'No file parameter was passed', \OC_Log::DEBUG);
exit;
}
if($maxX === 0 || $maxY === 0) {
\OC_Response::setStatus(400); //400 Bad Request
\OC_Log::write('core-preview', 'x and/or y set to 0', \OC_Log::DEBUG);
exit;
}
try{
$preview = new \OC\Preview(\OC_User::getUser(), 'files_versions');
$preview->setFile($file.'.v'.$version);
$preview->setMaxX($maxX);
$preview->setMaxY($maxY);
$preview->setScalingUp($scalingUp);
$preview->showPreview();
}catch(\Exception $e) {
\OC_Response::setStatus(500);
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
}

View File

@ -7,3 +7,8 @@
// Register with the capabilities API
OC_API::register('get', '/cloud/capabilities', array('OCA\Files_Versions\Capabilities', 'getCapabilities'), 'files_versions', OC_API::USER_AUTH);
$this->create('core_ajax_versions_preview', '/preview.png')->action(
function() {
require_once __DIR__ . '/../ajax/preview.php';
});

View File

@ -1,11 +1,11 @@
#dropdown.drop-versions {
width:22em;
width:24em;
}
#found_versions li {
width: 100%;
cursor: default;
height: 36px;
height: 56px;
float: left;
border-bottom: 1px solid rgba(100,100,100,.1);
}
@ -21,6 +21,12 @@
filter: alpha(opacity=50);
opacity: .5;
}
#found_versions li > a,
#found_versions li > span {
padding: 17px 7px;
}
#found_versions li > *:hover,
#found_versions li > *:focus {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
@ -33,6 +39,11 @@
padding-right: 4px;
}
#found_versions img.preview {
cursor: default;
opacity: 1;
}
#found_versions .versionDate {
min-width: 100px;
vertical-align: text-bottom;

View File

@ -129,6 +129,8 @@ function createVersionsDropdown(filename, files) {
var path = OC.filePath('files_versions', '', 'download.php');
var preview = '<img class="preview" src="'+revision.preview+'"/>';
var download ='<a href="' + path + "?file=" + files + '&revision=' + revision.version + '">';
download+='<img';
download+=' src="' + OC.imagePath('core', 'actions/download') + '"';
@ -146,7 +148,7 @@ function createVersionsDropdown(filename, files) {
var version=$('<li/>');
version.attr('value', revision.version);
version.html(download + revert);
version.html(preview + download + revert);
version.appendTo('#found_versions');
}

View File

@ -266,6 +266,7 @@ class Storage {
$versions[$key]['version'] = $version;
$versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($version);
$versions[$key]['path'] = $filename;
$versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $filename, 'version' => $version));
$versions[$key]['size'] = $versions_fileview->filesize($filename.'.v'.$version);
// if file with modified date exists, flag it in array as currently enabled version

View File

@ -27,5 +27,6 @@ OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$prefix = $_POST['ldap_serverconfig_chooser'];
$connection = new \OCA\user_ldap\lib\Connection($prefix);
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
$connection = new \OCA\user_ldap\lib\Connection($ldapWrapper, $prefix);
OCP\JSON::success(array('configuration' => $connection->getConfiguration()));

View File

@ -27,7 +27,8 @@ OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$prefix = $_POST['ldap_serverconfig_chooser'];
$connection = new \OCA\user_ldap\lib\Connection($prefix);
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
$connection = new \OCA\user_ldap\lib\Connection($ldapWrapper, $prefix);
$connection->setConfiguration($_POST);
$connection->saveConfiguration();
OCP\JSON::success();

View File

@ -28,7 +28,8 @@ OCP\JSON::callCheck();
$l=OC_L10N::get('user_ldap');
$connection = new \OCA\user_ldap\lib\Connection('', null);
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
$connection = new \OCA\user_ldap\lib\Connection($ldapWrapper, '', null);
if($connection->setConfiguration($_POST)) {
//Configuration is okay
if($connection->bind()) {

View File

@ -24,15 +24,15 @@
OCP\App::registerAdmin('user_ldap', 'settings');
$configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true);
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
if(count($configPrefixes) === 1) {
$connector = new OCA\user_ldap\lib\Connection($configPrefixes[0]);
$userBackend = new OCA\user_ldap\USER_LDAP();
$userBackend->setConnector($connector);
$groupBackend = new OCA\user_ldap\GROUP_LDAP();
$groupBackend->setConnector($connector);
$connector = new OCA\user_ldap\lib\Connection($ldapWrapper, $configPrefixes[0]);
$ldapAccess = new OCA\user_ldap\lib\Access($connector, $ldapWrapper);
$userBackend = new OCA\user_ldap\USER_LDAP($ldapAccess);
$groupBackend = new OCA\user_ldap\GROUP_LDAP($ldapAccess);
} else {
$userBackend = new OCA\user_ldap\User_Proxy($configPrefixes);
$groupBackend = new OCA\user_ldap\Group_Proxy($configPrefixes);
$userBackend = new OCA\user_ldap\User_Proxy($configPrefixes, $ldapWrapper);
$groupBackend = new OCA\user_ldap\Group_Proxy($configPrefixes, $ldapWrapper);
}
if(count($configPrefixes) > 0) {

View File

@ -23,13 +23,16 @@
namespace OCA\user_ldap;
class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
use OCA\user_ldap\lib\Access;
use OCA\user_ldap\lib\BackendUtility;
class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
protected $enabled = false;
public function setConnector(lib\Connection &$connection) {
parent::setConnector($connection);
$filter = $this->connection->ldapGroupFilter;
$gassoc = $this->connection->ldapGroupMemberAssocAttr;
public function __construct(Access $access) {
parent::__construct($access);
$filter = $this->access->connection->ldapGroupFilter;
$gassoc = $this->access->connection->ldapGroupMemberAssocAttr;
if(!empty($filter) && !empty($gassoc)) {
$this->enabled = true;
}
@ -47,30 +50,31 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$this->enabled) {
return false;
}
if($this->connection->isCached('inGroup'.$uid.':'.$gid)) {
return $this->connection->getFromCache('inGroup'.$uid.':'.$gid);
if($this->access->connection->isCached('inGroup'.$uid.':'.$gid)) {
return $this->access->connection->getFromCache('inGroup'.$uid.':'.$gid);
}
$dn_user = $this->username2dn($uid);
$dn_group = $this->groupname2dn($gid);
$dn_user = $this->access->username2dn($uid);
$dn_group = $this->access->groupname2dn($gid);
// just in case
if(!$dn_group || !$dn_user) {
$this->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
return false;
}
//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
$members = $this->readAttribute($dn_group, $this->connection->ldapGroupMemberAssocAttr);
$members = $this->access->readAttribute($dn_group,
$this->access->connection->ldapGroupMemberAssocAttr);
if(!$members) {
$this->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
return false;
}
//extra work if we don't get back user DNs
//TODO: this can be done with one LDAP query
if(strtolower($this->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
$dns = array();
foreach($members as $mid) {
$filter = str_replace('%uid', $mid, $this->connection->ldapLoginFilter);
$ldap_users = $this->fetchListOfUsers($filter, 'dn');
$filter = str_replace('%uid', $mid, $this->access->connection->ldapLoginFilter);
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
continue;
}
@ -80,7 +84,7 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
}
$isInGroup = in_array($dn_user, $members);
$this->connection->writeToCache('inGroup'.$uid.':'.$gid, $isInGroup);
$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, $isInGroup);
return $isInGroup;
}
@ -98,35 +102,36 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
return array();
}
$cacheKey = 'getUserGroups'.$uid;
if($this->connection->isCached($cacheKey)) {
return $this->connection->getFromCache($cacheKey);
if($this->access->connection->isCached($cacheKey)) {
return $this->access->connection->getFromCache($cacheKey);
}
$userDN = $this->username2dn($uid);
$userDN = $this->access->username2dn($uid);
if(!$userDN) {
$this->connection->writeToCache($cacheKey, array());
$this->access->connection->writeToCache($cacheKey, array());
return array();
}
//uniqueMember takes DN, memberuid the uid, so we need to distinguish
if((strtolower($this->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
|| (strtolower($this->connection->ldapGroupMemberAssocAttr) === 'member')
if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
|| (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member')
) {
$uid = $userDN;
} else if(strtolower($this->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
$result = $this->readAttribute($userDN, 'uid');
} else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
$result = $this->access->readAttribute($userDN, 'uid');
$uid = $result[0];
} else {
// just in case
$uid = $userDN;
}
$filter = $this->combineFilterWithAnd(array(
$this->connection->ldapGroupFilter,
$this->connection->ldapGroupMemberAssocAttr.'='.$uid
$filter = $this->access->combineFilterWithAnd(array(
$this->access->connection->ldapGroupFilter,
$this->access->connection->ldapGroupMemberAssocAttr.'='.$uid
));
$groups = $this->fetchListOfGroups($filter, array($this->connection->ldapGroupDisplayName, 'dn'));
$groups = array_unique($this->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
$this->connection->writeToCache($cacheKey, $groups);
$groups = $this->access->fetchListOfGroups($filter,
array($this->access->connection->ldapGroupDisplayName, 'dn'));
$groups = array_unique($this->access->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
$this->access->connection->writeToCache($cacheKey, $groups);
return $groups;
}
@ -144,70 +149,71 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
}
$cachekey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
// check for cache of the exact query
$groupUsers = $this->connection->getFromCache($cachekey);
$groupUsers = $this->access->connection->getFromCache($cachekey);
if(!is_null($groupUsers)) {
return $groupUsers;
}
// check for cache of the query without limit and offset
$groupUsers = $this->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
$groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
if(!is_null($groupUsers)) {
$groupUsers = array_slice($groupUsers, $offset, $limit);
$this->connection->writeToCache($cachekey, $groupUsers);
$this->access->connection->writeToCache($cachekey, $groupUsers);
return $groupUsers;
}
if($limit === -1) {
$limit = null;
}
$groupDN = $this->groupname2dn($gid);
$groupDN = $this->access->groupname2dn($gid);
if(!$groupDN) {
// group couldn't be found, return empty resultset
$this->connection->writeToCache($cachekey, array());
$this->access->connection->writeToCache($cachekey, array());
return array();
}
$members = $this->readAttribute($groupDN, $this->connection->ldapGroupMemberAssocAttr);
$members = $this->access->readAttribute($groupDN,
$this->access->connection->ldapGroupMemberAssocAttr);
if(!$members) {
//in case users could not be retrieved, return empty resultset
$this->connection->writeToCache($cachekey, array());
$this->access->connection->writeToCache($cachekey, array());
return array();
}
$groupUsers = array();
$isMemberUid = (strtolower($this->connection->ldapGroupMemberAssocAttr) === 'memberuid');
$isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid');
foreach($members as $member) {
if($isMemberUid) {
//we got uids, need to get their DNs to 'tranlsate' them to usernames
$filter = $this->combineFilterWithAnd(array(
$filter = $this->access->combineFilterWithAnd(array(
\OCP\Util::mb_str_replace('%uid', $member,
$this->connection->ldapLoginFilter, 'UTF-8'),
$this->getFilterPartForUserSearch($search)
$this->access->connection->ldapLoginFilter, 'UTF-8'),
$this->access->getFilterPartForUserSearch($search)
));
$ldap_users = $this->fetchListOfUsers($filter, 'dn');
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
continue;
}
$groupUsers[] = $this->dn2username($ldap_users[0]);
$groupUsers[] = $this->access->dn2username($ldap_users[0]);
} else {
//we got DNs, check if we need to filter by search or we can give back all of them
if(!empty($search)) {
if(!$this->readAttribute($member,
$this->connection->ldapUserDisplayName,
$this->getFilterPartForUserSearch($search))) {
if(!$this->access->readAttribute($member,
$this->access->connection->ldapUserDisplayName,
$this->access->getFilterPartForUserSearch($search))) {
continue;
}
}
// dn2username will also check if the users belong to the allowed base
if($ocname = $this->dn2username($member)) {
if($ocname = $this->access->dn2username($member)) {
$groupUsers[] = $ocname;
}
}
}
natsort($groupUsers);
$this->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
$this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
$groupUsers = array_slice($groupUsers, $offset, $limit);
$this->connection->writeToCache($cachekey, $groupUsers);
$this->access->connection->writeToCache($cachekey, $groupUsers);
return $groupUsers;
}
@ -245,7 +251,7 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
//Check cache before driving unnecessary searches
\OCP\Util::writeLog('user_ldap', 'getGroups '.$cachekey, \OCP\Util::DEBUG);
$ldap_groups = $this->connection->getFromCache($cachekey);
$ldap_groups = $this->access->connection->getFromCache($cachekey);
if(!is_null($ldap_groups)) {
return $ldap_groups;
}
@ -255,16 +261,18 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if($limit <= 0) {
$limit = null;
}
$filter = $this->combineFilterWithAnd(array(
$this->connection->ldapGroupFilter,
$this->getFilterPartForGroupSearch($search)
$filter = $this->access->combineFilterWithAnd(array(
$this->access->connection->ldapGroupFilter,
$this->access->getFilterPartForGroupSearch($search)
));
\OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, \OCP\Util::DEBUG);
$ldap_groups = $this->fetchListOfGroups($filter, array($this->connection->ldapGroupDisplayName, 'dn'),
$limit, $offset);
$ldap_groups = $this->ownCloudGroupNames($ldap_groups);
$ldap_groups = $this->access->fetchListOfGroups($filter,
array($this->access->connection->ldapGroupDisplayName, 'dn'),
$limit,
$offset);
$ldap_groups = $this->access->ownCloudGroupNames($ldap_groups);
$this->connection->writeToCache($cachekey, $ldap_groups);
$this->access->connection->writeToCache($cachekey, $ldap_groups);
return $ldap_groups;
}
@ -278,25 +286,26 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
* @return bool
*/
public function groupExists($gid) {
if($this->connection->isCached('groupExists'.$gid)) {
return $this->connection->getFromCache('groupExists'.$gid);
if($this->access->connection->isCached('groupExists'.$gid)) {
return $this->access->connection->getFromCache('groupExists'.$gid);
}
//getting dn, if false the group does not exist. If dn, it may be mapped only, requires more checking.
$dn = $this->groupname2dn($gid);
//getting dn, if false the group does not exist. If dn, it may be mapped
//only, requires more checking.
$dn = $this->access->groupname2dn($gid);
if(!$dn) {
$this->connection->writeToCache('groupExists'.$gid, false);
$this->access->connection->writeToCache('groupExists'.$gid, false);
return false;
}
//if group really still exists, we will be able to read its objectclass
$objcs = $this->readAttribute($dn, 'objectclass');
$objcs = $this->access->readAttribute($dn, 'objectclass');
if(!$objcs || empty($objcs)) {
$this->connection->writeToCache('groupExists'.$gid, false);
$this->access->connection->writeToCache('groupExists'.$gid, false);
return false;
}
$this->connection->writeToCache('groupExists'.$gid, true);
$this->access->connection->writeToCache('groupExists'.$gid, true);
return true;
}

View File

@ -23,6 +23,8 @@
namespace OCA\user_ldap;
use OCA\user_ldap\lib\ILDAPWrapper;
class Group_Proxy extends lib\Proxy implements \OCP\GroupInterface {
private $backends = array();
private $refBackend = null;
@ -31,12 +33,11 @@ class Group_Proxy extends lib\Proxy implements \OCP\GroupInterface {
* @brief Constructor
* @param $serverConfigPrefixes array containing the config Prefixes
*/
public function __construct($serverConfigPrefixes) {
parent::__construct();
public function __construct($serverConfigPrefixes, ILDAPWrapper $ldap) {
parent::__construct($ldap);
foreach($serverConfigPrefixes as $configPrefix) {
$this->backends[$configPrefix] = new \OCA\user_ldap\GROUP_LDAP();
$connector = $this->getConnector($configPrefix);
$this->backends[$configPrefix]->setConnector($connector);
$this->backends[$configPrefix] =
new \OCA\user_ldap\GROUP_LDAP($this->getAccess($configPrefix));
if(is_null($this->refBackend)) {
$this->refBackend = &$this->backends[$configPrefix];
}

View File

@ -23,12 +23,13 @@
namespace OCA\user_ldap\lib;
abstract class Access {
protected $connection;
class Access extends LDAPUtility {
public $connection;
//never ever check this var directly, always use getPagedSearchResultState
protected $pagedSearchedSuccessful;
public function setConnector(Connection &$connection) {
public function __construct(Connection $connection, ILDAPWrapper $ldap) {
parent::__construct($ldap);
$this->connection = $connection;
}
@ -54,14 +55,14 @@ abstract class Access {
return false;
}
$cr = $this->connection->getConnectionResource();
if(!is_resource($cr)) {
if(!$this->ldap->isResource($cr)) {
//LDAP not available
\OCP\Util::writeLog('user_ldap', 'LDAP resource not available.', \OCP\Util::DEBUG);
return false;
}
$dn = $this->DNasBaseParameter($dn);
$rr = @ldap_read($cr, $dn, $filter, array($attr));
if(!is_resource($rr)) {
$rr = @$this->ldap->read($cr, $dn, $filter, array($attr));
if(!$this->ldap->isResource($rr)) {
if(!empty($attr)) {
//do not throw this message on userExists check, irritates
\OCP\Util::writeLog('user_ldap', 'readAttribute failed for DN '.$dn, \OCP\Util::DEBUG);
@ -73,13 +74,14 @@ abstract class Access {
\OCP\Util::writeLog('user_ldap', 'readAttribute: '.$dn.' found', \OCP\Util::DEBUG);
return array();
}
$er = ldap_first_entry($cr, $rr);
if(!is_resource($er)) {
$er = $this->ldap->firstEntry($cr, $rr);
if(!$this->ldap->isResource($er)) {
//did not match the filter, return false
return false;
}
//LDAP attributes are not case sensitive
$result = \OCP\Util::mb_array_change_key_case(ldap_get_attributes($cr, $er), MB_CASE_LOWER, 'UTF-8');
$result = \OCP\Util::mb_array_change_key_case(
$this->ldap->getAttributes($cr, $er), MB_CASE_LOWER, 'UTF-8');
$attr = mb_strtolower($attr, 'UTF-8');
if(isset($result[$attr]) && $result[$attr]['count'] > 0) {
@ -653,7 +655,7 @@ abstract class Access {
// See if we have a resource, in case not cancel with message
$link_resource = $this->connection->getConnectionResource();
if(!is_resource($link_resource)) {
if(!$this->ldap->isResource($link_resource)) {
// Seems like we didn't find any resource.
// Return an empty array just like before.
\OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG);
@ -664,11 +666,12 @@ abstract class Access {
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset);
$linkResources = array_pad(array(), count($base), $link_resource);
$sr = ldap_search($linkResources, $base, $filter, $attr);
$error = ldap_errno($link_resource);
$sr = $this->ldap->search($linkResources, $base, $filter, $attr);
$error = $this->ldap->errno($link_resource);
if(!is_array($sr) || $error !== 0) {
\OCP\Util::writeLog('user_ldap',
'Error when searching: '.ldap_error($link_resource).' code '.ldap_errno($link_resource),
'Error when searching: '.$this->ldap->error($link_resource).
' code '.$this->ldap->errno($link_resource),
\OCP\Util::ERROR);
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR);
return array();
@ -677,19 +680,19 @@ abstract class Access {
// Do the server-side sorting
foreach(array_reverse($attr) as $sortAttr){
foreach($sr as $searchResource) {
ldap_sort($link_resource, $searchResource, $sortAttr);
$this->ldap->sort($link_resource, $searchResource, $sortAttr);
}
}
$findings = array();
foreach($sr as $key => $res) {
$findings = array_merge($findings, ldap_get_entries($link_resource, $res ));
$findings = array_merge($findings, $this->ldap->getEntries($link_resource, $res ));
}
if($pagedSearchOK) {
\OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO);
foreach($sr as $key => $res) {
$cookie = null;
if(ldap_control_paged_result_response($link_resource, $res, $cookie)) {
if($this->ldap->controlPagedResultResponse($link_resource, $res, $cookie)) {
\OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO);
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
}
@ -1103,8 +1106,9 @@ abstract class Access {
if($offset > 0) {
\OCP\Util::writeLog('user_ldap', 'Cookie '.$cookie, \OCP\Util::INFO);
}
$pagedSearchOK = ldap_control_paged_result($this->connection->getConnectionResource(),
$limit, false, $cookie);
$pagedSearchOK = $this->ldap->controlPagedResult(
$this->connection->getConnectionResource(), $limit,
false, $cookie);
if(!$pagedSearchOK) {
return false;
}

View File

@ -0,0 +1,38 @@
<?php
/**
* ownCloud LDAP BackendUtility
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@owncloud.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 OCA\user_ldap\lib;
use OCA\user_ldap\lib\Access;
abstract class BackendUtility {
protected $access;
/**
* @brief constructor, make sure the subclasses call this one!
* @param $access an instance of Access for LDAP interaction
*/
public function __construct(Access $access) {
$this->access = $access;
}
}

View File

@ -23,7 +23,7 @@
namespace OCA\user_ldap\lib;
class Connection {
class Connection extends LDAPUtility {
private $ldapConnectionRes = null;
private $configPrefix;
private $configID;
@ -60,7 +60,7 @@ class Connection {
'ldapQuotaDefault' => null,
'ldapEmailAttribute' => null,
'ldapCacheTTL' => null,
'ldapUuidAttribute' => null,
'ldapUuidAttribute' => 'auto',
'ldapOverrideUuidAttribute' => null,
'ldapOverrideMainServer' => false,
'ldapConfigurationActive' => false,
@ -77,7 +77,8 @@ class Connection {
* @param $configPrefix a string with the prefix for the configkey column (appconfig table)
* @param $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
*/
public function __construct($configPrefix = '', $configID = 'user_ldap') {
public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
parent::__construct($ldap);
$this->configPrefix = $configPrefix;
$this->configID = $configID;
$memcache = new \OC\Memcache\Factory();
@ -86,13 +87,14 @@ class Connection {
} else {
$this->cache = \OC_Cache::getGlobalCache();
}
$this->config['hasPagedResultSupport'] = (function_exists('ldap_control_paged_result')
&& function_exists('ldap_control_paged_result_response'));
$this->config['hasPagedResultSupport'] =
$this->ldap->hasPagedResultSupport();
}
public function __destruct() {
if(!$this->dontDestruct && is_resource($this->ldapConnectionRes)) {
@ldap_unbind($this->ldapConnectionRes);
if(!$this->dontDestruct &&
$this->ldap->isResource($this->ldapConnectionRes)) {
@$this->ldap->unbind($this->ldapConnectionRes);
};
}
@ -148,7 +150,7 @@ class Connection {
public function getConnectionResource() {
if(!$this->ldapConnectionRes) {
$this->init();
} else if(!is_resource($this->ldapConnectionRes)) {
} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
$this->ldapConnectionRes = null;
$this->establishConnection();
}
@ -361,6 +363,14 @@ class Connection {
&& $params[$parameter] === 'homeFolderNamingRule'))
&& !empty($value)) {
$value = 'attr:'.$value;
} else if (strpos($parameter, 'ldapBase') !== false
|| (isset($params[$parameter])
&& strpos($params[$parameter], 'ldapBase') !== false)) {
$this->readBase($params[$parameter], $value);
if(is_array($setParameters)) {
$setParameters[] = $parameter;
}
continue;
}
if(isset($this->config[$parameter])) {
$this->config[$parameter] = $value;
@ -386,7 +396,8 @@ class Connection {
public function saveConfiguration() {
$trans = array_flip($this->getConfigTranslationArray());
foreach($this->config as $key => $value) {
\OCP\Util::writeLog('user_ldap', 'LDAP: storing key '.$key.' value '.$value, \OCP\Util::DEBUG);
\OCP\Util::writeLog('user_ldap', 'LDAP: storing key '.$key.
' value '.print_r($value, true), \OCP\Util::DEBUG);
switch ($key) {
case 'ldapAgentPassword':
$value = base64_encode($value);
@ -431,8 +442,9 @@ class Connection {
$config[$dbKey] = '';
}
continue;
} else if((strpos($classKey, 'ldapBase') !== false)
|| (strpos($classKey, 'ldapAttributes') !== false)) {
} else if((strpos($classKey, 'ldapBase') !== false
|| strpos($classKey, 'ldapAttributes') !== false)
&& is_array($this->config[$classKey])) {
$config[$dbKey] = implode("\n", $this->config[$classKey]);
continue;
}
@ -551,7 +563,7 @@ class Connection {
* @returns an associative array with the default values. Keys are correspond
* to config-value entries in the database table
*/
public function getDefaults() {
static public function getDefaults() {
return array(
'ldap_host' => '',
'ldap_port' => '389',
@ -603,7 +615,7 @@ class Connection {
return false;
}
if(!$this->ldapConnectionRes) {
if(!function_exists('ldap_connect')) {
if(!$this->ldap->areLDAPFunctionsAvailable()) {
$phpLDAPinstalled = false;
\OCP\Util::writeLog('user_ldap',
'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
@ -623,7 +635,8 @@ class Connection {
if(!$this->config['ldapOverrideMainServer'] && !$this->getFromCache('overrideMainServer')) {
$this->doConnect($this->config['ldapHost'], $this->config['ldapPort']);
$bindStatus = $this->bind();
$error = is_resource($this->ldapConnectionRes) ? ldap_errno($this->ldapConnectionRes) : -1;
$error = $this->ldap->isResource($this->ldapConnectionRes) ?
$this->ldap->errno($this->ldapConnectionRes) : -1;
} else {
$bindStatus = false;
$error = null;
@ -653,11 +666,11 @@ class Connection {
//ldap_connect ignores port paramater when URLs are passed
$host .= ':' . $port;
}
$this->ldapConnectionRes = ldap_connect($host, $port);
if(ldap_set_option($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
if(ldap_set_option($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
$this->ldapConnectionRes = $this->ldap->connect($host, $port);
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
if($this->config['ldapTLS']) {
ldap_start_tls($this->ldapConnectionRes);
$this->ldap->startTls($this->ldapConnectionRes);
}
}
}
@ -678,13 +691,15 @@ class Connection {
$getConnectionResourceAttempt = true;
$cr = $this->getConnectionResource();
$getConnectionResourceAttempt = false;
if(!is_resource($cr)) {
if(!$this->ldap->isResource($cr)) {
return false;
}
$ldapLogin = @ldap_bind($cr, $this->config['ldapAgentName'], $this->config['ldapAgentPassword']);
$ldapLogin = @$this->ldap->bind($cr,
$this->config['ldapAgentName'],
$this->config['ldapAgentPassword']);
if(!$ldapLogin) {
\OCP\Util::writeLog('user_ldap',
'Bind failed: ' . ldap_errno($cr) . ': ' . ldap_error($cr),
'Bind failed: ' . $this->ldap->errno($cr) . ': ' . $this->ldap->error($cr),
\OCP\Util::ERROR);
$this->ldapConnectionRes = null;
return false;

View File

@ -0,0 +1,180 @@
<?php
/**
* ownCloud LDAP Wrapper Interface
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@owncloud.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 OCA\user_ldap\lib;
interface ILDAPWrapper {
//LDAP functions in use
/**
* @brief Bind to LDAP directory
* @param $link LDAP link resource
* @param $dn an RDN to log in with
* @param $password the password
* @return true on success, false otherwise
*
* with $dn and $password as null a anonymous bind is attempted.
*/
public function bind($link, $dn, $password);
/**
* @brief connect to an LDAP server
* @param $host The host to connect to
* @param $port The port to connect to
* @return a link resource on success, otherwise false
*/
public function connect($host, $port);
/**
* @brief Send LDAP pagination control
* @param $link LDAP link resource
* @param $pagesize number of results per page
* @param $isCritical Indicates whether the pagination is critical of not.
* @param $cookie structure sent by LDAP server
* @return true on success, false otherwise
*/
public function controlPagedResult($link, $pagesize, $isCritical, $cookie);
/**
* @brief Retrieve the LDAP pagination cookie
* @param $link LDAP link resource
* @param $result LDAP result resource
* @param $cookie structure sent by LDAP server
* @return true on success, false otherwise
*
* Corresponds to ldap_control_paged_result_response
*/
public function controlPagedResultResponse($link, $result, &$cookie);
/**
* @brief Return the LDAP error number of the last LDAP command
* @param $link LDAP link resource
* @return error message as string
*/
public function errno($link);
/**
* @brief Return the LDAP error message of the last LDAP command
* @param $link LDAP link resource
* @return error code as integer
*/
public function error($link);
/**
* @brief Return first result id
* @param $link LDAP link resource
* @param $result LDAP result resource
* @return an LDAP search result resource
* */
public function firstEntry($link, $result);
/**
* @brief Get attributes from a search result entry
* @param $link LDAP link resource
* @param $result LDAP result resource
* @return array containing the results, false on error
* */
public function getAttributes($link, $result);
/**
* @brief Get all result entries
* @param $link LDAP link resource
* @param $result LDAP result resource
* @return array containing the results, false on error
*/
public function getEntries($link, $result);
/**
* @brief Read an entry
* @param $link LDAP link resource
* @param $baseDN The DN of the entry to read from
* @param $filter An LDAP filter
* @param $attr array of the attributes to read
* @return an LDAP search result resource
*/
public function read($link, $baseDN, $filter, $attr);
/**
* @brief Search LDAP tree
* @param $link LDAP link resource
* @param $baseDN The DN of the entry to read from
* @param $filter An LDAP filter
* @param $attr array of the attributes to read
* @return an LDAP search result resource, false on error
*/
public function search($link, $baseDN, $filter, $attr);
/**
* @brief Sets the value of the specified option to be $value
* @param $link LDAP link resource
* @param $option a defined LDAP Server option
* @param $value the new value for the option
* @return true on success, false otherwise
*/
public function setOption($link, $option, $value);
/**
* @brief establish Start TLS
* @param $link LDAP link resource
* @return true on success, false otherwise
*/
public function startTls($link);
/**
* @brief Sort the result of a LDAP search
* @param $link LDAP link resource
* @param $result LDAP result resource
* @param $sortfilter attribute to use a key in sort
*/
public function sort($link, $result, $sortfilter);
/**
* @brief Unbind from LDAP directory
* @param $link LDAP link resource
* @return true on success, false otherwise
*/
public function unbind($link);
//additional required methods in owncloud
/**
* @brief Checks whether the server supports LDAP
* @return true if it the case, false otherwise
* */
public function areLDAPFunctionsAvailable();
/**
* @brief Checks whether PHP supports LDAP Paged Results
* @return true if it the case, false otherwise
* */
public function hasPagedResultSupport();
/**
* @brief Checks whether the submitted parameter is a resource
* @param $resource the resource variable to check
* @return true if it is a resource, false otherwise
*/
public function isResource($resource);
}

View File

@ -139,13 +139,14 @@ class Jobs extends \OC\BackgroundJob\TimedJob {
return self::$groupBE;
}
$configPrefixes = Helper::getServerConfigurationPrefixes(true);
if(count($configPrefixes) == 1) {
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
if(count($configPrefixes) === 1) {
//avoid the proxy when there is only one LDAP server configured
$connector = new Connection($configPrefixes[0]);
self::$groupBE = new \OCA\user_ldap\GROUP_LDAP();
self::$groupBE->setConnector($connector);
$connector = new OCA\user_ldap\lib\Connection($ldapWrapper, $configPrefixes[0]);
$ldapAccess = new OCA\user_ldap\lib\Access($connector, $ldapWrapper);
self::$groupBE = new OCA\user_ldap\GROUP_LDAP($ldapAccess);
} else {
self::$groupBE = new \OCA\user_ldap\Group_Proxy($configPrefixes);
self::$groupBE = new \OCA\user_ldap\Group_Proxy($configPrefixes, $ldapWrapper);
}
return self::$groupBE;

167
apps/user_ldap/lib/ldap.php Normal file
View File

@ -0,0 +1,167 @@
<?php
/**
* ownCloud LDAP Wrapper
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@owncloud.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 OCA\user_ldap\lib;
class LDAP implements ILDAPWrapper {
protected $curFunc = '';
protected $curArgs = array();
public function bind($link, $dn, $password) {
return $this->invokeLDAPMethod('bind', $link, $dn, $password);
}
public function connect($host, $port) {
return $this->invokeLDAPMethod('connect', $host, $port);
}
public function controlPagedResultResponse($link, $result, &$cookie) {
$this->preFunctionCall('ldap_control_paged_result_response',
array($link, $result, $cookie));
$result = ldap_control_paged_result_response($link, $result, $cookie);
$this->postFunctionCall();
return $result;
}
public function controlPagedResult($link, $pagesize, $isCritical, $cookie) {
return $this->invokeLDAPMethod('control_paged_result', $link, $pagesize,
$isCritical, $cookie);
}
public function errno($link) {
return $this->invokeLDAPMethod('errno', $link);
}
public function error($link) {
return $this->invokeLDAPMethod('error', $link);
}
public function firstEntry($link, $result) {
return $this->invokeLDAPMethod('first_entry', $link, $result);
}
public function getAttributes($link, $result) {
return $this->invokeLDAPMethod('get_attributes', $link, $result);
}
public function getEntries($link, $result) {
return $this->invokeLDAPMethod('get_entries', $link, $result);
}
public function read($link, $baseDN, $filter, $attr) {
return $this->invokeLDAPMethod('read', $link, $baseDN, $filter, $attr);
}
public function search($link, $baseDN, $filter, $attr) {
return $this->invokeLDAPMethod('search', $link, $baseDN,
$filter, $attr);
}
public function setOption($link, $option, $value) {
$this->invokeLDAPMethod('set_option', $link, $option, $value);
}
public function sort($link, $result, $sortfilter) {
return $this->invokeLDAPMethod('sort', $link, $result, $sortfilter);
}
public function startTls($link) {
return $this->invokeLDAPMethod('start_tls', $link);
}
public function unbind($link) {
return $this->invokeLDAPMethod('unbind', $link);
}
/**
* @brief Checks whether the server supports LDAP
* @return true if it the case, false otherwise
* */
public function areLDAPFunctionsAvailable() {
return function_exists('ldap_connect');
}
/**
* @brief Checks whether PHP supports LDAP Paged Results
* @return true if it the case, false otherwise
* */
public function hasPagedResultSupport() {
$hasSupport = function_exists('ldap_control_paged_result')
&& function_exists('ldap_control_paged_result_response');
return $hasSupport;
}
/**
* @brief Checks whether the submitted parameter is a resource
* @param $resource the resource variable to check
* @return true if it is a resource, false otherwise
*/
public function isResource($resource) {
return is_resource($resource);
}
private function invokeLDAPMethod() {
$arguments = func_get_args();
$func = 'ldap_' . array_shift($arguments);
if(function_exists($func)) {
$this->preFunctionCall($func, $arguments);
$result = call_user_func_array($func, $arguments);
$this->postFunctionCall();
return $result;
}
}
private function preFunctionCall($functionName, $args) {
$this->curFunc = $functionName;
$this->curArgs = $args;
}
private function postFunctionCall() {
if($this->isResource($this->curArgs[0])) {
$errorCode = ldap_errno($this->curArgs[0]);
$errorMsg = ldap_error($this->curArgs[0]);
if($errorCode !== 0) {
if($this->curFunc === 'ldap_sort' && $errorCode === -4) {
//You can safely ignore that decoding error.
//… says https://bugs.php.net/bug.php?id=18023
} else if($this->curFunc === 'ldap_get_entries'
&& $errorCode === -4) {
} else if ($errorCode === 32) {
//for now
} else if ($errorCode === 10) {
//referrals, we switch them off, but then there is AD :)
} else {
\OCP\Util::writeLog('user_ldap',
'LDAP error '.$errorMsg.' (' .
$errorCode.') after calling '.
$this->curFunc,
\OCP\Util::DEBUG);
}
}
}
$this->curFunc = '';
$this->curArgs = array();
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* ownCloud LDAP LDAPUtility
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@owncloud.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 OCA\user_ldap\lib;
abstract class LDAPUtility {
protected $ldap;
/**
* @brief constructor, make sure the subclasses call this one!
* @param $ldapWrapper an instance of an ILDAPWrapper
*/
public function __construct(ILDAPWrapper $ldapWrapper) {
$this->ldap = $ldapWrapper;
}
}

View File

@ -23,26 +23,27 @@
namespace OCA\user_ldap\lib;
abstract class Proxy {
static private $connectors = array();
use OCA\user_ldap\lib\Access;
public function __construct() {
abstract class Proxy {
static private $accesses = array();
private $ldap = null;
public function __construct(ILDAPWrapper $ldap) {
$this->ldap = $ldap;
$this->cache = \OC_Cache::getGlobalCache();
}
private function addConnector($configPrefix) {
self::$connectors[$configPrefix] = new \OCA\user_ldap\lib\Connection($configPrefix);
private function addAccess($configPrefix) {
$connector = new Connection($this->ldap, $configPrefix);
self::$accesses[$configPrefix] = new Access($connector, $this->ldap);
}
protected function getConnector($configPrefix) {
if(!isset(self::$connectors[$configPrefix])) {
$this->addConnector($configPrefix);
protected function getAccess($configPrefix) {
if(!isset(self::$accesses[$configPrefix])) {
$this->addAccess($configPrefix);
}
return self::$connectors[$configPrefix];
}
protected function getConnectors() {
return self::$connectors;
return self::$accesses[$configPrefix];
}
protected function getUserCacheKey($uid) {

View File

@ -49,14 +49,9 @@ $tmpl->assign('serverConfigurationPrefixes', $prefixes);
$tmpl->assign('serverConfigurationHosts', $hosts);
// assign default values
if(!isset($ldap)) {
$ldap = new \OCA\user_ldap\lib\Connection();
}
$defaults = $ldap->getDefaults();
$defaults = \OCA\user_ldap\lib\Connection::getDefaults();
foreach($defaults as $key => $default) {
$tmpl->assign($key.'_default', $default);
}
// $tmpl->assign();
return $tmpl->fetchPage();

View File

@ -1,46 +0,0 @@
<?php
/**
* ownCloud
*
* @author Arthur Schiwon
* @copyright 2012 Arthur Schiwon blizzz@owncloud.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/>.
*
*/
class Test_Group_Ldap extends PHPUnit_Framework_TestCase {
function setUp() {
OC_Group::clearBackends();
}
function testSingleBackend() {
OC_Group::useBackend(new OCA\user_ldap\GROUP_LDAP());
$group_ldap = new OCA\user_ldap\GROUP_LDAP();
$this->assertIsA(OC_Group::getGroups(), gettype(array()));
$this->assertIsA($group_ldap->getGroups(), gettype(array()));
$this->assertFalse(OC_Group::inGroup('john', 'dosers'), gettype(false));
$this->assertFalse($group_ldap->inGroup('john', 'dosers'), gettype(false));
//TODO: check also for expected true result. This backend won't be able to do any modifications, maybe use a dummy for this.
$this->assertIsA(OC_Group::getUserGroups('john doe'), gettype(array()));
$this->assertIsA($group_ldap->getUserGroups('john doe'), gettype(array()));
$this->assertIsA(OC_Group::usersInGroup('campers'), gettype(array()));
$this->assertIsA($group_ldap->usersInGroup('campers'), gettype(array()));
}
}

View File

@ -0,0 +1,411 @@
<?php
/**
* ownCloud
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@owncloud.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 OCA\user_ldap\tests;
use \OCA\user_ldap\USER_LDAP as UserLDAP;
use \OCA\user_ldap\lib\Access;
use \OCA\user_ldap\lib\Connection;
use \OCA\user_ldap\lib\ILDAPWrapper;
class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
protected $backend;
public function setUp() {
\OC_User::clearBackends();
\OC_Group::clearBackends();
}
private function getAccessMock() {
static $conMethods;
static $accMethods;
if(is_null($conMethods) || is_null($accMethods)) {
$conMethods = get_class_methods('\OCA\user_ldap\lib\Connection');
$accMethods = get_class_methods('\OCA\user_ldap\lib\Access');
}
$lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper');
$connector = $this->getMock('\OCA\user_ldap\lib\Connection',
$conMethods,
array($lw, null, null));
$access = $this->getMock('\OCA\user_ldap\lib\Access',
$accMethods,
array($connector, $lw));
return $access;
}
private function prepareMockForUserExists(&$access) {
$access->expects($this->any())
->method('username2dn')
->will($this->returnCallback(function($uid) {
switch ($uid) {
case 'gunslinger':
return 'dnOfRoland';
break;
case 'formerUser':
return 'dnOfFormerUser';
break;
case 'newyorker':
return 'dnOfNewYorker';
break;
case 'ladyofshadows':
return 'dnOfLadyOfShadows';
break;
defautl:
return false;
}
}));
}
/**
* @brief Prepares the Access mock for checkPassword tests
* @param $access mock of \OCA\user_ldap\lib\Access
* @return void
*/
private function prepareAccessForCheckPassword(&$access) {
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapLoginFilter') {
return '%uid';
}
return null;
}));
$access->expects($this->any())
->method('fetchListOfUsers')
->will($this->returnCallback(function($filter) {
if($filter === 'roland') {
return array('dnOfRoland');
}
return array();
}));
$access->expects($this->any())
->method('dn2username')
->with($this->equalTo('dnOfRoland'))
->will($this->returnValue('gunslinger'));
$access->expects($this->any())
->method('areCredentialsValid')
->will($this->returnCallback(function($dn, $pwd) {
if($pwd === 'dt19') {
return true;
}
return false;
}));
}
public function testCheckPassword() {
$access = $this->getAccessMock();
$this->prepareAccessForCheckPassword($access);
$backend = new UserLDAP($access);
\OC_User::useBackend($backend);
$result = $backend->checkPassword('roland', 'dt19');
$this->assertEquals('gunslinger', $result);
$result = $backend->checkPassword('roland', 'wrong');
$this->assertFalse($result);
$result = $backend->checkPassword('mallory', 'evil');
$this->assertFalse($result);
}
public function testCheckPasswordPublicAPI() {
$access = $this->getAccessMock();
$this->prepareAccessForCheckPassword($access);
$backend = new UserLDAP($access);
\OC_User::useBackend($backend);
$result = \OCP\User::checkPassword('roland', 'dt19');
$this->assertEquals('gunslinger', $result);
$result = \OCP\User::checkPassword('roland', 'wrong');
$this->assertFalse($result);
$result = \OCP\User::checkPassword('mallory', 'evil');
$this->assertFalse($result);
}
/**
* @brief Prepares the Access mock for getUsers tests
* @param $access mock of \OCA\user_ldap\lib\Access
* @return void
*/
private function prepareAccessForGetUsers(&$access) {
$access->expects($this->any())
->method('getFilterPartForUserSearch')
->will($this->returnCallback(function($search) {
return $search;
}));
$access->expects($this->any())
->method('combineFilterWithAnd')
->will($this->returnCallback(function($param) {
return $param[1];
}));
$access->expects($this->any())
->method('fetchListOfUsers')
->will($this->returnCallback(function($search, $a, $l, $o) {
$users = array('gunslinger', 'newyorker', 'ladyofshadows');
if(empty($search)) {
$result = $users;
} else {
$result = array();
foreach($users as $user) {
if(stripos($user, $search) !== false) {
$result[] = $user;
}
}
}
if(!is_null($l) || !is_null($o)) {
$result = array_slice($result, $o, $l);
}
return $result;
}));
$access->expects($this->any())
->method('ownCloudUserNames')
->will($this->returnArgument(0));
}
public function testGetUsers() {
$access = $this->getAccessMock();
$this->prepareAccessForGetUsers($access);
$backend = new UserLDAP($access);
$result = $backend->getUsers();
$this->assertEquals(3, count($result));
$result = $backend->getUsers('', 1, 2);
$this->assertEquals(1, count($result));
$result = $backend->getUsers('', 2, 1);
$this->assertEquals(2, count($result));
$result = $backend->getUsers('yo');
$this->assertEquals(2, count($result));
$result = $backend->getUsers('nix');
$this->assertEquals(0, count($result));
}
public function testGetUsersViaAPI() {
$access = $this->getAccessMock();
$this->prepareAccessForGetUsers($access);
$backend = new UserLDAP($access);
\OC_User::useBackend($backend);
$result = \OCP\User::getUsers();
$this->assertEquals(3, count($result));
$result = \OCP\User::getUsers('', 1, 2);
$this->assertEquals(1, count($result));
$result = \OCP\User::getUsers('', 2, 1);
$this->assertEquals(2, count($result));
$result = \OCP\User::getUsers('yo');
$this->assertEquals(2, count($result));
$result = \OCP\User::getUsers('nix');
$this->assertEquals(0, count($result));
}
public function testUserExists() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland') {
return array();
}
return false;
}));
//test for existing user
$result = $backend->userExists('gunslinger');
$this->assertTrue($result);
//test for deleted user
$result = $backend->userExists('formerUser');
$this->assertFalse($result);
//test for never-existing user
$result = $backend->userExists('mallory');
$this->assertFalse($result);
}
public function testUserExistsPublicAPI() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
\OC_User::useBackend($backend);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland') {
return array();
}
return false;
}));
//test for existing user
$result = \OCP\User::userExists('gunslinger');
$this->assertTrue($result);
//test for deleted user
$result = \OCP\User::userExists('formerUser');
$this->assertFalse($result);
//test for never-existing user
$result = \OCP\User::userExists('mallory');
$this->assertFalse($result);
}
public function testDeleteUser() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
//we do not support deleting users at all
$result = $backend->deleteUser('gunslinger');
$this->assertFalse($result);
}
public function testGetHome() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute';
}
return null;
}));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
case 'dnOfRoland':
if($attr === 'testAttribute') {
return array('/tmp/rolandshome/');
}
return array();
break;
case 'dnOfLadyOfShadows':
if($attr === 'testAttribute') {
return array('susannah/');
}
return array();
break;
default:
return false;
}
}));
//absolut path
$result = $backend->getHome('gunslinger');
$this->assertEquals('/tmp/rolandshome/', $result);
//datadir-relativ path
$result = $backend->getHome('ladyofshadows');
$datadir = \OCP\Config::getSystemValue('datadirectory',
\OC::$SERVERROOT.'/data');
$this->assertEquals($datadir.'/susannah/', $result);
//no path at all triggers OC default behaviour
$result = $backend->getHome('newyorker');
$this->assertFalse($result);
}
private function prepareAccessForGetDisplayName(&$access) {
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapUserDisplayName') {
return 'displayname';
}
return null;
}));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
case 'dnOfRoland':
if($attr === 'displayname') {
return array('Roland Deschain');
}
return array();
break;
default:
return false;
}
}));
}
public function testGetDisplayName() {
$access = $this->getAccessMock();
$this->prepareAccessForGetDisplayName($access);
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
//with displayName
$result = $backend->getDisplayName('gunslinger');
$this->assertEquals('Roland Deschain', $result);
//empty displayname retrieved
$result = $backend->getDisplayName('newyorker');
$this->assertEquals(null, $result);
}
public function testGetDisplayNamePublicAPI() {
$access = $this->getAccessMock();
$this->prepareAccessForGetDisplayName($access);
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
\OC_User::useBackend($backend);
//with displayName
$result = \OCP\User::getDisplayName('gunslinger');
$this->assertEquals('Roland Deschain', $result);
//empty displayname retrieved
$result = \OCP\User::getDisplayName('newyorker');
$this->assertEquals('newyorker', $result);
}
//no test for getDisplayNames, because it just invokes getUsers and
//getDisplayName
}

View File

@ -25,37 +25,46 @@
namespace OCA\user_ldap;
class USER_LDAP extends lib\Access implements \OCP\UserInterface {
use OCA\user_ldap\lib\ILDAPWrapper;
use OCA\user_ldap\lib\BackendUtility;
class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
private function updateQuota($dn) {
$quota = null;
$quotaDefault = $this->connection->ldapQuotaDefault;
$quotaAttribute = $this->connection->ldapQuotaAttribute;
$quotaDefault = $this->access->connection->ldapQuotaDefault;
$quotaAttribute = $this->access->connection->ldapQuotaAttribute;
if(!empty($quotaDefault)) {
$quota = $quotaDefault;
}
if(!empty($quotaAttribute)) {
$aQuota = $this->readAttribute($dn, $quotaAttribute);
$aQuota = $this->access->readAttribute($dn, $quotaAttribute);
if($aQuota && (count($aQuota) > 0)) {
$quota = $aQuota[0];
}
}
if(!is_null($quota)) {
\OCP\Config::setUserValue($this->dn2username($dn), 'files', 'quota', \OCP\Util::computerFileSize($quota));
\OCP\Config::setUserValue( $this->access->dn2username($dn),
'files',
'quota',
\OCP\Util::computerFileSize($quota));
}
}
private function updateEmail($dn) {
$email = null;
$emailAttribute = $this->connection->ldapEmailAttribute;
$emailAttribute = $this->access->connection->ldapEmailAttribute;
if(!empty($emailAttribute)) {
$aEmail = $this->readAttribute($dn, $emailAttribute);
$aEmail = $this->access->readAttribute($dn, $emailAttribute);
if($aEmail && (count($aEmail) > 0)) {
$email = $aEmail[0];
}
if(!is_null($email)) {
\OCP\Config::setUserValue($this->dn2username($dn), 'settings', 'email', $email);
\OCP\Config::setUserValue( $this->access->dn2username($dn),
'settings',
'email',
$email);
}
}
}
@ -70,15 +79,16 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
*/
public function checkPassword($uid, $password) {
//find out dn of the user name
$filter = \OCP\Util::mb_str_replace('%uid', $uid, $this->connection->ldapLoginFilter, 'UTF-8');
$ldap_users = $this->fetchListOfUsers($filter, 'dn');
$filter = \OCP\Util::mb_str_replace(
'%uid', $uid, $this->access->connection->ldapLoginFilter, 'UTF-8');
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
return false;
}
$dn = $ldap_users[0];
//do we have a username for him/her?
$ocname = $this->dn2username($dn);
$ocname = $this->access->dn2username($dn);
if($ocname) {
//update some settings, if necessary
@ -86,7 +96,7 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
$this->updateEmail($dn);
//are the credentials OK?
if(!$this->areCredentialsValid($dn, $password)) {
if(!$this->access->areCredentialsValid($dn, $password)) {
return false;
}
@ -107,7 +117,7 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
$cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
//check if users are cached, if so return
$ldap_users = $this->connection->getFromCache($cachekey);
$ldap_users = $this->access->connection->getFromCache($cachekey);
if(!is_null($ldap_users)) {
return $ldap_users;
}
@ -117,21 +127,23 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
if($limit <= 0) {
$limit = null;
}
$filter = $this->combineFilterWithAnd(array(
$this->connection->ldapUserFilter,
$this->getFilterPartForUserSearch($search)
$filter = $this->access->combineFilterWithAnd(array(
$this->access->connection->ldapUserFilter,
$this->access->getFilterPartForUserSearch($search)
));
\OCP\Util::writeLog('user_ldap',
'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter,
\OCP\Util::DEBUG);
//do the search and translate results to owncloud names
$ldap_users = $this->fetchListOfUsers($filter, array($this->connection->ldapUserDisplayName, 'dn'),
$ldap_users = $this->access->fetchListOfUsers(
$filter,
array($this->access->connection->ldapUserDisplayName, 'dn'),
$limit, $offset);
$ldap_users = $this->ownCloudUserNames($ldap_users);
$ldap_users = $this->access->ownCloudUserNames($ldap_users);
\OCP\Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', \OCP\Util::DEBUG);
$this->connection->writeToCache($cachekey, $ldap_users);
$this->access->connection->writeToCache($cachekey, $ldap_users);
return $ldap_users;
}
@ -141,24 +153,25 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
* @return boolean
*/
public function userExists($uid) {
if($this->connection->isCached('userExists'.$uid)) {
return $this->connection->getFromCache('userExists'.$uid);
if($this->access->connection->isCached('userExists'.$uid)) {
return $this->access->connection->getFromCache('userExists'.$uid);
}
//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
$dn = $this->username2dn($uid);
$dn = $this->access->username2dn($uid);
if(!$dn) {
$this->connection->writeToCache('userExists'.$uid, false);
\OCP\Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
$this->access->connection->ldapHost, \OCP\Util::DEBUG);
$this->access->connection->writeToCache('userExists'.$uid, false);
return false;
}
//check if user really still exists by reading its entry
if(!is_array($this->readAttribute($dn, ''))) {
$this->connection->writeToCache('userExists'.$uid, false);
if(!is_array($this->access->readAttribute($dn, ''))) {
\OCP\Util::writeLog('user_ldap', 'LDAP says no user '.$dn, \OCP\Util::DEBUG);
$this->access->connection->writeToCache('userExists'.$uid, false);
return false;
}
$this->connection->writeToCache('userExists'.$uid, true);
$this->access->connection->writeToCache('userExists'.$uid, true);
$this->updateQuota($dn);
return true;
}
@ -186,12 +199,13 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
}
$cacheKey = 'getHome'.$uid;
if($this->connection->isCached($cacheKey)) {
return $this->connection->getFromCache($cacheKey);
if($this->access->connection->isCached($cacheKey)) {
return $this->access->connection->getFromCache($cacheKey);
}
if(strpos($this->connection->homeFolderNamingRule, 'attr:') === 0) {
$attr = substr($this->connection->homeFolderNamingRule, strlen('attr:'));
$homedir = $this->readAttribute($this->username2dn($uid), $attr);
if(strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0) {
$attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
$homedir = $this->access->readAttribute(
$this->access->username2dn($uid), $attr);
if($homedir && isset($homedir[0])) {
$path = $homedir[0];
//if attribute's value is an absolute path take this, otherwise append it to data dir
@ -206,13 +220,13 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
$homedir = \OCP\Config::getSystemValue('datadirectory',
\OC::$SERVERROOT.'/data' ) . '/' . $homedir[0];
}
$this->connection->writeToCache($cacheKey, $homedir);
$this->access->connection->writeToCache($cacheKey, $homedir);
return $homedir;
}
}
//false will apply default behaviour as defined and done by OC_User
$this->connection->writeToCache($cacheKey, false);
$this->access->connection->writeToCache($cacheKey, false);
return false;
}
@ -227,16 +241,16 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
}
$cacheKey = 'getDisplayName'.$uid;
if(!is_null($displayName = $this->connection->getFromCache($cacheKey))) {
if(!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
return $displayName;
}
$displayName = $this->readAttribute(
$this->username2dn($uid),
$this->connection->ldapUserDisplayName);
$displayName = $this->access->readAttribute(
$this->access->username2dn($uid),
$this->access->connection->ldapUserDisplayName);
if($displayName && (count($displayName) > 0)) {
$this->connection->writeToCache($cacheKey, $displayName[0]);
$this->access->connection->writeToCache($cacheKey, $displayName[0]);
return $displayName[0];
}
@ -251,7 +265,7 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
*/
public function getDisplayNames($search = '', $limit = null, $offset = null) {
$cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
if(!is_null($displayNames = $this->connection->getFromCache($cacheKey))) {
if(!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
return $displayNames;
}
@ -260,7 +274,7 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
foreach ($users as $user) {
$displayNames[$user] = $this->getDisplayName($user);
}
$this->connection->writeToCache($cacheKey, $displayNames);
$this->access->connection->writeToCache($cacheKey, $displayNames);
return $displayNames;
}

View File

@ -23,6 +23,8 @@
namespace OCA\user_ldap;
use OCA\user_ldap\lib\ILDAPWrapper;
class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
private $backends = array();
private $refBackend = null;
@ -31,12 +33,11 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
* @brief Constructor
* @param $serverConfigPrefixes array containing the config Prefixes
*/
public function __construct($serverConfigPrefixes) {
parent::__construct();
public function __construct($serverConfigPrefixes, ILDAPWrapper $ldap) {
parent::__construct($ldap);
foreach($serverConfigPrefixes as $configPrefix) {
$this->backends[$configPrefix] = new \OCA\user_ldap\USER_LDAP();
$connector = $this->getConnector($configPrefix);
$this->backends[$configPrefix]->setConnector($connector);
$this->backends[$configPrefix] =
new \OCA\user_ldap\USER_LDAP($this->getAccess($configPrefix));
if(is_null($this->refBackend)) {
$this->refBackend = &$this->backends[$configPrefix];
}

View File

@ -12,6 +12,16 @@ DATABASEUSER=oc_autotest$EXECUTOR_NUMBER
ADMINLOGIN=admin$EXECUTOR_NUMBER
BASEDIR=$PWD
if ! [ -w config -a -w config/config.php ]; then
echo "Please enable write permissions on config and config/config.php" >&2
exit 1
fi
# Back up existing (dev) config if one exists
if [ -f config/config.php ]; then
mv config/config.php config/config-autotest-backup.php
fi
# use tmpfs for datadir - should speedup unit test execution
if [ -d /dev/shm ]; then
DATADIR=/dev/shm/data-autotest$EXECUTOR_NUMBER
@ -158,6 +168,13 @@ else
execute_tests $1 $2 $3
fi
cd $BASEDIR
# Restore existing config
if [ -f config/config-autotest-backup.php ]; then
mv config/config-autotest-backup.php config/config.php
fi
#
# NOTES on mysql:
# - CREATE DATABASE oc_autotest;

View File

@ -23,6 +23,8 @@ OC_JSON::checkLoggedIn();
OCP\JSON::callCheck();
OC_App::loadApps();
$defaults = new \OCP\Defaults();
if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSource'])) {
switch ($_POST['action']) {
case 'share':
@ -33,7 +35,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
if ($shareType === OCP\Share::SHARE_TYPE_LINK && $shareWith == '') {
$shareWith = null;
}
$token = OCP\Share::shareItem(
$_POST['itemType'],
$_POST['itemSource'],
@ -41,7 +43,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
$shareWith,
$_POST['permissions']
);
if (is_string($token)) {
OC_JSON::success(array('data' => array('token' => $token)));
} else {
@ -81,6 +83,104 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
($return) ? OC_JSON::success() : OC_JSON::error();
}
break;
case 'informRecipients':
$l = OC_L10N::get('core');
$shareType = (int) $_POST['shareType'];
$itemType = $_POST['itemType'];
$itemSource = $_POST['itemSource'];
$recipient = $_POST['recipient'];
$ownerDisplayName = \OCP\User::getDisplayName();
$from = \OCP\Util::getDefaultEmailAddress('sharing-noreply');
$noMail = array();
$recipientList = array();
if($shareType === \OCP\Share::SHARE_TYPE_USER) {
$recipientList[] = $recipient;
} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
$recipientList = \OC_Group::usersInGroup($recipient);
}
// don't send a mail to the user who shared the file
$recipientList = array_diff($recipientList, array(\OCP\User::getUser()));
// send mail to all recipients with an email address
foreach ($recipientList as $recipient) {
//get correct target folder name
$email = OC_Preferences::getValue($recipient, 'settings', 'email', '');
if ($email !== '') {
$displayName = \OCP\User::getDisplayName($recipient);
$items = \OCP\Share::getItemSharedWithUser($itemType, $itemSource, $recipient);
$filename = trim($items[0]['file_target'], '/');
$subject = (string)$l->t('%s shared »%s« with you', array($ownerDisplayName, $filename));
$expiration = null;
if (isset($items[0]['expiration'])) {
$date = new DateTime($items[0]['expiration']);
$expiration = $date->format('Y-m-d');
}
if ($itemType === 'folder') {
$foldername = "/Shared/" . $filename;
} else {
// if it is a file we can just link to the Shared folder,
// that's the place where the user will find the file
$foldername = "/Shared";
}
$link = \OCP\Util::linkToAbsolute('files', 'index.php', array("dir" => $foldername));
$content = new OC_Template("core", "mail", "");
$content->assign('link', $link);
$content->assign('user_displayname', $ownerDisplayName);
$content->assign('filename', $filename);
$content->assign('expiration', $expiration);
$text = $content->fetchPage();
$content = new OC_Template("core", "altmail", "");
$content->assign('link', $link);
$content->assign('user_displayname', $ownerDisplayName);
$content->assign('filename', $filename);
$content->assign('expiration', $expiration);
$alttext = $content->fetchPage();
$default_from = OCP\Util::getDefaultEmailAddress('sharing-noreply');
$from = OCP\Config::getUserValue(\OCP\User::getUser(), 'settings', 'email', $default_from);
// send it out now
try {
OCP\Util::sendMail($email, $displayName, $subject, $text, $from, $ownerDisplayName, 1, $alttext);
} catch (Exception $exception) {
$noMail[] = \OCP\User::getDisplayName($recipient);
}
}
}
\OCP\Share::setSendMailStatus($itemType, $itemSource, $shareType, true);
if (empty($noMail)) {
OCP\JSON::success();
} else {
OCP\JSON::error(array(
'data' => array(
'message' => $l->t("Couldn't send mail to following users: %s ",
implode(', ', $noMail)
)
)
));
}
break;
case 'informRecipientsDisabled':
$itemSource = $_POST['itemSource'];
$shareType = $_POST['shareType'];
$itemType = $_POST['itemType'];
$recipient = $_POST['recipient'];
\OCP\Share::setSendMailStatus($itemType, $itemSource, $shareType, false);
OCP\JSON::success();
break;
case 'email':
// read post variables
$user = OCP\USER::getUser();
@ -213,10 +313,10 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
}
}
$count = 0;
// enable l10n support
$l = OC_L10N::get('core');
foreach ($groups as $group) {
if ($count < 15) {
if (!isset($_GET['itemShares'])

View File

@ -11,7 +11,7 @@
margin-right:7em;
position:absolute;
right:0;
width:19em;
width:25em;
z-index:500;
padding:1em;
}

View File

@ -42,6 +42,10 @@ body { background:#fefefe; font:normal .8em/1.6em "Helvetica Neue",Helvetica,Ari
display: inline-block;
}
#header .avatardiv img {
opacity: 1;
}
/* INPUTS */
input[type="text"], input[type="password"], input[type="search"], input[type="number"], input[type="email"], input[type="url"],
textarea, select,
@ -158,22 +162,37 @@ input[type="submit"].enabled {
/* CONTENT ------------------------------------------------------------------ */
#controls {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
position: fixed;
height: 36px;
height: 44px;
width: 100%;
padding: 0 75px 0 6px;
padding-right: 75px;
margin: 0;
background: #eee;
border-bottom: 1px solid #e7e7e7;
z-index: 50;
-moz-box-sizing: border-box; box-sizing: border-box;
}
#controls .button {
#controls .button,
#controls button,
#controls input[type='submit'],
#controls input[type='text'],
#controls input[type='password'],
#controls select {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
height: 36px;
padding: 7px 10px
}
#content { position:relative; height:100%; width:100%; }
#content .hascontrols { position: relative; top: 2.9em; }
#content .hascontrols {
position: relative;
top: 45px;
}
#content-wrapper {
position:absolute; height:100%; width:100%; padding-top:3.5em; padding-left:80px;
-moz-box-sizing:border-box; box-sizing:border-box;
@ -744,15 +763,38 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;}
.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); -o-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); }
.arrow.up { top:-8px; right:2em; }
.arrow.down { -webkit-transform:rotate(180deg); -moz-transform:rotate(180deg); -o-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); }
.help-includes {overflow: hidden; width: 100%; height: 100%; -moz-box-sizing: border-box; box-sizing: border-box; padding-top: 2.8em; }
.help-includes {
overflow: hidden;
width: 100%;
height: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding-top: 44px;
}
.help-iframe {width: 100%; height: 100%; margin: 0;padding: 0; border: 0; overflow: auto;}
/* ---- BREADCRUMB ---- */
div.crumb { float:left; display:block; background:url('../img/breadcrumb.svg') no-repeat right 0; padding:.75em 1.5em 0 1em; height:2.9em; -moz-box-sizing:border-box; box-sizing:border-box; }
div.crumb:first-child { padding:10px 20px 10px 5px; }
div.crumb.last { font-weight:bold; background:none; padding-right:10px; }
div.crumb a{ padding: 0.9em 0 0.7em 0; }
div.crumb {
float: left;
display: block;
background: url('../img/breadcrumb.svg') no-repeat right center;
height: 44px;
}
div.crumb a {
position: relative;
top: 12px;
padding: 14px 24px 14px 17px;
color: #555;
}
div.crumb:first-child a {
position: relative;
top: 13px;
}
div.crumb.last {
font-weight: bold;
margin-right: 10px;
}
/* some feedback for hover/tap on breadcrumbs */
div.crumb:hover,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="36" width="11" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="translate(0 -1016.4)">
<path d="m0 0 11 18-11 18z" transform="translate(0 1016.4)" fill="#ddd"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 594 B

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="36" width="11" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<g transform="translate(0 -1016.4)">
<path d="m0.5 0 10 18-10 18 10-18z" transform="translate(0 1016.4)" stroke="#ddd" stroke-linecap="round" stroke-miterlimit="31.2" stroke-width="0.9" fill="#ddd"/>
</g>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="44" width="14" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<path d="M0.54879,0.047777,12.744,22,0.54879,43.951,12.744,22z" stroke="#d7d7d7" stroke-linecap="round" stroke-miterlimit="31.20000076000000178" stroke-width="1.09758711000000009" fill="#F00"/>
</svg>

Before

Width:  |  Height:  |  Size: 491 B

After

Width:  |  Height:  |  Size: 638 B

View File

@ -1,6 +1,6 @@
$(document).ready(function(){
if (OC.currentUser) {
$('#header .avatardiv').avatar(OC.currentUser, 32);
$('#header .avatardiv').avatar(OC.currentUser, 32, undefined, true);
// Personal settings
$('#avatar .avatardiv').avatar(OC.currentUser, 128);
}

View File

@ -15,7 +15,7 @@
* You may use this on any <div></div>
* Here I'm using <div class="avatardiv"></div> as an example.
*
* There are 4 ways to call this:
* There are 5 ways to call this:
*
* 1. $('.avatardiv').avatar('jdoe', 128);
* This will make the div to jdoe's fitting avatar, with a size of 128px.
@ -34,10 +34,15 @@
* 4. $('.avatardiv').avatar('jdoe', 128, true);
* This will behave like the first example, except it will also append random
* hashes to the custom avatar images, to force image reloading in IE8.
*
* 5. $('.avatardiv').avatar('jdoe', 128, undefined, true);
* This will behave like the first example, but it will hide the avatardiv, if
* it will display the default placeholder. undefined is the ie8fix from
* example 4 and can be either true, or false/undefined, to be ignored.
*/
(function ($) {
$.fn.avatar = function(user, size, ie8fix) {
$.fn.avatar = function(user, size, ie8fix, hidedefault) {
if (typeof(size) === 'undefined') {
if (this.height() > 0) {
size = this.height();
@ -69,12 +74,17 @@
var url = OC.Router.generate('core_avatar_get', {user: user, size: size})+'?requesttoken='+oc_requesttoken;
$.get(url, function(result) {
if (typeof(result) === 'object') {
if (result.data && result.data.displayname) {
$div.placeholder(user, result.data.displayname);
if (!hidedefault) {
if (result.data && result.data.displayname) {
$div.placeholder(user, result.data.displayname);
} else {
$div.placeholder(user);
}
} else {
$div.placeholder(user);
$div.hide();
}
} else {
$div.show();
if (ie8fix === true) {
$div.html('<img src="'+url+'#'+Math.floor(Math.random()*1000)+'">');
} else {

View File

@ -114,6 +114,7 @@ OC.Share={
data = false;
}
}});
return data;
},
share:function(itemType, itemSource, shareType, shareWith, permissions, callback) {
@ -217,9 +218,9 @@ OC.Share={
OC.Share.showLink(share.token, share.share_with, itemSource);
} else {
if (share.collection) {
OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, share.collection);
OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, share.mail_send, share.collection);
} else {
OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, false);
OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, share.mail_send, false);
}
}
if (share.expiration != null) {
@ -301,7 +302,7 @@ OC.Share={
}
});
},
addShareWith:function(shareType, shareWith, shareWithDisplayName, permissions, possiblePermissions, collection) {
addShareWith:function(shareType, shareWith, shareWithDisplayName, permissions, possiblePermissions, mailSend, collection) {
if (!OC.Share.itemShares[shareType]) {
OC.Share.itemShares[shareType] = [];
}
@ -343,6 +344,14 @@ OC.Share={
}else{
html += escapeHTML(shareWithDisplayName);
}
var mailNotificationEnabled = $('input:hidden[name=mailNotificationEnabled]').val();
if (mailNotificationEnabled === 'yes') {
var checked = '';
if (mailSend === '1') {
checked = 'checked';
}
html += '<input type="checkbox" name="mailNotification" class="mailNotification" ' + checked + ' />'+t('core', 'notify user by email')+'</label>';
}
if (possiblePermissions & OC.PERMISSION_CREATE || possiblePermissions & OC.PERMISSION_UPDATE || possiblePermissions & OC.PERMISSION_DELETE) {
if (editChecked == '') {
html += '<label style="display:none;">';
@ -699,5 +708,27 @@ $(document).ready(function() {
}
});
$(document).on('click', '#dropdown input[name=mailNotification]', function() {
var li = $(this).parent();
var itemType = $('#dropdown').data('item-type');
var itemSource = $('#dropdown').data('item-source');
var action = '';
if (this.checked) {
action = 'informRecipients';
} else {
action = 'informRecipientsDisabled';
}
var shareType = $(li).data('share-type');
var shareWith = $(li).data('share-with');
$.post(OC.filePath('core', 'ajax', 'share.php'), {action: action, recipient: shareWith, shareType: shareType, itemSource: itemSource, itemType: itemType}, function(result) {
if (result.status !== 'success') {
OC.dialogs.alert(t('core', result.data.message), t('core', 'Warning'));
}
});
});
});

View File

@ -0,0 +1,5 @@
Welcome to your ownCloud account!
This is just an example file for developers and git users.
The packaged and released versions will come with better examples.

View File

@ -1,5 +1,9 @@
<?php
print_unescaped($l->t("Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\nCheers!", array($_['user_displayname'], $_['filename'], $_['link'])));
print_unescaped($l->t("Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n", array($_['user_displayname'], $_['filename'], $_['link'])));
if ( isset($_['expiration']) ) {
print_unescaped($l->t("The share will expire on %s.\n\n", array($_['expiration'])));
}
p($l->t("Cheers!"));
?>
--

View File

@ -12,7 +12,11 @@
<td bgcolor="#f8f8f8" width="20px">&nbsp;</td>
<td bgcolor="#f8f8f8" style="font-weight:normal; font-size:0.8em; line-height:1.2em; font-family:verdana,'arial',sans;">
<?php
print_unescaped($l->t('Hey there,<br><br>just letting you know that %s shared »%s« with you.<br><a href="%s">View it!</a><br><br>Cheers!', array($_['user_displayname'], $_['filename'], $_['link'])));
print_unescaped($l->t('Hey there,<br><br>just letting you know that %s shared »%s« with you.<br><a href="%s">View it!</a><br><br>', array($_['user_displayname'], $_['filename'], $_['link'])));
if ( isset($_['expiration']) ) {
print_unescaped($l->t("The share will expire on %s.<br><br>", array($_['expiration'])));
}
p($l->t('Cheers!'));
?>
</td>
</tr>
@ -22,7 +26,8 @@ print_unescaped($l->t('Hey there,<br><br>just letting you know that %s shared »
<td bgcolor="#f8f8f8" style="font-weight:normal; font-size:0.8em; line-height:1.2em; font-family:verdana,'arial',sans;">--<br>
<?php p($theme->getName()); ?> -
<?php p($theme->getSlogan()); ?>
<br><a href="<?php print_unescaped($theme->getBaseUrl()); ?>"><?php print_unescaped($theme->getBaseUrl());?></a></td>
<br><a href="<?php print_unescaped($theme->getBaseUrl()); ?>"><?php print_unescaped($theme->getBaseUrl());?></a>
</td>
</tr>
<tr>
<td bgcolor="#f8f8f8" colspan="2">&nbsp;</td>

View File

@ -844,6 +844,14 @@
<length>32</length>
</field>
<field>
<name>mail_send</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<length>1</length>
</field>
<index>
<name>token_index</name>
<field>

View File

@ -207,7 +207,14 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
while( $row = $result->fetchRow()) {
$this->property_cache[$row['propertyname']] = $row['propertyvalue'];
}
$this->property_cache[self::GETETAG_PROPERTYNAME] = $this->getETagPropertyForPath($this->path);
// Don't call the static getETagPropertyForPath, its result is not cached
$this->getFileinfoCache();
if ($this->fileinfo_cache['etag']) {
$this->property_cache[self::GETETAG_PROPERTYNAME] = '"'.$this->fileinfo_cache['etag'].'"';
} else {
$this->property_cache[self::GETETAG_PROPERTYNAME] = null;
}
}
// if the array was empty, we need to return everything

View File

@ -13,6 +13,7 @@ if (file_exists(OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.
class OC_Defaults {
private $theme;
private $l;
private $defaultEntity;
private $defaultName;
@ -24,7 +25,7 @@ class OC_Defaults {
private $defaultLogoClaim;
function __construct() {
$l = OC_L10N::get('core');
$this->l = OC_L10N::get('core');
$this->defaultEntity = "ownCloud"; /* e.g. company name, used for footers and copyright notices */
$this->defaultName = "ownCloud"; /* short name, used when referring to the software */
@ -32,7 +33,7 @@ class OC_Defaults {
$this->defaultBaseUrl = "http://owncloud.org";
$this->defaultSyncClientUrl = " http://owncloud.org/sync-clients/";
$this->defaultDocBaseUrl = "http://doc.owncloud.org";
$this->defaultSlogan = $l->t("web services under your control");
$this->defaultSlogan = $this->l->t("web services under your control");
$this->defaultLogoClaim = "";
if (class_exists("OC_Theme")) {

View File

@ -85,22 +85,51 @@ function human_file_size( $bytes ) {
return OC_Helper::humanFileSize( $bytes );
}
function relative_modified_date($timestamp) {
/**
* @brief Strips the timestamp of its time value
* @param int $timestamp UNIX timestamp to strip
* @return $timestamp without time value
*/
function strip_time($timestamp){
$date = new \DateTime("@{$timestamp}");
$date->setTime(0, 0, 0);
return intval($date->format('U'));
}
/**
* @brief Formats timestamp relatively to the current time using
* a human-friendly format like "x minutes ago" or "yesterday"
* @param int $timestamp timestamp to format
* @param int $fromTime timestamp to compare from, defaults to current time
* @param bool $dateOnly whether to strip time information
* @return formatted timestamp
*/
function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false) {
$l=OC_L10N::get('lib');
$timediff = time() - $timestamp;
if (!isset($fromTime) || $fromTime === null){
$fromTime = time();
}
if ($dateOnly){
$fromTime = strip_time($fromTime);
$timestamp = strip_time($timestamp);
}
$timediff = $fromTime - $timestamp;
$diffminutes = round($timediff/60);
$diffhours = round($diffminutes/60);
$diffdays = round($diffhours/24);
$diffmonths = round($diffdays/31);
if($timediff < 60) { return $l->t('seconds ago'); }
else if($timediff < 3600) { return $l->n('%n minute ago', '%n minutes ago', $diffminutes); }
else if($timediff < 86400) { return $l->n('%n hour ago', '%n hours ago', $diffhours); }
else if((date('G')-$diffhours) > 0) { return $l->t('today'); }
else if((date('G')-$diffhours) > -24) { return $l->t('yesterday'); }
if(!$dateOnly && $timediff < 60) { return $l->t('seconds ago'); }
else if(!$dateOnly && $timediff < 3600) { return $l->n('%n minute ago', '%n minutes ago', $diffminutes); }
else if(!$dateOnly && $timediff < 86400) { return $l->n('%n hour ago', '%n hours ago', $diffhours); }
else if((date('G', $fromTime)-$diffhours) >= 0) { return $l->t('today'); }
else if((date('G', $fromTime)-$diffhours) >= -24) { return $l->t('yesterday'); }
// 86400 * 31 days = 2678400
else if($timediff < 2678400) { return $l->n('%n day go', '%n days ago', $diffdays); }
// 86400 * 60 days = 518400
else if($timediff < 5184000) { return $l->t('last month'); }
else if((date('n')-$diffmonths) > 0) { return $l->n('%n month ago', '%n months ago', $diffmonths); }
else if((date('n', $fromTime)-$diffmonths) > 0) { return $l->n('%n month ago', '%n months ago', $diffmonths); }
// 86400 * 365.25 days * 2 = 63113852
else if($timediff < 63113852) { return $l->t('last year'); }
else { return $l->t('years ago'); }
}

View File

@ -68,6 +68,7 @@ class OC_Util {
$userDirectory = $userRoot . '/files';
if( !is_dir( $userDirectory )) {
mkdir( $userDirectory, 0755, true );
OC_Util::copySkeleton($userDirectory);
}
//jail the user into his "home" directory
\OC\Files\Filesystem::init($user, $userDir);
@ -92,6 +93,35 @@ class OC_Util {
}
}
/**
* @brief copies the user skeleton files into the fresh user home files
* @param string $userDirectory
*/
public static function copySkeleton($userDirectory) {
OC_Util::copyr(\OC::$SERVERROOT.'/core/skeleton' , $userDirectory);
}
/**
* @brief copies a directory recursively
* @param string $source
* @param string $target
* @return void
*/
public static function copyr($source,$target) {
$dir = opendir($source);
@mkdir($target);
while(false !== ( $file = readdir($dir)) ) {
if ( !\OC\Files\Filesystem::isIgnoredDir($file) ) {
if ( is_dir($source . '/' . $file) ) {
OC_Util::copyr($source . '/' . $file , $target . '/' . $file);
} else {
copy($source . '/' . $file,$target . '/' . $file);
}
}
}
closedir($dir);
}
/**
* @return void
*/
@ -138,7 +168,7 @@ class OC_Util {
OC_Util::loadVersion();
return \OC::$server->getSession()->get('OC_Channel');
}
/**
* @description get the build number of the current installed of ownCloud.
* @return string

View File

@ -246,9 +246,9 @@ class Share {
/**
* @brief Get the item of item type shared with the current user
* @param string Item type
* @param string Item target
* @param int Format (optional) Format type must be defined by the backend
* @param string $itemType
* @param string $ItemTarget
* @param int $format (optional) Format type must be defined by the backend
* @return Return depends on format
*/
public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE,
@ -257,6 +257,55 @@ class Share {
$parameters, 1, $includeCollections);
}
/**
* @brief Get the item of item type shared with a given user by source
* @param string $ItemType
* @param string $ItemSource
* @param string $user User user to whom the item was shared
* @return array Return list of items with file_target, permissions and expiration
*/
public static function getItemSharedWithUser($itemType, $itemSource, $user) {
$shares = array();
// first check if there is a db entry for the specific user
$query = \OC_DB::prepare(
'SELECT `file_target`, `permissions`, `expiration`
FROM
`*PREFIX*share`
WHERE
`item_source` = ? AND `item_type` = ? AND `share_with` = ?'
);
$result = \OC_DB::executeAudited($query, array($itemSource, $itemType, $user));
while ($row = $result->fetchRow()) {
$shares[] = $row;
}
//if didn't found a result than let's look for a group share.
if(empty($shares)) {
$groups = \OC_Group::getUserGroups($user);
$query = \OC_DB::prepare(
'SELECT `file_target`, `permissions`, `expiration`
FROM
`*PREFIX*share`
WHERE
`item_source` = ? AND `item_type` = ? AND `share_with` in (?)'
);
$result = \OC_DB::executeAudited($query, array($itemSource, $itemType, implode(',', $groups)));
while ($row = $result->fetchRow()) {
$shares[] = $row;
}
}
return $shares;
}
/**
* @brief Get the item of item type shared with the current user by source
* @param string Item type
@ -653,6 +702,29 @@ class Share {
}
return false;
}
/**
* @brief sent status if users got informed by mail about share
* @param string $itemType
* @param string $itemSource
* @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
* @param bool $status
*/
public static function setSendMailStatus($itemType, $itemSource, $shareType, $status) {
$status = $status ? 1 : 0;
$query = \OC_DB::prepare(
'UPDATE `*PREFIX*share`
SET `mail_send` = ?
WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ?');
$result = $query->execute(array($status, $itemType, $itemSource, $shareType));
if($result === false) {
\OC_Log::write('OCP\Share', 'Couldn\'t set send mail status', \OC_Log::ERROR);
}
}
/**
* @brief Set the permissions of an item for a specific user or group
@ -983,19 +1055,19 @@ class Share {
if ($format == self::FORMAT_STATUSES) {
if ($itemType == 'file' || $itemType == 'folder') {
$select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`,'
.' `share_type`, `file_source`, `path`, `expiration`, `storage`';
.' `share_type`, `file_source`, `path`, `expiration`, `storage`, `mail_send`';
} else {
$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `expiration`';
$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `expiration`, `mail_send`';
}
} else {
if (isset($uidOwner)) {
if ($itemType == 'file' || $itemType == 'folder') {
$select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`,'
.' `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`,'
.' `expiration`, `token`, `storage`';
.' `expiration`, `token`, `storage`, `mail_send`';
} else {
$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`,'
.' `stime`, `file_source`, `expiration`, `token`';
.' `stime`, `file_source`, `expiration`, `token`, `mail_send`';
}
} else {
if ($fileDependent) {
@ -1006,11 +1078,11 @@ class Share {
$select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, '
.'`share_type`, `share_with`, `file_source`, `path`, `file_target`, '
.'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
.'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`';
.'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
} else {
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,
`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,
`file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`';
`file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`';
}
} else {
$select = '*';

View File

@ -90,8 +90,8 @@ function human_file_size( $bytes ) {
* @param $timestamp unix timestamp
* @returns human readable interpretation of the timestamp
*/
function relative_modified_date($timestamp) {
return(\relative_modified_date($timestamp));
function relative_modified_date($timestamp, $dateOnly = false) {
return(\relative_modified_date($timestamp, null, $dateOnly));
}

View File

@ -33,16 +33,17 @@ $tmpl->assign('shareAPIEnabled', OC_Appconfig::getValue('core', 'shareapi_enable
// Check if connected using HTTPS
if (OC_Request::serverProtocol() === 'https') {
$connectedHTTPS = true;
$connectedHTTPS = true;
} else {
$connectedHTTPS = false;
}
}
$tmpl->assign('isConnectedViaHTTPS', $connectedHTTPS);
$tmpl->assign('enforceHTTPSEnabled', OC_Config::getValue( "forcessl", false));
$tmpl->assign('allowLinks', OC_Appconfig::getValue('core', 'shareapi_allow_links', '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('allowMailNotification', OC_Appconfig::getValue('core', 'shareapi_allow_mail_notification', 'yes'));
$tmpl->assign('sharePolicy', OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'));
$tmpl->assign('forms', array());
foreach($forms as $form) {

View File

@ -55,18 +55,37 @@ tr:hover>td.remove>a { float:right; }
li.selected { background-color:#ddd; }
table:not(.nostyle) { width:100%; }
#rightcontent { padding-left: 1em; }
div.quota { float:right; display:block; position:absolute; right:25em; top:-1px; }
div.quota {
float: right;
display: block;
position: absolute;
right: 216px;
top: 0;
}
div.quota-select-wrapper { position: relative; }
div.recoveryPassword { left:50em; display:block; position:absolute; top:-1px; }
input#recoveryPassword {width:15em;}
select.quota { position:absolute; left:0; top:0; width:10em; }
select.quota-user { position:relative; left:0; top:0; width:10em; }
div.quota>span { position:absolute; right:0; white-space:nowrap; top:.7em; color:#888; text-shadow:0 1px 0 #fff; }
div.quota>span {
position: absolute;
right: 0;
white-space: nowrap;
top: 12px;
color: #888;
text-shadow: 0 1px 0 #fff;
}
select.quota.active { background: #fff; }
/* positioning fixes */
#newuser { position:relative; top:-3px; }
#newuser .multiselect { top:1px; }
#newuser .multiselect {
min-width: 150px !important;
}
#newuser .multiselect,
#newusergroups + input[type='submit'] {
position: relative;
top: 1px;
}
#headerGroups, #headerSubAdmins, #headerQuota { padding-left:18px; }
.ie8 table.hascontrols{border-collapse:collapse;width: 100%;}

View File

@ -45,12 +45,16 @@ function changeDisplayName(){
}
}
function updateAvatar () {
function updateAvatar (hidedefault) {
$headerdiv = $('#header .avatardiv');
$displaydiv = $('#displayavatar .avatardiv');
$headerdiv.css({'background-color': ''});
$headerdiv.avatar(OC.currentUser, 32, true);
if(hidedefault) {
$headerdiv.hide();
} else {
$headerdiv.css({'background-color': ''});
$headerdiv.avatar(OC.currentUser, 32, true);
}
$displaydiv.css({'background-color': ''});
$displaydiv.avatar(OC.currentUser, 128, true);
}
@ -232,7 +236,7 @@ $(document).ready(function(){
type: 'DELETE',
url: OC.Router.generate('core_avatar_delete'),
success: function(msg) {
updateAvatar();
updateAvatar(true);
}
});
});

View File

@ -128,7 +128,7 @@ if (!$_['internetconnectionworking']) {
</td>
</tr>
<tr>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('style="display:none"');?>>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('class="hidden"');?>>
<input type="checkbox" name="shareapi_allow_links" id="allowLinks"
value="1" <?php if ($_['allowLinks'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="allowLinks"><?php p($l->t('Allow links'));?></label><br/>
@ -137,7 +137,7 @@ if (!$_['internetconnectionworking']) {
</tr>
<?php if (!\OCP\App::isEnabled('files_encryption')) { ?>
<tr>
<td <?php if ($_['shareAPIEnabled'] == 'no') print_unescaped('style="display:none"');?>>
<td <?php if ($_['shareAPIEnabled'] == 'no') print_unescaped('class="hidden"');?>>
<input type="checkbox" name="shareapi_allow_public_upload" id="allowPublicUpload"
value="1" <?php if ($_['allowPublicUpload'] == 'yes') print_unescaped('checked="checked"'); ?> />
<label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/>
@ -146,7 +146,7 @@ if (!$_['internetconnectionworking']) {
</tr>
<?php } ?>
<tr>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('style="display:none"');?>>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('class="hidden"');?>>
<input type="checkbox" name="shareapi_allow_resharing" id="allowResharing"
value="1" <?php if ($_['allowResharing'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="allowResharing"><?php p($l->t('Allow resharing'));?></label><br/>
@ -154,7 +154,7 @@ if (!$_['internetconnectionworking']) {
</td>
</tr>
<tr>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('style="display:none"');?>>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('class="hidden"');?>>
<input type="radio" name="shareapi_share_policy" id="sharePolicyGlobal"
value="global" <?php if ($_['sharePolicy'] === 'global') print_unescaped('checked="checked"'); ?> />
<label for="sharePolicyGlobal"><?php p($l->t('Allow users to share with anyone')); ?></label><br/>
@ -163,6 +163,14 @@ if (!$_['internetconnectionworking']) {
<label for="sharePolicyGroupsOnly"><?php p($l->t('Allow users to only share with users in their groups'));?></label><br/>
</td>
</tr>
<tr>
<td <?php if ($_['shareAPIEnabled'] === 'no') print_unescaped('class="hidden"');?>>
<input type="checkbox" name="shareapi_allow_mail_notification" id="allowMailNotification"
value="1" <?php if ($_['allowMailNotification'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="allowMailNotification"><?php p($l->t('Allow mail notification'));?></label><br/>
<em><?php p($l->t('Allow user to send mail notification for shared files')); ?></em>
</td>
</tr>
</table>
</fieldset>
@ -223,7 +231,7 @@ endfor;?>
</td>
<td>
<?php if(is_int($entry->time)){
p(OC_Util::formatDate($entry->time));
p(OC_Util::formatDate($entry->time));
} else {
p($entry->time);
}?>

View File

@ -46,7 +46,6 @@ class Test_TemplateFunctions extends PHPUnit_Framework_TestCase {
$this->assertEquals("This is a good string!", $result);
}
public function testPrintUnescaped() {
$htmlString = "<script>alert('xss');</script>";
@ -66,5 +65,194 @@ class Test_TemplateFunctions extends PHPUnit_Framework_TestCase {
$this->assertEquals("This is a good string!", $result);
}
// ---------------------------------------------------------------------------
// Test relative_modified_date with dates only
// ---------------------------------------------------------------------------
public function testRelativeDateToday(){
$currentTime = 1380703592;
$elementTime = $currentTime;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('today', $result);
// 2 hours ago is still today
$elementTime = $currentTime - 2 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('today', $result);
}
public function testRelativeDateYesterday(){
$currentTime = 1380703592;
$elementTime = $currentTime - 24 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('yesterday', $result);
// yesterday - 2 hours is still yesterday
$elementTime = $currentTime - 26 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('yesterday', $result);
}
public function testRelativeDate2DaysAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 48 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('2 days ago', $result);
// 2 days ago minus 4 hours is still 2 days ago
$elementTime = $currentTime - 52 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('2 days ago', $result);
}
public function testRelativeDateLastMonth(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 31;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('last month', $result);
$elementTime = $currentTime - 86400 * 35;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('last month', $result);
}
public function testRelativeDateMonthsAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 60;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('2 months ago', $result);
$elementTime = $currentTime - 86400 * 65;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('2 months ago', $result);
}
public function testRelativeDateLastYear(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 365;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('last year', $result);
$elementTime = $currentTime - 86400 * 450;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('last year', $result);
}
public function testRelativeDateYearsAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 365.25 * 2;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('years ago', $result);
$elementTime = $currentTime - 86400 * 365.25 * 3;
$result = (string)relative_modified_date($elementTime, $currentTime, true);
$this->assertEquals('years ago', $result);
}
// ---------------------------------------------------------------------------
// Test relative_modified_date with timestamps only (date + time value)
// ---------------------------------------------------------------------------
public function testRelativeTimeSecondsAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 5;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('seconds ago', $result);
}
public function testRelativeTimeMinutesAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 190;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('3 minutes ago', $result);
}
public function testRelativeTimeHoursAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 7500;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('2 hours ago', $result);
}
public function testRelativeTime2DaysAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 48 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('2 days ago', $result);
// 2 days ago minus 4 hours is still 2 days ago
$elementTime = $currentTime - 52 * 3600;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('2 days ago', $result);
}
public function testRelativeTimeLastMonth(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 31;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('last month', $result);
$elementTime = $currentTime - 86400 * 35;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('last month', $result);
}
public function testRelativeTimeMonthsAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 60;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('2 months ago', $result);
$elementTime = $currentTime - 86400 * 65;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('2 months ago', $result);
}
public function testRelativeTimeLastYear(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 365;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('last year', $result);
$elementTime = $currentTime - 86400 * 450;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('last year', $result);
}
public function testRelativeTimeYearsAgo(){
$currentTime = 1380703592;
$elementTime = $currentTime - 86400 * 365.25 * 2;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('years ago', $result);
$elementTime = $currentTime - 86400 * 365.25 * 3;
$result = (string)relative_modified_date($elementTime, $currentTime, false);
$this->assertEquals('years ago', $result);
}
}