mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-22 16:16:41 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b72ded756 | |||
| 439860443a | |||
| 33bc4669cb | |||
| fa5ceedf23 | |||
| 49dcdbc49e | |||
| 578f248ce1 | |||
| 298fc0b847 | |||
| 8af9845117 | |||
| 3a6e368179 | |||
| 98afcf8c64 | |||
| 982394ca91 | |||
| 66b7b27aef | |||
| cc07be8a9e | |||
| 04f8b6b148 |
@@ -35,3 +35,6 @@ resourced
|
|||||||
envoyproxy
|
envoyproxy
|
||||||
unipromos
|
unipromos
|
||||||
Samsung
|
Samsung
|
||||||
|
wenet
|
||||||
|
qwertiko
|
||||||
|
setuplistener
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "1.25.7"
|
go-version: "1.25.7"
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
||||||
|
|
||||||
- name: Log into registry
|
- name: Log into registry
|
||||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
- name: Log into registry
|
- name: Log into registry
|
||||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: techarohq
|
username: techarohq
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
- name: Cache playwright binaries
|
- name: Cache playwright binaries
|
||||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||||
id: playwright-cache
|
id: playwright-cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: "24.11.0"
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: check-spelling
|
- name: check-spelling
|
||||||
id: spelling
|
id: spelling
|
||||||
uses: check-spelling/check-spelling@c635c2f3f714eec2fcf27b643a1919b9a811ef2e # v0.0.25
|
uses: check-spelling/check-spelling@cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c # v0.0.26
|
||||||
with:
|
with:
|
||||||
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
|
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
|
||||||
checkout: true
|
checkout: true
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Log into registry
|
- name: Log into registry
|
||||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Install CI target SSH key
|
- name: Install CI target SSH key
|
||||||
uses: shimataro/ssh-key-action@6b84f2e793b32fa0b03a379cadadec75cc539391 # v2.8.0
|
uses: shimataro/ssh-key-action@87a8f067114a8ce263df83e9ed5c849953548bc3 # v2.8.1
|
||||||
with:
|
with:
|
||||||
key: ${{ secrets.CI_SSH_KEY }}
|
key: ${{ secrets.CI_SSH_KEY }}
|
||||||
name: id_rsa
|
name: id_rsa
|
||||||
known_hosts: ${{ secrets.CI_SSH_KNOWN_HOSTS }}
|
known_hosts: ${{ secrets.CI_SSH_KNOWN_HOSTS }}
|
||||||
|
|
||||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Install the latest version of uv
|
- name: Install the latest version of uv
|
||||||
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
|
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
|
||||||
|
|
||||||
- name: Run zizmor 🌈
|
- name: Run zizmor 🌈
|
||||||
run: uvx zizmor --format sarif . > results.sarif
|
run: uvx zizmor --format sarif . > results.sarif
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: zizmor
|
category: zizmor
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ Anubis is brought to you by sponsors and donors like:
|
|||||||
<a href="https://dd-wrt.com/">
|
<a href="https://dd-wrt.com/">
|
||||||
<img src="./docs/static/img/sponsors/ddwrt-logo.webp" alt="embeDD GmbH" height="64">
|
<img src="./docs/static/img/sponsors/ddwrt-logo.webp" alt="embeDD GmbH" height="64">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://www.qwertiko.de?utm_campaign=github&utm_medium=referral&utm_content=anubis">
|
||||||
|
<img src="./docs/static/img/sponsors/qwertiko-logo.webp" alt="Qwertiko" height="64">
|
||||||
|
</a>
|
||||||
|
<a href="https://wenet.pl/?utm_campaign=github&utm_medium=referral&utm_content=anubis">
|
||||||
|
<img src="./docs/static/img/sponsors/wenet-logo.webp" alt="Wenet" height="64">
|
||||||
|
</a>
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|||||||
+26
-130
@@ -17,12 +17,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/http/pprof"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -33,12 +31,12 @@ import (
|
|||||||
"github.com/TecharoHQ/anubis/internal"
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
libanubis "github.com/TecharoHQ/anubis/lib"
|
libanubis "github.com/TecharoHQ/anubis/lib"
|
||||||
"github.com/TecharoHQ/anubis/lib/config"
|
"github.com/TecharoHQ/anubis/lib/config"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/metrics"
|
||||||
botPolicy "github.com/TecharoHQ/anubis/lib/policy"
|
botPolicy "github.com/TecharoHQ/anubis/lib/policy"
|
||||||
"github.com/TecharoHQ/anubis/lib/thoth"
|
"github.com/TecharoHQ/anubis/lib/thoth"
|
||||||
"github.com/TecharoHQ/anubis/web"
|
"github.com/TecharoHQ/anubis/web"
|
||||||
"github.com/facebookgo/flagenv"
|
"github.com/facebookgo/flagenv"
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
healthv1 "google.golang.org/grpc/health/grpc_health_v1"
|
healthv1 "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,33 +117,6 @@ func doHealthCheck() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseBindNetFromAddr determine bind network and address based on the given network and address.
|
|
||||||
func parseBindNetFromAddr(address string) (string, string) {
|
|
||||||
defaultScheme := "http://"
|
|
||||||
if !strings.Contains(address, "://") {
|
|
||||||
if strings.HasPrefix(address, ":") {
|
|
||||||
address = defaultScheme + "localhost" + address
|
|
||||||
} else {
|
|
||||||
address = defaultScheme + address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bindUri, err := url.Parse(address)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(fmt.Errorf("failed to parse bind URL: %w", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch bindUri.Scheme {
|
|
||||||
case "unix":
|
|
||||||
return "unix", bindUri.Path
|
|
||||||
case "tcp", "http", "https":
|
|
||||||
return "tcp", bindUri.Host
|
|
||||||
default:
|
|
||||||
log.Fatal(fmt.Errorf("unsupported network scheme %s in address %s", bindUri.Scheme, address))
|
|
||||||
}
|
|
||||||
return "", address
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSameSite(s string) http.SameSite {
|
func parseSameSite(s string) http.SameSite {
|
||||||
switch strings.ToLower(s) {
|
switch strings.ToLower(s) {
|
||||||
case "none":
|
case "none":
|
||||||
@@ -162,53 +133,6 @@ func parseSameSite(s string) http.SameSite {
|
|||||||
return http.SameSiteDefaultMode
|
return http.SameSiteDefaultMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupListener(network string, address string) (net.Listener, string) {
|
|
||||||
formattedAddress := ""
|
|
||||||
|
|
||||||
if network == "" {
|
|
||||||
// keep compatibility
|
|
||||||
network, address = parseBindNetFromAddr(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch network {
|
|
||||||
case "unix":
|
|
||||||
formattedAddress = "unix:" + address
|
|
||||||
case "tcp":
|
|
||||||
if strings.HasPrefix(address, ":") { // assume it's just a port e.g. :4259
|
|
||||||
formattedAddress = "http://localhost" + address
|
|
||||||
} else {
|
|
||||||
formattedAddress = "http://" + address
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
formattedAddress = fmt.Sprintf(`(%s) %s`, network, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
listener, err := net.Listen(network, address)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(fmt.Errorf("failed to bind to %s: %w", formattedAddress, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// additional permission handling for unix sockets
|
|
||||||
if network == "unix" {
|
|
||||||
mode, err := strconv.ParseUint(*socketMode, 8, 0)
|
|
||||||
if err != nil {
|
|
||||||
listener.Close()
|
|
||||||
log.Fatal(fmt.Errorf("could not parse socket mode %s: %w", *socketMode, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Chmod(address, os.FileMode(mode))
|
|
||||||
if err != nil {
|
|
||||||
err := listener.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close listener: %v", err)
|
|
||||||
}
|
|
||||||
log.Fatal(fmt.Errorf("could not change socket mode: %w", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return listener, formattedAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeReverseProxy(target string, targetSNI string, targetHost string, insecureSkipVerify bool, targetDisableKeepAlive bool) (http.Handler, error) {
|
func makeReverseProxy(target string, targetSNI string, targetHost string, insecureSkipVerify bool, targetDisableKeepAlive bool) (http.Handler, error) {
|
||||||
targetUri, err := url.Parse(target)
|
targetUri, err := url.Parse(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -304,11 +228,6 @@ func main() {
|
|||||||
|
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
|
|
||||||
if *metricsBind != "" {
|
|
||||||
wg.Add(1)
|
|
||||||
go metricsServer(ctx, *lg.With("subsystem", "metrics"), wg.Done)
|
|
||||||
}
|
|
||||||
|
|
||||||
var rp http.Handler
|
var rp http.Handler
|
||||||
// when using anubis via Systemd and environment variables, then it is not possible to set targe to an empty string but only to space
|
// when using anubis via Systemd and environment variables, then it is not possible to set targe to an empty string but only to space
|
||||||
if strings.TrimSpace(*target) != "" {
|
if strings.TrimSpace(*target) != "" {
|
||||||
@@ -348,6 +267,26 @@ func main() {
|
|||||||
lg.Debug("swapped to new logger")
|
lg.Debug("swapped to new logger")
|
||||||
slog.SetDefault(lg)
|
slog.SetDefault(lg)
|
||||||
|
|
||||||
|
if *metricsBind != "" || policy.Metrics != nil {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
ms := &metrics.Server{
|
||||||
|
Config: policy.Metrics,
|
||||||
|
Log: lg,
|
||||||
|
}
|
||||||
|
|
||||||
|
if policy.Metrics == nil {
|
||||||
|
lg.Debug("migrating flags to metrics config", "bind", *metricsBind, "network", *metricsBindNetwork, "socket-mode", *socketMode)
|
||||||
|
ms.Config = &config.Metrics{
|
||||||
|
Bind: *metricsBind,
|
||||||
|
Network: *metricsBindNetwork,
|
||||||
|
SocketMode: *socketMode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go ms.Run(ctx, wg.Done)
|
||||||
|
}
|
||||||
|
|
||||||
// Warn if persistent storage is used without a configured signing key
|
// Warn if persistent storage is used without a configured signing key
|
||||||
if policy.Store.IsPersistent() {
|
if policy.Store.IsPersistent() {
|
||||||
if *hs512Secret == "" && *ed25519PrivateKeyHex == "" && *ed25519PrivateKeyHexFile == "" {
|
if *hs512Secret == "" && *ed25519PrivateKeyHex == "" && *ed25519PrivateKeyHexFile == "" {
|
||||||
@@ -484,7 +423,11 @@ func main() {
|
|||||||
h = internal.JA4H(h)
|
h = internal.JA4H(h)
|
||||||
|
|
||||||
srv := http.Server{Handler: h, ErrorLog: internal.GetFilteredHTTPLogger()}
|
srv := http.Server{Handler: h, ErrorLog: internal.GetFilteredHTTPLogger()}
|
||||||
listener, listenerUrl := setupListener(*bindNetwork, *bind)
|
listener, listenerUrl, err := internal.SetupListener(*bindNetwork, *bind, *socketMode)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("SetupListener(%q, %q, %q): %v", *bindNetwork, *bind, *socketMode, err)
|
||||||
|
}
|
||||||
|
|
||||||
lg.Info(
|
lg.Info(
|
||||||
"listening",
|
"listening",
|
||||||
"url", listenerUrl,
|
"url", listenerUrl,
|
||||||
@@ -519,53 +462,6 @@ func main() {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func metricsServer(ctx context.Context, lg slog.Logger, done func()) {
|
|
||||||
defer done()
|
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
|
|
||||||
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
|
|
||||||
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
|
|
||||||
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
|
|
||||||
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
|
|
||||||
mux.Handle("/metrics", promhttp.Handler())
|
|
||||||
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
st, ok := internal.GetHealth("anubis")
|
|
||||||
if !ok {
|
|
||||||
slog.Error("health service anubis does not exist, file a bug")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch st {
|
|
||||||
case healthv1.HealthCheckResponse_NOT_SERVING:
|
|
||||||
http.Error(w, "NOT OK", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
case healthv1.HealthCheckResponse_SERVING:
|
|
||||||
fmt.Fprintln(w, "OK")
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
http.Error(w, "UNKNOWN", http.StatusFailedDependency)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
srv := http.Server{Handler: mux, ErrorLog: internal.GetFilteredHTTPLogger()}
|
|
||||||
listener, metricsUrl := setupListener(*metricsBindNetwork, *metricsBind)
|
|
||||||
lg.Debug("listening for metrics", "url", metricsUrl)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
<-ctx.Done()
|
|
||||||
c, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
if err := srv.Shutdown(c); err != nil {
|
|
||||||
log.Printf("cannot shut down: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := srv.Serve(listener); !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractEmbedFS(fsys embed.FS, root string, destDir string) error {
|
func extractEmbedFS(fsys embed.FS, root string, destDir string) error {
|
||||||
return fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
|
return fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -166,6 +166,15 @@ status_codes:
|
|||||||
CHALLENGE: 200
|
CHALLENGE: 200
|
||||||
DENY: 200
|
DENY: 200
|
||||||
|
|
||||||
|
# # Configuration for the metrics server. See the docs for more information:
|
||||||
|
# #
|
||||||
|
# # https://anubis.techaro.lol/docs/admin/policies#metrics-server
|
||||||
|
# #
|
||||||
|
# # This is commented out by default so that command line flags take precedence.
|
||||||
|
# metrics:
|
||||||
|
# bind: ":9090"
|
||||||
|
# network: "tcp"
|
||||||
|
|
||||||
# Anubis can store temporary data in one of a few backends. See the storage
|
# Anubis can store temporary data in one of a few backends. See the storage
|
||||||
# backends section of the docs for more information:
|
# backends section of the docs for more information:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -11,14 +11,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
<!-- This changes the project to: -->
|
||||||
|
|
||||||
|
- Move metrics server configuration to [the policy file](./admin/policies.mdx#metrics-server).
|
||||||
- Expose [pprof endpoints](https://pkg.go.dev/net/http/pprof) on the metrics listener to enable profiling Anubis in production.
|
- Expose [pprof endpoints](https://pkg.go.dev/net/http/pprof) on the metrics listener to enable profiling Anubis in production.
|
||||||
- fix: prevent nil pointer panic in challenge validation when threshold rules match during PassChallenge (#1463)
|
- fix: prevent nil pointer panic in challenge validation when threshold rules match during PassChallenge (#1463)
|
||||||
- Instruct reverse proxies to not cache error pages.
|
- Instruct reverse proxies to not cache error pages.
|
||||||
- Fixed mixed tab/space indentation in Caddy documentation code block
|
- Fixed mixed tab/space indentation in Caddy documentation code block
|
||||||
- Improve error messages and fix broken REDIRECT_DOMAINS link in docs ([#1193](https://github.com/TecharoHQ/anubis/issues/1193))
|
- Improve error messages and fix broken REDIRECT_DOMAINS link in docs ([#1193](https://github.com/TecharoHQ/anubis/issues/1193))
|
||||||
- Add Bulgarian locale ([#1394](https://github.com/TecharoHQ/anubis/pull/1394))
|
- Add Bulgarian locale ([#1394](https://github.com/TecharoHQ/anubis/pull/1394))
|
||||||
|
|
||||||
<!-- This changes the project to: -->
|
|
||||||
- Fix CEL internal errors when iterating `headers`/`query` map wrappers by implementing map iterators for `HTTPHeaders` and `URLValues` ([#1465](https://github.com/TecharoHQ/anubis/pull/1465)).
|
- Fix CEL internal errors when iterating `headers`/`query` map wrappers by implementing map iterators for `HTTPHeaders` and `URLValues` ([#1465](https://github.com/TecharoHQ/anubis/pull/1465)).
|
||||||
|
|
||||||
## v1.25.0: Necron
|
## v1.25.0: Necron
|
||||||
|
|||||||
@@ -87,15 +87,15 @@ Anubis uses these environment variables for configuration:
|
|||||||
| `ED25519_PRIVATE_KEY_HEX_FILE` | unset | Path to a file containing the hex-encoded ed25519 private key. Only one of this or its sister option may be set. **Required when using persistent storage backends** (like bbolt) to ensure challenges survive service restarts. When running multiple instances on the same base domain, the key must be the same across all instances. |
|
| `ED25519_PRIVATE_KEY_HEX_FILE` | unset | Path to a file containing the hex-encoded ed25519 private key. Only one of this or its sister option may be set. **Required when using persistent storage backends** (like bbolt) to ensure challenges survive service restarts. When running multiple instances on the same base domain, the key must be the same across all instances. |
|
||||||
| `ERROR_TITLE` | unset | <EO /> If set, override the translation stack to show a custom title for error pages such as "Something went wrong!". See [Customizing messages](./botstopper.mdx#customizing-messages) for more details. |
|
| `ERROR_TITLE` | unset | <EO /> If set, override the translation stack to show a custom title for error pages such as "Something went wrong!". See [Customizing messages](./botstopper.mdx#customizing-messages) for more details. |
|
||||||
| `JWT_RESTRICTION_HEADER` | `X-Real-IP` | If set, the JWT is only valid if the current value of this header matches the value when the JWT was created. You can use it e.g. to restrict a JWT to the source IP of the user using `X-Real-IP`. |
|
| `JWT_RESTRICTION_HEADER` | `X-Real-IP` | If set, the JWT is only valid if the current value of this header matches the value when the JWT was created. You can use it e.g. to restrict a JWT to the source IP of the user using `X-Real-IP`. |
|
||||||
| `METRICS_BIND` | `:9090` | The network address that Anubis serves Prometheus metrics on. See `BIND` for more information. |
|
| `METRICS_BIND` | `:9090` | The legacy configuration value for the network address that Anubis serves Prometheus metrics on. Please migrate this to [the policy file](./policies.mdx#metrics-server) as soon as possible. |
|
||||||
| `METRICS_BIND_NETWORK` | `tcp` | The address family that the Anubis metrics server listens on. See `BIND_NETWORK` for more information. |
|
| `METRICS_BIND_NETWORK` | `tcp` | The legacy configuration value for the address family that Anubis serves Prometheus metrics on. Please migrate this to [the policy file](./policies.mdx#metrics-server) as soon as possible. |
|
||||||
| `OG_EXPIRY_TIME` | `24h` | The expiration time for the Open Graph tag cache. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
|
| `OG_EXPIRY_TIME` | `24h` | The expiration time for the Open Graph tag cache. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
|
||||||
| `OG_PASSTHROUGH` | `false` | If set to `true`, Anubis will enable Open Graph tag passthrough. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
|
| `OG_PASSTHROUGH` | `false` | If set to `true`, Anubis will enable Open Graph tag passthrough. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
|
||||||
| `OG_CACHE_CONSIDER_HOST` | `false` | If set to `true`, Anubis will consider the host in the Open Graph tag cache key. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
|
| `OG_CACHE_CONSIDER_HOST` | `false` | If set to `true`, Anubis will consider the host in the Open Graph tag cache key. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
|
||||||
| `OVERLAY_FOLDER` | unset | <EO /> If set, treat the given path as an [overlay folder](./botstopper.mdx#custom-images-and-css), allowing you to customize CSS, fonts, images, and add other assets to BotStopper deployments. |
|
| `OVERLAY_FOLDER` | unset | <EO /> If set, treat the given path as an [overlay folder](./botstopper.mdx#custom-images-and-css), allowing you to customize CSS, fonts, images, and add other assets to BotStopper deployments. |
|
||||||
| `POLICY_FNAME` | unset | The file containing [bot policy configuration](./policies.mdx). See the bot policy documentation for more details. If unset, the default bot policy configuration is used. |
|
| `POLICY_FNAME` | unset | The file containing [bot policy configuration](./policies.mdx). See the bot policy documentation for more details. If unset, the default bot policy configuration is used. |
|
||||||
| `PUBLIC_URL` | unset | The externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for Traefik forwardAuth). Leave it unset when Anubis terminates traffic directly (sidecar/standalone deployments) or redirect building will fail with `redir=null`. |
|
| `PUBLIC_URL` | unset | The externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for Traefik forwardAuth). Leave it unset when Anubis terminates traffic directly (sidecar/standalone deployments) or redirect building will fail with `redir=null`. |
|
||||||
| `REDIRECT_DOMAINS` | unset | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains.mdx) for more details. |
|
| `REDIRECT_DOMAINS` | unset | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains.mdx) for more details. |
|
||||||
| `SERVE_ROBOTS_TXT` | `false` | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file. |
|
| `SERVE_ROBOTS_TXT` | `false` | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file. |
|
||||||
| `SLOG_LEVEL` | `INFO` | The log level for structured logging. Valid values are `DEBUG`, `INFO`, `WARN`, and `ERROR`. Set to `DEBUG` to see all requests, evaluations, and detailed diagnostic information. |
|
| `SLOG_LEVEL` | `INFO` | The log level for structured logging. Valid values are `DEBUG`, `INFO`, `WARN`, and `ERROR`. Set to `DEBUG` to see all requests, evaluations, and detailed diagnostic information. |
|
||||||
| `SOCKET_MODE` | `0770` | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets. |
|
| `SOCKET_MODE` | `0770` | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets. |
|
||||||
|
|||||||
@@ -117,6 +117,27 @@ remote_addresses:
|
|||||||
- 100.64.0.0/10
|
- 100.64.0.0/10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Metrics server
|
||||||
|
|
||||||
|
Anubis includes support for [Prometheus-style metrics](https://prometheus.io/docs/introduction/overview/), allowing systems administrators to monitor Anubis' performance and effectiveness. This is a separate HTTP server with metrics, health checking, and debug routes.
|
||||||
|
|
||||||
|
Anubis' metrics server is configured with the `metrics` block in the configuration file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to bind metrics to a Unix socket, make sure to set the network to `unix` and add a socket mode:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
metrics:
|
||||||
|
bind: "/tmp/anubis_metrics.sock"
|
||||||
|
network: unix
|
||||||
|
socketMode: "0700" # must be a string
|
||||||
|
```
|
||||||
|
|
||||||
## Imprint / Impressum support
|
## Imprint / Impressum support
|
||||||
|
|
||||||
Anubis has support for showing imprint / impressum information. This is defined in the `impressum` block of your configuration. See [Imprint / Impressum configuration](./configuration/impressum.mdx) for more information.
|
Anubis has support for showing imprint / impressum information. This is defined in the `impressum` block of your configuration. See [Imprint / Impressum configuration](./configuration/impressum.mdx) for more information.
|
||||||
|
|||||||
@@ -90,6 +90,12 @@ Anubis is brought to you by sponsors and donors like:
|
|||||||
<a href="https://dd-wrt.com/">
|
<a href="https://dd-wrt.com/">
|
||||||
<img src="/img/sponsors/ddwrt-logo.webp" alt="embeDD GmbH" height="64" />
|
<img src="/img/sponsors/ddwrt-logo.webp" alt="embeDD GmbH" height="64" />
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://www.qwertiko.de?utm_campaign=github&utm_medium=referral&utm_content=anubis">
|
||||||
|
<img src="/img/sponsors/qwertiko-logo.webp" alt="Qwertiko" height="64" />
|
||||||
|
</a>
|
||||||
|
<a href="https://wenet.pl/?utm_campaign=github&utm_medium=referral&utm_content=anubis">
|
||||||
|
<img src="/img/sponsors/wenet-logo.webp" alt="Wenet" height="64" />
|
||||||
|
</a>
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
@@ -0,0 +1,92 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseBindNetFromAddr determine bind network and address based on the given network and address.
|
||||||
|
func parseBindNetFromAddr(address string) (string, string, error) {
|
||||||
|
defaultScheme := "http://"
|
||||||
|
if !strings.Contains(address, "://") {
|
||||||
|
if strings.HasPrefix(address, ":") {
|
||||||
|
address = defaultScheme + "localhost" + address
|
||||||
|
} else {
|
||||||
|
address = defaultScheme + address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bindUri, err := url.Parse(address)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("failed to parse bind URL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch bindUri.Scheme {
|
||||||
|
case "unix":
|
||||||
|
return "unix", bindUri.Path, nil
|
||||||
|
case "tcp", "http", "https":
|
||||||
|
return "tcp", bindUri.Host, nil
|
||||||
|
default:
|
||||||
|
return "", "", fmt.Errorf("unsupported network scheme %s in address %s", bindUri.Scheme, address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupListener sets up a network listener based on the input from configuration
|
||||||
|
// envvars. It returns a network listener and the URL to that listener or an error.
|
||||||
|
func SetupListener(network, address, socketMode string) (net.Listener, string, error) {
|
||||||
|
formattedAddress := ""
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if network == "" {
|
||||||
|
// keep compatibility
|
||||||
|
network, address, err = parseBindNetFromAddr(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", fmt.Errorf("can't parse bind and network: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch network {
|
||||||
|
case "unix":
|
||||||
|
formattedAddress = "unix:" + address
|
||||||
|
case "tcp":
|
||||||
|
if strings.HasPrefix(address, ":") { // assume it's just a port e.g. :4259
|
||||||
|
formattedAddress = "http://localhost" + address
|
||||||
|
} else {
|
||||||
|
formattedAddress = "http://" + address
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
formattedAddress = fmt.Sprintf(`(%s) %s`, network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.Listen(network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", fmt.Errorf("failed to bind to %s: %w", formattedAddress, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional permission handling for unix sockets
|
||||||
|
if network == "unix" {
|
||||||
|
mode, err := strconv.ParseUint(socketMode, 8, 0)
|
||||||
|
if err != nil {
|
||||||
|
ln.Close()
|
||||||
|
return nil, "", fmt.Errorf("could not parse socket mode %s: %w", socketMode, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chmod(address, os.FileMode(mode))
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("could not change socket mode: %w", err)
|
||||||
|
clErr := ln.Close()
|
||||||
|
if clErr != nil {
|
||||||
|
return nil, "", errors.Join(err, clErr)
|
||||||
|
}
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ln, formattedAddress, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseBindNetFromAddr(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
address string
|
||||||
|
wantErr bool
|
||||||
|
network string
|
||||||
|
bind string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple tcp",
|
||||||
|
address: "localhost:9090",
|
||||||
|
wantErr: false,
|
||||||
|
network: "tcp",
|
||||||
|
bind: "localhost:9090",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "simple unix",
|
||||||
|
address: "unix:///tmp/foo.sock",
|
||||||
|
wantErr: false,
|
||||||
|
network: "unix",
|
||||||
|
bind: "/tmp/foo.sock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid network",
|
||||||
|
address: "foo:///tmp/bar.sock",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tcp uri",
|
||||||
|
address: "tcp://[::]:9090",
|
||||||
|
wantErr: false,
|
||||||
|
network: "tcp",
|
||||||
|
bind: "[::]:9090",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "http uri",
|
||||||
|
address: "http://[::]:9090",
|
||||||
|
wantErr: false,
|
||||||
|
network: "tcp",
|
||||||
|
bind: "[::]:9090",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "https uri",
|
||||||
|
address: "https://[::]:9090",
|
||||||
|
wantErr: false,
|
||||||
|
network: "tcp",
|
||||||
|
bind: "[::]:9090",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
network, bind, err := parseBindNetFromAddr(tt.address)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case tt.wantErr && err == nil:
|
||||||
|
t.Errorf("parseBindNetFromAddr(%q) should have errored but did not", tt.address)
|
||||||
|
case !tt.wantErr && err != nil:
|
||||||
|
t.Errorf("parseBindNetFromAddr(%q) threw an error: %v", tt.address, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if network != tt.network {
|
||||||
|
t.Errorf("parseBindNetFromAddr(%q) wanted network: %q, got: %q", tt.address, tt.network, network)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bind != tt.bind {
|
||||||
|
t.Errorf("parseBindNetFromAddr(%q) wanted bind: %q, got: %q", tt.address, tt.bind, bind)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupListener(t *testing.T) {
|
||||||
|
td := t.TempDir()
|
||||||
|
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
network, address, socketMode string
|
||||||
|
wantErr bool
|
||||||
|
socketURLPrefix string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple tcp",
|
||||||
|
network: "",
|
||||||
|
address: ":0",
|
||||||
|
wantErr: false,
|
||||||
|
socketURLPrefix: "http://localhost:",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "simple unix",
|
||||||
|
network: "",
|
||||||
|
address: "unix://" + filepath.Join(td, "a"),
|
||||||
|
socketMode: "0770",
|
||||||
|
wantErr: false,
|
||||||
|
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tcp",
|
||||||
|
network: "tcp",
|
||||||
|
address: ":0",
|
||||||
|
wantErr: false,
|
||||||
|
socketURLPrefix: "http://localhost:",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "udp",
|
||||||
|
network: "udp",
|
||||||
|
address: ":0",
|
||||||
|
wantErr: true,
|
||||||
|
socketURLPrefix: "http://localhost:",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unix socket",
|
||||||
|
network: "unix",
|
||||||
|
socketMode: "0770",
|
||||||
|
address: filepath.Join(td, "a"),
|
||||||
|
wantErr: false,
|
||||||
|
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid socket mode",
|
||||||
|
network: "unix",
|
||||||
|
socketMode: "taco bell",
|
||||||
|
address: filepath.Join(td, "a"),
|
||||||
|
wantErr: true,
|
||||||
|
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty socket mode",
|
||||||
|
network: "unix",
|
||||||
|
socketMode: "",
|
||||||
|
address: filepath.Join(td, "a"),
|
||||||
|
wantErr: true,
|
||||||
|
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
ln, socketURL, err := SetupListener(tt.network, tt.address, tt.socketMode)
|
||||||
|
switch {
|
||||||
|
case tt.wantErr && err == nil:
|
||||||
|
t.Errorf("SetupListener(%q, %q, %q) should have errored but did not", tt.network, tt.address, tt.socketMode)
|
||||||
|
case !tt.wantErr && err != nil:
|
||||||
|
t.Fatalf("SetupListener(%q, %q, %q) threw an error: %v", tt.network, tt.address, tt.socketMode, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ln != nil {
|
||||||
|
defer ln.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tt.wantErr && !strings.HasPrefix(socketURL, tt.socketURLPrefix) {
|
||||||
|
t.Errorf("SetupListener(%q, %q, %q) should have returned a URL with prefix %q but got: %q", tt.network, tt.address, tt.socketMode, tt.socketURLPrefix, socketURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.socketMode != "" {
|
||||||
|
mode, err := strconv.ParseUint(tt.socketMode, 8, 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sockPath := strings.TrimPrefix(socketURL, "unix:")
|
||||||
|
st, err := os.Stat(sockPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't os.Stat(%q): %v", sockPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if st.Mode().Perm() != fs.FileMode(mode) {
|
||||||
|
t.Errorf("file mode of %q should be %s but is actually %s", sockPath, strconv.FormatUint(mode, 8), strconv.FormatUint(uint64(st.Mode()), 8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -334,6 +334,7 @@ type fileConfig struct {
|
|||||||
DNSBL bool `json:"dnsbl"`
|
DNSBL bool `json:"dnsbl"`
|
||||||
DNSTTL DnsTTL `json:"dns_ttl"`
|
DNSTTL DnsTTL `json:"dns_ttl"`
|
||||||
Logging *Logging `json:"logging"`
|
Logging *Logging `json:"logging"`
|
||||||
|
Metrics *Metrics `json:"metrics,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fileConfig) Valid() error {
|
func (c *fileConfig) Valid() error {
|
||||||
@@ -375,6 +376,12 @@ func (c *fileConfig) Valid() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Metrics != nil {
|
||||||
|
if err := c.Metrics.Valid(); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
return fmt.Errorf("config is not valid:\n%w", errors.Join(errs...))
|
return fmt.Errorf("config is not valid:\n%w", errors.Join(errs...))
|
||||||
}
|
}
|
||||||
@@ -417,6 +424,7 @@ func Load(fin io.Reader, fname string) (*Config, error) {
|
|||||||
StatusCodes: c.StatusCodes,
|
StatusCodes: c.StatusCodes,
|
||||||
Store: c.Store,
|
Store: c.Store,
|
||||||
Logging: c.Logging,
|
Logging: c.Logging,
|
||||||
|
Metrics: c.Metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.OpenGraph.TimeToLive != "" {
|
if c.OpenGraph.TimeToLive != "" {
|
||||||
@@ -508,6 +516,7 @@ type Config struct {
|
|||||||
Logging *Logging
|
Logging *Logging
|
||||||
DNSBL bool
|
DNSBL bool
|
||||||
DNSTTL DnsTTL
|
DNSTTL DnsTTL
|
||||||
|
Metrics *Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) Valid() error {
|
func (c Config) Valid() error {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidMetricsConfig = errors.New("config: invalid metrics configuration")
|
||||||
|
ErrNoMetricsBind = errors.New("config.Metrics: must define bind")
|
||||||
|
ErrNoMetricsNetwork = errors.New("config.Metrics: must define network")
|
||||||
|
ErrNoMetricsSocketMode = errors.New("config.Metrics: must define socket mode when using unix sockets")
|
||||||
|
ErrInvalidMetricsSocketMode = errors.New("config.Metrics: invalid unix socket mode")
|
||||||
|
ErrInvalidMetricsNetwork = errors.New("config.Metrics: invalid metrics network")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Metrics struct {
|
||||||
|
Bind string `json:"bind" yaml:"bind"`
|
||||||
|
Network string `json:"network" yaml:"network"`
|
||||||
|
SocketMode string `json:"socketMode" yaml:"socketMode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metrics) Valid() error {
|
||||||
|
var errs []error
|
||||||
|
|
||||||
|
if m.Bind == "" {
|
||||||
|
errs = append(errs, ErrNoMetricsBind)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Network == "" {
|
||||||
|
errs = append(errs, ErrNoMetricsNetwork)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch m.Network {
|
||||||
|
case "tcp", "tcp4", "tcp6": // https://pkg.go.dev/net#Listen
|
||||||
|
case "unix":
|
||||||
|
if m.SocketMode == "" {
|
||||||
|
errs = append(errs, ErrNoMetricsSocketMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := strconv.ParseUint(m.SocketMode, 8, 0); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("%w: %w", ErrInvalidMetricsSocketMode, err))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
errs = append(errs, ErrInvalidMetricsNetwork)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) != 0 {
|
||||||
|
return errors.Join(ErrInvalidMetricsConfig, errors.Join(errs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMetricsValid(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
input *Metrics
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "basic TCP",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: ":9090",
|
||||||
|
Network: "tcp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "basic TCP4",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: ":9090",
|
||||||
|
Network: "tcp4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "basic TCP6",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: ":9090",
|
||||||
|
Network: "tcp6",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "basic unix",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: "/tmp/anubis-metrics.sock",
|
||||||
|
Network: "unix",
|
||||||
|
SocketMode: "0770",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no bind",
|
||||||
|
input: &Metrics{},
|
||||||
|
err: ErrNoMetricsBind,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no network",
|
||||||
|
input: &Metrics{},
|
||||||
|
err: ErrNoMetricsNetwork,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no unix socket mode",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: "/tmp/anubis-metrics.sock",
|
||||||
|
Network: "unix",
|
||||||
|
},
|
||||||
|
err: ErrNoMetricsSocketMode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid unix socket mode",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: "/tmp/anubis-metrics.sock",
|
||||||
|
Network: "unix",
|
||||||
|
SocketMode: "taco bell",
|
||||||
|
},
|
||||||
|
err: ErrInvalidMetricsSocketMode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid network",
|
||||||
|
input: &Metrics{
|
||||||
|
Bind: ":9090",
|
||||||
|
Network: "taco",
|
||||||
|
},
|
||||||
|
err: ErrInvalidMetricsNetwork,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := tt.input.Valid(); !errors.Is(err, tt.err) {
|
||||||
|
t.Logf("wanted error: %v", tt.err)
|
||||||
|
t.Logf("got error: %v", err)
|
||||||
|
t.Error("validation failed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: taco
|
||||||
+5
-1
@@ -5,5 +5,9 @@
|
|||||||
"remote_addresses": ["0.0.0.0/0", "::/0"],
|
"remote_addresses": ["0.0.0.0/0", "::/0"],
|
||||||
"action": "ALLOW"
|
"action": "ALLOW"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,3 +4,7 @@ bots:
|
|||||||
- "0.0.0.0/0"
|
- "0.0.0.0/0"
|
||||||
- "::/0"
|
- "::/0"
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+5
-1
@@ -8,5 +8,9 @@
|
|||||||
"action": "DENY"
|
"action": "DENY"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dnsbl": false
|
"dnsbl": false,
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,3 +3,7 @@ bots:
|
|||||||
headers_regex:
|
headers_regex:
|
||||||
CF-Worker: .*
|
CF-Worker: .*
|
||||||
action: DENY
|
action: DENY
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -4,3 +4,7 @@ bots:
|
|||||||
asns:
|
asns:
|
||||||
match:
|
match:
|
||||||
- 13335 # Cloudflare
|
- 13335 # Cloudflare
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+5
-1
@@ -5,5 +5,9 @@
|
|||||||
"user_agent_regex": "Mozilla",
|
"user_agent_regex": "Mozilla",
|
||||||
"action": "CHALLENGE"
|
"action": "CHALLENGE"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,7 @@ bots:
|
|||||||
- name: generic-browser
|
- name: generic-browser
|
||||||
user_agent_regex: Mozilla
|
user_agent_regex: Mozilla
|
||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -6,3 +6,7 @@ bots:
|
|||||||
- name: "test"
|
- name: "test"
|
||||||
user_agent_regex: ".*"
|
user_agent_regex: ".*"
|
||||||
action: "DENY"
|
action: "DENY"
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -6,3 +6,7 @@ bots:
|
|||||||
- '"Accept" in headers'
|
- '"Accept" in headers'
|
||||||
- headers["Accept"].contains("text/html")
|
- headers["Accept"].contains("text/html")
|
||||||
- randInt(1) == 0
|
- randInt(1) == 0
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+5
-1
@@ -6,5 +6,9 @@
|
|||||||
"action": "DENY"
|
"action": "DENY"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dnsbl": false
|
"dnsbl": false,
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,7 @@ bots:
|
|||||||
- name: everything
|
- name: everything
|
||||||
user_agent_regex: .*
|
user_agent_regex: .*
|
||||||
action: DENY
|
action: DENY
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -4,3 +4,7 @@ bots:
|
|||||||
geoip:
|
geoip:
|
||||||
countries:
|
countries:
|
||||||
- US
|
- US
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+5
-1
@@ -10,5 +10,9 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -6,3 +6,7 @@ bots:
|
|||||||
- userAgent.startsWith("git/") || userAgent.contains("libgit")
|
- userAgent.startsWith("git/") || userAgent.contains("libgit")
|
||||||
- >
|
- >
|
||||||
"Git-Protocol" in headers && headers["Git-Protocol"] == "version=2"
|
"Git-Protocol" in headers && headers["Git-Protocol"] == "version=2"
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+5
-1
@@ -3,5 +3,9 @@
|
|||||||
{
|
{
|
||||||
"import": "./testdata/hack-test.json"
|
"import": "./testdata/hack-test.json"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
bots:
|
bots:
|
||||||
- import: ./testdata/hack-test.yaml
|
- import: ./testdata/hack-test.yaml
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -3,5 +3,9 @@
|
|||||||
{
|
{
|
||||||
"import": "(data)/common/keep-internet-working.yaml"
|
"import": "(data)/common/keep-internet-working.yaml"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
bots:
|
bots:
|
||||||
- import: (data)/common/keep-internet-working.yaml
|
- import: (data)/common/keep-internet-working.yaml
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -8,3 +8,7 @@ impressum:
|
|||||||
page:
|
page:
|
||||||
title: Test
|
title: Test
|
||||||
body: <p>This is a test</p>
|
body: <p>This is a test</p>
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -13,3 +13,7 @@ logs:
|
|||||||
oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish
|
oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish
|
||||||
compress: true
|
compress: true
|
||||||
useLocalTime: false # timezone for rotated files is UTC
|
useLocalTime: false # timezone for rotated files is UTC
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -5,3 +5,7 @@ bots:
|
|||||||
|
|
||||||
logging:
|
logging:
|
||||||
sink: "stdio"
|
sink: "stdio"
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -6,3 +6,7 @@ bots:
|
|||||||
adjust: 5
|
adjust: 5
|
||||||
|
|
||||||
thresholds: []
|
thresholds: []
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+5
-1
@@ -75,5 +75,9 @@
|
|||||||
"user_agent_regex": "Mozilla",
|
"user_agent_regex": "Mozilla",
|
||||||
"action": "CHALLENGE"
|
"action": "CHALLENGE"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,3 +10,7 @@ openGraph:
|
|||||||
default:
|
default:
|
||||||
"og:title": "Xe's magic land of fun"
|
"og:title": "Xe's magic land of fun"
|
||||||
"og:description": "We're no strangers to love, you know the rules and so do I"
|
"og:description": "We're no strangers to love, you know the rules and so do I"
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -4,3 +4,7 @@ bots:
|
|||||||
user_agent_regex: Mozilla
|
user_agent_regex: Mozilla
|
||||||
weight:
|
weight:
|
||||||
adjust: 5
|
adjust: 5
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -9,5 +9,9 @@
|
|||||||
"status_codes": {
|
"status_codes": {
|
||||||
"CHALLENGE": 200,
|
"CHALLENGE": 200,
|
||||||
"DENY": 200
|
"DENY": 200
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,3 +6,7 @@ bots:
|
|||||||
status_codes:
|
status_codes:
|
||||||
CHALLENGE: 200
|
CHALLENGE: 200
|
||||||
DENY: 200
|
DENY: 200
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -9,5 +9,9 @@
|
|||||||
"status_codes": {
|
"status_codes": {
|
||||||
"CHALLENGE": 403,
|
"CHALLENGE": 403,
|
||||||
"DENY": 403
|
"DENY": 403
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"bind": ":9090",
|
||||||
|
"network": "tcp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,3 +6,7 @@ bots:
|
|||||||
status_codes:
|
status_codes:
|
||||||
CHALLENGE: 403
|
CHALLENGE: 403
|
||||||
DENY: 403
|
DENY: 403
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
+4
@@ -33,3 +33,7 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -2,3 +2,7 @@ bots:
|
|||||||
- name: weight
|
- name: weight
|
||||||
action: WEIGH
|
action: WEIGH
|
||||||
user_agent_regex: Mozilla
|
user_agent_regex: Mozilla
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
bind: ":9090"
|
||||||
|
network: "tcp"
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/http/pprof"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/config"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
healthv1 "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Config *config.Metrics
|
||||||
|
Log *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Run(ctx context.Context, done func()) error {
|
||||||
|
defer done()
|
||||||
|
lg := s.Log.With("subsystem", "metrics")
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
|
||||||
|
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
|
||||||
|
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
|
||||||
|
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
|
||||||
|
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
|
||||||
|
mux.Handle("/metrics", promhttp.Handler())
|
||||||
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
st, ok := internal.GetHealth("anubis")
|
||||||
|
if !ok {
|
||||||
|
slog.Error("health service anubis does not exist, file a bug")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch st {
|
||||||
|
case healthv1.HealthCheckResponse_NOT_SERVING:
|
||||||
|
http.Error(w, "NOT OK", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
case healthv1.HealthCheckResponse_SERVING:
|
||||||
|
fmt.Fprintln(w, "OK")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
http.Error(w, "UNKNOWN", http.StatusFailedDependency)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
srv := http.Server{
|
||||||
|
Handler: mux,
|
||||||
|
ErrorLog: internal.GetFilteredHTTPLogger(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, metricsURL, err := internal.SetupListener(s.Config.Bind, s.Config.Network, s.Config.SocketMode)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't setup listener: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
lg.Debug("listening for metrics", "url", metricsURL)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
c, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := srv.Shutdown(c); err != nil {
|
||||||
|
lg.Error("can't shut down metrics server", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := srv.Serve(ln); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
return fmt.Errorf("can't serve metrics server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ type ParsedConfig struct {
|
|||||||
DnsCache *dns.DnsCache
|
DnsCache *dns.DnsCache
|
||||||
Dns *dns.Dns
|
Dns *dns.Dns
|
||||||
Logger *slog.Logger
|
Logger *slog.Logger
|
||||||
|
Metrics *config.Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
func newParsedConfig(orig *config.Config) *ParsedConfig {
|
func newParsedConfig(orig *config.Config) *ParsedConfig {
|
||||||
@@ -53,6 +54,7 @@ func newParsedConfig(orig *config.Config) *ParsedConfig {
|
|||||||
orig: orig,
|
orig: orig,
|
||||||
OpenGraph: orig.OpenGraph,
|
OpenGraph: orig.OpenGraph,
|
||||||
StatusCodes: orig.StatusCodes,
|
StatusCodes: orig.StatusCodes,
|
||||||
|
Metrics: orig.Metrics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+146
-146
@@ -10,15 +10,15 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-js": "^5.2.0",
|
"@aws-crypto/sha256-js": "^5.2.0",
|
||||||
"preact": "^10.29.0"
|
"preact": "^10.29.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^20.5.0",
|
"@commitlint/cli": "^20.5.0",
|
||||||
"@commitlint/config-conventional": "^20.5.0",
|
"@commitlint/config-conventional": "^20.5.0",
|
||||||
"baseline-browser-mapping": "^2.10.8",
|
"baseline-browser-mapping": "^2.10.15",
|
||||||
"cssnano": "^7.1.3",
|
"cssnano": "^7.1.4",
|
||||||
"cssnano-preset-advanced": "^7.0.11",
|
"cssnano-preset-advanced": "^7.0.12",
|
||||||
"esbuild": "^0.27.4",
|
"esbuild": "^0.28.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"playwright": "^1.52.0",
|
"playwright": "^1.52.0",
|
||||||
"postcss-cli": "^11.0.1",
|
"postcss-cli": "^11.0.1",
|
||||||
@@ -91,6 +91,13 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@colordx/core": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@colordx/core/-/core-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-xBQ0MYRTNNxW3mS2sJtlQTT7C3Sasqgh1/PsHva7fyDb5uqYY+gv9V0utDdX8X80mqzbGz3u/IDJdn2d/uW09g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@commitlint/cli": {
|
"node_modules/@commitlint/cli": {
|
||||||
"version": "20.5.0",
|
"version": "20.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz",
|
||||||
@@ -401,9 +408,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
|
||||||
"integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==",
|
"integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -418,9 +425,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
|
||||||
"integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==",
|
"integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -435,9 +442,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==",
|
"integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -452,9 +459,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==",
|
"integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -469,9 +476,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
|
"integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -486,9 +493,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==",
|
"integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -503,9 +510,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==",
|
"integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -520,9 +527,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==",
|
"integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -537,9 +544,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
|
||||||
"integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==",
|
"integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -554,9 +561,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==",
|
"integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -571,9 +578,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
|
||||||
"integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==",
|
"integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -588,9 +595,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
|
||||||
"integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==",
|
"integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
@@ -605,9 +612,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
|
||||||
"integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==",
|
"integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
@@ -622,9 +629,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
|
||||||
"integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==",
|
"integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -639,9 +646,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
|
||||||
"integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==",
|
"integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@@ -656,9 +663,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
|
||||||
"integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==",
|
"integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -673,9 +680,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==",
|
"integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -690,9 +697,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-arm64": {
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==",
|
"integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -707,9 +714,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==",
|
"integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -724,9 +731,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-arm64": {
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==",
|
"integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -741,9 +748,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==",
|
"integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -758,9 +765,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openharmony-arm64": {
|
"node_modules/@esbuild/openharmony-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==",
|
"integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -775,9 +782,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==",
|
"integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -792,9 +799,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
|
||||||
"integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==",
|
"integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -809,9 +816,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
|
||||||
"integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==",
|
"integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -826,9 +833,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
|
||||||
"integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==",
|
"integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1048,9 +1055,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.10.8",
|
"version": "2.10.15",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.15.tgz",
|
||||||
"integrity": "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==",
|
"integrity": "sha512-1nfKCq9wuAZFTkA2ey/3OXXx7GzFjLdkTiFVNwlJ9WqdI706CZRIhEqjuwanjMIja+84jDLa9rcyZDPDiVkASQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -1242,13 +1249,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/colord": {
|
|
||||||
"version": "2.9.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
|
|
||||||
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "11.1.0",
|
"version": "11.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
|
||||||
@@ -1436,13 +1436,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cssnano": {
|
"node_modules/cssnano": {
|
||||||
"version": "7.1.3",
|
"version": "7.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.4.tgz",
|
||||||
"integrity": "sha512-mLFHQAzyapMVFLiJIn7Ef4C2UCEvtlTlbyILR6B5ZsUAV3D/Pa761R5uC1YPhyBkRd3eqaDm2ncaNrD7R4mTRg==",
|
"integrity": "sha512-T9PNS7y+5Nc9Qmu9mRONqfxG1RVY7Vuvky0XN6MZ+9hqplesTEwnj9r0ROtVuSwUVfaDhVlavuzWIVLUgm4hkQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano-preset-default": "^7.0.11",
|
"cssnano-preset-default": "^7.0.12",
|
||||||
"lilconfig": "^3.1.3"
|
"lilconfig": "^3.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1457,15 +1457,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cssnano-preset-advanced": {
|
"node_modules/cssnano-preset-advanced": {
|
||||||
"version": "7.0.11",
|
"version": "7.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-7.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-7.0.12.tgz",
|
||||||
"integrity": "sha512-k9Dz/8TBOmLojoMZ+2xwrGjscU1XwYVDVB9T1AmvZcwiWz4ibWm8/y+/SN5jhYcpMPTeDe7FhI2uEYlNq1iDGg==",
|
"integrity": "sha512-S+UCfEMBCaYqNmjY+yCTNh4ur+B83z5qpwkzUMER6kVpdQ5CBUxIkALZGhp2KPP3M4VefRCIBMqJ6Z0PFMwvEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"autoprefixer": "^10.4.27",
|
"autoprefixer": "^10.4.27",
|
||||||
"browserslist": "^4.28.1",
|
"browserslist": "^4.28.1",
|
||||||
"cssnano-preset-default": "^7.0.11",
|
"cssnano-preset-default": "^7.0.12",
|
||||||
"postcss-discard-unused": "^7.0.5",
|
"postcss-discard-unused": "^7.0.5",
|
||||||
"postcss-merge-idents": "^7.0.1",
|
"postcss-merge-idents": "^7.0.1",
|
||||||
"postcss-reduce-idents": "^7.0.1",
|
"postcss-reduce-idents": "^7.0.1",
|
||||||
@@ -1479,9 +1479,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cssnano-preset-default": {
|
"node_modules/cssnano-preset-default": {
|
||||||
"version": "7.0.11",
|
"version": "7.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.12.tgz",
|
||||||
"integrity": "sha512-waWlAMuCakP7//UCY+JPrQS1z0OSLeOXk2sKWJximKWGupVxre50bzPlvpbUwZIDylhf/ptf0Pk+Yf7C+hoa3g==",
|
"integrity": "sha512-B3Eoouzw/sl2zANI0AL9KbacummJTCww+fkHaDBMZad/xuVx8bUduPLly6hKVQAlrmvYkS1jB1CVQEKm3gn0AA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1489,7 +1489,7 @@
|
|||||||
"css-declaration-sorter": "^7.2.0",
|
"css-declaration-sorter": "^7.2.0",
|
||||||
"cssnano-utils": "^5.0.1",
|
"cssnano-utils": "^5.0.1",
|
||||||
"postcss-calc": "^10.1.1",
|
"postcss-calc": "^10.1.1",
|
||||||
"postcss-colormin": "^7.0.6",
|
"postcss-colormin": "^7.0.7",
|
||||||
"postcss-convert-values": "^7.0.9",
|
"postcss-convert-values": "^7.0.9",
|
||||||
"postcss-discard-comments": "^7.0.6",
|
"postcss-discard-comments": "^7.0.6",
|
||||||
"postcss-discard-duplicates": "^7.0.2",
|
"postcss-discard-duplicates": "^7.0.2",
|
||||||
@@ -1498,7 +1498,7 @@
|
|||||||
"postcss-merge-longhand": "^7.0.5",
|
"postcss-merge-longhand": "^7.0.5",
|
||||||
"postcss-merge-rules": "^7.0.8",
|
"postcss-merge-rules": "^7.0.8",
|
||||||
"postcss-minify-font-values": "^7.0.1",
|
"postcss-minify-font-values": "^7.0.1",
|
||||||
"postcss-minify-gradients": "^7.0.1",
|
"postcss-minify-gradients": "^7.0.2",
|
||||||
"postcss-minify-params": "^7.0.6",
|
"postcss-minify-params": "^7.0.6",
|
||||||
"postcss-minify-selectors": "^7.0.6",
|
"postcss-minify-selectors": "^7.0.6",
|
||||||
"postcss-normalize-charset": "^7.0.1",
|
"postcss-normalize-charset": "^7.0.1",
|
||||||
@@ -1709,9 +1709,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.27.4",
|
"version": "0.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
|
||||||
"integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==",
|
"integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -1722,32 +1722,32 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/aix-ppc64": "0.27.4",
|
"@esbuild/aix-ppc64": "0.28.0",
|
||||||
"@esbuild/android-arm": "0.27.4",
|
"@esbuild/android-arm": "0.28.0",
|
||||||
"@esbuild/android-arm64": "0.27.4",
|
"@esbuild/android-arm64": "0.28.0",
|
||||||
"@esbuild/android-x64": "0.27.4",
|
"@esbuild/android-x64": "0.28.0",
|
||||||
"@esbuild/darwin-arm64": "0.27.4",
|
"@esbuild/darwin-arm64": "0.28.0",
|
||||||
"@esbuild/darwin-x64": "0.27.4",
|
"@esbuild/darwin-x64": "0.28.0",
|
||||||
"@esbuild/freebsd-arm64": "0.27.4",
|
"@esbuild/freebsd-arm64": "0.28.0",
|
||||||
"@esbuild/freebsd-x64": "0.27.4",
|
"@esbuild/freebsd-x64": "0.28.0",
|
||||||
"@esbuild/linux-arm": "0.27.4",
|
"@esbuild/linux-arm": "0.28.0",
|
||||||
"@esbuild/linux-arm64": "0.27.4",
|
"@esbuild/linux-arm64": "0.28.0",
|
||||||
"@esbuild/linux-ia32": "0.27.4",
|
"@esbuild/linux-ia32": "0.28.0",
|
||||||
"@esbuild/linux-loong64": "0.27.4",
|
"@esbuild/linux-loong64": "0.28.0",
|
||||||
"@esbuild/linux-mips64el": "0.27.4",
|
"@esbuild/linux-mips64el": "0.28.0",
|
||||||
"@esbuild/linux-ppc64": "0.27.4",
|
"@esbuild/linux-ppc64": "0.28.0",
|
||||||
"@esbuild/linux-riscv64": "0.27.4",
|
"@esbuild/linux-riscv64": "0.28.0",
|
||||||
"@esbuild/linux-s390x": "0.27.4",
|
"@esbuild/linux-s390x": "0.28.0",
|
||||||
"@esbuild/linux-x64": "0.27.4",
|
"@esbuild/linux-x64": "0.28.0",
|
||||||
"@esbuild/netbsd-arm64": "0.27.4",
|
"@esbuild/netbsd-arm64": "0.28.0",
|
||||||
"@esbuild/netbsd-x64": "0.27.4",
|
"@esbuild/netbsd-x64": "0.28.0",
|
||||||
"@esbuild/openbsd-arm64": "0.27.4",
|
"@esbuild/openbsd-arm64": "0.28.0",
|
||||||
"@esbuild/openbsd-x64": "0.27.4",
|
"@esbuild/openbsd-x64": "0.28.0",
|
||||||
"@esbuild/openharmony-arm64": "0.27.4",
|
"@esbuild/openharmony-arm64": "0.28.0",
|
||||||
"@esbuild/sunos-x64": "0.27.4",
|
"@esbuild/sunos-x64": "0.28.0",
|
||||||
"@esbuild/win32-arm64": "0.27.4",
|
"@esbuild/win32-arm64": "0.28.0",
|
||||||
"@esbuild/win32-ia32": "0.27.4",
|
"@esbuild/win32-ia32": "0.28.0",
|
||||||
"@esbuild/win32-x64": "0.27.4"
|
"@esbuild/win32-x64": "0.28.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
@@ -2554,15 +2554,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-colormin": {
|
"node_modules/postcss-colormin": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.7.tgz",
|
||||||
"integrity": "sha512-oXM2mdx6IBTRm39797QguYzVEWzbdlFiMNfq88fCCN1Wepw3CYmJ/1/Ifa/KjWo+j5ZURDl2NTldLJIw51IeNQ==",
|
"integrity": "sha512-sBQ628lSj3VQpDquQel8Pen5mmjFPsO4pH9lDLaHB1AVkMRHtkl0pRB5DCWznc9upWsxint/kV+AveSj7W1tew==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@colordx/core": "^5.0.0",
|
||||||
"browserslist": "^4.28.1",
|
"browserslist": "^4.28.1",
|
||||||
"caniuse-api": "^3.0.0",
|
"caniuse-api": "^3.0.0",
|
||||||
"colord": "^2.9.3",
|
|
||||||
"postcss-value-parser": "^4.2.0"
|
"postcss-value-parser": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2808,13 +2808,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-minify-gradients": {
|
"node_modules/postcss-minify-gradients": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.2.tgz",
|
||||||
"integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==",
|
"integrity": "sha512-fVY3AB8Um7SJR5usHqTY2Ngf9qh8IRN+FFzrBP0ONJy6yYXsP7xyjK2BvSAIrpgs1cST+H91V0TXi3diHLYJtw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colord": "^2.9.3",
|
"@colordx/core": "^5.0.0",
|
||||||
"cssnano-utils": "^5.0.1",
|
"cssnano-utils": "^5.0.1",
|
||||||
"postcss-value-parser": "^4.2.0"
|
"postcss-value-parser": "^4.2.0"
|
||||||
},
|
},
|
||||||
@@ -3182,9 +3182,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/preact": {
|
"node_modules/preact": {
|
||||||
"version": "10.29.0",
|
"version": "10.29.1",
|
||||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz",
|
||||||
"integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==",
|
"integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
|||||||
+5
-5
@@ -22,10 +22,10 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^20.5.0",
|
"@commitlint/cli": "^20.5.0",
|
||||||
"@commitlint/config-conventional": "^20.5.0",
|
"@commitlint/config-conventional": "^20.5.0",
|
||||||
"baseline-browser-mapping": "^2.10.8",
|
"baseline-browser-mapping": "^2.10.15",
|
||||||
"cssnano": "^7.1.3",
|
"cssnano": "^7.1.4",
|
||||||
"cssnano-preset-advanced": "^7.0.11",
|
"cssnano-preset-advanced": "^7.0.12",
|
||||||
"esbuild": "^0.27.4",
|
"esbuild": "^0.28.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"playwright": "^1.52.0",
|
"playwright": "^1.52.0",
|
||||||
"postcss-cli": "^11.0.1",
|
"postcss-cli": "^11.0.1",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-js": "^5.2.0",
|
"@aws-crypto/sha256-js": "^5.2.0",
|
||||||
"preact": "^10.29.0"
|
"preact": "^10.29.1"
|
||||||
},
|
},
|
||||||
"commitlint": {
|
"commitlint": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|||||||
Reference in New Issue
Block a user