Merge pull request #938 from meshtastic/key-mismatch-logging

Key mismatch logging
This commit is contained in:
Garth Vander Houwen 2024-09-22 07:14:59 -07:00 committed by GitHub
commit ba7a3899d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 174 additions and 47 deletions

View file

@ -14574,7 +14574,7 @@
"Message" : {
},
"Message content exceeds 228 bytes." : {
"Message content exceeds 200 bytes." : {
},
"Message Status Options" : {

View file

@ -1687,7 +1687,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.5.5;
MARKETING_VERSION = 2.5.6;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -1722,7 +1722,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.5.5;
MARKETING_VERSION = 2.5.6;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -1754,7 +1754,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.5.5;
MARKETING_VERSION = 2.5.6;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1787,7 +1787,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.5.5;
MARKETING_VERSION = 2.5.6;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View file

@ -38,8 +38,8 @@ struct MessageChannelIntent: AppIntent {
throw AppIntentErrors.AppIntentError.message("Failed to encode message content")
}
if messageData.count > 228 {
throw $messageContent.needsValueError("Message content exceeds 228 bytes.")
if messageData.count > 200 {
throw $messageContent.needsValueError("Message content exceeds 200 bytes.")
}
if(!BLEManager.shared.sendMessage(message: messageContent, toUserNum: 0, channel: Int32(channelNumber), isEmoji: false, replyID: 0)){

View file

@ -24,6 +24,8 @@ enum RoutingError: Int, CaseIterable, Identifiable {
case notAuthorized = 33
case pkiFailed = 34
case pkiUnknownPubkey = 35
case adminBadSessionKey = 36
case adminPublicKeyUnauthorized = 37
var id: Int { self.rawValue }
var display: String {
@ -57,6 +59,10 @@ enum RoutingError: Int, CaseIterable, Identifiable {
return "routing.pkifailed".localized
case .pkiUnknownPubkey:
return "routing.pkiunknownpubkey".localized
case .adminBadSessionKey:
return "routing.adminbadsessionkey".localized
case .adminPublicKeyUnauthorized:
return "routing.adminpublickeyunauthorized".localized
}
}
var color: Color {
@ -97,7 +103,11 @@ enum RoutingError: Int, CaseIterable, Identifiable {
case .pkiFailed:
return true
case .pkiUnknownPubkey:
return false
return true
case .adminBadSessionKey:
return true
case .adminPublicKeyUnauthorized:
return true
}
}
func protoEnumValue() -> Routing.Error {
@ -132,6 +142,10 @@ enum RoutingError: Int, CaseIterable, Identifiable {
return Routing.Error.pkiFailed
case .pkiUnknownPubkey:
return Routing.Error.pkiUnknownPubkey
case .adminBadSessionKey:
return Routing.Error.adminBadSessionKey
case .adminPublicKeyUnauthorized:
return Routing.Error.adminPublicKeyUnauthorized
}
}
}

View file

@ -827,7 +827,7 @@ func textMessageAppPacket(
}
}
let rangeTest = messageText?.contains(rangeTestRegex) ?? false && messageText?.starts(with: "seq ") ?? false
if !wantRangeTestPackets && rangeTest {
return
}
@ -840,16 +840,13 @@ func textMessageAppPacket(
}
}
}
if messageText?.count ?? 0 > 0 {
MeshLogger.log("💬 \("mesh.log.textmessage.received".localized)")
let messageUsers = UserEntity.fetchRequest()
messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from])
do {
let fetchedUsers = try context.fetch(messageUsers)
let newMessage = MessageEntity(context: context)
newMessage.messageId = Int64(packet.id)
if packet.rxTime > 0 {
@ -863,60 +860,56 @@ func textMessageAppPacket(
newMessage.isEmoji = packet.decoded.emoji == 1
newMessage.channel = Int32(packet.channel)
newMessage.portNum = Int32(packet.decoded.portnum.rawValue)
if newMessage.toUser?.pkiEncrypted ?? false {
newMessage.pkiEncrypted = true
newMessage.publicKey = packet.publicKey
}
if packet.decoded.portnum == PortNum.detectionSensorApp {
if !UserDefaults.enableDetectionNotifications {
newMessage.read = true
}
}
if packet.decoded.replyID > 0 {
newMessage.replyID = Int64(packet.decoded.replyID)
}
if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != Constants.maximumNodeNum {
if !storeForwardBroadcast {
newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to })
}
}
if fetchedUsers.first(where: { $0.num == packet.from }) != nil {
newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from })
if !(newMessage.fromUser?.publicKey?.isEmpty ?? true) && newMessage.toUser != nil && packet.pkiEncrypted {
// We have a key and it is a PKC encrypted DM, check if it matches
if newMessage.fromUser?.publicKey != newMessage.publicKey {
newMessage.fromUser?.keyMatch = false
newMessage.fromUser?.newPublicKey = newMessage.publicKey
Logger.data.error("🔑 Key Mismatch origninal key: \(newMessage.fromUser?.publicKey?.base64EncodedString() ?? "No Key") new key: \(newMessage.fromUser?.newPublicKey?.base64EncodedString() ?? "No Key") ")
/// Set the public key for the message
if newMessage.fromUser?.pkiEncrypted ?? false {
newMessage.pkiEncrypted = true
newMessage.publicKey = packet.publicKey
}
/// Check for key mismatch
if let nodeKey = newMessage.fromUser?.publicKey {
if newMessage.toUser != nil && packet.pkiEncrypted && !packet.publicKey.isEmpty {
if nodeKey != newMessage.publicKey {
newMessage.fromUser?.keyMatch = false
newMessage.fromUser?.newPublicKey = newMessage.publicKey
let nodeKey = String(nodeKey.base64EncodedString()).prefix(8)
let messageKey = String(newMessage.publicKey?.base64EncodedString() ?? "No Key").prefix(8)
Logger.data.error("🔑 Key mismatch original key: \(nodeKey, privacy: .public) . . . new key: \(messageKey, privacy: .public) . . .")
}
}
} else {
} else if packet.pkiEncrypted {
/// We have no key, set it if it is not empty
if !packet.publicKey.isEmpty {
newMessage.fromUser?.pkiEncrypted = true
newMessage.fromUser?.publicKey = packet.publicKey
}
}
if packet.rxTime > 0 {
newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime)))
} else {
newMessage.fromUser?.userNode?.lastHeard = Date()
}
}
newMessage.messagePayload = messageText
newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText!)
if packet.to != Constants.maximumNodeNum && newMessage.fromUser != nil {
newMessage.fromUser?.lastMessage = Date()
}
var messageSaved = false
do {
try context.save()
Logger.data.info("💾 Saved a new message for \(newMessage.messageId)")

View file

@ -30,7 +30,7 @@ struct MessageText: View {
.background(isCurrentUser ? .accentColor : Color(.gray))
.cornerRadius(15)
.overlay {
if message.pkiEncrypted {
if message.pkiEncrypted && message.ackError == 0 && message.realACK {
VStack(alignment: .trailing) {
Spacer()
HStack {

View file

@ -2,7 +2,7 @@ import SwiftUI
import OSLog
struct TextMessageField: View {
static let maxbytes = 228
static let maxbytes = 200
@EnvironmentObject var bleManager: BLEManager
let destination: MessageDestination

View file

@ -15,6 +15,6 @@ struct TextMessageSize: View {
struct TextMessageSizePreview: PreviewProvider {
static var previews: some View {
TextMessageSize(maxbytes: 228, totalBytes: 100)
TextMessageSize(maxbytes: 200, totalBytes: 100)
}
}

View file

@ -322,6 +322,17 @@ public struct TAKPacket {
set {payloadVariant = .chat(newValue)}
}
///
/// Generic CoT detail XML
/// May be compressed / truncated by the sender
public var detail: Data {
get {
if case .detail(let v)? = payloadVariant {return v}
return Data()
}
set {payloadVariant = .detail(newValue)}
}
public var unknownFields = SwiftProtobuf.UnknownStorage()
///
@ -333,6 +344,10 @@ public struct TAKPacket {
///
/// ATAK GeoChat message
case chat(GeoChat)
///
/// Generic CoT detail XML
/// May be compressed / truncated by the sender
case detail(Data)
#if !swift(>=4.1)
public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool {
@ -348,6 +363,10 @@ public struct TAKPacket {
guard case .chat(let l) = lhs, case .chat(let r) = rhs else { preconditionFailure() }
return l == r
}()
case (.detail, .detail): return {
guard case .detail(let l) = lhs, case .detail(let r) = rhs else { preconditionFailure() }
return l == r
}()
default: return false
}
}
@ -555,6 +574,7 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
4: .same(proto: "status"),
5: .same(proto: "pli"),
6: .same(proto: "chat"),
7: .same(proto: "detail"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -593,6 +613,14 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
self.payloadVariant = .chat(v)
}
}()
case 7: try {
var v: Data?
try decoder.decodeSingularBytesField(value: &v)
if let v = v {
if self.payloadVariant != nil {try decoder.handleConflictingOneOf()}
self.payloadVariant = .detail(v)
}
}()
default: break
}
}
@ -624,6 +652,10 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
guard case .chat(let v)? = self.payloadVariant else { preconditionFailure() }
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
}()
case .detail?: try {
guard case .detail(let v)? = self.payloadVariant else { preconditionFailure() }
try visitor.visitSingularBytesField(value: v, fieldNumber: 7)
}()
case nil: break
}
try unknownFields.traverse(visitor: &visitor)

View file

@ -83,6 +83,39 @@ public struct DeviceProfile {
/// Clears the value of `moduleConfig`. Subsequent reads from it will return its default value.
public mutating func clearModuleConfig() {self._moduleConfig = nil}
///
/// Fixed position data
public var fixedPosition: Position {
get {return _fixedPosition ?? Position()}
set {_fixedPosition = newValue}
}
/// Returns true if `fixedPosition` has been explicitly set.
public var hasFixedPosition: Bool {return self._fixedPosition != nil}
/// Clears the value of `fixedPosition`. Subsequent reads from it will return its default value.
public mutating func clearFixedPosition() {self._fixedPosition = nil}
///
/// Ringtone for ExternalNotification
public var ringtone: String {
get {return _ringtone ?? String()}
set {_ringtone = newValue}
}
/// Returns true if `ringtone` has been explicitly set.
public var hasRingtone: Bool {return self._ringtone != nil}
/// Clears the value of `ringtone`. Subsequent reads from it will return its default value.
public mutating func clearRingtone() {self._ringtone = nil}
///
/// Predefined messages for CannedMessage
public var cannedMessages: String {
get {return _cannedMessages ?? String()}
set {_cannedMessages = newValue}
}
/// Returns true if `cannedMessages` has been explicitly set.
public var hasCannedMessages: Bool {return self._cannedMessages != nil}
/// Clears the value of `cannedMessages`. Subsequent reads from it will return its default value.
public mutating func clearCannedMessages() {self._cannedMessages = nil}
public var unknownFields = SwiftProtobuf.UnknownStorage()
public init() {}
@ -92,6 +125,9 @@ public struct DeviceProfile {
fileprivate var _channelURL: String? = nil
fileprivate var _config: LocalConfig? = nil
fileprivate var _moduleConfig: LocalModuleConfig? = nil
fileprivate var _fixedPosition: Position? = nil
fileprivate var _ringtone: String? = nil
fileprivate var _cannedMessages: String? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -110,6 +146,9 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
3: .standard(proto: "channel_url"),
4: .same(proto: "config"),
5: .standard(proto: "module_config"),
6: .standard(proto: "fixed_position"),
7: .same(proto: "ringtone"),
8: .standard(proto: "canned_messages"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -123,6 +162,9 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
case 3: try { try decoder.decodeSingularStringField(value: &self._channelURL) }()
case 4: try { try decoder.decodeSingularMessageField(value: &self._config) }()
case 5: try { try decoder.decodeSingularMessageField(value: &self._moduleConfig) }()
case 6: try { try decoder.decodeSingularMessageField(value: &self._fixedPosition) }()
case 7: try { try decoder.decodeSingularStringField(value: &self._ringtone) }()
case 8: try { try decoder.decodeSingularStringField(value: &self._cannedMessages) }()
default: break
}
}
@ -148,6 +190,15 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
try { if let v = self._moduleConfig {
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
} }()
try { if let v = self._fixedPosition {
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
} }()
try { if let v = self._ringtone {
try visitor.visitSingularStringField(value: v, fieldNumber: 7)
} }()
try { if let v = self._cannedMessages {
try visitor.visitSingularStringField(value: v, fieldNumber: 8)
} }()
try unknownFields.traverse(visitor: &visitor)
}
@ -157,6 +208,9 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
if lhs._channelURL != rhs._channelURL {return false}
if lhs._config != rhs._config {return false}
if lhs._moduleConfig != rhs._moduleConfig {return false}
if lhs._fixedPosition != rhs._fixedPosition {return false}
if lhs._ringtone != rhs._ringtone {return false}
if lhs._cannedMessages != rhs._cannedMessages {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View file

@ -235,9 +235,13 @@ public struct NodeInfoLite {
///
/// Number of hops away from us this node is (0 if adjacent)
public var hopsAway: UInt32 {
get {return _storage._hopsAway}
get {return _storage._hopsAway ?? 0}
set {_uniqueStorage()._hopsAway = newValue}
}
/// Returns true if `hopsAway` has been explicitly set.
public var hasHopsAway: Bool {return _storage._hopsAway != nil}
/// Clears the value of `hopsAway`. Subsequent reads from it will return its default value.
public mutating func clearHopsAway() {_uniqueStorage()._hopsAway = nil}
///
/// True if node is in our favorites list
@ -620,7 +624,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
var _deviceMetrics: DeviceMetrics? = nil
var _channel: UInt32 = 0
var _viaMqtt: Bool = false
var _hopsAway: UInt32 = 0
var _hopsAway: UInt32? = nil
var _isFavorite: Bool = false
#if swift(>=5.10)
@ -710,9 +714,9 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
if _storage._viaMqtt != false {
try visitor.visitSingularBoolField(value: _storage._viaMqtt, fieldNumber: 8)
}
if _storage._hopsAway != 0 {
try visitor.visitSingularUInt32Field(value: _storage._hopsAway, fieldNumber: 9)
}
try { if let v = _storage._hopsAway {
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 9)
} }()
if _storage._isFavorite != false {
try visitor.visitSingularBoolField(value: _storage._isFavorite, fieldNumber: 10)
}

View file

@ -1416,6 +1416,14 @@ public struct Routing {
///
/// The receiving node does not have a Public Key to decode with
case pkiUnknownPubkey // = 35
///
/// Admin packet otherwise checks out, but uses a bogus or expired session key
case adminBadSessionKey // = 36
///
/// Admin packet sent using PKC, but not from a public key on the admin key list
case adminPublicKeyUnauthorized // = 37
case UNRECOGNIZED(Int)
public init() {
@ -1438,6 +1446,8 @@ public struct Routing {
case 33: self = .notAuthorized
case 34: self = .pkiFailed
case 35: self = .pkiUnknownPubkey
case 36: self = .adminBadSessionKey
case 37: self = .adminPublicKeyUnauthorized
default: self = .UNRECOGNIZED(rawValue)
}
}
@ -1458,6 +1468,8 @@ public struct Routing {
case .notAuthorized: return 33
case .pkiFailed: return 34
case .pkiUnknownPubkey: return 35
case .adminBadSessionKey: return 36
case .adminPublicKeyUnauthorized: return 37
case .UNRECOGNIZED(let i): return i
}
}
@ -1486,6 +1498,8 @@ extension Routing.Error: CaseIterable {
.notAuthorized,
.pkiFailed,
.pkiUnknownPubkey,
.adminBadSessionKey,
.adminPublicKeyUnauthorized,
]
}
@ -2167,9 +2181,13 @@ public struct NodeInfo {
///
/// Number of hops away from us this node is (0 if adjacent)
public var hopsAway: UInt32 {
get {return _storage._hopsAway}
get {return _storage._hopsAway ?? 0}
set {_uniqueStorage()._hopsAway = newValue}
}
/// Returns true if `hopsAway` has been explicitly set.
public var hasHopsAway: Bool {return _storage._hopsAway != nil}
/// Clears the value of `hopsAway`. Subsequent reads from it will return its default value.
public mutating func clearHopsAway() {_uniqueStorage()._hopsAway = nil}
///
/// True if node is in our favorites list
@ -2997,6 +3015,10 @@ public struct DeviceMetadata {
/// Has Remote Hardware enabled
public var hasRemoteHardware_p: Bool = false
///
/// Has PKC capabilities
public var hasPkc_p: Bool = false
public var unknownFields = SwiftProtobuf.UnknownStorage()
public init() {}
@ -3818,6 +3840,8 @@ extension Routing.Error: SwiftProtobuf._ProtoNameProviding {
33: .same(proto: "NOT_AUTHORIZED"),
34: .same(proto: "PKI_FAILED"),
35: .same(proto: "PKI_UNKNOWN_PUBKEY"),
36: .same(proto: "ADMIN_BAD_SESSION_KEY"),
37: .same(proto: "ADMIN_PUBLIC_KEY_UNAUTHORIZED"),
]
}
@ -4326,7 +4350,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
var _deviceMetrics: DeviceMetrics? = nil
var _channel: UInt32 = 0
var _viaMqtt: Bool = false
var _hopsAway: UInt32 = 0
var _hopsAway: UInt32? = nil
var _isFavorite: Bool = false
#if swift(>=5.10)
@ -4416,9 +4440,9 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
if _storage._viaMqtt != false {
try visitor.visitSingularBoolField(value: _storage._viaMqtt, fieldNumber: 8)
}
if _storage._hopsAway != 0 {
try visitor.visitSingularUInt32Field(value: _storage._hopsAway, fieldNumber: 9)
}
try { if let v = _storage._hopsAway {
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 9)
} }()
if _storage._isFavorite != false {
try visitor.visitSingularBoolField(value: _storage._isFavorite, fieldNumber: 10)
}
@ -5281,6 +5305,7 @@ extension DeviceMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
8: .standard(proto: "position_flags"),
9: .standard(proto: "hw_model"),
10: .same(proto: "hasRemoteHardware"),
11: .same(proto: "hasPKC"),
]
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -5299,6 +5324,7 @@ extension DeviceMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
case 8: try { try decoder.decodeSingularUInt32Field(value: &self.positionFlags) }()
case 9: try { try decoder.decodeSingularEnumField(value: &self.hwModel) }()
case 10: try { try decoder.decodeSingularBoolField(value: &self.hasRemoteHardware_p) }()
case 11: try { try decoder.decodeSingularBoolField(value: &self.hasPkc_p) }()
default: break
}
}
@ -5335,6 +5361,9 @@ extension DeviceMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
if self.hasRemoteHardware_p != false {
try visitor.visitSingularBoolField(value: self.hasRemoteHardware_p, fieldNumber: 10)
}
if self.hasPkc_p != false {
try visitor.visitSingularBoolField(value: self.hasPkc_p, fieldNumber: 11)
}
try unknownFields.traverse(visitor: &visitor)
}
@ -5349,6 +5378,7 @@ extension DeviceMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
if lhs.positionFlags != rhs.positionFlags {return false}
if lhs.hwModel != rhs.hwModel {return false}
if lhs.hasRemoteHardware_p != rhs.hasRemoteHardware_p {return false}
if lhs.hasPkc_p != rhs.hasPkc_p {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

@ -1 +1 @@
Subproject commit 0acaec6eff00e748beeae89148093221f131cd9c
Subproject commit 5709c0a05eaefccbc9cb8ed3917adbf5fd134197