mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-16 08:26:49 +01:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc19a54976 | ||
|
|
12d999809f | ||
|
|
6771293336 | ||
|
|
d240c9dfee | ||
|
|
c7eda38933 | ||
|
|
09caa888ad | ||
|
|
e41a487371 | ||
|
|
7c08a8da2e | ||
|
|
82df824490 | ||
|
|
2f341001c1 |
28
.github/workflows/merge-main-into-compat.yml
vendored
28
.github/workflows/merge-main-into-compat.yml
vendored
@@ -1,28 +0,0 @@
|
||||
name: Merge Main Into Compat
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Configure git user
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
- name: Merge main into compat
|
||||
run: |
|
||||
git fetch origin compat
|
||||
git checkout compat
|
||||
git merge --no-edit origin/main
|
||||
- name: Push compat
|
||||
run: |
|
||||
git push origin compat
|
||||
3
Makefile
3
Makefile
@@ -80,6 +80,7 @@ test:
|
||||
docker-build-test:
|
||||
docker build -t godoxy .
|
||||
docker build --build-arg=MAKE_ARGS=agent=1 -t godoxy-agent .
|
||||
docker build --build-arg=MAKE_ARGS=socket-proxy=1 -t godoxy-socket-proxy .
|
||||
|
||||
go_ver := $(shell go version | cut -d' ' -f3 | cut -d'o' -f2)
|
||||
files := $(shell find . -name go.mod -type f -or -name Dockerfile -type f)
|
||||
@@ -110,7 +111,7 @@ mod-tidy:
|
||||
|
||||
build:
|
||||
mkdir -p $(shell dirname ${BIN_PATH})
|
||||
cd ${PWD} && go build ${BUILD_FLAGS} -o ${BIN_PATH} ./cmd
|
||||
go build -C ${PWD} ${BUILD_FLAGS} -o ${BIN_PATH} ./cmd
|
||||
${POST_BUILD}
|
||||
|
||||
run:
|
||||
|
||||
@@ -41,7 +41,6 @@ require (
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.17.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/diskfs/go-diskfs v1.7.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
@@ -64,7 +63,6 @@ require (
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.19.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gotify/server/v2 v2.7.3 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
@@ -118,7 +116,6 @@ require (
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.33.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
|
||||
2
goutils
2
goutils
Submodule goutils updated: c81cc80244...3fd00b70fa
@@ -16,16 +16,17 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/yusing/godoxy/internal/common"
|
||||
gperr "github.com/yusing/goutils/errs"
|
||||
strutils "github.com/yusing/goutils/strings"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Email string `json:"email,omitempty"`
|
||||
Domains []string `json:"domains,omitempty"`
|
||||
CertPath string `json:"cert_path,omitempty"`
|
||||
KeyPath string `json:"key_path,omitempty"`
|
||||
ACMEKeyPath string `json:"acme_key_path,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Options map[string]any `json:"options,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Domains []string `json:"domains,omitempty"`
|
||||
CertPath string `json:"cert_path,omitempty"`
|
||||
KeyPath string `json:"key_path,omitempty"`
|
||||
ACMEKeyPath string `json:"acme_key_path,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Options map[string]strutils.Redacted `json:"options,omitempty"`
|
||||
|
||||
Resolvers []string `json:"resolvers,omitempty"`
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/yusing/godoxy/internal/serialization"
|
||||
gperr "github.com/yusing/goutils/errs"
|
||||
strutils "github.com/yusing/goutils/strings"
|
||||
)
|
||||
|
||||
type Generator func(map[string]any) (challenge.Provider, gperr.Error)
|
||||
type Generator func(map[string]strutils.Redacted) (challenge.Provider, gperr.Error)
|
||||
|
||||
var Providers = make(map[string]Generator)
|
||||
|
||||
@@ -14,10 +15,10 @@ func DNSProvider[CT any, PT challenge.Provider](
|
||||
defaultCfg func() *CT,
|
||||
newProvider func(*CT) (PT, error),
|
||||
) Generator {
|
||||
return func(opt map[string]any) (challenge.Provider, gperr.Error) {
|
||||
return func(opt map[string]strutils.Redacted) (challenge.Provider, gperr.Error) {
|
||||
cfg := defaultCfg()
|
||||
if len(opt) > 0 {
|
||||
err := serialization.MapUnmarshalValidate(opt, &cfg)
|
||||
err := serialization.MapUnmarshalValidate(serialization.ToSerializedObject(opt), &cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Submodule internal/go-oidc updated: d599436494...0118916d67
Submodule internal/gopsutil updated: 5f60518fa5...cb4cb59837
@@ -178,7 +178,7 @@ func (cfg *MaxMind) doReq(method string) (*http.Response, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.SetBasicAuth(cfg.AccountID, cfg.LicenseKey)
|
||||
req.SetBasicAuth(cfg.AccountID, cfg.LicenseKey.String())
|
||||
resp, err := doReq(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
gperr "github.com/yusing/goutils/errs"
|
||||
strutils "github.com/yusing/goutils/strings"
|
||||
)
|
||||
|
||||
type (
|
||||
DatabaseType string
|
||||
Config struct {
|
||||
AccountID string `json:"account_id" validate:"required"`
|
||||
LicenseKey string `json:"license_key" validate:"required"`
|
||||
Database DatabaseType `json:"database" validate:"omitempty,oneof=geolite geoip2"`
|
||||
AccountID string `json:"account_id" validate:"required"`
|
||||
LicenseKey strutils.Redacted `json:"license_key" validate:"required"`
|
||||
Database DatabaseType `json:"database" validate:"omitempty,oneof=geolite geoip2"`
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -197,10 +197,16 @@ func (m *Middleware) ServeHTTP(next http.HandlerFunc, w http.ResponseWriter, r *
|
||||
}
|
||||
|
||||
if exec, ok := m.impl.(ResponseModifier); ok {
|
||||
rm := httputils.NewResponseModifier(w)
|
||||
defer rm.FlushRelease()
|
||||
next(rm, r)
|
||||
lrm := httputils.NewLazyResponseModifier(w, needsBuffering)
|
||||
defer lrm.FlushRelease()
|
||||
next(lrm, r)
|
||||
|
||||
// Skip modification if response wasn't buffered (non-HTML content)
|
||||
if !lrm.IsBuffered() {
|
||||
return
|
||||
}
|
||||
|
||||
rm := lrm.ResponseModifier()
|
||||
currentBody := rm.BodyReader()
|
||||
currentResp := &http.Response{
|
||||
StatusCode: rm.StatusCode(),
|
||||
@@ -228,6 +234,12 @@ func (m *Middleware) ServeHTTP(next http.HandlerFunc, w http.ResponseWriter, r *
|
||||
}
|
||||
}
|
||||
|
||||
// needsBuffering determines if a response should be buffered for modification.
|
||||
// Only HTML responses need buffering; streaming content (video, audio, etc.) should pass through.
|
||||
func needsBuffering(header http.Header) bool {
|
||||
return httputils.GetContentType(header).IsHTML()
|
||||
}
|
||||
|
||||
func (m *Middleware) LogWarn(req *http.Request) *zerolog.Event {
|
||||
return log.Warn().Str("middleware", m.name).
|
||||
Str("host", req.Host).
|
||||
|
||||
@@ -11,13 +11,14 @@ import (
|
||||
"github.com/luthermonson/go-proxmox"
|
||||
"github.com/yusing/godoxy/internal/net/gphttp"
|
||||
gperr "github.com/yusing/goutils/errs"
|
||||
strutils "github.com/yusing/goutils/strings"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
URL string `json:"url" validate:"required,url"`
|
||||
|
||||
TokenID string `json:"token_id" validate:"required"`
|
||||
Secret string `json:"secret" validate:"required"`
|
||||
TokenID string `json:"token_id" validate:"required"`
|
||||
Secret strutils.Redacted `json:"secret" validate:"required"`
|
||||
|
||||
NoTLSVerify bool `json:"no_tls_verify" yaml:"no_tls_verify,omitempty"`
|
||||
|
||||
@@ -48,7 +49,7 @@ func (c *Config) Init() gperr.Error {
|
||||
}
|
||||
|
||||
opts := []proxmox.Option{
|
||||
proxmox.WithAPIToken(c.TokenID, c.Secret),
|
||||
proxmox.WithAPIToken(c.TokenID, c.Secret.String()),
|
||||
proxmox.WithHTTPClient(&http.Client{
|
||||
Transport: tr,
|
||||
}),
|
||||
|
||||
@@ -2,10 +2,6 @@ package routes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@@ -34,7 +30,8 @@ func (r *RouteContext) Value(key any) any {
|
||||
func WithRouteContext(r *http.Request, route types.HTTPRoute) *http.Request {
|
||||
// we don't want to copy the request object every fucking requests
|
||||
// return r.WithContext(context.WithValue(r.Context(), routeContextKey, route))
|
||||
(*requestInternal)(unsafe.Pointer(r)).ctx = &RouteContext{
|
||||
ctxFieldPtr := (*context.Context)(unsafe.Pointer(uintptr(unsafe.Pointer(r)) + ctxFieldOffset))
|
||||
*ctxFieldPtr = &RouteContext{
|
||||
Context: r.Context(),
|
||||
Route: route,
|
||||
}
|
||||
@@ -107,43 +104,12 @@ func TryGetUpstreamURL(r *http.Request) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type requestInternal struct {
|
||||
Method string
|
||||
URL *url.URL
|
||||
Proto string
|
||||
ProtoMajor int
|
||||
ProtoMinor int
|
||||
Header http.Header
|
||||
Body io.ReadCloser
|
||||
GetBody func() (io.ReadCloser, error)
|
||||
ContentLength int64
|
||||
TransferEncoding []string
|
||||
Close bool
|
||||
Host string
|
||||
Form url.Values
|
||||
PostForm url.Values
|
||||
MultipartForm *multipart.Form
|
||||
Trailer http.Header
|
||||
RemoteAddr string
|
||||
RequestURI string
|
||||
TLS *tls.ConnectionState
|
||||
Cancel <-chan struct{}
|
||||
Response *http.Response
|
||||
Pattern string
|
||||
ctx context.Context
|
||||
}
|
||||
var ctxFieldOffset uintptr
|
||||
|
||||
func init() {
|
||||
// make sure ctx has the same offset as http.Request
|
||||
f, ok := reflect.TypeFor[requestInternal]().FieldByName("ctx")
|
||||
f, ok := reflect.TypeFor[http.Request]().FieldByName("ctx")
|
||||
if !ok {
|
||||
panic("ctx field not found")
|
||||
}
|
||||
f2, ok := reflect.TypeFor[http.Request]().FieldByName("ctx")
|
||||
if !ok {
|
||||
panic("ctx field not found")
|
||||
}
|
||||
if f.Offset != f2.Offset {
|
||||
panic(fmt.Sprintf("ctx has different offset than http.Request: %d != %d", f.Offset, f2.Offset))
|
||||
}
|
||||
ctxFieldOffset = f.Offset
|
||||
}
|
||||
|
||||
@@ -21,6 +21,22 @@ import (
|
||||
|
||||
type SerializedObject = map[string]any
|
||||
|
||||
// ToSerializedObject converts a map[string]VT to a SerializedObject.
|
||||
func ToSerializedObject[VT any](m map[string]VT) SerializedObject {
|
||||
so := make(SerializedObject, len(m))
|
||||
for k, v := range m {
|
||||
so[k] = v
|
||||
}
|
||||
return so
|
||||
}
|
||||
|
||||
func init() {
|
||||
strutils.SetJSONMarshaler(sonic.Marshal)
|
||||
strutils.SetJSONUnmarshaler(sonic.Unmarshal)
|
||||
strutils.SetYAMLMarshaler(yaml.Marshal)
|
||||
strutils.SetYAMLUnmarshaler(yaml.Unmarshal)
|
||||
}
|
||||
|
||||
type MapUnmarshaller interface {
|
||||
UnmarshalMap(m map[string]any) gperr.Error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user