Skip to content

kraciasty/stzr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

stzr

Go Reference Go Report Card GitHub go.mod Go version GitHub codecov

HTML sanitization using struct tags. Powered by bluemonday.

Rationale

Becoming fed up with manually sanitizing every string field in complex nested structures, I created a tag-based approach to handle HTML sanitization declaratively.

Features

A sane input sanitization experience:

  • Tag-based - just add the tag
  • Recursive - handles nested structs, slices, maps, pointers, generics
  • Built-in policies: strict and ugc powered by bluemonday policies
  • Extensible with policies or custom functions

Quickstart

go get -u github.com/kraciasty/stzr

Basic Usage

import "github.com/kraciasty/stzr"

type Character struct {
    Name string `sanitize:"strict"`
    Bio  string `sanitize:"ugc"`
}

character := &Character{
    Name: `<script>alert('morty')</script>Rick <b>Sanchez</b>`,
    Bio:  `Genius <b>scientist</b> from dimension C-137 <script>alert('wubba lubba dub dub')</script>`,
}

stzr.SanitizeStruct(character)
// Name: "Rick Sanchez"
// Bio:  "Genius <b>scientist</b> from dimension C-137"

Note

Nested structures work automatically - structs, slices, maps, and pointers are processed recursively:

type Episode struct {
    Title          string    `sanitize:"strict"`
    Description    string    `sanitize:"ugc"`
    Comments       []Comment // Nested structs handled automatically
    SkippedComment Comment   `sanitize:"-"` // Skipped
}

type Comment struct {
    Text       string `sanitize:"ugc"`
    Author     string `sanitize:"strict"`
    Dimension  string `sanitize:"strict"`
}

String Sanitization

clean, err := stzr.SanitizeString("ugc", `<script>bad</script>Wubba lubba <b>dub dub</b>!`)
// Returns: "Wubba lubba <b>dub dub</b>!"
Custom Policies
minimal := bluemonday.NewPolicy().AllowElements("b", "i")
links := bluemonday.NewPolicy().
    AllowElements("a").
    AllowAttrs("href").
    OnElements("a")

sanitizer := stzr.New(
    stzr.WithPolicy("minimal", minimal),
    stzr.WithPolicy("links", links),
)

type Blog struct {
    Content string `sanitize:"minimal"`
    Footer  string `sanitize:"links"`
}
Integration with oapi-codegen

Add x-oapi-codegen-extra-tags to your OpenAPI spec:

# openapi.yml
components:
  schemas:
    CreateCharacterRequest:
      type: object
      properties:
        name:
          type: string
          x-oapi-codegen-extra-tags: # <---
            sanitize: "strict"       # strict policy
        backstory:
          type: string
          x-oapi-codegen-extra-tags: # <---
            sanitize: "ugc"          # ugc policy

Generates:

type CreateCharacterRequest struct {
    Name      string `json:"name" sanitize:"strict"`
    Backstory string `json:"backstory" sanitize:"ugc"`
}
Integration with Protocol Buffers

Use something like protoc-go-inject-tag to add sanitization tags to generated protobuf structs:

// character.proto
message CreateCharacterRequest {
  string name = 1;      // @inject_tag: sanitize:"strict"
  string backstory = 2; // @inject_tag: sanitize:"ugc"
}

After generation, run:

protoc-go-inject-tag -input="*.pb.go"

Results in:

type CreateCharacterRequest struct {
    Name      string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty" sanitize:"strict"`
    Backstory string `protobuf:"bytes,2,opt,name=backstory,proto3" json:"backstory,omitempty" sanitize:"ugc"`
}

Documentation

For the Go code documentation reference - check pkg.go.dev.

Contributing

Contributions are welcome! If you find any issues or want to enhance the project, please submit a pull request.

License

This project is licensed under the MIT License. See the LICENSE file for more information.

Packages

 
 
 

Contributors

Languages