-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathPushRegistration.swift
129 lines (110 loc) · 5.38 KB
/
PushRegistration.swift
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import Foundation
import FxA
import Shared
import SwiftyJSON
public class PushRegistration: NSObject, NSCoding {
let uaid: String
let secret: String
// We don't need to have more than one subscription until WebPush is exposed to content Javascript
// however, if/when we do, it'll make migrating easier if we have been serializing it like this all along.
fileprivate var subscriptions: [String: PushSubscription]
public var defaultSubscription: PushSubscription {
return subscriptions[defaultSubscriptionID]!
}
public init(uaid: String, secret: String, subscriptions: [String: PushSubscription] = [:]) {
self.uaid = uaid
self.secret = secret
self.subscriptions = subscriptions
}
public convenience init(uaid: String, secret: String, subscription: PushSubscription) {
self.init(uaid: uaid, secret: secret, subscriptions: [defaultSubscriptionID: subscription])
}
@objc public convenience required init?(coder aDecoder: NSCoder) {
guard let uaid = aDecoder.decodeObject(forKey: "uaid") as? String,
let secret = aDecoder.decodeObject(forKey: "secret") as? String,
let subscriptions = aDecoder.decodeObject(forKey: "subscriptions") as? [String: PushSubscription] else {
fatalError("Cannot decode registration")
}
self.init(uaid: uaid, secret: secret, subscriptions: subscriptions)
}
@objc public func encode(with aCoder: NSCoder) {
aCoder.encode(uaid, forKey: "uaid")
aCoder.encode(secret, forKey: "secret")
aCoder.encode(subscriptions, forKey: "subscriptions")
}
public static func from(json: JSON) -> PushRegistration? {
guard let endpointString = json["endpoint"].string,
let endpoint = URL(string: endpointString),
let secret = json["secret"].string,
let uaid = json["uaid"].string,
let channelID = json["channelID"].string else {
return nil
}
guard let defaultSubscription = try? PushSubscription(channelID: channelID, endpoint: endpoint) else {
return nil
}
return PushRegistration(uaid: uaid, secret: secret, subscriptions: [defaultSubscriptionID: defaultSubscription])
}
}
fileprivate let defaultSubscriptionID = "defaultSubscription"
/// Small NSCodable class for persisting a channel subscription.
/// We use NSCoder because we expect it to be stored in the profile.
public class PushSubscription: NSObject, NSCoding {
let channelID: String
let endpoint: URL
let p256dhPublicKey: String
let p256dhPrivateKey: String
let authKey: String
init(channelID: String, endpoint: URL, p256dhPrivateKey: String, p256dhPublicKey: String, authKey: String) {
self.channelID = channelID
self.endpoint = endpoint
self.p256dhPrivateKey = p256dhPrivateKey
self.p256dhPublicKey = p256dhPublicKey
self.authKey = authKey
}
convenience init(channelID: String, endpoint: URL, keys: PushKeys) {
self.init(channelID: channelID,
endpoint: endpoint,
p256dhPrivateKey: keys.p256dhPrivateKey,
p256dhPublicKey: keys.p256dhPublicKey,
authKey: keys.auth)
}
convenience init(channelID: String, endpoint: URL) throws {
let keys = try PushCrypto.sharedInstance.generateKeys()
self.init(channelID: channelID, endpoint: endpoint, keys: keys)
}
@objc public convenience required init?(coder aDecoder: NSCoder) {
guard let channelID = aDecoder.decodeObject(forKey: "channelID") as? String,
let urlString = aDecoder.decodeObject(forKey: "endpoint") as? String,
let endpoint = URL(string: urlString),
let p256dhPrivateKey = aDecoder.decodeObject(forKey: "p256dhPrivateKey") as? String,
let p256dhPublicKey = aDecoder.decodeObject(forKey: "p256dhPublicKey") as? String,
let authKey = aDecoder.decodeObject(forKey: "authKey") as? String else {
return nil
}
self.init(channelID: channelID,
endpoint: endpoint,
p256dhPrivateKey: p256dhPrivateKey,
p256dhPublicKey: p256dhPublicKey,
authKey: authKey)
}
@objc public func encode(with aCoder: NSCoder) {
aCoder.encode(channelID, forKey: "channelID")
aCoder.encode(endpoint.absoluteString, forKey: "endpoint")
aCoder.encode(p256dhPrivateKey, forKey: "p256dhPrivateKey")
aCoder.encode(p256dhPublicKey, forKey: "p256dhPublicKey")
aCoder.encode(authKey, forKey: "authKey")
}
}
public extension PushSubscription {
public func aesgcm(payload: String, encryptionHeader: String, cryptoHeader: String) -> String? {
let headers = PushCryptoHeaders(encryption: encryptionHeader, cryptoKey: cryptoHeader)
return try? PushCrypto.sharedInstance.aesgcm(ciphertext: payload, withHeaders: headers, decryptWith: p256dhPrivateKey, authenticateWith: authKey)
}
public func aes128gcm(payload: String) -> String? {
return try? PushCrypto.sharedInstance.aes128gcm(payload: payload, decryptWith: p256dhPrivateKey, authenticateWith: authKey)
}
}