Skip to content

Commit

Permalink
fixup! fixup! Sharing link & mail parity
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Nov 25, 2020
1 parent 2dbe01b commit bba5d88
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 47 deletions.
7 changes: 4 additions & 3 deletions apps/files_sharing/src/components/SharingEntryLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ import Actions from '@nextcloud/vue/dist/Components/Actions'
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'

import GeneratePassword from '../utils/GeneratePassword'
import Share from '../models/Share'
import SharesMixin from '../mixins/SharesMixin'

Expand Down Expand Up @@ -460,7 +461,7 @@ export default {
},
async set(enabled) {
// TODO: directly save after generation to make sure the share is always protected
Vue.set(this.share, 'password', enabled ? await this.generatePassword() : '')
Vue.set(this.share, 'password', enabled ? await GeneratePassword() : '')
Vue.set(this.share, 'newPassword', this.share.password)
},
},
Expand Down Expand Up @@ -618,7 +619,7 @@ export default {
shareDefaults.expiration = this.config.defaultExpirationDateString
}
if (this.config.enableLinkPasswordByDefault) {
shareDefaults.password = await this.generatePassword()
shareDefaults.password = await GeneratePassword()
}

// do not push yet if we need a password or an expiration date
Expand All @@ -639,7 +640,7 @@ export default {
// ELSE, show the pending popovermenu
// if password enforced, pre-fill with random one
if (this.config.enforcePasswordForPublicLink) {
shareDefaults.password = await this.generatePassword()
shareDefaults.password = await GeneratePassword()
}

// create share & close menu
Expand Down
40 changes: 34 additions & 6 deletions apps/files_sharing/src/components/SharingInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import debounce from 'debounce'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'

import Config from '../services/ConfigService'
import GeneratePassword from '../utils/GeneratePassword'
import Share from '../models/Share'
import ShareRequests from '../mixins/ShareRequests'
import ShareTypes from '../mixins/ShareTypes'
Expand Down Expand Up @@ -412,9 +413,6 @@ export default {
return true
}

// TODO: reset the search string when done
// https://github.com/shentao/vue-multiselect/issues/633

// handle externalResults from OCA.Sharing.ShareSearch
if (value.handler) {
const share = await value.handler(this)
Expand All @@ -423,25 +421,55 @@ export default {
}

this.loading = true
console.debug('Adding a new share from the input for', value)
try {
let password = null

if (this.config.enforcePasswordForPublicLink
&& value.shareType === this.SHARE_TYPES.SHARE_TYPE_EMAIL) {
password = await GeneratePassword()
}

const path = (this.fileInfo.path + '/' + this.fileInfo.name).replace('//', '/')
const share = await this.createShare({
path,
shareType: value.shareType,
shareWith: value.shareWith,
password,
permissions: this.fileInfo.sharePermissions & OC.getCapabilities().files_sharing.default_permissions,
})
this.$emit('add:share', share)

this.getRecommendations()
// If we had a password, we need to show it to the user as it was generated
if (password) {
share.newPassword = password
// Wait for the newly added share
const component = await new Promise(resolve => {
this.$emit('add:share', share, resolve)
})

// open the menu on the
// freshly created share component
component.open = true
} else {
// Else we just add it normally
this.$emit('add:share', share)
}

// reset the search string when done
// FIXME: https://github.com/shentao/vue-multiselect/issues/633
if (this.$refs.multiselect?.$refs?.VueMultiselect?.search) {
this.$refs.multiselect.$refs.VueMultiselect.search = ''
}

} catch (response) {
await this.getRecommendations()
} catch (error) {
// focus back if any error
const input = this.$refs.multiselect.$el.querySelector('input')
if (input) {
input.focus()
}
this.query = value.shareWith
console.error('Error while adding new share', error)
} finally {
this.loading = false
}
Expand Down
31 changes: 0 additions & 31 deletions apps/files_sharing/src/mixins/SharesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
*
*/

import axios from '@nextcloud/axios'
import PQueue from 'p-queue'
import debounce from 'debounce'

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

const passwordSet = 'abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789'

export default {
mixins: [SharesRequests, ShareTypes],

Expand Down Expand Up @@ -326,33 +323,5 @@ export default {
return (this.dateTomorrow && dateMoment.isBefore(this.dateTomorrow, 'day'))
|| (this.dateMaxEnforced && dateMoment.isSameOrAfter(this.dateMaxEnforced, 'day'))
},

/**
* Generate a valid policy password or
* request a valid password if password_policy
* is enabled
*
* @returns {string} a valid password
*/
async generatePassword() {
// password policy is enabled, let's request a pass
if (this.config.passwordPolicy.api && this.config.passwordPolicy.api.generate) {
try {
const request = await axios.get(this.config.passwordPolicy.api.generate)
if (request.data.ocs.data.password) {
return request.data.ocs.data.password
}
} catch (error) {
console.info('Error generating password from password_policy', error)
}
}

// generate password of 10 length based on passwordSet
return Array(10).fill(0)
.reduce((prev, curr) => {
prev += passwordSet.charAt(Math.floor(Math.random() * passwordSet.length))
return prev
}, '')
},
},
}
56 changes: 56 additions & 0 deletions apps/files_sharing/src/utils/GeneratePassword.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

/**
* @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import axios from '@nextcloud/axios'
import Config from '../services/ConfigService'

const config = new Config()
const passwordSet = 'abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789'

/**
* Generate a valid policy password or
* request a valid password if password_policy
* is enabled
*
* @returns {string} a valid password
*/
export default async function() {
// password policy is enabled, let's request a pass
if (config.passwordPolicy.api && config.passwordPolicy.api.generate) {
try {
const request = await axios.get(config.passwordPolicy.api.generate)
if (request.data.ocs.data.password) {
return request.data.ocs.data.password
}
} catch (error) {
console.info('Error generating password from password_policy', error)
}
}

// generate password of 10 length based on passwordSet
return Array(10).fill(0)
.reduce((prev, curr) => {
prev += passwordSet.charAt(Math.floor(Math.random() * passwordSet.length))
return prev
}, '')
}
35 changes: 32 additions & 3 deletions apps/files_sharing/src/views/SharingTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@

<!-- link shares list -->
<SharingLinkList v-if="!loading"
ref="linkShareList"
:can-reshare="canReshare"
:file-info="fileInfo"
:shares="linkShares" />

<!-- other shares list -->
<SharingList v-if="!loading"
ref="shareList"
:shares="shares"
:file-info="fileInfo" />

Expand Down Expand Up @@ -295,18 +297,45 @@ export default {
},

/**
* Insert share at top of arrays
* Add a new share into the shares list
* and return the newly created share component
*
* @param {Share} share the share to insert
* @param {Share} share the share to add to the array
* @param {Function} resolve a function to run after the share is added and its component initialized
*/
addShare(share) {
addShare(share, resolve) {
// only catching share type MAIL as link shares are added differently
// meaning: not from the ShareInput
if (share.type === this.SHARE_TYPES.SHARE_TYPE_EMAIL) {
this.linkShares.unshift(share)
} else {
this.shares.unshift(share)
}
this.awaitForShare(share, resolve)
},

/**
* Await for next tick and render after the list updated
* Then resolve with the matched vue component of the
* provided share object
*
* @param {Share} share newly created share
* @param {Function} resolve a function to execute after
*/
awaitForShare(share, resolve) {
let listComponent = this.$refs.shareList
// Only mail shares comes from the input, link shares
// are managed internally in the SharingLinkList component
if (share.type === this.SHARE_TYPES.SHARE_TYPE_EMAIL) {
listComponent = this.$refs.linkShareList
}

this.$nextTick(() => {
const newShare = listComponent.$children.find(component => component.share === share)
if (newShare) {
resolve(newShare)
}
})
},
},
}
Expand Down
4 changes: 2 additions & 2 deletions apps/settings/templates/settings/admin/sharing.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
value="1" <?php if ($_['allowLinks'] === 'yes') {
print_unescaped('checked="checked"');
} ?> />
<label for="allowLinks"><?php p($l->t('Allow users to share via link'));?></label><br/>
<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/>
</p>

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

</p>
<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
Expand Down
1 change: 0 additions & 1 deletion build/integration/features/bootstrap/SharingContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,5 @@ protected function resetAppConfigs() {
$this->deleteServerConfig('core', 'shareapi_default_expire_date');
$this->deleteServerConfig('core', 'shareapi_expire_after_n_days');
$this->deleteServerConfig('core', 'link_defaultExpDays');
$this->deleteServerConfig('sharebymail', 'enforcePasswordProtection');
}
}
2 changes: 1 addition & 1 deletion build/integration/sharing_features/sharing-v1.feature
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Feature: sharing
Scenario: Creating a new mail share with password when password protection is enforced
Given dummy mail server is listening
And As an "admin"
And parameter "enforcePasswordProtection" of app "sharebymail" is set to "yes"
And parameter "shareapi_enforce_links_password" of app "core" is set to "yes"
And user "user0" exists
And As an "user0"
When creating a share with
Expand Down

0 comments on commit bba5d88

Please sign in to comment.