Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/3934.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Validate public space addresses and room aliases length
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.matrix.android.sdk.api

/**
* This object define some global constants regarding the Matrix specification
*/
object MatrixConstants {
/**
* Max length for an alias. Room aliases MUST NOT exceed 255 bytes (including the # sigil and the domain).
* See [maxAliasLocalPartLength]
* Ref. https://matrix.org/docs/spec/appendices#room-aliases
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

*/
const val ALIAS_MAX_LENGTH = 255

fun maxAliasLocalPartLength(domain: String): Int {
return (ALIAS_MAX_LENGTH - 1 /* # sigil */ - 1 /* ':' */ - domain.length)
.coerceAtLeast(0)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,14 @@ object MatrixPatterns {
return order != null && order.length < 50 && order matches ORDER_STRING_REGEX
}

fun candidateAliasFromRoomName(name: String): String {
return Regex("\\s").replace(name.lowercase(), "_").let {
"[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
}
fun candidateAliasFromRoomName(roomName: String, domain: String): String {
return roomName.lowercase()
// Replace spaces by '_'
.let { Regex("\\s").replace(it, "_") }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: these comments could be replaced by extensions with the same name as the comment (and potentially be reused)

roomName
  .lowercase()
  .replaceSpacesWithUnderscore()
  .removeInvalidRoomNameChars()
  .limitLength(length = MatrixConstants.maxAliasLocalPartLength(domain))


fun String.replaceSpacesWithUnderscore() = Regex("\\s").replace(this, "_")
fun String.removeInvalidRoomNameChars() = "[^a-z0-9._%#@=+-]".toRegex().replace(this, "")
fun String.limitLength(length: Int) = this.substring(0, length)

I'm more in the self documenting code camp than adding comments to describe what the code does, where possible!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 done in f385e74

// Remove all invalid chars
.let { "[^a-z0-9._%#@=+-]".toRegex().replace(it, "") }
// limit length
.substring(0, MatrixConstants.maxAliasLocalPartLength(domain))
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package im.vector.app.features.form

import android.text.Editable
import android.text.InputFilter
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
Expand Down Expand Up @@ -77,6 +78,9 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
@EpoxyAttribute
var suffixText: String? = null

@EpoxyAttribute
var maxLength: Int? = null

private val onTextChangeListener = object : SimpleTextWatcher() {
override fun afterTextChanged(s: Editable) {
onTextChange?.invoke(s.toString())
Expand Down Expand Up @@ -109,6 +113,15 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
holder.textInputEditText.addTextChangedListenerOnce(onTextChangeListener)
holder.textInputEditText.setOnEditorActionListener(editorActionListener)
holder.textInputEditText.onFocusChangeListener = onFocusChangedListener

if (maxLength != null) {
holder.textInputEditText.filters = arrayOf(InputFilter.LengthFilter(maxLength!!))
holder.textInputLayout.isCounterEnabled = true
holder.textInputLayout.counterMaxLength = maxLength!!
} else {
holder.textInputEditText.filters = arrayOf()
holder.textInputLayout.isCounterEnabled = false
}
}

override fun shouldSaveViewState(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import im.vector.app.features.form.formEditTextItem
import im.vector.app.features.form.formEditableAvatarItem
import im.vector.app.features.form.formSubmitButtonItem
import im.vector.app.features.form.formSwitchItem
import org.matrix.android.sdk.api.MatrixConstants
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
Expand Down Expand Up @@ -141,6 +142,7 @@ class CreateRoomController @Inject constructor(
value(viewState.aliasLocalPart)
suffixText(":" + viewState.homeServerName)
prefixText("#")
maxLength(MatrixConstants.maxAliasLocalPartLength(viewState.homeServerName))
hint(host.stringProvider.getString(R.string.room_alias_address_hint))
errorMessage(
host.roomAliasErrorFormatter.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import timber.log.Timber
class CreateRoomViewModel @AssistedInject constructor(@Assisted private val initialState: CreateRoomViewState,
private val session: Session,
private val rawService: RawService,
private val vectorPreferences: VectorPreferences
vectorPreferences: VectorPreferences
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) {

@AssistedFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import im.vector.app.features.form.formEditTextItem
import im.vector.app.features.form.formEditableSquareAvatarItem
import im.vector.app.features.form.formMultiLineEditTextItem
import im.vector.app.features.form.formSubmitButtonItem
import org.matrix.android.sdk.api.MatrixConstants
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import javax.inject.Inject
Expand Down Expand Up @@ -81,6 +82,7 @@ class CreateSubSpaceController @Inject constructor(
hint(host.stringProvider.getString(R.string.create_space_alias_hint))
suffixText(":" + data.homeServerName)
prefixText("#")
maxLength(MatrixConstants.maxAliasLocalPartLength(data.homeServerName))
errorMessage(
host.roomAliasErrorFormatter.format(
(((data.asyncCreateRoomRequest as? Fail)?.error) as? CreateRoomFailure.AliasError)?.aliasError)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import im.vector.app.features.discovery.settingsInfoItem
import im.vector.app.features.form.formEditTextItem
import im.vector.app.features.form.formSwitchItem
import im.vector.app.features.roomdirectory.createroom.RoomAliasErrorFormatter
import org.matrix.android.sdk.api.MatrixConstants
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomType
Expand Down Expand Up @@ -174,6 +175,7 @@ class RoomAliasController @Inject constructor(
formEditTextItem {
id("publishManuallyEdit")
value(data.publishManuallyState.value)
maxLength(MatrixConstants.ALIAS_MAX_LENGTH)
hint(host.stringProvider.getString(R.string.room_alias_address_hint))
inputType(InputType.TYPE_CLASS_TEXT)
onTextChange { text ->
Expand Down Expand Up @@ -253,6 +255,7 @@ class RoomAliasController @Inject constructor(
value(data.newLocalAliasState.value)
suffixText(":" + data.homeServerName)
prefixText("#")
maxLength(MatrixConstants.maxAliasLocalPartLength(data.homeServerName))
hint(host.stringProvider.getString(R.string.room_alias_address_hint))
errorMessage(host.roomAliasErrorFormatter.format((data.newLocalAliasState.asyncRequest as? Fail)?.error as? RoomAliasError))
onTextChange { value ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ data class CreateSpaceState(
val step: Step = Step.ChooseType,
val spaceType: SpaceType? = null,
val spaceTopology: SpaceTopology? = null,
val homeServerName: String? = null,
val homeServerName: String = "",
val aliasLocalPart: String? = null,
val aliasManuallyModified: Boolean = false,
val aliasVerificationTask: Async<Boolean> = Uninitialized,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class CreateSpaceViewModel @AssistedInject constructor(
)
} else {
val tentativeAlias =
MatrixPatterns.candidateAliasFromRoomName(action.name)
MatrixPatterns.candidateAliasFromRoomName(action.name, homeServerName)
copy(
nameInlineError = null,
name = action.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import im.vector.app.features.form.formEditableSquareAvatarItem
import im.vector.app.features.form.formMultiLineEditTextItem
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.roomdirectory.createroom.RoomAliasErrorFormatter
import org.matrix.android.sdk.api.MatrixConstants
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
Expand Down Expand Up @@ -94,6 +95,7 @@ class SpaceDetailEpoxyController @Inject constructor(
hint(host.stringProvider.getString(R.string.create_space_alias_hint))
suffixText(":" + data.homeServerName)
prefixText("#")
maxLength(MatrixConstants.maxAliasLocalPartLength(data.homeServerName))
onFocusChange { hasFocus ->
host.aliasTextIsFocused = hasFocus
}
Expand Down