Skip to content

Commit 3c392aa

Browse files
susnuxbackportbot[bot]
authored andcommitted
fix(files_sharing): restore state when updating share failed
We need to save the previous state - here the password - so that if the update fails we can revert the shown state. This happens e.g. if you have the password policy app and try to add an unsecure password. To reproduce (with password policy): 1. Create new link share 2. enable password protection 3. use insecure password like `1234` 4. save share Now you see that the update failed, but the password protection is still enabled. This happened because `password` and `newPassword` were misused. `password` was already set when `newPassword` was not saved so we could not know to what we need to reset when the update failed. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de> [skip ci]
1 parent f4b61b3 commit 3c392aa

File tree

3 files changed

+37
-27
lines changed

3 files changed

+37
-27
lines changed

apps/files_sharing/src/components/SharingEntryLink.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@
6767
{{ config.enforcePasswordForPublicLink ? t('files_sharing', 'Password protection (enforced)') : t('files_sharing', 'Password protection') }}
6868
</NcActionCheckbox>
6969

70-
<NcActionInput v-if="pendingEnforcedPassword || share.password"
70+
<NcActionInput v-if="pendingEnforcedPassword || isPasswordProtected"
7171
class="share-link-password"
7272
:label="t('files_sharing', 'Enter a password')"
73-
:value.sync="share.password"
73+
:value.sync="share.newPassword"
7474
:disabled="saving"
7575
:required="config.enableLinkPasswordByDefault || config.enforcePasswordForPublicLink"
7676
:minlength="isPasswordPolicyEnabled && config.passwordPolicy.minLength"
@@ -108,7 +108,8 @@
108108
</template>
109109
</NcActionInput>
110110

111-
<NcActionButton @click.prevent.stop="onNewLinkShare(true)">
111+
<NcActionButton :disabled="pendingEnforcedPassword && !share.newPassword"
112+
@click.prevent.stop="onNewLinkShare(true)">
112113
<template #icon>
113114
<CheckIcon :size="20" />
114115
</template>
@@ -630,6 +631,7 @@ export default {
630631
631632
// create share & close menu
632633
const share = new Share(shareDefaults)
634+
share.newPassword = share.password
633635
const component = await new Promise(resolve => {
634636
this.$emit('add:share', share, resolve)
635637
})
@@ -822,7 +824,7 @@ export default {
822824
*/
823825
onPasswordSubmit() {
824826
if (this.hasUnsavedPassword) {
825-
this.share.password = this.share.newPassword.trim()
827+
this.share.newPassword = this.share.newPassword.trim()
826828
this.queueUpdate('password')
827829
}
828830
},
@@ -837,7 +839,7 @@ export default {
837839
*/
838840
onPasswordProtectedByTalkChange() {
839841
if (this.hasUnsavedPassword) {
840-
this.share.password = this.share.newPassword.trim()
842+
this.share.newPassword = this.share.newPassword.trim()
841843
}
842844
843845
this.queueUpdate('sendPasswordByTalk', 'password')

apps/files_sharing/src/mixins/SharesMixin.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,12 @@ export default {
165165
isPasswordProtected: {
166166
get() {
167167
return this.config.enforcePasswordForPublicLink
168-
|| !!this.share.password
168+
|| this.share.password !== ''
169+
|| this.share.newPassword !== undefined
169170
},
170171
async set(enabled) {
171172
if (enabled) {
172-
this.share.password = await GeneratePassword(true)
173-
this.$set(this.share, 'newPassword', this.share.password)
173+
this.$set(this.share, 'newPassword', await GeneratePassword(true))
174174
} else {
175175
this.share.password = ''
176176
this.$delete(this.share, 'newPassword')
@@ -272,7 +272,7 @@ export default {
272272
this.loading = true
273273
this.open = false
274274
await this.deleteShare(this.share.id)
275-
console.debug('Share deleted', this.share.id)
275+
logger.debug('Share deleted', { shareId: this.share.id })
276276
const message = this.share.itemType === 'file'
277277
? t('files_sharing', 'File "{path}" has been unshared', { path: this.share.path })
278278
: t('files_sharing', 'Folder "{path}" has been unshared', { path: this.share.path })
@@ -303,39 +303,49 @@ export default {
303303
const properties = {}
304304
// force value to string because that is what our
305305
// share api controller accepts
306-
propertyNames.forEach(name => {
306+
for (const name of propertyNames) {
307+
if (name === 'password') {
308+
properties[name] = this.share.newPassword ?? this.share.password
309+
continue
310+
}
311+
307312
if (this.share[name] === null || this.share[name] === undefined) {
308313
properties[name] = ''
309314
} else if ((typeof this.share[name]) === 'object') {
310315
properties[name] = JSON.stringify(this.share[name])
311316
} else {
312317
properties[name] = this.share[name].toString()
313318
}
314-
})
319+
}
315320

316321
return this.updateQueue.add(async () => {
317322
this.saving = true
318323
this.errors = {}
319324
try {
320325
const updatedShare = await this.updateShare(this.share.id, properties)
321326

322-
if (propertyNames.indexOf('password') >= 0) {
327+
if (propertyNames.includes('password')) {
323328
// reset password state after sync
329+
this.share.password = this.share.newPassword ?? ''
324330
this.$delete(this.share, 'newPassword')
325331

326332
// updates password expiration time after sync
327333
this.share.passwordExpirationTime = updatedShare.password_expiration_time
328334
}
329335

330336
// clear any previous errors
331-
this.$delete(this.errors, propertyNames[0])
337+
for (const property of propertyNames) {
338+
this.$delete(this.errors, property)
339+
}
332340
showSuccess(this.updateSuccessMessage(propertyNames))
333341
} catch (error) {
334342
logger.error('Could not update share', { error, share: this.share, propertyNames })
335343

336344
const { message } = error
337345
if (message && message !== '') {
338-
this.onSyncError(propertyNames[0], message)
346+
for (const property of propertyNames) {
347+
this.onSyncError(property, message)
348+
}
339349
showError(message)
340350
} else {
341351
// We do not have information what happened, but we should still inform the user
@@ -384,6 +394,13 @@ export default {
384394
* @param {string} message the error message
385395
*/
386396
onSyncError(property, message) {
397+
if (property === 'password' && this.share.newPassword) {
398+
if (this.share.newPassword === this.share.password) {
399+
this.share.password = ''
400+
}
401+
this.$delete(this.share, 'newPassword')
402+
}
403+
387404
// re-open menu if closed
388405
this.open = true
389406
switch (property) {

apps/files_sharing/src/views/SharingDetailsTab.vue

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
</NcCheckboxRadioSwitch>
115115
<NcPasswordField v-if="isPasswordProtected"
116116
autocomplete="new-password"
117-
:value="hasUnsavedPassword ? share.newPassword : ''"
117+
:value="share.newPassword ?? ''"
118118
:error="passwordError"
119119
:helper-text="errorPasswordLabel || passwordHint"
120120
:required="isPasswordEnforced && isNewShare"
@@ -803,7 +803,6 @@ export default {
803803
if (this.isNewShare) {
804804
if ((this.config.enableLinkPasswordByDefault || this.isPasswordEnforced) && this.isPublicShare) {
805805
this.$set(this.share, 'newPassword', await GeneratePassword(true))
806-
this.$set(this.share, 'password', this.share.newPassword)
807806
this.advancedSectionAccordionExpanded = true
808807
}
809808
/* Set default expiration dates if configured */
@@ -901,10 +900,7 @@ export default {
901900
this.share.note = ''
902901
}
903902
if (this.isPasswordProtected) {
904-
if (this.hasUnsavedPassword && this.isValidShareAttribute(this.share.newPassword)) {
905-
this.share.password = this.share.newPassword
906-
this.$delete(this.share, 'newPassword')
907-
} else if (this.isPasswordEnforced && this.isNewShare && !this.isValidShareAttribute(this.share.password)) {
903+
if (this.isPasswordEnforced && this.isNewShare && !this.isValidShareAttribute(this.share.password)) {
908904
this.passwordError = true
909905
}
910906
} else {
@@ -928,7 +924,7 @@ export default {
928924
incomingShare.expireDate = this.hasExpirationDate ? this.share.expireDate : ''
929925
930926
if (this.isPasswordProtected) {
931-
incomingShare.password = this.share.password
927+
incomingShare.password = this.share.newPassword
932928
}
933929
934930
let share
@@ -960,9 +956,8 @@ export default {
960956
this.$emit('add:share', this.share)
961957
} else {
962958
// Let's update after creation as some attrs are only available after creation
959+
await this.queueUpdate(...permissionsAndAttributes)
963960
this.$emit('update:share', this.share)
964-
emit('update:share', this.share)
965-
this.queueUpdate(...permissionsAndAttributes)
966961
}
967962
968963
await this.getNode()
@@ -1039,10 +1034,6 @@ export default {
10391034
* "sendPasswordByTalk".
10401035
*/
10411036
onPasswordProtectedByTalkChange() {
1042-
if (this.hasUnsavedPassword) {
1043-
this.share.password = this.share.newPassword.trim()
1044-
}
1045-
10461037
this.queueUpdate('sendPasswordByTalk', 'password')
10471038
},
10481039
isValidShareAttribute(value) {

0 commit comments

Comments
 (0)