field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | LICENSE

FieldBackgroundExecutionUITestProbe.swift (5255B)


      1 import Foundation
      2 import RadrootsKit
      3 
      4 enum FieldBackgroundExecutionUITestProbe {
      5     private static let enabledKey = "RADROOTS_FIELD_IOS_UI_TEST_BACKGROUND_EXECUTION_PROBE"
      6     private static let redactionPolicy = RadrootsTelemetryRedactionPolicy.default
      7 
      8     static var isRequested: Bool {
      9         ProcessInfo.processInfo.environment[enabledKey] == "true"
     10     }
     11 
     12     static func value(
     13         registered: Bool,
     14         scheduledTaskCount: Int,
     15         pendingBeforeMaintenance: Int,
     16         pendingBeforeCancel: Int,
     17         pendingAfterCancel: Int,
     18         cancellationObserved: Bool,
     19         stagedBlobRemoved: Bool,
     20         transferSnapshotCount: Int,
     21         events: [RadrootsTelemetryEvent]
     22     ) -> String {
     23         let eventNames = Set(events.map(\.name))
     24         let values = events.flatMap(stringValues)
     25         return [
     26             "registered=\(registered)",
     27             "scheduled_task_count=\(scheduledTaskCount)",
     28             "schedule_observed=\(scheduledTaskCount >= 2)",
     29             "pending_before_maintenance=\(pendingBeforeMaintenance)",
     30             "pending_before_cancel=\(pendingBeforeCancel)",
     31             "pending_after_cancel=\(pendingAfterCancel)",
     32             "cancellation_observed=\(cancellationObserved)",
     33             "staged_blob_removed=\(stagedBlobRemoved)",
     34             "transfer_snapshot_count=\(transferSnapshotCount)",
     35             "background_register_seen=\(eventNames.contains("field_ios.background_execution.handler_registration"))",
     36             "background_schedule_seen=\(eventNames.contains("field_ios.background_execution.schedule"))",
     37             "background_cancel_all_seen=\(eventNames.contains("field_ios.background_execution.cancel_all"))",
     38             "background_transfer_inspect_seen=\(eventNames.contains("field_ios.background_execution.transfer_inspect"))",
     39             "background_staged_blob_sweep_seen=\(eventNames.contains("field_ios.background_execution.staged_blob_sweep"))",
     40             "background_relay_refresh_seen=\(eventNames.contains("field_ios.background_execution.relay_refresh"))",
     41             "background_maintenance_seen=\(eventNames.contains("field_ios.background_execution.maintenance"))",
     42             "unsafe_values_present=\(values.contains(where: containsUnsafeValue))",
     43             "relay_url_values_present=\(values.contains(where: containsRelayURL))",
     44             "secret_like_values_present=\(values.contains(where: containsSecretLikeValue))",
     45             "path_like_values_present=\(values.contains(where: containsPathLikeValue))",
     46             "npub_values_present=\(values.contains(where: containsNpubValue))"
     47         ].joined(separator: ";")
     48     }
     49 
     50     static func failureValue(outcome: String) -> String {
     51         [
     52             "registered=false",
     53             "scheduled_task_count=0",
     54             "schedule_observed=false",
     55             "pending_before_maintenance=0",
     56             "pending_before_cancel=0",
     57             "pending_after_cancel=0",
     58             "cancellation_observed=false",
     59             "staged_blob_removed=false",
     60             "transfer_snapshot_count=0",
     61             "background_register_seen=false",
     62             "background_schedule_seen=false",
     63             "background_cancel_all_seen=false",
     64             "background_transfer_inspect_seen=false",
     65             "background_staged_blob_sweep_seen=false",
     66             "background_relay_refresh_seen=false",
     67             "background_maintenance_seen=false",
     68             "probe_failure_outcome=\(outcome)",
     69             "unsafe_values_present=false",
     70             "relay_url_values_present=false",
     71             "secret_like_values_present=false",
     72             "path_like_values_present=false",
     73             "npub_values_present=false"
     74         ].joined(separator: ";")
     75     }
     76 
     77     private static func stringValues(from event: RadrootsTelemetryEvent) -> [String] {
     78         var values = event.message.map { [$0] } ?? []
     79         values.append(contentsOf: event.fields.map { field in
     80             field.value.renderedValue
     81         })
     82         return values
     83     }
     84 
     85     private static func containsUnsafeValue(_ value: String) -> Bool {
     86         redactionPolicy.containsUnsafeValue(value)
     87             || containsRelayURL(value)
     88             || containsSecretLikeValue(value)
     89             || containsPathLikeValue(value)
     90             || containsNpubValue(value)
     91     }
     92 
     93     private static func containsRelayURL(_ value: String) -> Bool {
     94         let normalized = value.lowercased()
     95         return normalized.contains("ws://") || normalized.contains("wss://")
     96     }
     97 
     98     private static func containsSecretLikeValue(_ value: String) -> Bool {
     99         let normalized = value.lowercased()
    100         return normalized.contains("nsec")
    101             || normalized.range(of: "[a-f0-9]{64}", options: .regularExpression) != nil
    102     }
    103 
    104     private static func containsPathLikeValue(_ value: String) -> Bool {
    105         let normalized = value.lowercased()
    106         return normalized.contains("/users/")
    107             || normalized.contains("/private/var/")
    108             || normalized.contains("/var/mobile/containers/")
    109             || normalized.contains("/var/folders/")
    110             || normalized.contains("file:///")
    111     }
    112 
    113     private static func containsNpubValue(_ value: String) -> Bool {
    114         value.lowercased().contains("npub")
    115     }
    116 }