3
.mailmap
|
@ -182,7 +182,8 @@ Jesús Macias <jmacias@solidgear.es> Jesus Macias <jmacias@full-on-net.com>
|
|||
jknockaert <jasper@knockaert.nl>
|
||||
Joan <aseques@gmail.com>
|
||||
Joar Wandborg <git@wandborg.com>
|
||||
Joas Schilling <nickvergessen@owncloud.com> Joas Schilling <nickvergessen@gmx.de>
|
||||
Joas Schilling <coding@schilljs.com> Joas Schilling <nickvergessen@gmx.de>
|
||||
Joas Schilling <coding@schilljs.com> Joas Schilling <nickvergessen@owncloud.com>
|
||||
joel hansson <joel.hansson@gmail.com>
|
||||
Johan Björk <johanimon@gmail.com>
|
||||
Johannes Twittmann <github.com@deryo.de>
|
||||
|
|
|
@ -1079,22 +1079,27 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
|||
'lastmodified' => time(),
|
||||
];
|
||||
|
||||
foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) {
|
||||
if (isset($properties[$xmlName])) {
|
||||
$propertiesBoolean = ['striptodos', 'stripalarms', 'stripattachments'];
|
||||
|
||||
$values[$dbName] = $properties[$xmlName];
|
||||
$fieldNames[] = $dbName;
|
||||
foreach($this->subscriptionPropertyMap as $xmlName=>$dbName) {
|
||||
if (array_key_exists($xmlName, $properties)) {
|
||||
$values[$dbName] = $properties[$xmlName];
|
||||
if (in_array($dbName, $propertiesBoolean)) {
|
||||
$values[$dbName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$valuesToInsert = array();
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
|
||||
foreach (array_keys($values) as $name) {
|
||||
$valuesToInsert[$name] = $query->createNamedParameter($values[$name]);
|
||||
}
|
||||
|
||||
$query->insert('calendarsubscriptions')
|
||||
->values([
|
||||
'principaluri' => $query->createNamedParameter($values['principaluri']),
|
||||
'uri' => $query->createNamedParameter($values['uri']),
|
||||
'source' => $query->createNamedParameter($values['source']),
|
||||
'lastmodified' => $query->createNamedParameter($values['lastmodified']),
|
||||
])
|
||||
->values($valuesToInsert)
|
||||
->execute();
|
||||
|
||||
return $this->db->lastInsertId('*PREFIX*calendarsubscriptions');
|
||||
|
|
|
@ -333,15 +333,20 @@ EOD;
|
|||
|
||||
public function testSubscriptions() {
|
||||
$id = $this->backend->createSubscription(self::UNIT_TEST_USER, 'Subscription', [
|
||||
'{http://calendarserver.org/ns/}source' => new Href('test-source')
|
||||
'{http://calendarserver.org/ns/}source' => new Href('test-source'),
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#1C4587',
|
||||
'{http://calendarserver.org/ns/}subscribed-strip-todos' => ''
|
||||
]);
|
||||
|
||||
$subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($subscriptions));
|
||||
$this->assertEquals('#1C4587', $subscriptions[0]['{http://apple.com/ns/ical/}calendar-color']);
|
||||
$this->assertEquals(true, $subscriptions[0]['{http://calendarserver.org/ns/}subscribed-strip-todos']);
|
||||
$this->assertEquals($id, $subscriptions[0]['id']);
|
||||
|
||||
$patch = new PropPatch([
|
||||
'{DAV:}displayname' => 'Unit test',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#ac0606',
|
||||
]);
|
||||
$this->backend->updateSubscription($id, $patch);
|
||||
$patch->commit();
|
||||
|
@ -350,6 +355,7 @@ EOD;
|
|||
$this->assertEquals(1, count($subscriptions));
|
||||
$this->assertEquals($id, $subscriptions[0]['id']);
|
||||
$this->assertEquals('Unit test', $subscriptions[0]['{DAV:}displayname']);
|
||||
$this->assertEquals('#ac0606', $subscriptions[0]['{http://apple.com/ns/ical/}calendar-color']);
|
||||
|
||||
$this->backend->deleteSubscription($id);
|
||||
$subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
|
||||
|
|
|
@ -217,28 +217,32 @@ class FederatedShareProvider implements IShareProvider {
|
|||
$share->getPermissions(),
|
||||
$token
|
||||
);
|
||||
$sharedByFederatedId = $share->getSharedBy();
|
||||
if ($this->userManager->userExists($sharedByFederatedId)) {
|
||||
$sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL();
|
||||
}
|
||||
$send = $this->notifications->sendRemoteShare(
|
||||
$token,
|
||||
$share->getSharedWith(),
|
||||
$share->getNode()->getName(),
|
||||
$shareId,
|
||||
$share->getShareOwner(),
|
||||
$share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(),
|
||||
$share->getSharedBy(),
|
||||
$sharedByFederatedId
|
||||
);
|
||||
|
||||
if ($send === false) {
|
||||
$data = $this->getRawShare($shareId);
|
||||
$share = $this->createShareObject($data);
|
||||
$this->removeShareFromTable($share);
|
||||
$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.',
|
||||
[$share->getNode()->getName(), $share->getSharedWith()]);
|
||||
throw new \Exception($message_t);
|
||||
try {
|
||||
$sharedByFederatedId = $share->getSharedBy();
|
||||
if ($this->userManager->userExists($sharedByFederatedId)) {
|
||||
$sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL();
|
||||
}
|
||||
$send = $this->notifications->sendRemoteShare(
|
||||
$token,
|
||||
$share->getSharedWith(),
|
||||
$share->getNode()->getName(),
|
||||
$shareId,
|
||||
$share->getShareOwner(),
|
||||
$share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(),
|
||||
$share->getSharedBy(),
|
||||
$sharedByFederatedId
|
||||
);
|
||||
|
||||
if ($send === false) {
|
||||
$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.',
|
||||
[$share->getNode()->getName(), $share->getSharedWith()]);
|
||||
throw new \Exception($message_t);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Failed to notify remote server of federated share, removing share (' . $e->getMessage() . ')');
|
||||
$this->removeShareFromTableById($shareId);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $shareId;
|
||||
|
@ -526,13 +530,22 @@ class FederatedShareProvider implements IShareProvider {
|
|||
* @param IShare $share
|
||||
*/
|
||||
public function removeShareFromTable(IShare $share) {
|
||||
$this->removeShareFromTableById($share->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* remove share from table
|
||||
*
|
||||
* @param string $shareId
|
||||
*/
|
||||
private function removeShareFromTableById($shareId) {
|
||||
$qb = $this->dbConnection->getQueryBuilder();
|
||||
$qb->delete('share')
|
||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
|
||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
|
||||
$qb->execute();
|
||||
|
||||
$qb->delete('federated_reshares')
|
||||
->where($qb->expr()->eq('share_id', $qb->createNamedParameter($share->getId())));
|
||||
->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
|
||||
$qb->execute();
|
||||
}
|
||||
|
||||
|
|
|
@ -217,10 +217,6 @@ class FederatedShareProviderTest extends \Test\TestCase {
|
|||
'sharedBy@http://localhost/'
|
||||
)->willReturn(false);
|
||||
|
||||
$this->rootFolder->expects($this->once())
|
||||
->method('getUserFolder')
|
||||
->with('shareOwner')
|
||||
->will($this->returnSelf());
|
||||
$this->rootFolder->method('getById')
|
||||
->with('42')
|
||||
->willReturn([$node]);
|
||||
|
@ -244,6 +240,62 @@ class FederatedShareProviderTest extends \Test\TestCase {
|
|||
$this->assertFalse($data);
|
||||
}
|
||||
|
||||
public function testCreateException() {
|
||||
$share = $this->shareManager->newShare();
|
||||
|
||||
$node = $this->getMock('\OCP\Files\File');
|
||||
$node->method('getId')->willReturn(42);
|
||||
$node->method('getName')->willReturn('myFile');
|
||||
|
||||
$share->setSharedWith('user@server.com')
|
||||
->setSharedBy('sharedBy')
|
||||
->setShareOwner('shareOwner')
|
||||
->setPermissions(19)
|
||||
->setNode($node);
|
||||
|
||||
$this->tokenHandler->method('generateToken')->willReturn('token');
|
||||
|
||||
$this->addressHandler->expects($this->any())->method('generateRemoteURL')
|
||||
->willReturn('http://localhost/');
|
||||
$this->addressHandler->expects($this->any())->method('splitUserRemote')
|
||||
->willReturn(['user', 'server.com']);
|
||||
|
||||
$this->notifications->expects($this->once())
|
||||
->method('sendRemoteShare')
|
||||
->with(
|
||||
$this->equalTo('token'),
|
||||
$this->equalTo('user@server.com'),
|
||||
$this->equalTo('myFile'),
|
||||
$this->anything(),
|
||||
'shareOwner',
|
||||
'shareOwner@http://localhost/',
|
||||
'sharedBy',
|
||||
'sharedBy@http://localhost/'
|
||||
)->willThrowException(new \Exception('dummy'));
|
||||
|
||||
$this->rootFolder->method('getById')
|
||||
->with('42')
|
||||
->willReturn([$node]);
|
||||
|
||||
try {
|
||||
$share = $this->provider->create($share);
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('dummy', $e->getMessage());
|
||||
}
|
||||
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$stmt = $qb->select('*')
|
||||
->from('share')
|
||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
|
||||
->execute();
|
||||
|
||||
$data = $stmt->fetch();
|
||||
$stmt->closeCursor();
|
||||
|
||||
$this->assertFalse($data);
|
||||
}
|
||||
|
||||
public function testCreateShareWithSelf() {
|
||||
$share = $this->shareManager->newShare();
|
||||
|
||||
|
|
|
@ -513,7 +513,7 @@
|
|||
* Event handler for when the URL changed
|
||||
*/
|
||||
_onUrlChanged: function(e) {
|
||||
if (e && e.dir) {
|
||||
if (e && _.isString(e.dir)) {
|
||||
this.changeDirectory(e.dir, false, true);
|
||||
}
|
||||
},
|
||||
|
@ -1397,6 +1397,16 @@
|
|||
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
|
||||
},
|
||||
|
||||
_isValidPath: function(path) {
|
||||
var sections = path.split('/');
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
if (sections[i] === '..') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the current directory name and updates the breadcrumb.
|
||||
* @param targetDir directory to display
|
||||
|
@ -1404,7 +1414,11 @@
|
|||
* @param {string} [fileId] file id
|
||||
*/
|
||||
_setCurrentDir: function(targetDir, changeUrl, fileId) {
|
||||
targetDir = targetDir.replace(/\\/g, '/').replace(/\/\.\.\//g, '/');
|
||||
targetDir = targetDir.replace(/\\/g, '/');
|
||||
if (!this._isValidPath(targetDir)) {
|
||||
targetDir = '/';
|
||||
changeUrl = true;
|
||||
}
|
||||
var previousDir = this.getCurrentDirectory(),
|
||||
baseDir = OC.basename(targetDir);
|
||||
|
||||
|
@ -1415,6 +1429,9 @@
|
|||
this.setPageTitle();
|
||||
}
|
||||
|
||||
if (targetDir.length > 0 && targetDir[0] !== '/') {
|
||||
targetDir = '/' + targetDir;
|
||||
}
|
||||
this._currentDirectory = targetDir;
|
||||
|
||||
// legacy stuff
|
||||
|
|
|
@ -1334,13 +1334,32 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList.changeDirectory('/another\\subdir');
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/another/subdir');
|
||||
});
|
||||
it('converts backslashes to slashes and removes traversals when calling changeDirectory()', function() {
|
||||
fileList.changeDirectory('/another\\subdir/../foo\\../bar\\..\\file/..\\folder/../');
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/another/subdir/foo/bar/file/folder/');
|
||||
it('switches to root dir when current directory is invalid', function() {
|
||||
_.each([
|
||||
'..',
|
||||
'/..',
|
||||
'../',
|
||||
'/../',
|
||||
'/../abc',
|
||||
'/abc/..',
|
||||
'/abc/../',
|
||||
'/../abc/',
|
||||
'/another\\subdir/../foo\\../bar\\..\\file/..\\folder/../'
|
||||
], function(path) {
|
||||
fileList.changeDirectory(path);
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/');
|
||||
});
|
||||
});
|
||||
it('does not convert folders with a ".." in the name', function() {
|
||||
fileList.changeDirectory('/abc../def');
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/abc../def');
|
||||
it('allows paths with dotdot at the beginning or end', function() {
|
||||
_.each([
|
||||
'/..abc',
|
||||
'/def..',
|
||||
'/...',
|
||||
'/abc../def'
|
||||
], function(path) {
|
||||
fileList.changeDirectory(path);
|
||||
expect(fileList.getCurrentDirectory()).toEqual(path);
|
||||
});
|
||||
});
|
||||
it('switches to root dir when current directory does not exist', function() {
|
||||
fileList.changeDirectory('/unexist');
|
||||
|
@ -1404,6 +1423,12 @@ describe('OCA.Files.FileList tests', function() {
|
|||
setDirSpy.restore();
|
||||
getFolderContentsStub.restore();
|
||||
});
|
||||
it('prepends a slash to directory if none was given', function() {
|
||||
fileList.changeDirectory('');
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/');
|
||||
fileList.changeDirectory('noslash');
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/noslash');
|
||||
});
|
||||
});
|
||||
describe('breadcrumb events', function() {
|
||||
var deferredList;
|
||||
|
|
|
@ -98,15 +98,30 @@ class Backends extends Base {
|
|||
$result = [
|
||||
'name' => $data['name'],
|
||||
'identifier' => $data['identifier'],
|
||||
'configuration' => array_map(function (DefinitionParameter $parameter) {
|
||||
return $parameter->getTypeName();
|
||||
}, $data['configuration'])
|
||||
'configuration' => $this->formatConfiguration($data['configuration'])
|
||||
];
|
||||
if ($backend instanceof Backend) {
|
||||
$result['storage_class'] = $backend->getStorageClass();
|
||||
$authBackends = $this->backendService->getAuthMechanismsByScheme(array_keys($backend->getAuthSchemes()));
|
||||
$result['supported_authentication_backends'] = array_keys($authBackends);
|
||||
$authConfig = array_map(function (AuthMechanism $auth) {
|
||||
return $this->serializeAuthBackend($auth)['configuration'];
|
||||
}, $authBackends);
|
||||
$result['authentication_configuration'] = array_combine(array_keys($authBackends), $authConfig);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DefinitionParameter[] $parameters
|
||||
* @return string[]
|
||||
*/
|
||||
private function formatConfiguration(array $parameters) {
|
||||
$configuration = array_filter($parameters, function (DefinitionParameter $parameter) {
|
||||
return $parameter->getType() !== DefinitionParameter::VALUE_HIDDEN;
|
||||
});
|
||||
return array_map(function (DefinitionParameter $parameter) {
|
||||
return $parameter->getTypeName();
|
||||
}, $configuration);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,42 @@
|
|||
var permission = parseInt($tr.attr('data-permissions')) | OC.PERMISSION_DELETE;
|
||||
$tr.attr('data-permissions', permission);
|
||||
}
|
||||
|
||||
// add row with expiration date for link only shares - influenced by _createRow of filelist
|
||||
if (this._linksOnly) {
|
||||
var expirationTimestamp = 0;
|
||||
if(fileData.shares[0].expiration !== null) {
|
||||
expirationTimestamp = moment(fileData.shares[0].expiration).valueOf();
|
||||
}
|
||||
$tr.attr('data-expiration', expirationTimestamp);
|
||||
|
||||
// date column (1000 milliseconds to seconds, 60 seconds, 60 minutes, 24 hours)
|
||||
// difference in days multiplied by 5 - brightest shade for expiry dates in more than 32 days (160/5)
|
||||
var modifiedColor = Math.round((expirationTimestamp - (new Date()).getTime()) / 1000 / 60 / 60 / 24 * 5);
|
||||
// ensure that the brightest color is still readable
|
||||
if (modifiedColor >= 160) {
|
||||
modifiedColor = 160;
|
||||
}
|
||||
|
||||
if (expirationTimestamp > 0) {
|
||||
formatted = OC.Util.formatDate(expirationTimestamp);
|
||||
text = OC.Util.relativeModifiedDate(expirationTimestamp);
|
||||
} else {
|
||||
formatted = t('files_sharing', 'No expiration date set');
|
||||
text = '';
|
||||
modifiedColor = 160;
|
||||
}
|
||||
td = $('<td></td>').attr({"class": "date"});
|
||||
td.append($('<span></span>').attr({
|
||||
"class": "modified",
|
||||
"title": formatted,
|
||||
"style": 'color:rgb(' + modifiedColor + ',' + modifiedColor + ',' + modifiedColor + ')'
|
||||
}).text(text)
|
||||
.tooltip({placement: 'top'})
|
||||
);
|
||||
|
||||
$tr.append(td);
|
||||
}
|
||||
return $tr;
|
||||
},
|
||||
|
||||
|
@ -98,6 +134,11 @@
|
|||
// root has special permissions
|
||||
this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
|
||||
this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty);
|
||||
|
||||
// hide expiration date header for non link only shares
|
||||
if (!this._linksOnly) {
|
||||
this.$el.find('th.column-expiration').addClass('hidden');
|
||||
}
|
||||
}
|
||||
else {
|
||||
OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments);
|
||||
|
@ -249,6 +290,7 @@
|
|||
type: share.share_type,
|
||||
target: share.share_with,
|
||||
stime: share.stime * 1000,
|
||||
expiration: share.expiration,
|
||||
};
|
||||
if (self._sharedWithUser) {
|
||||
file.shareOwner = share.displayname_owner;
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<th id="headerDate" class="hidden column-mtime">
|
||||
<a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Share time' )); ?></span><span class="sort-indicator"></span></a>
|
||||
</th>
|
||||
<th class="hidden column-expiration">
|
||||
<a class="columntitle"><span><?php p($l->t( 'Expiration date' )); ?></span></a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="fileList">
|
||||
|
|
|
@ -30,6 +30,9 @@ use OCP\Share\IShare;
|
|||
use OCP\Share\IManager;
|
||||
use OCP\Files\Mount\IMountPoint;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
class MountProviderTest extends \Test\TestCase {
|
||||
|
||||
/** @var MountProvider */
|
||||
|
|
|
@ -38,6 +38,9 @@ describe('OCA.Sharing.FileList tests', function() {
|
|||
'<th class="hidden column-mtime">' +
|
||||
'<a class="columntitle" data-sort="mtime"><span class="sort-indicator"></span></a>' +
|
||||
'</th>' +
|
||||
'<th class="column-expiration">' +
|
||||
'<a class="columntitle"><span>Expiration date</span></a>' +
|
||||
'</th>' +
|
||||
'</tr></thead>' +
|
||||
'<tbody id="fileList"></tbody>' +
|
||||
'<tfoot></tfoot>' +
|
||||
|
@ -512,6 +515,9 @@ describe('OCA.Sharing.FileList tests', function() {
|
|||
|
||||
fileList.reload();
|
||||
|
||||
var expirationDateInADay = moment()
|
||||
.add(1, 'days').format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
/* jshint camelcase: false */
|
||||
ocsResponse = {
|
||||
ocs: {
|
||||
|
@ -528,12 +534,28 @@ describe('OCA.Sharing.FileList tests', function() {
|
|||
path: '/local path/local name.txt',
|
||||
permissions: 1,
|
||||
stime: 11111,
|
||||
expiration: null,
|
||||
share_type: OC.Share.SHARE_TYPE_LINK,
|
||||
share_with: null,
|
||||
token: 'abc',
|
||||
mimetype: 'text/plain',
|
||||
uid_owner: 'user1',
|
||||
displayname_owner: 'User One'
|
||||
},{
|
||||
id: 8,
|
||||
item_type: 'file',
|
||||
item_source: 50,
|
||||
file_source: 50,
|
||||
path: '/local path2/local name2.txt',
|
||||
permissions: 1,
|
||||
stime: 11112,
|
||||
expiration: expirationDateInADay,
|
||||
share_type: OC.Share.SHARE_TYPE_LINK,
|
||||
share_with: null,
|
||||
token: 'abcd',
|
||||
mimetype: 'text/plain2',
|
||||
uid_owner: 'user2',
|
||||
displayname_owner: 'User One2'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
@ -570,10 +592,10 @@ describe('OCA.Sharing.FileList tests', function() {
|
|||
JSON.stringify(ocsResponse)
|
||||
);
|
||||
|
||||
// only renders the link share entry
|
||||
// only renders the link share entries
|
||||
var $rows = fileList.$el.find('tbody tr');
|
||||
var $tr = $rows.eq(0);
|
||||
expect($rows.length).toEqual(1);
|
||||
expect($rows.length).toEqual(2);
|
||||
expect($tr.attr('data-id')).toEqual('49');
|
||||
expect($tr.attr('data-type')).toEqual('file');
|
||||
expect($tr.attr('data-file')).toEqual('local name.txt');
|
||||
|
@ -588,8 +610,17 @@ describe('OCA.Sharing.FileList tests', function() {
|
|||
expect($tr.find('a.name').attr('href')).toEqual(
|
||||
OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
|
||||
);
|
||||
expect($tr.attr('data-expiration')).toEqual('0');
|
||||
expect($tr.find('td:last-child span').text()).toEqual('');
|
||||
|
||||
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
|
||||
|
||||
// change to next row
|
||||
$tr = $rows.eq(1);
|
||||
expect($tr.attr('data-id')).toEqual('50');
|
||||
expect($tr.attr('data-file')).toEqual('local name2.txt');
|
||||
expect($tr.attr('data-expiration')).not.toEqual('0');
|
||||
expect($tr.find('td:last-child span').text()).toEqual('in a day');
|
||||
});
|
||||
it('does not show virtual token recipient as recipient when password was set', function() {
|
||||
/* jshint camelcase: false */
|
||||
|
@ -613,7 +644,7 @@ describe('OCA.Sharing.FileList tests', function() {
|
|||
// only renders the link share entry
|
||||
var $rows = fileList.$el.find('tbody tr');
|
||||
var $tr = $rows.eq(0);
|
||||
expect($rows.length).toEqual(1);
|
||||
expect($rows.length).toEqual(2);
|
||||
expect($tr.attr('data-id')).toEqual('49');
|
||||
expect($tr.attr('data-type')).toEqual('file');
|
||||
expect($tr.attr('data-file')).toEqual('local name.txt');
|
||||
|
|
|
@ -645,7 +645,7 @@ class Storage {
|
|||
//distance between two version too small, mark to delete
|
||||
$toDelete[$key] = $version['path'] . '.v' . $version['version'];
|
||||
$size += $version['size'];
|
||||
\OCP\Util::writeLog('files_versions', 'Mark to expire '. $version['path'] .' next version should be ' . $nextVersion . " or smaller. (prevTimestamp: " . $prevTimestamp . "; step: " . $step, \OCP\Util::DEBUG);
|
||||
\OCP\Util::writeLog('files_versions', 'Mark to expire '. $version['path'] .' next version should be ' . $nextVersion . " or smaller. (prevTimestamp: " . $prevTimestamp . "; step: " . $step, \OCP\Util::INFO);
|
||||
} else {
|
||||
$nextVersion = $version['version'] - $step;
|
||||
$prevTimestamp = $version['version'];
|
||||
|
@ -766,7 +766,7 @@ class Storage {
|
|||
self::deleteVersion($versionsFileview, $path);
|
||||
\OC_Hook::emit('\OCP\Versions', 'delete', array('path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
|
||||
unset($allVersions[$key]); // update array with the versions we keep
|
||||
\OCP\Util::writeLog('files_versions', "Expire: " . $path, \OCP\Util::DEBUG);
|
||||
\OCP\Util::writeLog('files_versions', "Expire: " . $path, \OCP\Util::INFO);
|
||||
}
|
||||
|
||||
// Check if enough space is available after versions are rearranged.
|
||||
|
@ -782,7 +782,7 @@ class Storage {
|
|||
\OC_Hook::emit('\OCP\Versions', 'preDelete', array('path' => $version['path'].'.v'.$version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
|
||||
self::deleteVersion($versionsFileview, $version['path'] . '.v' . $version['version']);
|
||||
\OC_Hook::emit('\OCP\Versions', 'delete', array('path' => $version['path'].'.v'.$version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
|
||||
\OCP\Util::writeLog('files_versions', 'running out of space! Delete oldest version: ' . $version['path'].'.v'.$version['version'] , \OCP\Util::DEBUG);
|
||||
\OCP\Util::writeLog('files_versions', 'running out of space! Delete oldest version: ' . $version['path'].'.v'.$version['version'] , \OCP\Util::INFO);
|
||||
$versionsSize -= $version['size'];
|
||||
$availableSpace += $version['size'];
|
||||
next($allVersions);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
namespace OCA\User_LDAP\User;
|
||||
|
||||
use OC\Cache\CappedMemoryCache;
|
||||
use OCA\User_LDAP\LogWrapper;
|
||||
use OCA\User_LDAP\FilesystemHelper;
|
||||
use OCP\IAvatarManager;
|
||||
|
@ -62,14 +63,13 @@ class Manager {
|
|||
protected $avatarManager;
|
||||
|
||||
/**
|
||||
* array['byDN'] \OCA\User_LDAP\User\User[]
|
||||
* ['byUid'] \OCA\User_LDAP\User\User[]
|
||||
* @var array $users
|
||||
* @var CappedMemoryCache $usersByDN
|
||||
*/
|
||||
protected $users = array(
|
||||
'byDN' => array(),
|
||||
'byUid' => array(),
|
||||
);
|
||||
protected $usersByDN;
|
||||
/**
|
||||
* @var CappedMemoryCache $usersByUid
|
||||
*/
|
||||
protected $usersByUid;
|
||||
|
||||
/**
|
||||
* @param IConfig $ocConfig
|
||||
|
@ -93,6 +93,8 @@ class Manager {
|
|||
$this->image = $image;
|
||||
$this->db = $db;
|
||||
$this->userManager = $userManager;
|
||||
$this->usersByDN = new CappedMemoryCache();
|
||||
$this->usersByUid = new CappedMemoryCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,8 +118,8 @@ class Manager {
|
|||
$user = new User($uid, $dn, $this->access, $this->ocConfig,
|
||||
$this->ocFilesystem, clone $this->image, $this->ocLog,
|
||||
$this->avatarManager, $this->userManager);
|
||||
$this->users['byDN'][$dn] = $user;
|
||||
$this->users['byUid'][$uid] = $user;
|
||||
$this->usersByDN[$dn] = $user;
|
||||
$this->usersByUid[$uid] = $user;
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
@ -219,10 +221,10 @@ class Manager {
|
|||
*/
|
||||
public function get($id) {
|
||||
$this->checkAccess();
|
||||
if(isset($this->users['byDN'][$id])) {
|
||||
return $this->users['byDN'][$id];
|
||||
} else if(isset($this->users['byUid'][$id])) {
|
||||
return $this->users['byUid'][$id];
|
||||
if(isset($this->usersByDN[$id])) {
|
||||
return $this->usersByDN[$id];
|
||||
} else if(isset($this->usersByUid[$id])) {
|
||||
return $this->usersByUid[$id];
|
||||
}
|
||||
|
||||
if($this->access->stringResemblesDN($id) ) {
|
||||
|
|
|
@ -228,6 +228,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
|||
return false;
|
||||
}
|
||||
$newDn = $this->access->getUserDnByUuid($uuid);
|
||||
//check if renamed user is still valid by reapplying the ldap filter
|
||||
if(!is_array($this->access->readAttribute($newDn, '', $this->access->connection->ldapUserFilter))) {
|
||||
return false;
|
||||
}
|
||||
$this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
</button>
|
||||
<a href="<?php p(link_to_docs('admin-ldap')); ?>"
|
||||
target="_blank" rel="noreferrer">
|
||||
<img src="<?php print_unescaped(image_path('', 'actions/info.png')); ?>"
|
||||
<img src="<?php print_unescaped(image_path('', 'actions/info.svg')); ?>"
|
||||
style="height:1.75ex" />
|
||||
<?php p($l->t('Help'));?>
|
||||
</a>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</button>
|
||||
<a href="<?php p(link_to_docs('admin-ldap')); ?>"
|
||||
target="_blank" rel="noreferrer">
|
||||
<img src="<?php print_unescaped(image_path('', 'actions/info.png')); ?>"
|
||||
<img src="<?php print_unescaped(image_path('', 'actions/info.svg')); ?>"
|
||||
style="height:1.75ex" />
|
||||
<span class="ldap_grey"><?php p($l->t('Help'));?></span>
|
||||
</a>
|
||||
|
|
|
@ -26,6 +26,21 @@ Feature: sharing
|
|||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
|
||||
Scenario: Creating a new share with user who already received a share through their group
|
||||
Given As an "admin"
|
||||
And user "user0" exists
|
||||
And user "user1" exists
|
||||
And group "sharing-group" exists
|
||||
And user "user1" belongs to group "sharing-group"
|
||||
And file "welcome.txt" of user "user0" is shared with group "sharing-group"
|
||||
And As an "user0"
|
||||
Then sending "POST" to "/apps/files_sharing/api/v1/shares" with
|
||||
| path | welcome.txt |
|
||||
| shareWith | user1 |
|
||||
| shareType | 0 |
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
|
||||
Scenario: Creating a new public share
|
||||
Given user "user0" exists
|
||||
And As an "user0"
|
||||
|
|
|
@ -32,7 +32,6 @@ use OC\AppFramework\Utility\TimeFactory;
|
|||
use OC\Core\Controller\AvatarController;
|
||||
use OC\Core\Controller\LoginController;
|
||||
use OC\Core\Controller\LostController;
|
||||
use OC\Core\Controller\OccController;
|
||||
use OC\Core\Controller\TokenController;
|
||||
use OC\Core\Controller\TwoFactorChallengeController;
|
||||
use OC\Core\Controller\UserController;
|
||||
|
@ -126,18 +125,6 @@ class Application extends App {
|
|||
$c->query('SecureRandom')
|
||||
);
|
||||
});
|
||||
$container->registerService('OccController', function(SimpleContainer $c) {
|
||||
return new OccController(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$c->query('Config'),
|
||||
new \OC\Console\Application(
|
||||
$c->query('Config'),
|
||||
$c->query('ServerContainer')->getEventDispatcher(),
|
||||
$c->query('Request')
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Core class wrappers
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Core\Controller;
|
||||
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OC\Console\Application;
|
||||
use OCP\IConfig;
|
||||
use OCP\IRequest;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
|
||||
class OccController extends Controller {
|
||||
|
||||
/** @var array */
|
||||
private $allowedCommands = [
|
||||
'app:disable',
|
||||
'app:enable',
|
||||
'app:getpath',
|
||||
'app:list',
|
||||
'check',
|
||||
'config:list',
|
||||
'maintenance:mode',
|
||||
'status',
|
||||
'upgrade'
|
||||
];
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var Application */
|
||||
private $console;
|
||||
|
||||
/**
|
||||
* OccController constructor.
|
||||
*
|
||||
* @param string $appName
|
||||
* @param IRequest $request
|
||||
* @param IConfig $config
|
||||
* @param Application $console
|
||||
*/
|
||||
public function __construct($appName, IRequest $request,
|
||||
IConfig $config, Application $console) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->config = $config;
|
||||
$this->console = $console;
|
||||
}
|
||||
|
||||
/**
|
||||
* @PublicPage
|
||||
* @NoCSRFRequired
|
||||
*
|
||||
* Execute occ command
|
||||
* Sample request
|
||||
* POST http://domain.tld/index.php/occ/status',
|
||||
* {
|
||||
* 'params': {
|
||||
* '--no-warnings':'1',
|
||||
* '--output':'json'
|
||||
* },
|
||||
* 'token': 'someToken'
|
||||
* }
|
||||
*
|
||||
* @param string $command
|
||||
* @param string $token
|
||||
* @param array $params
|
||||
*
|
||||
* @return JSONResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function execute($command, $token, $params = []) {
|
||||
try {
|
||||
$this->validateRequest($command, $token);
|
||||
|
||||
$output = new BufferedOutput();
|
||||
$formatter = $output->getFormatter();
|
||||
$formatter->setDecorated(false);
|
||||
$this->console->setAutoExit(false);
|
||||
$this->console->loadCommands(new ArrayInput([]), $output);
|
||||
|
||||
$inputArray = array_merge(['command' => $command], $params);
|
||||
$input = new ArrayInput($inputArray);
|
||||
|
||||
$exitCode = $this->console->run($input, $output);
|
||||
$response = $output->fetch();
|
||||
|
||||
$json = [
|
||||
'exitCode' => $exitCode,
|
||||
'response' => $response
|
||||
];
|
||||
|
||||
} catch (\UnexpectedValueException $e){
|
||||
$json = [
|
||||
'exitCode' => 126,
|
||||
'response' => 'Not allowed',
|
||||
'details' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
return new JSONResponse($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if command is allowed and has a valid security token
|
||||
* @param $command
|
||||
* @param $token
|
||||
*/
|
||||
protected function validateRequest($command, $token){
|
||||
if (!in_array($this->request->getRemoteAddress(), ['::1', '127.0.0.1', 'localhost'])) {
|
||||
throw new \UnexpectedValueException('Web executor is not allowed to run from a different host');
|
||||
}
|
||||
|
||||
if (!in_array($command, $this->allowedCommands)) {
|
||||
throw new \UnexpectedValueException(sprintf('Command "%s" is not allowed to run via web request', $command));
|
||||
}
|
||||
|
||||
$coreToken = $this->config->getSystemValue('updater.secret', '');
|
||||
if ($coreToken === '') {
|
||||
throw new \UnexpectedValueException(
|
||||
'updater.secret is undefined in config/config.php. Either browse the admin settings in your ownCloud and click "Open updater" or define a strong secret using <pre>php -r \'echo password_hash("MyStrongSecretDoUseYourOwn!", PASSWORD_DEFAULT)."\n";\'</pre> and set this in the config.php.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!password_verify($token, $coreToken)) {
|
||||
throw new \UnexpectedValueException(
|
||||
'updater.secret does not match the provided token'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 128 B |
Before Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 251 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 138 B |
Before Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 212 B |
Before Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 493 B |
Before Width: | Height: | Size: 323 B |
Before Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 236 B |
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 160 B |
Before Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 249 B |
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 229 B |
Before Width: | Height: | Size: 106 B |
Before Width: | Height: | Size: 122 B |
Before Width: | Height: | Size: 159 B |
Before Width: | Height: | Size: 92 B |
Before Width: | Height: | Size: 96 B |
Before Width: | Height: | Size: 163 B |
Before Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 150 B |
Before Width: | Height: | Size: 163 B |
Before Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 307 B |
Before Width: | Height: | Size: 378 B |
Before Width: | Height: | Size: 424 B |
Before Width: | Height: | Size: 317 B |
Before Width: | Height: | Size: 336 B |
Before Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 293 B |
Before Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 118 B |
Before Width: | Height: | Size: 180 B |
Before Width: | Height: | Size: 496 B |
Before Width: | Height: | Size: 492 B |
Before Width: | Height: | Size: 122 B |
Before Width: | Height: | Size: 120 B |
Before Width: | Height: | Size: 238 B |
Before Width: | Height: | Size: 149 B |
Before Width: | Height: | Size: 128 B |
Before Width: | Height: | Size: 128 B |
Before Width: | Height: | Size: 142 B |
Before Width: | Height: | Size: 142 B |
Before Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 959 B |
Before Width: | Height: | Size: 648 B |
Before Width: | Height: | Size: 804 B |
Before Width: | Height: | Size: 984 B |
Before Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 892 B |
Before Width: | Height: | Size: 805 B |
Before Width: | Height: | Size: 640 B |