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

feat: add sentry for error logging and information. #107

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@
"version" : "4.13.2"
}
},
{
"identity" : "sentry-cocoa",
"kind" : "remoteSourceControl",
"location" : "https://github.com/getsentry/sentry-cocoa",
"state" : {
"revision" : "5575af93efb776414f243e93d6af9f6258dc539a",
"version" : "8.36.0"
}
},
{
"identity" : "swift-crypto",
"kind" : "remoteSourceControl",
Expand Down
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ let package = Package(
.package(url: "https://github.com/torusresearch/fetch-node-details-swift", from: "6.0.3"),
// NB: jwt-kit may only be a dependency in tests or it will break cocoapod support
.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.0.0"),
.package(url: "https://github.com/getsentry/sentry-cocoa", from: "8.36.0"),
],
targets: [
.target(
name: "TorusUtils",
dependencies: [
.product(name: "FetchNodeDetails", package: "fetch-node-details-swift"),
.product(name: "curveSecp256k1", package: "curvelib.swift"),
.product(name: "Sentry", package: "sentry-cocoa"),
]),
.testTarget(
name: "TorusUtilsTests",
Expand Down
4 changes: 3 additions & 1 deletion Sources/TorusUtils/Helpers/Common.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ internal func thresholdSame<T: Encodable>(arr: [T], threshold: Int) throws -> T?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .sortedKeys
for (_, value) in arr.enumerated() {
guard let jsonString = String(data: try jsonEncoder.encode(value), encoding: .utf8) else { throw TorusUtilError.encodingFailed("thresholdSame")
guard let jsonString = String(data: try jsonEncoder.encode(value), encoding: .utf8) else {
SentryUtils.captureException("thresholdSame")
throw TorusUtilError.encodingFailed("thresholdSame")
}
if let _ = hashmap[jsonString] {
hashmap[jsonString]! += 1
Expand Down
7 changes: 6 additions & 1 deletion Sources/TorusUtils/Helpers/KeyUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ enum TorusKeyType: String, Equatable, Hashable, Codable {

public class KeyUtils {
public static func keccak256Data(_ input: String) throws -> String {
guard let data = input.data(using: .utf8) else { throw TorusUtilError.invalidInput }
guard let data = input.data(using: .utf8) else {
SentryUtils.captureException("\(TorusUtilError.invalidInput)")
throw TorusUtilError.invalidInput
}
return try keccak256(data: data).toHexString()
}

Expand Down Expand Up @@ -68,6 +71,7 @@ public class KeyUtils {
if (publicKeyUnprefixed.count <= 128) {
publicKeyUnprefixed = publicKeyUnprefixed.addLeading0sForLength128()
} else {
SentryUtils.captureException("\(TorusUtilError.invalidPubKeySize)")
throw TorusUtilError.invalidPubKeySize
}

Expand Down Expand Up @@ -148,6 +152,7 @@ public class KeyUtils {

internal static func generateShares(keyType: TorusKeyType = .secp256k1, serverTimeOffset: Int, nodeIndexes: [BigUInt], nodePubKeys: [INodePub], privateKey: String) throws -> [ImportedShare] {
if keyType != TorusKeyType.secp256k1 {
SentryUtils.captureException("Unsupported key type")
throw TorusUtilError.runtime("Unsupported key type")
}

Expand Down
4 changes: 4 additions & 0 deletions Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ internal class Lagrange {
let indexList: [BigInt] = nodeIndex.map({ BigInt($0) })

if sharesList.count != indexList.count {
SentryUtils.captureException("sharesList not equal to indexList length in lagrangeInterpolation")
throw TorusUtilError.runtime("sharesList not equal to indexList length in lagrangeInterpolation")
}

Expand All @@ -112,6 +113,7 @@ internal class Lagrange {
guard
let inv = lower.inverse(KeyUtils.getOrderOfCurve())
else {
SentryUtils.captureException("\(TorusUtilError.decryptionFailed)")
throw TorusUtilError.decryptionFailed
}
var delta = (upper * inv).modulus(KeyUtils.getOrderOfCurve())
Expand All @@ -121,13 +123,15 @@ internal class Lagrange {
}

if secret == BigUInt(0) {
SentryUtils.captureException("\(TorusUtilError.interpolationFailed)")
throw TorusUtilError.interpolationFailed
}

let secretString = secret.serialize().hexString.addLeading0sForLength64()
if sharesDecrypt == sharesList.count {
return secretString
} else {
SentryUtils.captureException("\(TorusUtilError.interpolationFailed)")
throw TorusUtilError.interpolationFailed
}
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/TorusUtils/Helpers/MetadataUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ internal class MetadataUtils {
guard
let url = URL(string: url)
else {
SentryUtils.captureException("Invalid Url \(url)")
throw TorusUtilError.runtime("Invalid Url \(url)")
}
var rq = URLRequest(url: url)
Expand Down Expand Up @@ -103,6 +104,7 @@ internal class MetadataUtils {
if case .sapphire = network {
return try await getOrSetNonce(legacyMetadataHost: metadataHost, serverTimeOffset: serverTimeOffset ?? Int(trunc(Double(0 + Int(Date().timeIntervalSince1970)))), X: X, Y: Y, privateKey: privateKey, getOnly: getOnly, keyType: keyType)
} else {
SentryUtils.captureException("\(TorusUtilError.metadataNonceMissing)")
throw TorusUtilError.metadataNonceMissing
}
}
Expand Down
18 changes: 17 additions & 1 deletion Sources/TorusUtils/Helpers/NodeUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ internal class NodeUtils {
var importedShareCount = 0
if importedShares != nil && importedShares!.count > 0 {
if importedShares!.count != endpoints.count {
SentryUtils.captureException("\(TorusUtilError.importShareFailed)")
throw TorusUtilError.importShareFailed
}
isImportShareReq = true
Expand Down Expand Up @@ -214,6 +215,7 @@ internal class NodeUtils {
}

if importedShareCount > 0 && !(nodeSigs.count == endpoints.count) {
SentryUtils.captureException("\(TorusUtilError.commitmentRequestFailed)")
throw TorusUtilError.commitmentRequestFailed
}

Expand Down Expand Up @@ -286,6 +288,7 @@ internal class NodeUtils {
}

if isImportShareReq && !shareImportSuccess {
SentryUtils.captureException("\(TorusUtilError.importShareFailed)")
throw TorusUtilError.importShareFailed
}

Expand Down Expand Up @@ -364,6 +367,7 @@ internal class NodeUtils {
}

if thresholdPublicKey == nil {
SentryUtils.captureException("\(TorusUtilError.retrieveOrImportShareError)")
throw TorusUtilError.retrieveOrImportShareError
}

Expand Down Expand Up @@ -395,6 +399,7 @@ internal class NodeUtils {

// Invert comparision to return error early
if !(shareResponses.count >= thresholdReqCount && thresholdPublicKey != nil && (thresholdNonceData != nil || verifierParams.extended_verifier_id != nil || TorusUtils.isLegacyNetworkRouteMap(network: network))) {
SentryUtils.captureException("\(TorusUtilError.retrieveOrImportShareError)")
throw TorusUtilError.retrieveOrImportShareError
}

Expand Down Expand Up @@ -434,9 +439,11 @@ internal class NodeUtils {
let latestKey = item.keys[0]
nodeIndexes.append(latestKey.nodeIndex)
guard let cipherData = Data(base64Encoded: latestKey.share) else {
SentryUtils.captureException("cipher is not base64 encoded")
throw TorusUtilError.decodingFailed("cipher is not base64 encoded")
}
guard let cipherTextHex = String(data: cipherData, encoding: .utf8) else {
SentryUtils.captureException("cipher is not base64 encoded")
throw TorusUtilError.decodingFailed("cipherData is not utf8")
}
let decrypted = try MetadataUtils.decryptNodeData(eciesData: latestKey.shareMetadata, ciphertextHex: cipherTextHex, privKey: sessionAuthKeySerialized)
Expand All @@ -450,12 +457,14 @@ internal class NodeUtils {
let validSigs = sessionTokenSigs.filter({ $0 != nil }).map({ $0! })

if verifierParams.extended_verifier_id == nil && validSigs.count < threshold {
SentryUtils.captureException("\(TorusUtilError.retrieveOrImportShareError)")
throw TorusUtilError.retrieveOrImportShareError
}

let validTokens = sessionTokens.filter({ $0 != nil }).map({ $0! })

if verifierParams.extended_verifier_id == nil && validTokens.count < threshold {
SentryUtils.captureException("Insufficient number of signatures from nodes")
throw TorusUtilError.runtime("Insufficient number of signatures from nodes")
}

Expand Down Expand Up @@ -503,6 +512,7 @@ internal class NodeUtils {
}

if privateKey == nil {
SentryUtils.captureException("\(TorusUtilError.privateKeyDeriveFailed)")
throw TorusUtilError.privateKeyDeriveFailed
}

Expand Down Expand Up @@ -555,11 +565,13 @@ internal class NodeUtils {
finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPubKey, publicNonce])
pubNonce = PubNonce(x: thresholdNonceData!.pubNonce!.x, y: thresholdNonceData!.pubNonce!.y)
} else {
SentryUtils.captureException("\(TorusUtilError.pubNonceMissing)")
throw TorusUtilError.pubNonceMissing
}
}

if finalPubKey == nil {
SentryUtils.captureException("\(TorusUtilError.retrieveOrImportShareError)")
throw TorusUtilError.retrieveOrImportShareError
}

Expand All @@ -577,8 +589,10 @@ internal class NodeUtils {
// This is a sanity check to make doubly sure we are returning the correct private key after importing a share
if isImportShareReq {
if newPrivateKey == nil {
SentryUtils.captureException("\(TorusUtilError.importShareFailed)")
throw TorusUtilError.importShareFailed
} else if (!(finalPrivKey == newPrivateKey!.addLeading0sForLength64())) {
SentryUtils.captureException("\(TorusUtilError.importShareFailed)")
throw TorusUtilError.importShareFailed
}
}
Expand All @@ -587,7 +601,9 @@ internal class NodeUtils {
if typeOfUser == .v2 {
isUpgraded = metadataNonce == BigInt(0)
}


SentryUtils.logInformation(clientId: clientId, finalEvmAddress: finalEvmAddress, platform: "torus-utils-swift")

return TorusKey(
finalKeyData: TorusKey.FinalKeyData(
evmAddress: finalEvmAddress,
Expand Down
2 changes: 2 additions & 0 deletions Sources/TorusUtils/Point.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ internal struct Point: Codable {
if let xCoord = BigInt(x, radix: 16) {
self.x = xCoord
} else {
SentryUtils.captureException("\(TorusUtilError.invalidInput)")
throw TorusUtilError.invalidInput
}

if let yCoord = BigInt(y, radix: 16) {
self.y = yCoord
} else {
SentryUtils.captureException("\(TorusUtilError.invalidInput)")
throw TorusUtilError.invalidInput
}
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/TorusUtils/Share.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ internal class Share: Codable {
if let si = BigInt(shareIndex, radix: 16) {
self.shareIndex = si
} else {
SentryUtils.captureException("\(TorusUtilError.invalidInput)")
throw TorusUtilError.invalidInput
}

if let s = BigInt(share, radix: 16) {
self.share = s
} else {
SentryUtils.captureException("\(TorusUtilError.invalidInput)")
throw TorusUtilError.invalidInput
}
}
Expand Down
12 changes: 12 additions & 0 deletions Sources/TorusUtils/TorusUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import BigInt
import FetchNodeDetails
import Foundation
import OSLog
import Sentry
#if canImport(curveSecp256k1)
import curveSecp256k1
#endif
Expand Down Expand Up @@ -37,6 +38,7 @@ public class TorusUtils {
///
/// - Throws: `TorusUtilError.invalidInput`
public init(params: TorusOptions, loglevel: OSLogType = .default) throws {
SentryUtils.initSentry()
var defaultHost = ""
if params.legacyMetadataHost == nil {
if case let .legacy(urlHost) = params.network {
Expand All @@ -50,6 +52,7 @@ public class TorusUtils {
defaultHost = "https://node-1.dev-node.web3auth.io/metadata"
}
} else {
SentryUtils.captureException("\(TorusUtilError.invalidInput)")
throw TorusUtilError.invalidInput
}
}
Expand Down Expand Up @@ -176,6 +179,7 @@ public class TorusUtils {
) async throws -> TorusKey {
let nodePubs = TorusNodePubModelToINodePub(nodes: nodePubKeys)
if endpoints.count != nodeIndexes.count {
SentryUtils.captureException("Length of endpoints must be the same as length of nodeIndexes")
throw TorusUtilError.runtime("Length of endpoints must be the same as length of nodeIndexes")
}

Expand Down Expand Up @@ -214,17 +218,21 @@ public class TorusUtils {
if keyAssignResult.errorResult != nil {
let error = keyAssignResult.errorResult!.message
if error.lowercased().contains("verifier not supported") {
SentryUtils.captureException("Verifier not supported. Check if you: 1. Are on the right network (Torus testnet/mainnet) 2. Have setup a verifier on dashboard.web3auth.io?")
throw TorusUtilError.runtime("Verifier not supported. Check if you: 1. Are on the right network (Torus testnet/mainnet) 2. Have setup a verifier on dashboard.web3auth.io?")
} else {
SentryUtils.captureException(error)
throw TorusUtilError.runtime(error)
}
}

if keyAssignResult.keyResult == nil || keyAssignResult.keyResult?.keys.count == 0 {
SentryUtils.captureException("node results do not match at final lookup")
throw TorusUtilError.runtime("node results do not match at final lookup")
}

if keyAssignResult.nonceResult == nil && extendedVerifierId == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) {
SentryUtils.captureException("metadata nonce is missing in share response")
throw TorusUtilError.runtime("metadata nonce is missing in share response")
}

Expand Down Expand Up @@ -257,11 +265,13 @@ public class TorusUtils {
finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPubKey!, pubNonceKey])
pubNonce = pubNonceResult
} else {
SentryUtils.captureException("\(TorusUtilError.pubNonceMissing)")
throw TorusUtilError.pubNonceMissing
}
}

if oAuthPubKey == nil || finalPubKey == nil {
SentryUtils.captureException("\(TorusUtilError.privateKeyDeriveFailed)")
throw TorusUtilError.privateKeyDeriveFailed
}

Expand Down Expand Up @@ -329,6 +339,7 @@ public class TorusUtils {
finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPubKey, pubNonceKey])
pubNonce = nonceResult!.pubNonce!
} else {
SentryUtils.captureException("\(TorusUtilError.metadataNonceMissing)")
throw TorusUtilError.metadataNonceMissing
}
} else {
Expand All @@ -346,6 +357,7 @@ public class TorusUtils {
let oAuthAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: X, publicKeyY: Y)

if typeOfUser == .v2 && finalPubKey == nil {
SentryUtils.captureException("\(TorusUtilError.privateKeyDeriveFailed)")
throw TorusUtilError.privateKeyDeriveFailed
}

Expand Down
53 changes: 53 additions & 0 deletions Sources/TorusUtils/analytics/SentryUtils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// File.swift
//
//
// Created by Gaurav Goel on 16/09/24.
//

import Sentry

class SentryUtils {

static func initSentry() {
SentrySDK.start { options in
options.dsn = "https://[email protected]/4507961375195136"
options.debug = true
options.tracesSampleRate = 1.0
}
}


static func captureException(_ message: String) {
let error = NSError(domain: "torus-utils-swift", code: 0, userInfo: [NSLocalizedDescriptionKey: message])
SentrySDK.capture(error: error)
}


static func addBreadcrumb(message: String) {
let breadcrumb = Breadcrumb()
breadcrumb.message = message
breadcrumb.category = "custom"
SentrySDK.addBreadcrumb(breadcrumb)
}

// Static method to log information by setting tags
static func logInformation(clientId: String, finalEvmAddress: String, platform: String) {
SentrySDK.configureScope { scope in
scope.setTag(value: clientId, key: "clientId")
scope.setTag(value: finalEvmAddress, key: "finalEvmAddress")
scope.setTag(value: platform, key: "platform")
}
}

static func setContext(key: String, value: String) {
SentrySDK.configureScope { scope in
scope.setExtra(value: value, key: key)
}
}

static func close() {
SentrySDK.close()
}
}