From 5df0671ad95aae6e1f5f0e616f1dcb0bf05d23f7 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 ef7cd5655d7f0e8d4ccfdf853cb716c6f57845cb 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 5b8258cc3f87c65b85ec5c72a1247280a75d2af0 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 6038d6c9b1457af42a5daa888f7e999b04c5bbd1 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 1cd9698d750e671397842be7f1e3436b9f0d1ccd 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 }