Skip to content

Commit

Permalink
Merge pull request #1198 from WalletConnect/develop
Browse files Browse the repository at this point in the history
1.9.2
  • Loading branch information
alexander-lsvk authored Oct 30, 2023
2 parents f22bcf4 + aedef51 commit c3c84f2
Show file tree
Hide file tree
Showing 36 changed files with 461 additions and 284 deletions.
12 changes: 7 additions & 5 deletions Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,20 +136,22 @@ final class NotifyTests: XCTestCase {
let expectation = expectation(description: "expects client B to receive subscription after both clients are registered and client A creates one")
expectation.assertForOverFulfill = false

var subscription: NotifySubscription!

let clientB = makeWalletClient(prefix: "👐🏼 Wallet B: ")
clientB.subscriptionsPublisher.sink { subscriptions in
guard let subscription = subscriptions.first else { return }
Task(priority: .high) {
try await clientB.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
}
guard let newSubscription = subscriptions.first else { return }
subscription = newSubscription
expectation.fulfill()
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await clientB.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)

try await clientB.deleteSubscription(topic: subscription.topic)
}

func testWalletCreatesAndUpdatesSubscription() async {
Expand Down
25 changes: 16 additions & 9 deletions Example/PNDecryptionService/Info.plist
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
</dict>
</dict>
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>IntentsSupported</key>
<array>
<string>INSendMessageIntent</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
</dict>
</dict>
</plist>
105 changes: 89 additions & 16 deletions Example/PNDecryptionService/NotificationService.swift
Original file line number Diff line number Diff line change
@@ -1,42 +1,115 @@
import UserNotifications
import WalletConnectNotify
import os
import Intents

class NotificationService: UNNotificationServiceExtension {

var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
var bestAttemptContent: UNNotificationContent?

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
let topic = bestAttemptContent.userInfo["topic"] as! String
let ciphertext = bestAttemptContent.userInfo["blob"] as! String
NSLog("Push decryption, topic=%@", topic)
self.bestAttemptContent = request.content

if let content = bestAttemptContent,
let topic = content.userInfo["topic"] as? String,
let ciphertext = content.userInfo["blob"] as? String {

do {
let service = NotifyDecryptionService(groupIdentifier: "group.com.walletconnect.sdk")
let pushMessage = try service.decryptMessage(topic: topic, ciphertext: ciphertext)
bestAttemptContent.title = pushMessage.title
bestAttemptContent.body = pushMessage.body
contentHandler(bestAttemptContent)
return
let updatedContent = try handle(content: content, pushMessage: pushMessage, topic: topic)

let mutableContent = updatedContent.mutableCopy() as! UNMutableNotificationContent
mutableContent.title = pushMessage.title
mutableContent.body = pushMessage.body

contentHandler(mutableContent)
}
catch {
NSLog("Push decryption, error=%@", error.localizedDescription)
bestAttemptContent.title = ""
bestAttemptContent.body = error.localizedDescription
let mutableContent = content.mutableCopy() as! UNMutableNotificationContent
mutableContent.title = "Error"
mutableContent.body = error.localizedDescription

contentHandler(mutableContent)
}
contentHandler(bestAttemptContent)
}
}

override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}

private extension NotificationService {

func handle(content: UNNotificationContent, pushMessage: NotifyMessage, topic: String) throws -> UNNotificationContent {
let iconUrl = try pushMessage.icon.asURL()

let senderThumbnailImageData = try Data(contentsOf: iconUrl)
let senderThumbnailImageFileUrl = try downloadAttachment(data: senderThumbnailImageData, fileName: iconUrl.lastPathComponent)
let senderThumbnailImageFileData = try Data(contentsOf: senderThumbnailImageFileUrl)
let senderAvatar = INImage(imageData: senderThumbnailImageFileData)

var personNameComponents = PersonNameComponents()
personNameComponents.nickname = pushMessage.title

let senderPerson = INPerson(
personHandle: INPersonHandle(value: topic, type: .unknown),
nameComponents: personNameComponents,
displayName: pushMessage.title,
image: senderAvatar,
contactIdentifier: nil,
customIdentifier: topic,
isMe: false,
suggestionType: .none
)

let selfPerson = INPerson(
personHandle: INPersonHandle(value: "0", type: .unknown),
nameComponents: nil,
displayName: nil,
image: nil,
contactIdentifier: nil,
customIdentifier: nil,
isMe: true,
suggestionType: .none
)

let incomingMessagingIntent = INSendMessageIntent(
recipients: [selfPerson],
outgoingMessageType: .outgoingMessageText,
content: pushMessage.body,
speakableGroupName: nil,
conversationIdentifier: pushMessage.type,
serviceName: nil,
sender: senderPerson,
attachments: []
)

incomingMessagingIntent.setImage(senderAvatar, forParameterNamed: \.sender)

let interaction = INInteraction(intent: incomingMessagingIntent, response: nil)
interaction.direction = .incoming
interaction.donate(completion: nil)

return try content.updating(from: incomingMessagingIntent)
}

func downloadAttachment(data: Data, fileName: String) throws -> URL {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)

try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)

let fileURL = tmpSubFolderURL.appendingPathComponent(fileName)
try data.write(to: fileURL)

return fileURL
}
}
4 changes: 4 additions & 0 deletions Example/WalletApp/Other/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSUserActivityTypes</key>
<array>
<string>INSendMessageIntent</string>
</array>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleURLTypes</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import SwiftUI

struct ConnectionDetailsView: View {
@EnvironmentObject var presenter: ConnectionDetailsPresenter


private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss E, d MMM y"
return formatter
}

var body: some View {
ZStack {
Color.grey100
Expand Down Expand Up @@ -145,6 +151,39 @@ struct ConnectionDetailsView: View {
.padding(.top, 30)
}

VStack(alignment: .leading) {
Text("Expiry")
.font(.system(size: 15, weight: .semibold, design: .rounded))
.foregroundColor(.whiteBackground)
.padding(.horizontal, 8)
.padding(.vertical, 5)
.background(Color.grey70)
.cornerRadius(28, corners: .allCorners)
.padding(.leading, 15)
.padding(.top, 9)

VStack(spacing: 0) {
TagsView(items: [dateFormatter.string(from: presenter.session.expiryDate)]) {
Text($0)
.foregroundColor(.cyanBackround)
.font(.system(size: 13, weight: .semibold, design: .rounded))
.padding(.horizontal, 8)
.padding(.vertical, 3)
.background(Color.cyanBackround.opacity(0.2))
.cornerRadius(10, corners: .allCorners)
}
.padding(10)
}
.background(Color.whiteBackground)
.cornerRadius(20, corners: .allCorners)
.padding(.horizontal, 5)
.padding(.bottom, 5)
}
.background(Color("grey95"))
.cornerRadius(25, corners: .allCorners)
.padding(.horizontal, 20)
.padding(.top, 30)

Button {
presenter.onDelete()
} label: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,12 @@ final class NotificationsInteractor {
return try await withCheckedThrowingContinuation { continuation in
var cancellable: AnyCancellable?
cancellable = subscriptionsPublisher
.setFailureType(to: Error.self)
.timeout(10, scheduler: RunLoop.main, customError: { Errors.subscribeTimeout })
.sink(receiveCompletion: { completion in
defer { cancellable?.cancel() }
switch completion {
case .failure(let error): continuation.resume(with: .failure(error))
case .finished: break
}
}, receiveValue: { subscriptions in
.sink { subscriptions in
guard subscriptions.contains(where: { $0.metadata.url == domain }) else { return }
cancellable?.cancel()
continuation.resume(with: .success(()))
})

}
Task { [cancellable] in
do {
try await Notify.instance.subscribe(appDomain: domain, account: importAccount.account)
Expand Down
2 changes: 2 additions & 0 deletions Example/WalletApp/WalletApp.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.usernotifications.communication</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.walletconnect.sdk</string>
Expand Down
2 changes: 2 additions & 0 deletions Example/WalletApp/WalletAppRelease.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<dict>
<key>aps-environment</key>
<string>production</string>
<key>com.apple.developer.usernotifications.communication</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.walletconnect.sdk</string>
Expand Down
7 changes: 6 additions & 1 deletion Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class NotifyClient {
public func register(account: Account, domain: String, isLimited: Bool = false, onSign: @escaping SigningCallback) async throws {
try await identityService.register(account: account, domain: domain, isLimited: isLimited, onSign: onSign)
notifyAccountProvider.setAccount(account)
subscriptionWatcher.start()
try await subscriptionWatcher.start()
}

public func unregister(account: Account) async throws {
Expand Down Expand Up @@ -132,6 +132,11 @@ public class NotifyClient {

#if targetEnvironment(simulator)
extension NotifyClient {

public var subscriptionChangedPublisher: AnyPublisher<[NotifySubscription], Never> {
return notifySubscriptionsChangedRequestSubscriber.subscriptionChangedPublisher
}

public func register(deviceToken: String) async throws {
try await pushClient.register(deviceToken: deviceToken)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public struct NotifyClientFactory {
let identityClient = IdentityClientFactory.create(keyserver: keyserverURL, keychain: keychainStorage, logger: logger)
let notifyMessageSubscriber = NotifyMessageSubscriber(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, notifyStorage: notifyStorage, crypto: crypto, logger: logger)
let webDidResolver = NotifyWebDidResolver()
let deleteNotifySubscriptionRequester = DeleteNotifySubscriptionRequester(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, webDidResolver: webDidResolver, kms: kms, logger: logger, notifyStorage: notifyStorage)
let deleteNotifySubscriptionRequester = DeleteNotifySubscriptionRequester(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, kms: kms, logger: logger, notifyStorage: notifyStorage)
let resubscribeService = NotifyResubscribeService(networkInteractor: networkInteractor, notifyStorage: notifyStorage, logger: logger)

let notifyConfigProvider = NotifyConfigProvider(projectId: projectId, explorerHost: explorerHost)
Expand All @@ -56,7 +56,7 @@ public struct NotifyClientFactory {

let notifySubscribeResponseSubscriber = NotifySubscribeResponseSubscriber(networkingInteractor: networkInteractor, kms: kms, logger: logger, groupKeychainStorage: groupKeychainStorage, notifyStorage: notifyStorage, notifyConfigProvider: notifyConfigProvider)

let notifyUpdateRequester = NotifyUpdateRequester(keyserverURL: keyserverURL, webDidResolver: webDidResolver, identityClient: identityClient, networkingInteractor: networkInteractor, notifyConfigProvider: notifyConfigProvider, logger: logger, notifyStorage: notifyStorage)
let notifyUpdateRequester = NotifyUpdateRequester(keyserverURL: keyserverURL, identityClient: identityClient, networkingInteractor: networkInteractor, notifyConfigProvider: notifyConfigProvider, logger: logger, notifyStorage: notifyStorage)

let notifyUpdateResponseSubscriber = NotifyUpdateResponseSubscriber(networkingInteractor: networkInteractor, logger: logger, notifyConfigProvider: notifyConfigProvider, notifyStorage: notifyStorage)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ final class NotifyStorage: NotifyStoring {

func updateSubscription(_ subscription: NotifySubscription, scope: [String: ScopeValue], expiry: UInt64) {
let expiry = Date(timeIntervalSince1970: TimeInterval(expiry))
let updated = NotifySubscription(topic: subscription.topic, account: subscription.account, relay: subscription.relay, metadata: subscription.metadata, scope: scope, expiry: expiry, symKey: subscription.symKey)
let updated = NotifySubscription(topic: subscription.topic, account: subscription.account, relay: subscription.relay, metadata: subscription.metadata, scope: scope, expiry: expiry, symKey: subscription.symKey, appAuthenticationKey: subscription.appAuthenticationKey)
subscriptionStore.set(element: updated, for: updated.account.absoluteString)
updateSubscriptionSubject.send(updated)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class NotifySubscriptionsBuilder {
metadata: config.metadata,
scope: scope,
expiry: subscription.expiry,
symKey: subscription.symKey
symKey: subscription.symKey,
appAuthenticationKey: subscription.appAuthenticationKey
))
} catch {
continue
Expand Down
Loading

0 comments on commit c3c84f2

Please sign in to comment.