mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 11:25:20 +00:00
Extract Nostr into a dedicated module
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
import BitFoundation
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import Combine
|
||||
#if os(iOS)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
@testable import bitchat
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Nostr
|
||||
import Testing
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
import BitFoundation
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import Combine
|
||||
@testable import bitchat
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
@testable import bitchat
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
@testable import bitchat
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Nostr
|
||||
import Tor
|
||||
import XCTest
|
||||
@testable import bitchat
|
||||
@@ -303,6 +304,7 @@ final class GeoRelayDirectoryTests: XCTestCase {
|
||||
retrySleep: { delay in
|
||||
await retryRecorder.record(delay)
|
||||
},
|
||||
torReadyNotificationName: .TorDidBecomeReady,
|
||||
activeNotificationName: activeNotificationName,
|
||||
autoStart: autoStart
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Tests for NIP-17 gift-wrapped private messages
|
||||
//
|
||||
|
||||
import Nostr
|
||||
import Testing
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Combine
|
||||
import Nostr
|
||||
import XCTest
|
||||
@testable import bitchat
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Nostr
|
||||
import Combine
|
||||
import XCTest
|
||||
@testable import bitchat
|
||||
@@ -697,7 +698,7 @@ final class NostrRelayManagerTests: XCTestCase {
|
||||
}
|
||||
|
||||
private func makeContext(
|
||||
permission: LocationChannelManager.PermissionState,
|
||||
permission: LocationPermissionState,
|
||||
favorites: Set<Data> = [],
|
||||
activationAllowed: Bool = true,
|
||||
userTorEnabled: Bool = false,
|
||||
@@ -705,7 +706,7 @@ final class NostrRelayManagerTests: XCTestCase {
|
||||
torIsReady: Bool = true,
|
||||
torIsForeground: Bool = true
|
||||
) -> RelayManagerTestContext {
|
||||
let permissionSubject = CurrentValueSubject<LocationChannelManager.PermissionState, Never>(permission)
|
||||
let permissionSubject = CurrentValueSubject<LocationPermissionState, Never>(permission)
|
||||
let favoritesSubject = CurrentValueSubject<Set<Data>, Never>(favorites)
|
||||
let sessionFactory = MockRelaySessionFactory()
|
||||
let scheduler = MockRelayScheduler()
|
||||
@@ -782,7 +783,7 @@ final class NostrRelayManagerTests: XCTestCase {
|
||||
@MainActor
|
||||
private struct RelayManagerTestContext {
|
||||
let manager: NostrRelayManager
|
||||
let permissionSubject: CurrentValueSubject<LocationChannelManager.PermissionState, Never>
|
||||
let permissionSubject: CurrentValueSubject<LocationPermissionState, Never>
|
||||
let favoritesSubject: CurrentValueSubject<Set<Data>, Never>
|
||||
let sessionFactory: MockRelaySessionFactory
|
||||
let scheduler: MockRelayScheduler
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Nostr
|
||||
import Testing
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import BitFoundation
|
||||
@testable import bitchat
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Testing
|
||||
import Nostr
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import CoreGraphics
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
//
|
||||
// XChaCha20Poly1305CompatTests.swift
|
||||
// bitchatTests
|
||||
//
|
||||
// Tests for XChaCha20-Poly1305 encryption with proper error handling.
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
|
||||
import Testing
|
||||
import struct Foundation.Data
|
||||
@testable import bitchat
|
||||
|
||||
struct XChaCha20Poly1305CompatTests {
|
||||
|
||||
@Test func sealAndOpenRoundtrip() throws {
|
||||
let plaintext = "Hello, XChaCha20-Poly1305!".data(using: .utf8)!
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
let sealed = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: nonce)
|
||||
let decrypted = try XChaCha20Poly1305Compat.open(
|
||||
ciphertext: sealed.ciphertext,
|
||||
tag: sealed.tag,
|
||||
key: key,
|
||||
nonce24: nonce
|
||||
)
|
||||
|
||||
#expect(decrypted == plaintext)
|
||||
}
|
||||
|
||||
@Test func sealAndOpenWithAAD() throws {
|
||||
let plaintext = "Secret message".data(using: .utf8)!
|
||||
let key = Data(repeating: 0xAB, count: 32)
|
||||
let nonce = Data(repeating: 0xCD, count: 24)
|
||||
let aad = "additional authenticated data".data(using: .utf8)!
|
||||
|
||||
let sealed = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: nonce, aad: aad)
|
||||
let decrypted = try XChaCha20Poly1305Compat.open(
|
||||
ciphertext: sealed.ciphertext,
|
||||
tag: sealed.tag,
|
||||
key: key,
|
||||
nonce24: nonce,
|
||||
aad: aad
|
||||
)
|
||||
|
||||
#expect(decrypted == plaintext)
|
||||
}
|
||||
|
||||
@Test func sealProducesDifferentCiphertextWithDifferentNonces() throws {
|
||||
let plaintext = "Same plaintext".data(using: .utf8)!
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let nonce1 = Data(repeating: 0x01, count: 24)
|
||||
let nonce2 = Data(repeating: 0x02, count: 24)
|
||||
|
||||
let sealed1 = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: nonce1)
|
||||
let sealed2 = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: nonce2)
|
||||
|
||||
#expect(sealed1.ciphertext != sealed2.ciphertext)
|
||||
}
|
||||
|
||||
@Test func sealThrowsOnShortKey() {
|
||||
let plaintext = "Test".data(using: .utf8)!
|
||||
let shortKey = Data(repeating: 0x42, count: 16)
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: shortKey, nonce24: nonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func sealThrowsOnLongKey() {
|
||||
let plaintext = "Test".data(using: .utf8)!
|
||||
let longKey = Data(repeating: 0x42, count: 64)
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: longKey, nonce24: nonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func sealThrowsOnEmptyKey() {
|
||||
let plaintext = "Test".data(using: .utf8)!
|
||||
let emptyKey = Data()
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: emptyKey, nonce24: nonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func openThrowsOnInvalidKeyLength() {
|
||||
let ciphertext = Data(repeating: 0x00, count: 16)
|
||||
let tag = Data(repeating: 0x00, count: 16)
|
||||
let shortKey = Data(repeating: 0x42, count: 31)
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.open(ciphertext: ciphertext, tag: tag, key: shortKey, nonce24: nonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func sealThrowsOnShortNonce() {
|
||||
let plaintext = "Test".data(using: .utf8)!
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let shortNonce = Data(repeating: 0x24, count: 12)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: shortNonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func sealThrowsOnLongNonce() {
|
||||
let plaintext = "Test".data(using: .utf8)!
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let longNonce = Data(repeating: 0x24, count: 32)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: longNonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func sealThrowsOnEmptyNonce() {
|
||||
let plaintext = "Test".data(using: .utf8)!
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let emptyNonce = Data()
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: emptyNonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func openThrowsOnInvalidNonceLength() {
|
||||
let ciphertext = Data(repeating: 0x00, count: 16)
|
||||
let tag = Data(repeating: 0x00, count: 16)
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let shortNonce = Data(repeating: 0x24, count: 23)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.open(ciphertext: ciphertext, tag: tag, key: key, nonce24: shortNonce)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func openFailsWithWrongKey() throws {
|
||||
let plaintext = "Secret".data(using: .utf8)!
|
||||
let correctKey = Data(repeating: 0x42, count: 32)
|
||||
let wrongKey = Data(repeating: 0x43, count: 32)
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
let sealed = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: correctKey, nonce24: nonce)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.open(
|
||||
ciphertext: sealed.ciphertext,
|
||||
tag: sealed.tag,
|
||||
key: wrongKey,
|
||||
nonce24: nonce
|
||||
)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
|
||||
@Test func openFailsWithTamperedCiphertext() throws {
|
||||
let plaintext = "Secret".data(using: .utf8)!
|
||||
let key = Data(repeating: 0x42, count: 32)
|
||||
let nonce = Data(repeating: 0x24, count: 24)
|
||||
|
||||
let sealed = try XChaCha20Poly1305Compat.seal(plaintext: plaintext, key: key, nonce24: nonce)
|
||||
|
||||
// Create tampered ciphertext by changing first byte
|
||||
var tamperedBytes = [UInt8](sealed.ciphertext)
|
||||
tamperedBytes[0] = tamperedBytes[0] ^ 0xFF
|
||||
let tampered = Data(tamperedBytes)
|
||||
|
||||
var didThrow = false
|
||||
do {
|
||||
_ = try XChaCha20Poly1305Compat.open(
|
||||
ciphertext: tampered,
|
||||
tag: sealed.tag,
|
||||
key: key,
|
||||
nonce24: nonce
|
||||
)
|
||||
} catch {
|
||||
didThrow = true
|
||||
}
|
||||
#expect(didThrow)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user