Compare commits

..

25 commits

Author SHA1 Message Date
Conrad Kramer
85640ffce1 Switch to gRPC client in Swift app
Some checks are pending
Build AppImage / Build AppImage (push) Waiting to run
Build Apple Apps / Build App (iOS) (push) Waiting to run
Build Apple Apps / Build App (iOS Simulator) (push) Waiting to run
Build Apple Apps / Build App (macOS) (push) Waiting to run
Build Docker / Build Docker Image (push) Waiting to run
Build Rust Crate / Build Crate (macOS (Intel)) (push) Waiting to run
Build Rust Crate / Build Crate (macOS) (push) Waiting to run
Build Rust Crate / Build Crate (Linux) (push) Waiting to run
Build Rust Crate / Build Crate (Windows) (push) Waiting to run
2024-09-09 10:38:13 -07:00
Conrad Kramer
25a0f7c421 Add Developer ID Profiles to build 2024-09-07 20:35:28 -07:00
Jett Chen
e4b0f1660b GRPC Server Support
- Deprecates old json-rpc system
- Add GRPC daemon over uds
2024-09-08 11:33:11 +08:00
Conrad Kramer
3fbb520a10 Fix SwiftLint errors 2024-09-07 18:00:04 -07:00
Conrad Kramer
fa1ef6fcda Download provisioning profiles in release pipeline 2024-09-07 18:00:04 -07:00
Conrad Kramer
62a5739d86 Update pipelines with various fixes 2024-09-07 17:07:04 -07:00
Jett Chen
aa634d03e2 update protobuf definition file 2024-07-13 18:14:00 -07:00
Jett Chen
951b4ddae2 add protobuf definition file 2024-07-13 18:09:09 -07:00
Conrad Kramer
3dedca4de3 Update build settings 2024-07-06 17:20:46 -07:00
Conrad Kramer
3c70bc2a5c Remove SwiftLint from Xcode project 2024-07-06 12:18:58 -07:00
Conrad Kramer
bca07c33b8 Start authentication flow 2024-07-06 12:18:58 -07:00
Jett Chen
abf1101484
Wireguard Configuration in SQLite (#263)
#241
2024-04-21 18:01:47 -04:00
Conrad Kramer
df549d48e6 Implement Slack authentication on iOS 2024-04-03 15:12:11 -07:00
Conrad Kramer
ec8cc533ab Add apple-app-site-association file 2024-03-30 17:18:46 -07:00
Kartikey S. Chauhan
a97063f9b7 Initial website setup
- Created project structure with necessary directories and files
- Set up Next.js with Tailwind CSS and Font Awesome
- Added base HTML structure and layout components
- Configured routing and created the homepage
- Styled the homepage with basic styling
- Added FontAwesome icons
- Configured font imports and styles
- Integrated HackClub branding elements

This commit establishes the foundation for our website, including the project structure, styling, and initial content.
2024-03-30 17:02:11 -07:00
Conrad Kramer
cb1bc1c8aa Update release pipelines to upload release artifacts 2024-03-23 13:41:07 -07:00
Conrad Kramer
4334f8c9c9 Configure CARGO_TARGET_DIR to be inside of DerivedData 2024-03-16 10:34:59 -07:00
Conrad Kramer
0fe630878d Introduce initial UI for connecting to networks 2024-03-10 18:59:31 -04:00
Conrad Kramer
51fd638b72 Update for Xcode 15.2 2024-03-10 18:59:31 -04:00
David Zhong
c755f752a0
Implement launching a local daemon (#261)
Allow AppImage and non-systemd systems to launch a local burrow daemon.
2024-03-09 17:52:59 -08:00
Jett Chen
c4c342dc8b Add implementation for stop command
This adds implementation for stopping the tunnel
via the `Stop` command.
2024-02-25 04:14:32 +08:00
Ben
29d2bfae3f Remove redundant type annotation 2024-02-24 12:53:59 -05:00
Jett Chen
2088ae6ede Add Support for IPV6 and Arbitrary Server Address
Add IPV6 support for Apple Devices
Note: Works in GUI not CLI
Adds Support for Arbitrary Server Address
2024-02-24 12:44:31 -05:00
David Zhong
cca5999214 Bump Rust version in Dockerfile
clap-rs recently bumped their MSRV to 1.74 breaking the docker build.
2024-02-15 19:42:57 -08:00
David Zhong
ab73183b2b
Add ability to build GTK app AppImage (#240)
#238 Add AppImage build support

Implements

- Downgrade to libadwaita 1.3 for wider distro support
- Add build script, workflow, and docs for AppImage
- Add build docs for Debian (apt) and Void Linux
- Building AppImage in CI
2024-02-15 19:27:14 -08:00
210 changed files with 7521 additions and 1987 deletions

View file

@ -26,18 +26,18 @@ runs:
run: |
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
xcodebuild archive \
xcodebuild clean archive \
-allowProvisioningUpdates \
-allowProvisioningDeviceRegistration \
-skipPackagePluginValidation \
-skipMacroValidation \
-onlyUsePackageVersionsFromResolvedFile \
-authenticationKeyID ${{ inputs.app-store-key-id }} \
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
-onlyUsePackageVersionsFromResolvedFile \
-scheme '${{ inputs.scheme }}' \
-destination '${{ inputs.destination }}' \
-archivePath '${{ inputs.archive-path }}' \
-resultBundlePath BuildResults.xcresult
./Tools/xcresulttool-github BuildResults.xcresult
rm -rf AuthKey_${{ inputs.app-store-key-id }}.p8

View file

@ -18,32 +18,36 @@ inputs:
runs:
using: composite
steps:
- name: Cache Swift Packages
- name: Xcode Cache
uses: actions/cache@v3
with:
path: |
Apple/PackageCache
Apple/SourcePackages
Apple/DerivedData
key: ${{ runner.os }}-${{ inputs.scheme }}-${{ hashFiles('**/Package.resolved') }}
restore-keys: |
${{ runner.os }}-${{ inputs.scheme }}-${{ hashFiles('**/Package.resolved') }}
${{ runner.os }}-${{ inputs.scheme }}-
${{ runner.os }}-
- name: Build
shell: bash
working-directory: Apple
run: |
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
xcodebuild clean build-for-testing \
xcodebuild build-for-testing \
-allowProvisioningUpdates \
-allowProvisioningDeviceRegistration \
-skipPackagePluginValidation \
-skipMacroValidation \
-onlyUsePackageVersionsFromResolvedFile \
-authenticationKeyID ${{ inputs.app-store-key-id }} \
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \
-onlyUsePackageVersionsFromResolvedFile \
-clonedSourcePackagesDirPath SourcePackages \
-packageCachePath $PWD/PackageCache \
-skipPackagePluginValidation \
-skipMacroValidation \
-derivedDataPath $PWD/DerivedData \
-scheme '${{ inputs.scheme }}' \
-destination '${{ inputs.destination }}' \
-resultBundlePath BuildResults.xcresult

View file

@ -0,0 +1,30 @@
name: Download Provisioning Profiles
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
runs:
using: composite
steps:
- shell: bash
env:
FASTLANE_OPT_OUT_USAGE: 'YES'
run: |
APP_STORE_KEY=$(echo "${{ inputs.app-store-key }}" | jq -sR .)
cat << EOF > api-key.json
{
"key_id": "${{ inputs.app-store-key-id }}",
"issuer_id": "${{ inputs.app-store-key-issuer-id }}",
"key": $APP_STORE_KEY
}
EOF
fastlane sigh download_all --api_key_path api-key.json
rm -rf api-key.json

View file

@ -1,4 +1,4 @@
name: Notarize
name: Export
inputs:
app-store-key:
description: App Store key in PEM PKCS#8 format
@ -12,11 +12,8 @@ inputs:
archive-path:
description: Xcode archive path
required: true
destination:
description: The Xcode export destination. This can either be "export" or "upload"
required: true
method:
description: The Xcode export method. This can be one of app-store, validation, ad-hoc, package, enterprise, development, developer-id, or mac-application.
export-options:
description: The export options in JSON format
required: true
export-path:
description: The path to export the archive to
@ -24,19 +21,20 @@ inputs:
runs:
using: composite
steps:
- id: notarize
shell: bash
- shell: bash
working-directory: Apple
run: |
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
echo '{"destination":"${{ inputs.destination }}","method":"${{ inputs.method }}"}' \
| plutil -convert xml1 -o ExportOptions.plist -
echo '${{ inputs.export-options }}' | plutil -convert xml1 -o ExportOptions.plist -
xcodebuild \
-exportArchive \
-allowProvisioningUpdates \
-allowProvisioningDeviceRegistration \
-skipPackagePluginValidation \
-skipMacroValidation \
-onlyUsePackageVersionsFromResolvedFile \
-authenticationKeyID ${{ inputs.app-store-key-id }} \
-authenticationKeyIssuerID ${{ inputs.app-store-key-issuer-id }} \
-authenticationKeyPath "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" \

25
.github/actions/notarize/action.yml vendored Normal file
View file

@ -0,0 +1,25 @@
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
runs:
using: composite
steps:
- id: notarize
shell: bash
working-directory: Apple
run: |
echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8
ditto -c -k --keepParent Release/Burrow.app Upload.zip
xcrun notarytool submit --wait --issuer ${{ inputs.app-store-key-issuer-id }} --key-id ${{ inputs.app-store-key-id }} --key "${PWD}/AuthKey_${{ inputs.app-store-key-id }}.p8" Upload.zip
xcrun stapler staple Release/Burrow.app
rm -rf AuthKey_${{ inputs.app-store-key-id }}.p8 Release

View file

@ -18,9 +18,6 @@ inputs:
runs:
using: composite
steps:
- shell: bash
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- shell: bash
working-directory: Apple
run: |
@ -28,10 +25,10 @@ runs:
-scheme '${{ inputs.scheme }}' \
-destination '${{ inputs.destination }}' \
${{ inputs.test-plan && '-testPlan ' }}${{ inputs.test-plan }} \
-resultBundlePath "${{ inputs.artifact-prefix }}-${{ steps.vars.outputs.sha_short }}.xcresult"
-resultBundlePath "${{ inputs.artifact-prefix }}.xcresult"
- uses: kishikawakatsumi/xcresulttool@v1
if: always()
with:
path: Apple/${{ inputs.artifact-prefix }}-${{ steps.vars.outputs.sha_short }}.xcresult
path: Apple/${{ inputs.artifact-prefix }}.xcresult
title: ${{ inputs.check-name }}
show-passed-tests: false

29
.github/workflows/build-appimage.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Build AppImage
on:
push:
branches:
- main
pull_request:
branches:
- "*"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
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
name: Upload to GitHub
with:
name: AppImage
path: Burrow-x86_64.AppImage

View file

@ -1,7 +1,7 @@
name: Apple Build
name: Build Apple Apps
on:
push:
branches:
branches:
- main
pull_request:
branches:
@ -12,7 +12,7 @@ concurrency:
jobs:
build:
name: Build App (${{ matrix.platform }})
runs-on: macos-13
runs-on: macos-14
strategy:
fail-fast: false
matrix:
@ -24,7 +24,7 @@ jobs:
rust-targets:
- aarch64-apple-ios
- scheme: App
destination: platform=iOS Simulator,OS=17.2,name=iPhone 15 Pro
destination: platform=iOS Simulator,OS=18.0,name=iPhone 15 Pro
platform: iOS Simulator
sdk-name: iphonesimulator
rust-targets:
@ -38,7 +38,8 @@ jobs:
- x86_64-apple-darwin
- aarch64-apple-darwin
env:
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer
PROTOC_PATH: /opt/homebrew/bin/protoc
steps:
- name: Checkout
uses: actions/checkout@v3
@ -53,8 +54,10 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ join(matrix.rust-targets, ', ') }}
- name: Install Protobuf
shell: bash
run: brew install protobuf
- name: Build
id: build
uses: ./.github/actions/build-for-testing
@ -64,7 +67,7 @@ jobs:
app-store-key: ${{ secrets.APPSTORE_KEY }}
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
- name: Xcode Unit Test
- name: Run Unit Tests
if: ${{ matrix.xcode-unit-test != '' }}
continue-on-error: true
uses: ./.github/actions/test-without-building
@ -74,7 +77,7 @@ jobs:
test-plan: ${{ matrix.xcode-unit-test }}
artifact-prefix: unit-tests-${{ matrix.sdk-name }}
check-name: Xcode Unit Tests (${{ matrix.platform }})
- name: Xcode UI Test
- name: Run UI Tests
if: ${{ matrix.xcode-ui-test != '' }}
continue-on-error: true
uses: ./.github/actions/test-without-building
@ -83,4 +86,4 @@ jobs:
destination: ${{ matrix.destination }}
test-plan: ${{ matrix.xcode-ui-test }}
artifact-prefix: ui-tests-${{ matrix.sdk-name }}
check-name: Xcode UI Tests (${{ matrix.platform }})
check-name: Xcode UI Tests (${{ matrix.platform }})

View file

@ -6,6 +6,9 @@ on:
pull_request:
branches:
- "*"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build Docker Image
@ -33,6 +36,7 @@ jobs:
images: ghcr.io/${{ github.repository }}
tags: |
type=sha
type=match,pattern=builds/(.*),group=1
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and Push
uses: docker/build-push-action@v4

View file

@ -1,7 +1,4 @@
on:
push:
branches: [main]
pull_request:
on: workflow_dispatch
name: Build Flatpak
jobs:
flatpak:

View file

@ -1,16 +1,11 @@
on: workflow_dispatch
name: Build RPM
on:
push:
branches: [ "main" ]
pull_request:
branches:
- "*"
jobs:
build:
name: Build RPM
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
- name: Install RPM
run: cargo install cargo-generate-rpm
@ -20,4 +15,3 @@ jobs:
strip -s target/release/burrow
- name: Build RPM
run: cargo generate-rpm -p burrow

View file

@ -1,4 +1,4 @@
name: Rust Build
name: Build Rust Crate
on:
push:
branches:
@ -21,15 +21,21 @@ jobs:
- x86_64-unknown-linux-gnu
targets:
- aarch64-unknown-linux-gnu
- os: macos-12
platform: macOS
- os: macos-13
platform: macOS (Intel)
xcode: /Applications/Xcode_15.2.app
test-targets:
- x86_64-apple-darwin
targets:
- x86_64-apple-ios
- os: macos-14
platform: macOS
xcode: /Applications/Xcode_16.0.app
test-targets:
- aarch64-apple-darwin
targets:
- aarch64-apple-ios
- aarch64-apple-ios-sim
- x86_64-apple-ios
- os: windows-2022
platform: Windows
test-targets:
@ -38,10 +44,11 @@ jobs:
- aarch64-pc-windows-msvc
runs-on: ${{ matrix.os }}
env:
DEVELOPER_DIR: /Applications/Xcode_14.2.app/Contents/Developer
DEVELOPER_DIR: ${{ matrix.xcode }}/Contents/Developer
CARGO_INCREMENTAL: 0
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
RUST_BACKTRACE: short
PROTOC_VERSION: 3.25.1
steps:
- name: Checkout
uses: actions/checkout@v3
@ -54,10 +61,14 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y ${{ join(matrix.packages, ' ') }}
- name: Install Windows Deps
- name: Configure LLVM
if: matrix.os == 'windows-2022'
shell: bash
run: echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH
- name: Install protoc
uses: taiki-e/install-action@v2
with:
tool: protoc@${{ env.PROTOC_VERSION }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
@ -71,4 +82,4 @@ jobs:
run: cargo build --verbose --workspace --all-features --target ${{ join(matrix.targets, ' --target ') }} --target ${{ join(matrix.test-targets, ' --target ') }}
- name: Test
shell: bash
run: cargo test --verbose --workspace --all-features --target ${{ join(matrix.test-targets, ' --target ') }}
run: cargo test --verbose --workspace --all-features --target ${{ join(matrix.test-targets, ' --target ') }}

View file

@ -8,13 +8,14 @@ jobs:
name: Git Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Install Gitlint
shell: bash
run: python -m pip install gitlint
- name: Run Gitlint
shell: bash
run: gitlint --commits "${{ github.event.pull_request.base.sha }}..HEAD"
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Install
shell: bash
run: python -m pip install gitlint
- name: Lint
shell: bash
run: gitlint --commits "${{ github.event.pull_request.base.sha }}..HEAD"

View file

@ -1,8 +1,5 @@
name: Swift Lint
on:
push:
branches:
- main
pull_request:
branches:
- "*"
@ -14,8 +11,6 @@ jobs:
image: ghcr.io/realm/swiftlint:latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ssh-key: ${{ secrets.DEPLOY_KEY }}
uses: actions/checkout@v4
- name: Lint
run: swiftlint lint --reporter github-actions-logging
run: swiftlint lint --strict --reporter github-actions-logging

View file

@ -1,65 +1,119 @@
name: Build Apple Release
name: Release (Apple)
on:
release:
types:
- created
jobs:
build:
name: Build ${{ matrix.configuration['platform'] }} Release
runs-on: macos-13
name: Build ${{ matrix.platform }} Release
runs-on: macos-14
permissions:
contents: write
strategy:
fail-fast: false
matrix:
configuration:
- scheme: App (iOS)
destination: generic/platform=iOS
platform: iOS
method: ad-hoc
artifact-file: Apple/Release/Burrow.ipa
- scheme: App (macOS)
destination: generic/platform=macOS
platform: macOS
method: mac-application
artifact-file: Burrow.app.txz
include:
- platform: iOS
rust-targets:
- aarch64-apple-ios
- platform: macOS
rust-targets:
- x86_64-apple-darwin
- aarch64-apple-darwin
env:
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer
PROTOC_PATH: /opt/homebrew/bin/protoc
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ssh-key: ${{ secrets.DEPLOY_KEY }}
submodules: recursive
fetch-depth: 0
- name: Import Certificate
uses: ./.github/actions/import-cert
with:
certificate: ${{ secrets.DEVELOPER_CERT }}
password: ${{ secrets.DEVELOPER_CERT_PASSWORD }}
- name: Download Provisioning Profiles
uses: ./.github/actions/download-profiles
with:
app-store-key: ${{ secrets.APPSTORE_KEY }}
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
- name: Install Provisioning Profiles
shell: bash
run: |
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles/
cp -f Apple/Profiles/* ~/Library/MobileDevice/Provisioning\ Profiles/
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ join(matrix.rust-targets, ', ') }}
- name: Install Protobuf
shell: bash
run: brew install protobuf
- name: Configure Version
id: version
shell: bash
run: echo "BUILD_NUMBER=$(Tools/version.sh)" >> $GITHUB_OUTPUT
- name: Archive
uses: ./.github/actions/archive
with:
scheme: ${{ matrix.configuration['scheme'] }}
destination: ${{ matrix.configuration['destination'] }}
scheme: App
destination: generic/platform=${{ matrix.platform }}
app-store-key: ${{ secrets.APPSTORE_KEY }}
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
archive-path: Burrow.xcarchive
- name: Export Locally
- name: Export
uses: ./.github/actions/export
with:
method: ${{ matrix.configuration['method'] }}
method: ${{ matrix.platform == 'macOS' && 'developer-id' || 'ad-hoc' }}
destination: export
app-store-key: ${{ secrets.APPSTORE_KEY }}
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
archive-path: Burrow.xcarchive
export-options: |
{"teamID":"P6PV2R9443","destination":"export","method":"developer-id","provisioningProfiles":{"com.hackclub.burrow":"Burrow Developer ID","com.hackclub.burrow.network":"Burrow Network Developer ID"},"signingCertificate":"Developer ID Application","signingStyle":"manual"}
export-path: Release
- name: Compress
if: ${{ matrix.configuration['platform'] == 'macOS' }}
- name: Notarize
if: ${{ matrix.platform == 'macOS' }}
uses: ./.github/actions/notarize
with:
app-store-key: ${{ secrets.APPSTORE_KEY }}
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
- name: Compress (iOS)
if: ${{ matrix.platform == 'iOS' }}
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
run: |
cp Apple/Release/Burrow.ipa Burrow.ipa
aa archive -a lzma -b 8m -d Apple -subdir Burrow.xcarchive -o Burrow-${{ matrix.platform }}.xcarchive.aar
rm -rf Apple/Release
- name: Compress (macOS)
if: ${{ matrix.platform == 'macOS' }}
shell: bash
run: |
aa archive -a lzma -b 8m -d Apple/Release -subdir Burrow.app -o Burrow.app.aar
aa archive -a lzma -b 8m -d Apple -subdir Burrow.xcarchive -o Burrow-${{ matrix.platform }}.xcarchive.aar
rm -rf Apple/Release
- name: Upload to GitHub
uses: SierraSoftworks/gh-releases@v1.0.7
with:
token: ${{ secrets.GITHUB_TOKEN }}
overwrite: 'false'
files: ${{ matrix.configuration['artifact-file'] }}
release_tag: ${{ github.ref_name }}
overwrite: 'true'
files: |
${{ matrix.platform == 'macOS' && 'Burrow.aap.aar' || 'Burrow.ipa' }}
Burrow-${{ matrix.platform }}.xcarchive.aar
- name: Upload to App Store Connect
if: ${{ matrix.platform == 'iOS' }}
uses: ./.github/actions/export
with:
app-store-key: ${{ secrets.APPSTORE_KEY }}
app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }}
app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
archive-path: Burrow.xcarchive
export-options: |
{"method": "app-store", "destination": "upload"}
export-path: Release

View file

@ -0,0 +1,23 @@
name: Create Release If Needed
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * *'
concurrency:
group: ${{ github.workflow }}
jobs:
create:
name: Create Release If Needed
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- shell: bash
run: |
if [[ $(Tools/version.sh status) == "dirty" ]]; then
gh workflow run release-now.yml
fi

29
.github/workflows/release-linux.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Release (Linux)
on:
release:
types:
- created
jobs:
appimage:
name: Build AppImage
runs-on: ubuntu-latest
container: docker
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- 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
- name: Attach Artifacts
uses: SierraSoftworks/gh-releases@v1.0.7
with:
token: ${{ secrets.GITHUB_TOKEN }}
release_tag: ${{ github.ref_name }}
overwrite: "true"
files: |
Burrow-x86_64.AppImage

17
.github/workflows/release-now.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Create Release
on: workflow_dispatch
concurrency:
group: ${{ github.workflow }}
jobs:
create:
env:
GH_TOKEN: ${{ secrets.GH_RELEASE_TOKEN }}
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- shell: bash
run: Tools/version.sh increment

9
.gitignore vendored
View file

@ -1,8 +1,17 @@
# Xcode
xcuserdata
# Swift
Apple/Package/.swiftpm/
# Rust
target/
.env
.DS_STORE
.idea/
tmp/
*.db
*.sock

View file

@ -30,7 +30,6 @@ opt_in_rules:
- function_default_parameter_at_end
- ibinspectable_in_extension
- identical_operands
- implicitly_unwrapped_optional
- indentation_width
- joined_default_parameter
- last_where
@ -46,7 +45,6 @@ opt_in_rules:
- multiline_parameters
- multiline_parameters_brackets
- no_extension_access_modifier
- no_grouping_extension
- nslocalizedstring_key
- nslocalizedstring_require_bundle
- number_separator
@ -76,9 +74,7 @@ opt_in_rules:
- sorted_first_last
- sorted_imports
- static_operator
- strict_fileprivate
- strong_iboutlet
- switch_case_on_newline
- test_case_accessibility
- toggle_bool
- trailing_closure
@ -97,3 +93,5 @@ disabled_rules:
- force_try
- nesting
- todo
- trailing_comma
- switch_case_on_newline

42
.vscode/settings.json vendored
View file

@ -1,18 +1,26 @@
{
"files.autoSave": "onFocusChange",
"files.defaultLanguage": "rust",
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"files.trimTrailingWhitespace": true,
"editor.suggest.preview": true,
"editor.acceptSuggestionOnEnter": "on",
"rust-analyzer.restartServerOnConfigChange": true,
"rust-analyzer.cargo.features": "all",
"rust-analyzer.rustfmt.extraArgs": [
"+nightly"
],
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer",
},
"rust-analyzer.inlayHints.typeHints.enable": false
}
"files.autoSave": "onFocusChange",
"files.defaultLanguage": "rust",
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"files.trimTrailingWhitespace": true,
"editor.suggest.preview": true,
"editor.acceptSuggestionOnEnter": "on",
"rust-analyzer.restartServerOnConfigChange": true,
"rust-analyzer.cargo.features": "all",
"rust-analyzer.rustfmt.extraArgs": ["+nightly"],
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
},
"rust-analyzer.inlayHints.typeHints.enable": false,
"rust-analyzer.linkedProjects": [
"./burrow/Cargo.toml"
],
"[yaml]": {
"editor.insertSpaces": true,
"editor.tabSize": 2,
"editor.autoIndent": "advanced",
"diffEditor.ignoreTrimWhitespace": false,
"editor.formatOnSave": false
}
}

View file

@ -2,6 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:burrow.rs?mode=developer</string>
<string>webcredentials:burrow.rs?mode=developer</string>
</array>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>

View file

@ -2,6 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:burrow.rs?mode=developer</string>
<string>webcredentials:burrow.rs?mode=developer</string>
</array>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>

View file

@ -11,7 +11,12 @@ INFOPLIST_KEY_UIStatusBarStyle[sdk=iphone*] = UIStatusBarStyleDefault
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad[sdk=iphone*] = UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone[sdk=iphone*] = UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
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
CODE_SIGN_ENTITLEMENTS = App/App-iOS.entitlements

View file

@ -1,7 +1,9 @@
#if os(macOS)
import AppKit
import BurrowUI
import SwiftUI
@main
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
private let quitItem: NSMenuItem = {
@ -16,7 +18,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}()
private let toggleItem: NSMenuItem = {
let toggleView = NSHostingView(rootView: MenuItemToggleView(tunnel: BurrowApp.tunnel))
let toggleView = NSHostingView(rootView: MenuItemToggleView())
toggleView.frame.size = CGSize(width: 300, height: 32)
toggleView.autoresizingMask = [.width]

View file

@ -1,63 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -1,21 +1,14 @@
#if !os(macOS)
import BurrowUI
import SwiftUI
@main
@MainActor
@main
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 {
WindowGroup {
TunnelView(tunnel: Self.tunnel)
BurrowView()
}
}
}
#endif

679
Apple/App/MainMenu.xib Normal file
View file

@ -0,0 +1,679 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23091" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23091"/>
</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>

View file

@ -1,60 +0,0 @@
//
// 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
}
}
}
}

View file

@ -1,42 +0,0 @@
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"
}
}
}
}

View file

@ -1,146 +0,0 @@
import BurrowShared
import NetworkExtension
import SwiftUI
@Observable
class Tunnel {
private(set) var status: Status = .unknown
private var error: NEVPNError?
private let logger = Logger.logger(for: Tunnel.self)
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() {
guard let manager = managers?.first else { return }
manager.connection.stopVPNTunnel()
}
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
}
}
}

View file

@ -1,34 +0,0 @@
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() }
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,86 +1,123 @@
{
"originHash" : "fa512b990383b7e309c5854a5279817052294a8191a6d3c55c49cfb38e88c0c3",
"pins" : [
{
"identity" : "collectionconcurrencykit",
"identity" : "grpc-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
"location" : "https://github.com/grpc/grpc-swift.git",
"state" : {
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
"version" : "0.2.0"
"revision" : "6a90b7e77e29f9bda6c2b3a4165a40d6c02cfda1",
"version" : "1.23.0"
}
},
{
"identity" : "cryptoswift",
"identity" : "swift-async-algorithms",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"location" : "https://github.com/apple/swift-async-algorithms.git",
"state" : {
"revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c",
"version" : "1.8.1"
"revision" : "6ae9a051f76b81cc668305ceed5b0e0a7fd93d20",
"version" : "1.0.1"
}
},
{
"identity" : "sourcekitten",
"identity" : "swift-atomics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
"version" : "0.34.1"
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
"version" : "1.2.0"
}
},
{
"identity" : "swift-argument-parser",
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "fee6933f37fde9a5e12a1e4aeaa93fe60116ff2a",
"version" : "1.2.2"
"revision" : "9bf03ff58ce34478e66aaee630e491823326fd06",
"version" : "1.1.3"
}
},
{
"identity" : "swift-syntax",
"identity" : "swift-http-types",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"location" : "https://github.com/apple/swift-http-types",
"state" : {
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version" : "509.0.2"
"revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd",
"version" : "1.3.0"
}
},
{
"identity" : "swiftlint",
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/SwiftLint.git",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
"version" : "0.54.0"
"revision" : "9cb486020ebf03bfa5b5df985387a14a98744537",
"version" : "1.6.1"
}
},
{
"identity" : "swiftytexttable",
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
"version" : "0.9.0"
"revision" : "9746cf80e29edfef2a39924a66731249223f42a3",
"version" : "2.72.0"
}
},
{
"identity" : "swxmlhash",
"identity" : "swift-nio-extras",
"kind" : "remoteSourceControl",
"location" : "https://github.com/drmohundro/SWXMLHash.git",
"location" : "https://github.com/apple/swift-nio-extras.git",
"state" : {
"revision" : "4d0f62f561458cbe1f732171e625f03195151b60",
"version" : "7.0.1"
"revision" : "d1ead62745cc3269e482f1c51f27608057174379",
"version" : "1.24.0"
}
},
{
"identity" : "yams",
"identity" : "swift-nio-http2",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"location" : "https://github.com/apple/swift-nio-http2.git",
"state" : {
"revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3",
"version" : "5.0.6"
"revision" : "b5f7062b60e4add1e8c343ba4eb8da2e324b3a94",
"version" : "1.34.0"
}
},
{
"identity" : "swift-nio-ssl",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-ssl.git",
"state" : {
"revision" : "7b84abbdcef69cc3be6573ac12440220789dcd69",
"version" : "2.27.2"
}
},
{
"identity" : "swift-nio-transport-services",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-transport-services.git",
"state" : {
"revision" : "38ac8221dd20674682148d6451367f89c2652980",
"version" : "1.21.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "edb6ed4919f7756157fe02f2552b7e3850a538e5",
"version" : "1.28.1"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5",
"version" : "1.3.2"
}
}
],
"version" : 2
"version" : 3
}

View file

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
LastUpgradeVersion = "1600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View file

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
LastUpgradeVersion = "1600"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"

View file

@ -1,10 +1,8 @@
LD_EXPORT_SYMBOLS = NO
SKIP_INSTALL = NO
MERGED_BINARY_TYPE = manual
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor
ENABLE_PREVIEWS = YES

View file

@ -1,61 +1,44 @@
#include "Identity.xcconfig"
#include "Debug.xcconfig"
#include "Version.xcconfig"
SDKROOT = auto
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES
SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx
SWIFT_VERSION = 6.0
IPHONEOS_DEPLOYMENT_TARGET = 17.0
MACOSX_DEPLOYMENT_TARGET = 14.0
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO
SUPPORTS_MACCATALYST = NO
ALWAYS_SEARCH_USER_PATHS = NO
PRODUCT_NAME = $(TARGET_NAME:c99extidentifier)
PRODUCT_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).$(PRODUCT_NAME)
CURRENT_PROJECT_VERSION = 1
MARKETING_VERSION = 0.1
SKIP_INSTALL = YES
CODE_SIGN_IDENTITY = Apple Development
INFOPLIST_FILE = Configuration/Info.plist
GENERATE_INFOPLIST_FILE = YES
INFOPLIST_FILE = Configuration/Info.plist
INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023-2024 Hack Club
INFOPLIST_KEY_CFBundleDisplayName = Burrow
ENABLE_BITCODE = NO
ENABLE_APP_SANDBOX[sdk=macosx*] = YES
ENABLE_HARDENED_RUNTIME[sdk=macosx*] = YES
COMBINE_HIDPI_IMAGES = YES
COPY_PHASE_STRIP = NO
ENABLE_BITCODE = NO
ALWAYS_SEARCH_USER_PATHS = NO
COMBINE_HIDPI_IMAGES = YES
EAGER_LINKING = YES
FUSE_BUILD_SCRIPT_PHASES = YES
SWIFT_EMIT_LOC_STRINGS = YES
LOCALIZATION_PREFERS_STRING_CATALOGS = YES
ENABLE_DEBUG_DYLIB = NO
APP_GROUP_IDENTIFIER = group.$(APP_BUNDLE_IDENTIFIER)
APP_GROUP_IDENTIFIER[sdk=macosx*] = $(DEVELOPMENT_TEAM).$(APP_BUNDLE_IDENTIFIER)
NETWORK_EXTENSION_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).network
// Swift
SWIFT_VERSION = 5.0
SWIFT_EMIT_LOC_STRINGS = YES
// Release
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
SWIFT_COMPILATION_MODE = wholemodule
SWIFT_OPTIMIZATION_LEVEL = -Osize
LLVM_LTO = YES
DEAD_CODE_STRIPPING = YES
VALIDATE_PRODUCT = YES
// Debug
ONLY_ACTIVE_ARCH[config=Debug] = YES
DEBUG_INFORMATION_FORMAT[config=Debug] = dwarf
ENABLE_TESTABILITY[config=Debug] = YES
SWIFT_OPTIMIZATION_LEVEL[config=Debug] = -Onone
SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug] = DEBUG
SWIFT_COMPILATION_MODE[config=Debug] = singlefile
LLVM_LTO[config=Debug] = NO
DEAD_CODE_STRIPPING[config=Debug] = NO
VALIDATE_PRODUCT[config=Debug] = NO
// https://github.com/grpc/grpc-swift/issues/683#issuecomment-1130118953
OTHER_SWIFT_FLAGS = $(inherited) -Xcc -fmodule-map-file=$(GENERATED_MODULEMAP_DIR)/CNIOAtomics.modulemap -Xcc -fmodule-map-file=$(GENERATED_MODULEMAP_DIR)/CNIODarwin.modulemap -Xcc -fmodule-map-file=$(GENERATED_MODULEMAP_DIR)/CGRPCZlib.modulemap

View file

@ -0,0 +1,4 @@
#include "Framework.xcconfig"
SWIFT_INCLUDE_PATHS = $(PROJECT_DIR)/Configuration/Constants
GCC_PREPROCESSOR_DEFINITIONS = APP_BUNDLE_IDENTIFIER=$(APP_BUNDLE_IDENTIFIER) APP_GROUP_IDENTIFIER=$(APP_GROUP_IDENTIFIER) NETWORK_EXTENSION_BUNDLE_IDENTIFIER=$(NETWORK_EXTENSION_BUNDLE_IDENTIFIER)

View file

@ -7,5 +7,6 @@ NS_ASSUME_NONNULL_BEGIN
static NSString * const AppBundleIdentifier = MACRO_STRING(APP_BUNDLE_IDENTIFIER);
static NSString * const AppGroupIdentifier = MACRO_STRING(APP_GROUP_IDENTIFIER);
static NSString * const NetworkExtensionBundleIdentifier = MACRO_STRING(NETWORK_EXTENSION_BUNDLE_IDENTIFIER);
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,38 @@
@_implementationOnly import CConstants
import OSLog
public enum Constants {
enum Error: Swift.Error {
case invalidAppGroupIdentifier
}
public static let bundleIdentifier = AppBundleIdentifier
public static let appGroupIdentifier = AppGroupIdentifier
public static let networkExtensionBundleIdentifier = NetworkExtensionBundleIdentifier
public static var socketURL: URL {
get throws {
try groupContainerURL.appending(component: "burrow.sock", directoryHint: .notDirectory)
}
}
public static var databaseURL: URL {
get throws {
try groupContainerURL.appending(component: "burrow.db", directoryHint: .notDirectory)
}
}
private static var groupContainerURL: URL {
get throws { try _groupContainerURL.get() }
}
private static let _groupContainerURL: Result<URL, Error> = {
switch FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) {
case .some(let url): .success(url)
case .none: .failure(.invalidAppGroupIdentifier)
}
}()
}
extension Logger {
@_dynamicReplacement(for: subsystem)
public static var subsystem: String { Constants.bundleIdentifier }
}

View file

@ -1,4 +1,4 @@
module Constants {
module CConstants {
header "Constants.h"
export *
}

View file

@ -0,0 +1,26 @@
// Release
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
SWIFT_COMPILATION_MODE = wholemodule
SWIFT_OPTIMIZATION_LEVEL = -Osize
LLVM_LTO = YES
DEAD_CODE_STRIPPING = YES
STRIP_INSTALLED_PRODUCT = YES
STRIP_SWIFT_SYMBOLS = YES
COPY_PHASE_STRIP = NO
VALIDATE_PRODUCT = YES
ENABLE_MODULE_VERIFIER = YES
// Debug
ONLY_ACTIVE_ARCH[config=Debug] = YES
DEBUG_INFORMATION_FORMAT[config=Debug] = dwarf
ENABLE_TESTABILITY[config=Debug] = YES
GCC_PREPROCESSOR_DEFINITIONS[config=Debug] = DEBUG=1 $(inherited)
SWIFT_OPTIMIZATION_LEVEL[config=Debug] = -Onone
SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug] = DEBUG
SWIFT_COMPILATION_MODE[config=Debug] = singlefile
LLVM_LTO[config=Debug] = NO
DEAD_CODE_STRIPPING[config=Debug] = NO
VALIDATE_PRODUCT[config=Debug] = NO
STRIP_INSTALLED_PRODUCT[config=Debug] = NO
STRIP_SWIFT_SYMBOLS[config=Debug] = NO
ENABLE_MODULE_VERIFIER[config=Debug] = NO

View file

@ -1,4 +1,6 @@
MERGED_BINARY_TYPE = manual
LD_EXPORT_SYMBOLS = NO
OTHER_SWIFT_FLAGS = $(inherited) -Xfrontend -disable-autolink-framework -Xfrontend UIKit -Xfrontend -disable-autolink-framework -Xfrontend AppKit -Xfrontend -disable-autolink-framework -Xfrontend SwiftUI
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @executable_path/../../Frameworks
LD_RUNPATH_SEARCH_PATHS[sdk=macos*] = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks

View file

@ -0,0 +1,14 @@
PRODUCT_NAME = Burrow$(TARGET_NAME:c99extidentifier)
PRODUCT_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).$(TARGET_NAME:c99extidentifier)
APPLICATION_EXTENSION_API_ONLY = YES
SWIFT_INSTALL_OBJC_HEADER = NO
SWIFT_SKIP_AUTOLINKING_FRAMEWORKS = YES
SWIFT_SKIP_AUTOLINKING_LIBRARIES = YES
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks
DYLIB_INSTALL_NAME_BASE = @rpath
DYLIB_COMPATIBILITY_VERSION = 1
DYLIB_CURRENT_VERSION = 1
VERSIONING_SYSTEM =

View file

32
Apple/Core/Client.swift Normal file
View file

@ -0,0 +1,32 @@
import GRPC
import NIOTransportServices
public typealias TunnelClient = Burrow_TunnelAsyncClient
public typealias NetworksClient = Burrow_NetworksAsyncClient
public protocol Client {
init(channel: GRPCChannel)
}
extension Client {
public static func unix(socketURL: URL) -> Self {
let group = NIOTSEventLoopGroup()
let configuration = ClientConnection.Configuration.default(
target: .unixDomainSocket(socketURL.path),
eventLoopGroup: group
)
return Self(channel: ClientConnection(configuration: configuration))
}
}
extension TunnelClient: Client {
public init(channel: any GRPCChannel) {
self.init(channel: channel, defaultCallOptions: .init(), interceptors: .none)
}
}
extension NetworksClient: Client {
public init(channel: any GRPCChannel) {
self.init(channel: channel, defaultCallOptions: .init(), interceptors: .none)
}
}

View file

@ -0,0 +1 @@
../../../proto/burrow.proto

View file

@ -0,0 +1,11 @@
{
"invocations": [
{
"protoFiles": [
"burrow.proto",
],
"server": false,
"visibility": "public"
}
]
}

View file

@ -0,0 +1,10 @@
{
"invocations": [
{
"protoFiles": [
"burrow.proto",
],
"visibility": "public"
}
]
}

View file

@ -4,7 +4,7 @@ import os
extension Logger {
private static let loggers: OSAllocatedUnfairLock<[String: Logger]> = OSAllocatedUnfairLock(initialState: [:])
public static let subsystem = Constants.bundleIdentifier
public dynamic static var subsystem: String { "com.hackclub.burrow" }
public static func logger(for type: Any.Type) -> Logger {
let category = String(describing: type)

View file

@ -1,60 +0,0 @@
import BurrowShared
import Foundation
import Network
final class Client {
let connection: NWConnection
private let logger: Logger = Logger.logger(for: Client.self)
private var generator = SystemRandomNumberGenerator()
convenience init() throws {
self.init(url: try Constants.socketURL)
}
init(url: URL) {
let endpoint: NWEndpoint
if url.isFileURL {
endpoint = .unix(path: url.path(percentEncoded: false))
} else {
endpoint = .url(url)
}
let parameters = NWParameters.tcp
parameters.defaultProtocolStack
.applicationProtocols
.insert(NWProtocolFramer.Options(definition: NewlineProtocolFramer.definition), at: 0)
connection = NWConnection(to: endpoint, using: parameters)
connection.start(queue: .global())
}
func request<U: Decodable>(_ request: any Request, type: U.Type = U.self) async throws -> U {
do {
var copy = request
copy.id = generator.next(upperBound: UInt.max)
let content = try JSONEncoder().encode(copy)
logger.debug("> \(String(decoding: content, as: UTF8.self))")
try await self.connection.send(content: content)
let (response, _, _) = try await connection.receiveMessage()
logger.debug("< \(String(decoding: response, as: UTF8.self))")
return try JSONDecoder().decode(U.self, from: response)
} catch {
logger.error("\(error, privacy: .public)")
throw error
}
}
deinit {
connection.cancel()
}
}
extension Constants {
static var socketURL: URL {
get throws {
try groupContainerURL.appending(component: "burrow.sock", directoryHint: .notDirectory)
}
}
}

View file

@ -1,61 +0,0 @@
import Foundation
// swiftlint:disable identifier_name
enum BurrowError: Error {
case addrDoesntExist
case resultIsError
case cantParseResult
case resultIsNone
}
protocol Request: Codable where Command: Codable {
associatedtype Command
var id: UInt { get set }
var command: Command { get set }
}
struct BurrowSingleCommand: Request {
var id: UInt
var command: String
}
struct BurrowRequest<T>: Request where T: Codable {
var id: UInt
var command: T
}
struct BurrowStartRequest: Codable {
struct TunOptions: Codable {
let name: String?
let no_pi: Bool
let tun_excl: Bool
let tun_retrieve: Bool
let address: String?
}
struct StartOptions: Codable {
let tun: TunOptions
}
let Start: StartOptions
}
struct Response<T>: Decodable where T: Decodable {
var id: UInt
var result: T
}
struct BurrowResult<T>: Codable where T: Codable {
var Ok: T?
var Err: String?
}
struct ServerConfigData: Codable {
struct InternalConfig: Codable {
let address: String?
let name: String?
let mtu: Int32?
}
let ServerConfig: InternalConfig
}
// swiftlint:enable identifier_name

View file

@ -1,32 +0,0 @@
import Foundation
import Network
extension NWConnection {
// swiftlint:disable:next large_tuple
func receiveMessage() async throws -> (Data, NWConnection.ContentContext?, Bool) {
try await withUnsafeThrowingContinuation { continuation in
receiveMessage { completeContent, contentContext, isComplete, error in
if let error {
continuation.resume(throwing: error)
} else {
guard let completeContent = completeContent else {
fatalError("Both error and completeContent were nil")
}
continuation.resume(returning: (completeContent, contentContext, isComplete))
}
}
}
}
func send(content: Data) async throws {
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
send(content: content, completion: .contentProcessed { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: ())
}
})
}
}
}

View file

@ -1,54 +0,0 @@
import Foundation
import Network
final class NewlineProtocolFramer: NWProtocolFramerImplementation {
private static let delimeter: UInt8 = 10 // `\n`
static let definition = NWProtocolFramer.Definition(implementation: NewlineProtocolFramer.self)
static let label = "Lines"
init(framer: NWProtocolFramer.Instance) { }
func start(framer: NWProtocolFramer.Instance) -> NWProtocolFramer.StartResult { .ready }
func stop(framer: NWProtocolFramer.Instance) -> Bool { true }
func wakeup(framer: NWProtocolFramer.Instance) { }
func cleanup(framer: NWProtocolFramer.Instance) { }
func handleInput(framer: NWProtocolFramer.Instance) -> Int {
while true {
var result: [Data] = []
let parsed = framer.parseInput(minimumIncompleteLength: 1, maximumLength: 16_000) { buffer, _ in
guard let buffer else { return 0 }
var lines = buffer
.split(separator: Self.delimeter, omittingEmptySubsequences: false)
.map { Data($0) }
guard lines.count > 1 else { return 0 }
_ = lines.popLast()
result = lines
return lines.reduce(lines.count) { $0 + $1.count }
}
guard parsed && !result.isEmpty else { break }
for line in result {
framer.deliverInput(data: line, message: .init(instance: framer), isComplete: true)
}
}
return 0
}
func handleOutput(
framer: NWProtocolFramer.Instance,
message: NWProtocolFramer.Message,
messageLength: Int,
isComplete: Bool
) {
do {
try framer.writeOutputNoCopy(length: messageLength)
framer.writeOutput(data: [Self.delimeter])
} catch {
}
}
}

View file

@ -1,58 +1,74 @@
import BurrowShared
import AsyncAlgorithms
import BurrowConfiguration
import BurrowCore
import libburrow
import NetworkExtension
import os
class PacketTunnelProvider: NEPacketTunnelProvider {
enum Error: Swift.Error {
case missingTunnelConfiguration
}
private let logger = Logger.logger(for: PacketTunnelProvider.self)
private var client: TunnelClient {
get throws { try _client.get() }
}
private let _client: Result<TunnelClient, Swift.Error> = Result {
try TunnelClient.unix(socketURL: Constants.socketURL)
}
override init() {
do {
libburrow.spawnInProcess(
socketPath: try Constants.socketURL.path(percentEncoded: false),
databasePath: try Constants.databaseURL.path(percentEncoded: false)
)
} catch {
logger.error("Failed to spawn networking thread: \(error)")
}
}
override func startTunnel(options: [String: NSObject]? = nil) async throws {
do {
libburrow.spawnInProcess(socketPath: try Constants.socketURL.path)
let client = try Client()
let command = BurrowRequest(id: 0, command: "ServerConfig")
let data = try await client.request(command, type: Response<BurrowResult<ServerConfigData>>.self)
let encoded = try JSONEncoder().encode(data.result)
self.logger.log("Received final data: \(String(decoding: encoded, as: UTF8.self))")
guard let serverconfig = data.result.Ok else {
throw BurrowError.resultIsError
let configuration = try await Array(client.tunnelConfiguration(.init()).prefix(1)).first
guard let settings = configuration?.settings else {
throw Error.missingTunnelConfiguration
}
guard let tunNs = generateTunSettings(from: serverconfig) else {
throw BurrowError.addrDoesntExist
}
try await self.setTunnelNetworkSettings(tunNs)
self.logger.info("Set remote tunnel address to \(tunNs.tunnelRemoteAddress)")
let startRequest = BurrowRequest(
id: .random(in: (.min)..<(.max)),
command: BurrowStartRequest(
Start: BurrowStartRequest.StartOptions(
tun: BurrowStartRequest.TunOptions(
name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: nil
)
)
)
)
let response = try await client.request(startRequest, type: Response<BurrowResult<String>>.self)
self.logger.log("Received start server response: \(String(describing: response.result))")
try await setTunnelNetworkSettings(settings)
_ = try await client.tunnelStart(.init())
logger.log("Started tunnel with network settings: \(settings)")
} catch {
self.logger.error("Failed to start tunnel: \(error)")
logger.error("Failed to start tunnel: \(error)")
throw error
}
}
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
let cfig = from.ServerConfig
guard let addr = cfig.address else {
return nil
override func stopTunnel(with reason: NEProviderStopReason) async {
do {
_ = try await client.tunnelStop(.init())
logger.log("Stopped client")
} catch {
logger.error("Failed to stop tunnel: \(error)")
}
// Using a makeshift remote tunnel address
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
nst.ipv4Settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"])
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
return nst
}
}
extension Burrow_TunnelConfigurationResponse {
fileprivate var settings: NEPacketTunnelNetworkSettings {
let ipv6Addresses = addresses.filter { IPv6Address($0) != nil }
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
settings.mtu = NSNumber(value: mtu)
settings.ipv4Settings = NEIPv4Settings(
addresses: addresses.filter { IPv4Address($0) != nil },
subnetMasks: ["255.255.255.0"]
)
settings.ipv6Settings = NEIPv6Settings(
addresses: ipv6Addresses,
networkPrefixLengths: ipv6Addresses.map { _ in 64 }
)
return settings
}
}

View file

@ -56,10 +56,10 @@ CARGO_ARGS+=("--lib")
# Pass the configuration (Debug or Release) through to cargo
if [[ $SWIFT_ACTIVE_COMPILATION_CONDITIONS == *DEBUG* ]]; then
CARGO_DIR="debug"
CARGO_TARGET_SUBDIR="debug"
else
CARGO_ARGS+=("--release")
CARGO_DIR="release"
CARGO_TARGET_SUBDIR="release"
fi
if [[ -x "$(command -v rustup)" ]]; then
@ -68,13 +68,16 @@ else
CARGO_PATH="$(dirname $(readlink -f $(which cargo))):/usr/bin"
fi
PROTOC=$(readlink -f $(which protoc))
CARGO_PATH="$(dirname $PROTOC):$CARGO_PATH"
# Run cargo without the various environment variables set by Xcode.
# Those variables can confuse cargo and the build scripts it runs.
env -i PATH="$CARGO_PATH" cargo build "${CARGO_ARGS[@]}"
env -i PATH="$CARGO_PATH" PROTOC="$PROTOC" CARGO_TARGET_DIR="${CONFIGURATION_TEMP_DIR}/target" IPHONEOS_DEPLOYMENT_TARGET="$IPHONEOS_DEPLOYMENT_TARGET" MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" cargo build "${CARGO_ARGS[@]}"
mkdir -p "${BUILT_PRODUCTS_DIR}"
# Use `lipo` to merge the architectures together into BUILT_PRODUCTS_DIR
/usr/bin/xcrun --sdk $PLATFORM_NAME lipo \
-create $(printf "${PROJECT_DIR}/../target/%q/${CARGO_DIR}/libburrow.a " "${RUST_TARGETS[@]}") \
-create $(printf "${CONFIGURATION_TEMP_DIR}/target/%q/${CARGO_TARGET_SUBDIR}/libburrow.a " "${RUST_TARGETS[@]}") \
-output "${BUILT_PRODUCTS_DIR}/libburrow.a"

View file

@ -1,2 +1,2 @@
__attribute__((__swift_name__("spawnInProcess(socketPath:)")))
extern void spawn_in_process(const char * __nullable path);
__attribute__((__swift_name__("spawnInProcess(socketPath:databasePath:)")))
extern void spawn_in_process(const char * __nullable socket_path, const char * __nullable db_path);

Binary file not shown.

View file

@ -1,22 +0,0 @@
@_implementationOnly import Constants
public enum Constants {
enum Error: Swift.Error {
case invalidAppGroupIdentifier
}
public static let bundleIdentifier = AppBundleIdentifier
public static let appGroupIdentifier = AppGroupIdentifier
public static var groupContainerURL: URL {
get throws { try _groupContainerURL.get() }
}
private static let _groupContainerURL: Result<URL, Error> = {
guard let groupContainerURL = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) else {
return .failure(.invalidAppGroupIdentifier)
}
return .success(groupContainerURL)
}()
}

View file

@ -1,5 +0,0 @@
PRODUCT_NAME = BurrowShared
MERGEABLE_LIBRARY = YES
SWIFT_INCLUDE_PATHS = $(PROJECT_DIR)/Shared/Constants
GCC_PREPROCESSOR_DEFINITIONS = APP_BUNDLE_IDENTIFIER=$(APP_BUNDLE_IDENTIFIER) APP_GROUP_IDENTIFIER=$(APP_GROUP_IDENTIFIER)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -0,0 +1,344 @@
{
"images" : [
{
"filename" : "40.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "60.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "29.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "58.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "87.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "80.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "120.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "57.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "57x57"
},
{
"filename" : "114.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "57x57"
},
{
"filename" : "120.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "180.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "20.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "40.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "29.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "58.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "40.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "80.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "50.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "50x50"
},
{
"filename" : "100.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "50x50"
},
{
"filename" : "72.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "72x72"
},
{
"filename" : "144.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "72x72"
},
{
"filename" : "76.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "152.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "167.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "1024.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
},
{
"filename" : "16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "32.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "64.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "256.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "512.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "1024.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
},
{
"filename" : "48.png",
"idiom" : "watch",
"role" : "notificationCenter",
"scale" : "2x",
"size" : "24x24",
"subtype" : "38mm"
},
{
"filename" : "55.png",
"idiom" : "watch",
"role" : "notificationCenter",
"scale" : "2x",
"size" : "27.5x27.5",
"subtype" : "42mm"
},
{
"filename" : "58.png",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "87.png",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "watch",
"role" : "notificationCenter",
"scale" : "2x",
"size" : "33x33",
"subtype" : "45mm"
},
{
"filename" : "80.png",
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "40x40",
"subtype" : "38mm"
},
{
"filename" : "88.png",
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "44x44",
"subtype" : "40mm"
},
{
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "46x46",
"subtype" : "41mm"
},
{
"filename" : "100.png",
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "50x50",
"subtype" : "44mm"
},
{
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "51x51",
"subtype" : "45mm"
},
{
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "54x54",
"subtype" : "49mm"
},
{
"filename" : "172.png",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "86x86",
"subtype" : "38mm"
},
{
"filename" : "196.png",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "98x98",
"subtype" : "42mm"
},
{
"filename" : "216.png",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "108x108",
"subtype" : "44mm"
},
{
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "117x117",
"subtype" : "45mm"
},
{
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "129x129",
"subtype" : "49mm"
},
{
"filename" : "1024.png",
"idiom" : "watch-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x50",
"green" : "0x37",
"red" : "0xEC"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "flag-standalone-wtransparent.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x1A",
"green" : "0x17",
"red" : "0x88"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Some files were not shown because too many files have changed in this diff Show more