Skip to content

Commit bba5d88

Browse files
committed
fixup! fixup! Sharing link & mail parity
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
1 parent 2dbe01b commit bba5d88

File tree

8 files changed

+129
-47
lines changed

8 files changed

+129
-47
lines changed

apps/files_sharing/src/components/SharingEntryLink.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ import Actions from '@nextcloud/vue/dist/Components/Actions'
334334
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
335335
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
336336
337+
import GeneratePassword from '../utils/GeneratePassword'
337338
import Share from '../models/Share'
338339
import SharesMixin from '../mixins/SharesMixin'
339340
@@ -460,7 +461,7 @@ export default {
460461
},
461462
async set(enabled) {
462463
// TODO: directly save after generation to make sure the share is always protected
463-
Vue.set(this.share, 'password', enabled ? await this.generatePassword() : '')
464+
Vue.set(this.share, 'password', enabled ? await GeneratePassword() : '')
464465
Vue.set(this.share, 'newPassword', this.share.password)
465466
},
466467
},
@@ -618,7 +619,7 @@ export default {
618619
shareDefaults.expiration = this.config.defaultExpirationDateString
619620
}
620621
if (this.config.enableLinkPasswordByDefault) {
621-
shareDefaults.password = await this.generatePassword()
622+
shareDefaults.password = await GeneratePassword()
622623
}
623624
624625
// do not push yet if we need a password or an expiration date
@@ -639,7 +640,7 @@ export default {
639640
// ELSE, show the pending popovermenu
640641
// if password enforced, pre-fill with random one
641642
if (this.config.enforcePasswordForPublicLink) {
642-
shareDefaults.password = await this.generatePassword()
643+
shareDefaults.password = await GeneratePassword()
643644
}
644645
645646
// create share & close menu

apps/files_sharing/src/components/SharingInput.vue

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import debounce from 'debounce'
5353
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
5454
5555
import Config from '../services/ConfigService'
56+
import GeneratePassword from '../utils/GeneratePassword'
5657
import Share from '../models/Share'
5758
import ShareRequests from '../mixins/ShareRequests'
5859
import ShareTypes from '../mixins/ShareTypes'
@@ -412,9 +413,6 @@ export default {
412413
return true
413414
}
414415
415-
// TODO: reset the search string when done
416-
// https://github.com/shentao/vue-multiselect/issues/633
417-
418416
// handle externalResults from OCA.Sharing.ShareSearch
419417
if (value.handler) {
420418
const share = await value.handler(this)
@@ -423,25 +421,55 @@ export default {
423421
}
424422
425423
this.loading = true
424+
console.debug('Adding a new share from the input for', value)
426425
try {
426+
let password = null
427+
428+
if (this.config.enforcePasswordForPublicLink
429+
&& value.shareType === this.SHARE_TYPES.SHARE_TYPE_EMAIL) {
430+
password = await GeneratePassword()
431+
}
432+
427433
const path = (this.fileInfo.path + '/' + this.fileInfo.name).replace('//', '/')
428434
const share = await this.createShare({
429435
path,
430436
shareType: value.shareType,
431437
shareWith: value.shareWith,
438+
password,
432439
permissions: this.fileInfo.sharePermissions & OC.getCapabilities().files_sharing.default_permissions,
433440
})
434-
this.$emit('add:share', share)
435441
436-
this.getRecommendations()
442+
// If we had a password, we need to show it to the user as it was generated
443+
if (password) {
444+
share.newPassword = password
445+
// Wait for the newly added share
446+
const component = await new Promise(resolve => {
447+
this.$emit('add:share', share, resolve)
448+
})
449+
450+
// open the menu on the
451+
// freshly created share component
452+
component.open = true
453+
} else {
454+
// Else we just add it normally
455+
this.$emit('add:share', share)
456+
}
457+
458+
// reset the search string when done
459+
// FIXME: https://github.com/shentao/vue-multiselect/issues/633
460+
if (this.$refs.multiselect?.$refs?.VueMultiselect?.search) {
461+
this.$refs.multiselect.$refs.VueMultiselect.search = ''
462+
}
437463
438-
} catch (response) {
464+
await this.getRecommendations()
465+
} catch (error) {
439466
// focus back if any error
440467
const input = this.$refs.multiselect.$el.querySelector('input')
441468
if (input) {
442469
input.focus()
443470
}
444471
this.query = value.shareWith
472+
console.error('Error while adding new share', error)
445473
} finally {
446474
this.loading = false
447475
}

apps/files_sharing/src/mixins/SharesMixin.js

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
*
2121
*/
2222

23-
import axios from '@nextcloud/axios'
2423
import PQueue from 'p-queue'
2524
import debounce from 'debounce'
2625

@@ -30,8 +29,6 @@ import ShareTypes from './ShareTypes'
3029
import Config from '../services/ConfigService'
3130
import { getCurrentUser } from '@nextcloud/auth'
3231

33-
const passwordSet = 'abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789'
34-
3532
export default {
3633
mixins: [SharesRequests, ShareTypes],
3734

@@ -326,33 +323,5 @@ export default {
326323
return (this.dateTomorrow && dateMoment.isBefore(this.dateTomorrow, 'day'))
327324
|| (this.dateMaxEnforced && dateMoment.isSameOrAfter(this.dateMaxEnforced, 'day'))
328325
},
329-
330-
/**
331-
* Generate a valid policy password or
332-
* request a valid password if password_policy
333-
* is enabled
334-
*
335-
* @returns {string} a valid password
336-
*/
337-
async generatePassword() {
338-
// password policy is enabled, let's request a pass
339-
if (this.config.passwordPolicy.api && this.config.passwordPolicy.api.generate) {
340-
try {
341-
const request = await axios.get(this.config.passwordPolicy.api.generate)
342-
if (request.data.ocs.data.password) {
343-
return request.data.ocs.data.password
344-
}
345-
} catch (error) {
346-
console.info('Error generating password from password_policy', error)
347-
}
348-
}
349-
350-
// generate password of 10 length based on passwordSet
351-
return Array(10).fill(0)
352-
.reduce((prev, curr) => {
353-
prev += passwordSet.charAt(Math.floor(Math.random() * passwordSet.length))
354-
return prev
355-
}, '')
356-
},
357326
},
358327
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
/**
3+
* @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
4+
*
5+
* @author John Molakvoæ <skjnldsv@protonmail.com>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
import axios from '@nextcloud/axios'
25+
import Config from '../services/ConfigService'
26+
27+
const config = new Config()
28+
const passwordSet = 'abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789'
29+
30+
/**
31+
* Generate a valid policy password or
32+
* request a valid password if password_policy
33+
* is enabled
34+
*
35+
* @returns {string} a valid password
36+
*/
37+
export default async function() {
38+
// password policy is enabled, let's request a pass
39+
if (config.passwordPolicy.api && config.passwordPolicy.api.generate) {
40+
try {
41+
const request = await axios.get(config.passwordPolicy.api.generate)
42+
if (request.data.ocs.data.password) {
43+
return request.data.ocs.data.password
44+
}
45+
} catch (error) {
46+
console.info('Error generating password from password_policy', error)
47+
}
48+
}
49+
50+
// generate password of 10 length based on passwordSet
51+
return Array(10).fill(0)
52+
.reduce((prev, curr) => {
53+
prev += passwordSet.charAt(Math.floor(Math.random() * passwordSet.length))
54+
return prev
55+
}, '')
56+
}

apps/files_sharing/src/views/SharingTab.vue

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@
5252

5353
<!-- link shares list -->
5454
<SharingLinkList v-if="!loading"
55+
ref="linkShareList"
5556
:can-reshare="canReshare"
5657
:file-info="fileInfo"
5758
:shares="linkShares" />
5859

5960
<!-- other shares list -->
6061
<SharingList v-if="!loading"
62+
ref="shareList"
6163
:shares="shares"
6264
:file-info="fileInfo" />
6365

@@ -295,18 +297,45 @@ export default {
295297
},
296298
297299
/**
298-
* Insert share at top of arrays
300+
* Add a new share into the shares list
301+
* and return the newly created share component
299302
*
300-
* @param {Share} share the share to insert
303+
* @param {Share} share the share to add to the array
304+
* @param {Function} resolve a function to run after the share is added and its component initialized
301305
*/
302-
addShare(share) {
306+
addShare(share, resolve) {
303307
// only catching share type MAIL as link shares are added differently
304308
// meaning: not from the ShareInput
305309
if (share.type === this.SHARE_TYPES.SHARE_TYPE_EMAIL) {
306310
this.linkShares.unshift(share)
307311
} else {
308312
this.shares.unshift(share)
309313
}
314+
this.awaitForShare(share, resolve)
315+
},
316+
317+
/**
318+
* Await for next tick and render after the list updated
319+
* Then resolve with the matched vue component of the
320+
* provided share object
321+
*
322+
* @param {Share} share newly created share
323+
* @param {Function} resolve a function to execute after
324+
*/
325+
awaitForShare(share, resolve) {
326+
let listComponent = this.$refs.shareList
327+
// Only mail shares comes from the input, link shares
328+
// are managed internally in the SharingLinkList component
329+
if (share.type === this.SHARE_TYPES.SHARE_TYPE_EMAIL) {
330+
listComponent = this.$refs.linkShareList
331+
}
332+
333+
this.$nextTick(() => {
334+
const newShare = listComponent.$children.find(component => component.share === share)
335+
if (newShare) {
336+
resolve(newShare)
337+
}
338+
})
310339
},
311340
},
312341
}

apps/settings/templates/settings/admin/sharing.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
value="1" <?php if ($_['allowLinks'] === 'yes') {
7171
print_unescaped('checked="checked"');
7272
} ?> />
73-
<label for="allowLinks"><?php p($l->t('Allow users to share via link'));?></label><br/>
73+
<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/>
7474
</p>
7575

7676
<p id="publicLinkSettings" class="indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareAPIEnabled'] === 'no') {
@@ -96,7 +96,7 @@
9696
value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') {
9797
print_unescaped('checked="checked"');
9898
} ?> />
99-
<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date for link and email shares'));?></label><br/>
99+
<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/>
100100

101101
</p>
102102
<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {

build/integration/features/bootstrap/SharingContext.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,5 @@ protected function resetAppConfigs() {
4444
$this->deleteServerConfig('core', 'shareapi_default_expire_date');
4545
$this->deleteServerConfig('core', 'shareapi_expire_after_n_days');
4646
$this->deleteServerConfig('core', 'link_defaultExpDays');
47-
$this->deleteServerConfig('sharebymail', 'enforcePasswordProtection');
4847
}
4948
}

build/integration/sharing_features/sharing-v1.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Feature: sharing
8484
Scenario: Creating a new mail share with password when password protection is enforced
8585
Given dummy mail server is listening
8686
And As an "admin"
87-
And parameter "enforcePasswordProtection" of app "sharebymail" is set to "yes"
87+
And parameter "shareapi_enforce_links_password" of app "core" is set to "yes"
8888
And user "user0" exists
8989
And As an "user0"
9090
When creating a share with

0 commit comments

Comments
 (0)