Compare commits
No commits in common. "3cc3358a4f008cf4c24884c069fbfa56b533b6c4" and "44ecf042a373291ec9ea73cfbb1b4eadc9e67242" have entirely different histories.
3cc3358a4f
...
44ecf042a3
82 changed files with 622 additions and 2421 deletions
3
.github/actions/archive/action.yml
vendored
3
.github/actions/archive/action.yml
vendored
|
|
@ -29,9 +29,6 @@ runs:
|
||||||
xcodebuild archive \
|
xcodebuild archive \
|
||||||
-allowProvisioningUpdates \
|
-allowProvisioningUpdates \
|
||||||
-allowProvisioningDeviceRegistration \
|
-allowProvisioningDeviceRegistration \
|
||||||
-skipPackagePluginValidation \
|
|
||||||
-skipMacroValidation \
|
|
||||||
-onlyUsePackageVersionsFromResolvedFile \
|
|
||||||
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
||||||
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
||||||
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
||||||
|
|
|
||||||
10
.github/actions/build-for-testing/action.yml
vendored
10
.github/actions/build-for-testing/action.yml
vendored
|
|
@ -24,7 +24,6 @@ runs:
|
||||||
path: |
|
path: |
|
||||||
Apple/PackageCache
|
Apple/PackageCache
|
||||||
Apple/SourcePackages
|
Apple/SourcePackages
|
||||||
Apple/DerivedData
|
|
||||||
key: ${{ runner.os }}-${{ inputs.scheme }}-${{ hashFiles('**/Package.resolved') }}
|
key: ${{ runner.os }}-${{ inputs.scheme }}-${{ hashFiles('**/Package.resolved') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-${{ inputs.scheme }}-
|
${{ runner.os }}-${{ inputs.scheme }}-
|
||||||
|
|
@ -34,18 +33,17 @@ runs:
|
||||||
run: |
|
run: |
|
||||||
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
|
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
|
||||||
|
|
||||||
xcodebuild build-for-testing \
|
xcodebuild clean build-for-testing \
|
||||||
-allowProvisioningUpdates \
|
-allowProvisioningUpdates \
|
||||||
-allowProvisioningDeviceRegistration \
|
-allowProvisioningDeviceRegistration \
|
||||||
-skipPackagePluginValidation \
|
|
||||||
-skipMacroValidation \
|
|
||||||
-onlyUsePackageVersionsFromResolvedFile \
|
|
||||||
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
||||||
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
||||||
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
||||||
|
-onlyUsePackageVersionsFromResolvedFile \
|
||||||
-clonedSourcePackagesDirPath SourcePackages \
|
-clonedSourcePackagesDirPath SourcePackages \
|
||||||
-packageCachePath $PWD/PackageCache \
|
-packageCachePath $PWD/PackageCache \
|
||||||
-derivedDataPath $PWD/DerivedData \
|
-skipPackagePluginValidation \
|
||||||
|
-skipMacroValidation \
|
||||||
-scheme '${{ inputs.scheme }}' \
|
-scheme '${{ inputs.scheme }}' \
|
||||||
-destination '${{ inputs.destination }}' \
|
-destination '${{ inputs.destination }}' \
|
||||||
-resultBundlePath BuildResults.xcresult
|
-resultBundlePath BuildResults.xcresult
|
||||||
|
|
|
||||||
3
.github/actions/export/action.yml
vendored
3
.github/actions/export/action.yml
vendored
|
|
@ -37,9 +37,6 @@ runs:
|
||||||
-exportArchive \
|
-exportArchive \
|
||||||
-allowProvisioningUpdates \
|
-allowProvisioningUpdates \
|
||||||
-allowProvisioningDeviceRegistration \
|
-allowProvisioningDeviceRegistration \
|
||||||
-skipPackagePluginValidation \
|
|
||||||
-skipMacroValidation \
|
|
||||||
-onlyUsePackageVersionsFromResolvedFile \
|
|
||||||
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
||||||
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
||||||
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
||||||
|
|
|
||||||
57
.github/actions/notarize/action.yml
vendored
57
.github/actions/notarize/action.yml
vendored
|
|
@ -1,57 +0,0 @@
|
||||||
name: Notarize
|
|
||||||
inputs:
|
|
||||||
app-store-key:
|
|
||||||
description: App Store key in PEM PKCS#8 format
|
|
||||||
required: true
|
|
||||||
app-store-key-id:
|
|
||||||
description: App Store key ID
|
|
||||||
required: true
|
|
||||||
app-store-key-issuer-id:
|
|
||||||
description: App Store key issuer ID
|
|
||||||
required: true
|
|
||||||
archive-path:
|
|
||||||
description: Xcode archive path
|
|
||||||
required: true
|
|
||||||
outputs:
|
|
||||||
notarized-app:
|
|
||||||
description: The compressed and notarized app
|
|
||||||
value: ${{ steps.notarize.outputs.notarized-app }}
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- id: notarize
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
|
|
||||||
|
|
||||||
echo '{"destination":"upload","method":"developer-id"}' \
|
|
||||||
| plutil -convert xml1 -o ExportOptions.plist -
|
|
||||||
|
|
||||||
xcodebuild \
|
|
||||||
-exportArchive \
|
|
||||||
-allowProvisioningUpdates \
|
|
||||||
-allowProvisioningDeviceRegistration \
|
|
||||||
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
|
||||||
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
|
||||||
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
|
||||||
-archivePath '${{ inputs.archive-path }}' \
|
|
||||||
-exportOptionsPlist ExportOptions.plist
|
|
||||||
|
|
||||||
until xcodebuild \
|
|
||||||
-exportNotarizedApp \
|
|
||||||
-allowProvisioningUpdates \
|
|
||||||
-allowProvisioningDeviceRegistration \
|
|
||||||
-authenticationKeyID ${{ inputs.app-store-key-id }} \
|
|
||||||
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
|
|
||||||
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
|
|
||||||
-archivePath '${{ inputs.archive-path }}' \
|
|
||||||
-exportPath Release
|
|
||||||
do
|
|
||||||
echo "Failed to export app, trying again in 10s..."
|
|
||||||
sleep 10
|
|
||||||
done
|
|
||||||
|
|
||||||
tar --options xz:compression-level=9 -C Release -cJvf Wallet.txz ./
|
|
||||||
echo "notarized-app=Wallet.txz" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
rm -rf AuthKey_${{ inputs.app-store-key-id }}.p8 Release ExportOptions.plist
|
|
||||||
23
.github/workflows/build-appimage.yml
vendored
23
.github/workflows/build-appimage.yml
vendored
|
|
@ -1,23 +0,0 @@
|
||||||
name: Build AppImage
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
pull_request:
|
|
||||||
jobs:
|
|
||||||
appimage:
|
|
||||||
name: Build AppImage
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container: docker
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Build AppImage
|
|
||||||
run: |
|
|
||||||
docker build -t appimage-builder . -f burrow-gtk/build-aux/Dockerfile
|
|
||||||
docker create --name temp appimage-builder
|
|
||||||
docker cp temp:/app/burrow-gtk/build-appimage/Burrow-x86_64.AppImage .
|
|
||||||
docker rm temp
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: AppImage
|
|
||||||
path: Burrow-x86_64.AppImage
|
|
||||||
|
|
||||||
2
.github/workflows/build-apple.yml
vendored
2
.github/workflows/build-apple.yml
vendored
|
|
@ -12,7 +12,7 @@ concurrency:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build App (${{ matrix.platform }})
|
name: Build App (${{ matrix.platform }})
|
||||||
runs-on: macos-14
|
runs-on: macos-13
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|
|
||||||
5
.github/workflows/build-flatpak.yml
vendored
5
.github/workflows/build-flatpak.yml
vendored
|
|
@ -1,4 +1,7 @@
|
||||||
on: workflow_dispatch
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
name: Build Flatpak
|
name: Build Flatpak
|
||||||
jobs:
|
jobs:
|
||||||
flatpak:
|
flatpak:
|
||||||
|
|
|
||||||
49
.github/workflows/release-apple.yml
vendored
49
.github/workflows/release-apple.yml
vendored
|
|
@ -1,27 +1,26 @@
|
||||||
name: Build Apple Release
|
name: Build Apple Release
|
||||||
on:
|
on:
|
||||||
pull_request:
|
release:
|
||||||
branches:
|
types:
|
||||||
- "*"
|
- created
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build ${{ matrix.configuration['platform'] }} Release
|
name: Build ${{ matrix.configuration['platform'] }} Release
|
||||||
runs-on: macos-14
|
runs-on: macos-13
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
configuration:
|
configuration:
|
||||||
- destination: generic/platform=iOS
|
- scheme: App (iOS)
|
||||||
|
destination: generic/platform=iOS
|
||||||
platform: iOS
|
platform: iOS
|
||||||
|
method: ad-hoc
|
||||||
artifact-file: Apple/Release/Burrow.ipa
|
artifact-file: Apple/Release/Burrow.ipa
|
||||||
rust-targets:
|
- scheme: App (macOS)
|
||||||
- aarch64-apple-ios
|
destination: generic/platform=macOS
|
||||||
- destination: generic/platform=macOS
|
|
||||||
platform: macOS
|
platform: macOS
|
||||||
|
method: mac-application
|
||||||
artifact-file: Burrow.app.txz
|
artifact-file: Burrow.app.txz
|
||||||
rust-targets:
|
|
||||||
- x86_64-apple-darwin
|
|
||||||
- aarch64-apple-darwin
|
|
||||||
env:
|
env:
|
||||||
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
|
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -35,36 +34,32 @@ jobs:
|
||||||
with:
|
with:
|
||||||
certificate: ${{ secrets.DEVELOPER_CERT }}
|
certificate: ${{ secrets.DEVELOPER_CERT }}
|
||||||
password: ${{ secrets.DEVELOPER_CERT_PASSWORD }}
|
password: ${{ secrets.DEVELOPER_CERT_PASSWORD }}
|
||||||
- name: Install Rust
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
targets: ${{ join(matrix.rust-targets, ', ') }}
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
uses: ./.github/actions/archive
|
uses: ./.github/actions/archive
|
||||||
with:
|
with:
|
||||||
scheme: App
|
scheme: ${{ matrix.configuration['scheme'] }}
|
||||||
destination: ${{ matrix.configuration['destination'] }}
|
destination: ${{ matrix.configuration['destination'] }}
|
||||||
app-store-key: ${{ secrets.APPSTORE_KEY }}
|
app-store-key: ${{ secrets.APPSTORE_KEY }}
|
||||||
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
|
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
|
||||||
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
|
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
|
||||||
archive-path: Burrow.xcarchive
|
archive-path: Burrow.xcarchive
|
||||||
- name: Upload
|
- name: Export Locally
|
||||||
uses: ./.github/actions/export
|
uses: ./.github/actions/export
|
||||||
with:
|
with:
|
||||||
method: app-store-connect
|
method: ${{ matrix.configuration['method'] }}
|
||||||
destination: upload
|
destination: export
|
||||||
app-store-key: ${{ secrets.APPSTORE_KEY }}
|
app-store-key: ${{ secrets.APPSTORE_KEY }}
|
||||||
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
|
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
|
||||||
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
|
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
|
||||||
archive-path: Burrow.xcarchive
|
archive-path: Burrow.xcarchive
|
||||||
export-path: Release
|
export-path: Release
|
||||||
- name: Notarize
|
- name: Compress
|
||||||
if: ${{ matrix.configuration['platform'] == 'macOS' }}
|
if: ${{ matrix.configuration['platform'] == 'macOS' }}
|
||||||
uses: ./.github/actions/notarize
|
shell: bash
|
||||||
|
run: tar --options xz:compression-level=9 -C Apple/Release -cJf Burrow.app.txz ./
|
||||||
|
- name: Attach Artifact
|
||||||
|
uses: SierraSoftworks/gh-releases@v1.0.6
|
||||||
with:
|
with:
|
||||||
app-store-key: ${{ secrets.APPSTORE_KEY }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
|
overwrite: 'false'
|
||||||
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
|
files: ${{ matrix.configuration['artifact-file'] }}
|
||||||
archive-path: Burrow.xcarchive
|
|
||||||
product-name: Burrow.app
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ opt_in_rules:
|
||||||
- multiline_parameters
|
- multiline_parameters
|
||||||
- multiline_parameters_brackets
|
- multiline_parameters_brackets
|
||||||
- no_extension_access_modifier
|
- no_extension_access_modifier
|
||||||
|
- no_grouping_extension
|
||||||
- nslocalizedstring_key
|
- nslocalizedstring_key
|
||||||
- nslocalizedstring_require_bundle
|
- nslocalizedstring_require_bundle
|
||||||
- number_separator
|
- number_separator
|
||||||
|
|
@ -75,7 +76,9 @@ opt_in_rules:
|
||||||
- sorted_first_last
|
- sorted_first_last
|
||||||
- sorted_imports
|
- sorted_imports
|
||||||
- static_operator
|
- static_operator
|
||||||
|
- strict_fileprivate
|
||||||
- strong_iboutlet
|
- strong_iboutlet
|
||||||
|
- switch_case_on_newline
|
||||||
- test_case_accessibility
|
- test_case_accessibility
|
||||||
- toggle_bool
|
- toggle_bool
|
||||||
- trailing_closure
|
- trailing_closure
|
||||||
|
|
@ -94,5 +97,3 @@ disabled_rules:
|
||||||
- force_try
|
- force_try
|
||||||
- nesting
|
- nesting
|
||||||
- todo
|
- todo
|
||||||
- trailing_comma
|
|
||||||
- switch_case_on_newline
|
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,7 @@ INFOPLIST_KEY_UIStatusBarStyle[sdk=iphone*] = UIStatusBarStyleDefault
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad[sdk=iphone*] = UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad[sdk=iphone*] = UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone[sdk=iphone*] = UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone[sdk=iphone*] = UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
|
||||||
TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2
|
TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2
|
||||||
EXCLUDED_SOURCE_FILE_NAMES = MainMenu.xib
|
|
||||||
|
|
||||||
EXCLUDED_SOURCE_FILE_NAMES[sdk=macosx*] =
|
|
||||||
INFOPLIST_KEY_LSUIElement[sdk=macosx*] = YES
|
|
||||||
INFOPLIST_KEY_NSMainNibFile[sdk=macosx*] = MainMenu
|
|
||||||
INFOPLIST_KEY_NSPrincipalClass[sdk=macosx*] = NSApplication
|
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType[sdk=macosx*] = public.app-category.utilities
|
INFOPLIST_KEY_LSApplicationCategoryType[sdk=macosx*] = public.app-category.utilities
|
||||||
|
|
||||||
CODE_SIGN_ENTITLEMENTS = App/App-iOS.entitlements
|
CODE_SIGN_ENTITLEMENTS = App/App-iOS.entitlements
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import AppKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
@NSApplicationMain
|
|
||||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
private let quitItem: NSMenuItem = {
|
private let quitItem: NSMenuItem = {
|
||||||
let quitItem = NSMenuItem(
|
let quitItem = NSMenuItem(
|
||||||
|
|
@ -17,7 +16,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private let toggleItem: NSMenuItem = {
|
private let toggleItem: NSMenuItem = {
|
||||||
let toggleView = NSHostingView(rootView: MenuItemToggleView())
|
let toggleView = NSHostingView(rootView: MenuItemToggleView(tunnel: BurrowApp.tunnel))
|
||||||
toggleView.frame.size = CGSize(width: 300, height: 32)
|
toggleView.frame.size = CGSize(width: 300, height: 32)
|
||||||
toggleView.autoresizingMask = [.width]
|
toggleView.autoresizingMask = [.width]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"colors" : [
|
|
||||||
{
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "srgb",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0x50",
|
|
||||||
"green" : "0x37",
|
|
||||||
"red" : "0xEC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "flag-standalone-wtransparent.pdf",
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"colors" : [
|
|
||||||
{
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "srgb",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0x1A",
|
|
||||||
"green" : "0x17",
|
|
||||||
"red" : "0x88"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "WireGuard.svg",
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"preserves-vector-representation" : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<svg viewBox="0 0 46 79" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g stroke-width=".265" transform="matrix(1, 0, 0, 1, 144.316635, -78.301682)">
|
|
||||||
<path d="M -131.805 103.359 C -123.863 98.5 -113.717 101.469 -109.915 108.776 C -109.195 110.161 -109.103 112.293 -109.559 113.746 C -111.135 118.761 -114.855 121.574 -119.961 122.769 C -118.455 121.48 -117.257 120.019 -116.876 117.999 C -116.474 116.064 -116.911 114.05 -118.078 112.455 C -119.937 109.901 -123.263 108.888 -126.23 109.971 C -129.373 111.164 -131.095 114.033 -130.785 117.56 C -130.497 120.836 -128.011 122.959 -123.36 123.765 C -124.056 124.133 -124.591 124.404 -125.115 124.696 C -127.245 125.863 -129.099 127.475 -130.55 129.423 C -131.022 130.06 -131.347 130.112 -132.066 129.672 C -141.415 123.955 -142.016 109.605 -131.806 103.359 L -131.805 103.359 Z M -138.803 138.688 C -140.305 139.07 -141.761 139.634 -143.296 140.138 C -142.545 135.071 -136.612 130.404 -131.594 130.936 C -133.048 132.939 -133.896 135.317 -134.039 137.787 C -135.707 138.094 -137.278 138.301 -138.803 138.688 Z M -106.844 89.217 C -105.36 89.271 -103.873 89.248 -102.388 89.284 C -102.017 89.308 -101.649 89.359 -101.285 89.437 C -101.617 89.947 -101.992 90.428 -102.406 90.875 C -102.937 91.37 -103.537 91.853 -104.302 91.101 C -104.486 90.92 -104.921 90.962 -105.241 90.958 C -106.718 90.938 -108.197 90.891 -109.672 90.947 C -110.951 90.988 -112.227 91.118 -113.488 91.336 C -113.725 91.379 -114.078 92.165 -113.969 92.455 C -113.713 93.139 -113.339 93.893 -112.785 94.331 C -110.737 95.947 -108.559 97.399 -106.501 99.004 C -104.502 100.564 -102.641 102.274 -101.507 104.628 C -100.03 107.694 -99.987 110.91 -100.624 114.139 C -101.688 119.531 -104.416 123.998 -108.835 127.242 C -110.615 128.55 -112.819 129.292 -114.858 130.231 C -116.652 131.057 -118.498 131.769 -120.295 132.586 C -123.536 134.06 -125.357 137.577 -124.822 141.235 C -124.33 144.591 -121.386 147.392 -118.013 147.97 C -113.967 148.664 -109.792 146.034 -108.802 141.922 C -107.689 137.297 -110.202 133.168 -114.905 131.917 C -115.112 131.862 -115.32 131.81 -115.752 131.698 C -114.494 131.136 -113.407 130.735 -112.404 130.183 C -110.654 129.22 -108.936 128.201 -107.249 127.124 C -106.754 126.807 -106.486 126.807 -106.063 127.173 C -102.828 129.969 -100.899 133.448 -100.358 137.713 C -99.462 144.773 -102.804 151.259 -109.108 154.584 C -118.86 159.727 -130.794 153.873 -132.948 143.061 C -134.794 133.799 -128.257 125.399 -120.391 123.777 C -117.008 123.079 -113.914 121.671 -111.509 119.065 C -109.957 117.384 -109.205 115.942 -108.948 115.291 C -108.471 114.071 -108.227 112.772 -108.228 111.462 C -108.28 110.329 -108.546 109.216 -109.013 108.182 C -109.834 106.31 -112.98 103.332 -113.759 102.704 L -121.168 96.904 C -121.429 96.689 -121.723 96.705 -122.36 96.748 C -123.117 96.799 -125.053 96.906 -125.888 96.688 C -125.212 96.176 -123.371 95.432 -122.58 94.834 C -124.98 93.212 -127.721 93.798 -130.237 93.313 C -129.655 92.23 -126.776 90.564 -125.139 90.379 C -125.236 89.464 -125.385 88.556 -125.585 87.659 C -125.685 87.291 -126.096 86.934 -126.455 86.723 C -127.324 86.214 -128.246 85.793 -129.246 85.286 C -128.35 84.707 -127.313 84.386 -126.247 84.358 C -125.238 84.32 -124.228 84.418 -123.245 84.651 C -121.461 85.058 -120.037 84.792 -118.618 83.58 C -119.735 83.13 -120.852 82.719 -121.935 82.233 C -123.003 81.746 -124.043 81.202 -125.052 80.604 C -122.241 80.994 -119.523 82.048 -116.649 81.663 C -116.625 81.532 -116.6 81.402 -116.576 81.271 C -118.724 80.771 -120.873 80.271 -123.251 79.717 C -119.272 79.353 -115.567 79.293 -112.059 81.002 C -111.072 81.482 -110.039 81.88 -109.093 82.43 C -108.631 82.697 -108.321 83.225 -107.942 83.636 C -107.641 83.962 -107.4 84.399 -107.03 84.595 C -105.628 85.341 -104.084 85.37 -102.512 85.333 C -102.5 85.154 -102.489 84.986 -102.477 84.806 C -100.894 85.3 -99.113 87.125 -99.116 88.458 C -101.68 88.458 -104.242 88.449 -106.804 88.473 C -107.077 88.475 -107.349 88.675 -107.622 88.784 C -107.363 88.935 -107.108 89.207 -106.844 89.217 Z" style="fill: rgb(255, 255, 255);"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4 KiB |
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "WireGuardTitle.svg",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<svg width="1538" height="210" viewBox="0 0 1538 210" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M65.7132 204.476L0.500244 4.49222H24.9555L74.5901 158.827L125.493 4.49222H147.774L198.496 158.467L248.311 4.49222H272.041L207.009 204.476H188.895L136.182 43.4409L84.0113 204.476H65.7132ZM267.577 204.476V49.4109H292.213V204.476H267.577ZM349.324 136.908V204.476H325.051V50.1407H431.568C447.387 50.1407 459.766 53.9449 468.703 61.5533C477.638 69.1618 482.107 79.7288 482.107 93.2544C482.288 103.759 478.504 113.946 471.51 121.785C464.445 129.818 455.237 134.739 443.885 136.548L486.817 204.478H460.551L416.713 136.91L349.324 136.908ZM349.324 114.265H431.565C439.898 114.265 446.268 112.453 450.676 108.83C455.083 105.207 457.287 100.014 457.288 93.2518C457.288 86.49 455.084 81.3275 450.676 77.7643C446.266 74.2033 439.896 72.422 431.565 72.4202H349.324V114.265ZM504.99 204.476V49.7808H650.085V72.4241H529.259V111.008H608.602V133.289H529.259V182.198H656.785V204.48H504.98L504.99 204.476ZM827.46 150.318V120.972H772.934V97.9663H852.277V158.107C842.614 174.773 830.025 187.543 814.508 196.419C798.989 205.296 781.387 209.734 761.704 209.734C731.752 209.734 707.026 199.861 687.524 180.116C668.02 160.371 658.269 135.343 658.269 105.031C658.269 74.5986 668.051 49.5097 687.615 29.7643C707.179 10.0196 731.876 0.147217 761.704 0.147217C780.181 0.147217 797.028 4.19276 812.244 12.2839C827.443 20.3602 840.25 32.2924 849.379 46.8828L828.547 61.7363C822.413 49.9333 812.97 40.1755 801.375 33.6582C789.281 26.8286 775.592 23.3281 761.704 23.5135C739.242 23.5135 720.644 31.2122 705.911 46.6097C691.175 62.0066 683.808 81.4796 683.81 105.029C683.81 128.578 691.177 148.021 705.911 163.358C720.643 178.696 739.241 186.365 761.704 186.363C775.711 186.363 788.18 183.344 799.111 177.306C810.039 171.269 819.488 162.274 827.46 150.318ZM879.358 50.1436H903.631V149.231C903.631 164.085 907.134 174.108 914.138 179.301C921.141 184.494 935.029 187.091 955.802 187.09C976.693 187.09 990.642 184.494 997.647 179.301C1004.65 174.11 1008.15 164.087 1008.15 149.231V50.1436H1032.25V155.57C1032.25 174.531 1026.24 188.238 1014.22 196.691C1002.2 205.142 982.61 209.369 955.439 209.372C928.386 209.372 908.943 205.205 897.11 196.872C885.273 188.539 879.355 174.772 879.357 155.57L879.358 50.1436ZM1028.45 204.476L1107.07 49.7808H1122.29L1201.63 204.476H1175.73L1155.62 165.167H1073.92L1053.99 204.476H1028.45ZM1084.43 144.698H1144.93L1114.86 85.4626L1084.43 144.698ZM1228.55 136.908V204.476H1204.27V50.1406H1310.79C1326.61 50.1406 1338.99 53.9448 1347.93 61.5532C1356.86 69.1617 1361.33 79.7287 1361.33 93.2543C1361.51 103.759 1357.73 113.945 1350.73 121.784C1343.67 129.817 1334.46 134.739 1323.11 136.548L1366.04 204.478H1339.77L1295.94 136.91L1228.55 136.908ZM1228.55 114.265H1310.79C1319.12 114.265 1325.49 112.453 1329.9 108.83C1334.31 105.207 1336.51 100.014 1336.51 93.2517C1336.51 86.4899 1334.31 81.3274 1329.9 77.7642C1325.49 74.2032 1319.12 72.4218 1310.79 72.4201H1228.55V114.265ZM1453.24 49.7818C1478.48 49.7818 1498.83 56.9973 1514.29 71.4281C1529.74 85.861 1537.47 104.61 1537.47 127.674C1537.47 150.983 1529.9 169.611 1514.74 183.559C1499.58 197.506 1479.08 204.48 1453.24 204.481H1384.59V49.786H1453.24L1453.24 49.7818ZM1453.6 72.0631H1408.86V182.2H1453.6C1471.96 182.2 1486.39 177.278 1496.9 167.436C1507.4 157.595 1512.66 144.221 1512.66 127.312C1512.66 111.009 1507.22 97.7246 1496.35 87.4596C1485.48 77.1966 1471.23 72.0651 1453.6 72.0631Z" fill="white"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
|
@ -1,13 +1,21 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
#if !os(macOS)
|
|
||||||
@MainActor
|
|
||||||
@main
|
@main
|
||||||
|
@MainActor
|
||||||
struct BurrowApp: App {
|
struct BurrowApp: App {
|
||||||
|
static let tunnel = Tunnel { manager, proto in
|
||||||
|
proto.serverAddress = "hackclub.com"
|
||||||
|
manager.localizedDescription = "Burrow"
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
@NSApplicationDelegateAdaptor(AppDelegate.self)
|
||||||
|
var delegate
|
||||||
|
#endif
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
BurrowView()
|
TunnelView(tunnel: Self.tunnel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct BurrowView: View {
|
|
||||||
var body: some View {
|
|
||||||
NavigationStack {
|
|
||||||
VStack {
|
|
||||||
NetworkCarouselView()
|
|
||||||
Spacer()
|
|
||||||
TunnelStatusView()
|
|
||||||
TunnelButton()
|
|
||||||
.padding(.bottom)
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.navigationTitle("Networks")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct NetworkView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
BurrowView()
|
|
||||||
.environment(\.tunnel, PreviewTunnel())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct FloatingButtonStyle: ButtonStyle {
|
|
||||||
static let duration = 0.08
|
|
||||||
|
|
||||||
var color: Color
|
|
||||||
var cornerRadius: CGFloat
|
|
||||||
|
|
||||||
func makeBody(configuration: Configuration) -> some View {
|
|
||||||
configuration.label
|
|
||||||
.font(.headline)
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.frame(minHeight: 48)
|
|
||||||
.padding(.horizontal)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: cornerRadius)
|
|
||||||
.fill(
|
|
||||||
LinearGradient(
|
|
||||||
colors: [
|
|
||||||
configuration.isPressed ? color.opacity(0.9) : color.opacity(0.9),
|
|
||||||
configuration.isPressed ? color.opacity(0.9) : color
|
|
||||||
],
|
|
||||||
startPoint: .init(x: 0.2, y: 0),
|
|
||||||
endPoint: .init(x: 0.8, y: 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: cornerRadius)
|
|
||||||
.fill(configuration.isPressed ? .black : .white)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.shadow(color: .black.opacity(configuration.isPressed ? 0.0 : 0.1), radius: 2.5, x: 0, y: 2)
|
|
||||||
.scaleEffect(configuration.isPressed ? 0.975 : 1.0)
|
|
||||||
.padding(.bottom, 2)
|
|
||||||
.animation(
|
|
||||||
configuration.isPressed ? .easeOut(duration: Self.duration) : .easeIn(duration: Self.duration),
|
|
||||||
value: configuration.isPressed
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ButtonStyle where Self == FloatingButtonStyle {
|
|
||||||
static var floating: FloatingButtonStyle {
|
|
||||||
floating()
|
|
||||||
}
|
|
||||||
|
|
||||||
static func floating(color: Color = .accentColor, cornerRadius: CGFloat = 10) -> FloatingButtonStyle {
|
|
||||||
FloatingButtonStyle(color: color, cornerRadius: cornerRadius)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,679 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
|
||||||
<dependencies>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22689"/>
|
|
||||||
</dependencies>
|
|
||||||
<objects>
|
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
|
||||||
<connections>
|
|
||||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
|
|
||||||
</connections>
|
|
||||||
</customObject>
|
|
||||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
|
||||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
|
||||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="BurrowApp" customModuleProvider="target"/>
|
|
||||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
|
||||||
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Burrow" id="1Xt-HY-uBw">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Burrow" systemMenu="apple" id="uQy-DD-JDr">
|
|
||||||
<items>
|
|
||||||
<menuItem title="About Burrow" id="5kV-Vb-QxS">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
|
||||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
|
||||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
|
||||||
<menuItem title="Services" id="NMo-om-nkz">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
|
||||||
<menuItem title="Hide Burrow" keyEquivalent="h" id="Olw-nP-bQN">
|
|
||||||
<connections>
|
|
||||||
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Show All" id="Kd2-mp-pUS">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
|
||||||
<menuItem title="Quit Burrow" keyEquivalent="q" id="4sb-4s-VLi">
|
|
||||||
<connections>
|
|
||||||
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="File" id="dMs-cI-mzQ">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
|
||||||
<items>
|
|
||||||
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
|
|
||||||
<connections>
|
|
||||||
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
|
|
||||||
<connections>
|
|
||||||
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Open Recent" id="tXI-mr-wws">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Clear Menu" id="vNY-rz-j42">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
|
|
||||||
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
|
||||||
<connections>
|
|
||||||
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
|
|
||||||
<connections>
|
|
||||||
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
|
|
||||||
<connections>
|
|
||||||
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
|
|
||||||
<connections>
|
|
||||||
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
|
|
||||||
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
|
|
||||||
<connections>
|
|
||||||
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
|
||||||
<connections>
|
|
||||||
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
|
||||||
<connections>
|
|
||||||
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
|
||||||
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
|
||||||
<connections>
|
|
||||||
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
|
||||||
<connections>
|
|
||||||
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
|
||||||
<connections>
|
|
||||||
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
|
||||||
<connections>
|
|
||||||
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
|
||||||
<menuItem title="Find" id="4EN-yA-p0u">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
|
||||||
<connections>
|
|
||||||
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
|
||||||
<connections>
|
|
||||||
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
|
||||||
<connections>
|
|
||||||
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
|
||||||
<connections>
|
|
||||||
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
|
||||||
<connections>
|
|
||||||
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
|
||||||
<connections>
|
|
||||||
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
|
||||||
<connections>
|
|
||||||
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
|
||||||
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Substitutions" id="9ic-FL-obx">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
|
||||||
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Smart Links" id="cwL-P1-jid">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Speech" id="xrE-MZ-jX0">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Format" id="jxT-CU-nIS">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Font" id="Gi5-1S-RQB">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
|
|
||||||
<connections>
|
|
||||||
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
|
|
||||||
<connections>
|
|
||||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
|
|
||||||
<connections>
|
|
||||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
|
|
||||||
<connections>
|
|
||||||
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
|
|
||||||
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
|
|
||||||
<connections>
|
|
||||||
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
|
|
||||||
<connections>
|
|
||||||
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
|
|
||||||
<menuItem title="Kern" id="jBQ-r6-VK2">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Use Default" id="GUa-eO-cwY">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Use None" id="cDB-IK-hbR">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Tighten" id="46P-cB-AYj">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Loosen" id="ogc-rX-tC1">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Ligatures" id="o6e-r0-MWq">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Use Default" id="agt-UL-0e3">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Use None" id="J7y-lM-qPV">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Use All" id="xQD-1f-W4t">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Baseline" id="OaQ-X3-Vso">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Use Default" id="3Om-Ey-2VK">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Superscript" id="Rqc-34-cIF">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Subscript" id="I0S-gh-46l">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Raise" id="2h7-ER-AoG">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Lower" id="1tx-W0-xDw">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
|
|
||||||
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
|
|
||||||
<connections>
|
|
||||||
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
|
|
||||||
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Text" id="Fal-I4-PZk">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Text" id="d9c-me-L2H">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
|
|
||||||
<connections>
|
|
||||||
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
|
|
||||||
<connections>
|
|
||||||
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Justify" id="J5U-5w-g23">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
|
|
||||||
<connections>
|
|
||||||
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
|
|
||||||
<menuItem title="Writing Direction" id="H1b-Si-o9J">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem id="YGs-j5-SAR">
|
|
||||||
<string key="title"> Default</string>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem id="Lbh-J2-qVU">
|
|
||||||
<string key="title"> Left to Right</string>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem id="jFq-tB-4Kx">
|
|
||||||
<string key="title"> Right to Left</string>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
|
|
||||||
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem id="Nop-cj-93Q">
|
|
||||||
<string key="title"> Default</string>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem id="BgM-ve-c93">
|
|
||||||
<string key="title"> Left to Right</string>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem id="RB4-Sm-HuC">
|
|
||||||
<string key="title"> Right to Left</string>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
|
|
||||||
<menuItem title="Show Ruler" id="vLm-3I-IUL">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="View" id="H8h-7b-M4v">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
|
||||||
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleSidebar:" target="-1" id="iwa-gc-5KM"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Window" id="aUF-d1-5bR">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
|
||||||
<connections>
|
|
||||||
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
|
||||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Help" id="wpr-3q-Mcd">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Burrow Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
|
||||||
<connections>
|
|
||||||
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
<point key="canvasLocation" x="200" y="121"/>
|
|
||||||
</menu>
|
|
||||||
</objects>
|
|
||||||
</document>
|
|
||||||
60
Apple/App/Menu/MenuView.swift
Normal file
60
Apple/App/Menu/MenuView.swift
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// MenuView.swift
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by Thomas Stubblefield on 5/13/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MenuItemToggleView: View {
|
||||||
|
var tunnel: Tunnel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
Text("Burrow")
|
||||||
|
.font(.headline)
|
||||||
|
Spacer()
|
||||||
|
Toggle("Burrow", isOn: tunnel.isOn)
|
||||||
|
.labelsHidden()
|
||||||
|
.disabled(tunnel.isDisabled)
|
||||||
|
.toggleStyle(.switch)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 4)
|
||||||
|
.padding(10)
|
||||||
|
.frame(minWidth: 300, minHeight: 32, maxHeight: 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Tunnel {
|
||||||
|
var isDisabled: Bool {
|
||||||
|
switch self.status {
|
||||||
|
case .disconnected, .permissionRequired, .connected:
|
||||||
|
return false
|
||||||
|
case .unknown, .disabled, .connecting, .reasserting, .disconnecting, .invalid, .configurationReadWriteFailed:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isOn: Binding<Bool> {
|
||||||
|
Binding {
|
||||||
|
switch self.status {
|
||||||
|
case .connecting, .reasserting, .connected:
|
||||||
|
true
|
||||||
|
default:
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} set: { newValue in
|
||||||
|
switch (self.status, newValue) {
|
||||||
|
case (.permissionRequired, true):
|
||||||
|
Task { try await self.configure() }
|
||||||
|
case (.disconnected, true):
|
||||||
|
try? self.start()
|
||||||
|
case (.connected, false):
|
||||||
|
self.stop()
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
//
|
|
||||||
// MenuItemToggleView.swift
|
|
||||||
// App
|
|
||||||
//
|
|
||||||
// Created by Thomas Stubblefield on 5/13/23.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct MenuItemToggleView: View {
|
|
||||||
@Environment(\.tunnel)
|
|
||||||
var tunnel: Tunnel
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text("Burrow")
|
|
||||||
.font(.headline)
|
|
||||||
Text(tunnel.status.description)
|
|
||||||
.font(.subheadline)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
Toggle(isOn: tunnel.toggleIsOn) {
|
|
||||||
}
|
|
||||||
.disabled(tunnel.toggleDisabled)
|
|
||||||
.toggleStyle(.switch)
|
|
||||||
}
|
|
||||||
.accessibilityElement(children: .combine)
|
|
||||||
.padding(.horizontal, 4)
|
|
||||||
.padding(10)
|
|
||||||
.frame(minWidth: 300, minHeight: 32, maxHeight: 32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Tunnel {
|
|
||||||
fileprivate var toggleDisabled: Bool {
|
|
||||||
switch status {
|
|
||||||
case .disconnected, .permissionRequired, .connected, .disconnecting:
|
|
||||||
false
|
|
||||||
case .unknown, .disabled, .connecting, .reasserting, .invalid, .configurationReadWriteFailed:
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var toggleIsOn: Binding<Bool> {
|
|
||||||
Binding {
|
|
||||||
switch status {
|
|
||||||
case .connecting, .reasserting, .connected:
|
|
||||||
true
|
|
||||||
default:
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} set: { newValue in
|
|
||||||
switch (status, newValue) {
|
|
||||||
case (.permissionRequired, true):
|
|
||||||
enable()
|
|
||||||
case (_, true):
|
|
||||||
start()
|
|
||||||
case (_, false):
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
import BurrowShared
|
|
||||||
import NetworkExtension
|
|
||||||
|
|
||||||
@Observable
|
|
||||||
class NetworkExtensionTunnel: Tunnel {
|
|
||||||
@MainActor private(set) var status: TunnelStatus = .unknown
|
|
||||||
private var error: NEVPNError?
|
|
||||||
|
|
||||||
private let logger = Logger.logger(for: Tunnel.self)
|
|
||||||
private let bundleIdentifier: String
|
|
||||||
private var tasks: [Task<Void, Error>] = []
|
|
||||||
|
|
||||||
// Each manager corresponds to one entry in the Settings app.
|
|
||||||
// Our goal is to maintain a single manager, so we create one if none exist and delete any extra.
|
|
||||||
private var managers: [NEVPNManager]? {
|
|
||||||
didSet { Task { await updateStatus() } }
|
|
||||||
}
|
|
||||||
|
|
||||||
private var currentStatus: TunnelStatus {
|
|
||||||
guard let managers = managers else {
|
|
||||||
guard let error = error else {
|
|
||||||
return .unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
switch error.code {
|
|
||||||
case .configurationReadWriteFailed:
|
|
||||||
return .configurationReadWriteFailed
|
|
||||||
default:
|
|
||||||
return .unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let manager = managers.first else {
|
|
||||||
return .permissionRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
guard manager.isEnabled else {
|
|
||||||
return .disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
return manager.connection.tunnelStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
convenience init() {
|
|
||||||
self.init(Constants.networkExtensionBundleIdentifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
init(_ bundleIdentifier: String) {
|
|
||||||
self.bundleIdentifier = bundleIdentifier
|
|
||||||
|
|
||||||
let center = NotificationCenter.default
|
|
||||||
let configurationChanged = Task { [weak self] in
|
|
||||||
for try await _ in center.notifications(named: .NEVPNConfigurationChange).map({ _ in () }) {
|
|
||||||
await self?.update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let statusChanged = Task { [weak self] in
|
|
||||||
for try await _ in center.notifications(named: .NEVPNStatusDidChange).map({ _ in () }) {
|
|
||||||
await self?.updateStatus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks = [configurationChanged, statusChanged]
|
|
||||||
|
|
||||||
Task { await update() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private func update() async {
|
|
||||||
do {
|
|
||||||
managers = try await NETunnelProviderManager.managers
|
|
||||||
await self.updateStatus()
|
|
||||||
} catch let vpnError as NEVPNError {
|
|
||||||
error = vpnError
|
|
||||||
} catch {
|
|
||||||
logger.error("Failed to update VPN configurations: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateStatus() async {
|
|
||||||
await MainActor.run {
|
|
||||||
status = currentStatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func configure() async throws {
|
|
||||||
if managers == nil {
|
|
||||||
await update()
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let managers = managers else { return }
|
|
||||||
|
|
||||||
if managers.count > 1 {
|
|
||||||
try await withThrowingTaskGroup(of: Void.self, returning: Void.self) { group in
|
|
||||||
for manager in managers.suffix(from: 1) {
|
|
||||||
group.addTask { try await manager.remove() }
|
|
||||||
}
|
|
||||||
try await group.waitForAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard managers.isEmpty else { return }
|
|
||||||
|
|
||||||
let manager = NETunnelProviderManager()
|
|
||||||
manager.localizedDescription = "Burrow"
|
|
||||||
|
|
||||||
let proto = NETunnelProviderProtocol()
|
|
||||||
proto.providerBundleIdentifier = bundleIdentifier
|
|
||||||
proto.serverAddress = "hackclub.com"
|
|
||||||
|
|
||||||
manager.protocolConfiguration = proto
|
|
||||||
try await manager.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
func start() {
|
|
||||||
guard let manager = managers?.first else { return }
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
if !manager.isEnabled {
|
|
||||||
manager.isEnabled = true
|
|
||||||
try await manager.save()
|
|
||||||
}
|
|
||||||
try manager.connection.startVPNTunnel()
|
|
||||||
} catch {
|
|
||||||
logger.error("Failed to start: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func stop() {
|
|
||||||
guard let manager = managers?.first else { return }
|
|
||||||
manager.connection.stopVPNTunnel()
|
|
||||||
}
|
|
||||||
|
|
||||||
func enable() {
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
try await configure()
|
|
||||||
} catch {
|
|
||||||
logger.error("Failed to enable: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
tasks.forEach { $0.cancel() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NEVPNConnection {
|
|
||||||
fileprivate var tunnelStatus: TunnelStatus {
|
|
||||||
switch status {
|
|
||||||
case .connected:
|
|
||||||
.connected(connectedDate!)
|
|
||||||
case .connecting:
|
|
||||||
.connecting
|
|
||||||
case .disconnecting:
|
|
||||||
.disconnecting
|
|
||||||
case .disconnected:
|
|
||||||
.disconnected
|
|
||||||
case .reasserting:
|
|
||||||
.reasserting
|
|
||||||
case .invalid:
|
|
||||||
.invalid
|
|
||||||
@unknown default:
|
|
||||||
.unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct NetworkView<Content: View>: View {
|
|
||||||
var color: Color
|
|
||||||
var content: () -> Content
|
|
||||||
|
|
||||||
private var gradient: LinearGradient {
|
|
||||||
LinearGradient(
|
|
||||||
colors: [
|
|
||||||
color.opacity(0.8),
|
|
||||||
color
|
|
||||||
],
|
|
||||||
startPoint: .init(x: 0.2, y: 0),
|
|
||||||
endPoint: .init(x: 0.8, y: 1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
content()
|
|
||||||
.frame(maxWidth: .infinity, minHeight: 175, maxHeight: 175)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.fill(gradient)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.fill(.white)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.shadow(color: .black.opacity(0.1), radius: 3.0, x: 0, y: 2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AddNetworkView: View {
|
|
||||||
var body: some View {
|
|
||||||
Text("Add Network")
|
|
||||||
.frame(maxWidth: .infinity, minHeight: 175, maxHeight: 175)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.stroke(style: .init(lineWidth: 2, dash: [6]))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NetworkView where Content == AnyView {
|
|
||||||
init(network: any Network) {
|
|
||||||
color = network.backgroundColor
|
|
||||||
content = { AnyView(network.label) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NetworkCarouselView: View {
|
|
||||||
var networks: [any Network] = [
|
|
||||||
HackClub(id: "1"),
|
|
||||||
HackClub(id: "2"),
|
|
||||||
WireGuard(id: "4"),
|
|
||||||
HackClub(id: "5"),
|
|
||||||
]
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ScrollView(.horizontal) {
|
|
||||||
LazyHStack {
|
|
||||||
ForEach(networks, id: \.id) { network in
|
|
||||||
NetworkView(network: network)
|
|
||||||
.containerRelativeFrame(.horizontal, count: 10, span: 7, spacing: 0, alignment: .center)
|
|
||||||
.scrollTransition(.interactive, axis: .horizontal) { content, phase in
|
|
||||||
content
|
|
||||||
.scaleEffect(1.0 - abs(phase.value) * 0.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AddNetworkView()
|
|
||||||
}
|
|
||||||
.scrollTargetLayout()
|
|
||||||
}
|
|
||||||
.scrollClipDisabled()
|
|
||||||
.scrollIndicators(.hidden)
|
|
||||||
.defaultScrollAnchor(.center)
|
|
||||||
.scrollTargetBehavior(.viewAligned)
|
|
||||||
.containerRelativeFrame(.horizontal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct NetworkCarouselView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
NetworkCarouselView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct HackClub: Network {
|
|
||||||
var id: String
|
|
||||||
var backgroundColor: Color { .init("HackClub") }
|
|
||||||
|
|
||||||
var label: some View {
|
|
||||||
GeometryReader { reader in
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Image("HackClub")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(height: reader.size.height / 4)
|
|
||||||
Spacer()
|
|
||||||
Text("@conradev")
|
|
||||||
.foregroundStyle(.white)
|
|
||||||
.font(.body.monospaced())
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
protocol Network {
|
|
||||||
associatedtype Label: View
|
|
||||||
|
|
||||||
var id: String { get }
|
|
||||||
var backgroundColor: Color { get }
|
|
||||||
|
|
||||||
var label: Label { get }
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct WireGuard: Network {
|
|
||||||
var id: String
|
|
||||||
var backgroundColor: Color { .init("WireGuard") }
|
|
||||||
|
|
||||||
var label: some View {
|
|
||||||
GeometryReader { reader in
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
HStack {
|
|
||||||
Image("WireGuard")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
Image("WireGuardTitle")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(width: reader.size.width / 2)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, maxHeight: reader.size.height / 4)
|
|
||||||
Spacer()
|
|
||||||
Text("@conradev")
|
|
||||||
.foregroundStyle(.white)
|
|
||||||
.font(.body.monospaced())
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
42
Apple/App/Status.swift
Normal file
42
Apple/App/Status.swift
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import Foundation
|
||||||
|
import NetworkExtension
|
||||||
|
|
||||||
|
extension Tunnel {
|
||||||
|
enum Status: CustomStringConvertible, Equatable, Hashable {
|
||||||
|
case unknown
|
||||||
|
case permissionRequired
|
||||||
|
case disabled
|
||||||
|
case connecting
|
||||||
|
case connected(Date)
|
||||||
|
case disconnecting
|
||||||
|
case disconnected
|
||||||
|
case reasserting
|
||||||
|
case invalid
|
||||||
|
case configurationReadWriteFailed
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
switch self {
|
||||||
|
case .unknown:
|
||||||
|
return "Unknown"
|
||||||
|
case .permissionRequired:
|
||||||
|
return "Permission Required"
|
||||||
|
case .disconnected:
|
||||||
|
return "Disconnected"
|
||||||
|
case .disabled:
|
||||||
|
return "Disabled"
|
||||||
|
case .connecting:
|
||||||
|
return "Connecting"
|
||||||
|
case .connected:
|
||||||
|
return "Connected"
|
||||||
|
case .disconnecting:
|
||||||
|
return "Disconnecting"
|
||||||
|
case .reasserting:
|
||||||
|
return "Reasserting"
|
||||||
|
case .invalid:
|
||||||
|
return "Invalid"
|
||||||
|
case .configurationReadWriteFailed:
|
||||||
|
return "System Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,50 +1,146 @@
|
||||||
|
import BurrowShared
|
||||||
|
import NetworkExtension
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol Tunnel {
|
|
||||||
var status: TunnelStatus { get }
|
|
||||||
|
|
||||||
func start()
|
|
||||||
func stop()
|
|
||||||
func enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TunnelStatus: Equatable, Hashable {
|
|
||||||
case unknown
|
|
||||||
case permissionRequired
|
|
||||||
case disabled
|
|
||||||
case connecting
|
|
||||||
case connected(Date)
|
|
||||||
case disconnecting
|
|
||||||
case disconnected
|
|
||||||
case reasserting
|
|
||||||
case invalid
|
|
||||||
case configurationReadWriteFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TunnelKey: EnvironmentKey {
|
|
||||||
static let defaultValue: any Tunnel = NetworkExtensionTunnel()
|
|
||||||
}
|
|
||||||
|
|
||||||
extension EnvironmentValues {
|
|
||||||
var tunnel: any Tunnel {
|
|
||||||
get { self[TunnelKey.self] }
|
|
||||||
set { self[TunnelKey.self] = newValue }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
@Observable
|
@Observable
|
||||||
class PreviewTunnel: Tunnel {
|
class Tunnel {
|
||||||
var status: TunnelStatus = .permissionRequired
|
private(set) var status: Status = .unknown
|
||||||
|
private var error: NEVPNError?
|
||||||
|
|
||||||
func start() {
|
private let logger = Logger.logger(for: Tunnel.self)
|
||||||
status = .connected(.now)
|
private let bundleIdentifier: String
|
||||||
|
private let configure: (NETunnelProviderManager, NETunnelProviderProtocol) -> Void
|
||||||
|
private var tasks: [Task<Void, Error>] = []
|
||||||
|
|
||||||
|
// Each manager corresponds to one entry in the Settings app.
|
||||||
|
// Our goal is to maintain a single manager, so we create one if none exist and delete extra if there are any.
|
||||||
|
private var managers: [NEVPNManager]? {
|
||||||
|
didSet { status = currentStatus }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var currentStatus: Status {
|
||||||
|
guard let managers = managers else {
|
||||||
|
guard let error = error else {
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
switch error.code {
|
||||||
|
case .configurationReadWriteFailed:
|
||||||
|
return .configurationReadWriteFailed
|
||||||
|
default:
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let manager = managers.first else {
|
||||||
|
return .permissionRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
guard manager.isEnabled else {
|
||||||
|
return .disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
return manager.connection.tunnelStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(configure: @escaping (NETunnelProviderManager, NETunnelProviderProtocol) -> Void) {
|
||||||
|
self.init("com.hackclub.burrow.network", configure: configure)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ bundleIdentifier: String, configure: @escaping (NETunnelProviderManager, NETunnelProviderProtocol) -> Void) {
|
||||||
|
self.bundleIdentifier = bundleIdentifier
|
||||||
|
self.configure = configure
|
||||||
|
|
||||||
|
let center = NotificationCenter.default
|
||||||
|
let configurationChanged = Task {
|
||||||
|
for try await _ in center.notifications(named: .NEVPNConfigurationChange).map({ _ in () }) {
|
||||||
|
await update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let statusChanged = Task {
|
||||||
|
for try await _ in center.notifications(named: .NEVPNStatusDidChange).map({ _ in () }) {
|
||||||
|
await MainActor.run {
|
||||||
|
status = currentStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks = [configurationChanged, statusChanged]
|
||||||
|
|
||||||
|
Task { await update() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func update() async {
|
||||||
|
do {
|
||||||
|
let updated = try await NETunnelProviderManager.managers
|
||||||
|
await MainActor.run {
|
||||||
|
managers = updated
|
||||||
|
}
|
||||||
|
} catch let vpnError as NEVPNError {
|
||||||
|
error = vpnError
|
||||||
|
} catch {
|
||||||
|
logger.error("Failed to update VPN configurations: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func configure() async throws {
|
||||||
|
if managers == nil {
|
||||||
|
await update()
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let managers = managers else { return }
|
||||||
|
|
||||||
|
if managers.count > 1 {
|
||||||
|
try await withThrowingTaskGroup(of: Void.self, returning: Void.self) { group in
|
||||||
|
for manager in managers.suffix(from: 1) {
|
||||||
|
group.addTask { try await manager.remove() }
|
||||||
|
}
|
||||||
|
try await group.waitForAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if managers.isEmpty {
|
||||||
|
let manager = NETunnelProviderManager()
|
||||||
|
let proto = NETunnelProviderProtocol()
|
||||||
|
proto.providerBundleIdentifier = bundleIdentifier
|
||||||
|
configure(manager, proto)
|
||||||
|
|
||||||
|
manager.protocolConfiguration = proto
|
||||||
|
try await manager.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() throws {
|
||||||
|
guard let manager = managers?.first else { return }
|
||||||
|
try manager.connection.startVPNTunnel()
|
||||||
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
status = .disconnected
|
guard let manager = managers?.first else { return }
|
||||||
|
manager.connection.stopVPNTunnel()
|
||||||
}
|
}
|
||||||
func enable() {
|
|
||||||
status = .disconnected
|
deinit {
|
||||||
|
tasks.forEach { $0.cancel() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NEVPNConnection {
|
||||||
|
var tunnelStatus: Tunnel.Status {
|
||||||
|
switch status {
|
||||||
|
case .connected:
|
||||||
|
.connected(connectedDate!)
|
||||||
|
case .connecting:
|
||||||
|
.connecting
|
||||||
|
case .disconnecting:
|
||||||
|
.disconnecting
|
||||||
|
case .disconnected:
|
||||||
|
.disconnected
|
||||||
|
case .reasserting:
|
||||||
|
.reasserting
|
||||||
|
case .invalid:
|
||||||
|
.invalid
|
||||||
|
@unknown default:
|
||||||
|
.unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct TunnelButton: View {
|
|
||||||
@Environment(\.tunnel)
|
|
||||||
var tunnel: any Tunnel
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
if let action = tunnel.action {
|
|
||||||
Button {
|
|
||||||
tunnel.perform(action)
|
|
||||||
} label: {
|
|
||||||
Text(action.description)
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
.buttonStyle(.floating)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Tunnel {
|
|
||||||
fileprivate var action: TunnelButton.Action? {
|
|
||||||
switch status {
|
|
||||||
case .permissionRequired, .invalid:
|
|
||||||
.enable
|
|
||||||
case .disabled, .disconnecting, .disconnected:
|
|
||||||
.start
|
|
||||||
case .connecting, .connected, .reasserting:
|
|
||||||
.stop
|
|
||||||
case .unknown, .configurationReadWriteFailed:
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TunnelButton {
|
|
||||||
fileprivate enum Action {
|
|
||||||
case enable
|
|
||||||
case start
|
|
||||||
case stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TunnelButton.Action {
|
|
||||||
var description: LocalizedStringKey {
|
|
||||||
switch self {
|
|
||||||
case .enable: "Enable"
|
|
||||||
case .start: "Start"
|
|
||||||
case .stop: "Stop"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Tunnel {
|
|
||||||
fileprivate func perform(_ action: TunnelButton.Action) {
|
|
||||||
switch action {
|
|
||||||
case .enable: enable()
|
|
||||||
case .start: start()
|
|
||||||
case .stop: stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct TunnelStatusView: View {
|
|
||||||
@Environment(\.tunnel)
|
|
||||||
var tunnel: any Tunnel
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Text(tunnel.status.description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TunnelStatus: CustomStringConvertible {
|
|
||||||
var description: String {
|
|
||||||
switch self {
|
|
||||||
case .unknown:
|
|
||||||
"Unknown"
|
|
||||||
case .permissionRequired:
|
|
||||||
"Permission Required"
|
|
||||||
case .disconnected:
|
|
||||||
"Disconnected"
|
|
||||||
case .disabled:
|
|
||||||
"Disabled"
|
|
||||||
case .connecting:
|
|
||||||
"Connecting…"
|
|
||||||
case .connected:
|
|
||||||
"Connected"
|
|
||||||
case .disconnecting:
|
|
||||||
"Disconnecting…"
|
|
||||||
case .reasserting:
|
|
||||||
"Reasserting…"
|
|
||||||
case .invalid:
|
|
||||||
"Invalid"
|
|
||||||
case .configurationReadWriteFailed:
|
|
||||||
"System Error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
34
Apple/App/TunnelView.swift
Normal file
34
Apple/App/TunnelView.swift
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct TunnelView: View {
|
||||||
|
var tunnel: Tunnel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Text(verbatim: tunnel.status.description)
|
||||||
|
switch tunnel.status {
|
||||||
|
case .connected:
|
||||||
|
Button("Disconnect", action: stop)
|
||||||
|
case .permissionRequired:
|
||||||
|
Button("Allow", action: configure)
|
||||||
|
case .disconnected:
|
||||||
|
Button("Start", action: start)
|
||||||
|
default:
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func start() {
|
||||||
|
try? tunnel.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func stop() {
|
||||||
|
tunnel.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func configure() {
|
||||||
|
Task { try await tunnel.configure() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,32 +9,24 @@
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; };
|
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; };
|
||||||
0B46E8E02AC918CA00BA2A3C /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B46E8DF2AC918CA00BA2A3C /* Client.swift */; };
|
0B46E8E02AC918CA00BA2A3C /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B46E8DF2AC918CA00BA2A3C /* Client.swift */; };
|
||||||
43AA26D82A10004900F14CE6 /* MenuItemToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */; };
|
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuView.swift */; };
|
||||||
D00117312B2FFFC900D87C25 /* NWConnection+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */; };
|
D00117312B2FFFC900D87C25 /* NWConnection+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */; };
|
||||||
D00117332B3001A400D87C25 /* NewlineProtocolFramer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */; };
|
D00117332B3001A400D87C25 /* NewlineProtocolFramer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */; };
|
||||||
D001173B2B30341C00D87C25 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D001173A2B30341C00D87C25 /* Logging.swift */; };
|
D001173B2B30341C00D87C25 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D001173A2B30341C00D87C25 /* Logging.swift */; };
|
||||||
D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; };
|
D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; };
|
||||||
D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; };
|
D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; };
|
||||||
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; };
|
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; };
|
||||||
D01A79312B81630D0024EC91 /* NetworkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A79302B81630D0024EC91 /* NetworkView.swift */; };
|
|
||||||
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
|
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
|
||||||
D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
D032E6522B8A79C20006B8AD /* HackClub.swift in Sources */ = {isa = PBXBuildFile; fileRef = D032E6512B8A79C20006B8AD /* HackClub.swift */; };
|
|
||||||
D032E6542B8A79DA0006B8AD /* WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D032E6532B8A79DA0006B8AD /* WireGuard.swift */; };
|
|
||||||
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; };
|
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; };
|
||||||
D05B9F7829E39EEC008CB1F9 /* BurrowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7729E39EEC008CB1F9 /* BurrowView.swift */; };
|
D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */; };
|
||||||
D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D05B9F7929E39EED008CB1F9 /* Assets.xcassets */; };
|
D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D05B9F7929E39EED008CB1F9 /* Assets.xcassets */; };
|
||||||
D05EF8C82B81818D0017AB4F /* FloatingButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */; };
|
|
||||||
D08252762B5C9FC4005DA378 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08252752B5C9FC4005DA378 /* Constants.swift */; };
|
D08252762B5C9FC4005DA378 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08252752B5C9FC4005DA378 /* Constants.swift */; };
|
||||||
D09150422B9D2AF700BE3CB0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D09150412B9D2AF700BE3CB0 /* MainMenu.xib */; };
|
|
||||||
D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */; };
|
D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */; };
|
||||||
|
D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FE2A086E1C00AD070D /* Status.swift */; };
|
||||||
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B98FC629FDC5B5004E7149 /* Tunnel.swift */; };
|
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B98FC629FDC5B5004E7149 /* Tunnel.swift */; };
|
||||||
D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0BCC6032A09535900AD070D /* libburrow.a */; };
|
D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0BCC6032A09535900AD070D /* libburrow.a */; };
|
||||||
D0BCC60A2A09A0B800AD070D /* build-rust.sh in Resources */ = {isa = PBXBuildFile; fileRef = D0B98FBF29FD8072004E7149 /* build-rust.sh */; };
|
D0BCC60A2A09A0B800AD070D /* build-rust.sh in Resources */ = {isa = PBXBuildFile; fileRef = D0B98FBF29FD8072004E7149 /* build-rust.sh */; };
|
||||||
D0FAB5922B818A5900F6A84B /* NetworkExtensionTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */; };
|
|
||||||
D0FAB5962B818B2900F6A84B /* TunnelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5952B818B2900F6A84B /* TunnelButton.swift */; };
|
|
||||||
D0FAB5982B818B8200F6A84B /* TunnelStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5972B818B8200F6A84B /* TunnelStatusView.swift */; };
|
|
||||||
D0FAB59A2B818B9600F6A84B /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5992B818B9600F6A84B /* Network.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
|
@ -78,7 +70,7 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = "<group>"; };
|
0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = "<group>"; };
|
||||||
0B46E8DF2AC918CA00BA2A3C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
0B46E8DF2AC918CA00BA2A3C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
||||||
43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemToggleView.swift; sourceTree = "<group>"; };
|
43AA26D72A10004900F14CE6 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
|
||||||
D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NWConnection+Async.swift"; sourceTree = "<group>"; };
|
D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NWConnection+Async.swift"; sourceTree = "<group>"; };
|
||||||
D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewlineProtocolFramer.swift; sourceTree = "<group>"; };
|
D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewlineProtocolFramer.swift; sourceTree = "<group>"; };
|
||||||
D00117382B30341C00D87C25 /* libBurrowShared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBurrowShared.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
D00117382B30341C00D87C25 /* libBurrowShared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBurrowShared.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
|
@ -86,7 +78,6 @@
|
||||||
D00117412B30347800D87C25 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
D00117412B30347800D87C25 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||||
D00117422B30348D00D87C25 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
D00117422B30348D00D87C25 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||||
D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
D01A79302B81630D0024EC91 /* NetworkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkView.swift; sourceTree = "<group>"; };
|
|
||||||
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
|
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
|
||||||
D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = "<group>"; };
|
D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = "<group>"; };
|
||||||
D020F64229E4A1FF002790F6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D020F64229E4A1FF002790F6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
|
@ -101,26 +92,19 @@
|
||||||
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NetworkExtension-iOS.entitlements"; sourceTree = "<group>"; };
|
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NetworkExtension-iOS.entitlements"; sourceTree = "<group>"; };
|
||||||
D020F66829E4AA74002790F6 /* App-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "App-iOS.entitlements"; sourceTree = "<group>"; };
|
D020F66829E4AA74002790F6 /* App-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "App-iOS.entitlements"; sourceTree = "<group>"; };
|
||||||
D020F66929E4AA74002790F6 /* App-macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "App-macOS.entitlements"; sourceTree = "<group>"; };
|
D020F66929E4AA74002790F6 /* App-macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "App-macOS.entitlements"; sourceTree = "<group>"; };
|
||||||
D032E6512B8A79C20006B8AD /* HackClub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackClub.swift; sourceTree = "<group>"; };
|
|
||||||
D032E6532B8A79DA0006B8AD /* WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuard.swift; sourceTree = "<group>"; };
|
|
||||||
D05B9F7229E39EEC008CB1F9 /* Burrow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Burrow.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
D05B9F7229E39EEC008CB1F9 /* Burrow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Burrow.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowApp.swift; sourceTree = "<group>"; };
|
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowApp.swift; sourceTree = "<group>"; };
|
||||||
D05B9F7729E39EEC008CB1F9 /* BurrowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowView.swift; sourceTree = "<group>"; };
|
D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelView.swift; sourceTree = "<group>"; };
|
||||||
D05B9F7929E39EED008CB1F9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
D05B9F7929E39EED008CB1F9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatingButtonStyle.swift; sourceTree = "<group>"; };
|
|
||||||
D08252742B5C9DEB005DA378 /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
|
D08252742B5C9DEB005DA378 /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
|
||||||
D08252752B5C9FC4005DA378 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
D08252752B5C9FC4005DA378 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||||
D09150412B9D2AF700BE3CB0 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
|
|
||||||
D0B98FBF29FD8072004E7149 /* build-rust.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-rust.sh"; sourceTree = "<group>"; };
|
D0B98FBF29FD8072004E7149 /* build-rust.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-rust.sh"; sourceTree = "<group>"; };
|
||||||
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = "<group>"; };
|
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = "<group>"; };
|
||||||
D0B98FD829FDDB6F004E7149 /* libburrow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libburrow.h; sourceTree = "<group>"; };
|
D0B98FD829FDDB6F004E7149 /* libburrow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libburrow.h; sourceTree = "<group>"; };
|
||||||
D0B98FDC29FDDDCF004E7149 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
D0B98FDC29FDDDCF004E7149 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||||
D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkExtension+Async.swift"; sourceTree = "<group>"; };
|
D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkExtension+Async.swift"; sourceTree = "<group>"; };
|
||||||
|
D0BCC5FE2A086E1C00AD070D /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
|
||||||
D0BCC6032A09535900AD070D /* libburrow.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libburrow.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
D0BCC6032A09535900AD070D /* libburrow.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libburrow.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkExtensionTunnel.swift; sourceTree = "<group>"; };
|
|
||||||
D0FAB5952B818B2900F6A84B /* TunnelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelButton.swift; sourceTree = "<group>"; };
|
|
||||||
D0FAB5972B818B8200F6A84B /* TunnelStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelStatusView.swift; sourceTree = "<group>"; };
|
|
||||||
D0FAB5992B818B9600F6A84B /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
|
@ -151,6 +135,14 @@
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
43AA26D62A0FFFD000F14CE6 /* Menu */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43AA26D72A10004900F14CE6 /* MenuView.swift */,
|
||||||
|
);
|
||||||
|
path = Menu;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D00117392B30341C00D87C25 /* Shared */ = {
|
D00117392B30341C00D87C25 /* Shared */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -207,16 +199,6 @@
|
||||||
path = NetworkExtension;
|
path = NetworkExtension;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D032E64D2B8A69C90006B8AD /* Networks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0FAB5992B818B9600F6A84B /* Network.swift */,
|
|
||||||
D032E6512B8A79C20006B8AD /* HackClub.swift */,
|
|
||||||
D032E6532B8A79DA0006B8AD /* WireGuard.swift */,
|
|
||||||
);
|
|
||||||
path = Networks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D05B9F6929E39EEC008CB1F9 = {
|
D05B9F6929E39EEC008CB1F9 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -242,20 +224,14 @@
|
||||||
D05B9F7429E39EEC008CB1F9 /* App */ = {
|
D05B9F7429E39EEC008CB1F9 /* App */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
43AA26D62A0FFFD000F14CE6 /* Menu */,
|
||||||
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */,
|
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */,
|
||||||
D00AA8962A4669BC005C8102 /* AppDelegate.swift */,
|
D00AA8962A4669BC005C8102 /* AppDelegate.swift */,
|
||||||
43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */,
|
D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */,
|
||||||
D05B9F7729E39EEC008CB1F9 /* BurrowView.swift */,
|
|
||||||
D01A79302B81630D0024EC91 /* NetworkView.swift */,
|
|
||||||
D032E64D2B8A69C90006B8AD /* Networks */,
|
|
||||||
D0FAB5972B818B8200F6A84B /* TunnelStatusView.swift */,
|
|
||||||
D0FAB5952B818B2900F6A84B /* TunnelButton.swift */,
|
|
||||||
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */,
|
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */,
|
||||||
D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */,
|
D0BCC5FE2A086E1C00AD070D /* Status.swift */,
|
||||||
D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */,
|
D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */,
|
||||||
D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */,
|
|
||||||
D05B9F7929E39EED008CB1F9 /* Assets.xcassets */,
|
D05B9F7929E39EED008CB1F9 /* Assets.xcassets */,
|
||||||
D09150412B9D2AF700BE3CB0 /* MainMenu.xib */,
|
|
||||||
D020F66829E4AA74002790F6 /* App-iOS.entitlements */,
|
D020F66829E4AA74002790F6 /* App-iOS.entitlements */,
|
||||||
D020F66929E4AA74002790F6 /* App-macOS.entitlements */,
|
D020F66929E4AA74002790F6 /* App-macOS.entitlements */,
|
||||||
D020F64929E4A34B002790F6 /* App.xcconfig */,
|
D020F64929E4A34B002790F6 /* App.xcconfig */,
|
||||||
|
|
@ -343,7 +319,7 @@
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1510;
|
LastSwiftUpdateCheck = 1510;
|
||||||
LastUpgradeCheck = 1520;
|
LastUpgradeCheck = 1430;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
D00117372B30341C00D87C25 = {
|
D00117372B30341C00D87C25 = {
|
||||||
CreatedOnToolsVersion = 15.1;
|
CreatedOnToolsVersion = 15.1;
|
||||||
|
|
@ -393,7 +369,6 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */,
|
D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */,
|
||||||
D09150422B9D2AF700BE3CB0 /* MainMenu.xib in Resources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -448,19 +423,12 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0FAB59A2B818B9600F6A84B /* Network.swift in Sources */,
|
|
||||||
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */,
|
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */,
|
||||||
D0FAB5982B818B8200F6A84B /* TunnelStatusView.swift in Sources */,
|
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */,
|
||||||
43AA26D82A10004900F14CE6 /* MenuItemToggleView.swift in Sources */,
|
D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */,
|
||||||
D05B9F7829E39EEC008CB1F9 /* BurrowView.swift in Sources */,
|
D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */,
|
||||||
D0FAB5922B818A5900F6A84B /* NetworkExtensionTunnel.swift in Sources */,
|
|
||||||
D0FAB5962B818B2900F6A84B /* TunnelButton.swift in Sources */,
|
|
||||||
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */,
|
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */,
|
||||||
D05EF8C82B81818D0017AB4F /* FloatingButtonStyle.swift in Sources */,
|
|
||||||
D032E6522B8A79C20006B8AD /* HackClub.swift in Sources */,
|
|
||||||
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */,
|
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */,
|
||||||
D01A79312B81630D0024EC91 /* NetworkView.swift in Sources */,
|
|
||||||
D032E6542B8A79DA0006B8AD /* WireGuard.swift in Sources */,
|
|
||||||
D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */,
|
D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
@ -600,8 +568,8 @@
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/realm/SwiftLint.git";
|
repositoryURL = "https://github.com/realm/SwiftLint.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
branch = main;
|
kind = upToNextMajorVersion;
|
||||||
kind = branch;
|
minimumVersion = 0.54.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-argument-parser.git",
|
"location" : "https://github.com/apple/swift-argument-parser.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531",
|
"revision" : "fee6933f37fde9a5e12a1e4aeaa93fe60116ff2a",
|
||||||
"version" : "1.2.3"
|
"version" : "1.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -41,8 +41,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-syntax.git",
|
"location" : "https://github.com/apple/swift-syntax.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
|
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
|
||||||
"version" : "509.1.1"
|
"version" : "509.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -50,8 +50,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/realm/SwiftLint.git",
|
"location" : "https://github.com/realm/SwiftLint.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"branch" : "main",
|
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
|
||||||
"revision" : "7595ad3fafc1a31086dc40ba01fd898bf6b42d5f"
|
"version" : "0.54.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -68,8 +68,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/drmohundro/SWXMLHash.git",
|
"location" : "https://github.com/drmohundro/SWXMLHash.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f",
|
"revision" : "4d0f62f561458cbe1f732171e625f03195151b60",
|
||||||
"version" : "7.0.2"
|
"version" : "7.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1520"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.7">
|
version = "1.7">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1520"
|
LastUpgradeVersion = "1510"
|
||||||
version = "2.0">
|
version = "2.0">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import Network
|
||||||
final class Client {
|
final class Client {
|
||||||
let connection: NWConnection
|
let connection: NWConnection
|
||||||
|
|
||||||
private let logger = Logger.logger(for: Client.self)
|
private let logger: Logger = Logger.logger(for: Client.self)
|
||||||
private var generator = SystemRandomNumberGenerator()
|
private var generator = SystemRandomNumberGenerator()
|
||||||
|
|
||||||
convenience init() throws {
|
convenience init() throws {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ struct BurrowStartRequest: Codable {
|
||||||
let no_pi: Bool
|
let no_pi: Bool
|
||||||
let tun_excl: Bool
|
let tun_excl: Bool
|
||||||
let tun_retrieve: Bool
|
let tun_retrieve: Bool
|
||||||
let address: [String]
|
let address: String?
|
||||||
}
|
}
|
||||||
struct StartOptions: Codable {
|
struct StartOptions: Codable {
|
||||||
let tun: TunOptions
|
let tun: TunOptions
|
||||||
|
|
@ -51,7 +51,7 @@ struct BurrowResult<T>: Codable where T: Codable {
|
||||||
|
|
||||||
struct ServerConfigData: Codable {
|
struct ServerConfigData: Codable {
|
||||||
struct InternalConfig: Codable {
|
struct InternalConfig: Codable {
|
||||||
let address: [String]
|
let address: String?
|
||||||
let name: String?
|
let name: String?
|
||||||
let mtu: Int32?
|
let mtu: Int32?
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,10 @@ import os
|
||||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
private let logger = Logger.logger(for: PacketTunnelProvider.self)
|
private let logger = Logger.logger(for: PacketTunnelProvider.self)
|
||||||
|
|
||||||
override init() {
|
|
||||||
do {
|
|
||||||
libburrow.spawnInProcess(socketPath: try Constants.socketURL.path)
|
|
||||||
} catch {
|
|
||||||
logger.error("Failed to spawn: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func startTunnel(options: [String: NSObject]? = nil) async throws {
|
override func startTunnel(options: [String: NSObject]? = nil) async throws {
|
||||||
do {
|
do {
|
||||||
|
libburrow.spawnInProcess(socketPath: try Constants.socketURL.path)
|
||||||
|
|
||||||
let client = try Client()
|
let client = try Client()
|
||||||
|
|
||||||
let command = BurrowRequest(id: 0, command: "ServerConfig")
|
let command = BurrowRequest(id: 0, command: "ServerConfig")
|
||||||
|
|
@ -37,7 +31,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
command: BurrowStartRequest(
|
command: BurrowStartRequest(
|
||||||
Start: BurrowStartRequest.StartOptions(
|
Start: BurrowStartRequest.StartOptions(
|
||||||
tun: BurrowStartRequest.TunOptions(
|
tun: BurrowStartRequest.TunOptions(
|
||||||
name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: []
|
name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: nil
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -50,34 +44,14 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func stopTunnel(with reason: NEProviderStopReason) async {
|
|
||||||
do {
|
|
||||||
let client = try Client()
|
|
||||||
let command = BurrowRequest(id: 0, command: "Stop")
|
|
||||||
let data = try await client.request(command, type: Response<BurrowResult<String>>.self)
|
|
||||||
self.logger.log("Stopped client.")
|
|
||||||
} catch {
|
|
||||||
self.logger.error("Failed to stop tunnel: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
|
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
|
||||||
let cfig = from.ServerConfig
|
let cfig = from.ServerConfig
|
||||||
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
|
guard let addr = cfig.address else {
|
||||||
var v4Addresses = [String]()
|
return nil
|
||||||
var v6Addresses = [String]()
|
|
||||||
for addr in cfig.address {
|
|
||||||
if IPv4Address(addr) != nil {
|
|
||||||
v6Addresses.append(addr)
|
|
||||||
}
|
|
||||||
if IPv6Address(addr) != nil {
|
|
||||||
v4Addresses.append(addr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
nst.ipv4Settings = NEIPv4Settings(addresses: v4Addresses, subnetMasks: v4Addresses.map { _ in
|
// Using a makeshift remote tunnel address
|
||||||
"255.255.255.0"
|
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
|
||||||
})
|
nst.ipv4Settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"])
|
||||||
nst.ipv6Settings = NEIPv6Settings(addresses: v6Addresses, networkPrefixLengths: v6Addresses.map { _ in 64 })
|
|
||||||
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
|
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
|
||||||
return nst
|
return nst
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,10 @@ CARGO_ARGS+=("--lib")
|
||||||
|
|
||||||
# Pass the configuration (Debug or Release) through to cargo
|
# Pass the configuration (Debug or Release) through to cargo
|
||||||
if [[ $SWIFT_ACTIVE_COMPILATION_CONDITIONS == *DEBUG* ]]; then
|
if [[ $SWIFT_ACTIVE_COMPILATION_CONDITIONS == *DEBUG* ]]; then
|
||||||
CARGO_TARGET_SUBDIR="debug"
|
CARGO_DIR="debug"
|
||||||
else
|
else
|
||||||
CARGO_ARGS+=("--release")
|
CARGO_ARGS+=("--release")
|
||||||
CARGO_TARGET_SUBDIR="release"
|
CARGO_DIR="release"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -x "$(command -v rustup)" ]]; then
|
if [[ -x "$(command -v rustup)" ]]; then
|
||||||
|
|
@ -70,11 +70,11 @@ fi
|
||||||
|
|
||||||
# Run cargo without the various environment variables set by Xcode.
|
# Run cargo without the various environment variables set by Xcode.
|
||||||
# Those variables can confuse cargo and the build scripts it runs.
|
# Those variables can confuse cargo and the build scripts it runs.
|
||||||
env -i PATH="$CARGO_PATH" CARGO_TARGET_DIR="${CONFIGURATION_TEMP_DIR}/target" cargo build "${CARGO_ARGS[@]}"
|
env -i PATH="$CARGO_PATH" cargo build "${CARGO_ARGS[@]}"
|
||||||
|
|
||||||
mkdir -p "${BUILT_PRODUCTS_DIR}"
|
mkdir -p "${BUILT_PRODUCTS_DIR}"
|
||||||
|
|
||||||
# Use `lipo` to merge the architectures together into BUILT_PRODUCTS_DIR
|
# Use `lipo` to merge the architectures together into BUILT_PRODUCTS_DIR
|
||||||
/usr/bin/xcrun --sdk $PLATFORM_NAME lipo \
|
/usr/bin/xcrun --sdk $PLATFORM_NAME lipo \
|
||||||
-create $(printf "${CONFIGURATION_TEMP_DIR}/target/%q/${CARGO_TARGET_SUBDIR}/libburrow.a " "${RUST_TARGETS[@]}") \
|
-create $(printf "${PROJECT_DIR}/../target/%q/${CARGO_DIR}/libburrow.a " "${RUST_TARGETS[@]}") \
|
||||||
-output "${BUILT_PRODUCTS_DIR}/libburrow.a"
|
-output "${BUILT_PRODUCTS_DIR}/libburrow.a"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ public enum Constants {
|
||||||
|
|
||||||
public static let bundleIdentifier = AppBundleIdentifier
|
public static let bundleIdentifier = AppBundleIdentifier
|
||||||
public static let appGroupIdentifier = AppGroupIdentifier
|
public static let appGroupIdentifier = AppGroupIdentifier
|
||||||
public static let networkExtensionBundleIdentifier = NetworkExtensionBundleIdentifier
|
|
||||||
|
|
||||||
public static var groupContainerURL: URL {
|
public static var groupContainerURL: URL {
|
||||||
get throws { try _groupContainerURL.get() }
|
get throws { try _groupContainerURL.get() }
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,5 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
static NSString * const AppBundleIdentifier = MACRO_STRING(APP_BUNDLE_IDENTIFIER);
|
static NSString * const AppBundleIdentifier = MACRO_STRING(APP_BUNDLE_IDENTIFIER);
|
||||||
static NSString * const AppGroupIdentifier = MACRO_STRING(APP_GROUP_IDENTIFIER);
|
static NSString * const AppGroupIdentifier = MACRO_STRING(APP_GROUP_IDENTIFIER);
|
||||||
static NSString * const NetworkExtensionBundleIdentifier = MACRO_STRING(NETWORK_EXTENSION_BUNDLE_IDENTIFIER);
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@ PRODUCT_NAME = BurrowShared
|
||||||
MERGEABLE_LIBRARY = YES
|
MERGEABLE_LIBRARY = YES
|
||||||
|
|
||||||
SWIFT_INCLUDE_PATHS = $(PROJECT_DIR)/Shared/Constants
|
SWIFT_INCLUDE_PATHS = $(PROJECT_DIR)/Shared/Constants
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = APP_BUNDLE_IDENTIFIER=$(APP_BUNDLE_IDENTIFIER) APP_GROUP_IDENTIFIER=$(APP_GROUP_IDENTIFIER) NETWORK_EXTENSION_BUNDLE_IDENTIFIER=$(NETWORK_EXTENSION_BUNDLE_IDENTIFIER)
|
GCC_PREPROCESSOR_DEFINITIONS = APP_BUNDLE_IDENTIFIER=$(APP_BUNDLE_IDENTIFIER) APP_GROUP_IDENTIFIER=$(APP_GROUP_IDENTIFIER)
|
||||||
|
|
|
||||||
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -1074,7 +1074,7 @@ dependencies = [
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2 0.5.5",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
@ -2114,6 +2114,16 @@ version = "1.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.5"
|
version = "0.5.5"
|
||||||
|
|
@ -2295,7 +2305,7 @@ dependencies = [
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2 0.5.5",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
|
|
@ -2537,7 +2547,7 @@ dependencies = [
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"socket2",
|
"socket2 0.4.10",
|
||||||
"ssri",
|
"ssri",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM docker.io/library/rust:1.76.0-slim-bookworm AS builder
|
FROM docker.io/library/rust:1.70.0-slim-bookworm AS builder
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG LLVM_VERSION=16
|
ARG LLVM_VERSION=16
|
||||||
|
|
|
||||||
28
Makefile
28
Makefile
|
|
@ -1,4 +1,4 @@
|
||||||
tun := $(shell ifconfig -l | sed 's/ /\n/g' | grep utun | tail -n 1)
|
tun_num := $(shell ifconfig | awk -F 'utun|[: ]' '/utun[0-9]/ {print $$2}' | tail -n 1)
|
||||||
cargo_console := RUST_BACKTRACE=1 RUST_LOG=debug RUSTFLAGS='--cfg tokio_unstable' cargo run --all-features
|
cargo_console := RUST_BACKTRACE=1 RUST_LOG=debug RUSTFLAGS='--cfg tokio_unstable' cargo run --all-features
|
||||||
cargo_norm := RUST_BACKTRACE=1 RUST_LOG=debug cargo run
|
cargo_norm := RUST_BACKTRACE=1 RUST_LOG=debug cargo run
|
||||||
|
|
||||||
|
|
@ -17,33 +17,17 @@ daemon:
|
||||||
start:
|
start:
|
||||||
@$(cargo_norm) start
|
@$(cargo_norm) start
|
||||||
|
|
||||||
stop:
|
|
||||||
@$(cargo_norm) stop
|
|
||||||
|
|
||||||
test-dns:
|
test-dns:
|
||||||
@sudo route delete 8.8.8.8
|
@sudo route delete 8.8.8.8
|
||||||
@sudo route add 8.8.8.8 -interface $(tun)
|
@sudo route add 8.8.8.8 -interface utun$(tun_num)
|
||||||
@dig @8.8.8.8 hackclub.com
|
@dig @8.8.8.8 hackclub.com
|
||||||
|
|
||||||
test-https:
|
test-https:
|
||||||
@sudo route delete 193.183.0.162
|
@sudo route delete 193.183.0.162
|
||||||
@sudo route add 193.183.0.162 -interface $(tun)
|
@sudo route add 193.183.0.162 -interface utun$(tun_num)
|
||||||
@curl -vv https://search.marginalia.nu
|
@curl -vv https://search.marginalia.nu
|
||||||
|
|
||||||
v4_target := 146.190.62.39
|
|
||||||
test-http:
|
test-http:
|
||||||
@sudo route delete ${v4_target}
|
@sudo route delete 146.190.62.39
|
||||||
@sudo route add ${v4_target} -interface $(tun)
|
@sudo route add 146.190.62.39 -interface utun$(tun_num)
|
||||||
@curl -vv ${v4_target}:80
|
@curl -vv 146.190.62.39:80
|
||||||
|
|
||||||
test-ipv4:
|
|
||||||
@sudo route delete ${v4_target}
|
|
||||||
@sudo route add ${v4_target} -interface $(tun)
|
|
||||||
@ping ${v4_target}
|
|
||||||
|
|
||||||
v6_target := 2001:4860:4860::8888
|
|
||||||
test-ipv6:
|
|
||||||
@sudo route delete ${v6_target}
|
|
||||||
@sudo route -n add -inet6 ${v6_target} -interface $(tun)
|
|
||||||
@echo preparing
|
|
||||||
@sudo ping6 -v ${v6_target}
|
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,13 @@ Burrow is an open source tool for burrowing through firewalls, built by teenager
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Burrow is fully open source, you can fork the repo and start contributing easily. For more information and in-depth discussions, visit the `#burrow` channel on the [Hack Club Slack](https://hackclub.com/slack/), here you can ask for help and talk with other people interested in burrow! Checkout [GETTING_STARTED.md](./docs/GETTING_STARTED.md) for build instructions and [GTK_APP.md](./docs/GTK_APP.md) for the Linux app.
|
Burrow is fully open source, you can fork the repo and start contributing easily. For more information and in-depth discussions, visit the `#burrow` channel on the [Hack Club Slack](https://hackclub.com/slack/), here you can ask for help and talk with other people interested in burrow! For more information on how to contribute, please see [CONTRIBUTING.md]
|
||||||
|
|
||||||
The project structure is divided in the following folders:
|
The project structure is divided in the following folders:
|
||||||
|
|
||||||
```
|
```
|
||||||
Apple/ # Xcode project for burrow on macOS and iOS
|
Apple/ # Xcode project for burrow on macOS and iOS
|
||||||
burrow/ # Higher-level API library for tun and tun-async
|
burrow/ # Higher-level API library for tun and tun-async
|
||||||
burrow-gtk/ # GTK project for burrow on Linux
|
|
||||||
tun/ # Low-level interface to OS networking
|
tun/ # Low-level interface to OS networking
|
||||||
src/
|
src/
|
||||||
tokio/ # Async/Tokio code
|
tokio/ # Async/Tokio code
|
||||||
|
|
|
||||||
255
burrow-gtk/Cargo.lock
generated
255
burrow-gtk/Cargo.lock
generated
|
|
@ -257,16 +257,16 @@ dependencies = [
|
||||||
"caps",
|
"caps",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"clap",
|
"clap",
|
||||||
"console",
|
"env_logger",
|
||||||
"fehler",
|
"fehler",
|
||||||
"futures",
|
"futures",
|
||||||
"hmac",
|
"hmac",
|
||||||
"ip_network",
|
"ip_network",
|
||||||
"ip_network_table",
|
"ip_network_table",
|
||||||
|
"ipnet",
|
||||||
"libsystemd",
|
"libsystemd",
|
||||||
"log",
|
"log",
|
||||||
"nix 0.27.1",
|
"nix",
|
||||||
"once_cell",
|
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
|
@ -281,6 +281,7 @@ dependencies = [
|
||||||
"tracing-oslog",
|
"tracing-oslog",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"tun",
|
"tun",
|
||||||
|
"uuid",
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -331,11 +332,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cairo-rs"
|
name = "cairo-rs"
|
||||||
version = "0.17.10"
|
version = "0.18.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a"
|
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 2.4.2",
|
||||||
"cairo-sys-rs",
|
"cairo-sys-rs",
|
||||||
"glib",
|
"glib",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -345,9 +346,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cairo-sys-rs"
|
name = "cairo-sys-rs"
|
||||||
version = "0.17.10"
|
version = "0.18.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "691d0c66b1fb4881be80a760cb8fe76ea97218312f9dfe2c9cc0f496ca279cb1"
|
checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -500,19 +501,6 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "console"
|
|
||||||
version = "0.15.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
|
||||||
dependencies = [
|
|
||||||
"encode_unicode",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"unicode-width",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
@ -629,12 +617,6 @@ version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "encode_unicode"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.33"
|
version = "0.8.33"
|
||||||
|
|
@ -644,6 +626,19 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
||||||
|
dependencies = [
|
||||||
|
"humantime",
|
||||||
|
"is-terminal",
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
@ -735,14 +730,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flume"
|
name = "flume"
|
||||||
version = "0.10.14"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"nanorand",
|
"nanorand",
|
||||||
"pin-project",
|
|
||||||
"spin",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -873,11 +867,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdk-pixbuf"
|
name = "gdk-pixbuf"
|
||||||
version = "0.17.10"
|
version = "0.18.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "695d6bc846438c5708b07007537b9274d883373dd30858ca881d7d71b5540717"
|
checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"gdk-pixbuf-sys",
|
"gdk-pixbuf-sys",
|
||||||
"gio",
|
"gio",
|
||||||
"glib",
|
"glib",
|
||||||
|
|
@ -887,9 +880,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdk-pixbuf-sys"
|
name = "gdk-pixbuf-sys"
|
||||||
version = "0.17.10"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9285ec3c113c66d7d0ab5676599176f1f42f4944ca1b581852215bf5694870cb"
|
checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gio-sys",
|
"gio-sys",
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
|
|
@ -900,11 +893,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdk4"
|
name = "gdk4"
|
||||||
version = "0.6.3"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3abf96408a26e3eddf881a7f893a1e111767137136e347745e8ea6ed12731ff"
|
checksum = "7edb019ad581f8ecf8ea8e4baa6df7c483a95b5a59be3140be6a9c3b0c632af6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cairo-rs",
|
"cairo-rs",
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
"gdk4-sys",
|
"gdk4-sys",
|
||||||
|
|
@ -916,9 +908,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdk4-sys"
|
name = "gdk4-sys"
|
||||||
version = "0.6.3"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bc92aa1608c089c49393d014c38ac0390d01e4841e1fedaa75dbcef77aaed64"
|
checksum = "dbab43f332a3cf1df9974da690b5bb0e26720ed09a228178ce52175372dcfef0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cairo-sys-rs",
|
"cairo-sys-rs",
|
||||||
"gdk-pixbuf-sys",
|
"gdk-pixbuf-sys",
|
||||||
|
|
@ -982,11 +974,10 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gio"
|
name = "gio"
|
||||||
version = "0.17.10"
|
version = "0.18.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6973e92937cf98689b6a054a9e56c657ed4ff76de925e36fc331a15f0c5d30a"
|
checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
|
|
@ -1002,9 +993,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gio-sys"
|
name = "gio-sys"
|
||||||
version = "0.17.10"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ccf87c30a12c469b6d958950f6a9c09f2be20b7773f7e70d20b867fdf2628c3"
|
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
"gobject-sys",
|
"gobject-sys",
|
||||||
|
|
@ -1015,11 +1006,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glib"
|
name = "glib"
|
||||||
version = "0.17.10"
|
version = "0.18.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3fad45ba8d4d2cea612b432717e834f48031cd8853c8aaf43b2c79fec8d144b"
|
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 2.4.2",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-executor",
|
"futures-executor",
|
||||||
|
|
@ -1044,24 +1035,23 @@ checksum = "3431c56f463443cba9bc3600248bc6d680cb614c2ee1cdd39dab5415bd12ac5c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glib-macros"
|
name = "glib-macros"
|
||||||
version = "0.17.10"
|
version = "0.18.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eca5c79337338391f1ab8058d6698125034ce8ef31b72a442437fa6c8580de26"
|
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-crate",
|
"proc-macro-crate 2.0.1",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glib-sys"
|
name = "glib-sys"
|
||||||
version = "0.17.10"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d80aa6ea7bba0baac79222204aa786a6293078c210abe69ef1336911d4bdc4f0"
|
checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
|
|
@ -1075,9 +1065,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gobject-sys"
|
name = "gobject-sys"
|
||||||
version = "0.17.10"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd34c3317740a6358ec04572c1bcfd3ac0b5b6529275fae255b237b314bb8062"
|
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -1086,9 +1076,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphene-rs"
|
name = "graphene-rs"
|
||||||
version = "0.17.10"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "def4bb01265b59ed548b05455040d272d989b3012c42d4c1bbd39083cb9b40d9"
|
checksum = "3b2228cda1505613a7a956cca69076892cfbda84fc2b7a62b94a41a272c0c401"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glib",
|
"glib",
|
||||||
"graphene-sys",
|
"graphene-sys",
|
||||||
|
|
@ -1097,9 +1087,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphene-sys"
|
name = "graphene-sys"
|
||||||
version = "0.17.10"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1856fc817e6a6675e36cea0bd9a3afe296f5d9709d1e2d3182803ac77f0ab21d"
|
checksum = "cc4144cee8fc8788f2a9b73dc5f1d4e1189d1f95305c4cb7bd9c1af1cfa31f59"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -1109,11 +1099,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gsk4"
|
name = "gsk4"
|
||||||
version = "0.6.3"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f01ef44fa7cac15e2da9978529383e6bee03e570ba5bf7036b4c10a15cc3a3c"
|
checksum = "0d958e351d2f210309b32d081c832d7de0aca0b077aa10d88336c6379bd01f7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cairo-rs",
|
"cairo-rs",
|
||||||
"gdk4",
|
"gdk4",
|
||||||
"glib",
|
"glib",
|
||||||
|
|
@ -1125,9 +1114,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gsk4-sys"
|
name = "gsk4-sys"
|
||||||
version = "0.6.3"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c07a84fb4dcf1323d29435aa85e2f5f58bef564342bef06775ec7bd0da1f01b0"
|
checksum = "12bd9e3effea989f020e8f1ff3fa3b8c63ba93d43b899c11a118868853a56d55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cairo-sys-rs",
|
"cairo-sys-rs",
|
||||||
"gdk4-sys",
|
"gdk4-sys",
|
||||||
|
|
@ -1141,11 +1130,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4"
|
name = "gtk4"
|
||||||
version = "0.6.6"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b28a32a04cd75cef14a0983f8b0c669e0fe152a0a7725accdeb594e2c764c88b"
|
checksum = "5aeb51aa3e9728575a053e1f43543cd9992ac2477e1b186ad824fd4adfb70842"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cairo-rs",
|
"cairo-rs",
|
||||||
"field-offset",
|
"field-offset",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
|
|
@ -1158,18 +1146,17 @@ dependencies = [
|
||||||
"gtk4-macros",
|
"gtk4-macros",
|
||||||
"gtk4-sys",
|
"gtk4-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
|
||||||
"pango",
|
"pango",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4-macros"
|
name = "gtk4-macros"
|
||||||
version = "0.6.6"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a4d6b61570f76d3ee542d984da443b1cd69b6105264c61afec3abed08c2500f"
|
checksum = "d57ec49cf9b657f69a05bca8027cff0a8dfd0c49e812be026fc7311f2163832f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"proc-macro-crate",
|
"proc-macro-crate 1.3.1",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1178,9 +1165,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4-sys"
|
name = "gtk4-sys"
|
||||||
version = "0.6.3"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f8283f707b07e019e76c7f2934bdd4180c277e08aa93f4c0d8dd07b7a34e22f"
|
checksum = "54d8c4aa23638ce9faa2caf7e2a27d4a1295af2155c8e8d28c4d4eeca7a65eb8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cairo-sys-rs",
|
"cairo-sys-rs",
|
||||||
"gdk-pixbuf-sys",
|
"gdk-pixbuf-sys",
|
||||||
|
|
@ -1290,6 +1277,12 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.28"
|
version = "0.14.28"
|
||||||
|
|
@ -1383,6 +1376,20 @@ name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
|
|
@ -1422,11 +1429,10 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libadwaita"
|
name = "libadwaita"
|
||||||
version = "0.4.4"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ab9c0843f9f23ff25634df2743690c3a1faffe0a190e60c490878517eb81abf"
|
checksum = "2fe7e70c06507ed10a16cda707f358fbe60fe0dc237498f78c686ade92fd979c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
"gdk4",
|
"gdk4",
|
||||||
"gio",
|
"gio",
|
||||||
|
|
@ -1439,9 +1445,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libadwaita-sys"
|
name = "libadwaita-sys"
|
||||||
version = "0.4.4"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4231cb2499a9f0c4cdfa4885414b33e39901ddcac61150bc0bb4ff8a57ede404"
|
checksum = "5e10aaa38de1d53374f90deeb4535209adc40cc5dba37f9704724169bceec69a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gdk4-sys",
|
"gdk4-sys",
|
||||||
"gio-sys",
|
"gio-sys",
|
||||||
|
|
@ -1481,14 +1487,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsystemd"
|
name = "libsystemd"
|
||||||
version = "0.7.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c592dc396b464005f78a5853555b9f240bc5378bf5221acc4e129910b2678869"
|
checksum = "88b9597a67aa1c81a6624603e6bd0bcefb9e0f94c9c54970ec53771082104b4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hmac",
|
"hmac",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nix 0.27.1",
|
"nix",
|
||||||
"nom",
|
"nom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -1669,18 +1675,6 @@ dependencies = [
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.27.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.2",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"memoffset 0.9.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
|
|
@ -1813,11 +1807,10 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.17.10"
|
version = "0.18.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35be456fc620e61f62dff7ff70fbd54dcbaf0a4b920c0f16de1107c47d921d48"
|
checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
|
||||||
"gio",
|
"gio",
|
||||||
"glib",
|
"glib",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -1827,9 +1820,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango-sys"
|
name = "pango-sys"
|
||||||
version = "0.17.10"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3da69f9f3850b0d8990d462f8c709561975e95f689c1cdf0fecdebde78b35195"
|
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glib-sys",
|
"glib-sys",
|
||||||
"gobject-sys",
|
"gobject-sys",
|
||||||
|
|
@ -1901,26 +1894,6 @@ version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
|
|
||||||
dependencies = [
|
|
||||||
"pin-project-internal",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-internal"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.48",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
|
|
@ -1988,6 +1961,16 @@ dependencies = [
|
||||||
"toml_edit 0.19.15",
|
"toml_edit 0.19.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-crate"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a"
|
||||||
|
dependencies = [
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit 0.20.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
@ -2115,9 +2098,8 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "relm4"
|
name = "relm4"
|
||||||
version = "0.6.2"
|
version = "0.7.0-beta.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Relm4/Relm4#e189eee06b887470e0fd65cbaf6d7c0161bed5ea"
|
||||||
checksum = "0c16f3fad883034773b7f5af4d7e865532b8f3641e5a8bab2a34561a8d960d81"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"flume",
|
"flume",
|
||||||
|
|
@ -2133,9 +2115,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "relm4-macros"
|
name = "relm4-macros"
|
||||||
version = "0.6.2"
|
version = "0.7.0-beta.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Relm4/Relm4#e189eee06b887470e0fd65cbaf6d7c0161bed5ea"
|
||||||
checksum = "9340e2553c0a184a80a0bfa1dcf73c47f3d48933aa6be90724b202f9fbd24735"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -2566,6 +2547,15 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.56"
|
version = "1.0.56"
|
||||||
|
|
@ -2643,7 +2633,6 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2 0.5.5",
|
"socket2 0.5.5",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2850,7 +2839,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.7.4",
|
"libloading 0.7.4",
|
||||||
"log",
|
"log",
|
||||||
"nix 0.26.4",
|
"nix",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -2936,6 +2925,7 @@ version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
|
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -3088,6 +3078,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
relm4 = { version = "0.6", features = ["libadwaita", "gnome_44"]}
|
relm4 = { features = ["libadwaita", "gnome_45"], git = "https://github.com/Relm4/Relm4" }
|
||||||
burrow = { version = "*", path = "../burrow/" }
|
burrow = { version = "*", path = "../burrow/" }
|
||||||
tokio = { version = "1.35.0", features = ["time", "sync"] }
|
tokio = { version = "1.35.0", features = ["time", "sync"] }
|
||||||
gettext-rs = { version = "0.7.0", features = ["gettext-system"] }
|
gettext-rs = { version = "0.7.0", features = ["gettext-system"] }
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
FROM fedora:39
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
RUN set -eux && \
|
|
||||||
dnf update -y && \
|
|
||||||
dnf install -y clang ninja-build cmake meson gtk4-devel glib2-devel libadwaita-devel desktop-file-utils libappstream-glib util-linux wget fuse fuse-libs file
|
|
||||||
|
|
||||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
|
|
||||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY . /app
|
|
||||||
|
|
||||||
RUN cd /app/burrow-gtk/ && \
|
|
||||||
./build-aux/build_appimage.sh
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
BURROW_GTK_ROOT="$(readlink -f $(dirname -- "$(readlink -f -- "$BASH_SOURCE")")/..)"
|
|
||||||
BURROW_GTK_BUILD="$BURROW_GTK_ROOT/build-appimage"
|
|
||||||
LINUXDEPLOY_VERSION="${LINUXDEPLOY_VERSION:-"1-alpha-20240109-1"}"
|
|
||||||
BURROW_BUILD_TYPE="${BURROW_BUILD_TYPE:-"release"}"
|
|
||||||
|
|
||||||
if [ "$BURROW_GTK_ROOT" != $(pwd) ]; then
|
|
||||||
echo "Make sure to cd into burrow-gtk"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARCHITECTURE=$(lscpu | grep Architecture | awk '{print $2}')
|
|
||||||
|
|
||||||
if [ "$ARCHITECTURE" == "x86_64" ]; then
|
|
||||||
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/$LINUXDEPLOY_VERSION/linuxdeploy-x86_64.AppImage" -o /dev/null -O /tmp/linuxdeploy
|
|
||||||
chmod a+x /tmp/linuxdeploy
|
|
||||||
elif [ "$ARCHITECTURE" == "aarch64" ]; then
|
|
||||||
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/$LINUXDEPLOY_VERSION/linuxdeploy-aarch64.AppImage" -o /dev/null -O /tmp/linuxdeploy
|
|
||||||
chmod a+x /tmp/linuxdeploy
|
|
||||||
fi
|
|
||||||
|
|
||||||
meson setup $BURROW_GTK_BUILD --bindir bin --prefix /usr --buildtype $BURROW_BUILD_TYPE
|
|
||||||
meson compile -C $BURROW_GTK_BUILD
|
|
||||||
DESTDIR=AppDir meson install -C $BURROW_GTK_BUILD
|
|
||||||
cargo b --$BURROW_BUILD_TYPE --manifest-path=../Cargo.toml
|
|
||||||
/tmp/linuxdeploy --appimage-extract-and-run --appdir $BURROW_GTK_BUILD/AppDir -e $BURROW_GTK_BUILD/../../target/$BURROW_BUILD_TYPE/burrow --output appimage
|
|
||||||
mv *.AppImage $BURROW_GTK_BUILD
|
|
||||||
|
|
@ -34,8 +34,8 @@ i18n = import('i18n')
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
|
|
||||||
# External Dependencies
|
# External Dependencies
|
||||||
dependency('gtk4', version: '>= 4.0')
|
dependency('gtk4', version: '>= 4.12')
|
||||||
dependency('libadwaita-1', version: '>= 1.2')
|
dependency('libadwaita-1', version: '>= 1.4')
|
||||||
|
|
||||||
glib_compile_resources = find_program('glib-compile-resources', required: true)
|
glib_compile_resources = find_program('glib-compile-resources', required: true)
|
||||||
glib_compile_schemas = find_program('glib-compile-schemas', required: true)
|
glib_compile_schemas = find_program('glib-compile-schemas', required: true)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ const RECONNECT_POLL_TIME: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
settings_screen: Controller<settings_screen::SettingsScreen>,
|
_settings_screen: Controller<settings_screen::SettingsScreen>,
|
||||||
switch_screen: AsyncController<switch_screen::SwitchScreen>,
|
switch_screen: AsyncController<switch_screen::SwitchScreen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,35 +81,23 @@ impl AsyncComponent for App {
|
||||||
let view_switcher_bar = adw::ViewSwitcherBar::builder().stack(&view_stack).build();
|
let view_switcher_bar = adw::ViewSwitcherBar::builder().stack(&view_stack).build();
|
||||||
view_switcher_bar.set_reveal(true);
|
view_switcher_bar.set_reveal(true);
|
||||||
|
|
||||||
// When libadwaita 1.4 support becomes more avaliable, this approach is more appropriate
|
let toolbar = adw::ToolbarView::new();
|
||||||
//
|
toolbar.add_top_bar(
|
||||||
// let toolbar = adw::ToolbarView::new();
|
|
||||||
// toolbar.add_top_bar(
|
|
||||||
// &adw::HeaderBar::builder()
|
|
||||||
// .title_widget(>k::Label::new(Some("Burrow")))
|
|
||||||
// .build(),
|
|
||||||
// );
|
|
||||||
// toolbar.add_bottom_bar(&view_switcher_bar);
|
|
||||||
// toolbar.set_content(Some(&view_stack));
|
|
||||||
// root.set_content(Some(&toolbar));
|
|
||||||
|
|
||||||
let content = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
|
||||||
content.append(
|
|
||||||
&adw::HeaderBar::builder()
|
&adw::HeaderBar::builder()
|
||||||
.title_widget(>k::Label::new(Some("Burrow")))
|
.title_widget(>k::Label::new(Some("Burrow")))
|
||||||
.build(),
|
.build(),
|
||||||
);
|
);
|
||||||
content.append(&view_stack);
|
toolbar.add_bottom_bar(&view_switcher_bar);
|
||||||
content.append(&view_switcher_bar);
|
toolbar.set_content(Some(&view_stack));
|
||||||
|
|
||||||
root.set_content(Some(&content));
|
root.set_content(Some(&toolbar));
|
||||||
|
|
||||||
sender.input(AppMsg::PostInit);
|
sender.input(AppMsg::PostInit);
|
||||||
|
|
||||||
let model = App {
|
let model = App {
|
||||||
daemon_client,
|
daemon_client,
|
||||||
switch_screen,
|
switch_screen,
|
||||||
settings_screen,
|
_settings_screen: settings_screen,
|
||||||
};
|
};
|
||||||
|
|
||||||
AsyncComponentParts { model, widgets }
|
AsyncComponentParts { model, widgets }
|
||||||
|
|
@ -132,23 +120,14 @@ impl AsyncComponent for App {
|
||||||
disconnected_daemon_client = true;
|
disconnected_daemon_client = true;
|
||||||
self.switch_screen
|
self.switch_screen
|
||||||
.emit(switch_screen::SwitchScreenMsg::DaemonDisconnect);
|
.emit(switch_screen::SwitchScreenMsg::DaemonDisconnect);
|
||||||
self.settings_screen
|
|
||||||
.emit(settings_screen::SettingsScreenMsg::DaemonStateChange)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if disconnected_daemon_client || daemon_client.is_none() {
|
if disconnected_daemon_client || daemon_client.is_none() {
|
||||||
match DaemonClient::new().await {
|
*daemon_client = DaemonClient::new().await.ok();
|
||||||
Ok(new_daemon_client) => {
|
if daemon_client.is_some() {
|
||||||
*daemon_client = Some(new_daemon_client);
|
self.switch_screen
|
||||||
self.switch_screen
|
.emit(switch_screen::SwitchScreenMsg::DaemonReconnect);
|
||||||
.emit(switch_screen::SwitchScreenMsg::DaemonReconnect);
|
|
||||||
self.settings_screen
|
|
||||||
.emit(settings_screen::SettingsScreenMsg::DaemonStateChange)
|
|
||||||
}
|
|
||||||
Err(_e) => {
|
|
||||||
// TODO: Handle Error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,3 @@ mod settings_screen;
|
||||||
mod switch_screen;
|
mod switch_screen;
|
||||||
|
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
pub use settings::{DaemonGroupMsg, DiagGroupMsg};
|
|
||||||
|
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
use super::*;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DaemonGroup {
|
|
||||||
system_setup: SystemSetup,
|
|
||||||
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
|
||||||
already_running: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DaemonGroupInit {
|
|
||||||
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
|
||||||
pub system_setup: SystemSetup,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum DaemonGroupMsg {
|
|
||||||
LaunchLocal,
|
|
||||||
DaemonStateChange,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[relm4::component(pub, async)]
|
|
||||||
impl AsyncComponent for DaemonGroup {
|
|
||||||
type Init = DaemonGroupInit;
|
|
||||||
type Input = DaemonGroupMsg;
|
|
||||||
type Output = ();
|
|
||||||
type CommandOutput = ();
|
|
||||||
|
|
||||||
view! {
|
|
||||||
#[name(group)]
|
|
||||||
adw::PreferencesGroup {
|
|
||||||
#[watch]
|
|
||||||
set_sensitive:
|
|
||||||
(model.system_setup == SystemSetup::AppImage || model.system_setup == SystemSetup::Other) &&
|
|
||||||
!model.already_running,
|
|
||||||
set_title: "Local Daemon",
|
|
||||||
set_description: Some("Run Local Daemon"),
|
|
||||||
|
|
||||||
gtk::Button {
|
|
||||||
set_label: "Launch",
|
|
||||||
connect_clicked => DaemonGroupMsg::LaunchLocal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn init(
|
|
||||||
init: Self::Init,
|
|
||||||
root: Self::Root,
|
|
||||||
sender: AsyncComponentSender<Self>,
|
|
||||||
) -> AsyncComponentParts<Self> {
|
|
||||||
// Should be impossible to panic here
|
|
||||||
let model = DaemonGroup {
|
|
||||||
system_setup: init.system_setup,
|
|
||||||
daemon_client: init.daemon_client.clone(),
|
|
||||||
already_running: init.daemon_client.lock().await.is_some(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let widgets = view_output!();
|
|
||||||
|
|
||||||
AsyncComponentParts { model, widgets }
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update(
|
|
||||||
&mut self,
|
|
||||||
msg: Self::Input,
|
|
||||||
_sender: AsyncComponentSender<Self>,
|
|
||||||
_root: &Self::Root,
|
|
||||||
) {
|
|
||||||
match msg {
|
|
||||||
DaemonGroupMsg::LaunchLocal => {
|
|
||||||
let burrow_original_bin = std::env::vars()
|
|
||||||
.find(|(k, _)| k == "APPDIR")
|
|
||||||
.map(|(_, v)| v + "/usr/bin/burrow")
|
|
||||||
.unwrap_or("/usr/bin/burrow".to_owned());
|
|
||||||
|
|
||||||
let mut burrow_bin =
|
|
||||||
String::from_utf8(Command::new("mktemp").output().unwrap().stdout).unwrap();
|
|
||||||
burrow_bin.pop();
|
|
||||||
|
|
||||||
let privileged_spawn_script = format!(
|
|
||||||
r#"TEMP=$(mktemp -p /root)
|
|
||||||
cp {} $TEMP
|
|
||||||
chmod +x $TEMP
|
|
||||||
setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip $TEMP
|
|
||||||
mv $TEMP /tmp/burrow-detached-daemon"#,
|
|
||||||
burrow_original_bin
|
|
||||||
)
|
|
||||||
.replace('\n', "&&");
|
|
||||||
|
|
||||||
// TODO: Handle error condition
|
|
||||||
|
|
||||||
Command::new("pkexec")
|
|
||||||
.arg("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(privileged_spawn_script)
|
|
||||||
.arg(&burrow_bin)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Command::new("/tmp/burrow-detached-daemon")
|
|
||||||
.env("RUST_LOG", "debug")
|
|
||||||
.arg("daemon")
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
DaemonGroupMsg::DaemonStateChange => {
|
|
||||||
self.already_running = self.daemon_client.lock().await.is_some();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use diag::{StatusTernary, SystemSetup};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DiagGroup {
|
pub struct DiagGroup {
|
||||||
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
|
||||||
system_setup: SystemSetup,
|
init_system: SystemSetup,
|
||||||
service_installed: StatusTernary,
|
service_installed: StatusTernary,
|
||||||
socket_installed: StatusTernary,
|
socket_installed: StatusTernary,
|
||||||
socket_enabled: StatusTernary,
|
socket_enabled: StatusTernary,
|
||||||
|
|
@ -13,20 +14,19 @@ pub struct DiagGroup {
|
||||||
|
|
||||||
pub struct DiagGroupInit {
|
pub struct DiagGroupInit {
|
||||||
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
pub system_setup: SystemSetup,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagGroup {
|
impl DiagGroup {
|
||||||
async fn new(daemon_client: Arc<Mutex<Option<DaemonClient>>>) -> Result<Self> {
|
async fn new(daemon_client: Arc<Mutex<Option<DaemonClient>>>) -> Result<Self> {
|
||||||
let system_setup = SystemSetup::new();
|
let setup = SystemSetup::new();
|
||||||
let daemon_running = daemon_client.lock().await.is_some();
|
let daemon_running = daemon_client.lock().await.is_some();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
service_installed: system_setup.is_service_installed()?,
|
service_installed: setup.is_service_installed()?,
|
||||||
socket_installed: system_setup.is_socket_installed()?,
|
socket_installed: setup.is_socket_installed()?,
|
||||||
socket_enabled: system_setup.is_socket_enabled()?,
|
socket_enabled: setup.is_socket_enabled()?,
|
||||||
daemon_running,
|
daemon_running,
|
||||||
system_setup,
|
init_system: setup,
|
||||||
daemon_client,
|
daemon_client,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ impl AsyncComponent for DiagGroup {
|
||||||
|
|
||||||
adw::ActionRow {
|
adw::ActionRow {
|
||||||
#[watch]
|
#[watch]
|
||||||
set_title: &format!("System Type: {}", model.system_setup)
|
set_title: &format!("Init System: {}", model.init_system)
|
||||||
},
|
},
|
||||||
adw::ActionRow {
|
adw::ActionRow {
|
||||||
#[watch]
|
#[watch]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use diag::{StatusTernary, SystemSetup};
|
|
||||||
|
|
||||||
mod daemon_group;
|
|
||||||
mod diag_group;
|
mod diag_group;
|
||||||
|
|
||||||
pub use daemon_group::{DaemonGroup, DaemonGroupInit, DaemonGroupMsg};
|
pub use diag_group::{DiagGroup, DiagGroupInit};
|
||||||
pub use diag_group::{DiagGroup, DiagGroupInit, DiagGroupMsg};
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,17 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use diag::SystemSetup;
|
|
||||||
|
|
||||||
pub struct SettingsScreen {
|
pub struct SettingsScreen {
|
||||||
diag_group: AsyncController<settings::DiagGroup>,
|
_diag_group: AsyncController<settings::DiagGroup>,
|
||||||
daemon_group: AsyncController<settings::DaemonGroup>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SettingsScreenInit {
|
pub struct SettingsScreenInit {
|
||||||
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum SettingsScreenMsg {
|
|
||||||
DaemonStateChange,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[relm4::component(pub)]
|
#[relm4::component(pub)]
|
||||||
impl SimpleComponent for SettingsScreen {
|
impl SimpleComponent for SettingsScreen {
|
||||||
type Init = SettingsScreenInit;
|
type Init = SettingsScreenInit;
|
||||||
type Input = SettingsScreenMsg;
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
|
|
@ -28,44 +21,24 @@ impl SimpleComponent for SettingsScreen {
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
init: Self::Init,
|
init: Self::Init,
|
||||||
root: &Self::Root,
|
root: Self::Root,
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
let system_setup = SystemSetup::new();
|
|
||||||
|
|
||||||
let diag_group = settings::DiagGroup::builder()
|
let diag_group = settings::DiagGroup::builder()
|
||||||
.launch(settings::DiagGroupInit {
|
.launch(settings::DiagGroupInit {
|
||||||
system_setup,
|
|
||||||
daemon_client: Arc::clone(&init.daemon_client),
|
daemon_client: Arc::clone(&init.daemon_client),
|
||||||
})
|
})
|
||||||
.forward(sender.input_sender(), |_| {
|
.forward(sender.input_sender(), |_| ());
|
||||||
SettingsScreenMsg::DaemonStateChange
|
|
||||||
});
|
|
||||||
|
|
||||||
let daemon_group = settings::DaemonGroup::builder()
|
|
||||||
.launch(settings::DaemonGroupInit {
|
|
||||||
system_setup,
|
|
||||||
daemon_client: Arc::clone(&init.daemon_client),
|
|
||||||
})
|
|
||||||
.forward(sender.input_sender(), |_| {
|
|
||||||
SettingsScreenMsg::DaemonStateChange
|
|
||||||
});
|
|
||||||
|
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
widgets.preferences.add(diag_group.widget());
|
widgets.preferences.add(diag_group.widget());
|
||||||
widgets.preferences.add(daemon_group.widget());
|
|
||||||
|
|
||||||
let model = SettingsScreen { diag_group, daemon_group };
|
let model = SettingsScreen {
|
||||||
|
_diag_group: diag_group,
|
||||||
|
};
|
||||||
|
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: Self::Input, _sender: ComponentSender<Self>) {
|
fn update(&mut self, _: Self::Input, _sender: ComponentSender<Self>) {}
|
||||||
// Currently, `SettingsScreenMsg` only has one variant, so the if is ambiguous.
|
|
||||||
//
|
|
||||||
// if let SettingsScreenMsg::DaemonStateChange = msg {
|
|
||||||
self.diag_group.emit(DiagGroupMsg::Refresh);
|
|
||||||
self.daemon_group.emit(DaemonGroupMsg::DaemonStateChange);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ impl AsyncComponent for SwitchScreen {
|
||||||
view! {
|
view! {
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
set_valign: Align::Fill,
|
set_valign: Align::BaselineFill,
|
||||||
|
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,15 @@ pub enum StatusTernary {
|
||||||
// Realistically, we may not explicitly "support" non-systemd platforms which would simply this
|
// Realistically, we may not explicitly "support" non-systemd platforms which would simply this
|
||||||
// code greatly.
|
// code greatly.
|
||||||
// Along with replacing [`StatusTernary`] with good old [`bool`].
|
// Along with replacing [`StatusTernary`] with good old [`bool`].
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum SystemSetup {
|
pub enum SystemSetup {
|
||||||
Systemd,
|
Systemd,
|
||||||
AppImage,
|
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemSetup {
|
impl SystemSetup {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
if is_appimage() {
|
if Command::new("systemctl").arg("--version").output().is_ok() {
|
||||||
SystemSetup::AppImage
|
|
||||||
} else if Command::new("systemctl").arg("--version").output().is_ok() {
|
|
||||||
SystemSetup::Systemd
|
SystemSetup::Systemd
|
||||||
} else {
|
} else {
|
||||||
SystemSetup::Other
|
SystemSetup::Other
|
||||||
|
|
@ -36,7 +33,6 @@ impl SystemSetup {
|
||||||
pub fn is_service_installed(&self) -> Result<StatusTernary> {
|
pub fn is_service_installed(&self) -> Result<StatusTernary> {
|
||||||
match self {
|
match self {
|
||||||
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into()),
|
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into()),
|
||||||
SystemSetup::AppImage => Ok(StatusTernary::NA),
|
|
||||||
SystemSetup::Other => Ok(StatusTernary::NA),
|
SystemSetup::Other => Ok(StatusTernary::NA),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +40,6 @@ impl SystemSetup {
|
||||||
pub fn is_socket_installed(&self) -> Result<StatusTernary> {
|
pub fn is_socket_installed(&self) -> Result<StatusTernary> {
|
||||||
match self {
|
match self {
|
||||||
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into()),
|
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into()),
|
||||||
SystemSetup::AppImage => Ok(StatusTernary::NA),
|
|
||||||
SystemSetup::Other => Ok(StatusTernary::NA),
|
SystemSetup::Other => Ok(StatusTernary::NA),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +55,6 @@ impl SystemSetup {
|
||||||
let output = String::from_utf8(output)?;
|
let output = String::from_utf8(output)?;
|
||||||
Ok((output == "enabled\n").into())
|
Ok((output == "enabled\n").into())
|
||||||
}
|
}
|
||||||
SystemSetup::AppImage => Ok(StatusTernary::NA),
|
|
||||||
SystemSetup::Other => Ok(StatusTernary::NA),
|
SystemSetup::Other => Ok(StatusTernary::NA),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,12 +74,7 @@ impl Display for SystemSetup {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(match self {
|
f.write_str(match self {
|
||||||
SystemSetup::Systemd => "Systemd",
|
SystemSetup::Systemd => "Systemd",
|
||||||
SystemSetup::AppImage => "AppImage",
|
|
||||||
SystemSetup::Other => "Other",
|
SystemSetup::Other => "Other",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_appimage() -> bool {
|
|
||||||
std::env::vars().any(|(k, _)| k == "APPDIR")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
version: "2.1"
|
|
||||||
networks:
|
|
||||||
wg6:
|
|
||||||
enable_ipv6: true
|
|
||||||
ipam:
|
|
||||||
driver: default
|
|
||||||
config:
|
|
||||||
- subnet: "aa:bb:cc:de::/64"
|
|
||||||
services:
|
|
||||||
burrow:
|
|
||||||
image: lscr.io/linuxserver/wireguard:latest
|
|
||||||
privileged: true
|
|
||||||
container_name: burrow_server
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
- SYS_MODULE
|
|
||||||
environment:
|
|
||||||
- PUID=1000
|
|
||||||
- PGID=1000
|
|
||||||
- TZ=Asia/Calcutta
|
|
||||||
- SERVERURL=wg.burrow.rs
|
|
||||||
- SERVERPORT=51820
|
|
||||||
- PEERS=10
|
|
||||||
- PEERDNS=1.1.1.1
|
|
||||||
- INTERNAL_SUBNET=10.13.13.0
|
|
||||||
- ALLOWEDIPS=0.0.0.0/0, ::/0
|
|
||||||
- PERSISTENTKEEPALIVE_PEERS=all
|
|
||||||
- LOG_CONFS=true #optional
|
|
||||||
volumes:
|
|
||||||
- ./config:/config
|
|
||||||
- /lib/modules:/lib/modules
|
|
||||||
ports:
|
|
||||||
- 51820:51820/udp
|
|
||||||
sysctls:
|
|
||||||
- net.ipv4.conf.all.src_valid_mark=1
|
|
||||||
- net.ipv6.conf.all.disable_ipv6=0
|
|
||||||
- net.ipv6.conf.eth0.proxy_ndp=1
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
@ -21,7 +21,7 @@ enum RunState {
|
||||||
pub struct DaemonInstance {
|
pub struct DaemonInstance {
|
||||||
rx: async_channel::Receiver<DaemonCommand>,
|
rx: async_channel::Receiver<DaemonCommand>,
|
||||||
sx: async_channel::Sender<DaemonResponse>,
|
sx: async_channel::Sender<DaemonResponse>,
|
||||||
tun_interface: Arc<RwLock<Option<TunInterface>>>,
|
tun_interface: Option<Arc<RwLock<TunInterface>>>,
|
||||||
wg_interface: Arc<RwLock<Interface>>,
|
wg_interface: Arc<RwLock<Interface>>,
|
||||||
wg_state: RunState,
|
wg_state: RunState,
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ impl DaemonInstance {
|
||||||
rx,
|
rx,
|
||||||
sx,
|
sx,
|
||||||
wg_interface,
|
wg_interface,
|
||||||
tun_interface: Arc::new(RwLock::new(None)),
|
tun_interface: None,
|
||||||
wg_state: RunState::Idle,
|
wg_state: RunState::Idle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,15 +50,15 @@ impl DaemonInstance {
|
||||||
warn!("Got start, but tun interface already up.");
|
warn!("Got start, but tun interface already up.");
|
||||||
}
|
}
|
||||||
RunState::Idle => {
|
RunState::Idle => {
|
||||||
let tun_if = st.tun.open()?;
|
let tun_if = Arc::new(RwLock::new(st.tun.open()?));
|
||||||
debug!("Setting tun on wg_interface");
|
|
||||||
self.wg_interface.read().await.set_tun(tun_if).await;
|
|
||||||
debug!("tun set on wg_interface");
|
|
||||||
|
|
||||||
debug!("Setting tun_interface");
|
debug!("Setting tun_interface");
|
||||||
self.tun_interface = self.wg_interface.read().await.get_tun();
|
self.tun_interface = Some(tun_if.clone());
|
||||||
debug!("tun_interface set: {:?}", self.tun_interface);
|
debug!("tun_interface set: {:?}", self.tun_interface);
|
||||||
|
|
||||||
|
debug!("Setting tun on wg_interface");
|
||||||
|
self.wg_interface.write().await.set_tun(tun_if);
|
||||||
|
debug!("tun set on wg_interface");
|
||||||
|
|
||||||
debug!("Cloning wg_interface");
|
debug!("Cloning wg_interface");
|
||||||
let tmp_wg = self.wg_interface.clone();
|
let tmp_wg = self.wg_interface.clone();
|
||||||
|
|
@ -82,18 +82,22 @@ impl DaemonInstance {
|
||||||
}
|
}
|
||||||
Ok(DaemonResponseData::None)
|
Ok(DaemonResponseData::None)
|
||||||
}
|
}
|
||||||
DaemonCommand::ServerInfo => match &self.tun_interface.read().await.as_ref() {
|
DaemonCommand::ServerInfo => match &self.tun_interface {
|
||||||
None => Ok(DaemonResponseData::None),
|
None => Ok(DaemonResponseData::None),
|
||||||
Some(ti) => {
|
Some(ti) => {
|
||||||
info!("{:?}", ti);
|
info!("{:?}", ti);
|
||||||
Ok(DaemonResponseData::ServerInfo(ServerInfo::try_from(
|
Ok(DaemonResponseData::ServerInfo(ServerInfo::try_from(
|
||||||
ti.inner.get_ref(),
|
ti.read().await.inner.get_ref(),
|
||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DaemonCommand::Stop => {
|
DaemonCommand::Stop => {
|
||||||
self.wg_interface.read().await.remove_tun().await;
|
if self.tun_interface.is_some() {
|
||||||
self.wg_state = RunState::Idle;
|
self.tun_interface = None;
|
||||||
|
info!("Daemon stopping tun interface.");
|
||||||
|
} else {
|
||||||
|
warn!("Got stop, but tun interface is not up.")
|
||||||
|
}
|
||||||
Ok(DaemonResponseData::None)
|
Ok(DaemonResponseData::None)
|
||||||
}
|
}
|
||||||
DaemonCommand::ServerConfig => {
|
DaemonCommand::ServerConfig => {
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ impl TryFrom<&TunInterface> for ServerInfo {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub address: Vec<String>,
|
pub address: Option<String>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub mtu: Option<i32>,
|
pub mtu: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +65,7 @@ pub struct ServerConfig {
|
||||||
impl Default for ServerConfig {
|
impl Default for ServerConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
address: vec!["10.13.13.2".to_string()], // Dummy remote address
|
address: Some("10.13.13.2".to_string()), // Dummy remote address
|
||||||
name: None,
|
name: None,
|
||||||
mtu: None,
|
mtu: None,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: burrow/src/daemon/command.rs
|
source: burrow/src/daemon/command.rs
|
||||||
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions {\n tun: TunOptions { ..TunOptions::default() },\n })).unwrap()"
|
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions {\n tun: TunOptions { ..TunOptions::default() },\n })).unwrap()"
|
||||||
---
|
---
|
||||||
{"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":[]}}}
|
{"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":null}}}
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: burrow/src/daemon/command.rs
|
source: burrow/src/daemon/command.rs
|
||||||
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions::default())).unwrap()"
|
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions::default())).unwrap()"
|
||||||
---
|
---
|
||||||
{"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":[]}}}
|
{"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":null}}}
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
source: burrow/src/daemon/response.rs
|
source: burrow/src/daemon/response.rs
|
||||||
expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::ServerConfig(ServerConfig::default()))))?"
|
expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::ServerConfig(ServerConfig::default()))))?"
|
||||||
---
|
---
|
||||||
{"result":{"Ok":{"ServerConfig":{"address":["10.13.13.2"],"name":null,"mtu":null}}},"id":0}
|
{"result":{"Ok":{"ServerConfig":{"address":"10.13.13.2","name":null,"mtu":null}}},"id":0}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ async fn try_start() -> Result<()> {
|
||||||
let mut client = DaemonClient::new().await?;
|
let mut client = DaemonClient::new().await?;
|
||||||
client
|
client
|
||||||
.send_command(DaemonCommand::Start(DaemonStartOptions {
|
.send_command(DaemonCommand::Start(DaemonStartOptions {
|
||||||
tun: TunOptions::new().address(vec!["10.13.13.2", "::2"]),
|
tun: TunOptions::new().address("10.13.13.2"),
|
||||||
}))
|
}))
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ pub fn initialize() {
|
||||||
tracing_subscriber::fmt::layer()
|
tracing_subscriber::fmt::layer()
|
||||||
.with_level(true)
|
.with_level(true)
|
||||||
.with_writer(std::io::stderr)
|
.with_writer(std::io::stderr)
|
||||||
.with_line_number(true)
|
|
||||||
.compact()
|
.compact()
|
||||||
.with_filter(EnvFilter::from_default_env())
|
.with_filter(EnvFilter::from_default_env())
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ pub struct Peer {
|
||||||
|
|
||||||
pub struct Interface {
|
pub struct Interface {
|
||||||
pub private_key: String,
|
pub private_key: String,
|
||||||
pub address: Vec<String>,
|
pub address: String,
|
||||||
pub listen_port: u32,
|
pub listen_port: u32,
|
||||||
pub dns: Vec<String>,
|
pub dns: Vec<String>,
|
||||||
pub mtu: Option<u32>,
|
pub mtu: Option<u32>,
|
||||||
|
|
@ -93,8 +93,8 @@ impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
interface: Interface {
|
interface: Interface {
|
||||||
private_key: "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=".into(),
|
private_key: "GNqIAOCRxjl/cicZyvkvpTklgQuUmGUIEkH7IXF/sEE=".into(),
|
||||||
address: vec!["10.13.13.2/24".into()],
|
address: "10.13.13.2/24".into(),
|
||||||
listen_port: 51820,
|
listen_port: 51820,
|
||||||
dns: Default::default(),
|
dns: Default::default(),
|
||||||
mtu: Default::default(),
|
mtu: Default::default(),
|
||||||
|
|
@ -102,8 +102,8 @@ impl Default for Config {
|
||||||
peers: vec![Peer {
|
peers: vec![Peer {
|
||||||
endpoint: "wg.burrow.rs:51820".into(),
|
endpoint: "wg.burrow.rs:51820".into(),
|
||||||
allowed_ips: vec!["8.8.8.8/32".into(), "0.0.0.0/0".into()],
|
allowed_ips: vec!["8.8.8.8/32".into(), "0.0.0.0/0".into()],
|
||||||
public_key: "8GaFjVO6c4luCHG4ONO+1bFG8tO+Zz5/Gy+Geht1USM=".into(),
|
public_key: "uy75leriJay0+oHLhRMpV+A5xAQ0hCJ+q7Ww81AOvT4=".into(),
|
||||||
preshared_key: Some("ha7j4BjD49sIzyF9SNlbueK0AMHghlj6+u0G3bzC698=".into()),
|
preshared_key: Some("s7lx/mg+reVEMnGnqeyYOQkzD86n2+gYnx1M9ygi08k=".into()),
|
||||||
persistent_keepalive: Default::default(),
|
persistent_keepalive: Default::default(),
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
}],
|
}],
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
use std::{net::IpAddr, sync::Arc};
|
use std::{net::IpAddr, sync::Arc};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use fehler::throws;
|
use fehler::throws;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use ip_network_table::IpNetworkTable;
|
use ip_network_table::IpNetworkTable;
|
||||||
use tokio::sync::{RwLock, Notify};
|
use tokio::sync::RwLock;
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
use tun::tokio::TunInterface;
|
use tun::tokio::TunInterface;
|
||||||
|
|
||||||
|
|
@ -47,21 +46,9 @@ impl FromIterator<PeerPcb> for IndexedPcbs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IfaceStatus {
|
|
||||||
Running,
|
|
||||||
Idle
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Interface {
|
pub struct Interface {
|
||||||
tun: Arc<RwLock<Option<TunInterface>>>,
|
tun: Option<Arc<RwLock<TunInterface>>>,
|
||||||
pcbs: Arc<IndexedPcbs>,
|
pcbs: Arc<IndexedPcbs>,
|
||||||
status: Arc<RwLock<IfaceStatus>>,
|
|
||||||
stop_notifier: Arc<Notify>,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_running(status: Arc<RwLock<IfaceStatus>>) -> bool {
|
|
||||||
let st = status.read().await;
|
|
||||||
matches!(st.deref(), IfaceStatus::Running)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interface {
|
impl Interface {
|
||||||
|
|
@ -73,54 +60,35 @@ impl Interface {
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
let pcbs = Arc::new(pcbs);
|
let pcbs = Arc::new(pcbs);
|
||||||
Self { pcbs, tun: Arc::new(RwLock::new(None)), status: Arc::new(RwLock::new(IfaceStatus::Idle)), stop_notifier: Arc::new(Notify::new()) }
|
Self { pcbs, tun: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_tun(&self, tun: TunInterface) {
|
pub fn set_tun(&mut self, tun: Arc<RwLock<TunInterface>>) {
|
||||||
debug!("Setting tun interface");
|
self.tun = Some(tun);
|
||||||
self.tun.write().await.replace(tun);
|
|
||||||
let mut st = self.status.write().await;
|
|
||||||
*st = IfaceStatus::Running;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tun(&self) -> Arc<RwLock<Option<TunInterface>>> {
|
|
||||||
self.tun.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_tun(&self){
|
|
||||||
let mut st = self.status.write().await;
|
|
||||||
self.stop_notifier.notify_waiters();
|
|
||||||
*st = IfaceStatus::Idle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self) -> anyhow::Result<()> {
|
pub async fn run(&self) -> anyhow::Result<()> {
|
||||||
let pcbs = self.pcbs.clone();
|
let pcbs = self.pcbs.clone();
|
||||||
let tun = self
|
let tun = self
|
||||||
.tun
|
.tun
|
||||||
.clone();
|
.clone()
|
||||||
let status = self.status.clone();
|
.ok_or(anyhow::anyhow!("tun interface does not exist"))?;
|
||||||
let stop_notifier = self.stop_notifier.clone();
|
|
||||||
log::info!("Starting interface");
|
log::info!("Starting interface");
|
||||||
|
|
||||||
let outgoing = async move {
|
let outgoing = async move {
|
||||||
while is_running(status.clone()).await {
|
loop {
|
||||||
let mut buf = [0u8; 3000];
|
let mut buf = [0u8; 3000];
|
||||||
|
|
||||||
let src = {
|
let src = {
|
||||||
let t = tun.read().await;
|
let src = match tun.read().await.recv(&mut buf[..]).await {
|
||||||
let Some(_tun) = t.as_ref() else {
|
Ok(len) => &buf[..len],
|
||||||
continue;
|
Err(e) => {
|
||||||
|
error!("Failed to read from interface: {}", e);
|
||||||
|
continue
|
||||||
|
}
|
||||||
};
|
};
|
||||||
tokio::select! {
|
debug!("Read {} bytes from interface", src.len());
|
||||||
_ = stop_notifier.notified() => continue,
|
src
|
||||||
pkg = _tun.recv(&mut buf[..]) => match pkg {
|
|
||||||
Ok(len) => &buf[..len],
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to read from interface: {}", e);
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let dst_addr = match Tunnel::dst_address(src) {
|
let dst_addr = match Tunnel::dst_address(src) {
|
||||||
|
|
@ -155,7 +123,8 @@ impl Interface {
|
||||||
let mut tsks = vec![];
|
let mut tsks = vec![];
|
||||||
let tun = self
|
let tun = self
|
||||||
.tun
|
.tun
|
||||||
.clone();
|
.clone()
|
||||||
|
.ok_or(anyhow::anyhow!("tun interface does not exist"))?;
|
||||||
let outgoing = tokio::task::spawn(outgoing);
|
let outgoing = tokio::task::spawn(outgoing);
|
||||||
tsks.push(outgoing);
|
tsks.push(outgoing);
|
||||||
debug!("preparing to spawn read tasks");
|
debug!("preparing to spawn read tasks");
|
||||||
|
|
@ -180,10 +149,9 @@ impl Interface {
|
||||||
};
|
};
|
||||||
|
|
||||||
let pcb = pcbs.pcbs[i].clone();
|
let pcb = pcbs.pcbs[i].clone();
|
||||||
let status = self.status.clone();
|
|
||||||
let update_timers_tsk = async move {
|
let update_timers_tsk = async move {
|
||||||
let mut buf = [0u8; 65535];
|
let mut buf = [0u8; 65535];
|
||||||
while is_running(status.clone()).await {
|
loop {
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(250)).await;
|
tokio::time::sleep(tokio::time::Duration::from_millis(250)).await;
|
||||||
match pcb.update_timers(&mut buf).await {
|
match pcb.update_timers(&mut buf).await {
|
||||||
Ok(..) => (),
|
Ok(..) => (),
|
||||||
|
|
@ -196,9 +164,8 @@ impl Interface {
|
||||||
};
|
};
|
||||||
|
|
||||||
let pcb = pcbs.pcbs[i].clone();
|
let pcb = pcbs.pcbs[i].clone();
|
||||||
let status = self.status.clone();
|
|
||||||
let reset_rate_limiter_tsk = async move {
|
let reset_rate_limiter_tsk = async move {
|
||||||
while is_running(status.clone()).await {
|
loop {
|
||||||
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||||
pcb.reset_rate_limiter().await;
|
pcb.reset_rate_limiter().await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ impl PeerPcb {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self, tun_interface: Arc<RwLock<Option<TunInterface>>>) -> Result<(), Error> {
|
pub async fn run(&self, tun_interface: Arc<RwLock<TunInterface>>) -> Result<(), Error> {
|
||||||
tracing::debug!("starting read loop for pcb... for {:?}", &self);
|
tracing::debug!("starting read loop for pcb... for {:?}", &self);
|
||||||
let rid: i32 = random();
|
let rid: i32 = random();
|
||||||
let mut buf: [u8; 3000] = [0u8; 3000];
|
let mut buf: [u8; 3000] = [0u8; 3000];
|
||||||
|
|
@ -106,12 +106,12 @@ impl PeerPcb {
|
||||||
}
|
}
|
||||||
TunnResult::WriteToTunnelV4(packet, addr) => {
|
TunnResult::WriteToTunnelV4(packet, addr) => {
|
||||||
tracing::debug!("WriteToTunnelV4: {:?}, {:?}", packet, addr);
|
tracing::debug!("WriteToTunnelV4: {:?}, {:?}", packet, addr);
|
||||||
tun_interface.read().await.as_ref().ok_or(anyhow::anyhow!("tun interface does not exist"))?.send(packet).await?;
|
tun_interface.read().await.send(packet).await?;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
TunnResult::WriteToTunnelV6(packet, addr) => {
|
TunnResult::WriteToTunnelV6(packet, addr) => {
|
||||||
tracing::debug!("WriteToTunnelV6: {:?}, {:?}", packet, addr);
|
tracing::debug!("WriteToTunnelV6: {:?}, {:?}", packet, addr);
|
||||||
tun_interface.read().await.as_ref().ok_or(anyhow::anyhow!("tun interface does not exist"))?.send(packet).await?;
|
tun_interface.read().await.send(packet).await?;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,22 @@
|
||||||
# Linux GTK App Getting Started
|
# Linux GTK App Getting Started
|
||||||
|
|
||||||
Currently, the GTK App can be built as a binary or as an AppImage.
|
|
||||||
Note that the flatpak version can compile but will not run properly!
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
### Install Build Dependencies
|
### Install Build Dependencies
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Debian</summary>
|
|
||||||
|
|
||||||
> Note: Burrow currently cannot compile on Debian Stable (Bookworm) due to its outdated dependencies
|
|
||||||
|
|
||||||
1. Install build dependencies
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt install -y clang meson cmake pkg-config libgtk-4-dev libadwaita-1-dev gettext desktop-file-utils
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Install flatpak builder (Optional)
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt install -y flatpak-builder
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Install AppImage build tools (Optional)
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt install -y wget fuse file
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Fedora</summary>
|
<summary>Fedora</summary>
|
||||||
|
|
||||||
1. Install build dependencies
|
1. Install build dependencies
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo dnf install -y clang ninja-build cmake meson gtk4-devel glib2-devel libadwaita-devel desktop-file-utils libappstream-glib
|
sudo dnf install clang ninja cmake meson gtk4-devel glib2-devel libadwaita-devel desktop-file-utils libappstream-glib
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install flatpak builder (Optional)
|
2. Install flatpak builder (Optional)
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo dnf install -y flatpak-builder
|
sudo dnf install flatpak-builder
|
||||||
```
|
|
||||||
|
|
||||||
3. Install AppImage build tools (Optional)
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo dnf install -y util-linux wget fuse fuse-libs file
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Void Linux (glibc)</summary>
|
|
||||||
|
|
||||||
1. Install build dependencies
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo xbps-install -Sy gcc clang meson cmake pkg-config gtk4-devel gettext desktop-file-utils gtk4-update-icon-cache appstream-glib
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Install flatpak builder (Optional)
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo xbps-install -Sy flatpak-builder
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Install AppImage build tools (Optional)
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo xbps-install -Sy wget fuse file
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
@ -119,23 +62,6 @@ flatpak install --user \
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>AppImage</summary>
|
|
||||||
|
|
||||||
1. Enter the `burrow-gtk`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd burrow-gtk
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Compile the AppImage
|
|
||||||
|
|
||||||
```
|
|
||||||
./build-aux/build_appimage.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
|
|
@ -157,14 +83,3 @@ flatpak install --user \
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>AppImage</summary>
|
|
||||||
|
|
||||||
The compiled binary can be found in `build-appimage/Burrow-*.AppImage`.
|
|
||||||
|
|
||||||
```
|
|
||||||
./build-appimage/Burrow-*.AppImage
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
# Add this to ~/server/wg0.conf upon regeneration
|
|
||||||
|
|
||||||
PostUp = iptables -A FORWARD -i %i -j ACCEPT
|
|
||||||
|
|
||||||
PostUp = iptables -A FORWARD -o %i -j ACCEPT
|
|
||||||
|
|
||||||
PostUp = iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
|
|
||||||
|
|
||||||
PostUp = ip6tables -A FORWARD -i %i -j ACCEPT
|
|
||||||
|
|
||||||
PostUp = ip6tables -A FORWARD -o %i -j ACCEPT
|
|
||||||
|
|
||||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT
|
|
||||||
|
|
||||||
PostDown = iptables -D FORWARD -o %i -j ACCEPT
|
|
||||||
|
|
||||||
PostDown = iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
|
|
||||||
|
|
||||||
PostDown = ip6tables -D FORWARD -i %i -j ACCEPT
|
|
||||||
|
|
||||||
PostDown = ip6tables -D FORWARD -o %i -j ACCEPT
|
|
||||||
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
fehler = "1.0"
|
fehler = "1.0"
|
||||||
nix = { version = "0.26", features = ["ioctl"] }
|
nix = { version = "0.26", features = ["ioctl"] }
|
||||||
socket2 = "0.5"
|
socket2 = "0.4"
|
||||||
tokio = { version = "1.28", features = [] }
|
tokio = { version = "1.28", features = [] }
|
||||||
byteorder = "1.4"
|
byteorder = "1.4"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub struct TunOptions {
|
||||||
/// (Apple) Retrieve the tun interface
|
/// (Apple) Retrieve the tun interface
|
||||||
pub tun_retrieve: bool,
|
pub tun_retrieve: bool,
|
||||||
/// (Linux) The IP address of the tun interface.
|
/// (Linux) The IP address of the tun interface.
|
||||||
pub address: Vec<String>,
|
pub address: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TunOptions {
|
impl TunOptions {
|
||||||
|
|
@ -44,8 +44,8 @@ impl TunOptions {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address(mut self, address: Vec<impl ToString>) -> Self {
|
pub fn address(mut self, address: impl ToString) -> Self {
|
||||||
self.address = address.iter().map(|x| x.to_string()).collect();
|
self.address = Some(address.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ impl SysControlSocket for socket2::Socket {
|
||||||
unsafe { sys::resolve_ctl_info(self.as_raw_fd(), &mut info as *mut sys::ctl_info)? };
|
unsafe { sys::resolve_ctl_info(self.as_raw_fd(), &mut info as *mut sys::ctl_info)? };
|
||||||
|
|
||||||
let (_, addr) = unsafe {
|
let (_, addr) = unsafe {
|
||||||
socket2::SockAddr::try_init(|addr_storage, len| {
|
socket2::SockAddr::init(|addr_storage, len| {
|
||||||
*len = size_of::<sys::sockaddr_ctl>() as u32;
|
*len = size_of::<sys::sockaddr_ctl>() as u32;
|
||||||
|
|
||||||
let addr: &mut sys::sockaddr_ctl = &mut *addr_storage.cast();
|
let addr: &mut sys::sockaddr_ctl = &mut *addr_storage.cast();
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
use std::{io::{Error, IoSlice}, mem, net::{Ipv4Addr, SocketAddrV4}, os::fd::{AsRawFd, FromRawFd, RawFd}, ptr};
|
use std::{
|
||||||
use std::net::{IpAddr, Ipv6Addr, SocketAddrV6};
|
io::{Error, IoSlice},
|
||||||
use std::ptr::addr_of;
|
mem,
|
||||||
|
net::{Ipv4Addr, SocketAddrV4},
|
||||||
|
os::fd::{AsRawFd, FromRawFd, RawFd},
|
||||||
|
};
|
||||||
|
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
use fehler::throws;
|
use fehler::throws;
|
||||||
use libc::{c_char, iovec, writev, AF_INET, AF_INET6, sockaddr_in6};
|
use libc::{c_char, iovec, writev, AF_INET, AF_INET6};
|
||||||
use nix::sys::socket::SockaddrIn6;
|
|
||||||
use socket2::{Domain, SockAddr, Socket, Type};
|
use socket2::{Domain, SockAddr, Socket, Type};
|
||||||
use tracing::{self, instrument};
|
use tracing::{self, instrument};
|
||||||
|
|
||||||
|
|
@ -47,7 +49,7 @@ impl TunInterface {
|
||||||
pub fn retrieve() -> Option<TunInterface> {
|
pub fn retrieve() -> Option<TunInterface> {
|
||||||
(3..100)
|
(3..100)
|
||||||
.filter_map(|fd| unsafe {
|
.filter_map(|fd| unsafe {
|
||||||
let peer_addr = socket2::SockAddr::try_init(|storage, len| {
|
let peer_addr = socket2::SockAddr::init(|storage, len| {
|
||||||
*len = mem::size_of::<sys::sockaddr_ctl>() as u32;
|
*len = mem::size_of::<sys::sockaddr_ctl>() as u32;
|
||||||
libc::getpeername(fd, storage as *mut _, len);
|
libc::getpeername(fd, storage as *mut _, len);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -69,12 +71,9 @@ impl TunInterface {
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
fn configure(&self, options: TunOptions) {
|
fn configure(&self, options: TunOptions) {
|
||||||
for addr in options.address{
|
if let Some(addr) = options.address {
|
||||||
if let Ok(addr) = addr.parse::<IpAddr>() {
|
if let Ok(addr) = addr.parse() {
|
||||||
match addr {
|
self.set_ipv4_addr(addr)?;
|
||||||
IpAddr::V4(addr) => {self.set_ipv4_addr(addr)?}
|
|
||||||
IpAddr::V6(addr) => {self.set_ipv6_addr(addr)?}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,14 +117,6 @@ impl TunInterface {
|
||||||
iff
|
iff
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
|
||||||
#[instrument]
|
|
||||||
fn in6_ifreq(&self) -> sys::in6_ifreq {
|
|
||||||
let mut iff: sys::in6_ifreq = unsafe { mem::zeroed() };
|
|
||||||
iff.ifr_name = string_to_ifname(&self.name()?);
|
|
||||||
iff
|
|
||||||
}
|
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
#[instrument]
|
#[instrument]
|
||||||
pub fn set_ipv4_addr(&self, addr: Ipv4Addr) {
|
pub fn set_ipv4_addr(&self, addr: Ipv4Addr) {
|
||||||
|
|
@ -145,21 +136,6 @@ impl TunInterface {
|
||||||
Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr))
|
Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
|
||||||
pub fn set_ipv6_addr(&self, addr: Ipv6Addr) {
|
|
||||||
// let addr = SockAddr::from(SocketAddrV6::new(addr, 0, 0, 0));
|
|
||||||
// println!("addr: {:?}", addr);
|
|
||||||
// let mut iff = self.in6_ifreq()?;
|
|
||||||
// let sto = addr.as_storage();
|
|
||||||
// let ifadddr_ptr: *const sockaddr_in6 = addr_of!(sto).cast();
|
|
||||||
// iff.ifr_ifru.ifru_addr = unsafe { *ifadddr_ptr };
|
|
||||||
// println!("ifru addr set");
|
|
||||||
// println!("{:?}", sys::SIOCSIFADDR_IN6);
|
|
||||||
// self.perform6(|fd| unsafe { sys::if_set_addr6(fd, &iff) })?;
|
|
||||||
// tracing::info!("ipv6_addr_set");
|
|
||||||
tracing::warn!("Setting IPV6 address on MacOS CLI mode is not supported yet.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
fn perform<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
|
fn perform<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
|
||||||
let span = tracing::info_span!("perform", fd = self.as_raw_fd());
|
let span = tracing::info_span!("perform", fd = self.as_raw_fd());
|
||||||
|
|
@ -169,15 +145,6 @@ impl TunInterface {
|
||||||
perform(socket.as_raw_fd())?
|
perform(socket.as_raw_fd())?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
|
||||||
fn perform6<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
|
|
||||||
let span = tracing::info_span!("perform6", fd = self.as_raw_fd());
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let socket = Socket::new(Domain::IPV6, Type::DGRAM, None)?;
|
|
||||||
perform(socket.as_raw_fd())?
|
|
||||||
}
|
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
#[instrument]
|
#[instrument]
|
||||||
pub fn mtu(&self) -> i32 {
|
pub fn mtu(&self) -> i32 {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use libc::{c_char, c_int, c_short, c_uint, c_ulong, sockaddr, sockaddr_in6, time_t};
|
use libc::{c_char, c_int, c_short, c_uint, c_ulong, sockaddr};
|
||||||
pub use libc::{
|
pub use libc::{
|
||||||
c_void,
|
c_void,
|
||||||
sockaddr_ctl,
|
sockaddr_ctl,
|
||||||
|
|
@ -23,7 +23,6 @@ pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
|
||||||
pub const UTUN_OPT_IFNAME: libc::c_int = 2;
|
pub const UTUN_OPT_IFNAME: libc::c_int = 2;
|
||||||
|
|
||||||
pub const MAX_KCTL_NAME: usize = 96;
|
pub const MAX_KCTL_NAME: usize = 96;
|
||||||
pub const SCOPE6_ID_MAX: usize = 16;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
|
@ -75,107 +74,7 @@ pub struct ifreq {
|
||||||
pub ifr_ifru: ifr_ifru,
|
pub ifr_ifru: ifr_ifru,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct in6_addrlifetime{
|
|
||||||
pub ia6t_expire: time_t,
|
|
||||||
pub ia6t_preferred: time_t,
|
|
||||||
pub ia6t_vltime: u32,
|
|
||||||
pub ia6t_pltime: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct in6_ifstat {
|
|
||||||
pub ifs6_in_receive: u64,
|
|
||||||
pub ifs6_in_hdrerr: u64,
|
|
||||||
pub ifs6_in_toobig: u64,
|
|
||||||
pub ifs6_in_noroute: u64,
|
|
||||||
pub ifs6_in_addrerr: u64,
|
|
||||||
pub ifs6_in_protounknown: u64,
|
|
||||||
pub ifs6_in_truncated: u64,
|
|
||||||
pub ifs6_in_discard: u64,
|
|
||||||
pub ifs6_in_deliver: u64,
|
|
||||||
pub ifs6_out_forward: u64,
|
|
||||||
pub ifs6_out_request: u64,
|
|
||||||
pub ifs6_out_discard: u64,
|
|
||||||
pub ifs6_out_fragok: u64,
|
|
||||||
pub ifs6_out_fragfail: u64,
|
|
||||||
pub ifs6_out_fragcreat: u64,
|
|
||||||
pub ifs6_reass_reqd: u64,
|
|
||||||
pub ifs6_reass_ok: u64,
|
|
||||||
pub ifs6_atmfrag_rcvd: u64,
|
|
||||||
pub ifs6_reass_fail: u64,
|
|
||||||
pub ifs6_in_mcast: u64,
|
|
||||||
pub ifs6_out_mcast: u64,
|
|
||||||
pub ifs6_cantfoward_icmp6: u64,
|
|
||||||
pub ifs6_addr_expiry_cnt: u64,
|
|
||||||
pub ifs6_pfx_expiry_cnt: u64,
|
|
||||||
pub ifs6_defrtr_expiry_cnt: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct icmp6_ifstat {
|
|
||||||
pub ifs6_in_msg: u64,
|
|
||||||
pub ifs6_in_error: u64,
|
|
||||||
pub ifs6_in_dstunreach: u64,
|
|
||||||
pub ifs6_in_adminprohib: u64,
|
|
||||||
pub ifs6_in_timeexceed: u64,
|
|
||||||
pub ifs6_in_paramprob: u64,
|
|
||||||
pub ifs6_in_pkttoobig: u64,
|
|
||||||
pub ifs6_in_echo: u64,
|
|
||||||
pub ifs6_in_echoreply: u64,
|
|
||||||
pub ifs6_in_routersolicit: u64,
|
|
||||||
pub ifs6_in_routeradvert: u64,
|
|
||||||
pub ifs6_in_neighborsolicit: u64,
|
|
||||||
pub ifs6_in_neighboradvert: u64,
|
|
||||||
pub ifs6_in_redirect: u64,
|
|
||||||
pub ifs6_in_mldquery: u64,
|
|
||||||
pub ifs6_in_mldreport: u64,
|
|
||||||
pub ifs6_in_mlddone: u64,
|
|
||||||
pub ifs6_out_msg: u64,
|
|
||||||
pub ifs6_out_error: u64,
|
|
||||||
pub ifs6_out_dstunreach: u64,
|
|
||||||
pub ifs6_out_adminprohib: u64,
|
|
||||||
pub ifs6_out_timeexceed: u64,
|
|
||||||
pub ifs6_out_paramprob: u64,
|
|
||||||
pub ifs6_out_pkttoobig: u64,
|
|
||||||
pub ifs6_out_echo: u64,
|
|
||||||
pub ifs6_out_echoreply: u64,
|
|
||||||
pub ifs6_out_routersolicit: u64,
|
|
||||||
pub ifs6_out_routeradvert: u64,
|
|
||||||
pub ifs6_out_neighborsolicit: u64,
|
|
||||||
pub ifs6_out_neighboradvert: u64,
|
|
||||||
pub ifs6_out_redirect: u64,
|
|
||||||
pub ifs6_out_mldquery: u64,
|
|
||||||
pub ifs6_out_mldreport: u64,
|
|
||||||
pub ifs6_out_mlddone: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub union ifr_ifru6 {
|
|
||||||
pub ifru_addr: sockaddr_in6,
|
|
||||||
pub ifru_dstaddr: sockaddr_in6,
|
|
||||||
pub ifru_flags: c_int,
|
|
||||||
pub ifru_flags6: c_int,
|
|
||||||
pub ifru_metric: c_int,
|
|
||||||
pub ifru_intval: c_int,
|
|
||||||
pub ifru_data: *mut c_char,
|
|
||||||
pub ifru_lifetime: in6_addrlifetime, // ifru_lifetime
|
|
||||||
pub ifru_stat: in6_ifstat,
|
|
||||||
pub ifru_icmp6stat: icmp6_ifstat,
|
|
||||||
pub ifru_scope_id: [u32; SCOPE6_ID_MAX]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct in6_ifreq {
|
|
||||||
pub ifr_name: [c_char; IFNAMSIZ],
|
|
||||||
pub ifr_ifru: ifr_ifru6,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const SIOCSIFADDR: c_ulong = request_code_write!(b'i', 12, mem::size_of::<ifreq>());
|
pub const SIOCSIFADDR: c_ulong = request_code_write!(b'i', 12, mem::size_of::<ifreq>());
|
||||||
pub const SIOCSIFADDR_IN6: c_ulong = request_code_write!(b'i', 12, mem::size_of::<in6_ifreq>());
|
|
||||||
pub const SIOCGIFMTU: c_ulong = request_code_readwrite!(b'i', 51, mem::size_of::<ifreq>());
|
pub const SIOCGIFMTU: c_ulong = request_code_readwrite!(b'i', 51, mem::size_of::<ifreq>());
|
||||||
pub const SIOCSIFMTU: c_ulong = request_code_write!(b'i', 52, mem::size_of::<ifreq>());
|
pub const SIOCSIFMTU: c_ulong = request_code_write!(b'i', 52, mem::size_of::<ifreq>());
|
||||||
pub const SIOCGIFNETMASK: c_ulong = request_code_readwrite!(b'i', 37, mem::size_of::<ifreq>());
|
pub const SIOCGIFNETMASK: c_ulong = request_code_readwrite!(b'i', 37, mem::size_of::<ifreq>());
|
||||||
|
|
@ -198,6 +97,5 @@ ioctl_read_bad!(if_get_addr, libc::SIOCGIFADDR, ifreq);
|
||||||
ioctl_read_bad!(if_get_mtu, SIOCGIFMTU, ifreq);
|
ioctl_read_bad!(if_get_mtu, SIOCGIFMTU, ifreq);
|
||||||
ioctl_read_bad!(if_get_netmask, SIOCGIFNETMASK, ifreq);
|
ioctl_read_bad!(if_get_netmask, SIOCGIFNETMASK, ifreq);
|
||||||
ioctl_write_ptr_bad!(if_set_addr, SIOCSIFADDR, ifreq);
|
ioctl_write_ptr_bad!(if_set_addr, SIOCSIFADDR, ifreq);
|
||||||
ioctl_write_ptr_bad!(if_set_addr6, SIOCSIFADDR_IN6, in6_ifreq);
|
|
||||||
ioctl_write_ptr_bad!(if_set_mtu, SIOCSIFMTU, ifreq);
|
ioctl_write_ptr_bad!(if_set_mtu, SIOCSIFMTU, ifreq);
|
||||||
ioctl_write_ptr_bad!(if_set_netmask, SIOCSIFNETMASK, ifreq);
|
ioctl_write_ptr_bad!(if_set_netmask, SIOCSIFNETMASK, ifreq);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{io::Error, net::Ipv4Addr};
|
use std::{io::Error, net::Ipv4Addr};
|
||||||
use std::net::Ipv6Addr;
|
|
||||||
|
|
||||||
use fehler::throws;
|
use fehler::throws;
|
||||||
use tun::TunInterface;
|
use tun::TunInterface;
|
||||||
|
|
@ -34,15 +33,3 @@ fn write_packets() {
|
||||||
let bytes_written = tun.send(&buf)?;
|
let bytes_written = tun.send(&buf)?;
|
||||||
assert_eq!(bytes_written, 1504);
|
assert_eq!(bytes_written, 1504);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[throws]
|
|
||||||
#[ignore = "requires interactivity"]
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn set_ipv6() {
|
|
||||||
let tun = TunInterface::new()?;
|
|
||||||
println!("tun name: {:?}", tun.name()?);
|
|
||||||
let targ_addr: Ipv6Addr = "::1".parse().unwrap();
|
|
||||||
println!("v6 addr: {:?}", targ_addr);
|
|
||||||
tun.set_ipv6_addr(targ_addr)?;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue