From f7e86fe73f43e702cefb997d04fd34336858a2fc Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Wed, 9 Nov 2022 14:20:19 +0300 Subject: [PATCH] Regex: Fixes `Permalink` action on timeline (#303) --- .../Sources/Other/Extensions/String.swift | 8 --- .../Sources/Other/MatrixEntityRegex.swift | 4 +- .../LoginScreen/LoginCoordinator.swift | 2 +- .../Sources/MatrixEntityRegexTests.swift | 67 +++++++++++++++++++ changelog.d/pr-303.bugfix | 1 + 5 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 UnitTests/Sources/MatrixEntityRegexTests.swift create mode 100644 changelog.d/pr-303.bugfix diff --git a/ElementX/Sources/Other/Extensions/String.swift b/ElementX/Sources/Other/Extensions/String.swift index 6c26d2c03..bd02b3bbc 100644 --- a/ElementX/Sources/Other/Extensions/String.swift +++ b/ElementX/Sources/Other/Extensions/String.swift @@ -31,14 +31,6 @@ extension String { return string } - - /// Whether or not the string is a Matrix user ID. - var isMatrixUserID: Bool { - let range = NSRange(location: 0, length: count) - - let detector = try? NSRegularExpression(pattern: MatrixEntityRegex.userId.rawValue, options: .caseInsensitive) - return detector?.numberOfMatches(in: self, range: range) ?? 0 == 1 - } /// Calculates a numeric hash same as Element Web /// See original function here https://github.com/matrix-org/matrix-react-sdk/blob/321dd49db4fbe360fc2ff109ac117305c955b061/src/utils/FormattingUtils.js#L47 diff --git a/ElementX/Sources/Other/MatrixEntityRegex.swift b/ElementX/Sources/Other/MatrixEntityRegex.swift index 46ac9a6c8..9b66cef87 100644 --- a/ElementX/Sources/Other/MatrixEntityRegex.swift +++ b/ElementX/Sources/Other/MatrixEntityRegex.swift @@ -35,7 +35,7 @@ enum MatrixEntityRegex: String { case .roomId: return "![A-Z0-9]+:" + MatrixEntityRegex.homeserver.rawValue case .eventId: - return "\\$[A-Z0-9\\/+]+" + return "\\$[a-z0-9_\\-\\/]+(:[a-z0-9]+\\.[a-z0-9]+)?" } } @@ -49,7 +49,7 @@ enum MatrixEntityRegex: String { // swiftlint:enable force_try static func isMatrixHomeserver(_ homeserver: String) -> Bool { - guard let match = userIdentifierRegex.firstMatch(in: homeserver, range: .init(location: 0, length: homeserver.count)) else { + guard let match = homeserverRegex.firstMatch(in: homeserver, range: .init(location: 0, length: homeserver.count)) else { return false } diff --git a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift index f93a181ef..062583851 100644 --- a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift @@ -184,7 +184,7 @@ final class LoginCoordinator: Coordinator, Presentable { /// Parses the specified username and looks up the homeserver when a Matrix ID is entered. private func parseUsername(_ username: String) { - guard username.isMatrixUserID else { return } + guard MatrixEntityRegex.isMatrixUserIdentifier(username) else { return } let homeserverDomain = String(username.split(separator: ":")[1]) diff --git a/UnitTests/Sources/MatrixEntityRegexTests.swift b/UnitTests/Sources/MatrixEntityRegexTests.swift new file mode 100644 index 000000000..0f1b52101 --- /dev/null +++ b/UnitTests/Sources/MatrixEntityRegexTests.swift @@ -0,0 +1,67 @@ +// +// Copyright 2022 New Vector Ltd +// +// 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. +// + +import Foundation + +import XCTest + +@testable import ElementX + +class MatrixEntityRegexTests: XCTestCase { + func testHomeserver() { + XCTAssertTrue(MatrixEntityRegex.isMatrixHomeserver("matrix.org")) + XCTAssertTrue(MatrixEntityRegex.isMatrixHomeserver("MATRIX.ORG")) + XCTAssertFalse(MatrixEntityRegex.isMatrixHomeserver("matrix?.org")) + } + + func testUserId() { + XCTAssertTrue(MatrixEntityRegex.isMatrixUserIdentifier("@username:example.com")) + XCTAssertFalse(MatrixEntityRegex.isMatrixUserIdentifier("username:example.com")) + XCTAssertFalse(MatrixEntityRegex.isMatrixUserIdentifier("@username.example.com")) + } + + func testRoomAlias() { + XCTAssertTrue(MatrixEntityRegex.isMatrixRoomAlias("#element-ios:matrix.org")) + XCTAssertFalse(MatrixEntityRegex.isMatrixRoomAlias("element-ios:matrix.org")) + XCTAssertFalse(MatrixEntityRegex.isMatrixRoomAlias("#element-ios.matrix.org")) + } + + func testRoomId() { + XCTAssertTrue(MatrixEntityRegex.isMatrixRoomIdentifier("!pMBteVpcoJRdCJxDmn:matrix.org")) + XCTAssertFalse(MatrixEntityRegex.isMatrixRoomIdentifier("pMBteVpcoJRdCJxDmn:matrix.org")) + XCTAssertFalse(MatrixEntityRegex.isMatrixRoomIdentifier("!pMBteVpcoJRdCJxDmn.matrix.org")) + } + + func testEventId() { + // room version 1 + XCTAssertTrue(MatrixEntityRegex.isMatrixEventIdentifier("$h29iv0s8:example.com")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$h29iv0s8:example.")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$h29iv0s8:")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$h29iv0s8?")) + + // room version 3 + XCTAssertTrue(MatrixEntityRegex.isMatrixEventIdentifier("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk.")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk:")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk?")) + + // room version 4 + XCTAssertTrue(MatrixEntityRegex.isMatrixEventIdentifier("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg.")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg:")) + XCTAssertFalse(MatrixEntityRegex.isMatrixEventIdentifier("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg?")) + } +} diff --git a/changelog.d/pr-303.bugfix b/changelog.d/pr-303.bugfix new file mode 100644 index 000000000..66c9fcbf5 --- /dev/null +++ b/changelog.d/pr-303.bugfix @@ -0,0 +1 @@ +Fix identifier regexes: Fixes permalink action on timeline.