summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/REST/RESTError.swift
blob: 110eafbfcd50dcb5cdc35cd1c0efa2399e83e58a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//
//  RESTError.swift
//  RESTError
//
//  Created by pronebird on 27/07/2021.
//  Copyright © 2021 Mullvad VPN AB. All rights reserved.
//

import Foundation

extension REST {

    /// An error type returned by `REST.Client`
    enum Error: ChainedError {
        /// A failure to encode the payload
        case encodePayload(Swift.Error)

        /// A failure during networking
        case network(URLError)

        /// A failure reported by server
        case server(REST.ServerErrorResponse)

        /// A failure to decode the error response from server
        case decodeErrorResponse(Swift.Error)

        /// A failure to decode the success response from server
        case decodeSuccessResponse(Swift.Error)

        var errorDescription: String? {
            switch self {
            case .encodePayload:
                return "Failure to encode the payload"
            case .network:
                return "Network error"
            case .server:
                return "Server error"
            case .decodeErrorResponse:
                return "Failure to decode error response from server"
            case .decodeSuccessResponse:
                return "Failure to decode success response from server"
            }
        }
    }

    /// A struct that represents a server response in case of error (any HTTP status code except 2xx).
    struct ServerErrorResponse: LocalizedError, Decodable, Equatable {
        /// A list of known server error codes
        enum Code: String, Equatable {
            case invalidAccount = "INVALID_ACCOUNT"
            case keyLimitReached = "KEY_LIMIT_REACHED"
            case pubKeyNotFound = "PUBKEY_NOT_FOUND"

            static func ~= (pattern: Self, value: REST.ServerErrorResponse) -> Bool {
                return pattern.rawValue == value.code
            }
        }

        static var invalidAccount: Code {
            return .invalidAccount
        }
        static var keyLimitReached: Code {
            return .keyLimitReached
        }
        static var pubKeyNotFound: Code {
            return .pubKeyNotFound
        }

        let code: String
        let error: String?

        var errorDescription: String? {
            switch code {
            case Code.keyLimitReached.rawValue:
                return NSLocalizedString(
                    "KEY_LIMIT_REACHED_ERROR_DESCRIPTION",
                    tableName: "RESTClient",
                    value: "Too many WireGuard keys in use.",
                    comment: ""
                )
            case Code.invalidAccount.rawValue:
                return NSLocalizedString(
                    "INVALID_ACCOUNT_ERROR_DESCRIPTION",
                    tableName: "RESTClient",
                    value: "Invalid account.",
                    comment: ""
                )
            default:
                return nil
            }
        }

        var recoverySuggestion: String? {
            switch code {
            case Code.keyLimitReached.rawValue:
                return NSLocalizedString(
                    "KEY_LIMIT_REACHED_ERROR_RECOVERY_SUGGESTION",
                    tableName: "RESTClient",
                    value: "Please visit the website to revoke a key before login is possible.",
                    comment: ""
                )
            default:
                return nil
            }
        }

        static func == (lhs: Self, rhs: Self) -> Bool {
            return lhs.code == rhs.code
        }
    }

}