mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 20:45:19 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19da74d724 |
@@ -1,20 +0,0 @@
|
|||||||
# Prevent Github Languages stats skewing:
|
|
||||||
|
|
||||||
# Binaries and assets
|
|
||||||
**/*.xcframework/** linguist-vendored
|
|
||||||
**/*.xcassets/** linguist-vendored
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
**/*.pbxproj linguist-generated
|
|
||||||
**/*.storyboard linguist-generated
|
|
||||||
Package.resolved linguist-generated
|
|
||||||
|
|
||||||
# Downloaded CSVs
|
|
||||||
relays/online_relays_gps.csv linguist-vendored
|
|
||||||
|
|
||||||
# Docs
|
|
||||||
**/*.md linguist-documentation
|
|
||||||
|
|
||||||
# Configs
|
|
||||||
Configs/*.xcconfig linguist-documentation
|
|
||||||
**/*.plist linguist-documentation
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
name: Fetch GeoRelays Data
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 6 * * 0'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-relay-data:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Fetch GeoRelays
|
|
||||||
run: |
|
|
||||||
wget -q https://raw.githubusercontent.com/permissionlesstech/georelays/refs/heads/main/nostr_relays.csv
|
|
||||||
mv nostr_relays.csv ./relays/online_relays_gps.csv
|
|
||||||
|
|
||||||
- name: Check for changes
|
|
||||||
id: git-check
|
|
||||||
run: |
|
|
||||||
git diff --exit-code || echo "changes=true" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Commit and push changes
|
|
||||||
if: steps.git-check.outputs.changes == 'true'
|
|
||||||
run: |
|
|
||||||
git config --local user.email "action@github.com"
|
|
||||||
git config --local user.name "GitHub Action"
|
|
||||||
git add relays/online_relays_gps.csv
|
|
||||||
git commit -m "Automated update of relay data - $(date -u)"
|
|
||||||
git push
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
name: Build & Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Run Swift Tests (${{ matrix.name }})
|
|
||||||
runs-on: macos-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false # Don't cancel other matrix jobs when one fails
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: app
|
|
||||||
path: .
|
|
||||||
- name: BitLogger
|
|
||||||
path: localPackages/BitLogger
|
|
||||||
- name: BitFoundation
|
|
||||||
path: localPackages/BitFoundation
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Set up Swift
|
|
||||||
uses: swift-actions/setup-swift@v3
|
|
||||||
|
|
||||||
- name: Cache build artifacts
|
|
||||||
uses: actions/cache@v5
|
|
||||||
with:
|
|
||||||
path: ${{ matrix.path }}/.build
|
|
||||||
key: ${{ runner.os }}-${{ matrix.name }}-${{ hashFiles(format('{0}/**/*.swift', matrix.path), format('{0}/**/Package.resolved', matrix.path)) }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-${{ matrix.name }}-${{ hashFiles(format('{0}/**/Package.resolved', matrix.path)) }}
|
|
||||||
${{ runner.os }}-${{ matrix.name }}-
|
|
||||||
|
|
||||||
- name: Run Tests
|
|
||||||
run: swift test --parallel --quiet --package-path ${{ matrix.path }}
|
|
||||||
+4
-13
@@ -8,7 +8,9 @@ plans/
|
|||||||
## AI
|
## AI
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
AGENTS.md
|
AGENTS.md
|
||||||
.claude/
|
|
||||||
|
## User settings
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
||||||
*.xcscmblueprint
|
*.xcscmblueprint
|
||||||
@@ -55,8 +57,7 @@ iOSInjectionProject/
|
|||||||
|
|
||||||
## Xcode project
|
## Xcode project
|
||||||
*.xcodeproj/project.xcworkspace/
|
*.xcodeproj/project.xcworkspace/
|
||||||
## Xcode User settings
|
*.xcodeproj/xcshareddata/
|
||||||
xcuserdata/
|
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
__pycache__/
|
__pycache__/
|
||||||
@@ -67,16 +68,6 @@ __pycache__/
|
|||||||
*.tmp
|
*.tmp
|
||||||
*.temp
|
*.temp
|
||||||
|
|
||||||
## Cache
|
|
||||||
.cache/
|
|
||||||
|
|
||||||
# Local build results
|
# Local build results
|
||||||
.Result*/
|
.Result*/
|
||||||
.Result*.xcresult/
|
.Result*.xcresult/
|
||||||
TestResult.xcresult/
|
|
||||||
*.xcresult/
|
|
||||||
build.log
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Local configs
|
|
||||||
Local.xcconfig
|
|
||||||
|
|||||||
+3
-3
@@ -37,7 +37,7 @@ This three-message pattern provides:
|
|||||||
#### NoiseEncryptionService
|
#### NoiseEncryptionService
|
||||||
The main service managing all Noise operations:
|
The main service managing all Noise operations:
|
||||||
```swift
|
```swift
|
||||||
final class NoiseEncryptionService {
|
class NoiseEncryptionService {
|
||||||
private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey
|
private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey
|
||||||
private let sessionManager: NoiseSessionManager
|
private let sessionManager: NoiseSessionManager
|
||||||
private let channelEncryption = NoiseChannelEncryption()
|
private let channelEncryption = NoiseChannelEncryption()
|
||||||
@@ -47,7 +47,7 @@ final class NoiseEncryptionService {
|
|||||||
#### NoiseSession
|
#### NoiseSession
|
||||||
Individual session state for each peer:
|
Individual session state for each peer:
|
||||||
```swift
|
```swift
|
||||||
final class NoiseSession {
|
class NoiseSession {
|
||||||
private var handshakeState: NoiseHandshakeState?
|
private var handshakeState: NoiseHandshakeState?
|
||||||
private var sendCipher: NoiseCipherState?
|
private var sendCipher: NoiseCipherState?
|
||||||
private var receiveCipher: NoiseCipherState?
|
private var receiveCipher: NoiseCipherState?
|
||||||
@@ -58,7 +58,7 @@ final class NoiseSession {
|
|||||||
#### NoiseSessionManager
|
#### NoiseSessionManager
|
||||||
Thread-safe session management:
|
Thread-safe session management:
|
||||||
```swift
|
```swift
|
||||||
final class NoiseSessionManager {
|
class NoiseSessionManager {
|
||||||
private var sessions: [String: NoiseSession] = [:]
|
private var sessions: [String: NoiseSession] = [:]
|
||||||
private let sessionsQueue = DispatchQueue(label: "noise.sessions", attributes: .concurrent)
|
private let sessionsQueue = DispatchQueue(label: "noise.sessions", attributes: .concurrent)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#include "Release.xcconfig"
|
|
||||||
|
|
||||||
// Optional include of local configs
|
|
||||||
#include? "Local.xcconfig"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// Your Apple Developer Team ID - https://stackoverflow.com/a/18727947
|
|
||||||
DEVELOPMENT_TEAM = ABC123
|
|
||||||
|
|
||||||
// Unique bundle id to be able to register and run locally
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.$(DEVELOPMENT_TEAM)
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
MARKETING_VERSION = 1.5.1
|
|
||||||
CURRENT_PROJECT_VERSION = 1
|
|
||||||
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0
|
|
||||||
SWIFT_VERSION = 5.0
|
|
||||||
|
|
||||||
DEVELOPMENT_TEAM = L3N5LHJD5Y
|
|
||||||
CODE_SIGN_STYLE = Automatic
|
|
||||||
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat
|
|
||||||
APP_GROUP_ID = group.chat.bitchat
|
|
||||||
@@ -14,16 +14,16 @@ default:
|
|||||||
# Check prerequisites
|
# Check prerequisites
|
||||||
check:
|
check:
|
||||||
@echo "Checking prerequisites..."
|
@echo "Checking prerequisites..."
|
||||||
@command -v xcodebuild >/dev/null 2>&1 || (echo "❌ xcodebuild not found. Install Xcode from App Store" && exit 1)
|
@command -v xcodegen >/dev/null 2>&1 || (echo "❌ XcodeGen not found. Install with: brew install xcodegen" && exit 1)
|
||||||
@xcode-select -p | grep -q "Xcode.app" || (echo "❌ Full Xcode required, not just command line tools. Install from App Store and run:\n sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" && exit 1)
|
@command -v xcodebuild >/dev/null 2>&1 || (echo "❌ Xcode not found. Install Xcode from App Store" && exit 1)
|
||||||
@test -d "/Applications/Xcode.app" || (echo "❌ Xcode.app not found in Applications folder. Install from App Store" && exit 1)
|
@security find-identity -v -p codesigning | grep -q "Developer ID" || (echo "⚠️ No Developer ID found - code signing may fail" && exit 0)
|
||||||
@xcodebuild -version >/dev/null 2>&1 || (echo "❌ Xcode not properly configured. Try:\n sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" && exit 1)
|
|
||||||
@security find-identity -v -p codesigning | grep -q "Apple Development\|Developer ID" || (echo "⚠️ No Developer ID found - code signing may fail" && exit 0)
|
|
||||||
@echo "✅ All prerequisites met"
|
@echo "✅ All prerequisites met"
|
||||||
|
|
||||||
# Backup original files
|
# Backup original files
|
||||||
backup:
|
backup:
|
||||||
@echo "Backing up original project configuration..."
|
@echo "Backing up original project configuration..."
|
||||||
|
@cp project.yml project.yml.backup 2>/dev/null || true
|
||||||
|
@# Backup other files that get modified by xcodegen
|
||||||
@if [ -f bitchat.xcodeproj/project.pbxproj ]; then cp bitchat.xcodeproj/project.pbxproj bitchat.xcodeproj/project.pbxproj.backup; fi
|
@if [ -f bitchat.xcodeproj/project.pbxproj ]; then cp bitchat.xcodeproj/project.pbxproj bitchat.xcodeproj/project.pbxproj.backup; fi
|
||||||
@if [ -f bitchat/Info.plist ]; then cp bitchat/Info.plist bitchat/Info.plist.backup; fi
|
@if [ -f bitchat/Info.plist ]; then cp bitchat/Info.plist bitchat/Info.plist.backup; fi
|
||||||
|
|
||||||
@@ -44,8 +44,13 @@ patch-for-macos: backup
|
|||||||
@# Move iOS-specific files out of the way temporarily
|
@# Move iOS-specific files out of the way temporarily
|
||||||
@if [ -f bitchat/LaunchScreen.storyboard ]; then mv bitchat/LaunchScreen.storyboard bitchat/LaunchScreen.storyboard.ios; fi
|
@if [ -f bitchat/LaunchScreen.storyboard ]; then mv bitchat/LaunchScreen.storyboard bitchat/LaunchScreen.storyboard.ios; fi
|
||||||
|
|
||||||
|
# Generate Xcode project with patches
|
||||||
|
generate: patch-for-macos
|
||||||
|
@echo "Generating Xcode project..."
|
||||||
|
@xcodegen generate
|
||||||
|
|
||||||
# Build the macOS app
|
# Build the macOS app
|
||||||
build: #check generate
|
build: check generate
|
||||||
@echo "Building BitChat for macOS..."
|
@echo "Building BitChat for macOS..."
|
||||||
@xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" -configuration Debug CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" build
|
@xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" -configuration Debug CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" build
|
||||||
|
|
||||||
@@ -70,7 +75,9 @@ clean: restore
|
|||||||
# Quick run without cleaning (for development)
|
# Quick run without cleaning (for development)
|
||||||
dev-run: check
|
dev-run: check
|
||||||
@echo "Quick development build..."
|
@echo "Quick development build..."
|
||||||
@xcodebuild -project bitchat.xcodeproj -scheme "bitchat_macOS" -configuration Debug CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" build
|
@if [ ! -f project.yml.backup ]; then just patch-for-macos; fi
|
||||||
|
@xcodegen generate
|
||||||
|
@xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" -configuration Debug CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" build
|
||||||
@find ~/Library/Developer/Xcode/DerivedData -name "bitchat.app" -path "*/Debug/*" -not -path "*/Index.noindex/*" | head -1 | xargs -I {} open "{}"
|
@find ~/Library/Developer/Xcode/DerivedData -name "bitchat.app" -path "*/Debug/*" -not -path "*/Index.noindex/*" | head -1 | xargs -I {} open "{}"
|
||||||
|
|
||||||
# Show app info
|
# Show app info
|
||||||
@@ -99,9 +106,11 @@ nuke:
|
|||||||
@echo "🧨 Nuclear clean - removing all build artifacts and backups..."
|
@echo "🧨 Nuclear clean - removing all build artifacts and backups..."
|
||||||
@rm -rf ~/Library/Developer/Xcode/DerivedData/bitchat-* 2>/dev/null || true
|
@rm -rf ~/Library/Developer/Xcode/DerivedData/bitchat-* 2>/dev/null || true
|
||||||
@rm -rf bitchat.xcodeproj 2>/dev/null || true
|
@rm -rf bitchat.xcodeproj 2>/dev/null || true
|
||||||
|
@rm -f project.yml.backup 2>/dev/null || true
|
||||||
|
@rm -f project-macos.yml 2>/dev/null || true
|
||||||
@rm -f bitchat.xcodeproj/project.pbxproj.backup 2>/dev/null || true
|
@rm -f bitchat.xcodeproj/project.pbxproj.backup 2>/dev/null || true
|
||||||
@rm -f bitchat/Info.plist.backup 2>/dev/null || true
|
@rm -f bitchat/Info.plist.backup 2>/dev/null || true
|
||||||
@# Restore iOS-specific files if they were moved
|
@# Restore iOS-specific files if they were moved
|
||||||
@if [ -f bitchat/LaunchScreen.storyboard.ios ]; then mv bitchat/LaunchScreen.storyboard.ios bitchat/LaunchScreen.storyboard; fi
|
@if [ -f bitchat/LaunchScreen.storyboard.ios ]; then mv bitchat/LaunchScreen.storyboard.ios bitchat/LaunchScreen.storyboard; fi
|
||||||
@git checkout bitchat.xcodeproj/project.pbxproj bitchat/Info.plist 2>/dev/null || echo "⚠️ Not a git repo or no changes to restore"
|
@git checkout -- project.yml bitchat.xcodeproj/project.pbxproj bitchat/Info.plist 2>/dev/null || echo "⚠️ Not a git repo or no changes to restore"
|
||||||
@echo "✅ Nuclear clean complete"
|
@echo "✅ Nuclear clean complete"
|
||||||
|
|||||||
+3
-31
@@ -4,7 +4,6 @@ import PackageDescription
|
|||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "bitchat",
|
name: "bitchat",
|
||||||
defaultLocalization: "en",
|
|
||||||
platforms: [
|
platforms: [
|
||||||
.iOS(.v16),
|
.iOS(.v16),
|
||||||
.macOS(.v13)
|
.macOS(.v13)
|
||||||
@@ -16,49 +15,22 @@ let package = Package(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
dependencies:[
|
dependencies:[
|
||||||
.package(path: "localPackages/Arti"),
|
.package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.21.1"),
|
||||||
.package(path: "localPackages/BitFoundation"),
|
|
||||||
.package(path: "localPackages/BitLogger"),
|
|
||||||
.package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.21.1")
|
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "bitchat",
|
name: "bitchat",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "P256K", package: "swift-secp256k1"),
|
.product(name: "P256K", package: "swift-secp256k1")
|
||||||
.product(name: "BitFoundation", package: "BitFoundation"),
|
|
||||||
.product(name: "BitLogger", package: "BitLogger"),
|
|
||||||
.product(name: "Tor", package: "Arti")
|
|
||||||
],
|
],
|
||||||
path: "bitchat",
|
path: "bitchat",
|
||||||
exclude: [
|
exclude: [
|
||||||
"Info.plist",
|
"Info.plist",
|
||||||
"Assets.xcassets",
|
"Assets.xcassets",
|
||||||
"_PreviewHelpers/PreviewAssets.xcassets",
|
|
||||||
"bitchat.entitlements",
|
"bitchat.entitlements",
|
||||||
"bitchat-macOS.entitlements",
|
"bitchat-macOS.entitlements",
|
||||||
"LaunchScreen.storyboard",
|
"LaunchScreen.storyboard"
|
||||||
"ViewModels/Extensions/README.md"
|
|
||||||
],
|
|
||||||
resources: [
|
|
||||||
.process("Localizable.xcstrings")
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
.testTarget(
|
|
||||||
name: "bitchatTests",
|
|
||||||
dependencies: [
|
|
||||||
"bitchat",
|
|
||||||
.product(name: "BitFoundation", package: "BitFoundation")
|
|
||||||
],
|
|
||||||
path: "bitchatTests",
|
|
||||||
exclude: [
|
|
||||||
"Info.plist",
|
|
||||||
"README.md"
|
|
||||||
],
|
|
||||||
resources: [
|
|
||||||
.process("Localization"),
|
|
||||||
.process("Noise")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,121 +2,87 @@
|
|||||||
|
|
||||||
## bitchat
|
## bitchat
|
||||||
|
|
||||||
A decentralized peer-to-peer messaging app with dual transport architecture: local Bluetooth mesh networks for offline communication and internet-based Nostr protocol for global reach. No accounts, no phone numbers, no central servers. It's the side-groupchat.
|
A decentralized peer-to-peer messaging app that works over Bluetooth mesh networks. No internet required, no servers, no phone numbers. It's the side-groupchat.
|
||||||
|
|
||||||
[bitchat.free](http://bitchat.free)
|
[bitchat.free](http://bitchat.free)
|
||||||
|
|
||||||
📲 [App Store](https://apps.apple.com/us/app/bitchat-mesh/id6748219622)
|
📲 [App Store](https://apps.apple.com/us/app/bitchat-mesh/id6748219622)
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Private messages have not received external security review and may contain vulnerabilities. Do not use for sensitive use cases, and do not rely on its security until it has been reviewed. Now uses the [Noise Protocol](http://www.noiseprotocol.org) for identity and encryption. Public local chat (the main feature) has no security concerns.
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is released into the public domain. See the [LICENSE](LICENSE) file for details.
|
This project is released into the public domain. See the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Dual Transport Architecture**: Bluetooth mesh for offline + Nostr protocol for internet-based messaging
|
|
||||||
- **Location-Based Channels**: Geographic chat rooms using geohash coordinates over global Nostr relays
|
|
||||||
- **Intelligent Message Routing**: Automatically chooses best transport (Bluetooth → Nostr fallback)
|
|
||||||
- **Decentralized Mesh Network**: Automatic peer discovery and multi-hop message relay over Bluetooth LE
|
- **Decentralized Mesh Network**: Automatic peer discovery and multi-hop message relay over Bluetooth LE
|
||||||
- **Privacy First**: No accounts, no phone numbers, no persistent identifiers
|
- **Privacy First**: No accounts, no phone numbers, no persistent identifiers
|
||||||
- **Private Message End-to-End Encryption**: [Noise Protocol](https://noiseprotocol.org) for mesh, NIP-17 for Nostr
|
- **Private Message End-to-End Encryption**: [Noise Protocol](http://noiseprotocol.org)
|
||||||
- **IRC-Style Commands**: Familiar `/slap`, `/msg`, `/who` style interface
|
- **IRC-Style Commands**: Familiar `/slap`, `/msg`, `/who` style interface
|
||||||
- **Universal App**: Native support for iOS and macOS
|
- **Universal App**: Native support for iOS and macOS
|
||||||
- **Emergency Wipe**: Triple-tap to instantly clear all data
|
- **Emergency Wipe**: Triple-tap to instantly clear all data
|
||||||
- **Performance Optimizations**: LZ4 message compression, adaptive battery modes, and optimized networking
|
- **Performance Optimizations**: LZ4 message compression, adaptive battery modes, and optimized networking
|
||||||
|
|
||||||
|
|
||||||
## [Technical Architecture](https://deepwiki.com/permissionlesstech/bitchat)
|
## [Technical Architecture](https://deepwiki.com/permissionlesstech/bitchat)
|
||||||
|
|
||||||
BitChat uses a **hybrid messaging architecture** with two complementary transport layers:
|
### Binary Protocol
|
||||||
|
bitchat uses an efficient binary protocol optimized for Bluetooth LE:
|
||||||
|
- Compact packet format with 1-byte type field
|
||||||
|
- TTL-based message routing (max 7 hops)
|
||||||
|
- Automatic fragmentation for large messages
|
||||||
|
- Message deduplication via unique IDs
|
||||||
|
|
||||||
### Bluetooth Mesh Network (Offline)
|
### Mesh Networking
|
||||||
|
- Each device acts as both client and peripheral
|
||||||
- **Local Communication**: Direct peer-to-peer within Bluetooth range
|
- Automatic peer discovery and connection management
|
||||||
- **Multi-hop Relay**: Messages route through nearby devices (max 7 hops)
|
- Adaptive duty cycling for battery optimization
|
||||||
- **No Internet Required**: Works completely offline in disaster scenarios
|
|
||||||
- **Noise Protocol Encryption**: End-to-end encryption with forward secrecy
|
|
||||||
- **Binary Protocol**: Compact packet format optimized for Bluetooth LE constraints
|
|
||||||
- **Automatic Discovery**: Peer discovery and connection management
|
|
||||||
- **Adaptive Power**: Battery-optimized duty cycling
|
|
||||||
|
|
||||||
### Nostr Protocol (Internet)
|
|
||||||
|
|
||||||
- **Global Reach**: Connect with users worldwide via internet relays
|
|
||||||
- **Location Channels**: Geographic chat rooms using geohash coordinates
|
|
||||||
- **290+ Relay Network**: Distributed across the globe for reliability
|
|
||||||
- **NIP-17 Encryption**: Gift-wrapped private messages for internet privacy
|
|
||||||
- **Ephemeral Keys**: Fresh cryptographic identity per geohash area
|
|
||||||
|
|
||||||
### Channel Types
|
|
||||||
|
|
||||||
#### `mesh #bluetooth`
|
|
||||||
|
|
||||||
- **Transport**: Bluetooth Low Energy mesh network
|
|
||||||
- **Scope**: Local devices within multi-hop range
|
|
||||||
- **Internet**: Not required
|
|
||||||
- **Use Case**: Offline communication, protests, disasters, remote areas
|
|
||||||
|
|
||||||
#### Location Channels (`block #dr5rsj7`, `neighborhood #dr5rs`, `country #dr`)
|
|
||||||
|
|
||||||
- **Transport**: Nostr protocol over internet
|
|
||||||
- **Scope**: Geographic areas defined by geohash precision
|
|
||||||
- `block` (7 chars): City block level
|
|
||||||
- `neighborhood` (6 chars): District/neighborhood
|
|
||||||
- `city` (5 chars): City level
|
|
||||||
- `province` (4 chars): State/province
|
|
||||||
- `region` (2 chars): Country/large region
|
|
||||||
- **Internet**: Required (connects to Nostr relays)
|
|
||||||
- **Use Case**: Location-based community chat, local events, regional discussions
|
|
||||||
|
|
||||||
### Direct Message Routing
|
|
||||||
|
|
||||||
Private messages use **intelligent transport selection**:
|
|
||||||
|
|
||||||
1. **Bluetooth First** (preferred when available)
|
|
||||||
|
|
||||||
- Direct connection with established Noise session
|
|
||||||
- Fastest and most private option
|
|
||||||
|
|
||||||
2. **Nostr Fallback** (when Bluetooth unavailable)
|
|
||||||
|
|
||||||
- Uses recipient's Nostr public key
|
|
||||||
- NIP-17 gift-wrapping for privacy
|
|
||||||
- Routes through global relay network
|
|
||||||
|
|
||||||
3. **Smart Queuing** (when neither available)
|
|
||||||
- Messages queued until transport becomes available
|
|
||||||
- Automatic delivery when connection established
|
|
||||||
|
|
||||||
For detailed protocol documentation, see the [Technical Whitepaper](WHITEPAPER.md).
|
For detailed protocol documentation, see the [Technical Whitepaper](WHITEPAPER.md).
|
||||||
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
### Option 1: Using Xcode
|
### Option 1: Using XcodeGen (Recommended)
|
||||||
|
|
||||||
|
1. Install XcodeGen if you haven't already:
|
||||||
|
```bash
|
||||||
|
brew install xcodegen
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Generate the Xcode project:
|
||||||
```bash
|
```bash
|
||||||
cd bitchat
|
cd bitchat
|
||||||
|
xcodegen generate
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Open the generated project:
|
||||||
|
```bash
|
||||||
open bitchat.xcodeproj
|
open bitchat.xcodeproj
|
||||||
```
|
```
|
||||||
|
|
||||||
To run on a device there're a few steps to prepare the code:
|
### Option 2: Using Swift Package Manager
|
||||||
- Clone the local configs: `cp Configs/Local.xcconfig.example Configs/Local.xcconfig`
|
|
||||||
- Add your Developer Team ID into the newly created `Configs/Local.xcconfig`
|
|
||||||
- Bundle ID would be set to `chat.bitchat.<team_id>` (unless you set to something else)
|
|
||||||
- Entitlements need to be updated manually (TODO: Automate):
|
|
||||||
- Search and replace `group.chat.bitchat` with `group.<your_bundle_id>` (e.g. `group.chat.bitchat.ABC123`)
|
|
||||||
|
|
||||||
### Option 2: Using `just`
|
|
||||||
|
|
||||||
|
1. Open the project in Xcode:
|
||||||
```bash
|
```bash
|
||||||
brew install just
|
cd bitchat
|
||||||
|
open Package.swift
|
||||||
```
|
```
|
||||||
|
|
||||||
Want to try this on macos: `just run` will set it up and run from source.
|
2. Select your target device and run
|
||||||
|
|
||||||
|
### Option 3: Manual Xcode Project
|
||||||
|
|
||||||
|
1. Open Xcode and create a new iOS/macOS App
|
||||||
|
2. Copy all Swift files from the `bitchat` directory into your project
|
||||||
|
3. Update Info.plist with Bluetooth permissions
|
||||||
|
4. Set deployment target to iOS 16.0 / macOS 13.0
|
||||||
|
|
||||||
|
### Option 4: just
|
||||||
|
|
||||||
|
Want to try this on macos: `just run` will set it up and run from source.
|
||||||
Run `just clean` afterwards to restore things to original state for mobile app building and development.
|
Run `just clean` afterwards to restore things to original state for mobile app building and development.
|
||||||
|
|
||||||
## Localization
|
|
||||||
|
|
||||||
- Base app resources live under `bitchat/Localization/Base.lproj/`. Add new copy to `Localizable.strings` and plural rules to `Localizable.stringsdict`.
|
|
||||||
- Share extension strings are separate in `bitchatShareExtension/Localization/Base.lproj/Localizable.strings`.
|
|
||||||
- Prefer keys that describe intent (`app_info.features.offline.title`) and reuse existing ones where possible.
|
|
||||||
- Run `xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" -configuration Debug CODE_SIGNING_ALLOWED=NO build` to compile-check any localization updates.
|
|
||||||
|
|||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"type":1,"name":"C5C67AE61A322FBBC90B5C8FE31F44"}]
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"type":1,"name":"E76911D1F63AFE862FE85FDD58BA22"}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"2A06FD9C403255A7D7F7DD4C1D5411","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"2B2DF013CC35109F0E84824218C371","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"272A5ACD643F35A14D9D0C7D97FDBD","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"02A2B24D353061AA8ED3B5CAE135FA","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"1846F3D1223CD89DB37574063303CC","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"298FB4DD003C4885F92C170D32954D","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"6250CA76F834A1AB8ADA7C2BF60804","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"16EB30938731948B7DE73214F4EF62","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"type":1,"name":"18D4B812B33D1DAC12B7B9582F980A"}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"8F8E36790E3B91AC0D6C1DE4AA4B84","type":1}]
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"type":1,"name":"7241625CC9378F9B48DF34B4275067"}]
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"F70FD7F495326FAAF8F5F6678ECDB7","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"187DDE074D38699793B709B475FEA4","type":1}]
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user