Skip to content

[stable-25.0.x] validate password - #6663

Merged
mahibi merged 14 commits into
stable-25.0.xfrom
backport/5955/stable-25.0.x
Sep 9, 2026
Merged

mahibi merged 14 commits into
stable-25.0.xfrom
backport/5955/stable-25.0.x

Conversation

@backportbot

@backportbot backportbot Bot commented Sep 9, 2026

Copy link
Copy Markdown

Backport of PR #5955

sowjanyakch and others added 14 commits September 9, 2026 09:06
Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

add password logic

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

handle states of password states

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

copy password

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

remove unused function and add copyright info

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

modify layout and import changes with the package name change

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

split GuestAccessPasswordDialog into two functions

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>

fix detekt

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
…o master

The PR was rebased onto a master that had since migrated
ConversationInfo to Jetpack Compose, which broke the build: the merge
resurrected pre-migration files (GuestAccessHelper.kt, its
DialogPasswordBinding/ActivityConversationInfoBinding dialog code) and
dropped an unrelated master fix (@serializable on
ProvisioningCapability).

- Delete GuestAccessHelper.kt (obsolete View/XML-binding helper no
  longer referenced since the Compose migration) and port its
  password-validation dialog into ConversationInfoActivity's Compose
  screen, replacing the stale XML showPasswordDialog().
- Remove dead, unrelated state left over in ConversationInfoViewModel
  from the old base branch (GetCapabilitiesStartState, CreateRoomUIState)
  and a duplicate ConversationCreationRepository import.
- Restore @serializable on ProvisioningCapability, lost in the merge.
- Fix ConversationCreationActivity's password-set dialog not dismissing
  after a successful save, and drop an unused ktlint-failing import and
  a misapplied @Suppress in ConversationCreationViewModel.

Assisted-by: Claude Code:claude-sonnet-5

Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
…e rebase

An earlier rebase of this branch reintroduced view-model state that master
had deleted during the ConversationInfo Compose migration: eight sealed
view-state classes and the LiveData exposing them, plus the profile view
state. Nothing in the app reads or writes any of it.

Keep only SecurePasswordViewState, which the password-policy validation
this branch adds actually uses.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
…read

PasswordCapability, PasswordPolicies and PasswordAccount were referenced
nowhere, and of PasswordPolicy only api.validate is ever read - the
minLength and enforce* mirrors of the server capability, the nested
policies object and api.generate were all dead.

Drop the three unused classes and the unread fields, and rename
Capabilities.passwordCapability to passwordPolicy so the property matches
both its type and the password_policy key it maps.

Also correct a typo in the SPDX contributor address on the two files that
carried it.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Three leftovers from the earlier rebase that have nothing to do with this
feature: a whitespace-only edit to ProvisioningCapability, a
TooGenericExceptionCaught suppression on updateConversationPreset (which
catches nothing), and a stray blank line in the change-password dialog.

Also drop the LongMethod suppression from validatePassword; the function
is thirteen lines and only the catch needs suppressing.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
ConversationInfoViewModel injected ConversationCreationRepository purely
to reach validatePassword, coupling the conversation-info feature to
conversation creation's data layer for an endpoint that belongs to
neither.

Password-policy validation is an account-level concern, so give it a
PasswordPolicyRepository of its own and let both view models depend on
that instead.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
…e view model

The composables dug the validation endpoint out of
currentUser.capabilities and handed it, and in the conversation-info case
the credentials too, back to a view model that already holds the user.

Give CapabilitiesUtil a getPasswordValidationUrl accessor next to the
other capability lookups and let each view model resolve both itself, so
validatePassword and securePassword now take only the password.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
…both screens

Conversation creation and conversation info each carried their own copy of
the feature: two UI state types (ValidPasswordUiState and
SecurePasswordViewState) with the same three cases, two view-model methods
with the same body, two reset methods, and two composables rendering the
same message with different colour rules - one of which decided validity
by string-comparing the rendered message against the localized "password
is secure" label.

Replace all of it with a PasswordValidationState both view models expose,
a PasswordPolicyValidator that owns the request and the state, and a
PasswordPolicyField that renders the input together with the server's
verdict. Validity now reads result.passed through isPasswordAccepted.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
…licy

Save was gated on a successful validation round-trip, so on a server that
does not advertise the password_policy capability no request was ever
made, the state stayed None and the button never enabled - the guest
password could not be set at all. Conversation info made it worse by
passing an empty string as the endpoint, firing a doomed request at the
base URL and settling on Error.

Report the missing capability as its own NoPolicy state, which counts as
accepted: without a policy to check against there is nothing to fail.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Every keystroke fired its own request, so typing a ten-character password
sent ten of them - each a prefix of the password - and whichever response
happened to land last decided whether Save was enabled, regardless of what
the field then held.

Debounce by half a second and cancel the request in flight, so only the
last password typed is sent and only its verdict can be written. Clear the
verdict as soon as the password changes, so the previous password's result
cannot stand in for one that has not been checked yet.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
The result was unwrapped with ocs?.data!!, so a well-formed response that
carried no result threw a NullPointerException into the surrounding catch
and surfaced as an error whose message was whatever the NPE said.

Unwrap it in the repository, which is the layer that knows the wire
format, and fail with a described IllegalStateException. Log what went
wrong on the way past, since the dialog only tells the user that
something did.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
The XML dialog the Compose one replaced set inputType="textPassword". Its
replacement set nothing, so the guest password was drawn in clear text and
went through the keyboard's suggestion and learning path. The two dialogs
on the conversation creation screen never masked it either.

Mask it in the shared field, and hold it in remember rather than
rememberSaveable so the plain text is not written into the saved instance
state bundle.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
CreatedConversation already flagged the clipboard entry with
EXTRA_IS_SENSITIVE and confirmed the copy with a toast, but the two copy
actions this branch adds did neither, so on Android 13 and later the
password appeared in the clipboard preview and nothing told the user it
had been copied.

Lift that private helper into ClipboardUtils and use it at all three
sites.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
…composition

Dialog visibility and the validation state were activity fields written
from an observer, while the rest of the screen already collects its state
inside setContent. Hold both in the composition, collecting the validator
with collectAsStateWithLifecycle like uiState next to it, so the dialog
stops outliving the composition that shows it.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
@backportbot
backportbot Bot requested a review from mahibi September 9, 2026 09:07
@backportbot backportbot Bot added 3. to review Waiting for reviews AI assisted labels Sep 9, 2026
@backportbot backportbot Bot added this to the 25.0.0 milestone Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

APK file: https://github.com/nextcloud/talk-android/actions/runs/34332886381/artifacts/10097454139
To test this change/fix you can simply download above APK file and install and test it in parallel to your existing Nextcloud app.
qrcode (please click on link to get QR code displayed)

@mahibi
mahibi merged commit 08dd69a into stable-25.0.x Sep 9, 2026
11 of 15 checks passed
@mahibi
mahibi deleted the backport/5955/stable-25.0.x branch September 9, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews AI assisted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants