Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.9.2 #1198

Merged
merged 15 commits into from
Oct 30, 2023
Merged

1.9.2 #1198

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading