mirror of
https://github.com/safing/portmaster
synced 2025-09-01 10:09:11 +00:00
Merge pull request #1387 from safing/feature/windows-icons
Add windows icon support in core and more
This commit is contained in:
commit
ceaf1546d2
37 changed files with 536 additions and 310 deletions
72
.github/workflows/codeql-analysis.yml
vendored
72
.github/workflows/codeql-analysis.yml
vendored
|
@ -1,72 +0,0 @@
|
|||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "develop", master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "develop" ]
|
||||
schedule:
|
||||
- cron: '43 14 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
31
go.mod
31
go.mod
|
@ -4,6 +4,9 @@ go 1.21.1
|
|||
|
||||
toolchain go1.21.2
|
||||
|
||||
// TODO: Remove when https://github.com/tc-hib/winres/pull/4 is merged or changes are otherwise integrated.
|
||||
replace github.com/tc-hib/winres => github.com/dhaavi/winres v0.2.2
|
||||
|
||||
require (
|
||||
github.com/Xuanwo/go-locale v1.1.0
|
||||
github.com/agext/levenshtein v1.2.3
|
||||
|
@ -11,6 +14,7 @@ require (
|
|||
github.com/coreos/go-iptables v0.7.0
|
||||
github.com/florianl/go-conntrack v0.4.0
|
||||
github.com/florianl/go-nfqueue v1.3.1
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
|
@ -18,11 +22,12 @@ require (
|
|||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
github.com/jackc/puddle/v2 v2.2.1
|
||||
github.com/mat/besticon v3.12.0+incompatible
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/mitchellh/go-server-timing v1.0.1
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/safing/jess v0.3.2
|
||||
github.com/safing/portbase v0.18.6
|
||||
github.com/safing/portbase v0.18.7-0.20231218160927-7631b9d28afe
|
||||
github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec
|
||||
github.com/safing/spn v0.7.4
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
|
@ -30,15 +35,16 @@ require (
|
|||
github.com/spkg/zipfs v0.7.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tannerryan/ring v1.1.2
|
||||
github.com/tc-hib/winres v0.2.1
|
||||
github.com/tevino/abool v1.2.0
|
||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
|
||||
github.com/vincent-petithory/dataurl v1.0.0
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e
|
||||
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/sync v0.5.0
|
||||
golang.org/x/sys v0.15.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
zombiezen.com/go/sqlite v0.13.1
|
||||
zombiezen.com/go/sqlite v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -49,7 +55,7 @@ require (
|
|||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
github.com/awalterschulze/gographviz v2.0.3+incompatible // indirect
|
||||
github.com/bluele/gcache v0.0.2 // indirect
|
||||
github.com/danieljoos/wincred v1.2.0 // indirect
|
||||
github.com/danieljoos/wincred v1.2.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
|
@ -57,10 +63,11 @@ require (
|
|||
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
|
@ -72,6 +79,7 @@ require (
|
|||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
|
@ -84,8 +92,8 @@ require (
|
|||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||
github.com/valyala/fastrand v1.1.0 // indirect
|
||||
github.com/valyala/histogram v1.2.0 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
|
@ -95,14 +103,15 @@ require (
|
|||
github.com/zalando/go-keyring v0.2.3 // indirect
|
||||
go.etcd.io/bbolt v1.3.8 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/image v0.14.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20231130223849-479d60c2258b // indirect
|
||||
modernc.org/libc v1.34.11 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20231215062520-cd4a40b584a5 // indirect
|
||||
modernc.org/libc v1.37.5 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.7.2 // indirect
|
||||
modernc.org/sqlite v1.27.0 // indirect
|
||||
modernc.org/sqlite v1.28.0 // indirect
|
||||
)
|
||||
|
|
56
go.sum
56
go.sum
|
@ -33,8 +33,8 @@ github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1
|
|||
github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8=
|
||||
github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
|
||||
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
|
||||
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
|
||||
github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -42,6 +42,8 @@ github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x
|
|||
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dhaavi/winres v0.2.2 h1:SUago7FwhgLSMyDdeuV6enBZ+ZQSl0KwcnbWzvlfBls=
|
||||
github.com/dhaavi/winres v0.2.2/go.mod h1:1NTs+/DtKP1BplIL1+XQSoq4X1PUfLczexS7gf3x9T4=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8=
|
||||
|
@ -51,6 +53,8 @@ github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckR
|
|||
github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8=
|
||||
github.com/florianl/go-nfqueue v1.3.1 h1:khQ9fYCrjbu5CF8dZF55G2RTIEIQRI0Aj5k3msJR6Gw=
|
||||
github.com/florianl/go-nfqueue v1.3.1/go.mod h1:aHWbgkhryJxF5XxYvJ3oRZpdD4JP74Zu/hP1zuhja+M=
|
||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
||||
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
|
@ -70,6 +74,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
|||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
||||
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg=
|
||||
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4=
|
||||
|
@ -98,8 +104,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF
|
|||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
|
@ -145,6 +151,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mat/besticon v3.12.0+incompatible h1:1KTD6wisfjfnX+fk9Kx/6VEZL+MAW1LhCkL9Q47H9Bg=
|
||||
github.com/mat/besticon v3.12.0+incompatible/go.mod h1:mA1auQYHt6CW5e7L9HJLmqVQC8SzNk2gVwouO0AbiEU=
|
||||
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
|
@ -183,6 +191,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
|
|||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
|
@ -201,6 +211,8 @@ github.com/safing/jess v0.3.2 h1:d21+sautJlfTKcwgm6/TohUf0F8DL27Lug2XHBOBqvY=
|
|||
github.com/safing/jess v0.3.2/go.mod h1:N1Qiw9YBDHSVilocPEWHoGIEi+DvtmGds76rUhAyctU=
|
||||
github.com/safing/portbase v0.18.6 h1:uMZOG4C0K61QJE7I4fI+55r1I/eV42TJdI1xA02U1yo=
|
||||
github.com/safing/portbase v0.18.6/go.mod h1:qhhLjrr5iEGU9r7RZ6hJdtulOeycJ0d0jq95ZxGJ9Hs=
|
||||
github.com/safing/portbase v0.18.7-0.20231218160927-7631b9d28afe h1:JphzTgtBrWwdS4i8g8TJByv8fV1zDvsdh0irf5bx2uQ=
|
||||
github.com/safing/portbase v0.18.7-0.20231218160927-7631b9d28afe/go.mod h1:qhhLjrr5iEGU9r7RZ6hJdtulOeycJ0d0jq95ZxGJ9Hs=
|
||||
github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec h1:oSJY1seobofPwpMoJRkCgXnTwfiQWNfGMCPDfqgAEfg=
|
||||
github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE=
|
||||
github.com/safing/spn v0.7.4 h1:wAE17yWOgL/lEwluRXRj1gM08bhyg1f7GQHKuP3aNSw=
|
||||
|
@ -250,10 +262,10 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
||||
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
||||
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 h1:UFHFmFfixpmfRBcxuu+LA9l8MdURWVdVNUHxO5n1d2w=
|
||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26/go.mod h1:IGhd0qMDsUa9acVjsbsT7bu3ktadtGOHI79+idTew/M=
|
||||
github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=
|
||||
|
@ -282,8 +294,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
|
||||
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
||||
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
|
@ -353,8 +367,6 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -375,8 +387,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -396,17 +408,17 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20231130223849-479d60c2258b h1:fXhcWD4N2isj89cdDWZ6WttbixEyEaKisztUbShdhkw=
|
||||
gvisor.dev/gvisor v0.0.0-20231130223849-479d60c2258b/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
gvisor.dev/gvisor v0.0.0-20231215062520-cd4a40b584a5 h1:/tJBYxR5QOOgZxdn4Ug6ikzua1Brenl+ZEUZBjfuRJU=
|
||||
gvisor.dev/gvisor v0.0.0-20231215062520-cd4a40b584a5/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||
honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||
modernc.org/libc v1.34.11 h1:hQDcIUlSG4QAOkXCIQKkaAOV5ptXvkOx4ddbXzgW2JU=
|
||||
modernc.org/libc v1.34.11/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
||||
modernc.org/libc v1.37.5 h1:IDpTjKpyMYFenZ7DkOr6Jswhn79yxsXeWHi/4DaFDBA=
|
||||
modernc.org/libc v1.37.5/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
||||
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||
modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8=
|
||||
modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||
zombiezen.com/go/sqlite v0.13.1 h1:qDzxyWWmMtSSEH5qxamqBFmqA2BLSSbtODi3ojaE02o=
|
||||
zombiezen.com/go/sqlite v0.13.1/go.mod h1:Ht/5Rg3Ae2hoyh1I7gbWtWAl89CNocfqeb/aAMTkJr4=
|
||||
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
|
||||
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||
zombiezen.com/go/sqlite v1.0.0 h1:D2EvOZqumJBy+6t+0uNTTXnepUpB/pKG45op/UziI1o=
|
||||
zombiezen.com/go/sqlite v1.0.0/go.mod h1:Yx7FJ77tr7Ucwi5solhXAxpflyxk/BHNXArZ/JvDm60=
|
||||
|
|
|
@ -7,17 +7,11 @@ import (
|
|||
"io/fs"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/network/socket"
|
||||
)
|
||||
|
||||
var (
|
||||
baseWaitTime = 3 * time.Millisecond
|
||||
lookupRetries = 3
|
||||
)
|
||||
|
||||
// GetPID returns the already existing pid of the given socket info or searches for it.
|
||||
// This also acts as a getter for socket.Info.PID, as locking for that occurs here.
|
||||
func GetPID(socketInfo socket.Info) (pid int) {
|
||||
|
@ -43,60 +37,27 @@ func GetPID(socketInfo socket.Info) (pid int) {
|
|||
func findPID(uid, inode int) (pid int) {
|
||||
socketName := "socket:[" + strconv.Itoa(inode) + "]"
|
||||
|
||||
for i := 0; i <= lookupRetries; i++ {
|
||||
var pidsUpdated bool
|
||||
// Always update pid table (it has a call limiter anyway)
|
||||
updatePids()
|
||||
|
||||
// Get all pids for the given uid.
|
||||
pids, ok := getPidsByUser(uid)
|
||||
if !ok {
|
||||
// If we cannot find the uid in the map, update it.
|
||||
updatePids()
|
||||
pidsUpdated = true
|
||||
pids, ok = getPidsByUser(uid)
|
||||
}
|
||||
// Get all pids for the given uid.
|
||||
pids, ok := getPidsByUser(uid)
|
||||
if !ok {
|
||||
return socket.UndefinedProcessID
|
||||
}
|
||||
|
||||
// If we have found PIDs, search them.
|
||||
if ok {
|
||||
// Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to
|
||||
// be searched for.
|
||||
for i := len(pids) - 1; i >= 0; i-- {
|
||||
if findSocketFromPid(pids[i], socketName) {
|
||||
return pids[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we still cannot find our socket, and haven't yet updated the PID map,
|
||||
// do this and then check again immediately.
|
||||
if !pidsUpdated {
|
||||
updatePids()
|
||||
pids, ok = getPidsByUser(uid)
|
||||
if ok {
|
||||
// Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to
|
||||
// be searched for.
|
||||
for i := len(pids) - 1; i >= 0; i-- {
|
||||
if findSocketFromPid(pids[i], socketName) {
|
||||
return pids[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have updated the PID map, but still cannot find anything.
|
||||
// So, there is nothing we can do other than to wait a little for the kernel to
|
||||
// populate the information.
|
||||
|
||||
// Wait after each try, except for the last iteration
|
||||
if i < lookupRetries {
|
||||
// Wait in back-off fashion - with 3ms baseWaitTime: 3, 6, 9 - 18ms in total.
|
||||
time.Sleep(time.Duration(i+1) * baseWaitTime)
|
||||
// Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to
|
||||
// be searched for.
|
||||
for j := len(pids) - 1; j >= 0; j-- {
|
||||
if pidHasSocket(pids[j], socketName) {
|
||||
return pids[j]
|
||||
}
|
||||
}
|
||||
|
||||
return socket.UndefinedProcessID
|
||||
}
|
||||
|
||||
func findSocketFromPid(pid int, socketName string) bool {
|
||||
func pidHasSocket(pid int, socketName string) bool {
|
||||
socketBase := "/proc/" + strconv.Itoa(pid) + "/fd"
|
||||
entries := readDirNames(socketBase)
|
||||
if len(entries) == 0 {
|
||||
|
|
|
@ -28,6 +28,11 @@ var (
|
|||
ErrPIDNotFound = errors.New("could not find pid for socket inode")
|
||||
)
|
||||
|
||||
const (
|
||||
lookupTries = 5
|
||||
fastLookupTries = 2
|
||||
)
|
||||
|
||||
// Lookup looks for the given connection in the system state tables and returns the PID of the associated process and whether the connection is inbound.
|
||||
func Lookup(pktInfo *packet.Info, fast bool) (pid int, inbound bool, err error) {
|
||||
// auto-detect version
|
||||
|
|
|
@ -10,11 +10,6 @@ import (
|
|||
"github.com/safing/portmaster/network/socket"
|
||||
)
|
||||
|
||||
var (
|
||||
lookupTries = 20 // With a max wait of 5ms, this amounts to up to 100ms.
|
||||
fastLookupTries = 2
|
||||
)
|
||||
|
||||
func init() {
|
||||
// This increases performance on unsupported system.
|
||||
// It's not critical at all and does not break anything if it fails.
|
||||
|
|
|
@ -13,16 +13,14 @@ var (
|
|||
getUDP4Table = proc.GetUDP4Table
|
||||
getUDP6Table = proc.GetUDP6Table
|
||||
|
||||
lookupTries = 20 // With a max wait of 5ms, this amounts to up to 100ms.
|
||||
fastLookupTries = 2
|
||||
|
||||
baseWaitTime = 3 * time.Millisecond
|
||||
checkPIDTries = 5
|
||||
checkPIDBaseWaitTime = 5 * time.Millisecond
|
||||
)
|
||||
|
||||
// CheckPID checks the if socket info already has a PID and if not, tries to find it.
|
||||
// Depending on the OS, this might be a no-op.
|
||||
func CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool, err error) {
|
||||
for i := 1; i <= lookupTries; i++ {
|
||||
for i := 1; i <= checkPIDTries; i++ {
|
||||
// look for PID
|
||||
pid = proc.GetPID(socketInfo)
|
||||
if pid != socket.UndefinedProcessID {
|
||||
|
@ -31,10 +29,10 @@ func CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool,
|
|||
}
|
||||
|
||||
// every time, except for the last iteration
|
||||
if i < lookupTries {
|
||||
if i < checkPIDTries {
|
||||
// we found no PID, we could have been too fast, give the kernel some time to think
|
||||
// back off timer: with 3ms baseWaitTime: 3, 6, 9, 12, 15, 18, 21ms - 84ms in total
|
||||
time.Sleep(time.Duration(i+1) * baseWaitTime)
|
||||
// back off timer: with 5ms baseWaitTime: 5, 10, 15, 20, 25 - 75ms in total
|
||||
time.Sleep(time.Duration(i) * checkPIDBaseWaitTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,6 @@ var (
|
|||
getTCP6Table = iphelper.GetTCP6Table
|
||||
getUDP4Table = iphelper.GetUDP4Table
|
||||
getUDP6Table = iphelper.GetUDP6Table
|
||||
|
||||
// With a max wait of 5ms, this amounts to up to 25ms,
|
||||
// excluding potential data fetching time.
|
||||
// Measured on Windows: ~150ms
|
||||
lookupTries = 5
|
||||
|
||||
fastLookupTries = 2
|
||||
)
|
||||
|
||||
// CheckPID checks the if socket info already has a PID and if not, tries to find it.
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -124,7 +124,7 @@ func (h *AppImageHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
if tag, ok := p.GetTag(appImagePathTagKey); ok {
|
||||
return profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
Name: osdetail.GenerateBinaryNameFromPath(p.Path),
|
||||
Name: binmeta.GenerateBinaryNameFromPath(p.Path),
|
||||
PresentationPath: p.Path,
|
||||
UsePresentationPath: true,
|
||||
Fingerprints: []profile.Fingerprint{
|
||||
|
@ -141,7 +141,7 @@ func (h *AppImageHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
if tag, ok := p.GetTag(appImageMountIDTagKey); ok {
|
||||
return profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
Name: osdetail.GenerateBinaryNameFromPath(p.Path),
|
||||
Name: binmeta.GenerateBinaryNameFromPath(p.Path),
|
||||
PresentationPath: p.Path,
|
||||
UsePresentationPath: true,
|
||||
Fingerprints: []profile.Fingerprint{
|
||||
|
|
|
@ -3,9 +3,9 @@ package tags
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -69,7 +69,7 @@ func (h *flatpakHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
if tag, ok := p.GetTag(flatpakIDTagKey); ok {
|
||||
return profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
Name: osdetail.GenerateBinaryNameFromPath(p.Path),
|
||||
Name: binmeta.GenerateBinaryNameFromPath(p.Path),
|
||||
PresentationPath: p.Path,
|
||||
UsePresentationPath: true,
|
||||
Fingerprints: []profile.Fingerprint{
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
|
||||
"github.com/google/shlex"
|
||||
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -161,7 +161,7 @@ func (h *InterpHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
for _, ext := range it.Extensions {
|
||||
scriptName, _ = strings.CutSuffix(scriptName, ext)
|
||||
}
|
||||
scriptName = osdetail.GenerateBinaryNameFromPath(scriptName)
|
||||
scriptName = binmeta.GenerateBinaryNameFromPath(scriptName)
|
||||
|
||||
return profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
|
|
|
@ -3,9 +3,9 @@ package tags
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -117,7 +117,7 @@ func (h *SnapHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
|
||||
return profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
Name: osdetail.GenerateBinaryNameFromPath(tag.Value),
|
||||
Name: binmeta.GenerateBinaryNameFromPath(tag.Value),
|
||||
PresentationPath: p.Path,
|
||||
UsePresentationPath: hasVersion,
|
||||
Fingerprints: []profile.Fingerprint{
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -36,7 +36,7 @@ func (h *SVCHostTagHandler) Name() string {
|
|||
// of this handler.
|
||||
func (h *SVCHostTagHandler) TagDescriptions() []process.TagDescription {
|
||||
return []process.TagDescription{
|
||||
process.TagDescription{
|
||||
{
|
||||
ID: svchostTagKey,
|
||||
Name: "SvcHost Service Name",
|
||||
Description: "Name of a service running in svchost.exe as reported by Windows.",
|
||||
|
@ -86,10 +86,10 @@ func (h *SVCHostTagHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
// Create new profile based on tag.
|
||||
newProfile := profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
Name: "Windows Service: " + osdetail.GenerateBinaryNameFromPath(tag.Value),
|
||||
Name: "Windows Service: " + binmeta.GenerateBinaryNameFromPath(tag.Value),
|
||||
UsePresentationPath: false,
|
||||
Fingerprints: []profile.Fingerprint{
|
||||
profile.Fingerprint{
|
||||
{
|
||||
Type: profile.FingerprintTypeTagID,
|
||||
Key: tag.Key,
|
||||
Operation: profile.FingerprintOperationEqualsID,
|
||||
|
@ -99,9 +99,9 @@ func (h *SVCHostTagHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
})
|
||||
|
||||
// Load default icon for windows service.
|
||||
icon, err := icons.LoadAndSaveIcon(context.TODO(), `C:\Windows\System32\@WLOGO_48x48.png`)
|
||||
icon, err := binmeta.LoadAndSaveIcon(context.TODO(), `C:\Windows\System32\@WLOGO_48x48.png`)
|
||||
if err == nil {
|
||||
newProfile.Icons = []icons.Icon{*icon}
|
||||
newProfile.Icons = []binmeta.Icon{*icon}
|
||||
}
|
||||
|
||||
return newProfile
|
||||
|
|
|
@ -6,9 +6,9 @@ import (
|
|||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/utils"
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -101,7 +101,7 @@ func (h *WinStoreHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||
if tag, ok := p.GetTag(winStoreAppNameTagKey); ok {
|
||||
return profile.New(&profile.Profile{
|
||||
Source: profile.SourceLocal,
|
||||
Name: osdetail.GenerateBinaryNameFromPath(tag.Value),
|
||||
Name: binmeta.GenerateBinaryNameFromPath(tag.Value),
|
||||
PresentationPath: p.Path,
|
||||
UsePresentationPath: true,
|
||||
Fingerprints: []profile.Fingerprint{
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/safing/portbase/api"
|
||||
"github.com/safing/portbase/formats/dsd"
|
||||
"github.com/safing/portbase/utils"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func registerAPIEndpoints() error {
|
||||
|
@ -99,7 +99,7 @@ func handleGetProfileIcon(ar *api.Request) (data []byte, err error) {
|
|||
ext := filepath.Ext(name)
|
||||
|
||||
// Get profile icon.
|
||||
data, err = icons.GetProfileIcon(name)
|
||||
data, err = binmeta.GetProfileIcon(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ func handleUpdateProfileIcon(ar *api.Request) (any, error) {
|
|||
}
|
||||
|
||||
// Update profile icon.
|
||||
filename, err := icons.UpdateProfileIcon(ar.InputData, ext)
|
||||
filename, err := binmeta.UpdateProfileIcon(ar.InputData, ext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
32
profile/binmeta/convert.go
Normal file
32
profile/binmeta/convert.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package binmeta
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/png" // Register png support for image package
|
||||
|
||||
"github.com/fogleman/gg"
|
||||
_ "github.com/mat/besticon/ico" // Register ico support for image package
|
||||
)
|
||||
|
||||
// ConvertICOtoPNG converts a an .ico to a .png image.
|
||||
func ConvertICOtoPNG(ico []byte) (png []byte, err error) {
|
||||
// Decode the ICO.
|
||||
icon, _, err := image.Decode(bytes.NewReader(ico))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode ICO: %w", err)
|
||||
}
|
||||
|
||||
// Convert to raw image.
|
||||
img := gg.NewContextForImage(icon)
|
||||
|
||||
// Convert to PNG.
|
||||
imgBuf := &bytes.Buffer{}
|
||||
err = img.EncodePNG(imgBuf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encode PNG: %w", err)
|
||||
}
|
||||
|
||||
return imgBuf.Bytes(), nil
|
||||
}
|
10
profile/binmeta/find_default.go
Normal file
10
profile/binmeta/find_default.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
//go:build !linux && !windows
|
||||
|
||||
package binmeta
|
||||
|
||||
import "context"
|
||||
|
||||
// GetIconAndName returns zero values for unsupported platforms.
|
||||
func GetIconAndName(ctx context.Context, binPath string, homeDir string) (icon *Icon, name string, err error) {
|
||||
return nil, "", nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package icons
|
||||
package binmeta
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -9,36 +9,46 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// FindIcon finds an icon for the given binary name.
|
||||
// Providing the home directory of the user running the process of that binary can help find an icon.
|
||||
func FindIcon(ctx context.Context, binName string, homeDir string) (*Icon, error) {
|
||||
// GetIconAndName returns an icon and name of the given binary path.
|
||||
// Providing the home directory of the user running the process of that binary can improve results.
|
||||
// Even if an error is returned, the other return values are valid, if set.
|
||||
func GetIconAndName(ctx context.Context, binPath string, homeDir string) (icon *Icon, name string, err error) {
|
||||
// Derive name from binary.
|
||||
name = GenerateBinaryNameFromPath(binPath)
|
||||
|
||||
// Search for icon.
|
||||
iconPath, err := search(binName, homeDir)
|
||||
iconPath, err := searchForIcon(binPath, homeDir)
|
||||
if iconPath == "" {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find icon for %s: %w", binName, err)
|
||||
return nil, name, fmt.Errorf("failed to find icon for %s: %w", binPath, err)
|
||||
}
|
||||
return nil, nil
|
||||
return nil, name, nil
|
||||
}
|
||||
|
||||
return LoadAndSaveIcon(ctx, iconPath)
|
||||
// Save icon to internal storage.
|
||||
icon, err = LoadAndSaveIcon(ctx, iconPath)
|
||||
if err != nil {
|
||||
return nil, name, fmt.Errorf("failed to store icon for %s: %w", binPath, err)
|
||||
}
|
||||
|
||||
return icon, name, nil
|
||||
}
|
||||
|
||||
func search(binName string, homeDir string) (iconPath string, err error) {
|
||||
binName = strings.ToLower(binName)
|
||||
func searchForIcon(binPath string, homeDir string) (iconPath string, err error) {
|
||||
binPath = strings.ToLower(binPath)
|
||||
|
||||
// Search for icon path.
|
||||
for _, iconLoc := range iconLocations {
|
||||
basePath := iconLoc.GetPath(binName, homeDir)
|
||||
basePath := iconLoc.GetPath(binPath, homeDir)
|
||||
if basePath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch iconLoc.Type {
|
||||
case FlatDir:
|
||||
iconPath, err = searchDirectory(basePath, binName)
|
||||
iconPath, err = searchDirectory(basePath, binPath)
|
||||
case XDGIcons:
|
||||
iconPath, err = searchXDGIconStructure(basePath, binName)
|
||||
iconPath, err = searchXDGIconStructure(basePath, binPath)
|
||||
}
|
||||
|
||||
if iconPath != "" {
|
||||
|
@ -48,10 +58,10 @@ func search(binName string, homeDir string) (iconPath string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func searchXDGIconStructure(baseDirectory string, binName string) (iconPath string, err error) {
|
||||
func searchXDGIconStructure(baseDirectory string, binPath string) (iconPath string, err error) {
|
||||
for _, xdgIconDir := range xdgIconPaths {
|
||||
directory := filepath.Join(baseDirectory, xdgIconDir)
|
||||
iconPath, err = searchDirectory(directory, binName)
|
||||
iconPath, err = searchDirectory(directory, binPath)
|
||||
if iconPath != "" {
|
||||
return
|
||||
}
|
||||
|
@ -59,7 +69,7 @@ func searchXDGIconStructure(baseDirectory string, binName string) (iconPath stri
|
|||
return
|
||||
}
|
||||
|
||||
func searchDirectory(directory string, binName string) (iconPath string, err error) {
|
||||
func searchDirectory(directory string, binPath string) (iconPath string, err error) {
|
||||
entries, err := os.ReadDir(directory)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
|
@ -82,13 +92,13 @@ func searchDirectory(directory string, binName string) (iconPath string, err err
|
|||
iconName := strings.ToLower(entry.Name())
|
||||
iconName = strings.TrimSuffix(iconName, filepath.Ext(iconName))
|
||||
switch {
|
||||
case len(iconName) < len(binName):
|
||||
case len(iconName) < len(binPath):
|
||||
// Continue to next.
|
||||
case iconName == binName:
|
||||
case iconName == binPath:
|
||||
// Exact match, return immediately.
|
||||
return filepath.Join(directory, entry.Name()), nil
|
||||
case strings.HasPrefix(iconName, binName):
|
||||
excessChars := len(iconName) - len(binName)
|
||||
case strings.HasPrefix(iconName, binPath):
|
||||
excessChars := len(iconName) - len(binPath)
|
||||
if bestMatch == "" || excessChars < bestMatchExcessChars {
|
||||
bestMatch = entry.Name()
|
||||
bestMatchExcessChars = excessChars
|
|
@ -1,4 +1,4 @@
|
|||
package icons
|
||||
package binmeta
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
@ -19,7 +19,7 @@ func TestFindIcon(t *testing.T) {
|
|||
func testFindIcon(t *testing.T, binName string, homeDir string) {
|
||||
t.Helper()
|
||||
|
||||
iconPath, err := search(binName, homeDir)
|
||||
iconPath, err := searchForIcon(binName, homeDir)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
115
profile/binmeta/find_windows.go
Normal file
115
profile/binmeta/find_windows.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
package binmeta
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/tc-hib/winres"
|
||||
"github.com/tc-hib/winres/version"
|
||||
)
|
||||
|
||||
// GetIconAndName returns an icon and name of the given binary path.
|
||||
// Providing the home directory of the user running the process of that binary can improve results.
|
||||
// Even if an error is returned, the other return values are valid, if set.
|
||||
func GetIconAndName(ctx context.Context, binPath string, homeDir string) (icon *Icon, name string, err error) {
|
||||
// Get name and png from exe.
|
||||
png, name, err := getIconAndNamefromRSS(ctx, binPath)
|
||||
|
||||
// Fall back to name generation if name is not set.
|
||||
if name == "" {
|
||||
name = GenerateBinaryNameFromPath(binPath)
|
||||
}
|
||||
|
||||
// Handle previous error.
|
||||
if err != nil {
|
||||
return nil, name, err
|
||||
}
|
||||
|
||||
// Update profile icon and return icon object.
|
||||
filename, err := UpdateProfileIcon(png, "png")
|
||||
if err != nil {
|
||||
return nil, name, fmt.Errorf("failed to store icon: %w", err)
|
||||
}
|
||||
|
||||
return &Icon{
|
||||
Type: IconTypeAPI,
|
||||
Value: filename,
|
||||
}, name, nil
|
||||
}
|
||||
|
||||
func getIconAndNamefromRSS(ctx context.Context, binPath string) (png []byte, name string, err error) {
|
||||
// Open .exe file.
|
||||
exeFile, err := os.Open(binPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil, "", nil
|
||||
}
|
||||
return nil, "", fmt.Errorf("failed to open exe %s to get icon: %w", binPath, err)
|
||||
}
|
||||
defer exeFile.Close() //nolint:errcheck
|
||||
|
||||
// Load .exe resources.
|
||||
rss, err := winres.LoadFromEXE(exeFile)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to get rss: %w", err)
|
||||
}
|
||||
|
||||
// DEBUG: Print all available resources:
|
||||
// rss.Walk(func(typeID, resID winres.Identifier, langID uint16, data []byte) bool {
|
||||
// fmt.Printf("typeID=%d resID=%d langID=%d\n", typeID, resID, langID)
|
||||
// return true
|
||||
// })
|
||||
|
||||
// Get first icon.
|
||||
var (
|
||||
icon *winres.Icon
|
||||
iconErr error
|
||||
)
|
||||
rss.WalkType(winres.RT_GROUP_ICON, func(resID winres.Identifier, langID uint16, _ []byte) bool {
|
||||
icon, iconErr = rss.GetIconTranslation(resID, langID)
|
||||
return iconErr != nil
|
||||
})
|
||||
if iconErr != nil {
|
||||
return nil, "", fmt.Errorf("failed to get icon: %w", err)
|
||||
}
|
||||
// Convert icon.
|
||||
icoBuf := &bytes.Buffer{}
|
||||
err = icon.SaveICO(icoBuf)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to save ico: %w", err)
|
||||
}
|
||||
png, err = ConvertICOtoPNG(icoBuf.Bytes())
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to convert ico to png: %w", err)
|
||||
}
|
||||
|
||||
// Get name from version record.
|
||||
var (
|
||||
versionInfo *version.Info
|
||||
versionInfoErr error
|
||||
)
|
||||
rss.WalkType(winres.RT_VERSION, func(resID winres.Identifier, langID uint16, data []byte) bool {
|
||||
versionInfo, versionInfoErr = version.FromBytes(data)
|
||||
switch {
|
||||
case versionInfoErr != nil:
|
||||
return true
|
||||
case versionInfo == nil:
|
||||
return true
|
||||
}
|
||||
|
||||
// Get metadata table and main language.
|
||||
table := versionInfo.Table().GetMainTranslation()
|
||||
if table == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
name = table[version.ProductName]
|
||||
return name == ""
|
||||
})
|
||||
name = cleanFileDescription(name)
|
||||
|
||||
return png, name, nil
|
||||
}
|
27
profile/binmeta/find_windows_test.go
Normal file
27
profile/binmeta/find_windows_test.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package binmeta
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFindIcon(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("test meant for compiling and running on desktop")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
binName := os.Args[len(os.Args)-1]
|
||||
t.Logf("getting name and icon for %s", binName)
|
||||
png, name, err := getIconAndNamefromRSS(context.Background(), binName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("name: %s", name)
|
||||
err = os.WriteFile("icon.png", png, 0o0600)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package icons
|
||||
package binmeta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -42,8 +42,8 @@ func (t IconType) sortOrder() int {
|
|||
}
|
||||
}
|
||||
|
||||
// SortAndCompact sorts and compacts a list of icons.
|
||||
func SortAndCompact(icons []Icon) []Icon {
|
||||
// SortAndCompactIcons sorts and compacts a list of icons.
|
||||
func SortAndCompactIcons(icons []Icon) []Icon {
|
||||
// Sort.
|
||||
slices.SortFunc[[]Icon, Icon](icons, func(a, b Icon) int {
|
||||
aOrder := a.Type.sortOrder()
|
|
@ -1,4 +1,4 @@
|
|||
package icons
|
||||
package binmeta
|
||||
|
||||
import (
|
||||
"context"
|
|
@ -1,4 +1,4 @@
|
|||
package icons
|
||||
package binmeta
|
||||
|
||||
import (
|
||||
"fmt"
|
121
profile/binmeta/name.go
Normal file
121
profile/binmeta/name.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package binmeta
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
segmentsSplitter = regexp.MustCompile("[^A-Za-z0-9]*[A-Z]?[a-z0-9]*")
|
||||
nameOnly = regexp.MustCompile("^[A-Za-z0-9]+$")
|
||||
delimitersAtStart = regexp.MustCompile("^[^A-Za-z0-9]+")
|
||||
delimitersOnly = regexp.MustCompile("^[^A-Za-z0-9]+$")
|
||||
removeQuotes = strings.NewReplacer(`"`, ``, `'`, ``)
|
||||
)
|
||||
|
||||
// GenerateBinaryNameFromPath generates a more human readable binary name from
|
||||
// the given path. This function is used as fallback in the GetBinaryName
|
||||
// functions.
|
||||
func GenerateBinaryNameFromPath(path string) string {
|
||||
// Get file name from path.
|
||||
_, fileName := filepath.Split(path)
|
||||
|
||||
// Split up into segments.
|
||||
segments := segmentsSplitter.FindAllString(fileName, -1)
|
||||
|
||||
// Remove last segment if it's an extension.
|
||||
if len(segments) >= 2 {
|
||||
switch strings.ToLower(segments[len(segments)-1]) {
|
||||
case
|
||||
".exe", // Windows Executable
|
||||
".msi", // Windows Installer
|
||||
".bat", // Windows Batch File
|
||||
".cmd", // Windows Command Script
|
||||
".ps1", // Windows Powershell Cmdlet
|
||||
".run", // Linux Executable
|
||||
".appimage", // Linux AppImage
|
||||
".app", // MacOS Executable
|
||||
".action", // MacOS Automator Action
|
||||
".out": // Generic Compiled Executable
|
||||
segments = segments[:len(segments)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Debugging snippet:
|
||||
// fmt.Printf("segments: %s\n", segments)
|
||||
|
||||
// Go through segments and collect name parts.
|
||||
nameParts := make([]string, 0, len(segments))
|
||||
var fragments string
|
||||
for _, segment := range segments {
|
||||
// Group very short segments.
|
||||
if len(delimitersAtStart.ReplaceAllString(segment, "")) <= 2 {
|
||||
fragments += segment
|
||||
continue
|
||||
} else if fragments != "" {
|
||||
nameParts = append(nameParts, fragments)
|
||||
fragments = ""
|
||||
}
|
||||
|
||||
// Add segment to name.
|
||||
nameParts = append(nameParts, segment)
|
||||
}
|
||||
// Add last fragment.
|
||||
if fragments != "" {
|
||||
nameParts = append(nameParts, fragments)
|
||||
}
|
||||
|
||||
// Debugging snippet:
|
||||
// fmt.Printf("parts: %s\n", nameParts)
|
||||
|
||||
// Post-process name parts
|
||||
for i := range nameParts {
|
||||
// Remove any leading delimiters.
|
||||
nameParts[i] = delimitersAtStart.ReplaceAllString(nameParts[i], "")
|
||||
|
||||
// Title-case name-only parts.
|
||||
if nameOnly.MatchString(nameParts[i]) {
|
||||
nameParts[i] = strings.Title(nameParts[i]) //nolint:staticcheck
|
||||
}
|
||||
}
|
||||
|
||||
// Debugging snippet:
|
||||
// fmt.Printf("final: %s\n", nameParts)
|
||||
|
||||
return strings.Join(nameParts, " ")
|
||||
}
|
||||
|
||||
func cleanFileDescription(fileDescr string) string {
|
||||
fields := strings.Fields(fileDescr)
|
||||
|
||||
// Clean out and `"` and `'`.
|
||||
for i := range fields {
|
||||
fields[i] = removeQuotes.Replace(fields[i])
|
||||
}
|
||||
|
||||
// If there is a 1 or 2 character delimiter field, only use fields before it.
|
||||
endIndex := len(fields)
|
||||
for i, field := range fields {
|
||||
// Ignore the first field as well as fields with more than two characters.
|
||||
if i >= 1 && len(field) <= 2 && !nameOnly.MatchString(field) {
|
||||
endIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Concatenate name
|
||||
binName := strings.Join(fields[:endIndex], " ")
|
||||
|
||||
// If there are multiple sentences, only use the first.
|
||||
if strings.Contains(binName, ". ") {
|
||||
binName = strings.SplitN(binName, ". ", 2)[0]
|
||||
}
|
||||
|
||||
// If does not have any characters or numbers, return an empty string.
|
||||
if delimitersOnly.MatchString(binName) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimSpace(binName)
|
||||
}
|
48
profile/binmeta/name_test.go
Normal file
48
profile/binmeta/name_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package binmeta
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenerateBinaryNameFromPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, "Nslookup", GenerateBinaryNameFromPath("nslookup.exe"))
|
||||
assert.Equal(t, "System Settings", GenerateBinaryNameFromPath("SystemSettings.exe"))
|
||||
assert.Equal(t, "One Drive Setup", GenerateBinaryNameFromPath("OneDriveSetup.exe"))
|
||||
assert.Equal(t, "Msedge", GenerateBinaryNameFromPath("msedge.exe"))
|
||||
assert.Equal(t, "SIH Client", GenerateBinaryNameFromPath("SIHClient.exe"))
|
||||
assert.Equal(t, "Openvpn Gui", GenerateBinaryNameFromPath("openvpn-gui.exe"))
|
||||
assert.Equal(t, "Portmaster Core v0-1-2", GenerateBinaryNameFromPath("portmaster-core_v0-1-2.exe"))
|
||||
assert.Equal(t, "Win Store App", GenerateBinaryNameFromPath("WinStore.App.exe"))
|
||||
assert.Equal(t, "Test Script", GenerateBinaryNameFromPath(".test-script"))
|
||||
assert.Equal(t, "Browser Broker", GenerateBinaryNameFromPath("browser_broker.exe"))
|
||||
assert.Equal(t, "Virtual Box VM", GenerateBinaryNameFromPath("VirtualBoxVM"))
|
||||
assert.Equal(t, "Io Elementary Appcenter", GenerateBinaryNameFromPath("io.elementary.appcenter"))
|
||||
assert.Equal(t, "Microsoft Windows Store", GenerateBinaryNameFromPath("Microsoft.WindowsStore"))
|
||||
}
|
||||
|
||||
func TestCleanFileDescription(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, "Product Name", cleanFileDescription("Product Name"))
|
||||
assert.Equal(t, "Product Name", cleanFileDescription("Product Name. Does this and that."))
|
||||
assert.Equal(t, "Product Name", cleanFileDescription("Product Name - Does this and that."))
|
||||
assert.Equal(t, "Product Name", cleanFileDescription("Product Name / Does this and that."))
|
||||
assert.Equal(t, "Product Name", cleanFileDescription("Product Name :: Does this and that."))
|
||||
assert.Equal(t, "/ Product Name", cleanFileDescription("/ Product Name"))
|
||||
assert.Equal(t, "Product", cleanFileDescription("Product / Name"))
|
||||
assert.Equal(t, "Software 2", cleanFileDescription("Software 2"))
|
||||
assert.Equal(t, "Launcher for Software 2", cleanFileDescription("Launcher for 'Software 2'"))
|
||||
assert.Equal(t, "", cleanFileDescription(". / Name"))
|
||||
assert.Equal(t, "", cleanFileDescription(". "))
|
||||
assert.Equal(t, "", cleanFileDescription("."))
|
||||
assert.Equal(t, "N/A", cleanFileDescription("N/A"))
|
||||
|
||||
assert.Equal(t,
|
||||
"Product Name a Does this and that.",
|
||||
cleanFileDescription("Product Name a Does this and that."),
|
||||
)
|
||||
}
|
|
@ -5,11 +5,12 @@ import (
|
|||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portmaster/intel"
|
||||
)
|
||||
|
||||
var asnRegex = regexp.MustCompile("^(AS)?[0-9]+$")
|
||||
var asnRegex = regexp.MustCompile("^AS[0-9]+$")
|
||||
|
||||
// EndpointASN matches ASNs.
|
||||
type EndpointASN struct {
|
||||
|
@ -48,9 +49,10 @@ func (ep *EndpointASN) String() string {
|
|||
|
||||
func parseTypeASN(fields []string) (Endpoint, error) {
|
||||
if asnRegex.MatchString(fields[1]) {
|
||||
asn, err := strconv.ParseUint(fields[1][2:], 10, 64)
|
||||
asnString := strings.TrimPrefix(fields[1], "AS")
|
||||
asn, err := strconv.ParseUint(asnString, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse AS number %s", fields[1])
|
||||
return nil, fmt.Errorf("failed to parse AS number %s", asnString)
|
||||
}
|
||||
|
||||
ep := &EndpointASN{
|
||||
|
|
|
@ -107,6 +107,12 @@ func parseTypeDomain(fields []string) (Endpoint, error) {
|
|||
domain += "."
|
||||
}
|
||||
|
||||
// Check if this looks like an IP address.
|
||||
// At least the TLDs has characters.
|
||||
if looksLikeAnIP.MatchString(domain) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Fix domain case.
|
||||
domain = strings.ToLower(domain)
|
||||
needValidFQDN := true
|
||||
|
|
|
@ -59,6 +59,9 @@ func TestEndpointParsing(t *testing.T) {
|
|||
testParsing(t, "+ * UDP/1234")
|
||||
testParsing(t, "+ * TCP/HTTP")
|
||||
testParsing(t, "+ * TCP/80-443")
|
||||
|
||||
// TODO: Test fails:
|
||||
// testParsing(t, "+ 1234")
|
||||
}
|
||||
|
||||
func testParsing(t *testing.T, value string) {
|
||||
|
@ -69,6 +72,7 @@ func testParsing(t *testing.T, value string) {
|
|||
t.Error(err)
|
||||
return
|
||||
}
|
||||
// t.Logf("%T: %+v", ep, ep)
|
||||
if value != ep.String() {
|
||||
t.Errorf(`stringified endpoint mismatch: original was "%s", parsed is "%s"`, value, ep.String())
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
//go:build !linux
|
||||
|
||||
package icons
|
||||
|
||||
import "context"
|
||||
|
||||
// FindIcon returns nil, nil for unsupported platforms.
|
||||
func FindIcon(ctx context.Context, binName string, homeDir string) (*Icon, error) {
|
||||
return nil, nil
|
||||
}
|
|
@ -7,7 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/safing/portbase/database/record"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
// MergeProfiles merges multiple profiles into a new one.
|
||||
|
@ -30,7 +30,6 @@ func MergeProfiles(name string, primary *Profile, secondaries ...*Profile) (newP
|
|||
Description: primary.Description,
|
||||
Homepage: primary.Homepage,
|
||||
UsePresentationPath: false, // Disable presentation path.
|
||||
SecurityLevel: primary.SecurityLevel,
|
||||
Config: primary.Config,
|
||||
Created: nowUnix,
|
||||
}
|
||||
|
@ -53,12 +52,12 @@ func MergeProfiles(name string, primary *Profile, secondaries ...*Profile) (newP
|
|||
}
|
||||
|
||||
// Collect all icons.
|
||||
newProfile.Icons = make([]icons.Icon, 0, len(secondaries)+1) // Guess the needed space.
|
||||
newProfile.Icons = make([]binmeta.Icon, 0, len(secondaries)+1) // Guess the needed space.
|
||||
newProfile.Icons = append(newProfile.Icons, primary.Icons...)
|
||||
for _, sp := range secondaries {
|
||||
newProfile.Icons = append(newProfile.Icons, sp.Icons...)
|
||||
}
|
||||
newProfile.Icons = icons.SortAndCompact(newProfile.Icons)
|
||||
newProfile.Icons = binmeta.SortAndCompactIcons(newProfile.Icons)
|
||||
|
||||
// Collect all fingerprints.
|
||||
newProfile.Fingerprints = make([]Fingerprint, 0, len(primary.Fingerprints)+len(secondaries)) // Guess the needed space.
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/safing/portbase/database/migration"
|
||||
"github.com/safing/portbase/database/query"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
func registerMigrations() error {
|
||||
|
@ -103,7 +103,7 @@ func migrateIcons(ctx context.Context, _, to *version.Version, db *database.Inte
|
|||
}
|
||||
|
||||
// Migrate to icon list.
|
||||
profile.Icons = []icons.Icon{{
|
||||
profile.Icons = []binmeta.Icon{{
|
||||
Type: profile.IconType,
|
||||
Value: profile.Icon,
|
||||
}}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/modules"
|
||||
_ "github.com/safing/portmaster/core/base"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
"github.com/safing/portmaster/updates"
|
||||
)
|
||||
|
||||
|
@ -53,7 +53,7 @@ func prep() error {
|
|||
if err := iconsDir.Ensure(); err != nil {
|
||||
return fmt.Errorf("failed to create/check icons directory: %w", err)
|
||||
}
|
||||
icons.ProfileIconStoragePath = iconsDir.Path
|
||||
binmeta.ProfileIconStoragePath = iconsDir.Path
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -135,8 +135,6 @@ func NewLayeredProfile(localProfile *Profile) *LayeredProfile {
|
|||
|
||||
// TODO: Load additional profiles.
|
||||
|
||||
lp.updateCaches()
|
||||
|
||||
lp.CreateMeta()
|
||||
lp.SetKey(runtime.DefaultRegistry.DatabaseName() + ":" + revisionProviderPrefix + localProfile.ScopedID())
|
||||
|
||||
|
@ -292,9 +290,6 @@ func (lp *LayeredProfile) Update(md MatchingData, createProfileCallback func() *
|
|||
// get global config validity flag
|
||||
lp.globalValidityFlag.Refresh()
|
||||
|
||||
// update cached data fields
|
||||
lp.updateCaches()
|
||||
|
||||
// bump revision counter
|
||||
lp.increaseRevisionCounter(false)
|
||||
}
|
||||
|
@ -302,17 +297,6 @@ func (lp *LayeredProfile) Update(md MatchingData, createProfileCallback func() *
|
|||
return lp.RevisionCounter
|
||||
}
|
||||
|
||||
func (lp *LayeredProfile) updateCaches() {
|
||||
// update security level
|
||||
var newLevel uint8
|
||||
for _, layer := range lp.layers {
|
||||
if newLevel < layer.SecurityLevel {
|
||||
newLevel = layer.SecurityLevel
|
||||
}
|
||||
}
|
||||
atomic.StoreUint32(lp.securityLevel, uint32(newLevel))
|
||||
}
|
||||
|
||||
// SecurityLevel returns the highest security level of all layered profiles. This function is atomic and does not require any locking.
|
||||
func (lp *LayeredProfile) SecurityLevel() uint8 {
|
||||
return uint8(atomic.LoadUint32(lp.securityLevel))
|
||||
|
|
|
@ -15,10 +15,9 @@ import (
|
|||
"github.com/safing/portbase/database/record"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/utils"
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
"github.com/safing/portmaster/intel/filterlists"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
"github.com/safing/portmaster/profile/endpoints"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
)
|
||||
|
||||
// ProfileSource is the source of the profile.
|
||||
|
@ -69,9 +68,9 @@ type Profile struct { //nolint:maligned // not worth the effort
|
|||
// See IconType for more information.
|
||||
Icon string
|
||||
// Deprecated: IconType describes the type of the Icon property.
|
||||
IconType icons.IconType
|
||||
IconType binmeta.IconType
|
||||
// Icons holds a list of icons to represent the application.
|
||||
Icons []icons.Icon
|
||||
Icons []binmeta.Icon
|
||||
|
||||
// Deprecated: LinkedPath used to point to the executableis this
|
||||
// profile was created for.
|
||||
|
@ -88,12 +87,6 @@ type Profile struct { //nolint:maligned // not worth the effort
|
|||
UsePresentationPath bool
|
||||
// Fingerprints holds process matching information.
|
||||
Fingerprints []Fingerprint
|
||||
// SecurityLevel is the mininum security level to apply to
|
||||
// connections made with this profile.
|
||||
// Note(ppacher): we may deprecate this one as it can easily
|
||||
// be "simulated" by adjusting the settings
|
||||
// directly.
|
||||
SecurityLevel uint8
|
||||
// Config holds profile specific setttings. It's a nested
|
||||
// object with keys defining the settings database path. All keys
|
||||
// until the actual settings value (which is everything that is not
|
||||
|
@ -476,7 +469,7 @@ func (profile *Profile) updateMetadata(binaryPath string) (changed bool) {
|
|||
// Set Name if unset.
|
||||
if profile.Name == "" && profile.PresentationPath != "" {
|
||||
// Generate a default profile name from path.
|
||||
profile.Name = osdetail.GenerateBinaryNameFromPath(profile.PresentationPath)
|
||||
profile.Name = binmeta.GenerateBinaryNameFromPath(profile.PresentationPath)
|
||||
changed = true
|
||||
}
|
||||
|
||||
|
@ -514,38 +507,16 @@ func (profile *Profile) updateMetadataFromSystem(ctx context.Context, md Matchin
|
|||
return fmt.Errorf("tried to update metadata for non-local or non-path profile %s", profile.ScopedID())
|
||||
}
|
||||
|
||||
// Get binary name from PresentationPath.
|
||||
newName, err := osdetail.GetBinaryNameFromSystem(profile.PresentationPath)
|
||||
// Get home from ENV.
|
||||
var home string
|
||||
if env := md.Env(); env != nil {
|
||||
home = env["HOME"]
|
||||
}
|
||||
|
||||
// Get binary icon and name.
|
||||
newIcon, newName, err := binmeta.GetIconAndName(ctx, profile.PresentationPath, home)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, osdetail.ErrNotSupported):
|
||||
case errors.Is(err, osdetail.ErrNotFound):
|
||||
case errors.Is(err, osdetail.ErrEmptyOutput):
|
||||
default:
|
||||
log.Warningf("profile: error while getting binary name for %s: %s", profile.PresentationPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if the new name is valid.
|
||||
if strings.TrimSpace(newName) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get icon if path matches presentation path.
|
||||
var newIcon *icons.Icon
|
||||
if profile.PresentationPath == md.Path() {
|
||||
// Get home from ENV.
|
||||
var home string
|
||||
if env := md.Env(); env != nil {
|
||||
home = env["HOME"]
|
||||
}
|
||||
var err error
|
||||
newIcon, err = icons.FindIcon(ctx, profile.PresentationPath, home)
|
||||
if err != nil {
|
||||
log.Warningf("profile: failed to find icon for %s: %s", profile.PresentationPath, err)
|
||||
newIcon = nil
|
||||
}
|
||||
log.Warningf("profile: failed to get binary icon/name for %s: %s", profile.PresentationPath, err)
|
||||
}
|
||||
|
||||
// Apply new data to profile.
|
||||
|
@ -555,7 +526,7 @@ func (profile *Profile) updateMetadataFromSystem(ctx context.Context, md Matchin
|
|||
defer profile.Unlock()
|
||||
|
||||
// Apply new name if it changed.
|
||||
if profile.Name != newName {
|
||||
if newName != "" && profile.Name != newName {
|
||||
profile.Name = newName
|
||||
changed = true
|
||||
}
|
||||
|
@ -563,10 +534,10 @@ func (profile *Profile) updateMetadataFromSystem(ctx context.Context, md Matchin
|
|||
// Apply new icon if found.
|
||||
if newIcon != nil {
|
||||
if len(profile.Icons) == 0 {
|
||||
profile.Icons = []icons.Icon{*newIcon}
|
||||
profile.Icons = []binmeta.Icon{*newIcon}
|
||||
} else {
|
||||
profile.Icons = append(profile.Icons, *newIcon)
|
||||
profile.Icons = icons.SortAndCompact(profile.Icons)
|
||||
profile.Icons = binmeta.SortAndCompactIcons(profile.Icons)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/safing/portbase/config"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/portmaster/profile/icons"
|
||||
"github.com/safing/portmaster/profile/binmeta"
|
||||
)
|
||||
|
||||
// ProfileExport holds an export of a profile.
|
||||
|
@ -415,12 +415,12 @@ func ImportProfile(r *ProfileImportRequest, requiredProfileSource profile.Profil
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: icon data is invalid: %w", ErrImportFailed, err)
|
||||
}
|
||||
filename, err := icons.UpdateProfileIcon(du.Data, du.MediaType.Subtype)
|
||||
filename, err := binmeta.UpdateProfileIcon(du.Data, du.MediaType.Subtype)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: icon is invalid: %w", ErrImportFailed, err)
|
||||
}
|
||||
p.Icons = []icons.Icon{{
|
||||
Type: icons.IconTypeAPI,
|
||||
p.Icons = []binmeta.Icon{{
|
||||
Type: binmeta.IconTypeAPI,
|
||||
Value: filename,
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -254,6 +254,12 @@ func ImportSettings(r *SettingsImportRequest) (*ImportResult, error) {
|
|||
)
|
||||
}
|
||||
|
||||
// Save new config to disk.
|
||||
err := config.SaveConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to save config: %w", err)
|
||||
}
|
||||
|
||||
result.RestartRequired = restartRequired
|
||||
return result, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue