pax_global_header00006660000000000000000000000064145527166560014533gustar00rootroot0000000000000052 comment=1908cd17015631bbc0b5e8481652a848cdc49d85 pencode-0.4/000077500000000000000000000000001455271665600130135ustar00rootroot00000000000000pencode-0.4/.github/000077500000000000000000000000001455271665600143535ustar00rootroot00000000000000pencode-0.4/.github/workflows/000077500000000000000000000000001455271665600164105ustar00rootroot00000000000000pencode-0.4/.github/workflows/codeql-analysis.yml000066400000000000000000000050251455271665600222250ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. name: "CodeQL" on: push: branches: [master] pull_request: # The branches below must be a subset of the branches above branches: [master] schedule: - cron: '0 3 * * 4' jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: # Override automatic language detection by changing the below list # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] language: ['go'] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - name: Checkout repository uses: actions/checkout@v2 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 # If this run was triggered by a pull request event, then checkout # the head of the pull request instead of the merge commit. - run: git checkout HEAD^2 if: ${{ github.event_name == 'pull_request' }} # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 pencode-0.4/.goreleaser.yml000066400000000000000000000015311455271665600157440ustar00rootroot00000000000000before: hooks: - go mod tidy - go generate ./... builds: - id: pencode binary: pencode flags: - -trimpath env: - CGO_ENABLED=0 asmflags: - all=-trimpath={{.Env.GOPATH}} gcflags: - all=-trimpath={{.Env.GOPATH}} ldflags: -s -w -extldflags '-static' goos: - linux - windows - darwin - freebsd - openbsd goarch: - amd64 - 386 - arm - arm64 main: ./cmd/pencode ignore: - goos: darwin goarch: 386 archives: - id: tgz format: tar.gz format_overrides: - goos: windows format: zip - goos: darwin format: zip checksum: name_template: 'checksums.txt' snapshot: name_template: "{{ .Tag }}-next" changelog: sort: asc filters: exclude: - '^docs:' - '^test:' pencode-0.4/LICENSE000066400000000000000000000020561455271665600140230ustar00rootroot00000000000000MIT License Copyright (c) 2020 Joona Hoikkala Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.pencode-0.4/README.md000066400000000000000000000077561455271665600143110ustar00rootroot00000000000000# pencode - complex payload encoder Pencode is a tool that helps you to create payload encoding chains. It has been designed to be used in automation whereever it is required to apply multiple encodings to a payload (and possibly inserting the payload to a template in between). `pencoder` can be used as a standalone command line tool or as a library for other Go programs. ## Installation ``` go install github.com/ffuf/pencode/cmd/pencode@latest ``` ### Usage ``` pencode - complex payload encoder v0.4 Usage: ./pencode FUNC1 FUNC2 FUNC3... ./pencode reads input from stdin by default, which is typically piped from another process. OPTIONS: -input reads input from a file, line by line. ENCODERS b64encode - Base64 encoder hexencode - Hex string encoder htmlescape - HTML escape jsonescape - JSON escape unicodeencodeall - Unicode escape string encode (all characters) urlencode - URL encode reserved characters urlencodeall - URL encode all characters utf16 - UTF-16 encoder (Little Endian) utf16be - UTF-16 encoder (Big Endian) xmlescape - XML escape DECODERS b64decode - Base64 decoder hexdecode - Hex string decoder htmlunescape - HTML unescape jsonunescape - JSON unescape unicodedecode - Unicode escape string decode urldecode - URL decode xmlunescape - XML unescape HASHES md5 - MD5 sum sha1 - SHA1 checksum sha224 - SHA224 checksum sha256 - SHA256 checksum sha384 - SHA384 checksum sha512 - SHA512 checksum OTHER filename.tmpl - Replaces string #PAYLOAD# in content of a file that has .tmpl extension. lower - Convert string to lowercase upper - Convert string to uppercase ``` To urlencode, base64encode and hex encode a string: ``` $ echo 'what%ever'|pencode urlencode b64encode hexencode 64326868644355794e5756325a58493d ``` ### Templating Any command line parameter that is a file path ending with `.tmpl` is considered as a template file by pencode. It attempts to read the file content and to replace instances of a string `#PAYLOAD#` within the file with the input in the current encoder chain. ### Shell completion Pencode can provide tab completion for available encoders. Bash, Zsh, and Fish are supported. ``` $ pencode b64decode hexdecode unicodedecode urldecode urlencodeall utf16be ... ``` In order to activate shell completion, you need to inform your shell that completion is available for your script. #### Bash To get auto-complete working you need to `source` the `pencode-completion.bash` file in your `~/.bashrc` or similar: ``` source ~/path/to/pencode-completion.bash ``` #### Zsh To get auto-complete working you need to enable autocomplete _(not needed if you have Oh-My-Zsh)_ using `autoload -U compaudit && compinit` or by putting it into `~/.zshrc` Then `source` the `pencode-completion.zsh` file in your `.zshrc` or similar: ``` source ~/path/to/pencode-completion.zsh ``` #### Fish To get auto-complete working you need to `source` the `pencode-completion.fish` file to your config folder `~/.config/fish/completions/pencode.fish` or similar: ``` source ~/path/to/pencode-completion.fish ``` ### Usage as a library ```go package main import ( "fmt" "github.com/ffuf/pencode/pkg/pencode" ) func main() { inputdata := "Whatever you wish to run through the chain" # A slice of encoders in the preferred encoding chain execution order encoders := []string{ "utf16", "b64encode", } chain := pencode.NewChain() err := chain.Initialize(encoders) if err != nil { panic(err) } output, err := chain.Encode([]byte(inputdata)) if err != nil { panic(err) } fmt.Print(string(output)) } ``` ## License `pencode` is released under MIT license. See [LICENSE](https://github.com/ffuf/pencoder/blob/master/LICENSE). pencode-0.4/cmd/000077500000000000000000000000001455271665600135565ustar00rootroot00000000000000pencode-0.4/cmd/pencode/000077500000000000000000000000001455271665600151735ustar00rootroot00000000000000pencode-0.4/cmd/pencode/main.go000066400000000000000000000032451455271665600164520ustar00rootroot00000000000000package main import ( "bufio" "flag" "fmt" "os" "strings" "github.com/ffuf/pencode/pkg/pencode" ) func main() { chain := pencode.NewChain() inputWordlist := flag.String("input", "", "A wordlist to encode") flag.Usage = func() { fmt.Printf("pencode - complex payload encoder v%s\n\n", pencode.VERSION) fmt.Printf("Usage: %s FUNC1 FUNC2 FUNC3...\n\n", os.Args[0]) fmt.Printf("%s reads input from stdin by default, which is typically piped from another process.\n\n", os.Args[0]) fmt.Printf("OPTIONS:\n-input reads input from a file, line by line.\n\n") chain.Usage() } var listMode bool flag.BoolVar(&listMode, "list", false, "list available encoders") flag.Parse() if listMode { fmt.Println(strings.Join(chain.GetEncoders(), "\n")) os.Exit(1) } if len(os.Args) < 2 { flag.Usage() os.Exit(1) } err := chain.Initialize(flag.Args()) if err != nil { flag.Usage() fmt.Printf("\n[!] %s\n", err) os.Exit(1) } if *inputWordlist != "" { // read the input wordlist and output to stdout file, err := os.Open(*inputWordlist) if err != nil { fmt.Println(err) } defer file.Close() fs := bufio.NewScanner(file) fs.Split(bufio.ScanLines) for fs.Scan() { output, err := chain.Encode(fs.Bytes()) if err != nil { fmt.Printf(" [!] %s\n", err) } fmt.Println(string(output)) } } else { input := readInput() output, err := chain.Encode([]byte(input)) if err != nil { fmt.Printf(" [!] %s\n", err) } fmt.Print(string(output)) } } func readInput() string { input := os.Stdin defer input.Close() reader := bufio.NewScanner(input) data := "" for reader.Scan() { data = data + reader.Text() } return data } pencode-0.4/go.mod000066400000000000000000000000501455271665600141140ustar00rootroot00000000000000module github.com/ffuf/pencode go 1.14 pencode-0.4/pencode-completion.bash000066400000000000000000000000731455271665600174360ustar00rootroot00000000000000#!/usr/bin/env bash complete -W "\$(pencode -list)" pencodepencode-0.4/pencode-completion.fish000066400000000000000000000000541455271665600174510ustar00rootroot00000000000000complete -x -c pencode -a "(pencode -list)" pencode-0.4/pencode-completion.zsh000066400000000000000000000001271455271665600173250ustar00rootroot00000000000000compdef _pencode pencode function _pencode { _arguments "*: :($(pencode -list))" }pencode-0.4/pkg/000077500000000000000000000000001455271665600135745ustar00rootroot00000000000000pencode-0.4/pkg/pencode/000077500000000000000000000000001455271665600152115ustar00rootroot00000000000000pencode-0.4/pkg/pencode/base64decode.go000066400000000000000000000005441455271665600177730ustar00rootroot00000000000000package pencode import ( "encoding/base64" ) type Base64Decoder struct{} func (b Base64Decoder) Encode(input []byte) ([]byte, error) { output, err := base64.StdEncoding.DecodeString(string(input)) return output, err } func (b Base64Decoder) HelpText() string { return "Base64 decoder" } func (b Base64Decoder) Type() string { return "decoders" } pencode-0.4/pkg/pencode/base64encode.go000066400000000000000000000005411455271665600200020ustar00rootroot00000000000000package pencode import ( "encoding/base64" ) type Base64Encoder struct{} func (b Base64Encoder) Encode(input []byte) ([]byte, error) { output := base64.StdEncoding.EncodeToString(input) return []byte(output), nil } func (b Base64Encoder) HelpText() string { return "Base64 encoder" } func (b Base64Encoder) Type() string { return "encoders" } pencode-0.4/pkg/pencode/constants.go000066400000000000000000000000471455271665600175550ustar00rootroot00000000000000package pencode const VERSION = "0.4" pencode-0.4/pkg/pencode/encoders.go000066400000000000000000000066131455271665600173500ustar00rootroot00000000000000package pencode import ( "fmt" "sort" "strings" ) var availableEncoders = map[string]Encoder{ "b64encode": Base64Encoder{}, "b64decode": Base64Decoder{}, "filename.tmpl": Template{}, "hexencode": HexEncoder{}, "hexdecode": HexDecoder{}, "htmlescape": HTMLEscaper{}, "htmlunescape": HTMLUnescaper{}, "jsonescape": JSONEscaper{}, "jsonunescape": JSONUnescaper{}, "lower": StrToLower{}, "md5": MD5Hasher{}, "sha1": SHA1Hasher{}, "sha224": SHA224Hasher{}, "sha256": SHA256Hasher{}, "sha384": SHA384Hasher{}, "sha512": SHA512Hasher{}, "unicodedecode": UnicodeDecode{}, "unicodeencodeall": UnicodeEncodeAll{}, "upper": StrToUpper{}, "urlencode": URLEncoder{}, "urldecode": URLDecoder{}, "urlencodeall": URLEncoderAll{}, "utf16": UTF16LEEncode{}, "utf16be": UTF16BEEncode{}, "xmlescape": XMLEscaper{}, "xmlunescape": XMLUnescaper{}, } type Chain struct { Encoders []Encoder initialized bool actions []string } func NewChain() *Chain { c := Chain{initialized: false} return &c } // Initialize loops through requested names for encoders and sets up the encoder chain. If an unknown encoder is // requested, error will be returned. func (c *Chain) Initialize(actions []string) error { c.actions = actions c.Encoders = make([]Encoder, 0) for _, a := range actions { if ok, err := c.HasEncoder(a); ok { // Templates are a bit special if isTemplate(a) { tenc, err := NewTemplateEncoder(a) if err != nil { return err } c.Encoders = append(c.Encoders, tenc) } else { c.Encoders = append(c.Encoders, availableEncoders[a]) } } else if err != nil { return err } else { return fmt.Errorf("Encoder %s requested but not found.\n", a) } } c.initialized = true return nil } func (c *Chain) Encode(input []byte) ([]byte, error) { var err error if !c.initialized { return []byte{}, fmt.Errorf("Encoder chain not initialized.\n") } for _, e := range c.Encoders { input, err = e.Encode(input) if err != nil { return []byte{}, err } } return input, nil } // HasEncoder returns true if encoder with a specified name is configured func (c *Chain) HasEncoder(name string) (bool, error) { if _, ok := availableEncoders[name]; ok { return true, nil } // Check for template if isTemplate(name) { return hasTemplate(name) } return false, nil } func (c *Chain) GetEncoders() []string { // Sort the encoders alphabetically names := make([]string, 0, len(availableEncoders)) for e := range availableEncoders { names = append(names, e) } sort.Strings(names) return names } // Usage prints the help string for each configured encoder func (c *Chain) Usage() { // Calculate maximum keyword length for nice help formatting max_length := 0 for k := range availableEncoders { if len(k) > max_length { max_length = len(k) } } format := fmt.Sprintf(" %%-%ds- %%s\n", max_length+2) //names := c.GetEncoders() for _, t := range []string{"encoders", "decoders", "hashes", "other"} { fmt.Printf("%s\n", strings.ToUpper(t)) list := []string{} for n, e := range availableEncoders { if e.Type() == t { list = append(list, fmt.Sprintf(format, n, e.HelpText())) } } sort.Strings(list) for _, i := range list { fmt.Print(i) } fmt.Println() } } pencode-0.4/pkg/pencode/hexdecoder.go000066400000000000000000000005271455271665600176560ustar00rootroot00000000000000package pencode import ( "encoding/hex" ) type HexDecoder struct{} func (h HexDecoder) Encode(input []byte) ([]byte, error) { cleaned := removeAllWhitespace(string(input)) return hex.DecodeString(cleaned) } func (h HexDecoder) HelpText() string { return "Hex string decoder" } func (h HexDecoder) Type() string { return "decoders" } pencode-0.4/pkg/pencode/hexencoder.go000066400000000000000000000004651455271665600176710ustar00rootroot00000000000000package pencode import ( "encoding/hex" ) type HexEncoder struct{} func (h HexEncoder) Encode(input []byte) ([]byte, error) { return []byte(hex.EncodeToString(input)), nil } func (h HexEncoder) HelpText() string { return "Hex string encoder" } func (h HexEncoder) Type() string { return "encoders" } pencode-0.4/pkg/pencode/htmldecode.go000066400000000000000000000005051455271665600176500ustar00rootroot00000000000000package pencode import "html" type HTMLUnescaper struct{} func (u HTMLUnescaper) Encode(input []byte) ([]byte, error) { out := html.UnescapeString(string(input)) return []byte(out), nil } func (u HTMLUnescaper) HelpText() string { return "HTML unescape" } func (u HTMLUnescaper) Type() string { return "decoders" } pencode-0.4/pkg/pencode/htmlencode.go000066400000000000000000000004711455271665600176640ustar00rootroot00000000000000package pencode import "html" type HTMLEscaper struct{} func (u HTMLEscaper) Encode(input []byte) ([]byte, error) { out := html.EscapeString(string(input)) return []byte(out), nil } func (u HTMLEscaper) HelpText() string { return "HTML escape" } func (u HTMLEscaper) Type() string { return "encoders" } pencode-0.4/pkg/pencode/interfaces.go000066400000000000000000000001561455271665600176650ustar00rootroot00000000000000package pencode type Encoder interface { Encode([]byte) ([]byte, error) HelpText() string Type() string } pencode-0.4/pkg/pencode/jsondecode.go000066400000000000000000000010021455271665600176460ustar00rootroot00000000000000package pencode import "encoding/json" type JSONUnescaper struct{} type JSONInput struct { Input string `json:"input"` } func (u JSONUnescaper) Encode(input []byte) ([]byte, error) { inputJson := `{"input":"` + string(input) + `"}` var out JSONInput if err := json.Unmarshal([]byte(inputJson), &out); err != nil { return []byte{}, err } return []byte(out.Input), nil } func (u JSONUnescaper) HelpText() string { return "JSON unescape" } func (u JSONUnescaper) Type() string { return "decoders" } pencode-0.4/pkg/pencode/jsonencode.go000066400000000000000000000010231455271665600176630ustar00rootroot00000000000000package pencode import ( "bytes" "encoding/json" ) type JSONEscaper struct{} func (u JSONEscaper) Encode(input []byte) ([]byte, error) { buf := &bytes.Buffer{} enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) // prevents encoding of < and > characters err := enc.Encode(string(input)) if err != nil { return []byte{}, err } output := buf.Bytes() return output[1 : len(output)-2], nil } func (u JSONEscaper) HelpText() string { return "JSON escape" } func (u JSONEscaper) Type() string { return "encoders" } pencode-0.4/pkg/pencode/md5.go000066400000000000000000000004611455271665600162260ustar00rootroot00000000000000package pencode import ( "crypto/md5" "fmt" ) type MD5Hasher struct{} func (m MD5Hasher) Encode(input []byte) ([]byte, error) { return []byte(fmt.Sprintf("%x", md5.Sum(input))), nil } func (m MD5Hasher) HelpText() string { return "MD5 sum" } func (m MD5Hasher) Type() string { return "hashes" } pencode-0.4/pkg/pencode/sha1.go000066400000000000000000000004751455271665600164020ustar00rootroot00000000000000package pencode import ( "crypto/sha1" "fmt" ) type SHA1Hasher struct{} func (m SHA1Hasher) Encode(input []byte) ([]byte, error) { return []byte(fmt.Sprintf("%x", sha1.Sum(input))), nil } func (m SHA1Hasher) HelpText() string { return "SHA1 checksum" } func (m SHA1Hasher) Type() string { return "hashes" } pencode-0.4/pkg/pencode/sha224.go000066400000000000000000000005161455271665600165450ustar00rootroot00000000000000package pencode import ( "crypto/sha256" "fmt" ) type SHA224Hasher struct{} func (m SHA224Hasher) Encode(input []byte) ([]byte, error) { return []byte(fmt.Sprintf("%x", sha256.Sum224(input))), nil } func (m SHA224Hasher) HelpText() string { return "SHA224 checksum" } func (m SHA224Hasher) Type() string { return "hashes" } pencode-0.4/pkg/pencode/sha256.go000066400000000000000000000005161455271665600165520ustar00rootroot00000000000000package pencode import ( "crypto/sha256" "fmt" ) type SHA256Hasher struct{} func (m SHA256Hasher) Encode(input []byte) ([]byte, error) { return []byte(fmt.Sprintf("%x", sha256.Sum256(input))), nil } func (m SHA256Hasher) HelpText() string { return "SHA256 checksum" } func (m SHA256Hasher) Type() string { return "hashes" } pencode-0.4/pkg/pencode/sha384.go000066400000000000000000000005161455271665600165540ustar00rootroot00000000000000package pencode import ( "crypto/sha512" "fmt" ) type SHA384Hasher struct{} func (m SHA384Hasher) Encode(input []byte) ([]byte, error) { return []byte(fmt.Sprintf("%x", sha512.Sum384(input))), nil } func (m SHA384Hasher) HelpText() string { return "SHA384 checksum" } func (m SHA384Hasher) Type() string { return "hashes" } pencode-0.4/pkg/pencode/sha512.go000066400000000000000000000005161455271665600165450ustar00rootroot00000000000000package pencode import ( "crypto/sha512" "fmt" ) type SHA512Hasher struct{} func (m SHA512Hasher) Encode(input []byte) ([]byte, error) { return []byte(fmt.Sprintf("%x", sha512.Sum512(input))), nil } func (m SHA512Hasher) HelpText() string { return "SHA512 checksum" } func (m SHA512Hasher) Type() string { return "hashes" } pencode-0.4/pkg/pencode/strings.go000066400000000000000000000011161455271665600172300ustar00rootroot00000000000000package pencode import ( "strings" ) type StrToUpper struct{} type StrToLower struct{} func (s StrToUpper) Encode(input []byte) ([]byte, error) { return []byte(strings.ToUpper(string(input))), nil } func (s StrToUpper) HelpText() string { return "Convert string to uppercase" } func (s StrToUpper) Type() string { return "other" } func (s StrToLower) Encode(input []byte) ([]byte, error) { return []byte(strings.ToLower(string(input))), nil } func (s StrToLower) HelpText() string { return "Convert string to lowercase" } func (s StrToLower) Type() string { return "other" } pencode-0.4/pkg/pencode/template.go000066400000000000000000000020101455271665600173440ustar00rootroot00000000000000package pencode import ( "io/ioutil" "os" "strings" ) //isTemplate checks if the name ends with string ".tmpl" func isTemplate(name string) bool { return strings.HasSuffix(name, ".tmpl") } //hasTemplate checks if the name points to an existing file func hasTemplate(name string) (bool, error) { if _, err := os.Stat(name); err == nil { return true, nil } else { return false, err } } type Template struct { Data []byte Keyword string } func NewTemplateEncoder(name string) (Encoder, error) { var ok bool var err error t := Template{} // Using static keyword for now t.Keyword = "#PAYLOAD#" if ok, err = hasTemplate(name); ok { t.Data, err = ioutil.ReadFile(name) } return t, err } func (t Template) Encode(input []byte) ([]byte, error) { return []byte(strings.ReplaceAll(string(t.Data), t.Keyword, string(input))), nil } func (t Template) HelpText() string { return "Replaces string #PAYLOAD# in content of a file that has .tmpl extension." } func (t Template) Type() string { return "other" } pencode-0.4/pkg/pencode/unicodedecode.go000066400000000000000000000044531455271665600203400ustar00rootroot00000000000000package pencode import ( "unicode" "unicode/utf16" "unicode/utf8" ) type UnicodeDecode struct{} func (u UnicodeDecode) Encode(input []byte) ([]byte, error) { return unquoteBytes(input), nil } func (u UnicodeDecode) HelpText() string { return "Unicode escape string decode" } func (u UnicodeDecode) Type() string { return "decoders" } //This functionality is copied from encoding/json/decode.go with minor modifications func unquoteBytes(s []byte) []byte { b := make([]byte, len(s)+2*utf8.UTFMax) r := 0 w := copy(b, s[0:r]) for r < len(s) { // Out of room? Can only happen if s is full of // malformed UTF-8 and we're replacing each // byte with RuneError. if w >= len(b)-2*utf8.UTFMax { nb := make([]byte, (len(b)+utf8.UTFMax)*2) copy(nb, b[0:w]) b = nb } switch c := s[r]; { case c == '\\': r++ if r >= len(s) { return b[0:w] } switch s[r] { default: return b[0:w] case '"', '\\', '/', '\'': b[w] = s[r] r++ w++ case 'b': b[w] = '\b' r++ w++ case 'f': b[w] = '\f' r++ w++ case 'n': b[w] = '\n' r++ w++ case 'r': b[w] = '\r' r++ w++ case 't': b[w] = '\t' r++ w++ case 'u': r-- rr := getu4(s[r:]) if rr < 0 { return b[0:w] } r += 6 if utf16.IsSurrogate(rr) { rr1 := getu4(s[r:]) if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { // A valid pair; consume. r += 6 w += utf8.EncodeRune(b[w:], dec) break } // Invalid surrogate; fall back to replacement rune. rr = unicode.ReplacementChar } w += utf8.EncodeRune(b[w:], rr) } // ASCII case c < utf8.RuneSelf: b[w] = c r++ w++ // Coerce to well-formed UTF-8. default: rr, size := utf8.DecodeRune(s[r:]) r += size w += utf8.EncodeRune(b[w:], rr) } } return b[0:w] } // getu4 decodes \uXXXX from the beginning of s, returning the hex value, // or it returns -1. func getu4(s []byte) rune { if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { return -1 } var r rune for _, c := range s[2:6] { switch { case '0' <= c && c <= '9': c = c - '0' case 'a' <= c && c <= 'f': c = c - 'a' + 10 case 'A' <= c && c <= 'F': c = c - 'A' + 10 default: return -1 } r = r*16 + rune(c) } return r } pencode-0.4/pkg/pencode/unicodeencodeall.go000066400000000000000000000007501455271665600210370ustar00rootroot00000000000000package pencode import ( "bytes" "fmt" ) type UnicodeEncodeAll struct{} func (u UnicodeEncodeAll) Encode(input []byte) ([]byte, error) { var b bytes.Buffer runes := []rune(string(input)) for _, r := range runes { b.WriteString("\\u") b.WriteString(fmt.Sprintf("%04x", int64(r))) } return b.Bytes(), nil } func (u UnicodeEncodeAll) HelpText() string { return "Unicode escape string encode (all characters)" } func (u UnicodeEncodeAll) Type() string { return "encoders" } pencode-0.4/pkg/pencode/urldecode.go000066400000000000000000000005611455271665600175100ustar00rootroot00000000000000package pencode import ( "net/url" ) type URLDecoder struct{} func (u URLDecoder) Encode(input []byte) ([]byte, error) { output, err := url.QueryUnescape(string(input)) if err != nil { return []byte{}, err } return []byte(output), err } func (u URLDecoder) HelpText() string { return "URL decode" } func (u URLDecoder) Type() string { return "decoders" } pencode-0.4/pkg/pencode/urlencode.go000066400000000000000000000005011455271665600175140ustar00rootroot00000000000000package pencode import ( "net/url" ) type URLEncoder struct{} func (u URLEncoder) Encode(input []byte) ([]byte, error) { return []byte(url.QueryEscape(string(input))), nil } func (u URLEncoder) HelpText() string { return "URL encode reserved characters" } func (u URLEncoder) Type() string { return "encoders" } pencode-0.4/pkg/pencode/urlencodeall.go000066400000000000000000000007451455271665600202170ustar00rootroot00000000000000package pencode import ( "bytes" ) const upperhex = "0123456789ABCDEF" type URLEncoderAll struct{} func (u URLEncoderAll) Encode(input []byte) ([]byte, error) { var buf bytes.Buffer for _, c := range input { // Add "%" buf.WriteByte(37) buf.WriteByte(upperhex[c>>4]) buf.WriteByte(upperhex[c&15]) } return buf.Bytes(), nil } func (u URLEncoderAll) HelpText() string { return "URL encode all characters" } func (u URLEncoderAll) Type() string { return "encoders" } pencode-0.4/pkg/pencode/utf16beencoder.go000066400000000000000000000010241455271665600203510ustar00rootroot00000000000000package pencode import ( "bytes" "encoding/binary" "unicode/utf16" ) type UTF16BEEncode struct{} func (u UTF16BEEncode) Encode(input []byte) ([]byte, error) { var b bytes.Buffer runes := []rune(string(input)) utf16ints := utf16.Encode(runes) for _, r := range utf16ints { tmp := make([]byte, 2) binary.BigEndian.PutUint16(tmp, r) b.Write(tmp) } return b.Bytes(), nil } func (u UTF16BEEncode) HelpText() string { return "UTF-16 encoder (Big Endian)" } func (u UTF16BEEncode) Type() string { return "encoders" } pencode-0.4/pkg/pencode/utf16leencoder.go000066400000000000000000000010321455271665600203620ustar00rootroot00000000000000package pencode import ( "bytes" "encoding/binary" "unicode/utf16" ) type UTF16LEEncode struct{} func (u UTF16LEEncode) Encode(input []byte) ([]byte, error) { var b bytes.Buffer runes := []rune(string(input)) utf16ints := utf16.Encode(runes) for _, r := range utf16ints { tmp := make([]byte, 2) binary.LittleEndian.PutUint16(tmp, r) b.Write(tmp) } return b.Bytes(), nil } func (u UTF16LEEncode) HelpText() string { return "UTF-16 encoder (Little Endian)" } func (u UTF16LEEncode) Type() string { return "encoders" } pencode-0.4/pkg/pencode/util.go000066400000000000000000000003651455271665600165210ustar00rootroot00000000000000package pencode import ( "strings" "unicode" ) func removeAllWhitespace(input string) string { var b strings.Builder b.Grow(len(input)) for _, ch := range input { if !unicode.IsSpace(ch) { b.WriteRune(ch) } } return b.String() } pencode-0.4/pkg/pencode/xmldecode.go000066400000000000000000000010041455271665600174770ustar00rootroot00000000000000package pencode import "encoding/xml" type XMLUnescaper struct{} type XMLInput struct { Input string `xml:"input"` } func (u XMLUnescaper) Encode(input []byte) ([]byte, error) { inputXML := `` + string(input) + `` var out XMLInput if err := xml.Unmarshal([]byte(inputXML), &out); err != nil { return []byte{}, err } return []byte(out.Input), nil } func (u XMLUnescaper) HelpText() string { return "XML unescape" } func (u XMLUnescaper) Type() string { return "decoders" } pencode-0.4/pkg/pencode/xmlencode.go000066400000000000000000000006321455271665600175170ustar00rootroot00000000000000package pencode import ( "bytes" "encoding/xml" ) type XMLEscaper struct{} func (u XMLEscaper) Encode(input []byte) ([]byte, error) { buf := &bytes.Buffer{} if err := xml.EscapeText(buf, input); err != nil { return []byte{}, err } output := buf.Bytes() return output, nil } func (u XMLEscaper) HelpText() string { return "XML escape" } func (u XMLEscaper) Type() string { return "encoders" }