Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ package struct OnPremHeaderView: View {
+ Text(Image(systemName: "info.circle"))
.foregroundColor(.gray)
})
.accessibilityIdentifier("onPremInfoButton")
.multilineTextAlignment(.center)
.font(.textStyle(.h2))
.lineLimit(nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ public protocol AuthenticationAPI: Sendable {
func requestVerificationCode(for email: String) async throws

/// Get Activation key & code for email
/// - Parameter email: email of user
/// - Parameters:
/// - email: email of user
/// - basicAuth: basicAuth value
/// - Returns: Code & Key
#if DEBUG
func getActivationCode(forEmail email: String) async throws -> (code: String, key: String)
func getActivationCode(forEmail email: String, basicAuth: String) async throws -> (code: String, key: String)
#endif

/// Register Personal Account
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,12 @@ class AuthenticationAPIV0: AuthenticationAPI, VersionedAPI {
.parse(code: response.statusCode, data: data)
}

func getActivationCode(forEmail email: String) async throws -> (code: String, key: String) {
func getActivationCode(forEmail email: String, basicAuth: String) async throws -> (code: String, key: String) {
let path = "/i/users/activation-code?email=\(email)"
let auth = ProcessInfo.processInfo.environment["BASIC_AUTH"]!

let request = try URLRequestBuilder(path: path)
.withMethod(.get)
.addingHeader(field: "Authorization", value: "Basic \(auth)")
.addingHeader(field: "Authorization", value: "Basic \(basicAuth)")
.build()

let (data, response) = try await networkService.executeRequest(request)
Expand Down
16 changes: 16 additions & 0 deletions wire-ios/Tests/TestPlans/UITests.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@
{
"key" : "INBUCKET_PASSWORD",
"value" : "$(INBUCKET_PASSWORD)"
},
{
"key" : "ANTA_DEEPLINK_URL",
"value" : "$(ANTA_DEEPLINK_URL)"
},
{
"key" : "ANTA_INBUCKET_URL",
"value" : "$(ANTA_INBUCKET_URL)"
},
{
"key" : "BACKEND_URL_ANTA",
"value" : "$(BACKEND_URL_ANTA)"
},
{
"key" : "BASIC_AUTH_ANTA",
"value" : "$(BASIC_AUTH_ANTA)"
}
],
"targetForVariableExpansion" : {
Expand Down
5 changes: 3 additions & 2 deletions wire-ios/Wire-iOS/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -516,11 +516,12 @@ private extension AppDelegate {
}

private func fetchDefaultEnvironment() -> BackendEnvironment2 {
let env = ProcessInfo.processInfo.arguments.contains("--useEnvStaging") ? "staging" : "default"
guard let path = Bundle.backendBundle.path(
forResource: "default",
forResource: env,
ofType: "json"
) else {
fatalError("default.json missing in Backend.bundle")
fatalError("\(env).json missing in Backend.bundle")
}

do {
Expand Down
4 changes: 3 additions & 1 deletion wire-ios/WireUITests/ApiClients/InbucketClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@
//

import Foundation
import WireNetwork

enum InbucketClient {

static func getVerificationCode(email: String) async throws -> String {
let envVariables = try EnvironmentVariables()

var verificationCode = ""
let requestUrl = envVariables.inbucketURL.appending(path: "api/v1/mailbox/\(email)/latest")
let baseURL: URL = envVariables.inbucketURL
let requestUrl = baseURL.appending(path: "api/v1/mailbox/\(email)/latest")

var request = URLRequest(url: requestUrl)
request.httpMethod = "GET"
Expand Down
47 changes: 47 additions & 0 deletions wire-ios/WireUITests/Helper/BackendContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import Foundation
import WireNetwork

public enum BackendContext {
static var current: BackendTarget = .staging

static var backendEnvironment: BackendEnvironment {
switch current {
case .staging:
.staging
case .anta:
.anta
}
}
}

public enum BackendTarget {
case staging
case anta

var domainInfo: String {
switch self {
case .staging:
"staging.zinfra.io"
case .anta:
"anta.wire.link"
}
}
}
65 changes: 59 additions & 6 deletions wire-ios/WireUITests/Helper/EnvironmentVariables.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ struct EnvironmentVariables {
case missingInbucketURL
case missingInbucketUsername
case missingInbucketPassword
case missingDeepLinkURL
}

var backendURL: URL
var inbucketURL: URL
var inbucketUsername: String
var inbucketPassword: String
private let stagingBackendURL: URL
private let antaBackendURL: URL

private let stagingInbucketURL: URL
private let antaInbucketURL: URL

let antaDeepLinkURL: URL

let inbucketUsername: String
let inbucketPassword: String

init() throws {
guard let backendURLString = ProcessInfo.processInfo.environment["BACKEND_URL"],
Expand All @@ -50,9 +57,55 @@ struct EnvironmentVariables {
throw Failure.missingInbucketUsername
}

self.backendURL = URL(string: "https://\(backendURLString)")!
self.inbucketURL = URL(string: "https://\(inbucketHostname)")!
guard let antaDeeplinkURL = ProcessInfo.processInfo.environment["ANTA_DEEPLINK_URL"],
!antaDeeplinkURL.isEmpty else {
throw Failure.missingDeepLinkURL
}

guard let antaInbucketURL = ProcessInfo.processInfo.environment["ANTA_INBUCKET_URL"],
!antaInbucketURL.isEmpty else {
throw Failure.missingInbucketURL
}

guard let backendURLAntaString = ProcessInfo.processInfo.environment["BACKEND_URL_ANTA"],
!backendURLAntaString.isEmpty else {
throw Failure.missingBackendURL
}

self.stagingBackendURL = URL(string: "https://\(backendURLString)")!
self.stagingInbucketURL = URL(string: "https://\(inbucketHostname)")!
self.inbucketUsername = inbucketUsername
self.inbucketPassword = inbucketPassword
self.antaDeepLinkURL = URL(string: "https://\(antaDeeplinkURL)")!
self.antaInbucketURL = URL(string: "https://\(antaInbucketURL)")!
self.antaBackendURL = URL(string: "https://\(backendURLAntaString)")!
}

var inbucketURL: URL {
switch BackendContext.current {
case .anta:
antaInbucketURL
case .staging:
stagingInbucketURL
}
}

var backendURL: URL {
switch BackendContext.current {
case .anta:
antaBackendURL
case .staging:
stagingBackendURL
}
}

func deepLinkURL(for target: BackendTarget) -> URL {
switch target {
case .anta:
antaDeepLinkURL
case .staging:
fatalError("Not implemented yet")
}
}

}
40 changes: 36 additions & 4 deletions wire-ios/WireUITests/Helper/UserHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ class UserHelper {
private let authenticationManager = MockAuthManager()

init(apiVersion: APIVersion = .v8) {

self.createdUsers = []
self.networkStack = NetworkStack(
backendEnvironment: .staging,
backendEnvironment: BackendContext.backendEnvironment,
minTLSVersion: .v1_2,
cookieEncryptionKey: Data(),
authenticationManager: authenticationManager
Expand All @@ -55,6 +56,22 @@ class UserHelper {
self.conversationsAPI = ConversationsAPIBuilder(apiService: networkStack.apiService).makeAPI(for: apiVersion)
}

func basicAuth(_ backend: BackendTarget = BackendContext.current) -> String {
switch backend {
case .staging:
guard let auth = ProcessInfo.processInfo.environment["BASIC_AUTH"] else {
fatalError("Missing BASIC_AUTH environment variable")
}
return auth

case .anta:
guard let auth = ProcessInfo.processInfo.environment["BASIC_AUTH_ANTA"] else {
fatalError("Missing BASIC_AUTH_ANTA environment variable")
}
return auth
}
}

func createPersonalUser() async throws -> UserInfo {
let user = UserGenerator.generateUniqueUserInfo()

Expand All @@ -67,7 +84,10 @@ class UserHelper {
cookieStorage.cookies = cookies

// Get activation code
let (activationCode, activationKey) = try await BackendClient.getActivationCode(email: user.email)
let (activationCode, activationKey) = try await authenticationAPI.getActivationCode(
forEmail: user.email,
basicAuth: basicAuth()
)

// Activate user
try await authenticationAPI.activateUser(email: user.email, key: activationKey, code: activationCode)
Expand Down Expand Up @@ -153,7 +173,10 @@ class UserHelper {
}

func fetchAccessToken(email: String, password: String) async throws -> String {
let (activationCode, activationKey) = try await authenticationAPI.getActivationCode(forEmail: email)
let (activationCode, activationKey) = try await authenticationAPI.getActivationCode(
forEmail: email,
basicAuth: basicAuth()
)

try await authenticationAPI.activateUser(email: email, key: activationKey, code: activationCode)

Expand Down Expand Up @@ -258,15 +281,24 @@ class UserHelper {
}
}

private extension BackendEnvironment {
extension BackendEnvironment {
static let backendURL = "https://\(ProcessInfo.processInfo.environment["BACKEND_URL"]!)"
static let backendURLAnta = "https://\(ProcessInfo.processInfo.environment["BACKEND_URL_ANTA"]!)"
static let staging = BackendEnvironment(
url: URL(string: backendURL)!,
webSocketURL: URL(string: backendURL)!,
blacklistURL: URL(string: backendURL)!,
pinnedKeys: [],
proxySettings: nil
)

static let anta = BackendEnvironment(
url: URL(string: backendURLAnta)!,
webSocketURL: URL(string: backendURLAnta)!,
blacklistURL: URL(string: backendURLAnta)!,
pinnedKeys: [],
proxySettings: nil
)
}

enum FilterConversationsByCriteria {
Expand Down
48 changes: 45 additions & 3 deletions wire-ios/WireUITests/Helper/WireUITestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ class WireUITestCase: XCTestCase {

let launchArguments = [
"-resetData",
"--BackendEnvironmentTypeOverrideKey=staging",
"--persist-backend-type",
"--useEnvStaging",
"--preferred-api-version=8"
]

Expand All @@ -42,7 +41,7 @@ class WireUITestCase: XCTestCase {
app.launchArguments = launchArguments
app.setDeveloperFlags([
.useWireAuthentication: true,
.multibackend: false
.multibackend: true
])
app.launch()

Expand All @@ -55,4 +54,47 @@ class WireUITestCase: XCTestCase {
await userHelper.deleteCreatedUsers()
}

func setCustomBackend(byDeeplink deeplink: URL, timeout: TimeInterval = 5, domainInfo: String) {
XCTContext.runActivity(named: "Set custom backend via deeplink") { _ in
let deeplinkFullURL = "wire://access/?config=\(deeplink)"
guard let url = URL(string: deeplinkFullURL) else {
XCTFail("Invalid deeplink: \(deeplinkFullURL)")
return
}

XCUIDevice.shared.system.open(url)

let alert = springboard.alerts.firstMatch
if alert.waitForExistence(timeout: 2) {
let openButton = springboard.alerts.buttons
.matching(NSPredicate(format: "label BEGINSWITH[c] 'Open'"))
.firstMatch
if openButton.waitForExistence(timeout: 1) {
openButton.tap()
}
}

XCTAssertTrue(
app.wait(for: .runningForeground, timeout: timeout),
"App did not return to foreground after opening deeplink"
)
guard let welcomePage = try? SetCustomBackendPage().tapOnProceedButton() else {
XCTFail("Failed to proceed to set custom backend")
return
}
let labeltext = welcomePage.setBackendLabel.label
XCTAssertTrue(
labeltext.contains(domainInfo),
"Expected domain missing from \(labeltext)"
)
}
}

func switchBackend(target: BackendTarget) throws {

let deeplink = try EnvironmentVariables().deepLinkURL(for: target)
setCustomBackend(byDeeplink: deeplink, domainInfo: target.domainInfo)
// need to change for Inbucket
BackendContext.current = target
}
}
Loading
Loading