Skip to content

Commit

Permalink
NotifyConfig from explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
flypaper0 committed Oct 18, 2023
1 parent fbf5e09 commit eebe227
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 59 deletions.
3 changes: 2 additions & 1 deletion Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ final class NotifyTests: XCTestCase {
keychainStorage: keychain,
environment: .sandbox)
let keyserverURL = URL(string: "https://keys.walletconnect.com")!
let client = NotifyClientFactory.create(keyserverURL: keyserverURL,
let client = NotifyClientFactory.create(projectId: InputConfig.projectId,
keyserverURL: keyserverURL,
logger: notifyLogger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import Foundation

public struct NotifyClientFactory {

public static func create(groupIdentifier: String, networkInteractor: NetworkInteracting, pairingRegisterer: PairingRegisterer, pushClient: PushClient, crypto: CryptoProvider, notifyHost: String) -> NotifyClient {
public static func create(projectId: String, groupIdentifier: String, networkInteractor: NetworkInteracting, pairingRegisterer: PairingRegisterer, pushClient: PushClient, crypto: CryptoProvider, notifyHost: String) -> NotifyClient {
let logger = ConsoleLogger(prefix: "🔔",loggingLevel: .debug)
let keyValueStorage = UserDefaults.standard
let keyserverURL = URL(string: "https://keys.walletconnect.com")!
let keychainStorage = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk")
let groupKeychainService = GroupKeychainStorage(serviceIdentifier: groupIdentifier)

return NotifyClientFactory.create(
projectId: projectId,
keyserverURL: keyserverURL,
logger: logger,
keyValueStorage: keyValueStorage,
Expand All @@ -24,6 +25,7 @@ public struct NotifyClientFactory {
}

static func create(
projectId: String,
keyserverURL: URL,
logger: ConsoleLogging,
keyValueStorage: KeyValueStorage,
Expand All @@ -47,7 +49,7 @@ public struct NotifyClientFactory {
let resubscribeService = NotifyResubscribeService(networkInteractor: networkInteractor, notifyStorage: notifyStorage, logger: logger)

let dappsMetadataStore = CodableStore<AppMetadata>(defaults: keyValueStorage, identifier: NotifyStorageIdntifiers.dappsMetadataStore)
let notifyConfigProvider = NotifyConfigProvider()
let notifyConfigProvider = NotifyConfigProvider(projectId: projectId)

let notifySubscribeRequester = NotifySubscribeRequester(keyserverURL: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, logger: logger, kms: kms, webDidResolver: webDidResolver, notifyConfigProvider: notifyConfigProvider, dappsMetadataStore: dappsMetadataStore)

Expand Down
30 changes: 30 additions & 0 deletions Sources/WalletConnectNotify/Client/Wallet/NotifyConfig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Foundation

struct NotifyConfig: Codable {
struct NotificationType: Codable {
let id: String
let name: String
let description: String
}
struct ImageUrl: Codable {
let sm: String?
let md: String?
let lg: String?
}
let id: String
let name: String
let homepage: String
let description: String
let image_url: ImageUrl?
let notificationTypes: [NotificationType]

var metadata: AppMetadata {
return AppMetadata(
name: name,
description:
description,
url: homepage,
icons: [image_url?.sm, image_url?.md, image_url?.lg].compactMap { $0 }
)
}
}
33 changes: 33 additions & 0 deletions Sources/WalletConnectNotify/Client/Wallet/NotifyConfigAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Foundation

enum NotifyConfigAPI: HTTPService {

var path: String {
return "/w3i/v1/notify-config"
}

var method: HTTPMethod {
return .get
}

var body: Data? {
return nil
}

var queryParameters: [String : String]? {
switch self {
case .notifyDApps(let projectId, let appDomain):
return ["projectId": projectId, "appDomain": appDomain]
}
}

var additionalHeaderFields: [String : String]? {
return nil
}

var scheme: String {
return "https"
}

case notifyDApps(projectId: String, appDomain: String)
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@

import Foundation

actor NotifyConfigProvider {
enum Errors: Error {
case invalidUrl
}

private var cache = [String: Set<NotificationType>]()
private let projectId: String

init(projectId: String) {
self.projectId = projectId
}

func getSubscriptionScope(appDomain: String) async throws -> Set<NotificationType> {
if let availableScope = cache[appDomain] {
return availableScope
}
guard let notifyConfigUrl = URL(string: "https://\(appDomain)/.well-known/wc-notify-config.json") else { throw Errors.invalidUrl }
let (data, _) = try await URLSession.shared.data(from: notifyConfigUrl)
let config = try JSONDecoder().decode(NotificationConfig.self, from: data)
let availableScope = Set(config.types)
cache[appDomain] = availableScope
return availableScope
func resolveNotifyConfig(appDomain: String) async throws -> NotifyConfig {
let httpClient = HTTPNetworkClient(host: "explorer-api.walletconnect.com")
let request = NotifyConfigAPI.notifyDApps(projectId: projectId, appDomain: appDomain)
let response = try await httpClient.request(NotifyConfigResponse.self, at: request)
return response.data
}
}

private extension NotifyConfigProvider {

func getMetadata(appDomain: String) async throws -> AppMetadata {
guard let notifyConfigUrl = URL(string: "https://\(appDomain)/.well-known/wc-notify-config.json") else { throw Errors.invalidUrl }
let (data, _) = try await URLSession.shared.data(from: notifyConfigUrl)
let config = try JSONDecoder().decode(NotificationConfig.self, from: data)
return AppMetadata(name: config.name, description: config.description, url: appDomain, icons: config.icons)
struct NotifyConfigResponse: Codable {
let data: NotifyConfig
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,29 @@ class NotifySubscriptionsBuilder {
var result = [NotifySubscription]()

for subscription in notifyServerSubscriptions {
let scope = try await buildScope(selectedScope: subscription.scope, appDomain: subscription.appDomain)
guard let metadata = try? await notifyConfigProvider.getMetadata(appDomain: subscription.appDomain),
let topic = try? SymmetricKey(hex: subscription.symKey).derivedTopic() else { continue }
do {
let config = try await notifyConfigProvider.resolveNotifyConfig(appDomain: subscription.appDomain)
let topic = try SymmetricKey(hex: subscription.symKey).derivedTopic()
let scope = try await buildScope(selectedScope: subscription.scope, availableScope: config.notificationTypes)

let notifySubscription = NotifySubscription(topic: topic,
account: subscription.account,
relay: RelayProtocolOptions(protocol: "irn", data: nil),
metadata: metadata,
scope: scope,
expiry: subscription.expiry,
symKey: subscription.symKey)
result.append(notifySubscription)
result.append(NotifySubscription(
topic: topic,
account: subscription.account,
relay: RelayProtocolOptions(protocol: "irn", data: nil),
metadata: config.metadata,
scope: scope,
expiry: subscription.expiry,
symKey: subscription.symKey
))
} catch {
continue
}
}

return result
}

private func buildScope(selectedScope: [String], appDomain: String) async throws -> [String: ScopeValue] {
let availableScope = try await notifyConfigProvider.getSubscriptionScope(appDomain: appDomain)
private func buildScope(selectedScope: [String], availableScope: [NotifyConfig.NotificationType]) async throws -> [String: ScopeValue] {
return availableScope.reduce(into: [:]) {
$0[$1.name] = ScopeValue(description: $1.description, enabled: selectedScope.contains($1.name))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ class NotifySubscribeRequester {

logger.debug("Subscribing for Notify, dappUrl: \(appDomain)")

let metadata = try await notifyConfigProvider.getMetadata(appDomain: appDomain)
let config = try await notifyConfigProvider.resolveNotifyConfig(appDomain: appDomain)

let peerPublicKey = try await webDidResolver.resolveAgreementKey(domain: metadata.url)
let peerPublicKey = try await webDidResolver.resolveAgreementKey(domain: appDomain)
let subscribeTopic = peerPublicKey.rawRepresentation.sha256().toHexString()

let keysY = try generateAgreementKeys(peerPublicKey: peerPublicKey)

let responseTopic = keysY.derivedTopic()

dappsMetadataStore.set(metadata, forKey: responseTopic)
dappsMetadataStore.set(config.metadata, forKey: responseTopic)

try kms.setSymmetricKey(keysY.sharedKey, for: subscribeTopic)
try kms.setAgreementSecret(keysY, topic: responseTopic)
Expand Down Expand Up @@ -80,10 +80,17 @@ class NotifySubscribeRequester {
}

private func createJWTWrapper(dappPubKey: DIDKey, subscriptionAccount: Account, appDomain: String) async throws -> NotifySubscriptionPayload.Wrapper {
let types = try await notifyConfigProvider.getSubscriptionScope(appDomain: appDomain)
let scope = types.map{$0.name}.joined(separator: " ")
let config = try await notifyConfigProvider.resolveNotifyConfig(appDomain: appDomain)
let app = DIDWeb(host: appDomain)
let jwtPayload = NotifySubscriptionPayload(dappPubKey: dappPubKey, keyserver: keyserverURL, subscriptionAccount: subscriptionAccount, app: app, scope: scope)
let jwtPayload = NotifySubscriptionPayload(
dappPubKey: dappPubKey,
keyserver: keyserverURL,
subscriptionAccount: subscriptionAccount,
app: app,
scope: config.notificationTypes
.map { $0.name }
.joined(separator: " ")
)
return try identityClient.signAndCreateWrapper(
payload: jwtPayload,
account: subscriptionAccount
Expand Down
1 change: 1 addition & 0 deletions Sources/WalletConnectNotify/Notify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class Notify {
}
Push.configure(pushHost: config.pushHost, environment: config.environment)
return NotifyClientFactory.create(
projectId: Networking.projectId,
groupIdentifier: config.groupIdentifier,
networkInteractor: Networking.interactor,
pairingRegisterer: Pair.registerer,
Expand Down

This file was deleted.

This file was deleted.

0 comments on commit eebe227

Please sign in to comment.