pEpForiOS/UI/Settings/Setting/AccountSettings/ViewModel/AccountSettingsViewModel.swift
author Dirk Zimmermann <dz@pep.security>
Wed, 24 Apr 2019 12:43:18 +0200
branchIOS-1542
changeset 8358 e663f13a57cc
parent 8357 d848452952a6
child 8360 5fc3e8979152
permissions -rw-r--r--
IOS-1542 Implement verification.
andreas@3697
     1
//
andreas@3697
     2
//  AccountSettingsViewModel.swift
andreas@3697
     3
//  pEpForiOS
andreas@3697
     4
//
andreas@3697
     5
//  Created by Xavier Algarra on 13/06/2017.
andreas@3697
     6
//  Copyright © 2017 p≡p Security S.A. All rights reserved.
andreas@3697
     7
//
andreas@3697
     8
andreas@3697
     9
import Foundation
andreas@3697
    10
import MessageModel
xavier@7644
    11
import pEpIOSToolbox
andreas@3697
    12
dz@8358
    13
import PantomimeFramework
dz@8358
    14
andreas@3697
    15
public class AccountSettingsViewModel {
andreas@3697
    16
    public struct ServerViewModel {
andreas@3697
    17
        var address: String?
andreas@3697
    18
        var port: String?
andreas@3697
    19
        var transport: String?
andreas@3697
    20
    }
andreas@3697
    21
andreas@3697
    22
    public struct SecurityViewModel {
andreas@3697
    23
        var options = Server.Transport.toArray()
andreas@3697
    24
        var size : Int {
andreas@3697
    25
            get {
andreas@3697
    26
                return options.count
andreas@3697
    27
            }
andreas@3697
    28
        }
andreas@3697
    29
andreas@3697
    30
        subscript(option: Int) -> String {
andreas@3697
    31
            get {
andreas@3697
    32
                return options[option].asString()
andreas@3697
    33
            }
andreas@3697
    34
        }
andreas@3697
    35
    }
andreas@3697
    36
andreas@3697
    37
    private let headers = [
andreas@3697
    38
        NSLocalizedString("Account", comment: "Account settings"),
andreas@3697
    39
        NSLocalizedString("IMAP Settings", comment: "Account settings title IMAP"),
andreas@3697
    40
        NSLocalizedString("SMTP Settings", comment: "Account settings title SMTP")
andreas@3697
    41
    ]
andreas@3697
    42
    private var controlWord = "noRealPassword"
andreas@3697
    43
andreas@3697
    44
    public let svm = SecurityViewModel()
dirk@4019
    45
    public let isOAuth2: Bool
andreas@3697
    46
andreas@3697
    47
    public init(account: Account) {
dz@8354
    48
        // We are using a copy of the data here.
dz@8354
    49
        // The outside world must not know changed settings until they have been verified.
dirk@4019
    50
        isOAuth2 = account.server(with: .imap)?.authMethod == AuthMethod.saslXoauth2.rawValue
dz@8354
    51
        self.email = account.user.address
dz@8354
    52
        self.loginName = account.server(with: .imap)?.credentials.loginName ?? ""
dz@8354
    53
        self.name = account.user.userName ?? ""
andreas@3697
    54
dz@8354
    55
        if let server = account.smtpServer {
dz@8354
    56
            self.smtpServer = ServerViewModel(
dz@8354
    57
                address: server.address,
dz@8354
    58
                port: "\(server.port)",
dz@8354
    59
                transport: server.transport?.asString())
dz@8354
    60
        } else {
dz@8354
    61
            self.smtpServer = ServerViewModel()
dz@8354
    62
        }
dz@8354
    63
dz@8354
    64
        if let server = account.imapServer {
dz@8354
    65
            self.imapServer = ServerViewModel(
dz@8354
    66
                address: server.address,
dz@8354
    67
                port: "\(server.port)",
dz@8354
    68
                transport: server.transport?.asString())
dz@8354
    69
        } else {
dz@8354
    70
            self.imapServer = ServerViewModel()
andreas@3697
    71
        }
andreas@3697
    72
    }
andreas@3697
    73
dz@8356
    74
    private(set) var email: String
dz@8354
    75
dz@8353
    76
    /// - Note: The email model is based on the assumption that imap.loginName == smtp.loginName
dz@8356
    77
    private(set) var loginName: String
andreas@3697
    78
dz@8356
    79
    private(set) var name: String
andreas@3697
    80
dz@8356
    81
    private(set) var smtpServer: ServerViewModel
andreas@3697
    82
dz@8356
    83
    private(set) var imapServer: ServerViewModel
andreas@3697
    84
agp@8142
    85
    var verificationService: VerificationService?
andreas@3697
    86
    weak var delegate: AccountVerificationResultDelegate?
andreas@3697
    87
dz@8357
    88
    /// Holding both the data of the current account in verification,
dz@8357
    89
    /// and also the implementation of the verification.
dz@8357
    90
    private var verifiableAccount: VerifiableAccountProtocol?
dz@8357
    91
dz@8354
    92
    // Currently we assume imap and smtp servers exist already (update).
dz@8354
    93
    // If we run into problems here modify to updateOrCreate.
andreas@3697
    94
    func update(loginName: String, name: String, password: String? = nil, imap: ServerViewModel,
andreas@3697
    95
                smtp: ServerViewModel) {
dz@8358
    96
        var theVerifier = verifiableAccount ?? VerifiableAccount()
dz@8358
    97
        verifiableAccount = theVerifier
dz@8358
    98
dz@8358
    99
        theVerifier.address = email
dz@8358
   100
        theVerifier.userName = name
dz@8358
   101
        theVerifier.password = password
dz@8358
   102
        if loginName != email {
dz@8358
   103
            theVerifier.loginName = loginName
dz@8358
   104
        }
dz@8358
   105
dz@8358
   106
        if isOAuth2 {
dz@8358
   107
            // TODO: Set correct auth method, etc.
dz@8358
   108
        }
dz@8358
   109
dz@8358
   110
        theVerifier.serverIMAP = imap.address
dz@8358
   111
        if let portString = imap.port, let port = UInt16(portString) {
dz@8358
   112
            theVerifier.portIMAP = port
dz@8358
   113
        }
dz@8358
   114
        let _ = Server.Transport(fromString: imap.transport)
dz@8358
   115
        //  TODO: Set the correct transport
dz@8358
   116
dz@8354
   117
        // TODO: Implement
dz@8354
   118
        /*
andreas@3697
   119
        guard let serverImap = account.imapServer,
andreas@3697
   120
            let serverSmtp = account.smtpServer else {
dz@7517
   121
                Logger.frontendLogger.errorAndCrash("Account misses imap or smtp server.")
andreas@3697
   122
                return
andreas@3697
   123
        }
andreas@3697
   124
        let pass : String?
andreas@3697
   125
        if let p = password {
andreas@3697
   126
            pass = p
andreas@3697
   127
        } else {
andreas@3697
   128
            pass = serverImap.credentials.password
andreas@3697
   129
        }
andreas@3697
   130
        guard let editedServerImap = server(from: imap, serverType: .imap,
andreas@3697
   131
                                            loginName: loginName,
andreas@3697
   132
                                            password: pass,
andreas@3697
   133
                                            key: serverImap.credentials.key),
andreas@3697
   134
            let editedServerSmtp = server(from: smtp,
andreas@3697
   135
                                          serverType: .smtp,
andreas@3697
   136
                                          loginName: loginName,
andreas@3697
   137
                                          password: pass,
andreas@3697
   138
                                          key: serverSmtp.credentials.key)
andreas@3697
   139
            else {
dz@7517
   140
                Logger.frontendLogger.errorAndCrash("Invalid input.")
andreas@3697
   141
                return
andreas@3697
   142
        }
andreas@3697
   143
andreas@3697
   144
        serverImap.updateValues(with: editedServerImap)
andreas@3697
   145
        serverSmtp.updateValues(with: editedServerSmtp)
andreas@3697
   146
andreas@3697
   147
        self.account.user.userName = name
andreas@3697
   148
agp@8142
   149
        guard let verificationService = verificationService else {
agp@8142
   150
            Logger.frontendLogger.errorAndCrash("no VerificationService")
andreas@3697
   151
            return
andreas@3697
   152
        }
agp@8142
   153
        verificationService.requestVerification(account: account, delegate: self)
dz@8354
   154
         */
andreas@3697
   155
    }
andreas@3697
   156
andreas@3697
   157
    func sectionIsValid(section: Int) -> Bool {
borja@6875
   158
        return section >= 0 && section < headers.count
andreas@3697
   159
    }
andreas@3697
   160
andreas@3697
   161
    var count: Int {
andreas@3697
   162
        get {
andreas@3697
   163
            return headers.count
andreas@3697
   164
        }
andreas@3697
   165
    }
andreas@3697
   166
andreas@3697
   167
    subscript(section: Int) -> String {
andreas@3697
   168
        get {
andreas@3697
   169
            assert(sectionIsValid(section: section), "Section out of range")
andreas@3697
   170
            return headers[section]
andreas@3697
   171
        }
andreas@3697
   172
    }
andreas@3697
   173
andreas@3697
   174
    private func server(from viewModel:ServerViewModel, serverType:Server.ServerType,
andreas@3697
   175
                        loginName: String, password: String?, key: String? = nil) -> Server? {
andreas@3697
   176
        guard let viewModelPort = viewModel.port,
andreas@3697
   177
            let port = UInt16(viewModelPort),
andreas@3697
   178
            let address = viewModel.address else {
dz@7517
   179
                Logger.frontendLogger.errorAndCrash("viewModel misses required data.")
andreas@3697
   180
                return nil
andreas@3697
   181
        }
andreas@5601
   182
        let transport = Server.Transport(fromString: viewModel.transport)
andreas@3697
   183
andreas@3697
   184
        let credentials = ServerCredentials.create(loginName: loginName, key: key)
andreas@3697
   185
        if password != nil && password != "" {
andreas@3697
   186
            credentials.password = password
andreas@3697
   187
        }
andreas@3697
   188
andreas@3697
   189
        let server = Server.create(serverType: serverType, port: port, address: address,
andreas@3697
   190
                                   transport: transport, credentials: credentials)
andreas@3697
   191
andreas@3697
   192
        return server
andreas@3697
   193
    }
andreas@3697
   194
dirk@4052
   195
    func updateToken(accessToken: OAuth2AccessTokenProtocol) {
dz@8354
   196
        // TODO: What to do here? When does this get called?
dz@8354
   197
        /*
dirk@4053
   198
        guard let imapServer = account.imapServer,
dirk@4053
   199
            let smtpServer = account.smtpServer else {
dirk@4053
   200
                return
dirk@4052
   201
        }
dirk@4053
   202
        let password = accessToken.persistBase64Encoded()
dirk@4053
   203
        imapServer.credentials.password = password
dirk@4053
   204
        smtpServer.credentials.password = password
dz@8354
   205
         */
dirk@4052
   206
    }
andreas@3697
   207
}
andreas@3697
   208
andreas@5601
   209
// MARK: - AccountVerificationServiceDelegate
andreas@5601
   210
andreas@3697
   211
extension AccountSettingsViewModel: AccountVerificationServiceDelegate {
dz@7999
   212
    public func verified(account: Account,
andreas@5601
   213
                  service: AccountVerificationServiceProtocol,
andreas@3697
   214
                  result: AccountVerificationResult) {
andreas@5601
   215
        if result == .ok {
dz@7914
   216
            MessageModelUtil.performAndWait {
andreas@5601
   217
                account.save()
andreas@5601
   218
            }
andreas@5601
   219
        }
andreas@5601
   220
        GCD.onMainWait { [weak self] in
andreas@5601
   221
            guard let me = self else {
dz@7517
   222
                Logger.frontendLogger.lostMySelf()
andreas@5601
   223
                return
andreas@5601
   224
            }
andreas@5601
   225
            me.delegate?.didVerify(result: result, accountInput: nil)
andreas@3697
   226
        }
andreas@3697
   227
    }
andreas@3697
   228
}