From 4c7f2b62183eb27a6984ca9e3026d5b6dc9a8061 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:18:01 -0300 Subject: [PATCH 1/5] fix: use identifier from entity when identify param not provided - Keep identify parameter optional for cases like email where user may want to send code to alternative address - Use getIdentifierValue() as fallback when identify is not provided - This ensures token methods (SMS, WhatsApp, etc.) use the registered phone number from the entity Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/SignFileService.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Service/SignFileService.php b/lib/Service/SignFileService.php index 15657609bc..b9b5f59e89 100644 --- a/lib/Service/SignFileService.php +++ b/lib/Service/SignFileService.php @@ -612,7 +612,8 @@ public function requestCode( continue; } /** @var IToken $signatureMethod */ - $signatureMethod->requestCode($identify, $identifyMethod->getEntity()->getIdentifierKey()); + $identifier = $identify ?: $identifyMethod->getEntity()->getIdentifierValue(); + $signatureMethod->requestCode($identifier, $identifyMethod->getEntity()->getIdentifierKey()); return; } throw new LibresignException($this->l10n->t('Sending authorization code not enabled.')); From 45214e4e319785e4f205b6147a6cad860db16062 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:19:31 -0300 Subject: [PATCH 2/5] fix: update TwoFactorGateway API calls for v3 - Use factory->get() instead of factory->getGateway() - Use gateway->isComplete() instead of gateway->getConfig()->isComplete() - Compatible with TwoFactorGateway 3.0.0-dev.0 Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/IdentifyMethod/SignatureMethod/TokenService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Service/IdentifyMethod/SignatureMethod/TokenService.php b/lib/Service/IdentifyMethod/SignatureMethod/TokenService.php index 98bf1f1658..91f901f612 100644 --- a/lib/Service/IdentifyMethod/SignatureMethod/TokenService.php +++ b/lib/Service/IdentifyMethod/SignatureMethod/TokenService.php @@ -47,8 +47,8 @@ private function getGateway(string $gatewayName) { throw new LibresignException('App Two-Factor Gateway is not installed.'); } - $gateway = $factory->getGateway($gatewayName); - if (!$gateway->getConfig()->isComplete()) { + $gateway = $factory->get($gatewayName); + if (!$gateway->isComplete()) { throw new OCSForbiddenException($this->l10n->t('Gateway %s not configured on Two-Factor Gateway.', $gatewayName)); } return $gateway; From 0da4d8af5922ddfabfd69b26e8bafea1a6aa8b5a Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:20:14 -0300 Subject: [PATCH 3/5] refactor: rename ModalSMSManager to ModalTokenManager Rename component to reflect its broader use for all token-based authentication methods (SMS, WhatsApp, Signal, Telegram, XMPP) instead of just SMS. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- ...alSMSManager.vue => ModalTokenManager.vue} | 89 ++++++++++++------- 1 file changed, 58 insertions(+), 31 deletions(-) rename src/views/SignPDF/_partials/{ModalSMSManager.vue => ModalTokenManager.vue} (61%) diff --git a/src/views/SignPDF/_partials/ModalSMSManager.vue b/src/views/SignPDF/_partials/ModalTokenManager.vue similarity index 61% rename from src/views/SignPDF/_partials/ModalSMSManager.vue rename to src/views/SignPDF/_partials/ModalTokenManager.vue index 3c5ecf7689..6bc2e435fe 100644 --- a/src/views/SignPDF/_partials/ModalSMSManager.vue +++ b/src/views/SignPDF/_partials/ModalTokenManager.vue @@ -4,15 +4,14 @@ --> @@ -61,6 +54,7 @@ import NcTextField from '@nextcloud/vue/components/NcTextField' import { settingsService } from '../../../domains/settings/index.js' import { useSignStore } from '../../../store/sign.js' +import { useSignMethodsStore } from '../../../store/signMethods.js' const sanitizeNumber = val => { val = val.replace(/\D/g, '') @@ -68,7 +62,7 @@ const sanitizeNumber = val => { } export default { - name: 'ModalSMSManager', + name: 'ModalTokenManager', components: { NcDialog, NcLoadingIcon, @@ -78,19 +72,34 @@ export default { props: { phoneNumber: { type: String, - required: true, + required: false, + default: '', }, }, setup() { const signStore = useSignStore() - return { signStore } + const signMethodsStore = useSignMethodsStore() + return { signStore, signMethodsStore } + }, + data() { + return { + token: '', + newPhoneNumber: this.phoneNumber || '', + tokenRequested: false, + loading: false, + } + }, + computed: { + activeTokenMethod() { + const tokenMethods = ['sms', 'whatsapp', 'signal', 'telegram', 'xmpp'] + return tokenMethods.find(method => + Object.hasOwn(this.signMethodsStore.settings, method) + ) || 'sms' + }, + activeIdentifyMethod() { + return this.activeTokenMethod + }, }, - data: () => ({ - token: '', - newPhoneNumber: this.phoneNumber, - tokenRequested: false, - loading: false, - }), methods: { async saveNumber() { this.loading = true @@ -123,22 +132,40 @@ export default { await this.$nextTick() try { + const params = { + identifyMethod: this.activeIdentifyMethod, + signMethod: this.activeTokenMethod, + } + if (this.signStore.document.fileId) { - const { data } = await axios.post(generateOcsUrl('/apps/libresign/api/v1/sign/file_id/{fileId}/code', { - fileId: this.signStore.document.fileId, - })) + const { data } = await axios.post( + generateOcsUrl('/apps/libresign/api/v1/sign/file_id/{fileId}/code', { + fileId: this.signStore.document.fileId, + }), + params + ) showSuccess(data.ocs.data.message) } else { - const signer = this.signStore.document.signers.find(row => row.me) || {} - const { data } = await axios.post(generateOcsUrl('/apps/libresign/api/v1/sign/uuid/{fileId}/code', { + const signer = this.signStore.document.signers.find(row => row.me) || {} + const { data } = await axios.post( + generateOcsUrl('/apps/libresign/api/v1/sign/uuid/{uuid}/code', { uuid: signer.sign_uuid, - })) + }), + params + ) showSuccess(data.ocs.data.message) } - this.tokenRequested = true - } catch (err) { - showError(err.response.data.ocs.data.message) - } finally { + this.tokenRequested = true + } catch (err) { + const errorMessage = err.response?.data?.ocs?.data?.message || err.response?.data?.message || err.message + + if (errorMessage && errorMessage.includes('Invalid configuration')) { + const method = this.activeTokenMethod.charAt(0).toUpperCase() + this.activeTokenMethod.slice(1) + showError(t('libresign', '{method} is not configured. Please contact your administrator.', { method })) + } else { + showError(errorMessage) + } + } finally { this.loading = false } }, From ff3afdd31c232e76215e9794a66dd7c150e45246 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:28:10 -0300 Subject: [PATCH 4/5] feat: add needTokenCode method to support all token-based authentication Adds needTokenCode() method that checks for any active token-based authentication method (SMS, WhatsApp, Signal, Telegram, XMPP) needing a verification code. This replaces the SMS-only needSmsCode() check and enables proper modal display for all token-based methods. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/store/signMethods.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/store/signMethods.js b/src/store/signMethods.js index 979c745aff..18b2694bb9 100644 --- a/src/store/signMethods.js +++ b/src/store/signMethods.js @@ -77,6 +77,12 @@ export const useSignMethodsStore = defineStore('signMethods', { return Object.hasOwn(this.settings, 'sms') && this.settings.sms.needCode }, + needTokenCode() { + const tokenMethods = ['sms', 'whatsapp', 'signal', 'telegram', 'xmpp'] + return tokenMethods.some(method => + Object.hasOwn(this.settings, method) && this.settings[method].needCode + ) + }, needCertificate() { return this.certificateEngine === 'none' && !this.hasSignatureFile() }, From 1ab2aac154ab97fec7be3549565b0d9c70b6d8ac Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:28:21 -0300 Subject: [PATCH 5/5] feat: integrate ModalTokenManager for all token-based methods Updates Sign.vue to use the renamed ModalTokenManager component and needTokenCode() method. Changes signWithSMSCode to signWithTokenCode with automatic detection of active token method (SMS, WhatsApp, Signal, Telegram, or XMPP), enabling proper authentication for all token-based signature methods. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/views/SignPDF/_partials/Sign.vue | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/views/SignPDF/_partials/Sign.vue b/src/views/SignPDF/_partials/Sign.vue index 3b91f01c38..572bf622c8 100644 --- a/src/views/SignPDF/_partials/Sign.vue +++ b/src/views/SignPDF/_partials/Sign.vue @@ -130,9 +130,9 @@ :useModal="true" :errors="errors" @certificate:uploaded="onSignatureFileCreated" /> - + Object.hasOwn(this.signMethodsStore.settings, method) + ) || 'sms' + await this.signDocument({ - method: 'sms', + method: activeMethod, token, }) }, @@ -395,7 +400,7 @@ export default { this.showModalAndResetErrors('createSignature') return } - if (this.signMethodsStore.needSmsCode()) { + if (this.signMethodsStore.needTokenCode()) { this.showModalAndResetErrors('sms') return }