Skip to content

Commit

Permalink
gh-716 handle CONFIRMATION_REQUEST pushes; add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrey Scherbovich committed Nov 25, 2020
1 parent 8c9350d commit 051838b
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 10 deletions.
24 changes: 24 additions & 0 deletions Multisig.xcodeproj/project.pbxproj
Expand Up @@ -365,6 +365,8 @@
559670FF256E88FC0097D3A2 /* Signer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559670FE256E88FC0097D3A2 /* Signer.swift */; };
55967105256E92470097D3A2 /* SignerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55967104256E92470097D3A2 /* SignerTests.swift */; };
5596710D256E935F0097D3A2 /* MockSecureStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5596710C256E935F0097D3A2 /* MockSecureStore.swift */; };
55967119256EB2120097D3A2 /* RegisterNotificationTokenRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55967118256EB2120097D3A2 /* RegisterNotificationTokenRequestTests.swift */; };
55967123256EB7690097D3A2 /* ConfirmationRequestNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55967122256EB7690097D3A2 /* ConfirmationRequestNotification.swift */; };
5596C03825507EAE00EF23A5 /* CollectibleTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5596C03725507EAE00EF23A5 /* CollectibleTableViewCell.xib */; };
5596C03E25507F3C00EF23A5 /* CollectibleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5596C03D25507F3C00EF23A5 /* CollectibleTableViewCell.swift */; };
5596C0482550813B00EF23A5 /* CollectiblesHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5596C0472550813B00EF23A5 /* CollectiblesHeaderView.swift */; };
Expand Down Expand Up @@ -873,6 +875,8 @@
559670FE256E88FC0097D3A2 /* Signer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signer.swift; sourceTree = "<group>"; };
55967104256E92470097D3A2 /* SignerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignerTests.swift; sourceTree = "<group>"; };
5596710C256E935F0097D3A2 /* MockSecureStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSecureStore.swift; sourceTree = "<group>"; };
55967118256EB2120097D3A2 /* RegisterNotificationTokenRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterNotificationTokenRequestTests.swift; sourceTree = "<group>"; };
55967122256EB7690097D3A2 /* ConfirmationRequestNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationRequestNotification.swift; sourceTree = "<group>"; };
5596C03725507EAE00EF23A5 /* CollectibleTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CollectibleTableViewCell.xib; sourceTree = "<group>"; };
5596C03D25507F3C00EF23A5 /* CollectibleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectibleTableViewCell.swift; sourceTree = "<group>"; };
5596C0472550813B00EF23A5 /* CollectiblesHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectiblesHeaderView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1214,6 +1218,7 @@
0A0EFCA1246EADD100D3D8BF /* Data */ = {
isa = PBXGroup;
children = (
55967116256EB1E50097D3A2 /* Services */,
5556A03924489F5D003EC861 /* Persistence */,
);
path = Data;
Expand Down Expand Up @@ -1814,6 +1819,7 @@
0AF2737024DC57FA007E4012 /* IncomingEtherNotification.swift */,
0AF2737224DC580D007E4012 /* IncomingTokenNotification.swift */,
0AF2736E24DC57E8007E4012 /* MultisigNotification.swift */,
55967122256EB7690097D3A2 /* ConfirmationRequestNotification.swift */,
);
path = Notifications;
sourceTree = "<group>";
Expand Down Expand Up @@ -2111,6 +2117,22 @@
path = Mocks;
sourceTree = "<group>";
};
55967116256EB1E50097D3A2 /* Services */ = {
isa = PBXGroup;
children = (
55967117256EB1F10097D3A2 /* Safe Transaction Service */,
);
path = Services;
sourceTree = "<group>";
};
55967117256EB1F10097D3A2 /* Safe Transaction Service */ = {
isa = PBXGroup;
children = (
55967118256EB2120097D3A2 /* RegisterNotificationTokenRequestTests.swift */,
);
path = "Safe Transaction Service";
sourceTree = "<group>";
};
55A585352501417E005E778B /* PrivateKey */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3005,6 +3027,7 @@
55967105256E92470097D3A2 /* SignerTests.swift in Sources */,
5532D4DE2449A34A0067505A /* TestUtils.swift in Sources */,
5556A03C24489F5D003EC861 /* CoreDataStackTests.swift in Sources */,
55967119256EB2120097D3A2 /* RegisterNotificationTokenRequestTests.swift in Sources */,
551DDEF0244F1A0A00C719D3 /* SafeTests.swift in Sources */,
5532D4CC2449A1980067505A /* LogFormatterTests.swift in Sources */,
0ACC4C4E247534EC00ADF201 /* GnosisSafeTests.swift in Sources */,
Expand Down Expand Up @@ -3039,6 +3062,7 @@
0AF2736B24DC57C6007E4012 /* NotificationPayload.swift in Sources */,
0AF2737524DC581A007E4012 /* ExecutedMultisigTransactionNotification.swift in Sources */,
0AF2736F24DC57E8007E4012 /* MultisigNotification.swift in Sources */,
55967123256EB7690097D3A2 /* ConfirmationRequestNotification.swift in Sources */,
0AF2736D24DC57D5007E4012 /* PlainAddress.swift in Sources */,
0AF2737124DC57FA007E4012 /* IncomingEtherNotification.swift in Sources */,
);
Expand Down
Expand Up @@ -17,21 +17,29 @@ struct RegisterNotificationTokenRequest: JSONRequest {
let version: String
let deviceType: String = "IOS"
let buildNumber: String
let timestamp: String = String(Int(Date().timeIntervalSince1970 * 1_000))
let timestamp: String
let signatures: [String]?

var httpMethod: String { return "POST" }
var urlPath: String { return "/api/v1/notifications/devices/" }

typealias ResponseType = Response

init(deviceID: UUID, safes: [Address], token: String, bundle: String, version: String, buildNumber: String) throws {
init(deviceID: UUID,
safes: [Address],
token: String,
bundle: String,
version: String,
buildNumber: String,
timestamp: String = String(Int(Date().timeIntervalSince1970 * 1_000))) throws {

self.uuid = deviceID.uuidString.lowercased()
self.safes = safes.map { $0.checksummed }
self.cloudMessagingToken = token
self.bundle = bundle
self.version = version
self.buildNumber = buildNumber
self.timestamp = timestamp

let string = [
"gnosis-safe",
Expand Down
2 changes: 1 addition & 1 deletion Multisig/Logic/Models/Signer.swift
Expand Up @@ -10,7 +10,7 @@ import Foundation
import Web3

class Signer {
struct Signature {
struct Signature: Equatable {
var value: String
var signer: String
}
Expand Down
6 changes: 6 additions & 0 deletions Multisig/UI/App/RemoteNotificationHandler.swift
Expand Up @@ -76,6 +76,12 @@ class RemoteNotificationHandler {
unregister(address: address)
}

/// For add / remove signing key
func signingKeyUpdated() {
logDebug("Signing key updated")
registerAll()
}

func received(notification userInfo: [AnyHashable: Any]) {
assert(Thread.isMainThread)
logDebug("Received notification: \(userInfo)")
Expand Down
Expand Up @@ -165,6 +165,7 @@ class AppSettingsViewController: UITableViewController {
try App.shared.keychainService.removeData(
forKey: KeychainKey.ownerPrivateKey.rawValue)
AppSettings.setSigningKeyAddress(nil)
App.shared.notificationHandler.signingKeyUpdated()
App.shared.snackbar.show(message: "Owner key removed from this app")
Tracker.shared.setUserProperty("0", for: TrackingUserProperty.numKeysImported)
self.reload()
Expand Down
Expand Up @@ -57,6 +57,7 @@ class SelectOwnerAddressViewModel: ObservableObject {
try App.shared.keychainService.removeData(forKey: KeychainKey.ownerPrivateKey.rawValue)
try App.shared.keychainService.save(data: pkData, forKey: KeychainKey.ownerPrivateKey.rawValue)
AppSettings.setSigningKeyAddress(addresses[selectedIndex].checksummed)
App.shared.notificationHandler.signingKeyUpdated()
App.shared.snackbar.show(message: "Owner key successfully imported")
Tracker.shared.setUserProperty("1", for: TrackingUserProperty.numKeysImported)
return true
Expand Down
@@ -0,0 +1,33 @@
//
// RegisterNotificationTokenRequestTests.swift
// MultisigTests
//
// Created by Andrey Scherbovich on 25.11.20.
// Copyright © 2020 Gnosis Ltd. All rights reserved.
//

import XCTest
@testable import Multisig

class RegisterNotificationTokenRequestTests: XCTestCase {
let mockStore = MockSecureStore()

override func setUpWithError() throws {
App.shared.keychainService = mockStore
try! mockStore.save(data: Data(hex: "0xe7979e5f2ceb1d4ef76019d1fdba88b50ceefe0575bbfdf94969837c50a5d895"),
forKey: KeychainKey.ownerPrivateKey.rawValue)
}


func testRequestInitCalculatesProperSignature() throws {
let request = try RegisterNotificationTokenRequest(
deviceID: UUID(uuidString: "bb30cd3e-e0ad-4e9a-b726-44db67a0820b")!,
safes: [Address("0xEefFcdEAB4AC6005E90566B08EAda3994A573C1E")],
token: "erXBYb-CxU1jtSvwfZrxqW:APA91bH0IWkMWOGizlbNAwxV6OVjEmNR1feRs2WBT7BE6aVMm2C-x1COKqNYq19t5YNjIzVBKDyVVEqFojlkvEtiSaJA0lCZL0LfuEwfc8p9jfBuM6HG82pczVbnMev1J0gXlB3bIlAP",
bundle: "io.gnosis.multisig.dev.rinkeby",
version: "2.6.0",
buildNumber: "1",
timestamp: "1606319110027")
XCTAssertEqual(request.signatures, ["460ab62322407376576be061a6bfaaaa78cd1be4e0421d88cd635d0568ff2d473280d0edfd898bf1fd73f3fea8206ef91d6fbf6d9dc63b5d7d1378b8e4059f691c"])
}
}
16 changes: 10 additions & 6 deletions MultisigTests/Logic/Models/SignerTests.swift
Expand Up @@ -10,15 +10,19 @@ import XCTest
@testable import Multisig

class SignerTests: XCTestCase {
override class func setUp() {
let mockStore = MockSecureStore()

override func setUpWithError() throws {
super.setUp()
App.shared.keychainService = MockSecureStore()
App.shared.keychainService = mockStore
try! mockStore.save(data: Data(hex: "0xe7979e5f2ceb1d4ef76019d1fdba88b50ceefe0575bbfdf94969837c50a5d895"),
forKey: KeychainKey.ownerPrivateKey.rawValue)
}

func testSigner() throws {
// let string = "gnosis-safe33971c4e-fb98-4e18-a08d-13c881ae292a0x4dEBDD6CEe25b2F931D2FE265D70e1a533B024530x72ac1760daF52986421b1552BdCa04707E78950edSh5Se1XgEiTiY-4cv1ixY:APA91bG3vYjy9VgB3X3u5EsBphJABchb8Xgg2cOSSekPsxDsfE5xyBeu6gKY0wNhbJHgQUQQGocrHx0Shbx6JMFx2VOyhJx079AduN01NWD1-WjQerY5s3l-cLnHoNNn8fJfARqSUb3Gio.gnosis.multisig.prod.mainnet2.7.0IOS1991605186645155"
// let expectedSignature = Signer.Signature(value: <#T##String#>, signer: <#T##String#>)
// XCTAssertEqual(Signer.sign(string), <#T##expression2: Equatable##Equatable#>)
let string = "gnosis-safe"
let expected = Signer.Signature(value: "99a7a03e9597e85a0cc4188d270b72b1df2de943de804f144976f4c1e23116ff274d2dec4ee7201b88bdadf08259a5dc8e7e2bbf372347de3470beeab904e5d01b",
signer: "0x728cafe9fB8CC2218Fb12a9A2D9335193caa07e0")
XCTAssertEqual(try Signer.sign(string), expected)
}

}
3 changes: 2 additions & 1 deletion NotificationServiceExtension/NotificationService.swift
Expand Up @@ -24,7 +24,8 @@ class NotificationService: UNNotificationServiceExtension {
NewConfirmationNotification.self,
ExecutedMultisigTransactionNotification.self,
IncomingTokenNotification.self,
IncomingEtherNotification.self
IncomingEtherNotification.self,
ConfirmationRequestNotification.self
] as [MultisigNotification.Type])
.compactMap({ $0.init(payload: payload) })
.first
Expand Down
@@ -0,0 +1,33 @@
//
// ConfirmationRequestNotification.swift
// NotificationServiceExtension
//
// Created by Andrey Scherbovich on 25.11.20.
// Copyright © 2020 Gnosis Ltd. All rights reserved.
//

import Foundation

struct ConfirmationRequestNotification: MultisigNotification {
let address: PlainAddress

init?(payload: NotificationPayload) {
guard
let rawType = payload.type,
let type = NotificationType(rawValue: rawType),
type == .confirmationRequest,
let address = PlainAddress(payload.address)
else {
return nil
}
self.address = address
}

var localizedTitle: String {
"Confirmation required"
}

var localizedBody: String {
"\(address.truncatedInMiddle): A transaction requires your confirmation!"
}
}
Expand Up @@ -13,6 +13,7 @@ enum NotificationType: String {
case incomingToken = "INCOMING_TOKEN"
case executedMultisigTx = "EXECUTED_MULTISIG_TRANSACTION"
case newConfirmation = "NEW_CONFIRMATION"
case confirmationRequest = "CONFIRMATION_REQUEST"
}

protocol MultisigNotification {
Expand Down

0 comments on commit 051838b

Please sign in to comment.