Skip to content

Commit ef94cbc

Browse files
committed
feat(relayd): store and query TLS fingerprints
Release-Status: cut Signed-off-by: Xe Iaso <[email protected]>
1 parent 972cc99 commit ef94cbc

File tree

4 files changed

+127
-7
lines changed

4 files changed

+127
-7
lines changed

cmd/relayd/main.go

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package main
33
import (
44
"context"
55
"crypto/tls"
6+
"database/sql"
7+
"errors"
68
"flag"
79
"fmt"
810
"log"
@@ -19,16 +21,20 @@ import (
1921
"syscall"
2022
"time"
2123

24+
"github.com/avct/uasurfer"
2225
"github.com/google/uuid"
26+
"github.com/jackc/puddle/v2"
27+
_ "modernc.org/sqlite"
2328
"within.website/x/internal"
2429
)
2530

2631
var (
27-
bind = flag.String("bind", ":3004", "port to listen on")
28-
certDir = flag.String("cert-dir", "/xe/pki", "where to read mounted certificates from")
29-
certFname = flag.String("cert-fname", "tls.crt", "certificate filename")
30-
keyFname = flag.String("key-fname", "tls.key", "key filename")
31-
proxyTo = flag.String("proxy-to", "http://localhost:5000", "where to reverse proxy to")
32+
bind = flag.String("bind", ":3004", "port to listen on")
33+
certDir = flag.String("cert-dir", "/xe/pki", "where to read mounted certificates from")
34+
certFname = flag.String("cert-fname", "tls.crt", "certificate filename")
35+
fpDatabase = flag.String("fp-database", "", "location of fingerprint database")
36+
keyFname = flag.String("key-fname", "tls.key", "key filename")
37+
proxyTo = flag.String("proxy-to", "http://localhost:5000", "where to reverse proxy to")
3238
)
3339

3440
func main() {
@@ -38,6 +44,7 @@ func main() {
3844
"bind", *bind,
3945
"cert-dir", *certDir,
4046
"cert-fname", *certFname,
47+
"fp-database", *fpDatabase,
4148
"key-fname", *keyFname,
4249
"proxy-to", *proxyTo,
4350
)
@@ -82,6 +89,24 @@ func main() {
8289
log.Fatal(err)
8390
}
8491

92+
var db *sql.DB
93+
94+
if fpDatabase != nil {
95+
var err error
96+
db, err = sql.Open("sqlite", *fpDatabase)
97+
if err != nil {
98+
log.Fatal(err)
99+
}
100+
if err := db.Ping(); err != nil {
101+
log.Fatal(err)
102+
}
103+
}
104+
105+
uaParser, err := uaParserPool()
106+
if err != nil {
107+
log.Fatal(err)
108+
}
109+
85110
h := httputil.NewSingleHostReverseProxy(u)
86111
oldDirector := h.Director
87112

@@ -117,6 +142,47 @@ func main() {
117142
// req.Header.Set("X-TCP-Fingerprint-JA4T", tcpFP.String())
118143
// }
119144

145+
if uap, err := uaParser.Acquire(req.Context()); err == nil {
146+
defer uap.Release()
147+
148+
uasurfer.ParseUserAgent(req.UserAgent(), uap.Value())
149+
150+
vers := uap.Value().Browser.Version
151+
152+
req.Header.Set("Xe-X-Relayd-UserAgent-Browser", uap.Value().Browser.Name.StringTrimPrefix())
153+
req.Header.Set("Xe-X-Relayd-UserAgent-Browser-Version", fmt.Sprintf("%d.%d.%d", vers.Major, vers.Minor, vers.Patch))
154+
req.Header.Set("Xe-X-Relayd-UserAgent-OS", uap.Value().OS.Name.StringTrimPrefix())
155+
req.Header.Set("Xe-X-Relayd-UserAgent-Platform", uap.Value().OS.Platform.StringTrimPrefix())
156+
}
157+
158+
if ja4 := req.Header.Get("X-TLS-Fingerprint-JA4"); db != nil && ja4 != "" {
159+
var application, userAgent, notes sql.NullString
160+
if err := db.QueryRowContext(req.Context(), "SELECT application, user_agent_string, notes FROM fingerprints WHERE ja4_fingerprint = ?", ja4).Scan(&application, &userAgent, &notes); err == nil {
161+
slog.Debug("found a hit", "application", application, "userAgent", userAgent, "notes", notes)
162+
if application.Valid {
163+
req.Header.Set("Xe-X-Relayd-Ja4-Application", application.String)
164+
}
165+
166+
if userAgent.Valid {
167+
req.Header.Set("Xe-X-Relayd-Ja4-UserAgent", userAgent.String)
168+
}
169+
170+
if notes.Valid {
171+
req.Header.Set("Xe-X-Relayd-Ja4-Notes", notes.String)
172+
}
173+
} else if errors.Is(err, sql.ErrNoRows) {
174+
userAgent := req.UserAgent()
175+
notes := fmt.Sprintf("Observed via relayd on host %s at %s", req.Host, time.Now().Format(time.RFC3339))
176+
if _, err := db.ExecContext(req.Context(), "INSERT INTO fingerprints(user_agent_string, notes, ja4_fingerprint) VALUES (?, ?, ?)", userAgent, notes, ja4); err != nil {
177+
slog.Error("can't insert fingerprint into database", "err", err)
178+
}
179+
180+
req.Header.Set("Xe-X-Relayd-New-Client", "true")
181+
} else {
182+
slog.Debug("can't read from database", "err", err)
183+
}
184+
}
185+
120186
req.Header.Set("X-Forwarded-Host", req.URL.Host)
121187
req.Header.Set("X-Forwarded-Proto", "https")
122188
req.Header.Set("X-Forwarded-Scheme", "https")
@@ -215,3 +281,20 @@ func (kpr *keypairReloader) GetCertificate(*tls.ClientHelloInfo) (*tls.Certifica
215281

216282
return kpr.cert, nil
217283
}
284+
285+
func uaParserPool() (*puddle.Pool[*uasurfer.UserAgent], error) {
286+
cons := func(context.Context) (*uasurfer.UserAgent, error) {
287+
return &uasurfer.UserAgent{}, nil
288+
}
289+
des := func(ua *uasurfer.UserAgent) {
290+
ua.Reset()
291+
}
292+
293+
pool, err := puddle.NewPool(&puddle.Config[*uasurfer.UserAgent]{
294+
Constructor: cons,
295+
Destructor: des,
296+
MaxSize: 512,
297+
})
298+
299+
return pool, err
300+
}

cmd/relayd/relayd.service

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ Restart=always
77
RestartSec=30s
88
EnvironmentFile=/etc/within.website/x/relayd.env
99
LimitNOFILE=infinity
10+
DynamicUser=true
11+
CacheDirectory=relayd
12+
CacheDirectoryMode=0755
13+
StateDirectory=relayd
14+
StateDirectoryMode=0755
15+
ReadWritePaths=/run
1016

1117
[Install]
1218
WantedBy=multi-user.target

go.mod

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ require (
9090
github.com/TecharoHQ/yeet v0.2.1 // indirect
9191
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect
9292
github.com/andybalholm/brotli v1.1.1 // indirect
93+
github.com/avct/uasurfer v0.0.0-20250320214457-f1f6afeb74db // indirect
9394
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 // indirect
9495
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.29 // indirect
9596
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
@@ -109,6 +110,7 @@ require (
109110
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
110111
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
111112
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c // indirect
113+
github.com/dustin/go-humanize v1.0.1 // indirect
112114
github.com/ebitengine/purego v0.8.2 // indirect
113115
github.com/emirpasic/gods v1.18.1 // indirect
114116
github.com/evanw/esbuild v0.19.11 // indirect
@@ -128,7 +130,7 @@ require (
128130
github.com/goccy/go-yaml v1.12.0 // indirect
129131
github.com/gogo/protobuf v1.3.2 // indirect
130132
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
131-
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
133+
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
132134
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a // indirect
133135
github.com/goreleaser/chglog v0.7.0 // indirect
134136
github.com/goreleaser/fileglob v1.3.0 // indirect
@@ -152,6 +154,7 @@ require (
152154
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
153155
github.com/ipld/go-car/v2 v2.13.1 // indirect
154156
github.com/ipld/go-ipld-prime v0.21.0 // indirect
157+
github.com/jackc/puddle/v2 v2.2.2 // indirect
155158
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
156159
github.com/jbenet/goprocess v0.1.4 // indirect
157160
github.com/jinzhu/inflection v1.0.0 // indirect
@@ -183,12 +186,14 @@ require (
183186
github.com/natefinch/atomic v1.0.1 // indirect
184187
github.com/nats-io/nkeys v0.4.9 // indirect
185188
github.com/nats-io/nuid v1.0.1 // indirect
189+
github.com/ncruces/go-strftime v0.1.9 // indirect
186190
github.com/ncruces/julianday v1.0.0 // indirect
187191
github.com/opentracing/opentracing-go v1.2.0 // indirect
188192
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect
189193
github.com/pjbgf/sha1cd v0.3.2 // indirect
190194
github.com/pkg/term v1.2.0-beta.2 // indirect
191195
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
196+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
192197
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
193198
github.com/segmentio/asm v1.2.0 // indirect
194199
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
@@ -222,6 +227,10 @@ require (
222227
gopkg.in/yaml.v2 v2.4.0 // indirect
223228
gopkg.in/yaml.v3 v3.0.1 // indirect
224229
lukechampine.com/blake3 v1.2.1 // indirect
230+
modernc.org/libc v1.62.1 // indirect
231+
modernc.org/mathutil v1.7.1 // indirect
232+
modernc.org/memory v1.9.1 // indirect
233+
modernc.org/sqlite v1.37.0 // indirect
225234
)
226235

227236
require (
@@ -263,7 +272,7 @@ require (
263272
github.com/sacOO7/go-logger v0.0.0-20180719173527-9ac9add5a50d // indirect
264273
github.com/sacOO7/gowebsocket v0.0.0-20221109081133-70ac927be105
265274
github.com/sendgrid/rest v2.6.9+incompatible // indirect
266-
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
275+
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
267276
golang.org/x/image v0.24.0
268277
golang.org/x/mod v0.24.0 // indirect
269278
golang.org/x/net v0.39.0

go.sum

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
119119
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
120120
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
121121
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
122+
github.com/avct/uasurfer v0.0.0-20250320214457-f1f6afeb74db h1:Bk7CPE8ZVhOKA11SZlplKBRWfo17OyyPj0t1dgYN2qI=
123+
github.com/avct/uasurfer v0.0.0-20250320214457-f1f6afeb74db/go.mod h1:s+GCtuP4kZNxh1WGoqdWI1+PbluBcycrMMWuKQ9e5Nk=
122124
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
123125
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
124126
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 h1:zAxi9p3wsZMIaVCdoiQp2uZ9k1LsZvmAnoTBeZPXom0=
@@ -245,6 +247,8 @@ github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yA
245247
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
246248
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c h1:mxWGS0YyquJ/ikZOjSrRjjFIbUqIP9ojyYQ+QZTU3Rg=
247249
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
250+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
251+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
248252
github.com/eaburns/peggy v1.0.2 h1:RJwNVF4cvzLGiKInHGBT8sVwP5HDuVP/PaBU9tHO9Rk=
249253
github.com/eaburns/peggy v1.0.2/go.mod h1:X2pbl0EV5erfnK8kSGwo0lBCgMGokvR1E6KerAoDKXg=
250254
github.com/eaburns/pretty v1.0.0 h1:00W1wrrtMXUSqLPN0txS8j7g9qFXy6nA5vZVqVQOo6w=
@@ -442,6 +446,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
442446
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
443447
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
444448
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
449+
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
450+
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
445451
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
446452
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a h1:JJBdjSfqSy3mnDT0940ASQFghwcZ4y4cb6ttjAoXqwE=
447453
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI=
@@ -548,6 +554,8 @@ github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH
548554
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
549555
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
550556
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw=
557+
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
558+
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
551559
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
552560
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
553561
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
@@ -692,6 +700,8 @@ github.com/ncruces/go-sqlite3 v0.16.0 h1:O7eULuEjvSBnS1QCN+dDL/ixLQZoUGWr466A02G
692700
github.com/ncruces/go-sqlite3 v0.16.0/go.mod h1:2TmAeD93ImsKXJRsUIKohfMvt17dZSbS6pzJ3k6YYFg=
693701
github.com/ncruces/go-sqlite3/gormlite v0.16.0 h1:pBN2h323adfTF3NThIuHa3e7GCesgqrDZFEdAmdFNQE=
694702
github.com/ncruces/go-sqlite3/gormlite v0.16.0/go.mod h1:TyfqjFmR31x1iOth4t6hPgtUf2UvM8zupKSj6TZkP4c=
703+
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
704+
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
695705
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
696706
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
697707
github.com/nicklaw5/helix/v2 v2.31.0 h1:/8E5H20D/f3PGmSWT5NWtjwt+M8/GeCjnK/AkoLIFQA=
@@ -769,6 +779,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
769779
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
770780
github.com/redis/go-redis/v9 v9.5.5 h1:51VEyMF8eOO+NUHFm8fpg+IOc1xFuFOhxs3R+kPu1FM=
771781
github.com/redis/go-redis/v9 v9.5.5/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
782+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
783+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
772784
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
773785
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
774786
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -969,6 +981,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
969981
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
970982
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
971983
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
984+
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
985+
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
972986
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
973987
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
974988
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1498,6 +1512,14 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
14981512
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
14991513
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
15001514
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
1515+
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
1516+
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
1517+
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
1518+
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
1519+
modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
1520+
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
1521+
modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
1522+
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
15011523
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
15021524
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
15031525
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

0 commit comments

Comments
 (0)