mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 23:05:20 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8887e7318 | ||
|
|
63918bfebc | ||
|
|
b30a30ecce |
@@ -33,7 +33,6 @@
|
|||||||
0481A3472E6D869F00FC845E /* TorURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3442E6D869F00FC845E /* TorURLSession.swift */; };
|
0481A3472E6D869F00FC845E /* TorURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3442E6D869F00FC845E /* TorURLSession.swift */; };
|
||||||
0481A3482E6D869F00FC845E /* TorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3432E6D869F00FC845E /* TorManager.swift */; };
|
0481A3482E6D869F00FC845E /* TorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3432E6D869F00FC845E /* TorManager.swift */; };
|
||||||
0481A3492E6D869F00FC845E /* TorURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3442E6D869F00FC845E /* TorURLSession.swift */; };
|
0481A3492E6D869F00FC845E /* TorURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3442E6D869F00FC845E /* TorURLSession.swift */; };
|
||||||
|
|
||||||
0481A35B2E6D9BEF00FC845E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0481A35A2E6D9BEF00FC845E /* libz.tbd */; };
|
0481A35B2E6D9BEF00FC845E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0481A35A2E6D9BEF00FC845E /* libz.tbd */; };
|
||||||
0481A35D2E6DA18600FC845E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0481A35C2E6DA18600FC845E /* libz.tbd */; };
|
0481A35D2E6DA18600FC845E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0481A35C2E6DA18600FC845E /* libz.tbd */; };
|
||||||
0481A3902E734CAE00FC845E /* CommandProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A38F2E734CAE00FC845E /* CommandProcessorTests.swift */; };
|
0481A3902E734CAE00FC845E /* CommandProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A38F2E734CAE00FC845E /* CommandProcessorTests.swift */; };
|
||||||
@@ -383,7 +382,6 @@
|
|||||||
0481A39F2E744D6300FC845E /* tor-nolzma.xcframework */,
|
0481A39F2E744D6300FC845E /* tor-nolzma.xcframework */,
|
||||||
0481A35A2E6D9BEF00FC845E /* libz.tbd */,
|
0481A35A2E6D9BEF00FC845E /* libz.tbd */,
|
||||||
0481A35C2E6DA18600FC845E /* libz.tbd */,
|
0481A35C2E6DA18600FC845E /* libz.tbd */,
|
||||||
|
|
||||||
);
|
);
|
||||||
path = Frameworks;
|
path = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -815,7 +813,10 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
<<<<<<< Updated upstream
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> Stashed changes
|
||||||
7DD72D928FF9DD3CA81B46B0 /* Assets.xcassets in Resources */,
|
7DD72D928FF9DD3CA81B46B0 /* Assets.xcassets in Resources */,
|
||||||
E0A1B2C3D4E5F6012345678D /* relays/online_relays_gps.csv in Resources */,
|
E0A1B2C3D4E5F6012345678D /* relays/online_relays_gps.csv in Resources */,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -86,6 +86,38 @@ final class SecureLogger {
|
|||||||
return level.order >= minimumLevel.order
|
return level.order >= minimumLevel.order
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - In-memory debug buffer (DEBUG builds only)
|
||||||
|
#if DEBUG
|
||||||
|
private static let logBufferQueue = DispatchQueue(label: "chat.bitchat.securelogger.buffer")
|
||||||
|
private static var logBuffer: [String] = []
|
||||||
|
private static let logBufferCap: Int = 2000
|
||||||
|
|
||||||
|
/// Append a sanitized line to the in-memory debug buffer
|
||||||
|
private static func record(_ line: String) {
|
||||||
|
logBufferQueue.async {
|
||||||
|
logBuffer.append(line)
|
||||||
|
if logBuffer.count > logBufferCap {
|
||||||
|
logBuffer.removeFirst(logBuffer.count - logBufferCap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current logs as an array (oldest first)
|
||||||
|
static func getLogs() -> [String] {
|
||||||
|
return logBufferQueue.sync { logBuffer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current logs as a single string
|
||||||
|
static func getLogText() -> String {
|
||||||
|
return getLogs().joined(separator: "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the in-memory debug buffer
|
||||||
|
static func clearLogs() {
|
||||||
|
logBufferQueue.async { logBuffer.removeAll(keepingCapacity: false) }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// MARK: - Security Event Types
|
// MARK: - Security Event Types
|
||||||
|
|
||||||
enum SecurityEvent {
|
enum SecurityEvent {
|
||||||
@@ -159,7 +191,9 @@ final class SecureLogger {
|
|||||||
let errorDesc = sanitize(error.localizedDescription)
|
let errorDesc = sanitize(error.localizedDescription)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
os_log("%{public}@ Error in %{public}@: %{public}@", log: category, type: .error, location, sanitized, errorDesc)
|
let line = "\(location) Error: \(sanitized) — \(errorDesc)"
|
||||||
|
os_log("%{public}@", log: category, type: .error, line)
|
||||||
|
record(line)
|
||||||
#else
|
#else
|
||||||
os_log("%{private}@ Error in %{private}@: %{private}@", log: category, type: .error, location, sanitized, errorDesc)
|
os_log("%{private}@ Error in %{private}@: %{private}@", log: category, type: .error, location, sanitized, errorDesc)
|
||||||
#endif
|
#endif
|
||||||
@@ -203,6 +237,7 @@ private extension SecureLogger {
|
|||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
os_log("%{public}@", log: category, type: level.osLogType, sanitized)
|
os_log("%{public}@", log: category, type: level.osLogType, sanitized)
|
||||||
|
record(sanitized)
|
||||||
#else
|
#else
|
||||||
// In release builds, only log non-debug messages
|
// In release builds, only log non-debug messages
|
||||||
if level != .debug {
|
if level != .debug {
|
||||||
@@ -220,6 +255,7 @@ private extension SecureLogger {
|
|||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
os_log("%{public}@", log: .security, type: level.osLogType, message)
|
os_log("%{public}@", log: .security, type: level.osLogType, message)
|
||||||
|
record(message)
|
||||||
#else
|
#else
|
||||||
// In release, use private logging to prevent sensitive data exposure
|
// In release, use private logging to prevent sensitive data exposure
|
||||||
os_log("%{private}@", log: .security, type: level.osLogType, message)
|
os_log("%{private}@", log: .security, type: level.osLogType, message)
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
#if os(iOS)
|
||||||
|
import UIKit
|
||||||
|
#elseif os(macOS)
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
|
|
||||||
struct AppInfoView: View {
|
struct AppInfoView: View {
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
@@ -191,12 +196,77 @@ struct AppInfoView: View {
|
|||||||
.background(Color.red.opacity(0.1))
|
.background(Color.red.opacity(0.1))
|
||||||
.cornerRadius(8)
|
.cornerRadius(8)
|
||||||
|
|
||||||
.padding(.top)
|
#if DEBUG
|
||||||
|
// Debug section (visible only in Debug builds)
|
||||||
|
DebugLogsSection(textColor: textColor, secondaryTextColor: secondaryTextColor)
|
||||||
|
.padding(.top)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private struct DebugLogsSection: View {
|
||||||
|
let textColor: Color
|
||||||
|
let secondaryTextColor: Color
|
||||||
|
@State private var logsText: String = SecureLogger.getLogText()
|
||||||
|
private let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
|
SectionHeader("DEBUG")
|
||||||
|
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Button {
|
||||||
|
copyToPasteboard(logsText)
|
||||||
|
} label: {
|
||||||
|
Text("copy logs")
|
||||||
|
.font(.system(size: 14, design: .monospaced))
|
||||||
|
.foregroundColor(textColor)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
SecureLogger.clearLogs()
|
||||||
|
logsText = ""
|
||||||
|
} label: {
|
||||||
|
Text("clear logs")
|
||||||
|
.font(.system(size: 14, design: .monospaced))
|
||||||
|
.foregroundColor(textColor)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
Text(logsText.isEmpty ? "(no logs)" : logsText)
|
||||||
|
.font(.system(size: 12, design: .monospaced))
|
||||||
|
.foregroundColor(secondaryTextColor)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.textSelection(.enabled)
|
||||||
|
.padding(8)
|
||||||
|
}
|
||||||
|
.frame(minHeight: 180)
|
||||||
|
.background(secondaryTextColor.opacity(0.08))
|
||||||
|
.cornerRadius(8)
|
||||||
|
}
|
||||||
|
.onReceive(timer) { _ in
|
||||||
|
logsText = SecureLogger.getLogText()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func copyToPasteboard(_ text: String) {
|
||||||
|
#if os(iOS)
|
||||||
|
UIPasteboard.general.string = text
|
||||||
|
#elseif os(macOS)
|
||||||
|
let pb = NSPasteboard.general
|
||||||
|
pb.clearContents()
|
||||||
|
pb.setString(text, forType: .string)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct SectionHeader: View {
|
struct SectionHeader: View {
|
||||||
let title: String
|
let title: String
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|||||||
Reference in New Issue
Block a user