Patches to bring compatibility to Go 1.22
* Disabled container building * No TLS Fingerprinting * HTTP/2 H2C uses golang.org/x/net/http2/h2c * html DOM walking uses custom function instead of iterator * Pinned these packages to latest compatible releases: * github.com/go-jose/go-jose/v4 v4.0.5 * golang.org/x/crypto v0.33.0 * golang.org/x/net v0.37.0 * golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac * golang.org/x/text v0.22.0 * google.golang.org/genproto/googleapis v0.0.0-20240826202546-f6391c0de4c7
This commit is contained in:
committed by
WeebDataHoarder
parent
b1f1e9a54f
commit
0ca8e277f9
@@ -138,25 +138,12 @@ local Publish(mirror, registry, repo, secret, go, alpine, os, arch, trigger, pla
|
||||
#
|
||||
local containerArchitectures = ["linux/amd64", "linux/arm64", "linux/riscv64"];
|
||||
|
||||
local alpineVersion = "3.21";
|
||||
local goVersion = "1.24";
|
||||
local alpineVersion = "3.20";
|
||||
local goVersion = "1.22";
|
||||
|
||||
local mirror = "https://mirror.gcr.io";
|
||||
|
||||
[
|
||||
Build(mirror, goVersion, alpineVersion, "linux", "amd64") + {"trigger": {event: ["push", "tag"], }},
|
||||
Build(mirror, goVersion, alpineVersion, "linux", "arm64") + {"trigger": {event: ["push", "tag"], }},
|
||||
|
||||
# Test PRs
|
||||
Build(mirror, goVersion, alpineVersion, "linux", "amd64") + {"name": "test-pr", "trigger": {event: ["pull_request"], }},
|
||||
|
||||
# latest
|
||||
Publish(mirror, "git.gammaspectra.live", "git.gammaspectra.live/git/go-away", "git", goVersion, alpineVersion, "linux", "amd64", {event: ["push"], branch: ["master"], }, containerArchitectures, {tags: ["latest"],}) + {name: "publish-latest-git"},
|
||||
Publish(mirror, "codeberg.org", "codeberg.org/gone/go-away", "codeberg", goVersion, alpineVersion, "linux", "amd64", {event: ["push"], branch: ["master"], }, containerArchitectures, {tags: ["latest"],}) + {name: "publish-latest-codeberg"},
|
||||
Publish(mirror, "ghcr.io", "ghcr.io/weebdatahoarder/go-away", "github", goVersion, alpineVersion, "linux", "amd64", {event: ["push"], branch: ["master"], }, containerArchitectures, {tags: ["latest"],}) + {name: "publish-latest-github"},
|
||||
|
||||
# modern
|
||||
Publish(mirror, "git.gammaspectra.live", "git.gammaspectra.live/git/go-away", "git", goVersion, alpineVersion, "linux", "amd64", {event: ["promote", "tag"], target: ["production"], }, containerArchitectures, {auto_tag: true,}),
|
||||
Publish(mirror, "codeberg.org", "codeberg.org/gone/go-away", "codeberg", goVersion, alpineVersion, "linux", "amd64", {event: ["promote", "tag"], target: ["production"], }, containerArchitectures, {auto_tag: true,}),
|
||||
Publish(mirror, "ghcr.io", "ghcr.io/weebdatahoarder/go-away", "github", goVersion, alpineVersion, "linux", "amd64", {event: ["promote", "tag"], target: ["production"], }, containerArchitectures, {auto_tag: true,}),
|
||||
Build(mirror, goVersion, alpineVersion, "linux", "amd64"),
|
||||
Build(mirror, goVersion, alpineVersion, "linux", "arm64"),
|
||||
]
|
397
.drone.yml
397
.drone.yml
@@ -5,7 +5,7 @@ environment:
|
||||
GOOS: linux
|
||||
GOTOOLCHAIN: local
|
||||
kind: pipeline
|
||||
name: build-1.24-alpine3.21-amd64
|
||||
name: build-1.22-alpine3.20-amd64
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
@@ -16,7 +16,7 @@ steps:
|
||||
- mkdir .bin
|
||||
- go build -v -pgo=auto -v -trimpath -ldflags=-buildid= -o ./.bin/go-away ./cmd/go-away
|
||||
- go build -v -o ./.bin/test-wasm-runtime ./cmd/test-wasm-runtime
|
||||
image: golang:1.24-alpine3.21
|
||||
image: golang:1.22-alpine3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: build
|
||||
- commands:
|
||||
@@ -24,7 +24,7 @@ steps:
|
||||
--policy examples/forgejo.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-forgejo
|
||||
- commands:
|
||||
@@ -32,7 +32,7 @@ steps:
|
||||
--policy examples/generic.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-generic
|
||||
- commands:
|
||||
@@ -40,7 +40,7 @@ steps:
|
||||
--policy examples/spa.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-spa
|
||||
- commands:
|
||||
@@ -51,7 +51,7 @@ steps:
|
||||
0
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: test-wasm-success
|
||||
- commands:
|
||||
@@ -62,13 +62,9 @@ steps:
|
||||
1
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: test-wasm-fail
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
type: docker
|
||||
---
|
||||
environment:
|
||||
@@ -77,7 +73,7 @@ environment:
|
||||
GOOS: linux
|
||||
GOTOOLCHAIN: local
|
||||
kind: pipeline
|
||||
name: build-1.24-alpine3.21-arm64
|
||||
name: build-1.22-alpine3.20-arm64
|
||||
platform:
|
||||
arch: arm64
|
||||
os: linux
|
||||
@@ -88,7 +84,7 @@ steps:
|
||||
- mkdir .bin
|
||||
- go build -v -pgo=auto -v -trimpath -ldflags=-buildid= -o ./.bin/go-away ./cmd/go-away
|
||||
- go build -v -o ./.bin/test-wasm-runtime ./cmd/test-wasm-runtime
|
||||
image: golang:1.24-alpine3.21
|
||||
image: golang:1.22-alpine3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: build
|
||||
- commands:
|
||||
@@ -96,7 +92,7 @@ steps:
|
||||
--policy examples/forgejo.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-forgejo
|
||||
- commands:
|
||||
@@ -104,7 +100,7 @@ steps:
|
||||
--policy examples/generic.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-generic
|
||||
- commands:
|
||||
@@ -112,7 +108,7 @@ steps:
|
||||
--policy examples/spa.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-spa
|
||||
- commands:
|
||||
@@ -123,7 +119,7 @@ steps:
|
||||
0
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: test-wasm-success
|
||||
- commands:
|
||||
@@ -134,375 +130,12 @@ steps:
|
||||
1
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
image: alpine:3.20
|
||||
mirror: https://mirror.gcr.io
|
||||
name: test-wasm-fail
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
type: docker
|
||||
---
|
||||
environment:
|
||||
CGO_ENABLED: "0"
|
||||
GOARCH: amd64
|
||||
GOOS: linux
|
||||
GOTOOLCHAIN: local
|
||||
kind: pipeline
|
||||
name: test-pr
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- apk update
|
||||
- apk add --no-cache git
|
||||
- mkdir .bin
|
||||
- go build -v -pgo=auto -v -trimpath -ldflags=-buildid= -o ./.bin/go-away ./cmd/go-away
|
||||
- go build -v -o ./.bin/test-wasm-runtime ./cmd/test-wasm-runtime
|
||||
image: golang:1.24-alpine3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: build
|
||||
- commands:
|
||||
- ./.bin/go-away --check --slog-level DEBUG --backend example.com=http://127.0.0.1:80
|
||||
--policy examples/forgejo.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-forgejo
|
||||
- commands:
|
||||
- ./.bin/go-away --check --slog-level DEBUG --backend example.com=http://127.0.0.1:80
|
||||
--policy examples/generic.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-generic
|
||||
- commands:
|
||||
- ./.bin/go-away --check --slog-level DEBUG --backend example.com=http://127.0.0.1:80
|
||||
--policy examples/spa.yml --policy-snippets examples/snippets/
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: check-policy-spa
|
||||
- commands:
|
||||
- ./.bin/test-wasm-runtime -wasm ./embed/challenge/js-pow-sha256/runtime/runtime.wasm
|
||||
-make-challenge ./embed/challenge/js-pow-sha256/test/make-challenge.json -make-challenge-out
|
||||
./embed/challenge/js-pow-sha256/test/make-challenge-out.json -verify-challenge
|
||||
./embed/challenge/js-pow-sha256/test/verify-challenge.json -verify-challenge-out
|
||||
0
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: test-wasm-success
|
||||
- commands:
|
||||
- ./.bin/test-wasm-runtime -wasm ./embed/challenge/js-pow-sha256/runtime/runtime.wasm
|
||||
-make-challenge ./embed/challenge/js-pow-sha256/test/make-challenge.json -make-challenge-out
|
||||
./embed/challenge/js-pow-sha256/test/make-challenge-out.json -verify-challenge
|
||||
./embed/challenge/js-pow-sha256/test/verify-challenge-fail.json -verify-challenge-out
|
||||
1
|
||||
depends_on:
|
||||
- build
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: test-wasm-fail
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
type: docker
|
||||
---
|
||||
kind: pipeline
|
||||
name: publish-latest-git
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- echo '[registry."docker.io"]' > buildkitd.toml
|
||||
- echo ' mirrors = ["mirror.gcr.io"]' >> buildkitd.toml
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: setup-buildkitd
|
||||
- environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
LC_ALL: C
|
||||
PLUGIN_BUILDER_CONFIG: buildkitd.toml
|
||||
PLUGIN_BUILDER_DRIVER: docker-container
|
||||
SOURCE_DATE_EPOCH: 0
|
||||
TZ: UTC
|
||||
image: plugins/buildx
|
||||
name: docker
|
||||
privileged: true
|
||||
settings:
|
||||
auto_tag_suffix: alpine3.21
|
||||
build_args:
|
||||
from: alpine:3.21
|
||||
from_builder: golang:1.24-alpine3.21
|
||||
compress: true
|
||||
mirror: https://mirror.gcr.io
|
||||
password:
|
||||
from_secret: git_password
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/riscv64
|
||||
registry: git.gammaspectra.live
|
||||
repo: git.gammaspectra.live/git/go-away
|
||||
tags:
|
||||
- latest
|
||||
username:
|
||||
from_secret: git_username
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
type: docker
|
||||
---
|
||||
kind: pipeline
|
||||
name: publish-latest-codeberg
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- echo '[registry."docker.io"]' > buildkitd.toml
|
||||
- echo ' mirrors = ["mirror.gcr.io"]' >> buildkitd.toml
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: setup-buildkitd
|
||||
- environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
LC_ALL: C
|
||||
PLUGIN_BUILDER_CONFIG: buildkitd.toml
|
||||
PLUGIN_BUILDER_DRIVER: docker-container
|
||||
SOURCE_DATE_EPOCH: 0
|
||||
TZ: UTC
|
||||
image: plugins/buildx
|
||||
name: docker
|
||||
privileged: true
|
||||
settings:
|
||||
auto_tag_suffix: alpine3.21
|
||||
build_args:
|
||||
from: alpine:3.21
|
||||
from_builder: golang:1.24-alpine3.21
|
||||
compress: true
|
||||
mirror: https://mirror.gcr.io
|
||||
password:
|
||||
from_secret: codeberg_password
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/riscv64
|
||||
registry: codeberg.org
|
||||
repo: codeberg.org/gone/go-away
|
||||
tags:
|
||||
- latest
|
||||
username:
|
||||
from_secret: codeberg_username
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
type: docker
|
||||
---
|
||||
kind: pipeline
|
||||
name: publish-latest-github
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- echo '[registry."docker.io"]' > buildkitd.toml
|
||||
- echo ' mirrors = ["mirror.gcr.io"]' >> buildkitd.toml
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: setup-buildkitd
|
||||
- environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
LC_ALL: C
|
||||
PLUGIN_BUILDER_CONFIG: buildkitd.toml
|
||||
PLUGIN_BUILDER_DRIVER: docker-container
|
||||
SOURCE_DATE_EPOCH: 0
|
||||
TZ: UTC
|
||||
image: plugins/buildx
|
||||
name: docker
|
||||
privileged: true
|
||||
settings:
|
||||
auto_tag_suffix: alpine3.21
|
||||
build_args:
|
||||
from: alpine:3.21
|
||||
from_builder: golang:1.24-alpine3.21
|
||||
compress: true
|
||||
mirror: https://mirror.gcr.io
|
||||
password:
|
||||
from_secret: github_password
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/riscv64
|
||||
registry: ghcr.io
|
||||
repo: ghcr.io/weebdatahoarder/go-away
|
||||
tags:
|
||||
- latest
|
||||
username:
|
||||
from_secret: github_username
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
type: docker
|
||||
---
|
||||
kind: pipeline
|
||||
name: publish-1.24-alpine3.21-git
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- echo '[registry."docker.io"]' > buildkitd.toml
|
||||
- echo ' mirrors = ["mirror.gcr.io"]' >> buildkitd.toml
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: setup-buildkitd
|
||||
- environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
LC_ALL: C
|
||||
PLUGIN_BUILDER_CONFIG: buildkitd.toml
|
||||
PLUGIN_BUILDER_DRIVER: docker-container
|
||||
SOURCE_DATE_EPOCH: 0
|
||||
TZ: UTC
|
||||
image: plugins/buildx
|
||||
name: docker
|
||||
privileged: true
|
||||
settings:
|
||||
auto_tag: true
|
||||
auto_tag_suffix: alpine3.21
|
||||
build_args:
|
||||
from: alpine:3.21
|
||||
from_builder: golang:1.24-alpine3.21
|
||||
compress: true
|
||||
mirror: https://mirror.gcr.io
|
||||
password:
|
||||
from_secret: git_password
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/riscv64
|
||||
registry: git.gammaspectra.live
|
||||
repo: git.gammaspectra.live/git/go-away
|
||||
username:
|
||||
from_secret: git_username
|
||||
trigger:
|
||||
event:
|
||||
- promote
|
||||
- tag
|
||||
target:
|
||||
- production
|
||||
type: docker
|
||||
---
|
||||
kind: pipeline
|
||||
name: publish-1.24-alpine3.21-codeberg
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- echo '[registry."docker.io"]' > buildkitd.toml
|
||||
- echo ' mirrors = ["mirror.gcr.io"]' >> buildkitd.toml
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: setup-buildkitd
|
||||
- environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
LC_ALL: C
|
||||
PLUGIN_BUILDER_CONFIG: buildkitd.toml
|
||||
PLUGIN_BUILDER_DRIVER: docker-container
|
||||
SOURCE_DATE_EPOCH: 0
|
||||
TZ: UTC
|
||||
image: plugins/buildx
|
||||
name: docker
|
||||
privileged: true
|
||||
settings:
|
||||
auto_tag: true
|
||||
auto_tag_suffix: alpine3.21
|
||||
build_args:
|
||||
from: alpine:3.21
|
||||
from_builder: golang:1.24-alpine3.21
|
||||
compress: true
|
||||
mirror: https://mirror.gcr.io
|
||||
password:
|
||||
from_secret: codeberg_password
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/riscv64
|
||||
registry: codeberg.org
|
||||
repo: codeberg.org/gone/go-away
|
||||
username:
|
||||
from_secret: codeberg_username
|
||||
trigger:
|
||||
event:
|
||||
- promote
|
||||
- tag
|
||||
target:
|
||||
- production
|
||||
type: docker
|
||||
---
|
||||
kind: pipeline
|
||||
name: publish-1.24-alpine3.21-github
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
steps:
|
||||
- commands:
|
||||
- echo '[registry."docker.io"]' > buildkitd.toml
|
||||
- echo ' mirrors = ["mirror.gcr.io"]' >> buildkitd.toml
|
||||
image: alpine:3.21
|
||||
mirror: https://mirror.gcr.io
|
||||
name: setup-buildkitd
|
||||
- environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
LC_ALL: C
|
||||
PLUGIN_BUILDER_CONFIG: buildkitd.toml
|
||||
PLUGIN_BUILDER_DRIVER: docker-container
|
||||
SOURCE_DATE_EPOCH: 0
|
||||
TZ: UTC
|
||||
image: plugins/buildx
|
||||
name: docker
|
||||
privileged: true
|
||||
settings:
|
||||
auto_tag: true
|
||||
auto_tag_suffix: alpine3.21
|
||||
build_args:
|
||||
from: alpine:3.21
|
||||
from_builder: golang:1.24-alpine3.21
|
||||
compress: true
|
||||
mirror: https://mirror.gcr.io
|
||||
password:
|
||||
from_secret: github_password
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
- linux/riscv64
|
||||
registry: ghcr.io
|
||||
repo: ghcr.io/weebdatahoarder/go-away
|
||||
username:
|
||||
from_secret: github_username
|
||||
trigger:
|
||||
event:
|
||||
- promote
|
||||
- tag
|
||||
target:
|
||||
- production
|
||||
type: docker
|
||||
---
|
||||
kind: signature
|
||||
hmac: df53e4ea6f1c47df4d2a3f89b931b8513e83daa9c6c15baba2662d8112a721c8
|
||||
hmac: 00be8252a86e2c760c07c2baa6efa55d75f46fdc22299bb3feb1b199cc54af9e
|
||||
|
||||
...
|
||||
|
36
go.mod
36
go.mod
@@ -1,14 +1,12 @@
|
||||
module git.gammaspectra.live/git/go-away
|
||||
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.2
|
||||
go 1.22.12
|
||||
|
||||
require (
|
||||
codeberg.org/gone/http-cel v1.0.0
|
||||
codeberg.org/meta/gzipped/v2 v2.0.0-20231111234332-aa70c3194756
|
||||
github.com/alphadose/haxmap v1.4.1
|
||||
github.com/go-jose/go-jose/v4 v4.1.0
|
||||
github.com/go-jose/go-jose/v4 v4.0.5
|
||||
github.com/goccy/go-yaml v1.17.1
|
||||
github.com/google/cel-go v0.25.0
|
||||
github.com/itchyny/gojq v0.12.17
|
||||
@@ -16,7 +14,8 @@ require (
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/tetratelabs/wazero v1.9.0
|
||||
github.com/yl2chen/cidranger v1.0.2
|
||||
golang.org/x/crypto v0.37.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/net v0.37.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -29,13 +28,26 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.63.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
)
|
||||
|
||||
// Pin latest versions to support Go 1.22 to prevent a package update from changing them
|
||||
// TODO: remove this when Go 1.22+ is supported by other downstream users
|
||||
replace (
|
||||
github.com/go-jose/go-jose/v4 => github.com/go-jose/go-jose/v4 v4.0.5
|
||||
github.com/prometheus/procfs => github.com/prometheus/procfs v0.15.1
|
||||
golang.org/x/crypto => golang.org/x/crypto v0.33.0
|
||||
golang.org/x/exp => golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/net => golang.org/x/net v0.35.0
|
||||
golang.org/x/sys => golang.org/x/sys v0.30.0
|
||||
golang.org/x/text => golang.org/x/text v0.22.0
|
||||
google.golang.org/genproto/googleapis/api => google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7
|
||||
google.golang.org/genproto/googleapis/rpc => google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7
|
||||
)
|
||||
|
36
go.sum
36
go.sum
@@ -15,8 +15,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
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=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
|
||||
@@ -45,8 +45,8 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -62,20 +62,20 @@ github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZB
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f h1:tjZsroqekhC63+WMqzmWyW5Twj/ZfR5HAlpd5YQ1Vs0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f h1:N/PrbTw4kdkqNRzVfWPrBekzLuarFREcbFOiOLkXon4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@@ -433,7 +433,13 @@ func (d *RequestData) verifyChallengeStateCookie(cookie *http.Cookie) (TokenChal
|
||||
}
|
||||
|
||||
func (d *RequestData) verifyChallengeState() (state TokenChallengeMap, err error) {
|
||||
cookies := d.r.CookiesNamed(d.cookieName)
|
||||
var cookies []*http.Cookie
|
||||
for _, cookie := range d.r.Cookies() {
|
||||
if cookie.Name == d.cookieName {
|
||||
cookies = append(cookies, cookie)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cookies) == 0 {
|
||||
return nil, http.ErrNoCookie
|
||||
}
|
||||
|
@@ -1,48 +1,13 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
func applyTLSFingerprinter(server *http.Server) {
|
||||
if server.TLSConfig == nil {
|
||||
return
|
||||
}
|
||||
server.TLSConfig = server.TLSConfig.Clone()
|
||||
|
||||
getConfigForClient := server.TLSConfig.GetConfigForClient
|
||||
|
||||
if getConfigForClient == nil {
|
||||
getConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
server.TLSConfig.GetConfigForClient = func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
ja3n, ja4 := buildTLSFingerprint(clientHello)
|
||||
ptr := clientHello.Context().Value(tlsFingerprintKey{})
|
||||
if fpPtr, ok := ptr.(*TLSFingerprint); ok && ptr != nil && fpPtr != nil {
|
||||
fpPtr.ja3n.Store(&ja3n)
|
||||
fpPtr.ja4.Store(&ja4)
|
||||
}
|
||||
return getConfigForClient(clientHello)
|
||||
}
|
||||
server.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
|
||||
return context.WithValue(ctx, tlsFingerprintKey{}, &TLSFingerprint{})
|
||||
}
|
||||
}
|
||||
|
||||
type tlsFingerprintKey struct{}
|
||||
type TLSFingerprint struct {
|
||||
ja3n atomic.Pointer[TLSFingerprintJA3N]
|
||||
@@ -105,227 +70,6 @@ const (
|
||||
extensionEncryptedClientHello uint16 = 0xfe0d
|
||||
)
|
||||
|
||||
func tlsFingerprintJA3(hello *tls.ClientHelloInfo, sortExtensions bool) []byte {
|
||||
buf := make([]byte, 0, 256)
|
||||
|
||||
{
|
||||
var sslVersion uint16
|
||||
var hasGrease bool
|
||||
for _, v := range hello.SupportedVersions {
|
||||
if v&greaseMask != greaseValue {
|
||||
if v > sslVersion {
|
||||
sslVersion = v
|
||||
}
|
||||
} else {
|
||||
hasGrease = true
|
||||
}
|
||||
}
|
||||
|
||||
// maximum TLS 1.2 as specified on JA3, as TLS 1.3 is put in SupportedVersions
|
||||
if slices.Contains(hello.Extensions, extensionSupportedVersions) && hasGrease && sslVersion > tls.VersionTLS12 {
|
||||
sslVersion = tls.VersionTLS12
|
||||
}
|
||||
|
||||
buf = strconv.AppendUint(buf, uint64(sslVersion), 10)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
n := 0
|
||||
for _, cipher := range hello.CipherSuites {
|
||||
//if !slices.Contains(greaseValues[:], cipher) {
|
||||
if cipher&greaseMask != greaseValue {
|
||||
buf = strconv.AppendUint(buf, uint64(cipher), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
buf = append(buf, ',')
|
||||
n = 0
|
||||
|
||||
extensions := hello.Extensions
|
||||
if sortExtensions {
|
||||
extensions = slices.Clone(extensions)
|
||||
slices.Sort(extensions)
|
||||
}
|
||||
|
||||
for _, extension := range extensions {
|
||||
if extension&greaseMask != greaseValue {
|
||||
buf = strconv.AppendUint(buf, uint64(extension), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
buf = append(buf, ',')
|
||||
n = 0
|
||||
|
||||
for _, curve := range hello.SupportedCurves {
|
||||
if curve&greaseMask != greaseValue {
|
||||
buf = strconv.AppendUint(buf, uint64(curve), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
buf = append(buf, ',')
|
||||
n = 0
|
||||
|
||||
for _, point := range hello.SupportedPoints {
|
||||
buf = strconv.AppendUint(buf, uint64(point), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
|
||||
sum := md5.Sum(buf)
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
func tlsFingerprintJA4(hello *tls.ClientHelloInfo) (ja4 TLSFingerprintJA4) {
|
||||
buf := make([]byte, 0, 10)
|
||||
|
||||
// TODO: t = TLS, q = QUIC
|
||||
buf = append(buf, 't')
|
||||
|
||||
{
|
||||
var sslVersion uint16
|
||||
for _, v := range hello.SupportedVersions {
|
||||
if v&greaseMask != greaseValue {
|
||||
if v > sslVersion {
|
||||
sslVersion = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch sslVersion {
|
||||
case tls.VersionSSL30:
|
||||
buf = append(buf, 's', '3')
|
||||
case tls.VersionTLS10:
|
||||
buf = append(buf, '1', '0')
|
||||
case tls.VersionTLS11:
|
||||
buf = append(buf, '1', '1')
|
||||
case tls.VersionTLS12:
|
||||
buf = append(buf, '1', '2')
|
||||
case tls.VersionTLS13:
|
||||
buf = append(buf, '1', '3')
|
||||
default:
|
||||
sslVersion -= 0x0201
|
||||
buf = strconv.AppendUint(buf, uint64(sslVersion>>8), 10)
|
||||
buf = strconv.AppendUint(buf, uint64(sslVersion&0xff), 10)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if slices.Contains(hello.Extensions, extensionServerName) && hello.ServerName != "" {
|
||||
buf = append(buf, 'd')
|
||||
} else {
|
||||
buf = append(buf, 'i')
|
||||
}
|
||||
|
||||
ciphers := make([]uint16, 0, len(hello.CipherSuites))
|
||||
for _, cipher := range hello.CipherSuites {
|
||||
if cipher&greaseMask != greaseValue {
|
||||
ciphers = append(ciphers, cipher)
|
||||
}
|
||||
}
|
||||
|
||||
extensionCount := 0
|
||||
extensions := make([]uint16, 0, len(hello.Extensions))
|
||||
for _, extension := range hello.Extensions {
|
||||
if extension&greaseMask != greaseValue {
|
||||
extensionCount++
|
||||
if extension != extensionALPN && extension != extensionServerName {
|
||||
extensions = append(extensions, extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schemes := make([]tls.SignatureScheme, 0, len(hello.SignatureSchemes))
|
||||
|
||||
for _, scheme := range hello.SignatureSchemes {
|
||||
if scheme&greaseMask != greaseValue {
|
||||
schemes = append(schemes, scheme)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: maybe little endian
|
||||
slices.Sort(ciphers)
|
||||
slices.Sort(extensions)
|
||||
//slices.Sort(schemes)
|
||||
|
||||
if len(ciphers) < 10 {
|
||||
buf = append(buf, '0')
|
||||
buf = strconv.AppendUint(buf, uint64(len(ciphers)), 10)
|
||||
} else if len(ciphers) > 99 {
|
||||
buf = append(buf, '9', '9')
|
||||
} else {
|
||||
buf = strconv.AppendUint(buf, uint64(len(ciphers)), 10)
|
||||
}
|
||||
|
||||
if extensionCount < 10 {
|
||||
buf = append(buf, '0')
|
||||
buf = strconv.AppendUint(buf, uint64(extensionCount), 10)
|
||||
} else if extensionCount > 99 {
|
||||
buf = append(buf, '9', '9')
|
||||
} else {
|
||||
buf = strconv.AppendUint(buf, uint64(extensionCount), 10)
|
||||
}
|
||||
|
||||
if len(hello.SupportedProtos) > 0 && len(hello.SupportedProtos[0]) > 1 {
|
||||
buf = append(buf, hello.SupportedProtos[0][0], hello.SupportedProtos[0][len(hello.SupportedProtos[0])-1])
|
||||
} else {
|
||||
buf = append(buf, '0', '0')
|
||||
}
|
||||
|
||||
copy(ja4.A[:], buf)
|
||||
|
||||
ja4.B = ja4SHA256(uint16SliceToHex(ciphers))
|
||||
|
||||
extBuf := uint16SliceToHex(extensions)
|
||||
|
||||
if len(schemes) > 0 {
|
||||
extBuf = append(extBuf, '_')
|
||||
extBuf = append(extBuf, uint16SliceToHex(schemes)...)
|
||||
}
|
||||
|
||||
ja4.C = ja4SHA256(extBuf)
|
||||
|
||||
return ja4
|
||||
}
|
||||
|
||||
func uint16SliceToHex[T ~uint16](in []T) (out []byte) {
|
||||
if len(in) == 0 {
|
||||
return out
|
||||
}
|
||||
out = slices.Grow(out, hex.EncodedLen(len(in)*2)+len(in))
|
||||
|
||||
for _, n := range in {
|
||||
out = append(out, fmt.Sprintf("%04x", uint16(n))...)
|
||||
out = append(out, ',')
|
||||
}
|
||||
out = out[:len(out)-1]
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func ja4SHA256(buf []byte) [6]byte {
|
||||
if len(buf) == 0 {
|
||||
return [6]byte{0, 0, 0, 0, 0, 0}
|
||||
}
|
||||
sum := sha256.Sum256(buf)
|
||||
|
||||
return [6]byte(sum[:6])
|
||||
}
|
||||
|
||||
func buildTLSFingerprint(hello *tls.ClientHelloInfo) (ja3n TLSFingerprintJA3N, ja4 TLSFingerprintJA4) {
|
||||
return TLSFingerprintJA3N(tlsFingerprintJA3(hello, true)), tlsFingerprintJA4(hello)
|
||||
}
|
||||
|
||||
func GetTLSFingerprint(r *http.Request) *TLSFingerprint {
|
||||
ptr := r.Context().Value(tlsFingerprintKey{})
|
||||
if fpPtr, ok := ptr.(*TLSFingerprint); ok && ptr != nil && fpPtr != nil {
|
||||
|
269
utils/fingerprint_modern.go
Normal file
269
utils/fingerprint_modern.go
Normal file
@@ -0,0 +1,269 @@
|
||||
//go:build !go1.22 && !go1.23
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func applyTLSFingerprinter(server *http.Server) {
|
||||
server.TLSConfig = server.TLSConfig.Clone()
|
||||
|
||||
getCertificate := server.TLSConfig.GetCertificate
|
||||
if getCertificate == nil {
|
||||
server.TLSConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
ja3n, ja4 := buildTLSFingerprint(clientHello)
|
||||
ptr := clientHello.Context().Value(tlsFingerprintKey{})
|
||||
if fpPtr, ok := ptr.(*TLSFingerprint); ok && ptr != nil && fpPtr != nil {
|
||||
fpPtr.ja3n.Store(&ja3n)
|
||||
fpPtr.ja4.Store(&ja4)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
} else {
|
||||
server.TLSConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
ja3n, ja4 := buildTLSFingerprint(clientHello)
|
||||
ptr := clientHello.Context().Value(tlsFingerprintKey{})
|
||||
if fpPtr, ok := ptr.(*TLSFingerprint); ok && ptr != nil && fpPtr != nil {
|
||||
fpPtr.ja3n.Store(&ja3n)
|
||||
fpPtr.ja4.Store(&ja4)
|
||||
}
|
||||
|
||||
return getCertificate(clientHello)
|
||||
}
|
||||
}
|
||||
server.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
|
||||
return context.WithValue(ctx, tlsFingerprintKey{}, &TLSFingerprint{})
|
||||
}
|
||||
}
|
||||
|
||||
func tlsFingerprintJA3(hello *tls.ClientHelloInfo, sortExtensions bool) []byte {
|
||||
buf := make([]byte, 0, 256)
|
||||
|
||||
{
|
||||
var sslVersion uint16
|
||||
var hasGrease bool
|
||||
for _, v := range hello.SupportedVersions {
|
||||
if v&greaseMask != greaseValue {
|
||||
if v > sslVersion {
|
||||
sslVersion = v
|
||||
}
|
||||
} else {
|
||||
hasGrease = true
|
||||
}
|
||||
}
|
||||
|
||||
// maximum TLS 1.2 as specified on JA3, as TLS 1.3 is put in SupportedVersions
|
||||
if slices.Contains(hello.Extensions, extensionSupportedVersions) && hasGrease && sslVersion > tls.VersionTLS12 {
|
||||
sslVersion = tls.VersionTLS12
|
||||
}
|
||||
|
||||
buf = strconv.AppendUint(buf, uint64(sslVersion), 10)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
n := 0
|
||||
for _, cipher := range hello.CipherSuites {
|
||||
//if !slices.Contains(greaseValues[:], cipher) {
|
||||
if cipher&greaseMask != greaseValue {
|
||||
buf = strconv.AppendUint(buf, uint64(cipher), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
buf = append(buf, ',')
|
||||
n = 0
|
||||
|
||||
extensions := hello.Extensions
|
||||
if sortExtensions {
|
||||
extensions = slices.Clone(extensions)
|
||||
slices.Sort(extensions)
|
||||
}
|
||||
|
||||
for _, extension := range extensions {
|
||||
if extension&greaseMask != greaseValue {
|
||||
buf = strconv.AppendUint(buf, uint64(extension), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
buf = append(buf, ',')
|
||||
n = 0
|
||||
|
||||
for _, curve := range hello.SupportedCurves {
|
||||
if curve&greaseMask != greaseValue {
|
||||
buf = strconv.AppendUint(buf, uint64(curve), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
buf = append(buf, ',')
|
||||
n = 0
|
||||
|
||||
for _, point := range hello.SupportedPoints {
|
||||
buf = strconv.AppendUint(buf, uint64(point), 10)
|
||||
buf = append(buf, '-')
|
||||
n = 1
|
||||
}
|
||||
|
||||
buf = buf[:len(buf)-n]
|
||||
|
||||
sum := md5.Sum(buf)
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
func tlsFingerprintJA4(hello *tls.ClientHelloInfo) (ja4 TLSFingerprintJA4) {
|
||||
buf := make([]byte, 0, 10)
|
||||
|
||||
// TODO: t = TLS, q = QUIC
|
||||
buf = append(buf, 't')
|
||||
|
||||
{
|
||||
var sslVersion uint16
|
||||
for _, v := range hello.SupportedVersions {
|
||||
if v&greaseMask != greaseValue {
|
||||
if v > sslVersion {
|
||||
sslVersion = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch sslVersion {
|
||||
case tls.VersionSSL30:
|
||||
buf = append(buf, 's', '3')
|
||||
case tls.VersionTLS10:
|
||||
buf = append(buf, '1', '0')
|
||||
case tls.VersionTLS11:
|
||||
buf = append(buf, '1', '1')
|
||||
case tls.VersionTLS12:
|
||||
buf = append(buf, '1', '2')
|
||||
case tls.VersionTLS13:
|
||||
buf = append(buf, '1', '3')
|
||||
default:
|
||||
sslVersion -= 0x0201
|
||||
buf = strconv.AppendUint(buf, uint64(sslVersion>>8), 10)
|
||||
buf = strconv.AppendUint(buf, uint64(sslVersion&0xff), 10)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if slices.Contains(hello.Extensions, extensionServerName) && hello.ServerName != "" {
|
||||
buf = append(buf, 'd')
|
||||
} else {
|
||||
buf = append(buf, 'i')
|
||||
}
|
||||
|
||||
ciphers := make([]uint16, 0, len(hello.CipherSuites))
|
||||
for _, cipher := range hello.CipherSuites {
|
||||
if cipher&greaseMask != greaseValue {
|
||||
ciphers = append(ciphers, cipher)
|
||||
}
|
||||
}
|
||||
|
||||
extensionCount := 0
|
||||
extensions := make([]uint16, 0, len(hello.Extensions))
|
||||
for _, extension := range hello.Extensions {
|
||||
if extension&greaseMask != greaseValue {
|
||||
extensionCount++
|
||||
if extension != extensionALPN && extension != extensionServerName {
|
||||
extensions = append(extensions, extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schemes := make([]tls.SignatureScheme, 0, len(hello.SignatureSchemes))
|
||||
|
||||
for _, scheme := range hello.SignatureSchemes {
|
||||
if scheme&greaseMask != greaseValue {
|
||||
schemes = append(schemes, scheme)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: maybe little endian
|
||||
slices.Sort(ciphers)
|
||||
slices.Sort(extensions)
|
||||
//slices.Sort(schemes)
|
||||
|
||||
if len(ciphers) < 10 {
|
||||
buf = append(buf, '0')
|
||||
buf = strconv.AppendUint(buf, uint64(len(ciphers)), 10)
|
||||
} else if len(ciphers) > 99 {
|
||||
buf = append(buf, '9', '9')
|
||||
} else {
|
||||
buf = strconv.AppendUint(buf, uint64(len(ciphers)), 10)
|
||||
}
|
||||
|
||||
if extensionCount < 10 {
|
||||
buf = append(buf, '0')
|
||||
buf = strconv.AppendUint(buf, uint64(extensionCount), 10)
|
||||
} else if extensionCount > 99 {
|
||||
buf = append(buf, '9', '9')
|
||||
} else {
|
||||
buf = strconv.AppendUint(buf, uint64(extensionCount), 10)
|
||||
}
|
||||
|
||||
if len(hello.SupportedProtos) > 0 && len(hello.SupportedProtos[0]) > 1 {
|
||||
buf = append(buf, hello.SupportedProtos[0][0], hello.SupportedProtos[0][len(hello.SupportedProtos[0])-1])
|
||||
} else {
|
||||
buf = append(buf, '0', '0')
|
||||
}
|
||||
|
||||
copy(ja4.A[:], buf)
|
||||
|
||||
ja4.B = ja4SHA256(uint16SliceToHex(ciphers))
|
||||
|
||||
extBuf := uint16SliceToHex(extensions)
|
||||
|
||||
if len(schemes) > 0 {
|
||||
extBuf = append(extBuf, '_')
|
||||
extBuf = append(extBuf, uint16SliceToHex(schemes)...)
|
||||
}
|
||||
|
||||
ja4.C = ja4SHA256(extBuf)
|
||||
|
||||
return ja4
|
||||
}
|
||||
|
||||
func uint16SliceToHex[T ~uint16](in []T) (out []byte) {
|
||||
if len(in) == 0 {
|
||||
return out
|
||||
}
|
||||
out = slices.Grow(out, hex.EncodedLen(len(in)*2)+len(in))
|
||||
|
||||
for _, n := range in {
|
||||
out = append(out, fmt.Sprintf("%04x", uint16(n))...)
|
||||
out = append(out, ',')
|
||||
}
|
||||
out = out[:len(out)-1]
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func ja4SHA256(buf []byte) [6]byte {
|
||||
if len(buf) == 0 {
|
||||
return [6]byte{0, 0, 0, 0, 0, 0}
|
||||
}
|
||||
sum := sha256.Sum256(buf)
|
||||
|
||||
return [6]byte(sum[:6])
|
||||
}
|
||||
|
||||
func buildTLSFingerprint(hello *tls.ClientHelloInfo) (ja3n TLSFingerprintJA3N, ja4 TLSFingerprintJA4) {
|
||||
return TLSFingerprintJA3N(tlsFingerprintJA3(hello, true)), tlsFingerprintJA4(hello)
|
||||
}
|
@@ -16,27 +16,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewServer(handler http.Handler, tlsConfig *tls.Config) *http.Server {
|
||||
if tlsConfig == nil {
|
||||
proto := new(http.Protocols)
|
||||
proto.SetHTTP1(true)
|
||||
proto.SetUnencryptedHTTP2(true)
|
||||
h1s := &http.Server{
|
||||
Handler: handler,
|
||||
Protocols: proto,
|
||||
}
|
||||
|
||||
return h1s
|
||||
} else {
|
||||
server := &http.Server{
|
||||
TLSConfig: tlsConfig,
|
||||
Handler: handler,
|
||||
}
|
||||
applyTLSFingerprinter(server)
|
||||
return server
|
||||
}
|
||||
}
|
||||
|
||||
func SelectHTTPHandler(backends map[string]http.Handler, host string) http.Handler {
|
||||
backend, ok := backends[host]
|
||||
if !ok {
|
||||
|
28
utils/http_legacy.go
Normal file
28
utils/http_legacy.go
Normal file
@@ -0,0 +1,28 @@
|
||||
//go:build go1.22 || go1.23
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewServer(handler http.Handler, tlsConfig *tls.Config) *http.Server {
|
||||
if tlsConfig == nil {
|
||||
h2s := &http2.Server{}
|
||||
|
||||
h1s := &http.Server{
|
||||
Handler: h2c.NewHandler(handler, h2s),
|
||||
}
|
||||
|
||||
return h1s
|
||||
} else {
|
||||
server := &http.Server{
|
||||
TLSConfig: tlsConfig,
|
||||
Handler: handler,
|
||||
}
|
||||
return server
|
||||
}
|
||||
}
|
29
utils/http_modern.go
Normal file
29
utils/http_modern.go
Normal file
@@ -0,0 +1,29 @@
|
||||
//go:build !go1.22 && !go1.23
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewServer(handler http.Handler, tlsConfig *tls.Config) *http.Server {
|
||||
if tlsConfig == nil {
|
||||
proto := new(http.Protocols)
|
||||
proto.SetHTTP1(true)
|
||||
proto.SetUnencryptedHTTP2(true)
|
||||
h1s := &http.Server{
|
||||
Handler: handler,
|
||||
Protocols: proto,
|
||||
}
|
||||
|
||||
return h1s
|
||||
} else {
|
||||
server := &http.Server{
|
||||
TLSConfig: tlsConfig,
|
||||
Handler: handler,
|
||||
}
|
||||
applyTLSFingerprinter(server)
|
||||
return server
|
||||
}
|
||||
}
|
@@ -39,7 +39,7 @@ func FetchTags(backend http.Handler, uri *url.URL, kinds ...string) (result []ht
|
||||
return nil
|
||||
}
|
||||
|
||||
for n := range node.Descendants() {
|
||||
descendants(node, func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && slices.Contains(kinds, n.Data) {
|
||||
result = append(result, html.Node{
|
||||
Type: n.Type,
|
||||
@@ -49,7 +49,14 @@ func FetchTags(backend http.Handler, uri *url.URL, kinds ...string) (result []ht
|
||||
Attr: n.Attr,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func descendants(n *html.Node, f func(n *html.Node)) {
|
||||
f(n)
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
descendants(c, f)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user