// _____ _ // |_ _| |_ _ _ ___ ___ _ __ __ _ // | | | ' \| '_/ -_) -_) ' \/ _` |_ // |_| |_||_|_| \___\___|_|_|_\__,_(_) // // Threema iOS Client // Copyright (c) 2019-2020 Threema GmbH // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License, version 3, // as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import Foundation import CocoaLumberjackSwift import Sentry @objc class SentryClient: NSObject { private static let sentryNotEnabled = "SENTRY_NOT_ENABLED" @objc override init() { super.init() } /** Create Sentry and start crash handler. - Parameters: - rootViewController: Parent view controller */ @objc func start(rootViewController: UIViewController?) { guard SentryClient.isEnabled(), let sentryDsn = BundleUtil.object(forInfoDictionaryKey: "SentryClientDsn") as? String else { return } do { let options = try Sentry.Options(dict: ["dsn": sentryDsn]) options.beforeSend = { event in if let appDevice = event.context?["app"]?["device_app_hash"] as? String { // Save anonymous app device, it will be displayed under Settings - Advanced UserSettings.shared()?.sentryAppDevice = appDevice // Send app device hash to count users per event on sentry ui let user = User(userId: appDevice) event.user = user } if event.exceptions?.first?.value != nil { event.exceptions?.first?.value = self.redact(exceptionDescription: event.exceptions!.first!.value) } var send: Bool = false let dispatch = DispatchGroup() dispatch.enter() DispatchQueue.main.async { let confirm = UIAlertController(title: String(format: BundleUtil.localizedString(forKey: "sentry_crash_send_title"), "Threema"), message: BundleUtil.localizedString(forKey: "sentry_crash_send_description"), preferredStyle: .alert) confirm.addTextField { (textField) in textField.placeholder = BundleUtil.localizedString(forKey: "sentry_crash_comment_placeholder") } confirm.addAction(UIAlertAction(title: BundleUtil.localizedString(forKey: "sentry_crash_send_yes"), style: .default, handler: { (a) -> Void in if let textField = confirm.textFields?.first { event.message = textField.text ?? "" } send = true dispatch.leave() })) confirm.addAction(UIAlertAction(title: BundleUtil.localizedString(forKey: "sentry_crash_send_no"), style: .cancel, handler: { (a) -> Void in dispatch.leave() })) if let vc = rootViewController { DispatchQueue.main.async { vc.present(confirm, animated: true, completion: nil) } } else { dispatch.leave() } } dispatch.wait() if send { return event } return nil } SentrySDK.start(options: options) } catch { DDLogError("Could not start Sentry!") } } private func redact(exceptionDescription : String) -> String { let keys = ["encryptionKey", "k:", "password", "blobId", "blobThumbnailId", "\"k\""] var linesArray = exceptionDescription.linesArray for i in 0.. start Sentry crash handler */ private static func isEnabled() -> Bool { return !FileUtility.isExists(fileUrl: FileUtility.appDocumentsDirectory?.appendingPathComponent(sentryNotEnabled)) } }