mirror of
https://github.com/usestrix/firewall.git
synced 2026-11-09 05:19:35 -10:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c763b5e1ca | ||
|
|
efde5d935f | ||
|
|
0c2d1319fd | ||
|
|
0bc3b0c87a | ||
|
|
7c6bd72767 | ||
|
|
c94d982d1a | ||
|
|
eaefe102d4 | ||
|
|
56d34dae15 | ||
|
|
2c5bb47251 |
No files matched your search
@@ -0,0 +1,3 @@
|
||||
- name: Set the telemetry key
|
||||
shell: bash
|
||||
run: echo "FIREWALL_POSTHOG_KEY=${{ secrets.FIREWALL_POSTHOG_KEY }}" >> "$GITHUB_ENV"
|
||||
@@ -13,6 +13,7 @@ jobs:
|
||||
env:
|
||||
TEAM: ${{ vars.APPLE_TEAM }}
|
||||
NOTARY_PROFILE: firewall
|
||||
FIREWALL_POSTHOG_KEY: ${{ secrets.FIREWALL_POSTHOG_KEY }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Rewrite release notes
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
plan:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
notes:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ fromJson(inputs.plan).announcement_tag }}
|
||||
steps:
|
||||
- run: |
|
||||
url="https://github.com/${{ github.repository }}/releases/download/$TAG"
|
||||
cat > notes.md <<NOTES
|
||||
## macOS
|
||||
|
||||
[Firewall.pkg]($url/Firewall.pkg)
|
||||
|
||||
## Windows
|
||||
|
||||
[strix-firewall-x86_64-pc-windows-msvc.msi]($url/strix-firewall-x86_64-pc-windows-msvc.msi)
|
||||
|
||||
## Command line
|
||||
|
||||
\`\`\`sh
|
||||
cargo install strix-firewall
|
||||
\`\`\`
|
||||
|
||||
\`\`\`sh
|
||||
curl --proto '=https' --tlsv1.2 -LsSf $url/strix-firewall-installer.sh | sh
|
||||
\`\`\`
|
||||
|
||||
\`\`\`sh
|
||||
powershell -ExecutionPolicy Bypass -c "irm $url/strix-firewall-installer.ps1 | iex"
|
||||
\`\`\`
|
||||
NOTES
|
||||
gh release edit "$TAG" --repo "${{ github.repository }}" --notes-file notes.md
|
||||
@@ -127,6 +127,9 @@ jobs:
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
fi
|
||||
- name: "Set the telemetry key"
|
||||
run: "echo \"FIREWALL_POSTHOG_KEY=${{ secrets.FIREWALL_POSTHOG_KEY }}\" >> \"$GITHUB_ENV\""
|
||||
shell: "bash"
|
||||
- name: Install dist
|
||||
run: ${{ matrix.install_dist.run }}
|
||||
# Get the dist-manifest
|
||||
@@ -319,3 +322,12 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
custom-release-notes:
|
||||
needs:
|
||||
- plan
|
||||
- announce
|
||||
uses: ./.github/workflows/release-notes.yml
|
||||
with:
|
||||
plan: ${{ needs.plan.outputs.val }}
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,93 @@
|
||||
# Strix's Dependency Firewall
|
||||
|
||||
Stops malicious packages before they install. Built by [Strix](https://strix.ai/blog/firewall-announcement).
|
||||
|
||||
Screening runs on your device: downloads go straight to the registry, never through a Strix server.
|
||||
Each package's name and version are looked up [Strix's malicious-package blocklist](https://github.com/usestrix/firewall-blocklist), so installs are blocked system-wide *before* reaching your machine.
|
||||
|
||||
## Install
|
||||
|
||||
**Machine-wide**, from the [latest release](https://github.com/usestrix/firewall/releases/latest):
|
||||
|
||||
- macOS: open `Firewall.pkg`, then approve the extension when macOS asks.
|
||||
- Windows: run the `.msi` as an admin.
|
||||
|
||||
**Prefix-mode**
|
||||
|
||||
cargo:
|
||||
```sh
|
||||
cargo install strix-firewall
|
||||
```
|
||||
|
||||
curl:
|
||||
```sh
|
||||
curl -LsSf https://github.com/usestrix/firewall/releases/latest/download/strix-firewall-installer.sh | sh
|
||||
```
|
||||
|
||||
Powershell:
|
||||
```powershell
|
||||
powershell -c "irm https://github.com/usestrix/firewall/releases/latest/download/strix-firewall-installer.ps1 | iex"
|
||||
```
|
||||
|
||||
## Platforms
|
||||
|
||||
| | Machine-wide | Command prefix |
|
||||
|---|---|---|
|
||||
| macOS 13+ | ✅ Apple silicon or T2 chip | ✅ |
|
||||
| Windows 10/11, x86-64 | ✅ with a TPM 2.0 | ✅ |
|
||||
| Linux (glibc 2.35+), x86-64 or arm64 | 🚧 Coming Soon | ✅ |
|
||||
|
||||
## Supported registries
|
||||
|
||||
| Registry | Package managers |
|
||||
|---|---|
|
||||
| npm | npm, pnpm, bun |
|
||||
| PyPI | pip, uv, pdm, pipenv |
|
||||
| crates.io | cargo |
|
||||
| Go module proxy | go |
|
||||
| RubyGems | gem |
|
||||
|
||||
Mirrors of these, such as Artifactory or Nexus, can be added in via a config file.
|
||||
|
||||
## Features
|
||||
|
||||
- **Up-to-the-minute data:** Strix constantly monitors updates to top packages (covering 99% of installed packages) to scan for malware, and publishes the results. We also consult [OSSF's blocklist](https://github.com/ossf/malicious-packages) and [OSV](osv.dev), as well as other public reports. Updates take effect without any user action.
|
||||
- **Holds back new versions.** New packages are blocked by default, since malware is usually detected within a day. (Although this can be disabled, configured, and bypassed).
|
||||
- **Alerts you.** On macOS and Windows a popup names the blocked package and links its advisory.
|
||||
- **Two modes:**
|
||||
- **Machine-wide:** screens downloads from every app, across your entire machine.
|
||||
- **Command prefix:** e.g., `firewall npm install left-pad`, or create an alias with `alias npm='firewall npm`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Settings are in a `config.json`:
|
||||
|
||||
- Machine-wide: `/Library/Application Support/Firewall/` on macOS, `%ProgramData%\Strix Firewall\`
|
||||
on Windows. Only an admin can edit it; restart from the menu bar or tray to apply.
|
||||
- Command prefix: `~/.config/firewall/` on Linux, `~/Library/Application Support/com.usestrix.firewall/`
|
||||
on macOS, `%APPDATA%\usestrix\firewall\config\` on Windows.
|
||||
|
||||
```json
|
||||
{
|
||||
"min_age_hours": 48,
|
||||
"allow": { "npm": [{ "name": "left-pad", "version": "1.3.0" }] },
|
||||
"registries": {
|
||||
"npm": ["https://npm.example.com/"],
|
||||
"pypi": ["https://pypi.example.com/"]
|
||||
},
|
||||
"telemetry": false
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Default | |
|
||||
|---|---|---|
|
||||
| `min_age_hours` | `24` | How long new versions are held back. `0` turns this off. |
|
||||
| `allow` | none | Packages exempt from the hold, by ecosystem (`npm`, `pypi`, `cargo`, `gem`, `go`). Omit `version` for every version. Known malware is still blocked. |
|
||||
| `registries` | none | Mirrors, by the registry they copy (`npm`, `pypi`, `gem`, `go`, `cargo/index`). Both modes screen every mirror listed; command-prefix mode also downloads from the first one. |
|
||||
| `fail_open` | `true` | Allow a package when it can't be checked. |
|
||||
| `telemetry` | `true` | Log anonymized usage events to Strix. |
|
||||
| `port` | `8080` | Local port for command-prefix mode. |
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0. See [LICENSE](LICENSE).
|
||||
Generated
+1
-1
@@ -3393,7 +3393,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[package]]
|
||||
name = "strix-firewall"
|
||||
version = "0.1.0-rc.2"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"core-foundation 0.10.1",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "strix-firewall"
|
||||
version = "0.1.0-rc.2"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
authors = ["Strix"]
|
||||
|
||||
@@ -8,6 +8,9 @@ installers = ["shell", "powershell", "msi"]
|
||||
# core/wix/main.wxs is edited to install the service.
|
||||
allow-dirty = ["msi"]
|
||||
features = ["machine-wide"]
|
||||
source-tarball = false
|
||||
publish-jobs = ["./publish-crates"]
|
||||
post-announce-jobs = ["./release-notes"]
|
||||
global-artifacts-jobs = ["./build-macos-pkg"]
|
||||
github-build-setup = "../build-setup.yml"
|
||||
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
|
||||
@@ -33,12 +33,11 @@ enum SetupWindow {
|
||||
private struct MenuBarLabel: View {
|
||||
@ObservedObject var model: FirewallModel
|
||||
@Environment(\.openWindow) private var openWindow
|
||||
@State private var raised = false
|
||||
|
||||
var body: some View {
|
||||
Image(nsImage: Self.icon).onAppear {
|
||||
guard !raised, !model.screening else { return }
|
||||
raised = true
|
||||
Image(nsImage: Self.icon).task {
|
||||
await model.refresh()
|
||||
guard !model.configured else { return }
|
||||
SetupWindow.open(openWindow)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import AppKit
|
||||
import NetworkExtension
|
||||
import OSLog
|
||||
import Security
|
||||
import ServiceManagement
|
||||
import SystemExtensions
|
||||
|
||||
enum StepStatus: Equatable {
|
||||
@@ -71,9 +72,8 @@ final class FirewallModel: NSObject, ObservableObject {
|
||||
let running = connection.status == .connected
|
||||
Task { @MainActor in self?.screening = running }
|
||||
}
|
||||
Task {
|
||||
await refresh()
|
||||
if CommandLine.arguments.contains("--install") { await install() }
|
||||
if CommandLine.arguments.contains("--install") {
|
||||
Task { await install() }
|
||||
}
|
||||
Task { await watchBlocks() }
|
||||
}
|
||||
@@ -83,6 +83,10 @@ final class FirewallModel: NSObject, ObservableObject {
|
||||
func refresh() async {
|
||||
if let manager = try? await loadManager() {
|
||||
watched = manager
|
||||
// Nothing starts the tunnel at boot, so the app does once it is set up and not paused.
|
||||
if manager.isEnabled && manager.connection.status == .disconnected {
|
||||
try? manager.connection.startVPNTunnel()
|
||||
}
|
||||
if manager.isEnabled {
|
||||
screeningStep = .done("Enabled (\(manager.connection.status.label))")
|
||||
}
|
||||
@@ -116,6 +120,11 @@ final class FirewallModel: NSObject, ObservableObject {
|
||||
work: trustCertificateAuthority)
|
||||
else { return }
|
||||
|
||||
do {
|
||||
try SMAppService.mainApp.register()
|
||||
} catch {
|
||||
log("Could not open the app at login: \(error.localizedDescription)")
|
||||
}
|
||||
completed = true
|
||||
log("Setup complete")
|
||||
offerRestart()
|
||||
@@ -156,6 +165,7 @@ final class FirewallModel: NSObject, ObservableObject {
|
||||
await removeConfiguration()
|
||||
let strandedKey = removeStoredCA()
|
||||
await deactivate()
|
||||
try? await SMAppService.mainApp.unregister()
|
||||
if let strandedKey { trustStep = .failed(strandedKey) }
|
||||
|
||||
let failed = [extensionStep, screeningStep, trustStep].contains(where: \.isFailed)
|
||||
@@ -230,7 +240,7 @@ final class FirewallModel: NSObject, ObservableObject {
|
||||
blocked.append(package)
|
||||
if let allowance = BlockAlert.show(package) { await allow(package, allowance) }
|
||||
}
|
||||
blocked = Array(blocked.suffix(10))
|
||||
if blocked.count > 10 { blocked.removeFirst(blocked.count - 10) }
|
||||
}
|
||||
try? await Task.sleep(nanoseconds: 500_000_000)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user