element-ios/Riot/Modules/UserInteractiveAuthentication/UserInteractiveAuthenticationService.swift
ismailgulek 79b8f80ce9
Release 1.9.12 (#7081)
* Update voice broadcast tiles UI (#6965)

* Translated using Weblate (German)

Currently translated at 100.0% (2307 of 2307 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* speeding the animation a bit

* tests and identifier improvements

* fix

* changelog

* removed unused code

* Avoid unnecessary send state request (#6970)

* comment

* Curate MXCrypto protocol methods

* Add voice broadcast initial state in bubble data (#6972)

- Add voice broadcast initial state in bubble data
- Remove the local record after sending

* Voice Broadcast: log and block unexpected state change

* Sing out bottom bar

* new line

* Enable WYSIWYG plain text support

* Remove change on Apple swift-collections revision

* removed RiotSettings a non RiotSwiftUI reference from the ViewState code

* fixed a test

* Complete MXCryptoV2 implementation

* Multi session logut

* Switch the CI to code 14 and the iOS 14 simulator, fix UI tests

* Fixes #6987 - Prevent ZXing from unnecessarily requesting camera access

* Fixes #6988 - Prevent actor switching when tearing down the rendezvous

* Separator fix

* Removed warnings

* add Z-Labs tag or rich text editor and update to the new label naming

* changelog

* Hide old sessions list when the new dm is enabled

* Add changelog.d file

* Sing out filtering

* Avoid simultaneous state changes (#6986)

* Improve kebab menu in UserSessionOverview

* Add UI tests

* Add changelog.d file

* No customization for emptycell (#7000)

* PSG-976 Exclude current session from security recommendations and other sessions

* Padding fix

* Fixed unit tests

* Add empty onLearnMoreAction closure

* Add InfoView skeleton

* Add UserSessionOverviewViewBindings

* Style info view

* Add bottom sheet modifier

* Localise content

* Add inactive sessions copy

* Fix bug in InlineTextButton

* Improve UserSessionCardView

* Add “learn more” button in UserOtherSessions

* Show bottom sheet in user other sessions

* Show rename info alert

* Refine UX

* Add iOS 15- fallback

* Refine InfoView

* Add UI tests

* Improve UserOtherSessionsUITests

* Improve InlineTextButton API

* Add changelod.d file

* Fix failing UTs

* Hide keyboard in UserSessionName

* Add .viewSessionInfo view action

* Voice Broadcast - BugFix - send the last chunk (#7002)

* Voice Broadcast - BugFix - send the last chunk with the right sequence number

- we reset now and teardown the service only after the last chunk is sent

* updated package + tests

* change log

* Bug Fix : Crash if the room has avatar and voice broadcast tiles

* Add MVVM-C for InfoSheet

* improving UI tests for slow CI

* removing comment

* test improvements for slow ci

* Show bottom sheet in other sessions screen

* Show bottom sheet in rename session screen

* Delete bottom sheet modifier

* Show rename sheet

* UI and unit tests

* Refresh fix

* Changelog

* Add InfoSheet SwiftUI preview

* simplify the test to make it pass on the CI

* Fix memory leak

* Cleanup UI tests

* improving tests for the CI

* Fixed IRC-style message and commands support in Rich text editor

* tests updated for the CI

* test improvements

* removing a test that can't pass on the CI due to its speed

* Changelog

* CryptoV2 changes

* Display crypto version

* Voice broadcast - Disable the sleep mode during the recording until we are able to handle it

Currently go to "sleep mode" pauses the voice broadcast recording

* Add issue automation for the VoIP team

* Renamed sign out to logout

* Renamed sign out to logout

* Renamed sign out to logout

* Sign out of all other sessions

* Fix typo in issue automation

* Fixed unit tests

* Translations update from Weblate (#7017)

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (German)

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nl/

Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com>
Co-authored-by: Priit Jõerüüt <riot@joeruut.com>
Co-authored-by: Vri <element@vrifox.cc>
Co-authored-by: Johan Smits <johan@smitsmail.net>

* Prepare for new sprint

* Prepare for new sprint

* Threads: added support to read receipts (MSC3771)

- Update after review

* Threads: added support to notifications count (MSC3773)

* Update RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/UI/UserOtherSessionsUITests.swift

Co-authored-by: aringenbach <80891108+aringenbach@users.noreply.github.com>

* Update RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/UI/UserOtherSessionsUITests.swift

Co-authored-by: aringenbach <80891108+aringenbach@users.noreply.github.com>

* Comment fix

* the test may fail on CI without blocking the task/check

* tests may fail on CI

* test improvement

* test may fail on CI

* Hide push toggles for http pushers when there is no server support

* changelog

* Code review fixes

* Threads: added support to read receipts (MSC3771)

- Update after review

* Synchronise composer and toolbar resizing animation duration

* Add kResizeComposerAnimationDuration constant description

* fix for 6946

* Threads: add support to labs flag for read receipts

* Cleanup

* Code review fixes, created DestructiveButton

* Update issue automation

Stop using deprecated ProjectNext API in favour of the new ProjectV2 one

* Update PR automation

Stop using deprecated ProjectNext API in favour of the new ProjectV2 one

* Code review fixes

* Map location info

* Map location info

* Add location feature in UserSessionsOverview

* Add “show location” feature in other sessions list

* Add “show location“ feature in session overview

* Fix Package.resolved

* Cleanup merge leftovers

* Cleanup code

* Cleanup

* Add show/hide ip persistency

* Add location info in UserOtherSessions

* Refine settings logic

* Mock settings in UserSessionsOverviewViewModel

* Add settings service in UserOtherSessionsViewModel

* Inject setting service in UserSessionOverviewViewModel

* Add changelog.d file

* Fix UTs

* Cleanup merge leftovers

* Add animations

* Fix failing test

* Amend title font

* Amend copies

* Device Manager: Session list item is not tappable everywhere

* changelog

* Threads notification count in main timeline including un participated threads

* Changed title and body

* Removed "Do not ask again" button

* Remove indication about plain text mode coming soon

* Prevent `Unable to activate constraint with anchors .. because they have no common ancestor.` crashes. Only link toasts to the top safe area instead of the navigation controller

* Revert "Replace attributed string height calculation with a more reliable implementation"

This reverts commit 81773cd1e5.

* Revert "Fix timeline items text height calculation"

This reverts commit 8f9eddee50.

* Revert "Fixes vector-im/element-ios/issues/6441 - Incorrect timeline item text height calculation (#6679)"

This reverts commit 405c2d8e32.

* Fixes vector-im/element-ios/issues/6441 - Incorrect timeline item text height calculation

* Prepare for new sprint

* Refine bottom sheet layout

* updated pod

* changelog

* Switch to using an API key for interactions with AppStoreConnect while on CI; update fastlane and dependencies

* Rich-text editor: Fix text formatting enabled inconsistent state

* Labs: Rich-text editor - Fix text formatting switch losing the current content of the composer

* Re-order View computed properties and move to private mark

* Add intrinsic sized bottom sheet

* Snooze controller

* Changelog

* Fix composer view model tests

* Rich-text editor: enable translations between Markdown and HTML when toggling text formatting

* Force a layout on the room bubble cell messageTextView to get a correct frame

* Move Move UserAgentParserTests

* Add UserSessionDetailsUITests

* Improve UserSessionNameUITests

* Cleanup tests

* Improve UserSessionNameViewModelTests

* Test empty state for UserOtherSessions

* Fix typo

* Cleanup unused code

* Add changelog.d file

* Threads: removed "unread_thread_notifications" from sync filters for server that doesn't support MSC3773

* Remove 10s wait on failed initial sync

* Threads: removed "unread_thread_notifications" from sync filters for server that doesn't support MSC3773

- Update after review

* Revert "Device Manager: Session list item is not tappable everywhere"

This reverts commit e6367cba4c.

* Fixup session list item is not tappable everywhere

* Fix accessibility id in UserOtherSessions

* Poll not usable after logging out and back in

* Changelog

* Removed init

* voice dictation now works

* plain text

* Add voice broadcast slider (#7010)

* Display number of unread messages above threads button

* Translations update from Weblate (#7080)

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nl/

* Translated using Weblate (German)

Currently translated at 100.0% (2311 of 2311 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nl/

* Translated using Weblate (German)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Albanian)

Currently translated at 99.6% (2303 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sq/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2312 of 2312 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/

* Translated using Weblate (German)

Currently translated at 100.0% (2313 of 2313 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2313 of 2313 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2313 of 2313 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nl/

* Translated using Weblate (German)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2315 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/

* Translated using Weblate (Albanian)

Currently translated at 99.5% (2305 of 2315 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sq/

* Translated using Weblate (German)

Currently translated at 100.0% (2317 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Japanese)

Currently translated at 66.2% (1534 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ja/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (2317 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2317 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2317 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2317 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (2317 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/

* Translated using Weblate (Japanese)

Currently translated at 66.2% (1534 of 2317 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ja/

* Translated using Weblate (German)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (German)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/

* Translated using Weblate (French)

Currently translated at 97.6% (2272 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/fr/

* Translated using Weblate (Russian)

Currently translated at 80.5% (1873 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/

* Translated using Weblate (Russian)

Currently translated at 80.7% (1879 of 2326 strings)

Translation: Element iOS/Element iOS
Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/

Co-authored-by: Roel ter Maat <roel.termaat@nedap.com>
Co-authored-by: Vri <element@vrifox.cc>
Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com>
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Co-authored-by: Priit Jõerüüt <riot@joeruut.com>
Co-authored-by: Linerly <linerly@protonmail.com>
Co-authored-by: Jozef Gaal <preklady@mayday.sk>
Co-authored-by: random <dictionary@tutamail.com>
Co-authored-by: Szimszon <github@oregpreshaz.eu>
Co-authored-by: Suguru Hirahara <ovestekona@protonmail.com>
Co-authored-by: Thibault Martin <mail@thibaultmart.in>
Co-authored-by: Platon Terekhov <ockenfels_vevent@aleeas.com>

* changelog.d: Upgrade MatrixSDK version ([v0.24.3](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.3)).

* version++

Co-authored-by: giomfo <gforet@matrix.org>
Co-authored-by: Yoan Pintas <y.pintas@gmail.com>
Co-authored-by: Vri <element@vrifox.cc>
Co-authored-by: Anderas <andyuhnak@gmail.com>
Co-authored-by: Mauro Romito <mauro.romito@element.io>
Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>
Co-authored-by: Giom Foret <giom@matrix.org>
Co-authored-by: Aleksandrs Proskurins <paleksandrs@gmail.com>
Co-authored-by: aringenbach <arnaudr@element.io>
Co-authored-by: manuroe <manuroe@users.noreply.github.com>
Co-authored-by: David Langley <langley.dave@gmail.com>
Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
Co-authored-by: Alfonso Grillo <alfogrillo@gmail.com>
Co-authored-by: Alfonso Grillo <alfogrillo@element.io>
Co-authored-by: Kat Gerasimova <ekaterinag@element.io>
Co-authored-by: Element Translate Bot <admin@riot.im>
Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com>
Co-authored-by: Priit Jõerüüt <riot@joeruut.com>
Co-authored-by: Johan Smits <johan@smitsmail.net>
Co-authored-by: gulekismail <ismailgulek0@gmail.com>
Co-authored-by: Gil Eluard <gile@element.io>
Co-authored-by: Aleksandrs Proskurins <aleksandrsp@element.io>
Co-authored-by: aringenbach <80891108+aringenbach@users.noreply.github.com>
Co-authored-by: Stefan Ceriu <stefan.ceriu@gmail.com>
Co-authored-by: Roel ter Maat <roel.termaat@nedap.com>
Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Co-authored-by: Linerly <linerly@protonmail.com>
Co-authored-by: Jozef Gaal <preklady@mayday.sk>
Co-authored-by: random <dictionary@tutamail.com>
Co-authored-by: Szimszon <github@oregpreshaz.eu>
Co-authored-by: Suguru Hirahara <ovestekona@protonmail.com>
Co-authored-by: Thibault Martin <mail@thibaultmart.in>
Co-authored-by: Platon Terekhov <ockenfels_vevent@aleeas.com>
2022-11-15 16:40:36 +03:00

292 lines
12 KiB
Swift

//
// Copyright 2020 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
/// UserInteractiveAuthenticationService errors
enum UserInteractiveAuthenticationServiceError: Int, Error {
case flowNotSupported = 0
}
extension UserInteractiveAuthenticationServiceError: CustomNSError {
static let errorDomain = "UserInteractiveAuthenticationServiceErrorDomain"
var errorCode: Int {
return self.rawValue
}
var errorUserInfo: [String: Any] {
let userInfo: [String: Any]
switch self {
case .flowNotSupported:
userInfo = [NSLocalizedDescriptionKey: VectorL10n.authenticatedSessionFlowNotSupported]
}
return userInfo
}
}
/// AuthenticatedEndpointStatus indicates the success status after checking if an API endpoint needs authentication
enum AuthenticatedEndpointStatus {
case authenticationNotNeeded
case authenticationNeeded(_ authenticationSession: MXAuthenticationSession)
}
/// UserInteractiveAuthenticationService enables to check if an API endpoint needs authentication.
@objcMembers
final class UserInteractiveAuthenticationService: NSObject {
// MARK: - Constants
// MARK: - Properties
// MARK: Private
private let session: MXSession
// MARK: Public
// MARK: - Setup
init(session: MXSession) {
self.session = session
super.init()
}
// MARK: - Public
/// Check if API endpoint requires authentication and get authentication session if needed
/// - Parameters:
/// - request: Authenticated API endpoint request.
/// - completion: The closure executed the operation completes. AuthenticatedEndpointStatus indicates if authentication is needed or not.
/// - Returns: A `MXHTTPOperation` instance.
@discardableResult
func authenticatedEndpointStatus(for request: AuthenticatedEndpointRequest, completion: @escaping (Result<AuthenticatedEndpointStatus, Error>) -> Void) -> MXHTTPOperation {
return self.authenticationSession(with: request) { (authenticationSession) in
let status: AuthenticatedEndpointStatus
if let authenticationSession = authenticationSession {
status = .authenticationNeeded(authenticationSession)
} else {
status = .authenticationNotNeeded
}
completion(.success(status))
} failure: { (error) in
completion(.failure(error))
}
}
/// Check if API endpoint requires authentication.
/// - Parameters:
/// - request: Authenticated API endpoint request.
/// - completion: The closure executed the operation completes.
/// - Returns: A `MXHTTPOperation` instance.
@discardableResult
func canAuthenticate(with request: AuthenticatedEndpointRequest, completion: @escaping (Result<Bool, Error>) -> Void) -> MXHTTPOperation {
return self.authenticatedEndpointStatus(for: request) { (result) in
switch result {
case .success(let authenticationSessionResult):
let canAuthenticate: Bool
switch authenticationSessionResult {
case .authenticationNotNeeded:
canAuthenticate = true
case .authenticationNeeded(let authenticationSession):
canAuthenticate = self.canAuthenticate(with: authenticationSession)
}
completion(.success(canAuthenticate))
case .failure(let error):
completion(.failure(error))
}
}
}
/// Check if API endpoint requires authentication.
/// This method is compatible with Objective-C
/// - Parameters:
/// - request: Authenticated API endpoint request.
/// - success: The closure executed the operation succeed. Get an MXAuthenticationSession if authentication is required or nil if there is no authentication needed.
/// - failure: The closure executed the operation fails.
/// - Returns: A `MXHTTPOperation` instance.
@discardableResult
func authenticationSession(with request: AuthenticatedEndpointRequest,
success: @escaping (MXAuthenticationSession?) -> Void,
failure: @escaping (Error) -> Void) -> MXHTTPOperation {
// Get the authentication flow required for this API
return self.session.matrixRestClient.authSessionForRequest(withMethod: request.httpMethod, path: request.path, parameters: request.params, success: { [weak self] (authenticationSession) in
guard let self = self else {
return
}
if let authenticationSession = authenticationSession {
if let flows = authenticationSession.flows {
// Check if a supported flow exists
if self.isThereAKnownFlow(inFlows: flows) {
success(authenticationSession)
} else if self.firstUncompletedStageAuthenticationFallbackURL(for: authenticationSession) != nil {
success(authenticationSession)
} else {
// Flow not supported
failure(UserInteractiveAuthenticationServiceError.flowNotSupported)
}
}
} else {
// No need to authenticate
success(nil)
}
}, failure: { (error) in
guard let error = error else {
return
}
failure(error)
})
}
/// Check if a request error ask for User-Interactive Authentication.
/// - Parameter error: A request error.
/// - Returns: An AuthenticatedEndpointStatus if the error can indicates authentication status or nil for other errors
func getAuthenticatedEndpointStatus(fromRequestError error: Error) -> AuthenticatedEndpointStatus? {
guard let urlResponse = MXHTTPOperation.urlResponse(fromError: error) else {
return nil
}
var status: AuthenticatedEndpointStatus?
switch urlResponse.statusCode {
case 400:
status = .authenticationNotNeeded
case 401:
let nsError = error as NSError
if let jsonResponse = nsError.userInfo[MXHTTPClientErrorResponseDataKey] as? [AnyHashable: Any], let authenticationSession = MXAuthenticationSession(fromJSON: jsonResponse) {
status = .authenticationNeeded(authenticationSession)
}
default:
break
}
return status
}
/// Check if a request error ask for User-Interactive Authentication.
/// Note: ObjC compatible.
/// - Parameters:
/// - error: A request error.
/// - success: The closure executed the operation succeed. Get an MXAuthenticationSession if authentication is required or nil if there is no authentication needed.
/// - failure: The closure executed the operation fails.
func authenticationSession(fromRequestError error: Error, success: @escaping (MXAuthenticationSession?) -> Void, failure: @escaping (Error) -> Void) {
if let authenticatedEndpointStatus = self.getAuthenticatedEndpointStatus(fromRequestError: error) {
if case .authenticationNeeded(let authenticationSession) = authenticatedEndpointStatus {
success(authenticationSession)
} else {
success(nil)
}
} else {
failure(error)
}
}
/// Get the authentication fallback URL for the first uncompleted stage found.
/// - Parameter authenticationSession: An authentication session for a given request.
/// - Returns: The fallback URL for the first uncompleted stage found.
func firstUncompletedStageAuthenticationFallbackURL(for authenticationSession: MXAuthenticationSession) -> URL? {
guard let sessiondId = authenticationSession.session, let firstUncompletedStageIdentifier = self.firstUncompletedFlowIdentifier(in: authenticationSession) else {
return nil
}
return self.authenticationFallbackURL(for: firstUncompletedStageIdentifier, sessionId: sessiondId)
}
/// Build UIA fallback authentication URL for a given stage (https://matrix.org/docs/spec/client_server/latest#fallback)
/// - Parameters:
/// - flowIdentifier: The login type to authenticate with.
/// - sessionId: The the ID of the session given by the homeserver.
/// - Returns: a `MXHTTPOperation` instance.
func authenticationFallbackURL(for flowIdentifier: String, sessionId: String) -> URL? {
guard let homeserverStringURL = self.session.matrixRestClient.credentials.homeServer, let homeserverURL = URL(string: homeserverStringURL) else {
return nil
}
let fallbackPath = "\(kMXAPIPrefixPathR0)/auth/\(flowIdentifier)/fallback/web?session=\(sessionId)"
return URL(string: fallbackPath, relativeTo: homeserverURL)
}
/// Find the first uncompleted login flow stage in a MXauthenticationSession.
/// - Parameter authenticationSession: An authentication session for a given request.
/// - Returns: Uncompleted login flow stage identifier.
func firstUncompletedFlowIdentifier(in authenticationSession: MXAuthenticationSession) -> String? {
let completedStages = authenticationSession.completed ?? []
guard let flows = authenticationSession.flows else {
return nil
}
// Remove nil values
let allNonNullStages = flows.compactMap { $0.stages }
// Make a flat array of all stages
let allStages: [String] = allNonNullStages.flatMap { $0 }
// Keep stages order
let uncompletedStages = NSMutableOrderedSet(array: allStages)
// Keep uncompleted stages
let completedStagesSet = NSOrderedSet(array: completedStages)
uncompletedStages.minus(completedStagesSet)
let firstUncompletedFlowIdentifier = uncompletedStages.firstObject as? String
return firstUncompletedFlowIdentifier
}
/// Check if an array of login flows contains "m.login.password" flow.
func hasPasswordFlow(inFlows flows: [MXLoginFlow]) -> Bool {
for flow in flows {
if flow.type == MXLoginFlowType.password.identifier || flow.stages.contains(MXLoginFlowType.password.identifier) {
return true
}
}
return false
}
// MARK: - Private
private func isThereAKnownFlow(inFlows flows: [MXLoginFlow]) -> Bool {
return self.hasPasswordFlow(inFlows: flows)
}
private func canAuthenticate(with authenticationSession: MXAuthenticationSession) -> Bool {
if self.isThereAKnownFlow(inFlows: authenticationSession.flows) {
return true
}
if self.firstUncompletedStageAuthenticationFallbackURL(for: authenticationSession) != nil {
return true
}
return false
}
}