Add 3 yaml models (traefik and docker registry), Add a sanitizer for frontend user input
- commit
- 43cd92f1073cfeca94b6c0b0af4f0e11e052f3dc
- author
- bnema · · 2023-09-04 17:48 UTC
- committer
- bnema · · 2023-09-04 21:45 UTC
- parent
- d5beb42
- signature
- unsigned
7 files · +101 -3
M go.mod +4 -0
| @@ -13,6 +13,7 @@ require ( | |||
| 13 | 13 | require ( | |
| 14 | 14 | github.com/Microsoft/go-winio v0.6.1 // indirect | |
| 15 | 15 | github.com/andybalholm/cascadia v1.3.1 // indirect | |
| 16 | + | github.com/aymerick/douceur v0.2.0 // indirect | |
| 16 | 17 | github.com/containerd/containerd v1.7.5 // indirect | |
| 17 | 18 | github.com/docker/distribution v2.8.2+incompatible // indirect | |
| 18 | 19 | github.com/docker/go-connections v0.4.0 // indirect | |
| @@ -20,9 +21,11 @@ require ( | |||
| 20 | 21 | github.com/gogo/protobuf v1.3.2 // indirect | |
| 21 | 22 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | |
| 22 | 23 | github.com/gorilla/context v1.1.1 // indirect | |
| 24 | + | github.com/gorilla/css v1.0.0 // indirect | |
| 23 | 25 | github.com/gorilla/securecookie v1.1.1 // indirect | |
| 24 | 26 | github.com/gorilla/sessions v1.2.1 // indirect | |
| 25 | 27 | github.com/klauspost/compress v1.16.7 // indirect | |
| 28 | + | github.com/microcosm-cc/bluemonday v1.0.25 // indirect | |
| 26 | 29 | github.com/moby/patternmatcher v0.6.0 // indirect | |
| 27 | 30 | github.com/moby/sys/sequential v0.5.0 // indirect | |
| 28 | 31 | github.com/moby/term v0.5.0 // indirect | |
| @@ -41,6 +44,7 @@ require ( | |||
| 41 | 44 | ) | |
| 42 | 45 | ||
| 43 | 46 | require ( | |
| 47 | + | github.com/google/safehtml v0.1.0 | |
| 44 | 48 | github.com/labstack/echo-contrib v0.15.0 | |
| 45 | 49 | github.com/labstack/gommon v0.4.0 | |
| 46 | 50 | github.com/mattn/go-colorable v0.1.13 // indirect | |
| @@ -13,6 +13,7 @@ require ( | |||||
| 13 | require ( | 13 | require ( | ||
| 14 | github.com/Microsoft/go-winio v0.6.1 // indirect | 14 | github.com/Microsoft/go-winio v0.6.1 // indirect | ||
| 15 | github.com/andybalholm/cascadia v1.3.1 // indirect | 15 | github.com/andybalholm/cascadia v1.3.1 // indirect | ||
| 16 | + | github.com/aymerick/douceur v0.2.0 // indirect | |||
| 16 | github.com/containerd/containerd v1.7.5 // indirect | 17 | github.com/containerd/containerd v1.7.5 // indirect | ||
| 17 | github.com/docker/distribution v2.8.2+incompatible // indirect | 18 | github.com/docker/distribution v2.8.2+incompatible // indirect | ||
| 18 | github.com/docker/go-connections v0.4.0 // indirect | 19 | github.com/docker/go-connections v0.4.0 // indirect | ||
| @@ -20,9 +21,11 @@ require ( | |||||
| 20 | github.com/gogo/protobuf v1.3.2 // indirect | 21 | github.com/gogo/protobuf v1.3.2 // indirect | ||
| 21 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | 22 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | ||
| 22 | github.com/gorilla/context v1.1.1 // indirect | 23 | github.com/gorilla/context v1.1.1 // indirect | ||
| 24 | + | github.com/gorilla/css v1.0.0 // indirect | |||
| 23 | github.com/gorilla/securecookie v1.1.1 // indirect | 25 | github.com/gorilla/securecookie v1.1.1 // indirect | ||
| 24 | github.com/gorilla/sessions v1.2.1 // indirect | 26 | github.com/gorilla/sessions v1.2.1 // indirect | ||
| 25 | github.com/klauspost/compress v1.16.7 // indirect | 27 | github.com/klauspost/compress v1.16.7 // indirect | ||
| 28 | + | github.com/microcosm-cc/bluemonday v1.0.25 // indirect | |||
| 26 | github.com/moby/patternmatcher v0.6.0 // indirect | 29 | github.com/moby/patternmatcher v0.6.0 // indirect | ||
| 27 | github.com/moby/sys/sequential v0.5.0 // indirect | 30 | github.com/moby/sys/sequential v0.5.0 // indirect | ||
| 28 | github.com/moby/term v0.5.0 // indirect | 31 | github.com/moby/term v0.5.0 // indirect | ||
| @@ -41,6 +44,7 @@ require ( | |||||
| 41 | ) | 44 | ) | ||
| 42 | 45 | ||||
| 43 | require ( | 46 | require ( | ||
| 47 | + | github.com/google/safehtml v0.1.0 | |||
| 44 | github.com/labstack/echo-contrib v0.15.0 | 48 | github.com/labstack/echo-contrib v0.15.0 | ||
| 45 | github.com/labstack/gommon v0.4.0 | 49 | github.com/labstack/gommon v0.4.0 | ||
| 46 | github.com/mattn/go-colorable v0.1.13 // indirect | 50 | github.com/mattn/go-colorable v0.1.13 // indirect | ||
M go.sum +8 -0 generated file: collapsed
A pkg/templating/models/registry-compose.goyml +15 -0
| @@ -0,0 +1,15 @@ | |||
| 1 | + | registry: | |
| 2 | + | restart: always | |
| 3 | + | image: registry:2 | |
| 4 | + | ports: | |
| 5 | + | - 5000:5000 | |
| 6 | + | environment: | |
| 7 | + | REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt | |
| 8 | + | REGISTRY_HTTP_TLS_KEY: /certs/domain.key | |
| 9 | + | REGISTRY_AUTH: htpasswd | |
| 10 | + | REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd | |
| 11 | + | REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm | |
| 12 | + | volumes: | |
| 13 | + | - /path/data:/var/lib/registry | |
| 14 | + | - /path/certs:/certs | |
| 15 | + | - /path/auth:/auth⏎̸ | |
| @@ -0,0 +1,15 @@ | |||||
| 1 | + | registry: | |||
| 2 | + | restart: always | |||
| 3 | + | image: registry:2 | |||
| 4 | + | ports: | |||
| 5 | + | - 5000:5000 | |||
| 6 | + | environment: | |||
| 7 | + | REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt | |||
| 8 | + | REGISTRY_HTTP_TLS_KEY: /certs/domain.key | |||
| 9 | + | REGISTRY_AUTH: htpasswd | |||
| 10 | + | REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd | |||
| 11 | + | REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm | |||
| 12 | + | volumes: | |||
| 13 | + | - /path/data:/var/lib/registry | |||
| 14 | + | - /path/certs:/certs | |||
| 15 | + | - /path/auth:/auth⏎̸ | |||
A pkg/templating/models/traefik-compose.goyml +21 -0
| @@ -0,0 +1,21 @@ | |||
| 1 | + | version: "3" | |
| 2 | + | ||
| 3 | + | services: | |
| 4 | + | traefik: | |
| 5 | + | image: traefik:v2.10.4 | |
| 6 | + | container_name: traefik | |
| 7 | + | restart: unless-stopped | |
| 8 | + | ports: | |
| 9 | + | - "80:80" | |
| 10 | + | - "443:443" | |
| 11 | + | volumes: | |
| 12 | + | - /var/run/docker.sock:/var/run/docker.sock:ro | |
| 13 | + | - /home/brice/traefik/data/traefik.yml:/etc/traefik/traefik.yml | |
| 14 | + | - /home/brice/traefik/data/acme.json:/acme.json | |
| 15 | + | labels: | |
| 16 | + | - "traefik.enable=true" | |
| 17 | + | - "traefik.http.routers.api.rule=Host(`traefik.{{ topdomain }}`)" | |
| 18 | + | - "traefik.http.routers.api.service=api@internal" | |
| 19 | + | - "traefik.http.routers.api.entrypoints=websecure" | |
| 20 | + | - "traefik.http.routers.api.tls.certresolver=myresolver" | |
| 21 | + | - "traefik.http.services.api.loadbalancer.server.port=8080" | |
| @@ -0,0 +1,21 @@ | |||||
| 1 | + | version: "3" | |||
| 2 | + | ||||
| 3 | + | services: | |||
| 4 | + | traefik: | |||
| 5 | + | image: traefik:v2.10.4 | |||
| 6 | + | container_name: traefik | |||
| 7 | + | restart: unless-stopped | |||
| 8 | + | ports: | |||
| 9 | + | - "80:80" | |||
| 10 | + | - "443:443" | |||
| 11 | + | volumes: | |||
| 12 | + | - /var/run/docker.sock:/var/run/docker.sock:ro | |||
| 13 | + | - /home/brice/traefik/data/traefik.yml:/etc/traefik/traefik.yml | |||
| 14 | + | - /home/brice/traefik/data/acme.json:/acme.json | |||
| 15 | + | labels: | |||
| 16 | + | - "traefik.enable=true" | |||
| 17 | + | - "traefik.http.routers.api.rule=Host(`traefik.{{ topdomain }}`)" | |||
| 18 | + | - "traefik.http.routers.api.service=api@internal" | |||
| 19 | + | - "traefik.http.routers.api.entrypoints=websecure" | |||
| 20 | + | - "traefik.http.routers.api.tls.certresolver=myresolver" | |||
| 21 | + | - "traefik.http.services.api.loadbalancer.server.port=8080" | |||
A pkg/templating/models/traefik.goyml +26 -0
| @@ -0,0 +1,26 @@ | |||
| 1 | + | api: | |
| 2 | + | dashboard: true | |
| 3 | + | ||
| 4 | + | entryPoints: | |
| 5 | + | web: | |
| 6 | + | address: ":80" | |
| 7 | + | websecure: | |
| 8 | + | address: ":443" | |
| 9 | + | ||
| 10 | + | providers: | |
| 11 | + | docker: | |
| 12 | + | endpoint: "unix:///var/run/docker.sock" | |
| 13 | + | exposedByDefault: false | |
| 14 | + | ||
| 15 | + | certificatesResolvers: | |
| 16 | + | myresolver: | |
| 17 | + | acme: | |
| 18 | + | email: {{ admin.email }} | |
| 19 | + | storage: acme.json | |
| 20 | + | httpChallenge: | |
| 21 | + | entryPoint: web | |
| 22 | + | ||
| 23 | + | log: | |
| 24 | + | level: "DEBUG" # Set the desired log level: DEBUG, INFO, WARN, ERROR, FATAL, PANIC | |
| 25 | + | ||
| 26 | + | accessLog: {} | |
| @@ -0,0 +1,26 @@ | |||||
| 1 | + | api: | |||
| 2 | + | dashboard: true | |||
| 3 | + | ||||
| 4 | + | entryPoints: | |||
| 5 | + | web: | |||
| 6 | + | address: ":80" | |||
| 7 | + | websecure: | |||
| 8 | + | address: ":443" | |||
| 9 | + | ||||
| 10 | + | providers: | |||
| 11 | + | docker: | |||
| 12 | + | endpoint: "unix:///var/run/docker.sock" | |||
| 13 | + | exposedByDefault: false | |||
| 14 | + | ||||
| 15 | + | certificatesResolvers: | |||
| 16 | + | myresolver: | |||
| 17 | + | acme: | |||
| 18 | + | email: {{ admin.email }} | |||
| 19 | + | storage: acme.json | |||
| 20 | + | httpChallenge: | |||
| 21 | + | entryPoint: web | |||
| 22 | + | ||||
| 23 | + | log: | |||
| 24 | + | level: "DEBUG" # Set the desired log level: DEBUG, INFO, WARN, ERROR, FATAL, PANIC | |||
| 25 | + | ||||
| 26 | + | accessLog: {} | |||
A pkg/templating/sanitizer.go +22 -0
| @@ -0,0 +1,22 @@ | |||
| 1 | + | package templating | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "fmt" | |
| 5 | + | ||
| 6 | + | "github.com/microcosm-cc/bluemonday" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | // SanitizeHTML sanitizes HTML input using bluemonday package and returns an error if sanitization altered the input. | |
| 10 | + | func SanitizeHTML(htmlInput string) (string, error) { | |
| 11 | + | // Create a new UGC policy | |
| 12 | + | p := bluemonday.UGCPolicy() | |
| 13 | + | ||
| 14 | + | // Sanitize the input HTML | |
| 15 | + | sanitized := p.Sanitize(htmlInput) | |
| 16 | + | ||
| 17 | + | if sanitized != htmlInput { | |
| 18 | + | return sanitized, fmt.Errorf("HTML input was altered during sanitization") | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | return sanitized, nil | |
| 22 | + | } | |
| @@ -0,0 +1,22 @@ | |||||
| 1 | + | package templating | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "fmt" | |||
| 5 | + | ||||
| 6 | + | "github.com/microcosm-cc/bluemonday" | |||
| 7 | + | ) | |||
| 8 | + | ||||
| 9 | + | // SanitizeHTML sanitizes HTML input using bluemonday package and returns an error if sanitization altered the input. | |||
| 10 | + | func SanitizeHTML(htmlInput string) (string, error) { | |||
| 11 | + | // Create a new UGC policy | |||
| 12 | + | p := bluemonday.UGCPolicy() | |||
| 13 | + | ||||
| 14 | + | // Sanitize the input HTML | |||
| 15 | + | sanitized := p.Sanitize(htmlInput) | |||
| 16 | + | ||||
| 17 | + | if sanitized != htmlInput { | |||
| 18 | + | return sanitized, fmt.Errorf("HTML input was altered during sanitization") | |||
| 19 | + | } | |||
| 20 | + | ||||
| 21 | + | return sanitized, nil | |||
| 22 | + | } | |||
R pkg/utils/txt-render.go → pkg/templating/txt-render.go +5 -3 renamed, 84% similar
| @@ -1,17 +1,19 @@ | |||
| 1 | - | package utils | |
| 1 | + | package templating | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
| 5 | 5 | "errors" | |
| 6 | 6 | "io/fs" | |
| 7 | 7 | "text/template" | |
| 8 | + | ||
| 9 | + | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 8 | 10 | ) | |
| 9 | 11 | ||
| 10 | 12 | type TXTRenderer struct { | |
| 11 | 13 | Models *template.Template | |
| 12 | 14 | Format string | |
| 13 | 15 | ParseError error | |
| 14 | - | Logger *Logger | |
| 16 | + | Logger *utils.Logger | |
| 15 | 17 | } | |
| 16 | 18 | ||
| 17 | 19 | // Render function renders the template with the given data | |
| @@ -39,7 +41,7 @@ func (r *TXTRenderer) TXTRender(data interface{}) (string, error) { | |||
| 39 | 41 | } | |
| 40 | 42 | ||
| 41 | 43 | // GetRenderer function returns a new Renderer instance | |
| 42 | - | func GetTXTRenderer(filename string, fs fs.FS, logger *Logger) (*TXTRenderer, error) { | |
| 44 | + | func GetTXTRenderer(filename string, fs fs.FS, logger *utils.Logger) (*TXTRenderer, error) { | |
| 43 | 45 | mdls, err := template.New(filename).ParseFS(fs, filename) | |
| 44 | 46 | if err != nil { | |
| 45 | 47 | logger.Error().Err(err).Msg("Failed to parse template") | |
| @@ -1,17 +1,19 @@ | |||||
| 1 | - | package utils | 1 | + | package templating |
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "bytes" | 4 | "bytes" | ||
| 5 | "errors" | 5 | "errors" | ||
| 6 | "io/fs" | 6 | "io/fs" | ||
| 7 | "text/template" | 7 | "text/template" | ||
| 8 | + | ||||
| 9 | + | "gogs.bnema.dev/gordon-echo/pkg/utils" | |||
| 8 | ) | 10 | ) | ||
| 9 | 11 | ||||
| 10 | type TXTRenderer struct { | 12 | type TXTRenderer struct { | ||
| 11 | Models *template.Template | 13 | Models *template.Template | ||
| 12 | Format string | 14 | Format string | ||
| 13 | ParseError error | 15 | ParseError error | ||
| 14 | - | Logger *Logger | 16 | + | Logger *utils.Logger |
| 15 | } | 17 | } | ||
| 16 | 18 | ||||
| 17 | // Render function renders the template with the given data | 19 | // Render function renders the template with the given data | ||
| @@ -39,7 +41,7 @@ func (r *TXTRenderer) TXTRender(data interface{}) (string, error) { | |||||
| 39 | } | 41 | } | ||
| 40 | 42 | ||||
| 41 | // GetRenderer function returns a new Renderer instance | 43 | // GetRenderer function returns a new Renderer instance | ||
| 42 | - | func GetTXTRenderer(filename string, fs fs.FS, logger *Logger) (*TXTRenderer, error) { | 44 | + | func GetTXTRenderer(filename string, fs fs.FS, logger *utils.Logger) (*TXTRenderer, error) { |
| 43 | mdls, err := template.New(filename).ParseFS(fs, filename) | 45 | mdls, err := template.New(filename).ParseFS(fs, filename) | ||
| 44 | if err != nil { | 46 | if err != nil { | ||
| 45 | logger.Error().Err(err).Msg("Failed to parse template") | 47 | logger.Error().Err(err).Msg("Failed to parse template") | ||