Browse Source

Merge pull request #48 from writeas/vendor-deps

Vendor dependencies for writeas-cli
master
Matt Baer 4 years ago
committed by GitHub
parent
commit
99e1973652
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 13973 additions and 1 deletions
  1. +2
    -1
      go.mod
  2. +22
    -0
      vendor/code.as/core/socks/.gitignore
  3. +22
    -0
      vendor/code.as/core/socks/LICENSE
  4. +58
    -0
      vendor/code.as/core/socks/README.md
  5. +218
    -0
      vendor/code.as/core/socks/socks.go
  6. +20
    -0
      vendor/github.com/atotto/clipboard/.travis.yml
  7. +27
    -0
      vendor/github.com/atotto/clipboard/LICENSE
  8. +48
    -0
      vendor/github.com/atotto/clipboard/README.md
  9. +20
    -0
      vendor/github.com/atotto/clipboard/clipboard.go
  10. +52
    -0
      vendor/github.com/atotto/clipboard/clipboard_darwin.go
  11. +112
    -0
      vendor/github.com/atotto/clipboard/clipboard_unix.go
  12. +128
    -0
      vendor/github.com/atotto/clipboard/clipboard_windows.go
  13. +1
    -0
      vendor/github.com/atotto/clipboard/go.mod
  14. +11
    -0
      vendor/github.com/cloudfoundry/jibber_jabber/.travis.yml
  15. +201
    -0
      vendor/github.com/cloudfoundry/jibber_jabber/LICENSE
  16. +44
    -0
      vendor/github.com/cloudfoundry/jibber_jabber/README.md
  17. +22
    -0
      vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber.go
  18. +57
    -0
      vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix.go
  19. +114
    -0
      vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows.go
  20. +354
    -0
      vendor/github.com/hashicorp/errwrap/LICENSE
  21. +89
    -0
      vendor/github.com/hashicorp/errwrap/README.md
  22. +169
    -0
      vendor/github.com/hashicorp/errwrap/errwrap.go
  23. +1
    -0
      vendor/github.com/hashicorp/errwrap/go.mod
  24. +12
    -0
      vendor/github.com/hashicorp/go-multierror/.travis.yml
  25. +353
    -0
      vendor/github.com/hashicorp/go-multierror/LICENSE
  26. +31
    -0
      vendor/github.com/hashicorp/go-multierror/Makefile
  27. +97
    -0
      vendor/github.com/hashicorp/go-multierror/README.md
  28. +41
    -0
      vendor/github.com/hashicorp/go-multierror/append.go
  29. +26
    -0
      vendor/github.com/hashicorp/go-multierror/flatten.go
  30. +27
    -0
      vendor/github.com/hashicorp/go-multierror/format.go
  31. +3
    -0
      vendor/github.com/hashicorp/go-multierror/go.mod
  32. +4
    -0
      vendor/github.com/hashicorp/go-multierror/go.sum
  33. +51
    -0
      vendor/github.com/hashicorp/go-multierror/multierror.go
  34. +37
    -0
      vendor/github.com/hashicorp/go-multierror/prefix.go
  35. +16
    -0
      vendor/github.com/hashicorp/go-multierror/sort.go
  36. +11
    -0
      vendor/github.com/howeyc/gopass/.travis.yml
  37. +15
    -0
      vendor/github.com/howeyc/gopass/LICENSE.txt
  38. +384
    -0
      vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE
  39. +27
    -0
      vendor/github.com/howeyc/gopass/README.md
  40. +110
    -0
      vendor/github.com/howeyc/gopass/pass.go
  41. +25
    -0
      vendor/github.com/howeyc/gopass/terminal.go
  42. +69
    -0
      vendor/github.com/howeyc/gopass/terminal_solaris.go
  43. +1
    -0
      vendor/github.com/microcosm-cc/bluemonday/.coveralls.yml
  44. +21
    -0
      vendor/github.com/microcosm-cc/bluemonday/.travis.yml
  45. +51
    -0
      vendor/github.com/microcosm-cc/bluemonday/CONTRIBUTING.md
  46. +6
    -0
      vendor/github.com/microcosm-cc/bluemonday/CREDITS.md
  47. +28
    -0
      vendor/github.com/microcosm-cc/bluemonday/LICENSE.md
  48. +42
    -0
      vendor/github.com/microcosm-cc/bluemonday/Makefile
  49. +350
    -0
      vendor/github.com/microcosm-cc/bluemonday/README.md
  50. +104
    -0
      vendor/github.com/microcosm-cc/bluemonday/doc.go
  51. +297
    -0
      vendor/github.com/microcosm-cc/bluemonday/helpers.go
  52. +253
    -0
      vendor/github.com/microcosm-cc/bluemonday/policies.go
  53. +552
    -0
      vendor/github.com/microcosm-cc/bluemonday/policy.go
  54. +581
    -0
      vendor/github.com/microcosm-cc/bluemonday/sanitize.go
  55. +21
    -0
      vendor/github.com/mitchellh/go-homedir/LICENSE
  56. +14
    -0
      vendor/github.com/mitchellh/go-homedir/README.md
  57. +1
    -0
      vendor/github.com/mitchellh/go-homedir/go.mod
  58. +157
    -0
      vendor/github.com/mitchellh/go-homedir/homedir.go
  59. +16
    -0
      vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml
  60. +21
    -0
      vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE
  61. +36
    -0
      vendor/github.com/shurcooL/sanitized_anchor_name/README.md
  62. +29
    -0
      vendor/github.com/shurcooL/sanitized_anchor_name/main.go
  63. +3
    -0
      vendor/github.com/writeas/go-writeas/v2/.gitignore
  64. +21
    -0
      vendor/github.com/writeas/go-writeas/v2/LICENSE
  65. +71
    -0
      vendor/github.com/writeas/go-writeas/v2/README.md
  66. +75
    -0
      vendor/github.com/writeas/go-writeas/v2/auth.go
  67. +186
    -0
      vendor/github.com/writeas/go-writeas/v2/collection.go
  68. +8
    -0
      vendor/github.com/writeas/go-writeas/v2/go.mod
  69. +4
    -0
      vendor/github.com/writeas/go-writeas/v2/go.sum
  70. +330
    -0
      vendor/github.com/writeas/go-writeas/v2/post.go
  71. +34
    -0
      vendor/github.com/writeas/go-writeas/v2/user.go
  72. +199
    -0
      vendor/github.com/writeas/go-writeas/v2/writeas.go
  73. +27
    -0
      vendor/github.com/writeas/impart/.gitignore
  74. +22
    -0
      vendor/github.com/writeas/impart/LICENSE
  75. +61
    -0
      vendor/github.com/writeas/impart/README.md
  76. +4
    -0
      vendor/github.com/writeas/impart/doc.go
  77. +20
    -0
      vendor/github.com/writeas/impart/errors.go
  78. +3
    -0
      vendor/github.com/writeas/impart/go.mod
  79. +13
    -0
      vendor/github.com/writeas/impart/request.go
  80. +76
    -0
      vendor/github.com/writeas/impart/response.go
  81. +8
    -0
      vendor/github.com/writeas/saturday/.gitignore
  82. +30
    -0
      vendor/github.com/writeas/saturday/.travis.yml
  83. +29
    -0
      vendor/github.com/writeas/saturday/LICENSE.txt
  84. +284
    -0
      vendor/github.com/writeas/saturday/README.md
  85. +1412
    -0
      vendor/github.com/writeas/saturday/block.go
  86. +949
    -0
      vendor/github.com/writeas/saturday/html.go
  87. +1151
    -0
      vendor/github.com/writeas/saturday/inline.go
  88. +332
    -0
      vendor/github.com/writeas/saturday/latex.go
  89. +926
    -0
      vendor/github.com/writeas/saturday/markdown.go
  90. +396
    -0
      vendor/github.com/writeas/saturday/smartypants.go
  91. +373
    -0
      vendor/github.com/writeas/web-core/LICENSE
  92. +19
    -0
      vendor/github.com/writeas/web-core/posts/parse.go
  93. +63
    -0
      vendor/github.com/writeas/web-core/posts/render.go
  94. +3
    -0
      vendor/golang.org/x/crypto/AUTHORS
  95. +3
    -0
      vendor/golang.org/x/crypto/CONTRIBUTORS
  96. +27
    -0
      vendor/golang.org/x/crypto/LICENSE
  97. +22
    -0
      vendor/golang.org/x/crypto/PATENTS
  98. +951
    -0
      vendor/golang.org/x/crypto/ssh/terminal/terminal.go
  99. +114
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util.go
  100. +12
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_aix.go

+ 2
- 1
go.mod View File

@@ -1,7 +1,6 @@
module github.com/writeas/writeas-cli

require (
code.as/core/socks v1.0.0
github.com/atotto/clipboard v0.1.1
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
@@ -24,3 +23,5 @@ require (
gopkg.in/ini.v1 v1.39.3
gopkg.in/urfave/cli.v1 v1.20.0
)

go 1.13

+ 22
- 0
vendor/code.as/core/socks/.gitignore View File

@@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe

+ 22
- 0
vendor/code.as/core/socks/LICENSE View File

@@ -0,0 +1,22 @@
Copyright (c) 2012, Hailiang Wang. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 58
- 0
vendor/code.as/core/socks/README.md View File

@@ -0,0 +1,58 @@
SOCKS
=====

[![GoDoc](https://godoc.org/code.as/core/socks?status.svg)](https://godoc.org/code.as/core/socks)

SOCKS is a SOCKS4, SOCKS4A and SOCKS5 proxy package for Go, forked from [h12w/socks](https://github.com/h12w/socks) and patched so it's `go get`able.

## Quick Start
### Get the package

go get -u "code.as/core/socks"

### Import the package

import "code.as/core/socks"

### Create a SOCKS proxy dialing function

dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
tr := &http.Transport{Dial: dialSocksProxy}
httpClient := &http.Client{Transport: tr}

## Example

```go
package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"

"code.as/core/socks"
)

func main() {
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
tr := &http.Transport{Dial: dialSocksProxy}
httpClient := &http.Client{Transport: tr}
resp, err := httpClient.Get("http://www.google.com")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatal(resp.StatusCode)
}
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(buf))
}
```

## Alternatives
http://godoc.org/golang.org/x/net/proxy

+ 218
- 0
vendor/code.as/core/socks/socks.go View File

@@ -0,0 +1,218 @@
// Copyright 2012, Hailiang Wang. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package socks implements a SOCKS (SOCKS4, SOCKS4A and SOCKS5) proxy client.

A complete example using this package:
package main

import (
"code.as/core/socks"
"fmt"
"net/http"
"io/ioutil"
)

func main() {
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
tr := &http.Transport{Dial: dialSocksProxy}
httpClient := &http.Client{Transport: tr}

bodyText, err := TestHttpsGet(httpClient, "https://h12.io/about")
if err != nil {
fmt.Println(err.Error())
}
fmt.Print(bodyText)
}

func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) {
resp, err := c.Get(url)
if err != nil { return }
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil { return }
bodyText = string(body)
return
}
*/
package socks

import (
"errors"
"fmt"
"net"
"strconv"
)

// Constants to choose which version of SOCKS protocol to use.
const (
SOCKS4 = iota
SOCKS4A
SOCKS5
)

// DialSocksProxy returns the dial function to be used in http.Transport object.
// Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5.
// Argument proxy should be in this format "127.0.0.1:1080".
func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) {
if socksType == SOCKS5 {
return func(_, targetAddr string) (conn net.Conn, err error) {
return dialSocks5(proxy, targetAddr)
}
}

// SOCKS4, SOCKS4A
return func(_, targetAddr string) (conn net.Conn, err error) {
return dialSocks4(socksType, proxy, targetAddr)
}
}

func dialSocks5(proxy, targetAddr string) (conn net.Conn, err error) {
// dial TCP
conn, err = net.Dial("tcp", proxy)
if err != nil {
return
}

// version identifier/method selection request
req := []byte{
5, // version number
1, // number of methods
0, // method 0: no authentication (only anonymous access supported for now)
}
resp, err := sendReceive(conn, req)
if err != nil {
return
} else if len(resp) != 2 {
err = errors.New("Server does not respond properly.")
return
} else if resp[0] != 5 {
err = errors.New("Server does not support Socks 5.")
return
} else if resp[1] != 0 { // no auth
err = errors.New("socks method negotiation failed.")
return
}

// detail request
host, port, err := splitHostPort(targetAddr)
req = []byte{
5, // version number
1, // connect command
0, // reserved, must be zero
3, // address type, 3 means domain name
byte(len(host)), // address length
}
req = append(req, []byte(host)...)
req = append(req, []byte{
byte(port >> 8), // higher byte of destination port
byte(port), // lower byte of destination port (big endian)
}...)
resp, err = sendReceive(conn, req)
if err != nil {
return
} else if len(resp) != 10 {
err = errors.New("Server does not respond properly.")
} else if resp[1] != 0 {
err = errors.New("Can't complete SOCKS5 connection.")
}

return
}

func dialSocks4(socksType int, proxy, targetAddr string) (conn net.Conn, err error) {
// dial TCP
conn, err = net.Dial("tcp", proxy)
if err != nil {
return
}

// connection request
host, port, err := splitHostPort(targetAddr)
if err != nil {
return
}
ip := net.IPv4(0, 0, 0, 1).To4()
if socksType == SOCKS4 {
ip, err = lookupIP(host)
if err != nil {
return
}
}
req := []byte{
4, // version number
1, // command CONNECT
byte(port >> 8), // higher byte of destination port
byte(port), // lower byte of destination port (big endian)
ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided
0, // user id is empty, anonymous proxy only
}
if socksType == SOCKS4A {
req = append(req, []byte(host+"\x00")...)
}

resp, err := sendReceive(conn, req)
if err != nil {
return
} else if len(resp) != 8 {
err = errors.New("Server does not respond properly.")
return
}
switch resp[1] {
case 90:
// request granted
case 91:
err = errors.New("Socks connection request rejected or failed.")
case 92:
err = errors.New("Socks connection request rejected becasue SOCKS server cannot connect to identd on the client.")
case 93:
err = errors.New("Socks connection request rejected because the client program and identd report different user-ids.")
default:
err = errors.New("Socks connection request failed, unknown error.")
}
return
}

func sendReceive(conn net.Conn, req []byte) (resp []byte, err error) {
_, err = conn.Write(req)
if err != nil {
return
}
resp, err = readAll(conn)
return
}

func readAll(conn net.Conn) (resp []byte, err error) {
resp = make([]byte, 1024)
n, err := conn.Read(resp)
resp = resp[:n]
return
}

func lookupIP(host string) (ip net.IP, err error) {
ips, err := net.LookupIP(host)
if err != nil {
return
}
if len(ips) == 0 {
err = errors.New(fmt.Sprintf("Cannot resolve host: %s.", host))
return
}
ip = ips[0].To4()
if len(ip) != net.IPv4len {
fmt.Println(len(ip), ip)
err = errors.New("IPv6 is not supported by SOCKS4.")
return
}
return
}

func splitHostPort(addr string) (host string, port uint16, err error) {
host, portStr, err := net.SplitHostPort(addr)
portInt, err := strconv.ParseUint(portStr, 10, 16)
port = uint16(portInt)
return
}

+ 20
- 0
vendor/github.com/atotto/clipboard/.travis.yml View File

@@ -0,0 +1,20 @@
language: go

go:
- go1.4.3
- go1.5.4
- go1.6.4
- go1.7.6
- go1.8.7
- go1.9.4
- go1.10

before_install:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start

script:
- sudo apt-get install xsel
- go test -v .
- sudo apt-get install xclip
- go test -v .

+ 27
- 0
vendor/github.com/atotto/clipboard/LICENSE View File

@@ -0,0 +1,27 @@
Copyright (c) 2013 Ato Araki. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of @atotto. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 48
- 0
vendor/github.com/atotto/clipboard/README.md View File

@@ -0,0 +1,48 @@
[![Build Status](https://travis-ci.org/atotto/clipboard.svg?branch=master)](https://travis-ci.org/atotto/clipboard)

[![GoDoc](https://godoc.org/github.com/atotto/clipboard?status.svg)](http://godoc.org/github.com/atotto/clipboard)

# Clipboard for Go

Provide copying and pasting to the Clipboard for Go.

Build:

$ go get github.com/atotto/clipboard

Platforms:

* OSX
* Windows 7 (probably work on other Windows)
* Linux, Unix (requires 'xclip' or 'xsel' command to be installed)


Document:

* http://godoc.org/github.com/atotto/clipboard

Notes:

* Text string only
* UTF-8 text encoding only (no conversion)

TODO:

* Clipboard watcher(?)

## Commands:

paste shell command:

$ go get github.com/atotto/clipboard/cmd/gopaste
$ # example:
$ gopaste > document.txt

copy shell command:

$ go get github.com/atotto/clipboard/cmd/gocopy
$ # example:
$ cat document.txt | gocopy




+ 20
- 0
vendor/github.com/atotto/clipboard/clipboard.go View File

@@ -0,0 +1,20 @@
// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package clipboard read/write on clipboard
package clipboard

// ReadAll read string from clipboard
func ReadAll() (string, error) {
return readAll()
}

// WriteAll write string to clipboard
func WriteAll(text string) error {
return writeAll(text)
}

// Unsupported might be set true during clipboard init, to help callers decide
// whether or not to offer clipboard options.
var Unsupported bool

+ 52
- 0
vendor/github.com/atotto/clipboard/clipboard_darwin.go View File

@@ -0,0 +1,52 @@
// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin

package clipboard

import (
"os/exec"
)

var (
pasteCmdArgs = "pbpaste"
copyCmdArgs = "pbcopy"
)

func getPasteCommand() *exec.Cmd {
return exec.Command(pasteCmdArgs)
}

func getCopyCommand() *exec.Cmd {
return exec.Command(copyCmdArgs)
}

func readAll() (string, error) {
pasteCmd := getPasteCommand()
out, err := pasteCmd.Output()
if err != nil {
return "", err
}
return string(out), nil
}

func writeAll(text string) error {
copyCmd := getCopyCommand()
in, err := copyCmd.StdinPipe()
if err != nil {
return err
}

if err := copyCmd.Start(); err != nil {
return err
}
if _, err := in.Write([]byte(text)); err != nil {
return err
}
if err := in.Close(); err != nil {
return err
}
return copyCmd.Wait()
}

+ 112
- 0
vendor/github.com/atotto/clipboard/clipboard_unix.go View File

@@ -0,0 +1,112 @@
// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build freebsd linux netbsd openbsd solaris dragonfly

package clipboard

import (
"errors"
"os/exec"
)

const (
xsel = "xsel"
xclip = "xclip"
termuxClipboardGet = "termux-clipboard-get"
termuxClipboardSet = "termux-clipboard-set"
)

var (
Primary bool

pasteCmdArgs []string
copyCmdArgs []string

xselPasteArgs = []string{xsel, "--output", "--clipboard"}
xselCopyArgs = []string{xsel, "--input", "--clipboard"}

xclipPasteArgs = []string{xclip, "-out", "-selection", "clipboard"}
xclipCopyArgs = []string{xclip, "-in", "-selection", "clipboard"}

termuxPasteArgs = []string{termuxClipboardGet}
termuxCopyArgs = []string{termuxClipboardSet}

missingCommands = errors.New("No clipboard utilities available. Please install xsel, xclip, or Termux:API add-on for termux-clipboard-get/set.")
)

func init() {
pasteCmdArgs = xclipPasteArgs
copyCmdArgs = xclipCopyArgs

if _, err := exec.LookPath(xclip); err == nil {
return
}

pasteCmdArgs = xselPasteArgs
copyCmdArgs = xselCopyArgs

if _, err := exec.LookPath(xsel); err == nil {
return
}

pasteCmdArgs = termuxPasteArgs
copyCmdArgs = termuxCopyArgs

if _, err := exec.LookPath(termuxClipboardSet); err == nil {
if _, err := exec.LookPath(termuxClipboardGet); err == nil {
return
}
}

Unsupported = true
}

func getPasteCommand() *exec.Cmd {
if Primary {
pasteCmdArgs = pasteCmdArgs[:1]
}
return exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...)
}

func getCopyCommand() *exec.Cmd {
if Primary {
copyCmdArgs = copyCmdArgs[:1]
}
return exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...)
}

func readAll() (string, error) {
if Unsupported {
return "", missingCommands
}
pasteCmd := getPasteCommand()
out, err := pasteCmd.Output()
if err != nil {
return "", err
}
return string(out), nil
}

func writeAll(text string) error {
if Unsupported {
return missingCommands
}
copyCmd := getCopyCommand()
in, err := copyCmd.StdinPipe()
if err != nil {
return err
}

if err := copyCmd.Start(); err != nil {
return err
}
if _, err := in.Write([]byte(text)); err != nil {
return err
}
if err := in.Close(); err != nil {
return err
}
return copyCmd.Wait()
}

+ 128
- 0
vendor/github.com/atotto/clipboard/clipboard_windows.go View File

@@ -0,0 +1,128 @@
// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package clipboard

import (
"syscall"
"time"
"unsafe"
)

const (
cfUnicodetext = 13
gmemMoveable = 0x0002
)

var (
user32 = syscall.MustLoadDLL("user32")
openClipboard = user32.MustFindProc("OpenClipboard")
closeClipboard = user32.MustFindProc("CloseClipboard")
emptyClipboard = user32.MustFindProc("EmptyClipboard")
getClipboardData = user32.MustFindProc("GetClipboardData")
setClipboardData = user32.MustFindProc("SetClipboardData")

kernel32 = syscall.NewLazyDLL("kernel32")
globalAlloc = kernel32.NewProc("GlobalAlloc")
globalFree = kernel32.NewProc("GlobalFree")
globalLock = kernel32.NewProc("GlobalLock")
globalUnlock = kernel32.NewProc("GlobalUnlock")
lstrcpy = kernel32.NewProc("lstrcpyW")
)

// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
func waitOpenClipboard() error {
started := time.Now()
limit := started.Add(time.Second)
var r uintptr
var err error
for time.Now().Before(limit) {
r, _, err = openClipboard.Call(0)
if r != 0 {
return nil
}
time.Sleep(time.Millisecond)
}
return err
}

func readAll() (string, error) {
err := waitOpenClipboard()
if err != nil {
return "", err
}
defer closeClipboard.Call()

h, _, err := getClipboardData.Call(cfUnicodetext)
if h == 0 {
return "", err
}

l, _, err := globalLock.Call(h)
if l == 0 {
return "", err
}

text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])

r, _, err := globalUnlock.Call(h)
if r == 0 {
return "", err
}

return text, nil
}

func writeAll(text string) error {
err := waitOpenClipboard()
if err != nil {
return err
}
defer closeClipboard.Call()

r, _, err := emptyClipboard.Call(0)
if r == 0 {
return err
}

data := syscall.StringToUTF16(text)

// "If the hMem parameter identifies a memory object, the object must have
// been allocated using the function with the GMEM_MOVEABLE flag."
h, _, err := globalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
if h == 0 {
return err
}
defer func() {
if h != 0 {
globalFree.Call(h)
}
}()

l, _, err := globalLock.Call(h)
if l == 0 {
return err
}

r, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
if r == 0 {
return err
}

r, _, err = globalUnlock.Call(h)
if r == 0 {
if err.(syscall.Errno) != 0 {
return err
}
}

r, _, err = setClipboardData.Call(cfUnicodetext, h)
if r == 0 {
return err
}
h = 0 // suppress deferred cleanup
return nil
}

+ 1
- 0
vendor/github.com/atotto/clipboard/go.mod View File

@@ -0,0 +1 @@
module github.com/atotto/clipboard

+ 11
- 0
vendor/github.com/cloudfoundry/jibber_jabber/.travis.yml View File

@@ -0,0 +1,11 @@
language: go
go:
- 1.2
before_install:
- go get github.com/onsi/ginkgo/...
- go get github.com/onsi/gomega/...
- go install github.com/onsi/ginkgo/ginkgo
script: PATH=$PATH:$HOME/gopath/bin ginkgo -r .
branches:
only:
- master

+ 201
- 0
vendor/github.com/cloudfoundry/jibber_jabber/LICENSE View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2014 Pivotal

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

+ 44
- 0
vendor/github.com/cloudfoundry/jibber_jabber/README.md View File

@@ -0,0 +1,44 @@
# Jibber Jabber [![Build Status](https://travis-ci.org/cloudfoundry/jibber_jabber.svg?branch=master)](https://travis-ci.org/cloudfoundry/jibber_jabber)
Jibber Jabber is a GoLang Library that can be used to detect an operating system's current language.

### OS Support

OSX and Linux via the `LC_ALL` and `LANG` environment variables. These are standard variables that are used in ALL versions of UNIX for language detection.

Windows via [GetUserDefaultLocaleName](http://msdn.microsoft.com/en-us/library/windows/desktop/dd318136.aspx) and [GetSystemDefaultLocaleName](http://msdn.microsoft.com/en-us/library/windows/desktop/dd318122.aspx) system calls. These calls are supported in Windows Vista and up.

# Usage
Add the following line to your go `import`:

```
"github.com/cloudfoundry/jibber_jabber"
```

### DetectIETF
`DetectIETF` will return the current locale as a string. The format of the locale will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code, a DASH, then an [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.

```
userLocale, err := jibber_jabber.DetectIETF()
println("Locale:", userLocale)
```

### DetectLanguage
`DetectLanguage` will return the current languge as a string. The format will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code.

```
userLanguage, err := jibber_jabber.DetectLanguage()
println("Language:", userLanguage)
```

### DetectTerritory
`DetectTerritory` will return the current locale territory as a string. The format will be the [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.

```
localeTerritory, err := jibber_jabber.DetectTerritory()
println("Territory:", localeTerritory)
```

### Errors
All the Detect commands will return an error if they are unable to read the Locale from the system.

For Windows, additional error information is provided due to the nature of the system call being used.

+ 22
- 0
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber.go View File

@@ -0,0 +1,22 @@
package jibber_jabber

import (
"strings"
)

const (
COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE = "Could not detect Language"
)

func splitLocale(locale string) (string, string) {
formattedLocale := strings.Split(locale, ".")[0]
formattedLocale = strings.Replace(formattedLocale, "-", "_", -1)

pieces := strings.Split(formattedLocale, "_")
language := pieces[0]
territory := ""
if len(pieces) > 1 {
territory = strings.Split(formattedLocale, "_")[1]
}
return language, territory
}

+ 57
- 0
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix.go View File

@@ -0,0 +1,57 @@
// +build darwin freebsd linux netbsd openbsd

package jibber_jabber

import (
"errors"
"os"
"strings"
)

func getLangFromEnv() (locale string) {
locale = os.Getenv("LC_ALL")
if locale == "" {
locale = os.Getenv("LANG")
}
return
}

func getUnixLocale() (unix_locale string, err error) {
unix_locale = getLangFromEnv()
if unix_locale == "" {
err = errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE)
}

return
}

func DetectIETF() (locale string, err error) {
unix_locale, err := getUnixLocale()
if err == nil {
language, territory := splitLocale(unix_locale)
locale = language
if territory != "" {
locale = strings.Join([]string{language, territory}, "-")
}
}

return
}

func DetectLanguage() (language string, err error) {
unix_locale, err := getUnixLocale()
if err == nil {
language, _ = splitLocale(unix_locale)
}

return
}

func DetectTerritory() (territory string, err error) {
unix_locale, err := getUnixLocale()
if err == nil {
_, territory = splitLocale(unix_locale)
}

return
}

+ 114
- 0
vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows.go View File

@@ -0,0 +1,114 @@
// +build windows

package jibber_jabber

import (
"errors"
"syscall"
"unsafe"
)

const LOCALE_NAME_MAX_LENGTH uint32 = 85

var SUPPORTED_LOCALES = map[uintptr]string{
0x0407: "de-DE",
0x0409: "en-US",
0x0c0a: "es-ES", //or is it 0x040a
0x040c: "fr-FR",
0x0410: "it-IT",
0x0411: "ja-JA",
0x0412: "ko_KR",
0x0416: "pt-BR",
//0x0419: "ru_RU", - Will add support for Russian when nicksnyder/go-i18n supports Russian
0x0804: "zh-CN",
0x0c04: "zh-HK",
0x0404: "zh-TW",
}

func getWindowsLocaleFrom(sysCall string) (locale string, err error) {
buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)

dll := syscall.MustLoadDLL("kernel32")
proc := dll.MustFindProc(sysCall)
r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
if r == 0 {
err = errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
return
}

locale = syscall.UTF16ToString(buffer)

return
}

func getAllWindowsLocaleFrom(sysCall string) (string, error) {
dll, err := syscall.LoadDLL("kernel32")
if err != nil {
return "", errors.New("Could not find kernel32 dll")
}

proc, err := dll.FindProc(sysCall)
if err != nil {
return "", err
}

locale, _, dllError := proc.Call()
if locale == 0 {
return "", errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
}

return SUPPORTED_LOCALES[locale], nil
}

func getWindowsLocale() (locale string, err error) {
dll, err := syscall.LoadDLL("kernel32")
if err != nil {
return "", errors.New("Could not find kernel32 dll")
}

proc, err := dll.FindProc("GetVersion")
if err != nil {
return "", err
}

v, _, _ := proc.Call()
windowsVersion := byte(v)
isVistaOrGreater := (windowsVersion >= 6)

if isVistaOrGreater {
locale, err = getWindowsLocaleFrom("GetUserDefaultLocaleName")
if err != nil {
locale, err = getWindowsLocaleFrom("GetSystemDefaultLocaleName")
}
} else if !isVistaOrGreater {
locale, err = getAllWindowsLocaleFrom("GetUserDefaultLCID")
if err != nil {
locale, err = getAllWindowsLocaleFrom("GetSystemDefaultLCID")
}
} else {
panic(v)
}
return
}
func DetectIETF() (locale string, err error) {
locale, err = getWindowsLocale()
return
}

func DetectLanguage() (language string, err error) {
windows_locale, err := getWindowsLocale()
if err == nil {
language, _ = splitLocale(windows_locale)
}

return
}

func DetectTerritory() (territory string, err error) {
windows_locale, err := getWindowsLocale()
if err == nil {
_, territory = splitLocale(windows_locale)
}

return
}

+ 354
- 0
vendor/github.com/hashicorp/errwrap/LICENSE View File

@@ -0,0 +1,354 @@
Mozilla Public License, version 2.0

1. Definitions

1.1. “Contributor”

means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.

1.2. “Contributor Version”

means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor’s Contribution.

1.3. “Contribution”

means Covered Software of a particular Contributor.

1.4. “Covered Software”

means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.

1.5. “Incompatible With Secondary Licenses”
means

a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or

b. that the Covered Software was made available under the terms of version
1.1 or earlier of the License, but not also under the terms of a
Secondary License.

1.6. “Executable Form”

means any form of the work other than Source Code Form.

1.7. “Larger Work”

means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.

1.8. “License”

means this document.

1.9. “Licensable”

means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed by
this License.

1.10. “Modifications”

means any of the following:

a. any file in Source Code Form that results from an addition to, deletion
from, or modification of the contents of Covered Software; or

b. any new file in Source Code Form that contains any Covered Software.

1.11. “Patent Claims” of a Contributor

means any patent claim(s), including without limitation, method, process,
and apparatus claims, in any patent Licensable by such Contributor that
would be infringed, but for the grant of the License, by the making,
using, selling, offering for sale, having made, import, or transfer of
either its Contributions or its Contributor Version.

1.12. “Secondary License”

means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.

1.13. “Source Code Form”

means the form of the work preferred for making modifications.

1.14. “You” (or “Your”)

means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, “control” means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.


2. License Grants and Conditions

2.1. Grants

Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:

a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or as
part of a Larger Work; and

b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions
or its Contributor Version.

2.2. Effective Date

The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.

2.3. Limitations on Grant Scope

The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:

a. for any code that a Contributor has removed from Covered Software; or

b. for infringements caused by: (i) Your and any other third party’s
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or

c. under Patent Claims infringed by Covered Software in the absence of its
Contributions.

This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the
notice requirements in Section 3.4).

2.4. Subsequent Licenses

No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this License
(see Section 10.2) or under the terms of a Secondary License (if permitted
under the terms of Section 3.3).

2.5. Representation

Each Contributor represents that the Contributor believes its Contributions
are its original creation(s) or it has sufficient rights to grant the
rights to its Contributions conveyed by this License.

2.6. Fair Use

This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.

2.7. Conditions

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.


3. Responsibilities

3.1. Distribution of Source Form

All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form
of the Covered Software is governed by the terms of this License, and how
they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients’ rights in the Source Code Form.

3.2. Distribution of Executable Form

If You distribute Covered Software in Executable Form then:

a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and

b. You may distribute such Executable Form under the terms of this License,
or sublicense it under different terms, provided that the license for
the Executable Form does not attempt to limit or alter the recipients’
rights in the Source Code Form under this License.

3.3. Distribution of a Larger Work

You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software
with a work governed by one or more Secondary Licenses, and the Covered
Software is not Incompatible With Secondary Licenses, this License permits
You to additionally distribute such Covered Software under the terms of
such Secondary License(s), so that the recipient of the Larger Work may, at
their option, further distribute the Covered Software under the terms of
either this License or such Secondary License(s).

3.4. Notices

You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations
of liability) contained within the Source Code Form of the Covered
Software, except that You may alter any license notices to the extent
required to remedy known factual inaccuracies.

3.5. Application of Additional Terms

You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on behalf
of any Contributor. You must make it absolutely clear that any such
warranty, support, indemnity, or liability obligation is offered by You
alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.

4. Inability to Comply Due to Statute or Regulation

If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: (a) comply with the terms of this License
to the maximum extent possible; and (b) describe the limitations and the code
they affect. Such description must be placed in a text file included with all
distributions of the Covered Software under this License. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.

5. Termination

5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
if such Contributor fails to notify You of the non-compliance by some
reasonable means prior to 60 days after You have come back into compliance.
Moreover, Your grants from a particular Contributor are reinstated on an
ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of
non-compliance with this License from such Contributor, and You become
compliant prior to 30 days after Your receipt of the notice.

5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims,
and cross-claims) alleging that a Contributor Version directly or
indirectly infringes any patent, then the rights granted to You by any and
all Contributors for the Covered Software under Section 2.1 of this License
shall terminate.

5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.

6. Disclaimer of Warranty

Covered Software is provided under this License on an “as is” basis, without
warranty of any kind, either expressed, implied, or statutory, including,
without limitation, warranties that the Covered Software is free of defects,
merchantable, fit for a particular purpose or non-infringing. The entire
risk as to the quality and performance of the Covered Software is with You.
Should any Covered Software prove defective in any respect, You (not any
Contributor) assume the cost of any necessary servicing, repair, or
correction. This disclaimer of warranty constitutes an essential part of this
License. No use of any Covered Software is authorized under this License
except under this disclaimer.

7. Limitation of Liability

Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from such
party’s negligence to the extent applicable law prohibits such limitation.
Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.

8. Litigation

Any litigation relating to this License may be brought only in the courts of
a jurisdiction where the defendant maintains its principal place of business
and such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a party’s ability to bring cross-claims or counter-claims.

9. Miscellaneous

This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.


10. Versions of the License

10.1. New Versions

Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.

10.2. Effect of New Versions

You may distribute the Covered Software under the terms of the version of
the License under which You originally received the Covered Software, or
under the terms of any subsequent version published by the license
steward.

10.3. Modified Versions

If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a modified
version of this License if you rename the license and remove any
references to the name of the license steward (except to note that such
modified license differs from this License).

10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.

Exhibit A - Source Code Form License Notice

This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.

If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

Exhibit B - “Incompatible With Secondary Licenses” Notice

This Source Code Form is “Incompatible
With Secondary Licenses”, as defined by
the Mozilla Public License, v. 2.0.


+ 89
- 0
vendor/github.com/hashicorp/errwrap/README.md View File

@@ -0,0 +1,89 @@
# errwrap

`errwrap` is a package for Go that formalizes the pattern of wrapping errors
and checking if an error contains another error.

There is a common pattern in Go of taking a returned `error` value and
then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
with this pattern is that you completely lose the original `error` structure.

Arguably the _correct_ approach is that you should make a custom structure
implementing the `error` interface, and have the original error as a field
on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
This is a good approach, but you have to know the entire chain of possible
rewrapping that happens, when you might just care about one.

`errwrap` formalizes this pattern (it doesn't matter what approach you use
above) by giving a single interface for wrapping errors, checking if a specific
error is wrapped, and extracting that error.

## Installation and Docs

Install using `go get github.com/hashicorp/errwrap`.

Full documentation is available at
http://godoc.org/github.com/hashicorp/errwrap

## Usage

#### Basic Usage

Below is a very basic example of its usage:

```go
// A function that always returns an error, but wraps it, like a real
// function might.
func tryOpen() error {
_, err := os.Open("/i/dont/exist")
if err != nil {
return errwrap.Wrapf("Doesn't exist: {{err}}", err)
}

return nil
}

func main() {
err := tryOpen()

// We can use the Contains helpers to check if an error contains
// another error. It is safe to do this with a nil error, or with
// an error that doesn't even use the errwrap package.
if errwrap.Contains(err, "does not exist") {
// Do something
}
if errwrap.ContainsType(err, new(os.PathError)) {
// Do something
}

// Or we can use the associated `Get` functions to just extract
// a specific error. This would return nil if that specific error doesn't
// exist.
perr := errwrap.GetType(err, new(os.PathError))
}
```

#### Custom Types

If you're already making custom types that properly wrap errors, then
you can get all the functionality of `errwraps.Contains` and such by
implementing the `Wrapper` interface with just one function. Example:

```go
type AppError {
Code ErrorCode
Err error
}

func (e *AppError) WrappedErrors() []error {
return []error{e.Err}
}
```

Now this works:

```go
err := &AppError{Err: fmt.Errorf("an error")}
if errwrap.ContainsType(err, fmt.Errorf("")) {
// This will work!
}
```

+ 169
- 0
vendor/github.com/hashicorp/errwrap/errwrap.go View File

@@ -0,0 +1,169 @@
// Package errwrap implements methods to formalize error wrapping in Go.
//
// All of the top-level functions that take an `error` are built to be able
// to take any error, not just wrapped errors. This allows you to use errwrap
// without having to type-check and type-cast everywhere.
package errwrap

import (
"errors"
"reflect"
"strings"
)

// WalkFunc is the callback called for Walk.
type WalkFunc func(error)

// Wrapper is an interface that can be implemented by custom types to
// have all the Contains, Get, etc. functions in errwrap work.
//
// When Walk reaches a Wrapper, it will call the callback for every
// wrapped error in addition to the wrapper itself. Since all the top-level
// functions in errwrap use Walk, this means that all those functions work
// with your custom type.
type Wrapper interface {
WrappedErrors() []error
}

// Wrap defines that outer wraps inner, returning an error type that
// can be cleanly used with the other methods in this package, such as
// Contains, GetAll, etc.
//
// This function won't modify the error message at all (the outer message
// will be used).
func Wrap(outer, inner error) error {
return &wrappedError{
Outer: outer,
Inner: inner,
}
}

// Wrapf wraps an error with a formatting message. This is similar to using
// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
// errors, you should replace it with this.
//
// format is the format of the error message. The string '{{err}}' will
// be replaced with the original error message.
func Wrapf(format string, err error) error {
outerMsg := "<nil>"
if err != nil {
outerMsg = err.Error()
}

outer := errors.New(strings.Replace(
format, "{{err}}", outerMsg, -1))

return Wrap(outer, err)
}

// Contains checks if the given error contains an error with the
// message msg. If err is not a wrapped error, this will always return
// false unless the error itself happens to match this msg.
func Contains(err error, msg string) bool {
return len(GetAll(err, msg)) > 0
}

// ContainsType checks if the given error contains an error with
// the same concrete type as v. If err is not a wrapped error, this will
// check the err itself.
func ContainsType(err error, v interface{}) bool {
return len(GetAllType(err, v)) > 0
}

// Get is the same as GetAll but returns the deepest matching error.
func Get(err error, msg string) error {
es := GetAll(err, msg)
if len(es) > 0 {
return es[len(es)-1]
}

return nil
}

// GetType is the same as GetAllType but returns the deepest matching error.
func GetType(err error, v interface{}) error {
es := GetAllType(err, v)
if len(es) > 0 {
return es[len(es)-1]
}

return nil
}

// GetAll gets all the errors that might be wrapped in err with the
// given message. The order of the errors is such that the outermost
// matching error (the most recent wrap) is index zero, and so on.
func GetAll(err error, msg string) []error {
var result []error

Walk(err, func(err error) {
if err.Error() == msg {
result = append(result, err)
}
})

return result
}

// GetAllType gets all the errors that are the same type as v.
//
// The order of the return value is the same as described in GetAll.
func GetAllType(err error, v interface{}) []error {
var result []error

var search string
if v != nil {
search = reflect.TypeOf(v).String()
}
Walk(err, func(err error) {
var needle string
if err != nil {
needle = reflect.TypeOf(err).String()
}

if needle == search {
result = append(result, err)
}
})

return result
}

// Walk walks all the wrapped errors in err and calls the callback. If
// err isn't a wrapped error, this will be called once for err. If err
// is a wrapped error, the callback will be called for both the wrapper
// that implements error as well as the wrapped error itself.
func Walk(err error, cb WalkFunc) {
if err == nil {
return
}

switch e := err.(type) {
case *wrappedError:
cb(e.Outer)
Walk(e.Inner, cb)
case Wrapper:
cb(err)

for _, err := range e.WrappedErrors() {
Walk(err, cb)
}
default:
cb(err)
}
}

// wrappedError is an implementation of error that has both the
// outer and inner errors.
type wrappedError struct {
Outer error
Inner error
}

func (w *wrappedError) Error() string {
return w.Outer.Error()
}

func (w *wrappedError) WrappedErrors() []error {
return []error{w.Outer, w.Inner}
}

+ 1
- 0
vendor/github.com/hashicorp/errwrap/go.mod View File

@@ -0,0 +1 @@
module github.com/hashicorp/errwrap

+ 12
- 0
vendor/github.com/hashicorp/go-multierror/.travis.yml View File

@@ -0,0 +1,12 @@
sudo: false

language: go

go:
- 1.x

branches:
only:
- master

script: make test testrace

+ 353
- 0
vendor/github.com/hashicorp/go-multierror/LICENSE View File

@@ -0,0 +1,353 @@
Mozilla Public License, version 2.0

1. Definitions

1.1. “Contributor”

means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.

1.2. “Contributor Version”

means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor’s Contribution.

1.3. “Contribution”

means Covered Software of a particular Contributor.

1.4. “Covered Software”

means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.

1.5. “Incompatible With Secondary Licenses”
means

a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or

b. that the Covered Software was made available under the terms of version
1.1 or earlier of the License, but not also under the terms of a
Secondary License.

1.6. “Executable Form”

means any form of the work other than Source Code Form.

1.7. “Larger Work”

means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.

1.8. “License”

means this document.

1.9. “Licensable”

means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed by
this License.

1.10. “Modifications”

means any of the following:

a. any file in Source Code Form that results from an addition to, deletion
from, or modification of the contents of Covered Software; or

b. any new file in Source Code Form that contains any Covered Software.

1.11. “Patent Claims” of a Contributor

means any patent claim(s), including without limitation, method, process,
and apparatus claims, in any patent Licensable by such Contributor that
would be infringed, but for the grant of the License, by the making,
using, selling, offering for sale, having made, import, or transfer of
either its Contributions or its Contributor Version.

1.12. “Secondary License”

means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.

1.13. “Source Code Form”

means the form of the work preferred for making modifications.

1.14. “You” (or “Your”)

means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, “control” means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.


2. License Grants and Conditions

2.1. Grants

Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:

a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or as
part of a Larger Work; and

b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions
or its Contributor Version.

2.2. Effective Date

The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.

2.3. Limitations on Grant Scope

The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:

a. for any code that a Contributor has removed from Covered Software; or

b. for infringements caused by: (i) Your and any other third party’s
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or

c. under Patent Claims infringed by Covered Software in the absence of its
Contributions.

This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the
notice requirements in Section 3.4).

2.4. Subsequent Licenses

No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this License
(see Section 10.2) or under the terms of a Secondary License (if permitted
under the terms of Section 3.3).

2.5. Representation

Each Contributor represents that the Contributor believes its Contributions
are its original creation(s) or it has sufficient rights to grant the
rights to its Contributions conveyed by this License.

2.6. Fair Use

This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.

2.7. Conditions

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.


3. Responsibilities

3.1. Distribution of Source Form

All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form
of the Covered Software is governed by the terms of this License, and how
they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients’ rights in the Source Code Form.

3.2. Distribution of Executable Form

If You distribute Covered Software in Executable Form then:

a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and

b. You may distribute such Executable Form under the terms of this License,
or sublicense it under different terms, provided that the license for
the Executable Form does not attempt to limit or alter the recipients’
rights in the Source Code Form under this License.

3.3. Distribution of a Larger Work

You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software
with a work governed by one or more Secondary Licenses, and the Covered
Software is not Incompatible With Secondary Licenses, this License permits
You to additionally distribute such Covered Software under the terms of
such Secondary License(s), so that the recipient of the Larger Work may, at
their option, further distribute the Covered Software under the terms of
either this License or such Secondary License(s).

3.4. Notices

You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations
of liability) contained within the Source Code Form of the Covered
Software, except that You may alter any license notices to the extent
required to remedy known factual inaccuracies.

3.5. Application of Additional Terms

You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on behalf
of any Contributor. You must make it absolutely clear that any such
warranty, support, indemnity, or liability obligation is offered by You
alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.

4. Inability to Comply Due to Statute or Regulation

If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: (a) comply with the terms of this License
to the maximum extent possible; and (b) describe the limitations and the code
they affect. Such description must be placed in a text file included with all
distributions of the Covered Software under this License. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.

5. Termination

5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
if such Contributor fails to notify You of the non-compliance by some
reasonable means prior to 60 days after You have come back into compliance.
Moreover, Your grants from a particular Contributor are reinstated on an
ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of
non-compliance with this License from such Contributor, and You become
compliant prior to 30 days after Your receipt of the notice.

5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims,
and cross-claims) alleging that a Contributor Version directly or
indirectly infringes any patent, then the rights granted to You by any and
all Contributors for the Covered Software under Section 2.1 of this License
shall terminate.

5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.

6. Disclaimer of Warranty

Covered Software is provided under this License on an “as is” basis, without
warranty of any kind, either expressed, implied, or statutory, including,
without limitation, warranties that the Covered Software is free of defects,
merchantable, fit for a particular purpose or non-infringing. The entire
risk as to the quality and performance of the Covered Software is with You.
Should any Covered Software prove defective in any respect, You (not any
Contributor) assume the cost of any necessary servicing, repair, or
correction. This disclaimer of warranty constitutes an essential part of this
License. No use of any Covered Software is authorized under this License
except under this disclaimer.

7. Limitation of Liability

Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from such
party’s negligence to the extent applicable law prohibits such limitation.
Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.

8. Litigation

Any litigation relating to this License may be brought only in the courts of
a jurisdiction where the defendant maintains its principal place of business
and such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a party’s ability to bring cross-claims or counter-claims.

9. Miscellaneous

This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.


10. Versions of the License

10.1. New Versions

Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.

10.2. Effect of New Versions

You may distribute the Covered Software under the terms of the version of
the License under which You originally received the Covered Software, or
under the terms of any subsequent version published by the license
steward.

10.3. Modified Versions

If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a modified
version of this License if you rename the license and remove any
references to the name of the license steward (except to note that such
modified license differs from this License).

10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.

Exhibit A - Source Code Form License Notice

This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.

If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

Exhibit B - “Incompatible With Secondary Licenses” Notice

This Source Code Form is “Incompatible
With Secondary Licenses”, as defined by
the Mozilla Public License, v. 2.0.

+ 31
- 0
vendor/github.com/hashicorp/go-multierror/Makefile View File

@@ -0,0 +1,31 @@
TEST?=./...

default: test

# test runs the test suite and vets the code.
test: generate
@echo "==> Running tests..."
@go list $(TEST) \
| grep -v "/vendor/" \
| xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS}

# testrace runs the race checker
testrace: generate
@echo "==> Running tests (race)..."
@go list $(TEST) \
| grep -v "/vendor/" \
| xargs -n1 go test -timeout=60s -race ${TESTARGS}

# updatedeps installs all the dependencies needed to run and build.
updatedeps:
@sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'"

# generate runs `go generate` to build the dynamically generated source files.
generate:
@echo "==> Generating..."
@find . -type f -name '.DS_Store' -delete
@go list ./... \
| grep -v "/vendor/" \
| xargs -n1 go generate

.PHONY: default test testrace updatedeps generate

+ 97
- 0
vendor/github.com/hashicorp/go-multierror/README.md View File

@@ -0,0 +1,97 @@
# go-multierror

[![Build Status](http://img.shields.io/travis/hashicorp/go-multierror.svg?style=flat-square)][travis]
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]

[travis]: https://travis-ci.org/hashicorp/go-multierror
[godocs]: https://godoc.org/github.com/hashicorp/go-multierror

`go-multierror` is a package for Go that provides a mechanism for
representing a list of `error` values as a single `error`.

This allows a function in Go to return an `error` that might actually
be a list of errors. If the caller knows this, they can unwrap the
list and access the errors. If the caller doesn't know, the error
formats to a nice human-readable format.

`go-multierror` implements the
[errwrap](https://github.com/hashicorp/errwrap) interface so that it can
be used with that library, as well.

## Installation and Docs

Install using `go get github.com/hashicorp/go-multierror`.

Full documentation is available at
http://godoc.org/github.com/hashicorp/go-multierror

## Usage

go-multierror is easy to use and purposely built to be unobtrusive in
existing Go applications/libraries that may not be aware of it.

**Building a list of errors**

The `Append` function is used to create a list of errors. This function
behaves a lot like the Go built-in `append` function: it doesn't matter
if the first argument is nil, a `multierror.Error`, or any other `error`,
the function behaves as you would expect.

```go
var result error

if err := step1(); err != nil {
result = multierror.Append(result, err)
}
if err := step2(); err != nil {
result = multierror.Append(result, err)
}

return result
```

**Customizing the formatting of the errors**

By specifying a custom `ErrorFormat`, you can customize the format
of the `Error() string` function:

```go
var result *multierror.Error

// ... accumulate errors here, maybe using Append

if result != nil {
result.ErrorFormat = func([]error) string {
return "errors!"
}
}
```

**Accessing the list of errors**

`multierror.Error` implements `error` so if the caller doesn't know about
multierror, it will work just fine. But if you're aware a multierror might
be returned, you can use type switches to access the list of errors:

```go
if err := something(); err != nil {
if merr, ok := err.(*multierror.Error); ok {
// Use merr.Errors
}
}
```

**Returning a multierror only if there are errors**

If you build a `multierror.Error`, you can use the `ErrorOrNil` function
to return an `error` implementation only if there are errors to return:

```go
var result *multierror.Error

// ... accumulate errors here

// Return the `error` only if errors were added to the multierror, otherwise
// return nil since there are no errors.
return result.ErrorOrNil()
```

+ 41
- 0
vendor/github.com/hashicorp/go-multierror/append.go View File

@@ -0,0 +1,41 @@
package multierror

// Append is a helper function that will append more errors
// onto an Error in order to create a larger multi-error.
//
// If err is not a multierror.Error, then it will be turned into
// one. If any of the errs are multierr.Error, they will be flattened
// one level into err.
func Append(err error, errs ...error) *Error {
switch err := err.(type) {
case *Error:
// Typed nils can reach here, so initialize if we are nil
if err == nil {
err = new(Error)
}

// Go through each error and flatten
for _, e := range errs {
switch e := e.(type) {
case *Error:
if e != nil {
err.Errors = append(err.Errors, e.Errors...)
}
default:
if e != nil {
err.Errors = append(err.Errors, e)
}
}
}

return err
default:
newErrs := make([]error, 0, len(errs)+1)
if err != nil {
newErrs = append(newErrs, err)
}
newErrs = append(newErrs, errs...)

return Append(&Error{}, newErrs...)
}
}

+ 26
- 0
vendor/github.com/hashicorp/go-multierror/flatten.go View File

@@ -0,0 +1,26 @@
package multierror

// Flatten flattens the given error, merging any *Errors together into
// a single *Error.
func Flatten(err error) error {
// If it isn't an *Error, just return the error as-is
if _, ok := err.(*Error); !ok {
return err
}

// Otherwise, make the result and flatten away!
flatErr := new(Error)
flatten(err, flatErr)
return flatErr
}

func flatten(err error, flatErr *Error) {
switch err := err.(type) {
case *Error:
for _, e := range err.Errors {
flatten(e, flatErr)
}
default:
flatErr.Errors = append(flatErr.Errors, err)
}
}

+ 27
- 0
vendor/github.com/hashicorp/go-multierror/format.go View File

@@ -0,0 +1,27 @@
package multierror

import (
"fmt"
"strings"
)

// ErrorFormatFunc is a function callback that is called by Error to
// turn the list of errors into a string.
type ErrorFormatFunc func([]error) string

// ListFormatFunc is a basic formatter that outputs the number of errors
// that occurred along with a bullet point list of the errors.
func ListFormatFunc(es []error) string {
if len(es) == 1 {
return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
}

points := make([]string, len(es))
for i, err := range es {
points[i] = fmt.Sprintf("* %s", err)
}

return fmt.Sprintf(
"%d errors occurred:\n\t%s\n\n",
len(es), strings.Join(points, "\n\t"))
}

+ 3
- 0
vendor/github.com/hashicorp/go-multierror/go.mod View File

@@ -0,0 +1,3 @@
module github.com/hashicorp/go-multierror

require github.com/hashicorp/errwrap v1.0.0

+ 4
- 0
vendor/github.com/hashicorp/go-multierror/go.sum View File

@@ -0,0 +1,4 @@
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=

+ 51
- 0
vendor/github.com/hashicorp/go-multierror/multierror.go View File

@@ -0,0 +1,51 @@
package multierror

import (
"fmt"
)

// Error is an error type to track multiple errors. This is used to
// accumulate errors in cases and return them as a single "error".
type Error struct {
Errors []error
ErrorFormat ErrorFormatFunc
}

func (e *Error) Error() string {
fn := e.ErrorFormat
if fn == nil {
fn = ListFormatFunc
}

return fn(e.Errors)
}

// ErrorOrNil returns an error interface if this Error represents
// a list of errors, or returns nil if the list of errors is empty. This
// function is useful at the end of accumulation to make sure that the value
// returned represents the existence of errors.
func (e *Error) ErrorOrNil() error {
if e == nil {
return nil
}
if len(e.Errors) == 0 {
return nil
}

return e
}

func (e *Error) GoString() string {
return fmt.Sprintf("*%#v", *e)
}

// WrappedErrors returns the list of errors that this Error is wrapping.
// It is an implementation of the errwrap.Wrapper interface so that
// multierror.Error can be used with that library.
//
// This method is not safe to be called concurrently and is no different
// than accessing the Errors field directly. It is implemented only to
// satisfy the errwrap.Wrapper interface.
func (e *Error) WrappedErrors() []error {
return e.Errors
}

+ 37
- 0
vendor/github.com/hashicorp/go-multierror/prefix.go View File

@@ -0,0 +1,37 @@
package multierror

import (
"fmt"

"github.com/hashicorp/errwrap"
)

// Prefix is a helper function that will prefix some text
// to the given error. If the error is a multierror.Error, then
// it will be prefixed to each wrapped error.
//
// This is useful to use when appending multiple multierrors
// together in order to give better scoping.
func Prefix(err error, prefix string) error {
if err == nil {
return nil
}

format := fmt.Sprintf("%s {{err}}", prefix)
switch err := err.(type) {
case *Error:
// Typed nils can reach here, so initialize if we are nil
if err == nil {
err = new(Error)
}

// Wrap each of the errors
for i, e := range err.Errors {
err.Errors[i] = errwrap.Wrapf(format, e)
}

return err
default:
return errwrap.Wrapf(format, err)
}
}

+ 16
- 0
vendor/github.com/hashicorp/go-multierror/sort.go View File

@@ -0,0 +1,16 @@
package multierror

// Len implements sort.Interface function for length
func (err Error) Len() int {
return len(err.Errors)
}

// Swap implements sort.Interface function for swapping elements
func (err Error) Swap(i, j int) {
err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
}

// Less implements sort.Interface function for determining order
func (err Error) Less(i, j int) bool {
return err.Errors[i].Error() < err.Errors[j].Error()
}

+ 11
- 0
vendor/github.com/howeyc/gopass/.travis.yml View File

@@ -0,0 +1,11 @@
language: go

os:
- linux
- osx

go:
- 1.3
- 1.4
- 1.5
- tip

+ 15
- 0
vendor/github.com/howeyc/gopass/LICENSE.txt View File

@@ -0,0 +1,15 @@
ISC License

Copyright (c) 2012 Chris Howey

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 384
- 0
vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE View File

@@ -0,0 +1,384 @@
Unless otherwise noted, all files in this distribution are released
under the Common Development and Distribution License (CDDL).
Exceptions are noted within the associated source files.

--------------------------------------------------------------------


COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0

1. Definitions.

1.1. "Contributor" means each individual or entity that creates
or contributes to the creation of Modifications.

1.2. "Contributor Version" means the combination of the Original
Software, prior Modifications used by a Contributor (if any),
and the Modifications made by that particular Contributor.

1.3. "Covered Software" means (a) the Original Software, or (b)
Modifications, or (c) the combination of files containing
Original Software with files containing Modifications, in
each case including portions thereof.

1.4. "Executable" means the Covered Software in any form other
than Source Code.

1.5. "Initial Developer" means the individual or entity that first
makes Original Software available under this License.

1.6. "Larger Work" means a work which combines Covered Software or
portions thereof with code not governed by the terms of this
License.

1.7. "License" means this document.

1.8. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed
herein.

1.9. "Modifications" means the Source Code and Executable form of
any of the following:

A. Any file that results from an addition to, deletion from or
modification of the contents of a file containing Original
Software or previous Modifications;

B. Any new file that contains any part of the Original
Software or previous Modifications; or

C. Any new file that is contributed or otherwise made
available under the terms of this License.

1.10. "Original Software" means the Source Code and Executable
form of computer software code that is originally released
under this License.

1.11. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method,
process, and apparatus claims, in any patent Licensable by
grantor.

1.12. "Source Code" means (a) the common form of computer software
code in which modifications are made and (b) associated
documentation included in or with such code.

1.13. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms
of, this License. For legal entities, "You" includes any
entity which controls, is controlled by, or is under common
control with You. For purposes of this definition,
"control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty
percent (50%) of the outstanding shares or beneficial
ownership of such entity.

2. License Grants.

2.1. The Initial Developer Grant.

Conditioned upon Your compliance with Section 3.1 below and
subject to third party intellectual property claims, the Initial
Developer hereby grants You a world-wide, royalty-free,
non-exclusive license:

(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer, to use,
reproduce, modify, display, perform, sublicense and
distribute the Original Software (or portions thereof),
with or without Modifications, and/or as part of a Larger
Work; and

(b) under Patent Claims infringed by the making, using or
selling of Original Software, to make, have made, use,
practice, sell, and offer for sale, and/or otherwise
dispose of the Original Software (or portions thereof).

(c) The licenses granted in Sections 2.1(a) and (b) are
effective on the date Initial Developer first distributes
or otherwise makes the Original Software available to a
third party under the terms of this License.

(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: (1) for code that You delete from the Original
Software, or (2) for infringements caused by: (i) the
modification of the Original Software, or (ii) the
combination of the Original Software with other software
or devices.

2.2. Contributor Grant.

Conditioned upon Your compliance with Section 3.1 below and
subject to third party intellectual property claims, each
Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:

(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor to use, reproduce,
modify, display, perform, sublicense and distribute the
Modifications created by such Contributor (or portions
thereof), either on an unmodified basis, with other
Modifications, as Covered Software and/or as part of a
Larger Work; and

(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either
alone and/or in combination with its Contributor Version
(or portions of such combination), to make, use, sell,
offer for sale, have made, and/or otherwise dispose of:
(1) Modifications made by that Contributor (or portions
thereof); and (2) the combination of Modifications made by
that Contributor with its Contributor Version (or portions
of such combination).

(c) The licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first distributes or
otherwise makes the Modifications available to a third
party.

(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: (1) for any code that Contributor has deleted
from the Contributor Version; (2) for infringements caused
by: (i) third party modifications of Contributor Version,
or (ii) the combination of Modifications made by that
Contributor with other software (except as part of the
Contributor Version) or other devices; or (3) under Patent
Claims infringed by Covered Software in the absence of
Modifications made by that Contributor.

3. Distribution Obligations.

3.1. Availability of Source Code.

Any Covered Software that You distribute or otherwise make
available in Executable form must also be made available in Source
Code form and that Source Code form must be distributed only under
the terms of this License. You must include a copy of this
License with every copy of the Source Code form of the Covered
Software You distribute or otherwise make available. You must
inform recipients of any such Covered Software in Executable form
as to how they can obtain such Covered Software in Source Code
form in a reasonable manner on or through a medium customarily
used for software exchange.

3.2. Modifications.

The Modifications that You create or to which You contribute are
governed by the terms of this License. You represent that You
believe Your Modifications are Your original creation(s) and/or
You have sufficient rights to grant the rights conveyed by this
License.

3.3. Required Notices.

You must include a notice in each of Your Modifications that
identifies You as the Contributor of the Modification. You may
not remove or alter any copyright, patent or trademark notices
contained within the Covered Software, or any notices of licensing
or any descriptive text giving attribution to any Contributor or
the Initial Developer.

3.4. Application of Additional Terms.

You may not offer or impose any terms on any Covered Software in
Source Code form that alters or restricts the applicable version
of this License or the recipients' rights hereunder. You may
choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of
Covered Software. However, you may do so only on Your own behalf,
and not on behalf of the Initial Developer or any Contributor.
You must make it absolutely clear that any such warranty, support,
indemnity or liability obligation is offered by You alone, and You
hereby agree to indemnify the Initial Developer and every
Contributor for any liability incurred by the Initial Developer or
such Contributor as a result of warranty, support, indemnity or
liability terms You offer.

3.5. Distribution of Executable Versions.

You may distribute the Executable form of the Covered Software
under the terms of this License or under the terms of a license of
Your choice, which may contain terms different from this License,
provided that You are in compliance with the terms of this License
and that the license for the Executable form does not attempt to
limit or alter the recipient's rights in the Source Code form from
the rights set forth in this License. If You distribute the
Covered Software in Executable form under a different license, You
must make it absolutely clear that any terms which differ from
this License are offered by You alone, not by the Initial
Developer or Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred
by the Initial Developer or such Contributor as a result of any
such terms You offer.

3.6. Larger Works.

You may create a Larger Work by combining Covered Software with
other code not governed by the terms of this License and
distribute the Larger Work as a single product. In such a case,
You must make sure the requirements of this License are fulfilled
for the Covered Software.

4. Versions of the License.

4.1. New Versions.

Sun Microsystems, Inc. is the initial license steward and may
publish revised and/or new versions of this License from time to
time. Each version will be given a distinguishing version number.
Except as provided in Section 4.3, no one other than the license
steward has the right to modify this License.

4.2. Effect of New Versions.

You may always continue to use, distribute or otherwise make the
Covered Software available under the terms of the version of the
License under which You originally received the Covered Software.
If the Initial Developer includes a notice in the Original
Software prohibiting it from being distributed or otherwise made
available under any subsequent version of the License, You must
distribute and make the Covered Software available under the terms
of the version of the License under which You originally received
the Covered Software. Otherwise, You may also choose to use,
distribute or otherwise make the Covered Software available under
the terms of any subsequent version of the License published by
the license steward.

4.3. Modified Versions.

When You are an Initial Developer and You want to create a new
license for Your Original Software, You may create and use a
modified version of this License if You: (a) rename the license
and remove any references to the name of the license steward
(except to note that the license differs from this License); and
(b) otherwise make it clear that the license contains terms which
differ from this License.

5. DISCLAIMER OF WARRANTY.

COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
DISCLAIMER.

6. TERMINATION.

6.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to
cure such breach within 30 days of becoming aware of the breach.
Provisions which, by their nature, must remain in effect beyond
the termination of this License shall survive.

6.2. If You assert a patent infringement claim (excluding
declaratory judgment actions) against Initial Developer or a
Contributor (the Initial Developer or Contributor against whom You
assert such claim is referred to as "Participant") alleging that
the Participant Software (meaning the Contributor Version where
the Participant is a Contributor or the Original Software where
the Participant is the Initial Developer) directly or indirectly
infringes any patent, then any and all rights granted directly or
indirectly to You by such Participant, the Initial Developer (if
the Initial Developer is not the Participant) and all Contributors
under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
notice from Participant terminate prospectively and automatically
at the expiration of such 60 day notice period, unless if within
such 60 day period You withdraw Your claim with respect to the
Participant Software against such Participant either unilaterally
or pursuant to a written agreement with Participant.

6.3. In the event of termination under Sections 6.1 or 6.2 above,
all end user licenses that have been validly granted by You or any
distributor hereunder prior to termination (excluding licenses
granted to You by any distributor) shall survive termination.

7. LIMITATION OF LIABILITY.

UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
APPLY TO YOU.

8. U.S. GOVERNMENT END USERS.

The Covered Software is a "commercial item," as that term is
defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
computer software" (as that term is defined at 48
C.F.R. 252.227-7014(a)(1)) and "commercial computer software
documentation" as such terms are used in 48 C.F.R. 12.212
(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48
C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
U.S. Government End Users acquire Covered Software with only those
rights set forth herein. This U.S. Government Rights clause is in
lieu of, and supersedes, any other FAR, DFAR, or other clause or
provision that addresses Government rights in computer software
under this License.

9. MISCELLANEOUS.

This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed
by the law of the jurisdiction specified in a notice contained
within the Original Software (except to the extent applicable law,
if any, provides otherwise), excluding such jurisdiction's
conflict-of-law provisions. Any litigation relating to this
License shall be subject to the jurisdiction of the courts located
in the jurisdiction and venue specified in a notice contained
within the Original Software, with the losing party responsible
for costs, including, without limitation, court costs and
reasonable attorneys' fees and expenses. The application of the
United Nations Convention on Contracts for the International Sale
of Goods is expressly excluded. Any law or regulation which
provides that the language of a contract shall be construed
against the drafter shall not apply to this License. You agree
that You alone are responsible for compliance with the United
States export administration regulations (and the export control
laws and regulation of any other countries) when You use,
distribute or otherwise make available any Covered Software.

10. RESPONSIBILITY FOR CLAIMS.

As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or
indirectly, out of its utilization of rights under this License
and You agree to work with Initial Developer and Contributors to
distribute such responsibility on an equitable basis. Nothing
herein is intended or shall be deemed to constitute any admission
of liability.

--------------------------------------------------------------------

NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
DISTRIBUTION LICENSE (CDDL)

For Covered Software in this distribution, this License shall
be governed by the laws of the State of California (excluding
conflict-of-law provisions).

Any litigation relating to this License shall be subject to the
jurisdiction of the Federal Courts of the Northern District of
California and the state courts of the State of California, with
venue lying in Santa Clara County, California.

+ 27
- 0
vendor/github.com/howeyc/gopass/README.md View File

@@ -0,0 +1,27 @@
# getpasswd in Go [![GoDoc](https://godoc.org/github.com/howeyc/gopass?status.svg)](https://godoc.org/github.com/howeyc/gopass) [![Build Status](https://secure.travis-ci.org/howeyc/gopass.png?branch=master)](http://travis-ci.org/howeyc/gopass)

Retrieve password from user terminal or piped input without echo.

Verified on BSD, Linux, and Windows.

Example:
```go
package main

import "fmt"
import "github.com/howeyc/gopass"

func main() {
fmt.Printf("Password: ")

// Silent. For printing *'s use gopass.GetPasswdMasked()
pass, err := gopass.GetPasswd()
if err != nil {
// Handle gopass.ErrInterrupted or getch() read error
}

// Do something with pass
}
```

Caution: Multi-byte characters not supported!

+ 110
- 0
vendor/github.com/howeyc/gopass/pass.go View File

@@ -0,0 +1,110 @@
package gopass

import (
"errors"
"fmt"
"io"
"os"
)

type FdReader interface {
io.Reader
Fd() uintptr
}

var defaultGetCh = func(r io.Reader) (byte, error) {
buf := make([]byte, 1)
if n, err := r.Read(buf); n == 0 || err != nil {
if err != nil {
return 0, err
}
return 0, io.EOF
}
return buf[0], nil
}

var (
maxLength = 512
ErrInterrupted = errors.New("interrupted")
ErrMaxLengthExceeded = fmt.Errorf("maximum byte limit (%v) exceeded", maxLength)

// Provide variable so that tests can provide a mock implementation.
getch = defaultGetCh
)

// getPasswd returns the input read from terminal.
// If prompt is not empty, it will be output as a prompt to the user
// If masked is true, typing will be matched by asterisks on the screen.
// Otherwise, typing will echo nothing.
func getPasswd(prompt string, masked bool, r FdReader, w io.Writer) ([]byte, error) {
var err error
var pass, bs, mask []byte
if masked {
bs = []byte("\b \b")
mask = []byte("*")
}

if isTerminal(r.Fd()) {
if oldState, err := makeRaw(r.Fd()); err != nil {
return pass, err
} else {
defer func() {
restore(r.Fd(), oldState)
fmt.Fprintln(w)
}()
}
}

if prompt != "" {
fmt.Fprint(w, prompt)
}

// Track total bytes read, not just bytes in the password. This ensures any
// errors that might flood the console with nil or -1 bytes infinitely are
// capped.
var counter int
for counter = 0; counter <= maxLength; counter++ {
if v, e := getch(r); e != nil {
err = e
break
} else if v == 127 || v == 8 {
if l := len(pass); l > 0 {
pass = pass[:l-1]
fmt.Fprint(w, string(bs))
}
} else if v == 13 || v == 10 {
break
} else if v == 3 {
err = ErrInterrupted
break
} else if v != 0 {
pass = append(pass, v)
fmt.Fprint(w, string(mask))
}
}

if counter > maxLength {
err = ErrMaxLengthExceeded
}

return pass, err
}

// GetPasswd returns the password read from the terminal without echoing input.
// The returned byte array does not include end-of-line characters.
func GetPasswd() ([]byte, error) {
return getPasswd("", false, os.Stdin, os.Stdout)
}

// GetPasswdMasked returns the password read from the terminal, echoing asterisks.
// The returned byte array does not include end-of-line characters.
func GetPasswdMasked() ([]byte, error) {
return getPasswd("", true, os.Stdin, os.Stdout)
}

// GetPasswdPrompt prompts the user and returns the password read from the terminal.
// If mask is true, then asterisks are echoed.
// The returned byte array does not include end-of-line characters.
func GetPasswdPrompt(prompt string, mask bool, r FdReader, w io.Writer) ([]byte, error) {
return getPasswd(prompt, mask, r, w)
}

+ 25
- 0
vendor/github.com/howeyc/gopass/terminal.go View File

@@ -0,0 +1,25 @@
// +build !solaris

package gopass

import "golang.org/x/crypto/ssh/terminal"

type terminalState struct {
state *terminal.State
}

func isTerminal(fd uintptr) bool {
return terminal.IsTerminal(int(fd))
}

func makeRaw(fd uintptr) (*terminalState, error) {
state, err := terminal.MakeRaw(int(fd))

return &terminalState{
state: state,
}, err
}

func restore(fd uintptr, oldState *terminalState) error {
return terminal.Restore(int(fd), oldState.state)
}

+ 69
- 0
vendor/github.com/howeyc/gopass/terminal_solaris.go View File

@@ -0,0 +1,69 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
// Below is derived from Solaris source, so CDDL license is included.

package gopass

import (
"syscall"

"golang.org/x/sys/unix"
)

type terminalState struct {
state *unix.Termios
}

// isTerminal returns true if there is a terminal attached to the given
// file descriptor.
// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
func isTerminal(fd uintptr) bool {
var termio unix.Termio
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
return err == nil
}

// makeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
func makeRaw(fd uintptr) (*terminalState, error) {
oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
if err != nil {
return nil, err
}
oldTermios := *oldTermiosPtr

newTermios := oldTermios
newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL
if err := unix.IoctlSetTermios(int(fd), unix.TCSETS, &newTermios); err != nil {
return nil, err
}

return &terminalState{
state: oldTermiosPtr,
}, nil
}

func restore(fd uintptr, oldState *terminalState) error {
return unix.IoctlSetTermios(int(fd), unix.TCSETS, oldState.state)
}

+ 1
- 0
vendor/github.com/microcosm-cc/bluemonday/.coveralls.yml View File

@@ -0,0 +1 @@
repo_token: x2wlA1x0X8CK45ybWpZRCVRB4g7vtkhaw

+ 21
- 0
vendor/github.com/microcosm-cc/bluemonday/.travis.yml View File

@@ -0,0 +1,21 @@
language: go
go:
- 1.1
- 1.2
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- 1.10
- tip
matrix:
allow_failures:
- go: tip
fast_finish: true
install:
- go get golang.org/x/net/html
script:
- go test -v ./...

+ 51
- 0
vendor/github.com/microcosm-cc/bluemonday/CONTRIBUTING.md View File

@@ -0,0 +1,51 @@
# Contributing to bluemonday

Third-party patches are essential for keeping bluemonday secure and offering the features developers want. However there are a few guidelines that we need contributors to follow so that we can maintain the quality of work that developers who use bluemonday expect.

## Getting Started

* Make sure you have a [Github account](https://github.com/signup/free)

## Guidelines

1. Do not vendor dependencies. As a security package, were we to vendor dependencies the projects that then vendor bluemonday may not receive the latest security updates to the dependencies. By not vendoring dependencies the project that implements bluemonday will vendor the latest version of any dependent packages. Vendoring is a project problem, not a package problem. bluemonday will be tested against the latest version of dependencies periodically and during any PR/merge.

## Submitting an Issue

* Submit a ticket for your issue, assuming one does not already exist
* Clearly describe the issue including the steps to reproduce (with sample input and output) if it is a bug

If you are reporting a security flaw, you may expect that we will provide the code to fix it for you. Otherwise you may want to submit a pull request to ensure the resolution is applied sooner rather than later:

* Fork the repository on Github
* Issue a pull request containing code to resolve the issue

## Submitting a Pull Request

* Submit a ticket for your issue, assuming one does not already exist
* Describe the reason for the pull request and if applicable show some example inputs and outputs to demonstrate what the patch does
* Fork the repository on Github
* Before submitting the pull request you should
1. Include tests for your patch, 1 test should encapsulate the entire patch and should refer to the Github issue
1. If you have added new exposed/public functionality, you should ensure it is documented appropriately
1. If you have added new exposed/public functionality, you should consider demonstrating how to use it within one of the helpers or shipped policies if appropriate or within a test if modifying a helper or policy is not appropriate
1. Run all of the tests `go test -v ./...` or `make test` and ensure all tests pass
1. Run gofmt `gofmt -w ./$*` or `make fmt`
1. Run vet `go tool vet *.go` or `make vet` and resolve any issues
1. Install golint using `go get -u github.com/golang/lint/golint` and run vet `golint *.go` or `make lint` and resolve every warning
* When submitting the pull request you should
1. Note the issue(s) it resolves, i.e. `Closes #6` in the pull request comment to close issue #6 when the pull request is accepted

Once you have submitted a pull request, we *may* merge it without changes. If we have any comments or feedback, or need you to make changes to your pull request we will update the Github pull request or the associated issue. We expect responses from you within two weeks, and we may close the pull request is there is no activity.

### Contributor Licence Agreement

We haven't gone for the formal "Sign a Contributor Licence Agreement" thing that projects like [puppet](https://cla.puppetlabs.com/), [Mojito](https://developer.yahoo.com/cocktails/mojito/cla/) and companies like [Google](http://code.google.com/legal/individual-cla-v1.0.html) are using.

But we do need to know that we can accept and merge your contributions, so for now the act of contributing a pull request should be considered equivalent to agreeing to a contributor licence agreement, specifically:

You accept that the act of submitting code to the bluemonday project is to grant a copyright licence to the project that is perpetual, worldwide, non-exclusive, no-charge, royalty free and irrevocable.

You accept that all who comply with the licence of the project (BSD 3-clause) are permitted to use your contributions to the project.

You accept, and by submitting code do declare, that you have the legal right to grant such a licence to the project and that each of the contributions is your own original creation.

+ 6
- 0
vendor/github.com/microcosm-cc/bluemonday/CREDITS.md View File

@@ -0,0 +1,6 @@
1. Andrew Krasichkov @buglloc https://github.com/buglloc
1. John Graham-Cumming http://jgc.org/
1. Mike Samuel mikesamuel@gmail.com
1. Dmitri Shuralyov shurcooL@gmail.com
1. https://github.com/opennota
1. https://github.com/Gufran

+ 28
- 0
vendor/github.com/microcosm-cc/bluemonday/LICENSE.md View File

@@ -0,0 +1,28 @@
Copyright (c) 2014, David Kitchen <david@buro9.com>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the organisation (Microcosm) nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 42
- 0
vendor/github.com/microcosm-cc/bluemonday/Makefile View File

@@ -0,0 +1,42 @@
# Targets:
#
# all: Builds the code locally after testing
#
# fmt: Formats the source files
# build: Builds the code locally
# vet: Vets the code
# lint: Runs lint over the code (you do not need to fix everything)
# test: Runs the tests
# cover: Gives you the URL to a nice test coverage report
#
# install: Builds, tests and installs the code locally

.PHONY: all fmt build vet lint test cover install

# The first target is always the default action if `make` is called without
# args we build and install into $GOPATH so that it can just be run

all: fmt vet test install

fmt:
@gofmt -s -w ./$*

build:
@go build

vet:
@go vet *.go

lint:
@golint *.go

test:
@go test -v ./...

cover: COVERAGE_FILE := coverage.out
cover:
@go test -coverprofile=$(COVERAGE_FILE) && \
cover -html=$(COVERAGE_FILE) && rm $(COVERAGE_FILE)

install:
@go install ./...

+ 350
- 0
vendor/github.com/microcosm-cc/bluemonday/README.md View File

@@ -0,0 +1,350 @@
# bluemonday [![Build Status](https://travis-ci.org/microcosm-cc/bluemonday.svg?branch=master)](https://travis-ci.org/microcosm-cc/bluemonday) [![GoDoc](https://godoc.org/github.com/microcosm-cc/bluemonday?status.png)](https://godoc.org/github.com/microcosm-cc/bluemonday) [![Sourcegraph](https://sourcegraph.com/github.com/microcosm-cc/bluemonday/-/badge.svg)](https://sourcegraph.com/github.com/microcosm-cc/bluemonday?badge)

bluemonday is a HTML sanitizer implemented in Go. It is fast and highly configurable.

bluemonday takes untrusted user generated content as an input, and will return HTML that has been sanitised against a whitelist of approved HTML elements and attributes so that you can safely include the content in your web page.

If you accept user generated content, and your server uses Go, you **need** bluemonday.

The default policy for user generated content (`bluemonday.UGCPolicy().Sanitize()`) turns this:
```html
Hello <STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A>World
```

Into a harmless:
```html
Hello World
```

And it turns this:
```html
<a href="javascript:alert('XSS1')" onmouseover="alert('XSS2')">XSS<a>
```

Into this:
```html
XSS
```

Whilst still allowing this:
```html
<a href="http://www.google.com/">
<img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>
```

To pass through mostly unaltered (it gained a rel="nofollow" which is a good thing for user generated content):
```html
<a href="http://www.google.com/" rel="nofollow">
<img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>
```

It protects sites from [XSS](http://en.wikipedia.org/wiki/Cross-site_scripting) attacks. There are many [vectors for an XSS attack](https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet) and the best way to mitigate the risk is to sanitize user input against a known safe list of HTML elements and attributes.

You should **always** run bluemonday **after** any other processing.

If you use [blackfriday](https://github.com/russross/blackfriday) or [Pandoc](http://johnmacfarlane.net/pandoc/) then bluemonday should be run after these steps. This ensures that no insecure HTML is introduced later in your process.

bluemonday is heavily inspired by both the [OWASP Java HTML Sanitizer](https://code.google.com/p/owasp-java-html-sanitizer/) and the [HTML Purifier](http://htmlpurifier.org/).

## Technical Summary

Whitelist based, you need to either build a policy describing the HTML elements and attributes to permit (and the `regexp` patterns of attributes), or use one of the supplied policies representing good defaults.

The policy containing the whitelist is applied using a fast non-validating, forward only, token-based parser implemented in the [Go net/html library](https://godoc.org/golang.org/x/net/html) by the core Go team.

We expect to be supplied with well-formatted HTML (closing elements for every applicable open element, nested correctly) and so we do not focus on repairing badly nested or incomplete HTML. We focus on simply ensuring that whatever elements do exist are described in the policy whitelist and that attributes and links are safe for use on your web page. [GIGO](http://en.wikipedia.org/wiki/Garbage_in,_garbage_out) does apply and if you feed it bad HTML bluemonday is not tasked with figuring out how to make it good again.

### Supported Go Versions

bluemonday is tested against Go 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, and tip.

We do not support Go 1.0 as we depend on `golang.org/x/net/html` which includes a reference to `io.ErrNoProgress` which did not exist in Go 1.0.

## Is it production ready?

*Yes*

We are using bluemonday in production having migrated from the widely used and heavily field tested OWASP Java HTML Sanitizer.

We are passing our extensive test suite (including AntiSamy tests as well as tests for any issues raised). Check for any [unresolved issues](https://github.com/microcosm-cc/bluemonday/issues?page=1&state=open) to see whether anything may be a blocker for you.

We invite pull requests and issues to help us ensure we are offering comprehensive protection against various attacks via user generated content.

## Usage

Install in your `${GOPATH}` using `go get -u github.com/microcosm-cc/bluemonday`

Then call it:
```go
package main

import (
"fmt"

"github.com/microcosm-cc/bluemonday"
)

func main() {
// Do this once for each unique policy, and use the policy for the life of the program
// Policy creation/editing is not safe to use in multiple goroutines
p := bluemonday.UGCPolicy()
// The policy can then be used to sanitize lots of input and it is safe to use the policy in multiple goroutines
html := p.Sanitize(
`<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
)

// Output:
// <a href="http://www.google.com" rel="nofollow">Google</a>
fmt.Println(html)
}
```

We offer three ways to call Sanitize:
```go
p.Sanitize(string) string
p.SanitizeBytes([]byte) []byte
p.SanitizeReader(io.Reader) bytes.Buffer
```

If you are obsessed about performance, `p.SanitizeReader(r).Bytes()` will return a `[]byte` without performing any unnecessary casting of the inputs or outputs. Though the difference is so negligible you should never need to care.

You can build your own policies:
```go
package main

import (
"fmt"

"github.com/microcosm-cc/bluemonday"
)

func main() {
p := bluemonday.NewPolicy()

// Require URLs to be parseable by net/url.Parse and either:
// mailto: http:// or https://
p.AllowStandardURLs()

// We only allow <p> and <a href="">
p.AllowAttrs("href").OnElements("a")
p.AllowElements("p")

html := p.Sanitize(
`<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
)

// Output:
// <a href="http://www.google.com">Google</a>
fmt.Println(html)
}
```

We ship two default policies:

1. `bluemonday.StrictPolicy()` which can be thought of as equivalent to stripping all HTML elements and their attributes as it has nothing on its whitelist. An example usage scenario would be blog post titles where HTML tags are not expected at all and if they are then the elements *and* the content of the elements should be stripped. This is a *very* strict policy.
2. `bluemonday.UGCPolicy()` which allows a broad selection of HTML elements and attributes that are safe for user generated content. Note that this policy does *not* whitelist iframes, object, embed, styles, script, etc. An example usage scenario would be blog post bodies where a variety of formatting is expected along with the potential for TABLEs and IMGs.

## Policy Building

The essence of building a policy is to determine which HTML elements and attributes are considered safe for your scenario. OWASP provide an [XSS prevention cheat sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) to help explain the risks, but essentially:

1. Avoid anything other than the standard HTML elements
1. Avoid `script`, `style`, `iframe`, `object`, `embed`, `base` elements that allow code to be executed by the client or third party content to be included that can execute code
1. Avoid anything other than plain HTML attributes with values matched to a regexp

Basically, you should be able to describe what HTML is fine for your scenario. If you do not have confidence that you can describe your policy please consider using one of the shipped policies such as `bluemonday.UGCPolicy()`.

To create a new policy:
```go
p := bluemonday.NewPolicy()
```

To add elements to a policy either add just the elements:
```go
p.AllowElements("b", "strong")
```

Or add elements as a virtue of adding an attribute:
```go
// Not the recommended pattern, see the recommendation on using .Matching() below
p.AllowAttrs("nowrap").OnElements("td", "th")
```

Attributes can either be added to all elements:
```go
p.AllowAttrs("dir").Matching(regexp.MustCompile("(?i)rtl|ltr")).Globally()
```

Or attributes can be added to specific elements:
```go
// Not the recommended pattern, see the recommendation on using .Matching() below
p.AllowAttrs("value").OnElements("li")
```

It is **always** recommended that an attribute be made to match a pattern. XSS in HTML attributes is very easy otherwise:
```go
// \p{L} matches unicode letters, \p{N} matches unicode numbers
p.AllowAttrs("title").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally()
```

You can stop at any time and call .Sanitize():
```go
// string htmlIn passed in from a HTTP POST
htmlOut := p.Sanitize(htmlIn)
```

And you can take any existing policy and extend it:
```go
p := bluemonday.UGCPolicy()
p.AllowElements("fieldset", "select", "option")
```

### Links

Links are difficult beasts to sanitise safely and also one of the biggest attack vectors for malicious content.

It is possible to do this:
```go
p.AllowAttrs("href").Matching(regexp.MustCompile(`(?i)mailto|https?`)).OnElements("a")
```

But that will not protect you as the regular expression is insufficient in this case to have prevented a malformed value doing something unexpected.

We provide some additional global options for safely working with links.

`RequireParseableURLs` will ensure that URLs are parseable by Go's `net/url` package:
```go
p.RequireParseableURLs(true)
```

If you have enabled parseable URLs then the following option will `AllowRelativeURLs`. By default this is disabled (bluemonday is a whitelist tool... you need to explicitly tell us to permit things) and when disabled it will prevent all local and scheme relative URLs (i.e. `href="localpage.html"`, `href="../home.html"` and even `href="//www.google.com"` are relative):
```go
p.AllowRelativeURLs(true)
```

If you have enabled parseable URLs then you can whitelist the schemes (commonly called protocol when thinking of `http` and `https`) that are permitted. Bear in mind that allowing relative URLs in the above option will allow for a blank scheme:
```go
p.AllowURLSchemes("mailto", "http", "https")
```

Regardless of whether you have enabled parseable URLs, you can force all URLs to have a rel="nofollow" attribute. This will be added if it does not exist, but only when the `href` is valid:
```go
// This applies to "a" "area" "link" elements that have a "href" attribute
p.RequireNoFollowOnLinks(true)
```

We provide a convenience method that applies all of the above, but you will still need to whitelist the linkable elements for the URL rules to be applied to:
```go
p.AllowStandardURLs()
p.AllowAttrs("cite").OnElements("blockquote", "q")
p.AllowAttrs("href").OnElements("a", "area")
p.AllowAttrs("src").OnElements("img")
```

An additional complexity regarding links is the data URI as defined in [RFC2397](http://tools.ietf.org/html/rfc2397). The data URI allows for images to be served inline using this format:

```html
<img src="data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=">
```

We have provided a helper to verify the mimetype followed by base64 content of data URIs links:

```go
p.AllowDataURIImages()
```

That helper will enable GIF, JPEG, PNG and WEBP images.

It should be noted that there is a potential [security](http://palizine.plynt.com/issues/2010Oct/bypass-xss-filters/) [risk](https://capec.mitre.org/data/definitions/244.html) with the use of data URI links. You should only enable data URI links if you already trust the content.

We also have some features to help deal with user generated content:
```go
p.AddTargetBlankToFullyQualifiedLinks(true)
```

This will ensure that anchor `<a href="" />` links that are fully qualified (the href destination includes a host name) will get `target="_blank"` added to them.

Additionally any link that has `target="_blank"` after the policy has been applied will also have the `rel` attribute adjusted to add `noopener`. This means a link may start like `<a href="//host/path"/>` and will end up as `<a href="//host/path" rel="noopener" target="_blank">`. It is important to note that the addition of `noopener` is a security feature and not an issue. There is an unfortunate feature to browsers that a browser window opened as a result of `target="_blank"` can still control the opener (your web page) and this protects against that. The background to this can be found here: [https://dev.to/ben/the-targetblank-vulnerability-by-example](https://dev.to/ben/the-targetblank-vulnerability-by-example)

### Policy Building Helpers

We also bundle some helpers to simplify policy building:
```go

// Permits the "dir", "id", "lang", "title" attributes globally
p.AllowStandardAttributes()

// Permits the "img" element and its standard attributes
p.AllowImages()

// Permits ordered and unordered lists, and also definition lists
p.AllowLists()

// Permits HTML tables and all applicable elements and non-styling attributes
p.AllowTables()
```

### Invalid Instructions

The following are invalid:
```go
// This does not say where the attributes are allowed, you need to add
// .Globally() or .OnElements(...)
// This will be ignored without error.
p.AllowAttrs("value")

// This does not say where the attributes are allowed, you need to add
// .Globally() or .OnElements(...)
// This will be ignored without error.
p.AllowAttrs(
"type",
).Matching(
regexp.MustCompile("(?i)^(circle|disc|square|a|A|i|I|1)$"),
)
```

Both examples exhibit the same issue, they declare attributes but do not then specify whether they are whitelisted globally or only on specific elements (and which elements). Attributes belong to one or more elements, and the policy needs to declare this.

## Limitations

We are not yet including any tools to help whitelist and sanitize CSS. Which means that unless you wish to do the heavy lifting in a single regular expression (inadvisable), **you should not allow the "style" attribute anywhere**.

It is not the job of bluemonday to fix your bad HTML, it is merely the job of bluemonday to prevent malicious HTML getting through. If you have mismatched HTML elements, or non-conforming nesting of elements, those will remain. But if you have well-structured HTML bluemonday will not break it.

## TODO

* Add support for CSS sanitisation to allow some CSS properties based on a whitelist, possibly using the [Gorilla CSS3 scanner](http://www.gorillatoolkit.org/pkg/css/scanner) - PRs welcome so long as testing covers XSS and demonstrates safety first
* Investigate whether devs want to blacklist elements and attributes. This would allow devs to take an existing policy (such as the `bluemonday.UGCPolicy()` ) that encapsulates 90% of what they're looking for but does more than they need, and to remove the extra things they do not want to make it 100% what they want
* Investigate whether devs want a validating HTML mode, in which the HTML elements are not just transformed into a balanced tree (every start tag has a closing tag at the correct depth) but also that elements and character data appear only in their allowed context (i.e. that a `table` element isn't a descendent of a `caption`, that `colgroup`, `thead`, `tbody`, `tfoot` and `tr` are permitted, and that character data is not permitted)

## Development

If you have cloned this repo you will probably need the dependency:

`go get golang.org/x/net/html`

Gophers can use their familiar tools:

`go build`

`go test`

I personally use a Makefile as it spares typing the same args over and over whilst providing consistency for those of us who jump from language to language and enjoy just typing `make` in a project directory and watch magic happen.

`make` will build, vet, test and install the library.

`make clean` will remove the library from a *single* `${GOPATH}/pkg` directory tree

`make test` will run the tests

`make cover` will run the tests and *open a browser window* with the coverage report

`make lint` will run golint (install via `go get github.com/golang/lint/golint`)

## Long term goals

1. Open the code to adversarial peer review similar to the [Attack Review Ground Rules](https://code.google.com/p/owasp-java-html-sanitizer/wiki/AttackReviewGroundRules)
1. Raise funds and pay for an external security review

+ 104
- 0
vendor/github.com/microcosm-cc/bluemonday/doc.go View File

@@ -0,0 +1,104 @@
// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/*
Package bluemonday provides a way of describing a whitelist of HTML elements
and attributes as a policy, and for that policy to be applied to untrusted
strings from users that may contain markup. All elements and attributes not on
the whitelist will be stripped.

The default bluemonday.UGCPolicy().Sanitize() turns this:

Hello <STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A>World

Into the more harmless:

Hello World

And it turns this:

<a href="javascript:alert('XSS1')" onmouseover="alert('XSS2')">XSS<a>

Into this:

XSS

Whilst still allowing this:

<a href="http://www.google.com/">
<img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>

To pass through mostly unaltered (it gained a rel="nofollow"):

<a href="http://www.google.com/" rel="nofollow">
<img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>

The primary purpose of bluemonday is to take potentially unsafe user generated
content (from things like Markdown, HTML WYSIWYG tools, etc) and make it safe
for you to put on your website.

It protects sites against XSS (http://en.wikipedia.org/wiki/Cross-site_scripting)
and other malicious content that a user interface may deliver. There are many
vectors for an XSS attack (https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet)
and the safest thing to do is to sanitize user input against a known safe list
of HTML elements and attributes.

Note: You should always run bluemonday after any other processing.

If you use blackfriday (https://github.com/russross/blackfriday) or
Pandoc (http://johnmacfarlane.net/pandoc/) then bluemonday should be run after
these steps. This ensures that no insecure HTML is introduced later in your
process.

bluemonday is heavily inspired by both the OWASP Java HTML Sanitizer
(https://code.google.com/p/owasp-java-html-sanitizer/) and the HTML Purifier
(http://htmlpurifier.org/).

We ship two default policies, one is bluemonday.StrictPolicy() and can be
thought of as equivalent to stripping all HTML elements and their attributes as
it has nothing on its whitelist.

The other is bluemonday.UGCPolicy() and allows a broad selection of HTML
elements and attributes that are safe for user generated content. Note that
this policy does not whitelist iframes, object, embed, styles, script, etc.

The essence of building a policy is to determine which HTML elements and
attributes are considered safe for your scenario. OWASP provide an XSS
prevention cheat sheet ( https://www.google.com/search?q=xss+prevention+cheat+sheet )
to help explain the risks, but essentially:

1. Avoid whitelisting anything other than plain HTML elements
2. Avoid whitelisting `script`, `style`, `iframe`, `object`, `embed`, `base`
elements
3. Avoid whitelisting anything other than plain HTML elements with simple
values that you can match to a regexp
*/
package bluemonday

+ 297
- 0
vendor/github.com/microcosm-cc/bluemonday/helpers.go View File

@@ -0,0 +1,297 @@
// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bluemonday

import (
"encoding/base64"
"net/url"
"regexp"
)

// A selection of regular expressions that can be used as .Matching() rules on
// HTML attributes.
var (
// CellAlign handles the `align` attribute
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-align
CellAlign = regexp.MustCompile(`(?i)^(center|justify|left|right|char)$`)

// CellVerticalAlign handles the `valign` attribute
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-valign
CellVerticalAlign = regexp.MustCompile(`(?i)^(baseline|bottom|middle|top)$`)

// Direction handles the `dir` attribute
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo#attr-dir
Direction = regexp.MustCompile(`(?i)^(rtl|ltr)$`)

// ImageAlign handles the `align` attribute on the `image` tag
// http://www.w3.org/MarkUp/Test/Img/imgtest.html
ImageAlign = regexp.MustCompile(
`(?i)^(left|right|top|texttop|middle|absmiddle|baseline|bottom|absbottom)$`,
)

// Integer describes whole positive integers (including 0) used in places
// like td.colspan
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-colspan
Integer = regexp.MustCompile(`^[0-9]+$`)

// ISO8601 according to the W3 group is only a subset of the ISO8601
// standard: http://www.w3.org/TR/NOTE-datetime
//
// Used in places like time.datetime
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#attr-datetime
//
// Matches patterns:
// Year:
// YYYY (eg 1997)
// Year and month:
// YYYY-MM (eg 1997-07)
// Complete date:
// YYYY-MM-DD (eg 1997-07-16)
// Complete date plus hours and minutes:
// YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
// Complete date plus hours, minutes and seconds:
// YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
// Complete date plus hours, minutes, seconds and a decimal fraction of a
// second
// YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
ISO8601 = regexp.MustCompile(
`^[0-9]{4}(-[0-9]{2}(-[0-9]{2}([ T][0-9]{2}(:[0-9]{2}){1,2}(.[0-9]{1,6})` +
`?Z?([\+-][0-9]{2}:[0-9]{2})?)?)?)?$`,
)

// ListType encapsulates the common value as well as the latest spec
// values for lists
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol#attr-type
ListType = regexp.MustCompile(`(?i)^(circle|disc|square|a|A|i|I|1)$`)

// SpaceSeparatedTokens is used in places like `a.rel` and the common attribute
// `class` which both contain space delimited lists of data tokens
// http://www.w3.org/TR/html-markup/datatypes.html#common.data.tokens-def
// Regexp: \p{L} matches unicode letters, \p{N} matches unicode numbers
SpaceSeparatedTokens = regexp.MustCompile(`^([\s\p{L}\p{N}_-]+)$`)

// Number is a double value used on HTML5 meter and progress elements
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-meter-element
Number = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$`)

// NumberOrPercent is used predominantly as units of measurement in width
// and height attributes
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-height
NumberOrPercent = regexp.MustCompile(`^[0-9]+[%]?$`)

// Paragraph of text in an attribute such as *.'title', img.alt, etc
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-title
// Note that we are not allowing chars that could close tags like '>'
Paragraph = regexp.MustCompile(`^[\p{L}\p{N}\s\-_',\[\]!\./\\\(\)]*$`)

// dataURIImagePrefix is used by AllowDataURIImages to define the acceptable
// prefix of data URIs that contain common web image formats.
//
// This is not exported as it's not useful by itself, and only has value
// within the AllowDataURIImages func
dataURIImagePrefix = regexp.MustCompile(
`^image/(gif|jpeg|png|webp);base64,`,
)
)

// AllowStandardURLs is a convenience function that will enable rel="nofollow"
// on "a", "area" and "link" (if you have allowed those elements) and will
// ensure that the URL values are parseable and either relative or belong to the
// "mailto", "http", or "https" schemes
func (p *Policy) AllowStandardURLs() {
// URLs must be parseable by net/url.Parse()
p.RequireParseableURLs(true)

// !url.IsAbs() is permitted
p.AllowRelativeURLs(true)

// Most common URL schemes only
p.AllowURLSchemes("mailto", "http", "https")

// For all anchors we will add rel="nofollow" if it does not already exist
// This applies to "a" "area" "link"
p.RequireNoFollowOnLinks(true)
}

// AllowStandardAttributes will enable "id", "title" and the language specific
// attributes "dir" and "lang" on all elements that are whitelisted
func (p *Policy) AllowStandardAttributes() {
// "dir" "lang" are permitted as both language attributes affect charsets
// and direction of text.
p.AllowAttrs("dir").Matching(Direction).Globally()
p.AllowAttrs(
"lang",
).Matching(regexp.MustCompile(`[a-zA-Z]{2,20}`)).Globally()

// "id" is permitted. This is pretty much as some HTML elements require this
// to work well ("dfn" is an example of a "id" being value)
// This does create a risk that JavaScript and CSS within your web page
// might identify the wrong elements. Ensure that you select things
// accurately
p.AllowAttrs("id").Matching(
regexp.MustCompile(`[a-zA-Z0-9\:\-_\.]+`),
).Globally()

// "title" is permitted as it improves accessibility.
p.AllowAttrs("title").Matching(Paragraph).Globally()
}

// AllowStyling presently enables the class attribute globally.
//
// Note: When bluemonday ships a CSS parser and we can safely sanitise that,
// this will also allow sanitized styling of elements via the style attribute.
func (p *Policy) AllowStyling() {

// "class" is permitted globally
p.AllowAttrs("class").Matching(SpaceSeparatedTokens).Globally()
}

// AllowImages enables the img element and some popular attributes. It will also
// ensure that URL values are parseable. This helper does not enable data URI
// images, for that you should also use the AllowDataURIImages() helper.
func (p *Policy) AllowImages() {

// "img" is permitted
p.AllowAttrs("align").Matching(ImageAlign).OnElements("img")
p.AllowAttrs("alt").Matching(Paragraph).OnElements("img")
p.AllowAttrs("height", "width").Matching(NumberOrPercent).OnElements("img")

// Standard URLs enabled
p.AllowStandardURLs()
p.AllowAttrs("src").OnElements("img")
}

// AllowDataURIImages permits the use of inline images defined in RFC2397
// http://tools.ietf.org/html/rfc2397
// http://en.wikipedia.org/wiki/Data_URI_scheme
//
// Images must have a mimetype matching:
// image/gif
// image/jpeg
// image/png
// image/webp
//
// NOTE: There is a potential security risk to allowing data URIs and you should
// only permit them on content you already trust.
// http://palizine.plynt.com/issues/2010Oct/bypass-xss-filters/
// https://capec.mitre.org/data/definitions/244.html
func (p *Policy) AllowDataURIImages() {

// URLs must be parseable by net/url.Parse()
p.RequireParseableURLs(true)

// Supply a function to validate images contained within data URI
p.AllowURLSchemeWithCustomPolicy(
"data",
func(url *url.URL) (allowUrl bool) {
if url.RawQuery != "" || url.Fragment != "" {
return false
}

matched := dataURIImagePrefix.FindString(url.Opaque)
if matched == "" {
return false
}

_, err := base64.StdEncoding.DecodeString(url.Opaque[len(matched):])
if err != nil {
return false
}

return true
},
)
}

// AllowLists will enabled ordered and unordered lists, as well as definition
// lists
func (p *Policy) AllowLists() {
// "ol" "ul" are permitted
p.AllowAttrs("type").Matching(ListType).OnElements("ol", "ul")

// "li" is permitted
p.AllowAttrs("type").Matching(ListType).OnElements("li")
p.AllowAttrs("value").Matching(Integer).OnElements("li")

// "dl" "dt" "dd" are permitted
p.AllowElements("dl", "dt", "dd")
}

// AllowTables will enable a rich set of elements and attributes to describe
// HTML tables
func (p *Policy) AllowTables() {

// "table" is permitted
p.AllowAttrs("height", "width").Matching(NumberOrPercent).OnElements("table")
p.AllowAttrs("summary").Matching(Paragraph).OnElements("table")

// "caption" is permitted
p.AllowElements("caption")

// "col" "colgroup" are permitted
p.AllowAttrs("align").Matching(CellAlign).OnElements("col", "colgroup")
p.AllowAttrs("height", "width").Matching(
NumberOrPercent,
).OnElements("col", "colgroup")
p.AllowAttrs("span").Matching(Integer).OnElements("colgroup", "col")
p.AllowAttrs("valign").Matching(
CellVerticalAlign,
).OnElements("col", "colgroup")

// "thead" "tr" are permitted
p.AllowAttrs("align").Matching(CellAlign).OnElements("thead", "tr")
p.AllowAttrs("valign").Matching(CellVerticalAlign).OnElements("thead", "tr")

// "td" "th" are permitted
p.AllowAttrs("abbr").Matching(Paragraph).OnElements("td", "th")
p.AllowAttrs("align").Matching(CellAlign).OnElements("td", "th")
p.AllowAttrs("colspan", "rowspan").Matching(Integer).OnElements("td", "th")
p.AllowAttrs("headers").Matching(
SpaceSeparatedTokens,
).OnElements("td", "th")
p.AllowAttrs("height", "width").Matching(
NumberOrPercent,
).OnElements("td", "th")
p.AllowAttrs(
"scope",
).Matching(
regexp.MustCompile(`(?i)(?:row|col)(?:group)?`),
).OnElements("td", "th")
p.AllowAttrs("valign").Matching(CellVerticalAlign).OnElements("td", "th")
p.AllowAttrs("nowrap").Matching(
regexp.MustCompile(`(?i)|nowrap`),
).OnElements("td", "th")

// "tbody" "tfoot"
p.AllowAttrs("align").Matching(CellAlign).OnElements("tbody", "tfoot")
p.AllowAttrs("valign").Matching(
CellVerticalAlign,
).OnElements("tbody", "tfoot")
}

+ 253
- 0
vendor/github.com/microcosm-cc/bluemonday/policies.go View File

@@ -0,0 +1,253 @@
// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bluemonday

import (
"regexp"
)

// StrictPolicy returns an empty policy, which will effectively strip all HTML
// elements and their attributes from a document.
func StrictPolicy() *Policy {
return NewPolicy()
}

// StripTagsPolicy is DEPRECATED. Use StrictPolicy instead.
func StripTagsPolicy() *Policy {
return StrictPolicy()
}

// UGCPolicy returns a policy aimed at user generated content that is a result
// of HTML WYSIWYG tools and Markdown conversions.
//
// This is expected to be a fairly rich document where as much markup as
// possible should be retained. Markdown permits raw HTML so we are basically
// providing a policy to sanitise HTML5 documents safely but with the
// least intrusion on the formatting expectations of the user.
func UGCPolicy() *Policy {

p := NewPolicy()

///////////////////////
// Global attributes //
///////////////////////

// "class" is not permitted as we are not allowing users to style their own
// content

p.AllowStandardAttributes()

//////////////////////////////
// Global URL format policy //
//////////////////////////////

p.AllowStandardURLs()

////////////////////////////////
// Declarations and structure //
////////////////////////////////

// "xml" "xslt" "DOCTYPE" "html" "head" are not permitted as we are
// expecting user generated content to be a fragment of HTML and not a full
// document.

//////////////////////////
// Sectioning root tags //
//////////////////////////

// "article" and "aside" are permitted and takes no attributes
p.AllowElements("article", "aside")

// "body" is not permitted as we are expecting user generated content to be a fragment
// of HTML and not a full document.

// "details" is permitted, including the "open" attribute which can either
// be blank or the value "open".
p.AllowAttrs(
"open",
).Matching(regexp.MustCompile(`(?i)^(|open)$`)).OnElements("details")

// "fieldset" is not permitted as we are not allowing forms to be created.

// "figure" is permitted and takes no attributes
p.AllowElements("figure")

// "nav" is not permitted as it is assumed that the site (and not the user)
// has defined navigation elements

// "section" is permitted and takes no attributes
p.AllowElements("section")

// "summary" is permitted and takes no attributes
p.AllowElements("summary")

//////////////////////////
// Headings and footers //
//////////////////////////

// "footer" is not permitted as we expect user content to be a fragment and
// not structural to this extent

// "h1" through "h6" are permitted and take no attributes
p.AllowElements("h1", "h2", "h3", "h4", "h5", "h6")

// "header" is not permitted as we expect user content to be a fragment and
// not structural to this extent

// "hgroup" is permitted and takes no attributes
p.AllowElements("hgroup")

/////////////////////////////////////
// Content grouping and separating //
/////////////////////////////////////

// "blockquote" is permitted, including the "cite" attribute which must be
// a standard URL.
p.AllowAttrs("cite").OnElements("blockquote")

// "br" "div" "hr" "p" "span" "wbr" are permitted and take no attributes
p.AllowElements("br", "div", "hr", "p", "span", "wbr")

///////////
// Links //
///////////

// "a" is permitted
p.AllowAttrs("href").OnElements("a")

// "area" is permitted along with the attributes that map image maps work
p.AllowAttrs("name").Matching(
regexp.MustCompile(`^([\p{L}\p{N}_-]+)$`),
).OnElements("map")
p.AllowAttrs("alt").Matching(Paragraph).OnElements("area")
p.AllowAttrs("coords").Matching(
regexp.MustCompile(`^([0-9]+,)+[0-9]+$`),
).OnElements("area")
p.AllowAttrs("href").OnElements("area")
p.AllowAttrs("rel").Matching(SpaceSeparatedTokens).OnElements("area")
p.AllowAttrs("shape").Matching(
regexp.MustCompile(`(?i)^(default|circle|rect|poly)$`),
).OnElements("area")
p.AllowAttrs("usemap").Matching(
regexp.MustCompile(`(?i)^#[\p{L}\p{N}_-]+$`),
).OnElements("img")

// "link" is not permitted

/////////////////////
// Phrase elements //
/////////////////////

// The following are all inline phrasing elements
p.AllowElements("abbr", "acronym", "cite", "code", "dfn", "em",
"figcaption", "mark", "s", "samp", "strong", "sub", "sup", "var")

// "q" is permitted and "cite" is a URL and handled by URL policies
p.AllowAttrs("cite").OnElements("q")

// "time" is permitted
p.AllowAttrs("datetime").Matching(ISO8601).OnElements("time")

////////////////////
// Style elements //
////////////////////

// block and inline elements that impart no semantic meaning but style the
// document
p.AllowElements("b", "i", "pre", "small", "strike", "tt", "u")

// "style" is not permitted as we are not yet sanitising CSS and it is an
// XSS attack vector

//////////////////////
// HTML5 Formatting //
//////////////////////

// "bdi" "bdo" are permitted
p.AllowAttrs("dir").Matching(Direction).OnElements("bdi", "bdo")

// "rp" "rt" "ruby" are permitted
p.AllowElements("rp", "rt", "ruby")

///////////////////////////
// HTML5 Change tracking //
///////////////////////////

// "del" "ins" are permitted
p.AllowAttrs("cite").Matching(Paragraph).OnElements("del", "ins")
p.AllowAttrs("datetime").Matching(ISO8601).OnElements("del", "ins")

///////////
// Lists //
///////////

p.AllowLists()

////////////
// Tables //
////////////

p.AllowTables()

///////////
// Forms //
///////////

// By and large, forms are not permitted. However there are some form
// elements that can be used to present data, and we do permit those
//
// "button" "fieldset" "input" "keygen" "label" "output" "select" "datalist"
// "textarea" "optgroup" "option" are all not permitted

// "meter" is permitted
p.AllowAttrs(
"value",
"min",
"max",
"low",
"high",
"optimum",
).Matching(Number).OnElements("meter")

// "progress" is permitted
p.AllowAttrs("value", "max").Matching(Number).OnElements("progress")

//////////////////////
// Embedded content //
//////////////////////

// Vast majority not permitted
// "audio" "canvas" "embed" "iframe" "object" "param" "source" "svg" "track"
// "video" are all not permitted

p.AllowImages()

return p
}

+ 552
- 0
vendor/github.com/microcosm-cc/bluemonday/policy.go View File

@@ -0,0 +1,552 @@
// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bluemonday

import (
"net/url"
"regexp"
"strings"
)

// Policy encapsulates the whitelist of HTML elements and attributes that will
// be applied to the sanitised HTML.
//
// You should use bluemonday.NewPolicy() to create a blank policy as the
// unexported fields contain maps that need to be initialized.
type Policy struct {

// Declares whether the maps have been initialized, used as a cheap check to
// ensure that those using Policy{} directly won't cause nil pointer
// exceptions
initialized bool

// If true then we add spaces when stripping tags, specifically the closing
// tag is replaced by a space character.
addSpaces bool

// When true, add rel="nofollow" to HTML anchors
requireNoFollow bool

// When true, add rel="nofollow" to HTML anchors
// Will add for href="http://foo"
// Will skip for href="/foo" or href="foo"
requireNoFollowFullyQualifiedLinks bool

// When true add target="_blank" to fully qualified links
// Will add for href="http://foo"
// Will skip for href="/foo" or href="foo"
addTargetBlankToFullyQualifiedLinks bool

// When true, URLs must be parseable by "net/url" url.Parse()
requireParseableURLs bool

// When true, u, _ := url.Parse("url"); !u.IsAbs() is permitted
allowRelativeURLs bool

// When true, allow data attributes.
allowDataAttributes bool

// map[htmlElementName]map[htmlAttributeName]attrPolicy
elsAndAttrs map[string]map[string]attrPolicy

// map[htmlAttributeName]attrPolicy
globalAttrs map[string]attrPolicy

// If urlPolicy is nil, all URLs with matching schema are allowed.
// Otherwise, only the URLs with matching schema and urlPolicy(url)
// returning true are allowed.
allowURLSchemes map[string]urlPolicy

// If an element has had all attributes removed as a result of a policy
// being applied, then the element would be removed from the output.
//
// However some elements are valid and have strong layout meaning without
// any attributes, i.e. <table>. To prevent those being removed we maintain
// a list of elements that are allowed to have no attributes and that will
// be maintained in the output HTML.
setOfElementsAllowedWithoutAttrs map[string]struct{}

setOfElementsToSkipContent map[string]struct{}
}

type attrPolicy struct {

// optional pattern to match, when not nil the regexp needs to match
// otherwise the attribute is removed
regexp *regexp.Regexp
}

type attrPolicyBuilder struct {
p *Policy

attrNames []string
regexp *regexp.Regexp
allowEmpty bool
}

type urlPolicy func(url *url.URL) (allowUrl bool)

// init initializes the maps if this has not been done already
func (p *Policy) init() {
if !p.initialized {
p.elsAndAttrs = make(map[string]map[string]attrPolicy)
p.globalAttrs = make(map[string]attrPolicy)
p.allowURLSchemes = make(map[string]urlPolicy)
p.setOfElementsAllowedWithoutAttrs = make(map[string]struct{})
p.setOfElementsToSkipContent = make(map[string]struct{})
p.initialized = true
}
}

// NewPolicy returns a blank policy with nothing whitelisted or permitted. This
// is the recommended way to start building a policy and you should now use
// AllowAttrs() and/or AllowElements() to construct the whitelist of HTML
// elements and attributes.
func NewPolicy() *Policy {

p := Policy{}

p.addDefaultElementsWithoutAttrs()
p.addDefaultSkipElementContent()

return &p
}

// AllowAttrs takes a range of HTML attribute names and returns an
// attribute policy builder that allows you to specify the pattern and scope of
// the whitelisted attribute.
//
// The attribute policy is only added to the core policy when either Globally()
// or OnElements(...) are called.
func (p *Policy) AllowAttrs(attrNames ...string) *attrPolicyBuilder {

p.init()

abp := attrPolicyBuilder{
p: p,
allowEmpty: false,
}

for _, attrName := range attrNames {
abp.attrNames = append(abp.attrNames, strings.ToLower(attrName))
}

return &abp
}

// AllowDataAttributes whitelists all data attributes. We can't specify the name
// of each attribute exactly as they are customized.
//
// NOTE: These values are not sanitized and applications that evaluate or process
// them without checking and verification of the input may be at risk if this option
// is enabled. This is a 'caveat emptor' option and the person enabling this option
// needs to fully understand the potential impact with regards to whatever application
// will be consuming the sanitized HTML afterwards, i.e. if you know you put a link in a
// data attribute and use that to automatically load some new window then you're giving
// the author of a HTML fragment the means to open a malicious destination automatically.
// Use with care!
func (p *Policy) AllowDataAttributes() {
p.allowDataAttributes = true
}

// AllowNoAttrs says that attributes on element are optional.
//
// The attribute policy is only added to the core policy when OnElements(...)
// are called.
func (p *Policy) AllowNoAttrs() *attrPolicyBuilder {

p.init()

abp := attrPolicyBuilder{
p: p,
allowEmpty: true,
}
return &abp
}

// AllowNoAttrs says that attributes on element are optional.
//
// The attribute policy is only added to the core policy when OnElements(...)
// are called.
func (abp *attrPolicyBuilder) AllowNoAttrs() *attrPolicyBuilder {

abp.allowEmpty = true

return abp
}

// Matching allows a regular expression to be applied to a nascent attribute
// policy, and returns the attribute policy. Calling this more than once will
// replace the existing regexp.
func (abp *attrPolicyBuilder) Matching(regex *regexp.Regexp) *attrPolicyBuilder {

abp.regexp = regex

return abp
}

// OnElements will bind an attribute policy to a given range of HTML elements
// and return the updated policy
func (abp *attrPolicyBuilder) OnElements(elements ...string) *Policy {

for _, element := range elements {
element = strings.ToLower(element)

for _, attr := range abp.attrNames {

if _, ok := abp.p.elsAndAttrs[element]; !ok {
abp.p.elsAndAttrs[element] = make(map[string]attrPolicy)
}

ap := attrPolicy{}
if abp.regexp != nil {
ap.regexp = abp.regexp
}

abp.p.elsAndAttrs[element][attr] = ap
}

if abp.allowEmpty {
abp.p.setOfElementsAllowedWithoutAttrs[element] = struct{}{}

if _, ok := abp.p.elsAndAttrs[element]; !ok {
abp.p.elsAndAttrs[element] = make(map[string]attrPolicy)
}
}
}

return abp.p
}

// Globally will bind an attribute policy to all HTML elements and return the
// updated policy
func (abp *attrPolicyBuilder) Globally() *Policy {

for _, attr := range abp.attrNames {
if _, ok := abp.p.globalAttrs[attr]; !ok {
abp.p.globalAttrs[attr] = attrPolicy{}
}

ap := attrPolicy{}
if abp.regexp != nil {
ap.regexp = abp.regexp
}

abp.p.globalAttrs[attr] = ap
}

return abp.p
}

// AllowElements will append HTML elements to the whitelist without applying an
// attribute policy to those elements (the elements are permitted
// sans-attributes)
func (p *Policy) AllowElements(names ...string) *Policy {
p.init()

for _, element := range names {
element = strings.ToLower(element)

if _, ok := p.elsAndAttrs[element]; !ok {
p.elsAndAttrs[element] = make(map[string]attrPolicy)
}
}

return p
}

// RequireNoFollowOnLinks will result in all <a> tags having a rel="nofollow"
// added to them if one does not already exist
//
// Note: This requires p.RequireParseableURLs(true) and will enable it.
func (p *Policy) RequireNoFollowOnLinks(require bool) *Policy {

p.requireNoFollow = require
p.requireParseableURLs = true

return p
}

// RequireNoFollowOnFullyQualifiedLinks will result in all <a> tags that point
// to a non-local destination (i.e. starts with a protocol and has a host)
// having a rel="nofollow" added to them if one does not already exist
//
// Note: This requires p.RequireParseableURLs(true) and will enable it.
func (p *Policy) RequireNoFollowOnFullyQualifiedLinks(require bool) *Policy {

p.requireNoFollowFullyQualifiedLinks = require
p.requireParseableURLs = true

return p
}

// AddTargetBlankToFullyQualifiedLinks will result in all <a> tags that point
// to a non-local destination (i.e. starts with a protocol and has a host)
// having a target="_blank" added to them if one does not already exist
//
// Note: This requires p.RequireParseableURLs(true) and will enable it.
func (p *Policy) AddTargetBlankToFullyQualifiedLinks(require bool) *Policy {

p.addTargetBlankToFullyQualifiedLinks = require
p.requireParseableURLs = true

return p
}

// RequireParseableURLs will result in all URLs requiring that they be parseable
// by "net/url" url.Parse()
// This applies to:
// - a.href
// - area.href
// - blockquote.cite
// - img.src
// - link.href
// - script.src
func (p *Policy) RequireParseableURLs(require bool) *Policy {

p.requireParseableURLs = require

return p
}

// AllowRelativeURLs enables RequireParseableURLs and then permits URLs that
// are parseable, have no schema information and url.IsAbs() returns false
// This permits local URLs
func (p *Policy) AllowRelativeURLs(require bool) *Policy {

p.RequireParseableURLs(true)
p.allowRelativeURLs = require

return p
}

// AllowURLSchemes will append URL schemes to the whitelist
// Example: p.AllowURLSchemes("mailto", "http", "https")
func (p *Policy) AllowURLSchemes(schemes ...string) *Policy {
p.init()

p.RequireParseableURLs(true)

for _, scheme := range schemes {
scheme = strings.ToLower(scheme)

// Allow all URLs with matching scheme.
p.allowURLSchemes[scheme] = nil
}

return p
}

// AllowURLSchemeWithCustomPolicy will append URL schemes with
// a custom URL policy to the whitelist.
// Only the URLs with matching schema and urlPolicy(url)
// returning true will be allowed.
func (p *Policy) AllowURLSchemeWithCustomPolicy(
scheme string,
urlPolicy func(url *url.URL) (allowUrl bool),
) *Policy {

p.init()

p.RequireParseableURLs(true)

scheme = strings.ToLower(scheme)

p.allowURLSchemes[scheme] = urlPolicy

return p
}

// AddSpaceWhenStrippingTag states whether to add a single space " " when
// removing tags that are not whitelisted by the policy.
//
// This is useful if you expect to strip tags in dense markup and may lose the
// value of whitespace.
//
// For example: "<p>Hello</p><p>World</p>"" would be sanitized to "HelloWorld"
// with the default value of false, but you may wish to sanitize this to
// " Hello World " by setting AddSpaceWhenStrippingTag to true as this would
// retain the intent of the text.
func (p *Policy) AddSpaceWhenStrippingTag(allow bool) *Policy {

p.addSpaces = allow

return p
}

// SkipElementsContent adds the HTML elements whose tags is needed to be removed
// with its content.
func (p *Policy) SkipElementsContent(names ...string) *Policy {

p.init()

for _, element := range names {
element = strings.ToLower(element)

if _, ok := p.setOfElementsToSkipContent[element]; !ok {
p.setOfElementsToSkipContent[element] = struct{}{}
}
}

return p
}

// AllowElementsContent marks the HTML elements whose content should be
// retained after removing the tag.
func (p *Policy) AllowElementsContent(names ...string) *Policy {

p.init()

for _, element := range names {
delete(p.setOfElementsToSkipContent, strings.ToLower(element))
}

return p
}

// addDefaultElementsWithoutAttrs adds the HTML elements that we know are valid
// without any attributes to an internal map.
// i.e. we know that <table> is valid, but <bdo> isn't valid as the "dir" attr
// is mandatory
func (p *Policy) addDefaultElementsWithoutAttrs() {
p.init()

p.setOfElementsAllowedWithoutAttrs["abbr"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["acronym"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["address"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["article"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["aside"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["audio"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["b"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["bdi"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["blockquote"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["body"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["br"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["button"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["canvas"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["caption"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["center"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["cite"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["code"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["col"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["colgroup"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["datalist"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["dd"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["del"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["details"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["dfn"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["div"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["dl"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["dt"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["em"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["fieldset"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["figcaption"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["figure"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["footer"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["h1"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["h2"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["h3"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["h4"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["h5"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["h6"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["head"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["header"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["hgroup"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["hr"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["html"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["i"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["ins"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["kbd"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["li"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["mark"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["marquee"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["nav"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["ol"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["optgroup"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["option"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["p"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["pre"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["q"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["rp"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["rt"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["ruby"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["s"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["samp"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["script"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["section"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["select"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["small"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["span"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["strike"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["strong"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["style"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["sub"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["summary"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["sup"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["svg"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["table"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["tbody"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["td"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["textarea"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["tfoot"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["th"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["thead"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["title"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["time"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["tr"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["tt"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["u"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["ul"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["var"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["video"] = struct{}{}
p.setOfElementsAllowedWithoutAttrs["wbr"] = struct{}{}

}

// addDefaultSkipElementContent adds the HTML elements that we should skip
// rendering the character content of, if the element itself is not allowed.
// This is all character data that the end user would not normally see.
// i.e. if we exclude a <script> tag then we shouldn't render the JavaScript or
// anything else until we encounter the closing </script> tag.
func (p *Policy) addDefaultSkipElementContent() {
p.init()

p.setOfElementsToSkipContent["frame"] = struct{}{}
p.setOfElementsToSkipContent["frameset"] = struct{}{}
p.setOfElementsToSkipContent["iframe"] = struct{}{}
p.setOfElementsToSkipContent["noembed"] = struct{}{}
p.setOfElementsToSkipContent["noframes"] = struct{}{}
p.setOfElementsToSkipContent["noscript"] = struct{}{}
p.setOfElementsToSkipContent["nostyle"] = struct{}{}
p.setOfElementsToSkipContent["object"] = struct{}{}
p.setOfElementsToSkipContent["script"] = struct{}{}
p.setOfElementsToSkipContent["style"] = struct{}{}
p.setOfElementsToSkipContent["title"] = struct{}{}
}

+ 581
- 0
vendor/github.com/microcosm-cc/bluemonday/sanitize.go View File

@@ -0,0 +1,581 @@
// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bluemonday

import (
"bytes"
"io"
"net/url"
"regexp"
"strings"

"golang.org/x/net/html"
)

var (
dataAttribute = regexp.MustCompile("^data-.+")
dataAttributeXMLPrefix = regexp.MustCompile("^xml.+")
dataAttributeInvalidChars = regexp.MustCompile("[A-Z;]+")
)

// Sanitize takes a string that contains a HTML fragment or document and applies
// the given policy whitelist.
//
// It returns a HTML string that has been sanitized by the policy or an empty
// string if an error has occurred (most likely as a consequence of extremely
// malformed input)
func (p *Policy) Sanitize(s string) string {
if strings.TrimSpace(s) == "" {
return s
}

return p.sanitize(strings.NewReader(s)).String()
}

// SanitizeBytes takes a []byte that contains a HTML fragment or document and applies
// the given policy whitelist.
//
// It returns a []byte containing the HTML that has been sanitized by the policy
// or an empty []byte if an error has occurred (most likely as a consequence of
// extremely malformed input)
func (p *Policy) SanitizeBytes(b []byte) []byte {
if len(bytes.TrimSpace(b)) == 0 {
return b
}

return p.sanitize(bytes.NewReader(b)).Bytes()
}

// SanitizeReader takes an io.Reader that contains a HTML fragment or document
// and applies the given policy whitelist.
//
// It returns a bytes.Buffer containing the HTML that has been sanitized by the
// policy. Errors during sanitization will merely return an empty result.
func (p *Policy) SanitizeReader(r io.Reader) *bytes.Buffer {
return p.sanitize(r)
}

// Performs the actual sanitization process.
func (p *Policy) sanitize(r io.Reader) *bytes.Buffer {

// It is possible that the developer has created the policy via:
// p := bluemonday.Policy{}
// rather than:
// p := bluemonday.NewPolicy()
// If this is the case, and if they haven't yet triggered an action that
// would initiliaze the maps, then we need to do that.
p.init()

var (
buff bytes.Buffer
skipElementContent bool
skippingElementsCount int64
skipClosingTag bool
closingTagToSkipStack []string
mostRecentlyStartedToken string
)

tokenizer := html.NewTokenizer(r)
for {
if tokenizer.Next() == html.ErrorToken {
err := tokenizer.Err()
if err == io.EOF {
// End of input means end of processing
return &buff
}

// Raw tokenizer error
return &bytes.Buffer{}
}

token := tokenizer.Token()
switch token.Type {
case html.DoctypeToken:

// DocType is not handled as there is no safe parsing mechanism
// provided by golang.org/x/net/html for the content, and this can
// be misused to insert HTML tags that are not then sanitized
//
// One might wish to recursively sanitize here using the same policy
// but I will need to do some further testing before considering
// this.

case html.CommentToken:

// Comments are ignored by default

case html.StartTagToken:

mostRecentlyStartedToken = token.Data

aps, ok := p.elsAndAttrs[token.Data]
if !ok {
if _, ok := p.setOfElementsToSkipContent[token.Data]; ok {
skipElementContent = true
skippingElementsCount++
}
if p.addSpaces {
buff.WriteString(" ")
}
break
}

if len(token.Attr) != 0 {
token.Attr = p.sanitizeAttrs(token.Data, token.Attr, aps)
}

if len(token.Attr) == 0 {
if !p.allowNoAttrs(token.Data) {
skipClosingTag = true
closingTagToSkipStack = append(closingTagToSkipStack, token.Data)
if p.addSpaces {
buff.WriteString(" ")
}
break
}
}

if !skipElementContent {
buff.WriteString(token.String())
}

case html.EndTagToken:

if mostRecentlyStartedToken == token.Data {
mostRecentlyStartedToken = ""
}

if skipClosingTag && closingTagToSkipStack[len(closingTagToSkipStack)-1] == token.Data {
closingTagToSkipStack = closingTagToSkipStack[:len(closingTagToSkipStack)-1]
if len(closingTagToSkipStack) == 0 {
skipClosingTag = false
}
if p.addSpaces {
buff.WriteString(" ")
}
break
}

if _, ok := p.elsAndAttrs[token.Data]; !ok {
if _, ok := p.setOfElementsToSkipContent[token.Data]; ok {
skippingElementsCount--
if skippingElementsCount == 0 {
skipElementContent = false
}
}
if p.addSpaces {
buff.WriteString(" ")
}
break
}

if !skipElementContent {
buff.WriteString(token.String())
}

case html.SelfClosingTagToken:

aps, ok := p.elsAndAttrs[token.Data]
if !ok {
if p.addSpaces {
buff.WriteString(" ")
}
break
}

if len(token.Attr) != 0 {
token.Attr = p.sanitizeAttrs(token.Data, token.Attr, aps)
}

if len(token.Attr) == 0 && !p.allowNoAttrs(token.Data) {
if p.addSpaces {
buff.WriteString(" ")
}
break
}

if !skipElementContent {
buff.WriteString(token.String())
}

case html.TextToken:

if !skipElementContent {
switch mostRecentlyStartedToken {
case "script":
// not encouraged, but if a policy allows JavaScript we
// should not HTML escape it as that would break the output
buff.WriteString(token.Data)
case "style":
// not encouraged, but if a policy allows CSS styles we
// should not HTML escape it as that would break the output
buff.WriteString(token.Data)
default:
// HTML escape the text
buff.WriteString(token.String())
}
}
default:
// A token that didn't exist in the html package when we wrote this
return &bytes.Buffer{}
}
}
}

// sanitizeAttrs takes a set of element attribute policies and the global
// attribute policies and applies them to the []html.Attribute returning a set
// of html.Attributes that match the policies
func (p *Policy) sanitizeAttrs(
elementName string,
attrs []html.Attribute,
aps map[string]attrPolicy,
) []html.Attribute {

if len(attrs) == 0 {
return attrs
}

// Builds a new attribute slice based on the whether the attribute has been
// whitelisted explicitly or globally.
cleanAttrs := []html.Attribute{}
for _, htmlAttr := range attrs {
if p.allowDataAttributes {
// If we see a data attribute, let it through.
if isDataAttribute(htmlAttr.Key) {
cleanAttrs = append(cleanAttrs, htmlAttr)
continue
}
}
// Is there an element specific attribute policy that applies?
if ap, ok := aps[htmlAttr.Key]; ok {
if ap.regexp != nil {
if ap.regexp.MatchString(htmlAttr.Val) {
cleanAttrs = append(cleanAttrs, htmlAttr)
continue
}
} else {
cleanAttrs = append(cleanAttrs, htmlAttr)
continue
}
}

// Is there a global attribute policy that applies?
if ap, ok := p.globalAttrs[htmlAttr.Key]; ok {

if ap.regexp != nil {
if ap.regexp.MatchString(htmlAttr.Val) {
cleanAttrs = append(cleanAttrs, htmlAttr)
}
} else {
cleanAttrs = append(cleanAttrs, htmlAttr)
}
}
}

if len(cleanAttrs) == 0 {
// If nothing was allowed, let's get out of here
return cleanAttrs
}
// cleanAttrs now contains the attributes that are permitted

if linkable(elementName) {
if p.requireParseableURLs {
// Ensure URLs are parseable:
// - a.href
// - area.href
// - link.href
// - blockquote.cite
// - q.cite
// - img.src
// - script.src
tmpAttrs := []html.Attribute{}
for _, htmlAttr := range cleanAttrs {
switch elementName {
case "a", "area", "link":
if htmlAttr.Key == "href" {
if u, ok := p.validURL(htmlAttr.Val); ok {
htmlAttr.Val = u
tmpAttrs = append(tmpAttrs, htmlAttr)
}
break
}
tmpAttrs = append(tmpAttrs, htmlAttr)
case "blockquote", "q":
if htmlAttr.Key == "cite" {
if u, ok := p.validURL(htmlAttr.Val); ok {
htmlAttr.Val = u
tmpAttrs = append(tmpAttrs, htmlAttr)
}
break
}
tmpAttrs = append(tmpAttrs, htmlAttr)
case "img", "script":
if htmlAttr.Key == "src" {
if u, ok := p.validURL(htmlAttr.Val); ok {
htmlAttr.Val = u
tmpAttrs = append(tmpAttrs, htmlAttr)
}
break
}
tmpAttrs = append(tmpAttrs, htmlAttr)
default:
tmpAttrs = append(tmpAttrs, htmlAttr)
}
}
cleanAttrs = tmpAttrs
}

if (p.requireNoFollow ||
p.requireNoFollowFullyQualifiedLinks ||
p.addTargetBlankToFullyQualifiedLinks) &&
len(cleanAttrs) > 0 {

// Add rel="nofollow" if a "href" exists
switch elementName {
case "a", "area", "link":
var hrefFound bool
var externalLink bool
for _, htmlAttr := range cleanAttrs {
if htmlAttr.Key == "href" {
hrefFound = true

u, err := url.Parse(htmlAttr.Val)
if err != nil {
continue
}
if u.Host != "" {
externalLink = true
}

continue
}
}

if hrefFound {
var (
noFollowFound bool
targetBlankFound bool
)

addNoFollow := (p.requireNoFollow ||
externalLink && p.requireNoFollowFullyQualifiedLinks)

addTargetBlank := (externalLink &&
p.addTargetBlankToFullyQualifiedLinks)

tmpAttrs := []html.Attribute{}
for _, htmlAttr := range cleanAttrs {

var appended bool
if htmlAttr.Key == "rel" && addNoFollow {

if strings.Contains(htmlAttr.Val, "nofollow") {
noFollowFound = true
tmpAttrs = append(tmpAttrs, htmlAttr)
appended = true
} else {
htmlAttr.Val += " nofollow"
noFollowFound = true
tmpAttrs = append(tmpAttrs, htmlAttr)
appended = true
}
}

if elementName == "a" && htmlAttr.Key == "target" {
if htmlAttr.Val == "_blank" {
targetBlankFound = true
}
if addTargetBlank && !targetBlankFound {
htmlAttr.Val = "_blank"
targetBlankFound = true
tmpAttrs = append(tmpAttrs, htmlAttr)
appended = true
}
}

if !appended {
tmpAttrs = append(tmpAttrs, htmlAttr)
}
}
if noFollowFound || targetBlankFound {
cleanAttrs = tmpAttrs
}

if addNoFollow && !noFollowFound {
rel := html.Attribute{}
rel.Key = "rel"
rel.Val = "nofollow"
cleanAttrs = append(cleanAttrs, rel)
}

if elementName == "a" && addTargetBlank && !targetBlankFound {
rel := html.Attribute{}
rel.Key = "target"
rel.Val = "_blank"
targetBlankFound = true
cleanAttrs = append(cleanAttrs, rel)
}

if targetBlankFound {
// target="_blank" has a security risk that allows the
// opened window/tab to issue JavaScript calls against
// window.opener, which in effect allow the destination
// of the link to control the source:
// https://dev.to/ben/the-targetblank-vulnerability-by-example
//
// To mitigate this risk, we need to add a specific rel
// attribute if it is not already present.
// rel="noopener"
//
// Unfortunately this is processing the rel twice (we
// already looked at it earlier ^^) as we cannot be sure
// of the ordering of the href and rel, and whether we
// have fully satisfied that we need to do this. This
// double processing only happens *if* target="_blank"
// is true.
var noOpenerAdded bool
tmpAttrs := []html.Attribute{}
for _, htmlAttr := range cleanAttrs {
var appended bool
if htmlAttr.Key == "rel" {
if strings.Contains(htmlAttr.Val, "noopener") {
noOpenerAdded = true
tmpAttrs = append(tmpAttrs, htmlAttr)
} else {
htmlAttr.Val += " noopener"
noOpenerAdded = true
tmpAttrs = append(tmpAttrs, htmlAttr)
}

appended = true
}
if !appended {
tmpAttrs = append(tmpAttrs, htmlAttr)
}
}
if noOpenerAdded {
cleanAttrs = tmpAttrs
} else {
// rel attr was not found, or else noopener would
// have been added already
rel := html.Attribute{}
rel.Key = "rel"
rel.Val = "noopener"
cleanAttrs = append(cleanAttrs, rel)
}

}
}
default:
}
}
}

return cleanAttrs
}

func (p *Policy) allowNoAttrs(elementName string) bool {
_, ok := p.setOfElementsAllowedWithoutAttrs[elementName]
return ok
}

func (p *Policy) validURL(rawurl string) (string, bool) {
if p.requireParseableURLs {
// URLs are valid if when space is trimmed the URL is valid
rawurl = strings.TrimSpace(rawurl)

// URLs cannot contain whitespace, unless it is a data-uri
if (strings.Contains(rawurl, " ") ||
strings.Contains(rawurl, "\t") ||
strings.Contains(rawurl, "\n")) &&
!strings.HasPrefix(rawurl, `data:`) {
return "", false
}

// URLs are valid if they parse
u, err := url.Parse(rawurl)
if err != nil {
return "", false
}

if u.Scheme != "" {

urlPolicy, ok := p.allowURLSchemes[u.Scheme]
if !ok {
return "", false

}

if urlPolicy == nil || urlPolicy(u) == true {
return u.String(), true
}

return "", false
}

if p.allowRelativeURLs {
if u.String() != "" {
return u.String(), true
}
}

return "", false
}

return rawurl, true
}

func linkable(elementName string) bool {
switch elementName {
case "a", "area", "blockquote", "img", "link", "script":
return true
default:
return false
}
}

func isDataAttribute(val string) bool {
if !dataAttribute.MatchString(val) {
return false
}
rest := strings.Split(val, "data-")
if len(rest) == 1 {
return false
}
// data-xml* is invalid.
if dataAttributeXMLPrefix.MatchString(rest[1]) {
return false
}
// no uppercase or semi-colons allowed.
if dataAttributeInvalidChars.MatchString(rest[1]) {
return false
}
return true
}

+ 21
- 0
vendor/github.com/mitchellh/go-homedir/LICENSE View File

@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2013 Mitchell Hashimoto

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.

+ 14
- 0
vendor/github.com/mitchellh/go-homedir/README.md View File

@@ -0,0 +1,14 @@
# go-homedir

This is a Go library for detecting the user's home directory without
the use of cgo, so the library can be used in cross-compilation environments.

Usage is incredibly simple, just call `homedir.Dir()` to get the home directory
for a user, and `homedir.Expand()` to expand the `~` in a path to the home
directory.

**Why not just use `os/user`?** The built-in `os/user` package requires
cgo on Darwin systems. This means that any Go code that uses that package
cannot cross compile. But 99% of the time the use for `os/user` is just to
retrieve the home directory, which we can do for the current user without
cgo. This library does that, enabling cross-compilation.

+ 1
- 0
vendor/github.com/mitchellh/go-homedir/go.mod View File

@@ -0,0 +1 @@
module github.com/mitchellh/go-homedir

+ 157
- 0
vendor/github.com/mitchellh/go-homedir/homedir.go View File

@@ -0,0 +1,157 @@
package homedir

import (
"bytes"
"errors"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
)

// DisableCache will disable caching of the home directory. Caching is enabled
// by default.
var DisableCache bool

var homedirCache string
var cacheLock sync.RWMutex

// Dir returns the home directory for the executing user.
//
// This uses an OS-specific method for discovering the home directory.
// An error is returned if a home directory cannot be detected.
func Dir() (string, error) {
if !DisableCache {
cacheLock.RLock()
cached := homedirCache
cacheLock.RUnlock()
if cached != "" {
return cached, nil
}
}

cacheLock.Lock()
defer cacheLock.Unlock()

var result string
var err error
if runtime.GOOS == "windows" {
result, err = dirWindows()
} else {
// Unix-like system, so just assume Unix
result, err = dirUnix()
}

if err != nil {
return "", err
}
homedirCache = result
return result, nil
}

// Expand expands the path to include the home directory if the path
// is prefixed with `~`. If it isn't prefixed with `~`, the path is
// returned as-is.
func Expand(path string) (string, error) {
if len(path) == 0 {
return path, nil
}

if path[0] != '~' {
return path, nil
}

if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
return "", errors.New("cannot expand user-specific home dir")
}

dir, err := Dir()
if err != nil {
return "", err
}

return filepath.Join(dir, path[1:]), nil
}

func dirUnix() (string, error) {
homeEnv := "HOME"
if runtime.GOOS == "plan9" {
// On plan9, env vars are lowercase.
homeEnv = "home"
}

// First prefer the HOME environmental variable
if home := os.Getenv(homeEnv); home != "" {
return home, nil
}

var stdout bytes.Buffer

// If that fails, try OS specific commands
if runtime.GOOS == "darwin" {
cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
result := strings.TrimSpace(stdout.String())
if result != "" {
return result, nil
}
}
} else {
cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
// If the error is ErrNotFound, we ignore it. Otherwise, return it.
if err != exec.ErrNotFound {
return "", err
}
} else {
if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
// username:password:uid:gid:gecos:home:shell
passwdParts := strings.SplitN(passwd, ":", 7)
if len(passwdParts) > 5 {
return passwdParts[5], nil
}
}
}
}

// If all else fails, try the shell
stdout.Reset()
cmd := exec.Command("sh", "-c", "cd && pwd")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}

result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output when reading home directory")
}

return result, nil
}

func dirWindows() (string, error) {
// First prefer the HOME environmental variable
if home := os.Getenv("HOME"); home != "" {
return home, nil
}

// Prefer standard environment variable USERPROFILE
if home := os.Getenv("USERPROFILE"); home != "" {
return home, nil
}

drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank")
}

return home, nil
}

+ 16
- 0
vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml View File

@@ -0,0 +1,16 @@
sudo: false
language: go
go:
- 1.x
- master
matrix:
allow_failures:
- go: master
fast_finish: true
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v -race ./...

+ 21
- 0
vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE View File

@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2015 Dmitri Shuralyov

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.

+ 36
- 0
vendor/github.com/shurcooL/sanitized_anchor_name/README.md View File

@@ -0,0 +1,36 @@
sanitized_anchor_name
=====================

[![Build Status](https://travis-ci.org/shurcooL/sanitized_anchor_name.svg?branch=master)](https://travis-ci.org/shurcooL/sanitized_anchor_name) [![GoDoc](https://godoc.org/github.com/shurcooL/sanitized_anchor_name?status.svg)](https://godoc.org/github.com/shurcooL/sanitized_anchor_name)

Package sanitized_anchor_name provides a func to create sanitized anchor names.

Its logic can be reused by multiple packages to create interoperable anchor names
and links to those anchors.

At this time, it does not try to ensure that generated anchor names
are unique, that responsibility falls on the caller.

Installation
------------

```bash
go get -u github.com/shurcooL/sanitized_anchor_name
```

Example
-------

```Go
anchorName := sanitized_anchor_name.Create("This is a header")

fmt.Println(anchorName)

// Output:
// this-is-a-header
```

License
-------

- [MIT License](LICENSE)

+ 29
- 0
vendor/github.com/shurcooL/sanitized_anchor_name/main.go View File

@@ -0,0 +1,29 @@
// Package sanitized_anchor_name provides a func to create sanitized anchor names.
//
// Its logic can be reused by multiple packages to create interoperable anchor names
// and links to those anchors.
//
// At this time, it does not try to ensure that generated anchor names
// are unique, that responsibility falls on the caller.
package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name"

import "unicode"

// Create returns a sanitized anchor name for the given text.
func Create(text string) string {
var anchorName []rune
var futureDash = false
for _, r := range text {
switch {
case unicode.IsLetter(r) || unicode.IsNumber(r):
if futureDash && len(anchorName) > 0 {
anchorName = append(anchorName, '-')
}
futureDash = false
anchorName = append(anchorName, unicode.ToLower(r))
default:
futureDash = true
}
}
return string(anchorName)
}

+ 3
- 0
vendor/github.com/writeas/go-writeas/v2/.gitignore View File

@@ -0,0 +1,3 @@
*~
*.swp
writeas

+ 21
- 0
vendor/github.com/writeas/go-writeas/v2/LICENSE View File

@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 Write.as

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.

+ 71
- 0
vendor/github.com/writeas/go-writeas/v2/README.md View File

@@ -0,0 +1,71 @@
# go-writeas

[![godoc](https://godoc.org/go.code.as/writeas.v2?status.svg)](https://godoc.org/go.code.as/writeas.v2)

Official Write.as Go client library.

## Installation

**Warning**: the `v2` branch is under heavy development and its API will change without notice.

For a stable API, use `go.code.as/writeas.v1` and upgrade to `v2` once everything is merged into `master`.

```bash
go get go.code.as/writeas.v2
```

## Documentation

See all functionality and usages in the [API documentation](https://developer.write.as/docs/api/).

### Example usage

```go
import "go.code.as/writeas.v2"

func main() {
// Create the client
c := writeas.NewClient()

// Publish a post
p, err := c.CreatePost(&writeas.PostParams{
Title: "Title!",
Content: "This is a post.",
Font: "sans",
})
if err != nil {
// Perhaps show err.Error()
}

// Save token for later, since it won't ever be returned again
token := p.Token

// Update a published post
p, err = c.UpdatePost(p.ID, token, &writeas.PostParams{
Content: "Now it's been updated!",
})
if err != nil {
// handle
}

// Get a published post
p, err = c.GetPost(p.ID)
if err != nil {
// handle
}

// Delete a post
err = c.DeletePost(p.ID, token)
}
```

## Contributing

The library covers our usage, but might not be comprehensive of the API. So we always welcome contributions and improvements from the community. Before sending pull requests, make sure you've done the following:

* Run `goimports` on all updated .go files.
* Document all exported structs and funcs.

## License

MIT

+ 75
- 0
vendor/github.com/writeas/go-writeas/v2/auth.go View File

@@ -0,0 +1,75 @@
package writeas

import (
"fmt"
"net/http"
)

// LogIn authenticates a user with Write.as.
// See https://developer.write.as/docs/api/#authenticate-a-user
func (c *Client) LogIn(username, pass string) (*AuthUser, error) {
u := &AuthUser{}
up := struct {
Alias string `json:"alias"`
Pass string `json:"pass"`
}{
Alias: username,
Pass: pass,
}

env, err := c.post("/auth/login", up, u)
if err != nil {
return nil, err
}

var ok bool
if u, ok = env.Data.(*AuthUser); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}

status := env.Code
if status != http.StatusOK {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else if status == http.StatusUnauthorized {
return nil, fmt.Errorf("Incorrect password.")
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("User does not exist.")
} else if status == http.StatusTooManyRequests {
return nil, fmt.Errorf("Too many log in attempts in a short period of time.")
}
return nil, fmt.Errorf("Problem authenticating: %d. %v\n", status, err)
}

c.SetToken(u.AccessToken)
return u, nil
}

// LogOut logs the current user out, making the Client's current access token
// invalid.
func (c *Client) LogOut() error {
env, err := c.delete("/auth/me", nil)
if err != nil {
return err
}

status := env.Code
if status != http.StatusNoContent {
if status == http.StatusNotFound {
return fmt.Errorf("Access token is invalid or doesn't exist")
}
return fmt.Errorf("Unable to log out: %v", env.ErrorMessage)
}

// Logout successful, so update the Client
c.token = ""

return nil
}

func (c *Client) isNotLoggedIn(code int) bool {
if c.token == "" {
return false
}
return code == http.StatusUnauthorized
}

+ 186
- 0
vendor/github.com/writeas/go-writeas/v2/collection.go View File

@@ -0,0 +1,186 @@
package writeas

import (
"fmt"
"net/http"
)

type (
// Collection represents a collection of posts. Blogs are a type of collection
// on Write.as.
Collection struct {
Alias string `json:"alias"`
Title string `json:"title"`
Description string `json:"description"`
StyleSheet string `json:"style_sheet"`
Private bool `json:"private"`
Views int64 `json:"views"`
Domain string `json:"domain,omitempty"`
Email string `json:"email,omitempty"`
URL string `json:"url,omitempty"`

TotalPosts int `json:"total_posts"`

Posts *[]Post `json:"posts,omitempty"`
}

// CollectionParams holds values for creating a collection.
CollectionParams struct {
Alias string `json:"alias"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
}
)

// CreateCollection creates a new collection, returning a user-friendly error
// if one comes up. Requires a Write.as subscription. See
// https://developer.write.as/docs/api/#create-a-collection
func (c *Client) CreateCollection(sp *CollectionParams) (*Collection, error) {
p := &Collection{}
env, err := c.post("/collections", sp, p)
if err != nil {
return nil, err
}

var ok bool
if p, ok = env.Data.(*Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}

status := env.Code
if status != http.StatusCreated {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else if status == http.StatusForbidden {
return nil, fmt.Errorf("Casual or Pro user required.")
} else if status == http.StatusConflict {
return nil, fmt.Errorf("Collection name is already taken.")
} else if status == http.StatusPreconditionFailed {
return nil, fmt.Errorf("Reached max collection quota.")
}
return nil, fmt.Errorf("Problem getting post: %d. %v\n", status, err)
}
return p, nil
}

// GetCollection retrieves a collection, returning the Collection and any error
// (in user-friendly form) that occurs. See
// https://developer.write.as/docs/api/#retrieve-a-collection
func (c *Client) GetCollection(alias string) (*Collection, error) {
coll := &Collection{}
env, err := c.get(fmt.Sprintf("/collections/%s", alias), coll)
if err != nil {
return nil, err
}

var ok bool
if coll, ok = env.Data.(*Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code

if status == http.StatusOK {
return coll, nil
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("Collection not found.")
} else {
return nil, fmt.Errorf("Problem getting collection: %d. %v\n", status, err)
}
}

// GetCollectionPosts retrieves a collection's posts, returning the Posts
// and any error (in user-friendly form) that occurs. See
// https://developer.write.as/docs/api/#retrieve-collection-posts
func (c *Client) GetCollectionPosts(alias string) (*[]Post, error) {
coll := &Collection{}
env, err := c.get(fmt.Sprintf("/collections/%s/posts", alias), coll)
if err != nil {
return nil, err
}

var ok bool
if coll, ok = env.Data.(*Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code

if status == http.StatusOK {
return coll.Posts, nil
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("Collection not found.")
} else {
return nil, fmt.Errorf("Problem getting collection: %d. %v\n", status, err)
}
}

// GetCollectionPost retrieves a post from a collection
// and any error (in user-friendly form) that occurs). See
// https://developers.write.as/docs/api/#retrieve-a-collection-post
func (c *Client) GetCollectionPost(alias, slug string) (*Post, error) {
post := Post{}

env, err := c.get(fmt.Sprintf("/collections/%s/posts/%s", alias, slug), &post)
if err != nil {
return nil, err
}

if _, ok := env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}

if env.Code == http.StatusOK {
return &post, nil
} else if env.Code == http.StatusNotFound {
return nil, fmt.Errorf("Post %s not found in collection %s", slug, alias)
}

return nil, fmt.Errorf("Problem getting post %s from collection %s: %d. %v\n", slug, alias, env.Code, err)
}

// GetUserCollections retrieves the authenticated user's collections.
// See https://developers.write.as/docs/api/#retrieve-user-39-s-collections
func (c *Client) GetUserCollections() (*[]Collection, error) {
colls := &[]Collection{}
env, err := c.get("/me/collections", colls)
if err != nil {
return nil, err
}

var ok bool
if colls, ok = env.Data.(*[]Collection); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code

if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
}
return nil, fmt.Errorf("Problem getting collections: %d. %v\n", status, err)
}
return colls, nil
}

// DeleteCollection permanently deletes a collection and makes any posts on it
// anonymous.
//
// See https://developers.write.as/docs/api/#delete-a-collection.
func (c *Client) DeleteCollection(alias string) error {
endpoint := "/collections/" + alias
env, err := c.delete(endpoint, nil /* data */)
if err != nil {
return err
}

status := env.Code
switch status {
case http.StatusNoContent:
return nil
case http.StatusUnauthorized:
return fmt.Errorf("Not authenticated.")
case http.StatusBadRequest:
return fmt.Errorf("Bad request: %s", env.ErrorMessage)
default:
return fmt.Errorf("Problem deleting collection: %d. %s\n", status, env.ErrorMessage)
}
}

+ 8
- 0
vendor/github.com/writeas/go-writeas/v2/go.mod View File

@@ -0,0 +1,8 @@
module github.com/writeas/go-writeas/v2

go 1.9

require (
code.as/core/socks v1.0.0
github.com/writeas/impart v1.1.0
)

+ 4
- 0
vendor/github.com/writeas/go-writeas/v2/go.sum View File

@@ -0,0 +1,4 @@
code.as/core/socks v1.0.0 h1:SPQXNp4SbEwjOAP9VzUahLHak8SDqy5n+9cm9tpjZOs=
code.as/core/socks v1.0.0/go.mod h1:BAXBy5O9s2gmw6UxLqNJcVbWY7C/UPs+801CcSsfWOY=
github.com/writeas/impart v1.1.0 h1:nPnoO211VscNkp/gnzir5UwCDEvdHThL5uELU60NFSE=
github.com/writeas/impart v1.1.0/go.mod h1:g0MpxdnTOHHrl+Ca/2oMXUHJ0PcRAEWtkCzYCJUXC9Y=

+ 330
- 0
vendor/github.com/writeas/go-writeas/v2/post.go View File

@@ -0,0 +1,330 @@
package writeas

import (
"fmt"
"net/http"
"time"
)

type (
// Post represents a published Write.as post, whether anonymous, owned by a
// user, or part of a collection.
Post struct {
ID string `json:"id"`
Slug string `json:"slug"`
Token string `json:"token"`
Font string `json:"appearance"`
Language *string `json:"language"`
RTL *bool `json:"rtl"`
Listed bool `json:"listed"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Title string `json:"title"`
Content string `json:"body"`
Views int64 `json:"views"`
Tags []string `json:"tags"`
Images []string `json:"images"`
OwnerName string `json:"owner,omitempty"`

Collection *Collection `json:"collection,omitempty"`
}

// OwnedPostParams are, together, fields only the original post author knows.
OwnedPostParams struct {
ID string `json:"id"`
Token string `json:"token,omitempty"`
}

// PostParams holds values for creating or updating a post.
PostParams struct {
// Parameters only for updating
ID string `json:"-"`
Token string `json:"token,omitempty"`

// Parameters for creating or updating
Slug string `json:"slug"`
Created *time.Time `json:"created,omitempty"`
Updated *time.Time `json:"updated,omitempty"`
Title string `json:"title,omitempty"`
Content string `json:"body,omitempty"`
Font string `json:"font,omitempty"`
IsRTL *bool `json:"rtl,omitempty"`
Language *string `json:"lang,omitempty"`

// Parameters only for creating
Crosspost []map[string]string `json:"crosspost,omitempty"`

// Parameters for collection posts
Collection string `json:"-"`
}

// PinnedPostParams holds values for pinning a post
PinnedPostParams struct {
ID string `json:"id"`
Position int `json:"position"`
}

// BatchPostResult contains the post-specific result as part of a larger
// batch operation.
BatchPostResult struct {
ID string `json:"id,omitempty"`
Code int `json:"code,omitempty"`
ErrorMessage string `json:"error_msg,omitempty"`
}

// ClaimPostResult contains the post-specific result for a request to
// associate a post to an account.
ClaimPostResult struct {
ID string `json:"id,omitempty"`
Code int `json:"code,omitempty"`
ErrorMessage string `json:"error_msg,omitempty"`
Post *Post `json:"post,omitempty"`
}
)

// GetPost retrieves a published post, returning the Post and any error (in
// user-friendly form) that occurs. See
// https://developer.write.as/docs/api/#retrieve-a-post.
func (c *Client) GetPost(id string) (*Post, error) {
p := &Post{}
env, err := c.get(fmt.Sprintf("/posts/%s", id), p)
if err != nil {
return nil, err
}

var ok bool
if p, ok = env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code

if status == http.StatusOK {
return p, nil
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("Post not found.")
} else if status == http.StatusGone {
return nil, fmt.Errorf("Post unpublished.")
}
return nil, fmt.Errorf("Problem getting post: %d. %s\n", status, env.ErrorMessage)
}

// CreatePost publishes a new post, returning a user-friendly error if one comes
// up. See https://developer.write.as/docs/api/#publish-a-post.
func (c *Client) CreatePost(sp *PostParams) (*Post, error) {
p := &Post{}
endPre := ""
if sp.Collection != "" {
endPre = "/collections/" + sp.Collection
}
env, err := c.post(endPre+"/posts", sp, p)
if err != nil {
return nil, err
}

var ok bool
if p, ok = env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}

status := env.Code
if status != http.StatusCreated {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
}
return nil, fmt.Errorf("Problem creating post: %d. %s\n", status, env.ErrorMessage)
}
return p, nil
}

// UpdatePost updates a published post with the given PostParams. See
// https://developer.write.as/docs/api/#update-a-post.
func (c *Client) UpdatePost(id, token string, sp *PostParams) (*Post, error) {
return c.updatePost("", id, token, sp)
}

func (c *Client) updatePost(collection, identifier, token string, sp *PostParams) (*Post, error) {
p := &Post{}
endpoint := "/posts/" + identifier
/*
if collection != "" {
endpoint = "/collections/" + collection + endpoint
} else {
sp.Token = token
}
*/
sp.Token = token
env, err := c.put(endpoint, sp, p)
if err != nil {
return nil, err
}

var ok bool
if p, ok = env.Data.(*Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}

status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
} else if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
}
return nil, fmt.Errorf("Problem updating post: %d. %s\n", status, env.ErrorMessage)
}
return p, nil
}

// DeletePost permanently deletes a published post. See
// https://developer.write.as/docs/api/#delete-a-post.
func (c *Client) DeletePost(id, token string) error {
return c.deletePost("", id, token)
}

func (c *Client) deletePost(collection, identifier, token string) error {
p := map[string]string{}
endpoint := "/posts/" + identifier
/*
if collection != "" {
endpoint = "/collections/" + collection + endpoint
} else {
p["token"] = token
}
*/
p["token"] = token
env, err := c.delete(endpoint, p)
if err != nil {
return err
}

status := env.Code
if status == http.StatusNoContent {
return nil
} else if c.isNotLoggedIn(status) {
return fmt.Errorf("Not authenticated.")
} else if status == http.StatusBadRequest {
return fmt.Errorf("Bad request: %s", env.ErrorMessage)
}
return fmt.Errorf("Problem deleting post: %d. %s\n", status, env.ErrorMessage)
}

// ClaimPosts associates anonymous posts with a user / account.
// https://developer.write.as/docs/api/#claim-posts.
func (c *Client) ClaimPosts(sp *[]OwnedPostParams) (*[]ClaimPostResult, error) {
p := &[]ClaimPostResult{}
env, err := c.post("/posts/claim", sp, p)
if err != nil {
return nil, err
}

var ok bool
if p, ok = env.Data.(*[]ClaimPostResult); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}

status := env.Code
if status == http.StatusOK {
return p, nil
} else if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
} else if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else {
return nil, fmt.Errorf("Problem claiming post: %d. %s\n", status, env.ErrorMessage)
}
// TODO: does this also happen with moving posts?
}

// GetUserPosts retrieves the authenticated user's posts.
// See https://developers.write.as/docs/api/#retrieve-user-39-s-posts
func (c *Client) GetUserPosts() (*[]Post, error) {
p := &[]Post{}
env, err := c.get("/me/posts", p)
if err != nil {
return nil, err
}

var ok bool
if p, ok = env.Data.(*[]Post); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
status := env.Code

if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return nil, fmt.Errorf("Not authenticated.")
}
return nil, fmt.Errorf("Problem getting user posts: %d. %s\n", status, env.ErrorMessage)
}
return p, nil
}

// PinPost pins a post in the given collection.
// See https://developers.write.as/docs/api/#pin-a-post-to-a-collection
func (c *Client) PinPost(alias string, pp *PinnedPostParams) error {
res := &[]BatchPostResult{}
env, err := c.post(fmt.Sprintf("/collections/%s/pin", alias), []*PinnedPostParams{pp}, res)
if err != nil {
return err
}

var ok bool
if res, ok = env.Data.(*[]BatchPostResult); !ok {
return fmt.Errorf("Wrong data returned from API.")
}

// Check for basic request errors on top level response
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return fmt.Errorf("Not authenticated.")
}
return fmt.Errorf("Problem pinning post: %d. %s\n", status, env.ErrorMessage)
}

// Check the individual post result
if len(*res) == 0 || len(*res) > 1 {
return fmt.Errorf("Wrong data returned from API.")
}
if (*res)[0].Code != http.StatusOK {
return fmt.Errorf("Problem pinning post: %d", (*res)[0].Code)
// TODO: return ErrorMessage (right now it'll be empty)
// return fmt.Errorf("Problem pinning post: %s", res[0].ErrorMessage)
}
return nil
}

// UnpinPost unpins a post from the given collection.
// See https://developers.write.as/docs/api/#unpin-a-post-from-a-collection
func (c *Client) UnpinPost(alias string, pp *PinnedPostParams) error {
res := &[]BatchPostResult{}
env, err := c.post(fmt.Sprintf("/collections/%s/unpin", alias), []*PinnedPostParams{pp}, res)
if err != nil {
return err
}

var ok bool
if res, ok = env.Data.(*[]BatchPostResult); !ok {
return fmt.Errorf("Wrong data returned from API.")
}

// Check for basic request errors on top level response
status := env.Code
if status != http.StatusOK {
if c.isNotLoggedIn(status) {
return fmt.Errorf("Not authenticated.")
}
return fmt.Errorf("Problem unpinning post: %d. %s\n", status, env.ErrorMessage)
}

// Check the individual post result
if len(*res) == 0 || len(*res) > 1 {
return fmt.Errorf("Wrong data returned from API.")
}
if (*res)[0].Code != http.StatusOK {
return fmt.Errorf("Problem unpinning post: %d", (*res)[0].Code)
// TODO: return ErrorMessage (right now it'll be empty)
// return fmt.Errorf("Problem unpinning post: %s", res[0].ErrorMessage)
}
return nil
}

+ 34
- 0
vendor/github.com/writeas/go-writeas/v2/user.go View File

@@ -0,0 +1,34 @@
package writeas

import "time"

type (
// AuthUser represents a just-authenticated user. It contains information
// that'll only be returned once (now) per user session.
AuthUser struct {
AccessToken string `json:"access_token,omitempty"`
Password string `json:"password,omitempty"`
User *User `json:"user"`
}

// User represents a registered Write.as user.
User struct {
Username string `json:"username"`
Email string `json:"email"`
Created time.Time `json:"created"`

// Optional properties
Subscription *UserSubscription `json:"subscription"`
}

// UserSubscription contains information about a user's Write.as
// subscription.
UserSubscription struct {
Name string `json:"name"`
Begin time.Time `json:"begin"`
End time.Time `json:"end"`
AutoRenew bool `json:"auto_renew"`
Active bool `json:"is_active"`
Delinquent bool `json:"is_delinquent"`
}
)

+ 199
- 0
vendor/github.com/writeas/go-writeas/v2/writeas.go View File

@@ -0,0 +1,199 @@
// Package writeas provides the binding for the Write.as API
package writeas

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"

"code.as/core/socks"
"github.com/writeas/impart"
)

const (
apiURL = "https://write.as/api"
devAPIURL = "https://development.write.as/api"
torAPIURL = "http://writeas7pm7rcdqg.onion/api"

// Current go-writeas version
Version = "2-dev"
)

// Client is used to interact with the Write.as API. It can be used to make
// authenticated or unauthenticated calls.
type Client struct {
baseURL string

// Access token for the user making requests.
token string
// Client making requests to the API
client *http.Client

// UserAgent overrides the default User-Agent header
UserAgent string
}

// defaultHTTPTimeout is the default http.Client timeout.
const defaultHTTPTimeout = 10 * time.Second

// NewClient creates a new API client. By default, all requests are made
// unauthenticated. To optionally make authenticated requests, call `SetToken`.
//
// c := writeas.NewClient()
// c.SetToken("00000000-0000-0000-0000-000000000000")
func NewClient() *Client {
return NewClientWith(Config{URL: apiURL})
}

// NewTorClient creates a new API client for communicating with the Write.as
// Tor hidden service, using the given port to connect to the local SOCKS
// proxy.
func NewTorClient(port int) *Client {
return NewClientWith(Config{URL: torAPIURL, TorPort: port})
}

// NewDevClient creates a new API client for development and testing. It'll
// communicate with our development servers, and SHOULD NOT be used in
// production.
func NewDevClient() *Client {
return NewClientWith(Config{URL: devAPIURL})
}

// Config configures a Write.as client.
type Config struct {
// URL of the Write.as API service. Defaults to https://write.as/api.
URL string

// If specified, the API client will communicate with the Write.as Tor
// hidden service using the provided port to connect to the local SOCKS
// proxy.
TorPort int

// If specified, requests will be authenticated using this user token.
// This may be provided after making a few anonymous requests with
// SetToken.
Token string
}

// NewClientWith builds a new API client with the provided configuration.
func NewClientWith(c Config) *Client {
if c.URL == "" {
c.URL = apiURL
}

httpClient := &http.Client{Timeout: defaultHTTPTimeout}
if c.TorPort > 0 {
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, fmt.Sprintf("127.0.0.1:%d", c.TorPort))
httpClient.Transport = &http.Transport{Dial: dialSocksProxy}
}

return &Client{
client: httpClient,
baseURL: c.URL,
token: c.Token,
}
}

// SetToken sets the user token for all future Client requests. Setting this to
// an empty string will change back to unauthenticated requests.
func (c *Client) SetToken(token string) {
c.token = token
}

// Token returns the user token currently set to the Client.
func (c *Client) Token() string {
return c.token
}

func (c *Client) get(path string, r interface{}) (*impart.Envelope, error) {
method := "GET"
if method != "GET" && method != "HEAD" {
return nil, fmt.Errorf("Method %s not currently supported by library (only HEAD and GET).\n", method)
}

return c.request(method, path, nil, r)
}

func (c *Client) post(path string, data, r interface{}) (*impart.Envelope, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
return c.request("POST", path, b, r)
}

func (c *Client) put(path string, data, r interface{}) (*impart.Envelope, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
return c.request("PUT", path, b, r)
}

func (c *Client) delete(path string, data map[string]string) (*impart.Envelope, error) {
r, err := c.buildRequest("DELETE", path, nil)
if err != nil {
return nil, err
}

q := r.URL.Query()
for k, v := range data {
q.Add(k, v)
}
r.URL.RawQuery = q.Encode()

return c.doRequest(r, nil)
}

func (c *Client) request(method, path string, data io.Reader, result interface{}) (*impart.Envelope, error) {
r, err := c.buildRequest(method, path, data)
if err != nil {
return nil, err
}

return c.doRequest(r, result)
}

func (c *Client) buildRequest(method, path string, data io.Reader) (*http.Request, error) {
url := fmt.Sprintf("%s%s", c.baseURL, path)
r, err := http.NewRequest(method, url, data)
if err != nil {
return nil, fmt.Errorf("Create request: %v", err)
}
c.prepareRequest(r)

return r, nil
}

func (c *Client) doRequest(r *http.Request, result interface{}) (*impart.Envelope, error) {
resp, err := c.client.Do(r)
if err != nil {
return nil, fmt.Errorf("Request: %v", err)
}
defer resp.Body.Close()

env := &impart.Envelope{
Code: resp.StatusCode,
}
if result != nil {
env.Data = result

err = json.NewDecoder(resp.Body).Decode(&env)
if err != nil {
return nil, err
}
}

return env, nil
}

func (c *Client) prepareRequest(r *http.Request) {
ua := c.UserAgent
if ua == "" {
ua = "go-writeas v" + Version
}
r.Header.Set("User-Agent", ua)
r.Header.Add("Content-Type", "application/json")
if c.token != "" {
r.Header.Add("Authorization", "Token "+c.token)
}
}

+ 27
- 0
vendor/github.com/writeas/impart/.gitignore View File

@@ -0,0 +1,27 @@
*~
*.swp

# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof

+ 22
- 0
vendor/github.com/writeas/impart/LICENSE View File

@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2015 Write.as

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.


+ 61
- 0
vendor/github.com/writeas/impart/README.md View File

@@ -0,0 +1,61 @@
impart
======

![MIT license](https://img.shields.io/github/license/writeas/impart.svg) [![#writeas on freenode](https://img.shields.io/badge/freenode-%23writeas-blue.svg)](http://webchat.freenode.net/?channels=writeas) [![Public Slack discussion](http://slack.write.as/badge.svg)](http://slack.write.as/)

**impart** is a library for the final layer between the API and the consumer. It's used in the latest [Write.as](https://write.as) and [HTMLhouse](https://html.house) APIs.

We're still in the early stages of development, so there may be breaking changes.

## Example use

```go
package main

import (
"fmt"
"github.com/writeas/impart"
"net/http"
)

type handlerFunc func(w http.ResponseWriter, r *http.Request) error

func main() {
http.HandleFunc("/", handle(index))
http.ListenAndServe("127.0.0.1:8080", nil)
}

func index(w http.ResponseWriter, r *http.Request) error {
fmt.Fprintf(w, "Hello world!")

return nil
}

func handle(f handlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
handleError(w, r, func() error {
// Do authentication...

// Handle the request
err := f(w, r)

// Log the request and result...

return err
}())
}
}

func handleError(w http.ResponseWriter, r *http.Request, err error) {
if err == nil {
return
}

if err, ok := err.(impart.HTTPError); ok {
impart.WriteError(w, err)
return
}

impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Internal server error :("})
}
```

+ 4
- 0
vendor/github.com/writeas/impart/doc.go View File

@@ -0,0 +1,4 @@
// Package impart provides a simple interface for a JSON-based API. It is
// designed for passing errors around a web application, sending back a status
// code and error message if needed, or a status code and some data on success.
package impart

+ 20
- 0
vendor/github.com/writeas/impart/errors.go View File

@@ -0,0 +1,20 @@
package impart

import (
"net/http"
)

// HTTPError holds an HTTP status code and an error message.
type HTTPError struct {
Status int
Message string
}

// Error displays the HTTPError's error message and satisfies the error
// interface.
func (h HTTPError) Error() string {
if h.Message == "" {
return http.StatusText(h.Status)
}
return h.Message
}

+ 3
- 0
vendor/github.com/writeas/impart/go.mod View File

@@ -0,0 +1,3 @@
module github.com/writeas/impart

go 1.9

+ 13
- 0
vendor/github.com/writeas/impart/request.go View File

@@ -0,0 +1,13 @@
package impart

import (
"mime"
"net/http"
)

// ReqJSON returns whether or not the given Request is sending JSON, based on
// the Content-Type header being application/json.
func ReqJSON(r *http.Request) bool {
ct, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
return ct == "application/json"
}

+ 76
- 0
vendor/github.com/writeas/impart/response.go View File

@@ -0,0 +1,76 @@
package impart

import (
"encoding/json"
"net/http"
"strconv"
)

type (
// Envelope contains metadata and optional data for a response object.
// Responses will always contain a status code and either:
// - response Data on a 2xx response, or
// - an ErrorMessage on non-2xx responses
//
// ErrorType is not currently used.
Envelope struct {
Code int `json:"code"`
ErrorType string `json:"error_type,omitempty"`
ErrorMessage string `json:"error_msg,omitempty"`
Data interface{} `json:"data,omitempty"`
}
)

func writeBody(w http.ResponseWriter, body []byte, status int, contentType string) error {
w.Header().Set("Content-Type", contentType+"; charset=UTF-8")
w.Header().Set("Content-Length", strconv.Itoa(len(body)))
w.WriteHeader(status)
_, err := w.Write(body)
return err
}

func RenderActivityJSON(w http.ResponseWriter, value interface{}, status int) error {
body, err := json.Marshal(value)
if err != nil {
return err
}
return writeBody(w, body, status, "application/activity+json")
}

func renderJSON(w http.ResponseWriter, value interface{}, status int) error {
body, err := json.Marshal(value)
if err != nil {
return err
}
return writeBody(w, body, status, "application/json")
}

func renderString(w http.ResponseWriter, status int, msg string) error {
return writeBody(w, []byte(msg), status, "text/plain")
}

// WriteSuccess writes the successful data and metadata to the ResponseWriter as
// JSON.
func WriteSuccess(w http.ResponseWriter, data interface{}, status int) error {
env := &Envelope{
Code: status,
Data: data,
}
return renderJSON(w, env, status)
}

// WriteError writes the error to the ResponseWriter as JSON.
func WriteError(w http.ResponseWriter, e HTTPError) error {
env := &Envelope{
Code: e.Status,
ErrorMessage: e.Message,
}
return renderJSON(w, env, e.Status)
}

// WriteRedirect sends a redirect
func WriteRedirect(w http.ResponseWriter, e HTTPError) int {
w.Header().Set("Location", e.Message)
w.WriteHeader(e.Status)
return e.Status
}

+ 8
- 0
vendor/github.com/writeas/saturday/.gitignore View File

@@ -0,0 +1,8 @@
*.out
*.swp
*.8
*.6
_obj
_test*
markdown
tags

+ 30
- 0
vendor/github.com/writeas/saturday/.travis.yml View File

@@ -0,0 +1,30 @@
sudo: false
language: go
go:
- 1.5.4
- 1.6.2
- tip
matrix:
include:
- go: 1.2.2
script:
- go get -t -v ./...
- go test -v -race ./...
- go: 1.3.3
script:
- go get -t -v ./...
- go test -v -race ./...
- go: 1.4.3
script:
- go get -t -v ./...
- go test -v -race ./...
allow_failures:
- go: tip
fast_finish: true
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v -race ./...

+ 29
- 0
vendor/github.com/writeas/saturday/LICENSE.txt View File

@@ -0,0 +1,29 @@
Blackfriday is distributed under the Simplified BSD License:

> Copyright © 2011 Russ Ross
> All rights reserved.
>
> Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions
> are met:
>
> 1. Redistributions of source code must retain the above copyright
> notice, this list of conditions and the following disclaimer.
>
> 2. Redistributions in binary form must reproduce the above
> copyright notice, this list of conditions and the following
> disclaimer in the documentation and/or other materials provided with
> the distribution.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> POSSIBILITY OF SUCH DAMAGE.

+ 284
- 0
vendor/github.com/writeas/saturday/README.md View File

@@ -0,0 +1,284 @@
Saturday
========
Saturday is a fork of [Blackfriday](https://github.com/russross/blackfriday) used on [Write.as](https://write.as).

We love Markdown, but aren't a Markdown-only platform. So we've stripped out and modified redundant or potentially frustrating syntax in this library.

## Changes

* Made images and links behave like standard Markdown (now they won't render when there are spaces between label/alt-text and URL) 12db6e2f7ebcc5d6d88e5b330e4c6d88b577bc95
* Only support atx-style headings 32843b3dfc510153e76d8f535a9084fc8e22245a
* Removed smart periods, quotes, angles & backticks 72080d757965efc04255fd25ad97c76ef6f03ea9
* Only support horizontal rules made of hyphens f75e5c8d41435593b7f24243e5c22b50f2b399b4
* Only support fenced code blocks, not indented blocks 8223c01e430de7fd35f3c38ef75f802734cc0cfc
* Keep leading spaces in paragraphs 24845d212205e789fe24ec27ebc1c4cd121523c9

Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday) [![GoDoc](https://godoc.org/github.com/russross/blackfriday?status.svg)](https://godoc.org/github.com/russross/blackfriday)
-----------

Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
is paranoid about its input (so you can safely feed it user-supplied
data), it is fast, it supports common extensions (tables, smart
punctuation substitutions, etc.), and it is safe for all utf-8
(unicode) input.

HTML output is currently supported, along with Smartypants
extensions. An experimental LaTeX output engine is also included.

It started as a translation from C of [Sundown][3].


### Installation

Blackfriday is compatible with Go 1. If you are using an older
release of Go, consider using v1.1 of blackfriday, which was based
on the last stable release of Go prior to Go 1. You can find it as a
tagged commit on github.

With Go 1 and git installed:

go get github.com/russross/blackfriday

will download, compile, and install the package into your `$GOPATH`
directory hierarchy. Alternatively, you can achieve the same if you
import it into a project:

import "github.com/russross/blackfriday"

and `go get` without parameters.

### Usage

For basic usage, it is as simple as getting your input into a byte
slice and calling:

output := blackfriday.MarkdownBasic(input)

This renders it with no extensions enabled. To get a more useful
feature set, use this instead:

output := blackfriday.MarkdownCommon(input)

#### Sanitize untrusted content

Blackfriday itself does nothing to protect against malicious content. If you are
dealing with user-supplied markdown, we recommend running blackfriday's output
through HTML sanitizer such as
[Bluemonday](https://github.com/microcosm-cc/bluemonday).

Here's an example of simple usage of blackfriday together with bluemonday:

``` go
import (
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday"
)

// ...
unsafe := blackfriday.MarkdownCommon(input)
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
```

#### Custom options

If you want to customize the set of options, first get a renderer
(currently either the HTML or LaTeX output engines), then use it to
call the more general `Markdown` function. For examples, see the
implementations of `MarkdownBasic` and `MarkdownCommon` in
`markdown.go`.

You can also check out `blackfriday-tool` for a more complete example
of how to use it. Download and install it using:

go get github.com/russross/blackfriday-tool

This is a simple command-line tool that allows you to process a
markdown file using a standalone program. You can also browse the
source directly on github if you are just looking for some example
code:

* <http://github.com/russross/blackfriday-tool>

Note that if you have not already done so, installing
`blackfriday-tool` will be sufficient to download and install
blackfriday in addition to the tool itself. The tool binary will be
installed in `$GOPATH/bin`. This is a statically-linked binary that
can be copied to wherever you need it without worrying about
dependencies and library versions.


### Features

All features of Sundown are supported, including:

* **Compatibility**. The Markdown v1.0.3 test suite passes with
the `--tidy` option. Without `--tidy`, the differences are
mostly in whitespace and entity escaping, where blackfriday is
more consistent and cleaner.

* **Common extensions**, including table support, fenced code
blocks, autolinks, strikethroughs, non-strict emphasis, etc.

* **Safety**. Blackfriday is paranoid when parsing, making it safe
to feed untrusted user input without fear of bad things
happening. The test suite stress tests this and there are no
known inputs that make it crash. If you find one, please let me
know and send me the input that does it.

NOTE: "safety" in this context means *runtime safety only*. In order to
protect yourself against JavaScript injection in untrusted content, see
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).

* **Fast processing**. It is fast enough to render on-demand in
most web applications without having to cache the output.

* **Thread safety**. You can run multiple parsers in different
goroutines without ill effect. There is no dependence on global
shared state.

* **Minimal dependencies**. Blackfriday only depends on standard
library packages in Go. The source code is pretty
self-contained, so it is easy to add to any project, including
Google App Engine projects.

* **Standards compliant**. Output successfully validates using the
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.


### Extensions

In addition to the standard markdown syntax, this package
implements the following extensions:

* **Intra-word emphasis supression**. The `_` character is
commonly used inside words when discussing code, so having
markdown interpret it as an emphasis command is usually the
wrong thing. Blackfriday lets you treat all emphasis markers as
normal characters when they occur inside a word.

* **Tables**. Tables can be created by drawing them in the input
using a simple syntax:

```
Name | Age
--------|------
Bob | 27
Alice | 23
```

* **Fenced code blocks**. In addition to the normal 4-space
indentation to mark code blocks, you can explicitly mark them
and supply a language (to make syntax highlighting simple). Just
mark it like this:

``` go
func getTrue() bool {
return true
}
```

You can use 3 or more backticks to mark the beginning of the
block, and the same number to mark the end of the block.

To preserve classes of fenced code blocks while using the bluemonday
HTML sanitizer, use the following policy:

``` go
p := bluemonday.UGCPolicy()
p.AllowAttrs("class").Matching(regexp.MustCompile("^language-[a-zA-Z0-9]+$")).OnElements("code")
html := p.SanitizeBytes(unsafe)
```

* **Definition lists**. A simple definition list is made of a single-line
term followed by a colon and the definition for that term.

Cat
: Fluffy animal everyone likes
Internet
: Vector of transmission for pictures of cats

Terms must be separated from the previous definition by a blank line.

* **Footnotes**. A marker in the text that will become a superscript number;
a footnote definition that will be placed in a list of footnotes at the
end of the document. A footnote looks like this:

This is a footnote.[^1]
[^1]: the footnote text.

* **Autolinking**. Blackfriday can find URLs that have not been
explicitly marked as links and turn them into links.

* **Strikethrough**. Use two tildes (`~~`) to mark text that
should be crossed out.

* **Hard line breaks**. With this extension enabled (it is off by
default in the `MarkdownBasic` and `MarkdownCommon` convenience
functions), newlines in the input translate into line breaks in
the output.

* **Smart quotes**. Smartypants-style punctuation substitution is
supported, turning normal double- and single-quote marks into
curly quotes, etc.

* **LaTeX-style dash parsing** is an additional option, where `--`
is translated into `&ndash;`, and `---` is translated into
`&mdash;`. This differs from most smartypants processors, which
turn a single hyphen into an ndash and a double hyphen into an
mdash.

* **Smart fractions**, where anything that looks like a fraction
is translated into suitable HTML (instead of just a few special
cases like most smartypant processors). For example, `4/5`
becomes `<sup>4</sup>&frasl;<sub>5</sub>`, which renders as
<sup>4</sup>&frasl;<sub>5</sub>.


### Other renderers

Blackfriday is structured to allow alternative rendering engines. Here
are a few of note:

* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown):
provides a GitHub Flavored Markdown renderer with fenced code block
highlighting, clickable header anchor links.

It's not customizable, and its goal is to produce HTML output
equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),
except the rendering is performed locally.

* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
but for markdown.

* LaTeX output: renders output as LaTeX. This is currently part of the
main Blackfriday repository, but may be split into its own project
in the future. If you are interested in owning and maintaining the
LaTeX output component, please be in touch.

It renders some basic documents, but is only experimental at this
point. In particular, it does not do any inline escaping, so input
that happens to look like LaTeX code will be passed through without
modification.
* [Md2Vim](https://github.com/FooSoft/md2vim): transforms markdown files into vimdoc format.


### Todo

* More unit testing
* Improve unicode support. It does not understand all unicode
rules (about what constitutes a letter, a punctuation symbol,
etc.), so it may fail to detect word boundaries correctly in
some instances. It is safe on all utf-8 input.


### License

[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt)


[1]: http://daringfireball.net/projects/markdown/ "Markdown"
[2]: http://golang.org/ "Go Language"
[3]: https://github.com/vmg/sundown "Sundown"

+ 1412
- 0
vendor/github.com/writeas/saturday/block.go
File diff suppressed because it is too large
View File


+ 949
- 0
vendor/github.com/writeas/saturday/html.go View File

@@ -0,0 +1,949 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//

//
//
// HTML rendering backend
//
//

package blackfriday

import (
"bytes"
"fmt"
"regexp"
"strconv"
"strings"
)

// Html renderer configuration options.
const (
HTML_SKIP_HTML = 1 << iota // skip preformatted HTML blocks
HTML_SKIP_STYLE // skip embedded <style> elements
HTML_SKIP_IMAGES // skip embedded images
HTML_SKIP_LINKS // skip all links
HTML_SAFELINK // only link to trusted protocols
HTML_NOFOLLOW_LINKS // only link with rel="nofollow"
HTML_NOREFERRER_LINKS // only link with rel="noreferrer"
HTML_HREF_TARGET_BLANK // add a blank target
HTML_TOC // generate a table of contents
HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents)
HTML_COMPLETE_PAGE // generate a complete HTML page
HTML_USE_XHTML // generate XHTML output instead of HTML
HTML_USE_SMARTYPANTS // enable smart punctuation substitutions
HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS)
HTML_SMARTYPANTS_DASHES // enable smart dashes (with HTML_USE_SMARTYPANTS)
HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS and HTML_SMARTYPANTS_DASHES)
HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering
HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source
)

var (
alignments = []string{
"left",
"right",
"center",
}

// TODO: improve this regexp to catch all possible entities:
htmlEntity = regexp.MustCompile(`&[a-z]{2,5};`)
)

type HtmlRendererParameters struct {
// Prepend this text to each relative URL.
AbsolutePrefix string
// Add this text to each footnote anchor, to ensure uniqueness.
FootnoteAnchorPrefix string
// Show this text inside the <a> tag for a footnote return link, if the
// HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
// <sup>[return]</sup> is used.
FootnoteReturnLinkContents string
// If set, add this text to the front of each Header ID, to ensure
// uniqueness.
HeaderIDPrefix string
// If set, add this text to the back of each Header ID, to ensure uniqueness.
HeaderIDSuffix string
}

// Html is a type that implements the Renderer interface for HTML output.
//
// Do not create this directly, instead use the HtmlRenderer function.
type Html struct {
flags int // HTML_* options
closeTag string // how to end singleton tags: either " />" or ">"
title string // document title
css string // optional css file url (used with HTML_COMPLETE_PAGE)

parameters HtmlRendererParameters

// table of contents data
tocMarker int
headerCount int
currentLevel int
toc *bytes.Buffer

// Track header IDs to prevent ID collision in a single generation.
headerIDs map[string]int

smartypants *smartypantsRenderer
}

const (
xhtmlClose = " />"
htmlClose = ">"
)

// HtmlRenderer creates and configures an Html object, which
// satisfies the Renderer interface.
//
// flags is a set of HTML_* options ORed together.
// title is the title of the document, and css is a URL for the document's
// stylesheet.
// title and css are only used when HTML_COMPLETE_PAGE is selected.
func HtmlRenderer(flags int, title string, css string) Renderer {
return HtmlRendererWithParameters(flags, title, css, HtmlRendererParameters{})
}

func HtmlRendererWithParameters(flags int, title string,
css string, renderParameters HtmlRendererParameters) Renderer {
// configure the rendering engine
closeTag := htmlClose
if flags&HTML_USE_XHTML != 0 {
closeTag = xhtmlClose
}

if renderParameters.FootnoteReturnLinkContents == "" {
renderParameters.FootnoteReturnLinkContents = `<sup>[return]</sup>`
}

return &Html{
flags: flags,
closeTag: closeTag,
title: title,
css: css,
parameters: renderParameters,

headerCount: 0,
currentLevel: 0,
toc: new(bytes.Buffer),

headerIDs: make(map[string]int),

smartypants: smartypants(flags),
}
}

// Using if statements is a bit faster than a switch statement. As the compiler
// improves, this should be unnecessary this is only worthwhile because
// attrEscape is the single largest CPU user in normal use.
// Also tried using map, but that gave a ~3x slowdown.
func escapeSingleChar(char byte) (string, bool) {
if char == '"' {
return "&quot;", true
}
if char == '&' {
return "&amp;", true
}
if char == '<' {
return "&lt;", true
}
if char == '>' {
return "&gt;", true
}
return "", false
}

func attrEscape(out *bytes.Buffer, src []byte) {
org := 0
for i, ch := range src {
if entity, ok := escapeSingleChar(ch); ok {
if i > org {
// copy all the normal characters since the last escape
out.Write(src[org:i])
}
org = i + 1
out.WriteString(entity)
}
}
if org < len(src) {
out.Write(src[org:])
}
}

func entityEscapeWithSkip(out *bytes.Buffer, src []byte, skipRanges [][]int) {
end := 0
for _, rang := range skipRanges {
attrEscape(out, src[end:rang[0]])
out.Write(src[rang[0]:rang[1]])
end = rang[1]
}
attrEscape(out, src[end:])
}

func (options *Html) GetFlags() int {
return options.flags
}

func (options *Html) TitleBlock(out *bytes.Buffer, text []byte) {
text = bytes.TrimPrefix(text, []byte("% "))
text = bytes.Replace(text, []byte("\n% "), []byte("\n"), -1)
out.WriteString("<h1 class=\"title\">")
out.Write(text)
out.WriteString("\n</h1>")
}

func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id string) {
marker := out.Len()
doubleSpace(out)

if id == "" && options.flags&HTML_TOC != 0 {
id = fmt.Sprintf("toc_%d", options.headerCount)
}

if id != "" {
id = options.ensureUniqueHeaderID(id)

if options.parameters.HeaderIDPrefix != "" {
id = options.parameters.HeaderIDPrefix + id
}

if options.parameters.HeaderIDSuffix != "" {
id = id + options.parameters.HeaderIDSuffix
}

out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id))
} else {
out.WriteString(fmt.Sprintf("<h%d>", level))
}

tocMarker := out.Len()
if !text() {
out.Truncate(marker)
return
}

// are we building a table of contents?
if options.flags&HTML_TOC != 0 {
options.TocHeaderWithAnchor(out.Bytes()[tocMarker:], level, id)
}

out.WriteString(fmt.Sprintf("</h%d>\n", level))
}

func (options *Html) BlockHtml(out *bytes.Buffer, text []byte) {
if options.flags&HTML_SKIP_HTML != 0 {
return
}

doubleSpace(out)
out.Write(text)
out.WriteByte('\n')
}

func (options *Html) HRule(out *bytes.Buffer) {
doubleSpace(out)
out.WriteString("<hr")
out.WriteString(options.closeTag)
out.WriteByte('\n')
}

func (options *Html) BlockCode(out *bytes.Buffer, text []byte, lang string) {
doubleSpace(out)

// parse out the language names/classes
count := 0
for _, elt := range strings.Fields(lang) {
if elt[0] == '.' {
elt = elt[1:]
}
if len(elt) == 0 {
continue
}
if count == 0 {
out.WriteString("<pre><code class=\"language-")
} else {
out.WriteByte(' ')
}
attrEscape(out, []byte(elt))
count++
}

if count == 0 {
out.WriteString("<pre><code>")
} else {
out.WriteString("\">")
}

attrEscape(out, text)
out.WriteString("</code></pre>\n")
}

func (options *Html) BlockQuote(out *bytes.Buffer, text []byte) {
doubleSpace(out)
out.WriteString("<blockquote>\n")
out.Write(text)
out.WriteString("</blockquote>\n")
}

func (options *Html) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
doubleSpace(out)
out.WriteString("<table>\n<thead>\n")
out.Write(header)
out.WriteString("</thead>\n\n<tbody>\n")
out.Write(body)
out.WriteString("</tbody>\n</table>\n")
}

func (options *Html) TableRow(out *bytes.Buffer, text []byte) {
doubleSpace(out)
out.WriteString("<tr>\n")
out.Write(text)
out.WriteString("\n</tr>\n")
}

func (options *Html) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
doubleSpace(out)
switch align {
case TABLE_ALIGNMENT_LEFT:
out.WriteString("<th align=\"left\">")
case TABLE_ALIGNMENT_RIGHT:
out.WriteString("<th align=\"right\">")
case TABLE_ALIGNMENT_CENTER:
out.WriteString("<th align=\"center\">")
default:
out.WriteString("<th>")
}

out.Write(text)
out.WriteString("</th>")
}

func (options *Html) TableCell(out *bytes.Buffer, text []byte, align int) {
doubleSpace(out)
switch align {
case TABLE_ALIGNMENT_LEFT:
out.WriteString("<td align=\"left\">")
case TABLE_ALIGNMENT_RIGHT:
out.WriteString("<td align=\"right\">")
case TABLE_ALIGNMENT_CENTER:
out.WriteString("<td align=\"center\">")
default:
out.WriteString("<td>")
}

out.Write(text)
out.WriteString("</td>")
}

func (options *Html) Footnotes(out *bytes.Buffer, text func() bool) {
out.WriteString("<div class=\"footnotes\">\n")
options.HRule(out)
options.List(out, text, LIST_TYPE_ORDERED)
out.WriteString("</div>\n")
}

func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
doubleSpace(out)
}
slug := slugify(name)
out.WriteString(`<li id="`)
out.WriteString(`fn:`)
out.WriteString(options.parameters.FootnoteAnchorPrefix)
out.Write(slug)
out.WriteString(`">`)
out.Write(text)
if options.flags&HTML_FOOTNOTE_RETURN_LINKS != 0 {
out.WriteString(` <a class="footnote-return" href="#`)
out.WriteString(`fnref:`)
out.WriteString(options.parameters.FootnoteAnchorPrefix)
out.Write(slug)
out.WriteString(`">`)
out.WriteString(options.parameters.FootnoteReturnLinkContents)
out.WriteString(`</a>`)
}
out.WriteString("</li>\n")
}

func (options *Html) List(out *bytes.Buffer, text func() bool, flags int) {
marker := out.Len()
doubleSpace(out)

if flags&LIST_TYPE_DEFINITION != 0 {
out.WriteString("<dl>")
} else if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("<ol>")
} else {
out.WriteString("<ul>")
}
if !text() {
out.Truncate(marker)
return
}
if flags&LIST_TYPE_DEFINITION != 0 {
out.WriteString("</dl>\n")
} else if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("</ol>\n")
} else {
out.WriteString("</ul>\n")
}
}

func (options *Html) ListItem(out *bytes.Buffer, text []byte, flags int) {
if (flags&LIST_ITEM_CONTAINS_BLOCK != 0 && flags&LIST_TYPE_DEFINITION == 0) ||
flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
doubleSpace(out)
}
if flags&LIST_TYPE_TERM != 0 {
out.WriteString("<dt>")
} else if flags&LIST_TYPE_DEFINITION != 0 {
out.WriteString("<dd>")
} else {
out.WriteString("<li>")
}
out.Write(text)
if flags&LIST_TYPE_TERM != 0 {
out.WriteString("</dt>\n")
} else if flags&LIST_TYPE_DEFINITION != 0 {
out.WriteString("</dd>\n")
} else {
out.WriteString("</li>\n")
}
}

func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
doubleSpace(out)

out.WriteString("<p>")
if !text() {
out.Truncate(marker)
return
}
out.WriteString("</p>\n")
}

func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) {
skipRanges := htmlEntity.FindAllIndex(link, -1)
if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) && kind != LINK_TYPE_EMAIL {
// mark it but don't link it if it is not a safe link: no smartypants
out.WriteString("<tt>")
entityEscapeWithSkip(out, link, skipRanges)
out.WriteString("</tt>")
return
}

out.WriteString("<a href=\"")
if kind == LINK_TYPE_EMAIL {
out.WriteString("mailto:")
} else {
options.maybeWriteAbsolutePrefix(out, link)
}

entityEscapeWithSkip(out, link, skipRanges)

var relAttrs []string
if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "nofollow")
}
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "noreferrer")
}
if len(relAttrs) > 0 {
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
}

// blank target only add to external link
if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
out.WriteString("\" target=\"_blank")
}

out.WriteString("\">")

// Pretty print: if we get an email address as
// an actual URI, e.g. `mailto:foo@bar.com`, we don't
// want to print the `mailto:` prefix
switch {
case bytes.HasPrefix(link, []byte("mailto://")):
attrEscape(out, link[len("mailto://"):])
case bytes.HasPrefix(link, []byte("mailto:")):
attrEscape(out, link[len("mailto:"):])
default:
entityEscapeWithSkip(out, link, skipRanges)
}

out.WriteString("</a>")
}

func (options *Html) CodeSpan(out *bytes.Buffer, text []byte) {
out.WriteString("<code>")
attrEscape(out, text)
out.WriteString("</code>")
}

func (options *Html) DoubleEmphasis(out *bytes.Buffer, text []byte) {
out.WriteString("<strong>")
out.Write(text)
out.WriteString("</strong>")
}

func (options *Html) Emphasis(out *bytes.Buffer, text []byte) {
if len(text) == 0 {
return
}
out.WriteString("<em>")
out.Write(text)
out.WriteString("</em>")
}

func (options *Html) maybeWriteAbsolutePrefix(out *bytes.Buffer, link []byte) {
if options.parameters.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
out.WriteString(options.parameters.AbsolutePrefix)
if link[0] != '/' {
out.WriteByte('/')
}
}
}

func (options *Html) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
if options.flags&HTML_SKIP_IMAGES != 0 {
return
}

out.WriteString("<img src=\"")
options.maybeWriteAbsolutePrefix(out, link)
attrEscape(out, link)
out.WriteString("\" alt=\"")
if len(alt) > 0 {
attrEscape(out, alt)
}
if len(title) > 0 {
out.WriteString("\" title=\"")
attrEscape(out, title)
}

out.WriteByte('"')
out.WriteString(options.closeTag)
}

func (options *Html) LineBreak(out *bytes.Buffer) {
out.WriteString("<br")
out.WriteString(options.closeTag)
out.WriteByte('\n')
}

func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
if options.flags&HTML_SKIP_LINKS != 0 {
// write the link text out but don't link it, just mark it with typewriter font
out.WriteString("<tt>")
attrEscape(out, content)
out.WriteString("</tt>")
return
}

if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) {
// write the link text out but don't link it, just mark it with typewriter font
out.WriteString("<tt>")
attrEscape(out, content)
out.WriteString("</tt>")
return
}

out.WriteString("<a href=\"")
options.maybeWriteAbsolutePrefix(out, link)
attrEscape(out, link)
if len(title) > 0 {
out.WriteString("\" title=\"")
attrEscape(out, title)
}
var relAttrs []string
if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "nofollow")
}
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "noreferrer")
}
if len(relAttrs) > 0 {
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
}

// blank target only add to external link
if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
out.WriteString("\" target=\"_blank")
}

out.WriteString("\">")
out.Write(content)
out.WriteString("</a>")
return
}

func (options *Html) RawHtmlTag(out *bytes.Buffer, text []byte) {
if options.flags&HTML_SKIP_HTML != 0 {
return
}
if options.flags&HTML_SKIP_STYLE != 0 && isHtmlTag(text, "style") {
return
}
if options.flags&HTML_SKIP_LINKS != 0 && isHtmlTag(text, "a") {
return
}
if options.flags&HTML_SKIP_IMAGES != 0 && isHtmlTag(text, "img") {
return
}
out.Write(text)
}

func (options *Html) TripleEmphasis(out *bytes.Buffer, text []byte) {
out.WriteString("<strong><em>")
out.Write(text)
out.WriteString("</em></strong>")
}

func (options *Html) StrikeThrough(out *bytes.Buffer, text []byte) {
out.WriteString("<del>")
out.Write(text)
out.WriteString("</del>")
}

func (options *Html) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
slug := slugify(ref)
out.WriteString(`<sup class="footnote-ref" id="`)
out.WriteString(`fnref:`)
out.WriteString(options.parameters.FootnoteAnchorPrefix)
out.Write(slug)
out.WriteString(`"><a rel="footnote" href="#`)
out.WriteString(`fn:`)
out.WriteString(options.parameters.FootnoteAnchorPrefix)
out.Write(slug)
out.WriteString(`">`)
out.WriteString(strconv.Itoa(id))
out.WriteString(`</a></sup>`)
}

func (options *Html) Entity(out *bytes.Buffer, entity []byte) {
out.Write(entity)
}

func (options *Html) NormalText(out *bytes.Buffer, text []byte) {
if options.flags&HTML_USE_SMARTYPANTS != 0 {
options.Smartypants(out, text)
} else {
attrEscape(out, text)
}
}

func (options *Html) Smartypants(out *bytes.Buffer, text []byte) {
smrt := smartypantsData{false, false}

// first do normal entity escaping
var escaped bytes.Buffer
attrEscape(&escaped, text)
text = escaped.Bytes()

mark := 0
for i := 0; i < len(text); i++ {
if action := options.smartypants[text[i]]; action != nil {
if i > mark {
out.Write(text[mark:i])
}

previousChar := byte(0)
if i > 0 {
previousChar = text[i-1]
}
i += action(out, &smrt, previousChar, text[i:])
mark = i + 1
}
}

if mark < len(text) {
out.Write(text[mark:])
}
}

func (options *Html) DocumentHeader(out *bytes.Buffer) {
if options.flags&HTML_COMPLETE_PAGE == 0 {
return
}

ending := ""
if options.flags&HTML_USE_XHTML != 0 {
out.WriteString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
out.WriteString("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
out.WriteString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
ending = " /"
} else {
out.WriteString("<!DOCTYPE html>\n")
out.WriteString("<html>\n")
}
out.WriteString("<head>\n")
out.WriteString(" <title>")
options.NormalText(out, []byte(options.title))
out.WriteString("</title>\n")
out.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
out.WriteString(VERSION)
out.WriteString("\"")
out.WriteString(ending)
out.WriteString(">\n")
out.WriteString(" <meta charset=\"utf-8\"")
out.WriteString(ending)
out.WriteString(">\n")
if options.css != "" {
out.WriteString(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")
attrEscape(out, []byte(options.css))
out.WriteString("\"")
out.WriteString(ending)
out.WriteString(">\n")
}
out.WriteString("</head>\n")
out.WriteString("<body>\n")

options.tocMarker = out.Len()
}

func (options *Html) DocumentFooter(out *bytes.Buffer) {
// finalize and insert the table of contents
if options.flags&HTML_TOC != 0 {
options.TocFinalize()

// now we have to insert the table of contents into the document
var temp bytes.Buffer

// start by making a copy of everything after the document header
temp.Write(out.Bytes()[options.tocMarker:])

// now clear the copied material from the main output buffer
out.Truncate(options.tocMarker)

// corner case spacing issue
if options.flags&HTML_COMPLETE_PAGE != 0 {
out.WriteByte('\n')
}

// insert the table of contents
out.WriteString("<nav>\n")
out.Write(options.toc.Bytes())
out.WriteString("</nav>\n")

// corner case spacing issue
if options.flags&HTML_COMPLETE_PAGE == 0 && options.flags&HTML_OMIT_CONTENTS == 0 {
out.WriteByte('\n')
}

// write out everything that came after it
if options.flags&HTML_OMIT_CONTENTS == 0 {
out.Write(temp.Bytes())
}
}

if options.flags&HTML_COMPLETE_PAGE != 0 {
out.WriteString("\n</body>\n")
out.WriteString("</html>\n")
}

}

func (options *Html) TocHeaderWithAnchor(text []byte, level int, anchor string) {
for level > options.currentLevel {
switch {
case bytes.HasSuffix(options.toc.Bytes(), []byte("</li>\n")):
// this sublist can nest underneath a header
size := options.toc.Len()
options.toc.Truncate(size - len("</li>\n"))

case options.currentLevel > 0:
options.toc.WriteString("<li>")
}
if options.toc.Len() > 0 {
options.toc.WriteByte('\n')
}
options.toc.WriteString("<ul>\n")
options.currentLevel++
}

for level < options.currentLevel {
options.toc.WriteString("</ul>")
if options.currentLevel > 1 {
options.toc.WriteString("</li>\n")
}
options.currentLevel--
}

options.toc.WriteString("<li><a href=\"#")
if anchor != "" {
options.toc.WriteString(anchor)
} else {
options.toc.WriteString("toc_")
options.toc.WriteString(strconv.Itoa(options.headerCount))
}
options.toc.WriteString("\">")
options.headerCount++

options.toc.Write(text)

options.toc.WriteString("</a></li>\n")
}

func (options *Html) TocHeader(text []byte, level int) {
options.TocHeaderWithAnchor(text, level, "")
}

func (options *Html) TocFinalize() {
for options.currentLevel > 1 {
options.toc.WriteString("</ul></li>\n")
options.currentLevel--
}

if options.currentLevel > 0 {
options.toc.WriteString("</ul>\n")
}
}

func isHtmlTag(tag []byte, tagname string) bool {
found, _ := findHtmlTagPos(tag, tagname)
return found
}

// Look for a character, but ignore it when it's in any kind of quotes, it
// might be JavaScript
func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
inSingleQuote := false
inDoubleQuote := false
inGraveQuote := false
i := start
for i < len(html) {
switch {
case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote:
return i
case html[i] == '\'':
inSingleQuote = !inSingleQuote
case html[i] == '"':
inDoubleQuote = !inDoubleQuote
case html[i] == '`':
inGraveQuote = !inGraveQuote
}
i++
}
return start
}

func findHtmlTagPos(tag []byte, tagname string) (bool, int) {
i := 0
if i < len(tag) && tag[0] != '<' {
return false, -1
}
i++
i = skipSpace(tag, i)

if i < len(tag) && tag[i] == '/' {
i++
}

i = skipSpace(tag, i)
j := 0
for ; i < len(tag); i, j = i+1, j+1 {
if j >= len(tagname) {
break
}

if strings.ToLower(string(tag[i]))[0] != tagname[j] {
return false, -1
}
}

if i == len(tag) {
return false, -1
}

rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>')
if rightAngle > i {
return true, rightAngle
}

return false, -1
}

func skipUntilChar(text []byte, start int, char byte) int {
i := start
for i < len(text) && text[i] != char {
i++
}
return i
}

func skipSpace(tag []byte, i int) int {
for i < len(tag) && isspace(tag[i]) {
i++
}
return i
}

func skipChar(data []byte, start int, char byte) int {
i := start
for i < len(data) && data[i] == char {
i++
}
return i
}

func doubleSpace(out *bytes.Buffer) {
if out.Len() > 0 {
out.WriteByte('\n')
}
}

func isRelativeLink(link []byte) (yes bool) {
// a tag begin with '#'
if link[0] == '#' {
return true
}

// link begin with '/' but not '//', the second maybe a protocol relative link
if len(link) >= 2 && link[0] == '/' && link[1] != '/' {
return true
}

// only the root '/'
if len(link) == 1 && link[0] == '/' {
return true
}

// current directory : begin with "./"
if bytes.HasPrefix(link, []byte("./")) {
return true
}

// parent directory : begin with "../"
if bytes.HasPrefix(link, []byte("../")) {
return true
}

return false
}

func (options *Html) ensureUniqueHeaderID(id string) string {
for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] {
tmp := fmt.Sprintf("%s-%d", id, count+1)

if _, tmpFound := options.headerIDs[tmp]; !tmpFound {
options.headerIDs[id] = count + 1
id = tmp
} else {
id = id + "-1"
}
}

if _, found := options.headerIDs[id]; !found {
options.headerIDs[id] = 0
}

return id
}

+ 1151
- 0
vendor/github.com/writeas/saturday/inline.go
File diff suppressed because it is too large
View File


+ 332
- 0
vendor/github.com/writeas/saturday/latex.go View File

@@ -0,0 +1,332 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//

//
//
// LaTeX rendering backend
//
//

package blackfriday

import (
"bytes"
)

// Latex is a type that implements the Renderer interface for LaTeX output.
//
// Do not create this directly, instead use the LatexRenderer function.
type Latex struct {
}

// LatexRenderer creates and configures a Latex object, which
// satisfies the Renderer interface.
//
// flags is a set of LATEX_* options ORed together (currently no such options
// are defined).
func LatexRenderer(flags int) Renderer {
return &Latex{}
}

func (options *Latex) GetFlags() int {
return 0
}

// render code chunks using verbatim, or listings if we have a language
func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, lang string) {
if lang == "" {
out.WriteString("\n\\begin{verbatim}\n")
} else {
out.WriteString("\n\\begin{lstlisting}[language=")
out.WriteString(lang)
out.WriteString("]\n")
}
out.Write(text)
if lang == "" {
out.WriteString("\n\\end{verbatim}\n")
} else {
out.WriteString("\n\\end{lstlisting}\n")
}
}

func (options *Latex) TitleBlock(out *bytes.Buffer, text []byte) {

}

func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) {
out.WriteString("\n\\begin{quotation}\n")
out.Write(text)
out.WriteString("\n\\end{quotation}\n")
}

func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
// a pretty lame thing to do...
out.WriteString("\n\\begin{verbatim}\n")
out.Write(text)
out.WriteString("\n\\end{verbatim}\n")
}

func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) {
marker := out.Len()

switch level {
case 1:
out.WriteString("\n\\section{")
case 2:
out.WriteString("\n\\subsection{")
case 3:
out.WriteString("\n\\subsubsection{")
case 4:
out.WriteString("\n\\paragraph{")
case 5:
out.WriteString("\n\\subparagraph{")
case 6:
out.WriteString("\n\\textbf{")
}
if !text() {
out.Truncate(marker)
return
}
out.WriteString("}\n")
}

func (options *Latex) HRule(out *bytes.Buffer) {
out.WriteString("\n\\HRule\n")
}

func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) {
marker := out.Len()
if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("\n\\begin{enumerate}\n")
} else {
out.WriteString("\n\\begin{itemize}\n")
}
if !text() {
out.Truncate(marker)
return
}
if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("\n\\end{enumerate}\n")
} else {
out.WriteString("\n\\end{itemize}\n")
}
}

func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) {
out.WriteString("\n\\item ")
out.Write(text)
}

func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
out.WriteString("\n")
if !text() {
out.Truncate(marker)
return
}
out.WriteString("\n")
}

func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
out.WriteString("\n\\begin{tabular}{")
for _, elt := range columnData {
switch elt {
case TABLE_ALIGNMENT_LEFT:
out.WriteByte('l')
case TABLE_ALIGNMENT_RIGHT:
out.WriteByte('r')
default:
out.WriteByte('c')
}
}
out.WriteString("}\n")
out.Write(header)
out.WriteString(" \\\\\n\\hline\n")
out.Write(body)
out.WriteString("\n\\end{tabular}\n")
}

func (options *Latex) TableRow(out *bytes.Buffer, text []byte) {
if out.Len() > 0 {
out.WriteString(" \\\\\n")
}
out.Write(text)
}

func (options *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}

func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}

// TODO: this
func (options *Latex) Footnotes(out *bytes.Buffer, text func() bool) {

}

func (options *Latex) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {

}

func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) {
out.WriteString("\\href{")
if kind == LINK_TYPE_EMAIL {
out.WriteString("mailto:")
}
out.Write(link)
out.WriteString("}{")
out.Write(link)
out.WriteString("}")
}

func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) {
out.WriteString("\\texttt{")
escapeSpecialChars(out, text)
out.WriteString("}")
}

func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) {
out.WriteString("\\textbf{")
out.Write(text)
out.WriteString("}")
}

func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) {
out.WriteString("\\textit{")
out.Write(text)
out.WriteString("}")
}

func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
// treat it like a link
out.WriteString("\\href{")
out.Write(link)
out.WriteString("}{")
out.Write(alt)
out.WriteString("}")
} else {
out.WriteString("\\includegraphics{")
out.Write(link)
out.WriteString("}")
}
}

func (options *Latex) LineBreak(out *bytes.Buffer) {
out.WriteString(" \\\\\n")
}

func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
out.WriteString("\\href{")
out.Write(link)
out.WriteString("}{")
out.Write(content)
out.WriteString("}")
}

func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) {
}

func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) {
out.WriteString("\\textbf{\\textit{")
out.Write(text)
out.WriteString("}}")
}

func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) {
out.WriteString("\\sout{")
out.Write(text)
out.WriteString("}")
}

// TODO: this
func (options *Latex) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {

}

func needsBackslash(c byte) bool {
for _, r := range []byte("_{}%$&\\~#") {
if c == r {
return true
}
}
return false
}

func escapeSpecialChars(out *bytes.Buffer, text []byte) {
for i := 0; i < len(text); i++ {
// directly copy normal characters
org := i

for i < len(text) && !needsBackslash(text[i]) {
i++
}
if i > org {
out.Write(text[org:i])
}

// escape a character
if i >= len(text) {
break
}
out.WriteByte('\\')
out.WriteByte(text[i])
}
}

func (options *Latex) Entity(out *bytes.Buffer, entity []byte) {
// TODO: convert this into a unicode character or something
out.Write(entity)
}

func (options *Latex) NormalText(out *bytes.Buffer, text []byte) {
escapeSpecialChars(out, text)
}

// header and footer
func (options *Latex) DocumentHeader(out *bytes.Buffer) {
out.WriteString("\\documentclass{article}\n")
out.WriteString("\n")
out.WriteString("\\usepackage{graphicx}\n")
out.WriteString("\\usepackage{listings}\n")
out.WriteString("\\usepackage[margin=1in]{geometry}\n")
out.WriteString("\\usepackage[utf8]{inputenc}\n")
out.WriteString("\\usepackage{verbatim}\n")
out.WriteString("\\usepackage[normalem]{ulem}\n")
out.WriteString("\\usepackage{hyperref}\n")
out.WriteString("\n")
out.WriteString("\\hypersetup{colorlinks,%\n")
out.WriteString(" citecolor=black,%\n")
out.WriteString(" filecolor=black,%\n")
out.WriteString(" linkcolor=black,%\n")
out.WriteString(" urlcolor=black,%\n")
out.WriteString(" pdfstartview=FitH,%\n")
out.WriteString(" breaklinks=true,%\n")
out.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
out.WriteString(VERSION)
out.WriteString("}}\n")
out.WriteString("\n")
out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
out.WriteString("\\parindent=0pt\n")
out.WriteString("\n")
out.WriteString("\\begin{document}\n")
}

func (options *Latex) DocumentFooter(out *bytes.Buffer) {
out.WriteString("\n\\end{document}\n")
}

+ 926
- 0
vendor/github.com/writeas/saturday/markdown.go View File

@@ -0,0 +1,926 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//

//
//
// Markdown parsing and processing
//
//

// Blackfriday markdown processor.
//
// Translates plain text with simple formatting rules into HTML or LaTeX.
package blackfriday

import (
"bytes"
"fmt"
"strings"
"unicode/utf8"
)

const VERSION = "1.5"

// These are the supported markdown parsing extensions.
// OR these values together to select multiple extensions.
const (
EXTENSION_NO_INTRA_EMPHASIS = 1 << iota // ignore emphasis markers inside words
EXTENSION_TABLES // render tables
EXTENSION_FENCED_CODE // render fenced code blocks
EXTENSION_AUTOLINK // detect embedded URLs that are not explicitly marked
EXTENSION_STRIKETHROUGH // strikethrough text using ~~test~~
EXTENSION_LAX_HTML_BLOCKS // loosen up HTML block parsing rules
EXTENSION_SPACE_HEADERS // be strict about prefix header rules
EXTENSION_HARD_LINE_BREAK // translate newlines into line breaks
EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four
EXTENSION_FOOTNOTES // Pandoc-style footnotes
EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
EXTENSION_HEADER_IDS // specify header IDs with {#id}
EXTENSION_TITLEBLOCK // Titleblock ala pandoc
EXTENSION_AUTO_HEADER_IDS // Create the header ID from the text
EXTENSION_BACKSLASH_LINE_BREAK // translate trailing backslashes into line breaks
EXTENSION_DEFINITION_LISTS // render definition lists

commonHtmlFlags = 0 |
HTML_USE_XHTML |
HTML_USE_SMARTYPANTS |
HTML_SMARTYPANTS_FRACTIONS |
HTML_SMARTYPANTS_DASHES |
HTML_SMARTYPANTS_LATEX_DASHES

commonExtensions = 0 |
EXTENSION_NO_INTRA_EMPHASIS |
EXTENSION_TABLES |
EXTENSION_FENCED_CODE |
EXTENSION_AUTOLINK |
EXTENSION_STRIKETHROUGH |
EXTENSION_SPACE_HEADERS |
EXTENSION_HEADER_IDS |
EXTENSION_BACKSLASH_LINE_BREAK |
EXTENSION_DEFINITION_LISTS
)

// These are the possible flag values for the link renderer.
// Only a single one of these values will be used; they are not ORed together.
// These are mostly of interest if you are writing a new output format.
const (
LINK_TYPE_NOT_AUTOLINK = iota
LINK_TYPE_NORMAL
LINK_TYPE_EMAIL
)

// These are the possible flag values for the ListItem renderer.
// Multiple flag values may be ORed together.
// These are mostly of interest if you are writing a new output format.
const (
LIST_TYPE_ORDERED = 1 << iota
LIST_TYPE_DEFINITION
LIST_TYPE_TERM
LIST_ITEM_CONTAINS_BLOCK
LIST_ITEM_BEGINNING_OF_LIST
LIST_ITEM_END_OF_LIST
)

// These are the possible flag values for the table cell renderer.
// Only a single one of these values will be used; they are not ORed together.
// These are mostly of interest if you are writing a new output format.
const (
TABLE_ALIGNMENT_LEFT = 1 << iota
TABLE_ALIGNMENT_RIGHT
TABLE_ALIGNMENT_CENTER = (TABLE_ALIGNMENT_LEFT | TABLE_ALIGNMENT_RIGHT)
)

// The size of a tab stop.
const (
TAB_SIZE_DEFAULT = 4
TAB_SIZE_EIGHT = 8
)

// blockTags is a set of tags that are recognized as HTML block tags.
// Any of these can be included in markdown text without special escaping.
var blockTags = map[string]struct{}{
"blockquote": {},
"del": {},
"div": {},
"dl": {},
"fieldset": {},
"form": {},
"h1": {},
"h2": {},
"h3": {},
"h4": {},
"h5": {},
"h6": {},
"iframe": {},
"ins": {},
"math": {},
"noscript": {},
"ol": {},
"pre": {},
"p": {},
"script": {},
"style": {},
"table": {},
"ul": {},

// HTML5
"address": {},
"article": {},
"aside": {},
"canvas": {},
"figcaption": {},
"figure": {},
"footer": {},
"header": {},
"hgroup": {},
"main": {},
"nav": {},
"output": {},
"progress": {},
"section": {},
"video": {},
}

// Renderer is the rendering interface.
// This is mostly of interest if you are implementing a new rendering format.
//
// When a byte slice is provided, it contains the (rendered) contents of the
// element.
//
// When a callback is provided instead, it will write the contents of the
// respective element directly to the output buffer and return true on success.
// If the callback returns false, the rendering function should reset the
// output buffer as though it had never been called.
//
// Currently Html and Latex implementations are provided
type Renderer interface {
// block-level callbacks
BlockCode(out *bytes.Buffer, text []byte, lang string)
BlockQuote(out *bytes.Buffer, text []byte)
BlockHtml(out *bytes.Buffer, text []byte)
Header(out *bytes.Buffer, text func() bool, level int, id string)
HRule(out *bytes.Buffer)
List(out *bytes.Buffer, text func() bool, flags int)
ListItem(out *bytes.Buffer, text []byte, flags int)
Paragraph(out *bytes.Buffer, text func() bool)
Table(out *bytes.Buffer, header []byte, body []byte, columnData []int)
TableRow(out *bytes.Buffer, text []byte)
TableHeaderCell(out *bytes.Buffer, text []byte, flags int)
TableCell(out *bytes.Buffer, text []byte, flags int)
Footnotes(out *bytes.Buffer, text func() bool)
FootnoteItem(out *bytes.Buffer, name, text []byte, flags int)
TitleBlock(out *bytes.Buffer, text []byte)

// Span-level callbacks
AutoLink(out *bytes.Buffer, link []byte, kind int)
CodeSpan(out *bytes.Buffer, text []byte)
DoubleEmphasis(out *bytes.Buffer, text []byte)
Emphasis(out *bytes.Buffer, text []byte)
Image(out *bytes.Buffer, link []byte, title []byte, alt []byte)
LineBreak(out *bytes.Buffer)
Link(out *bytes.Buffer, link []byte, title []byte, content []byte)
RawHtmlTag(out *bytes.Buffer, tag []byte)
TripleEmphasis(out *bytes.Buffer, text []byte)
StrikeThrough(out *bytes.Buffer, text []byte)
FootnoteRef(out *bytes.Buffer, ref []byte, id int)

// Low-level callbacks
Entity(out *bytes.Buffer, entity []byte)
NormalText(out *bytes.Buffer, text []byte)

// Header and footer
DocumentHeader(out *bytes.Buffer)
DocumentFooter(out *bytes.Buffer)

GetFlags() int
}

// Callback functions for inline parsing. One such function is defined
// for each character that triggers a response when parsing inline data.
type inlineParser func(p *parser, out *bytes.Buffer, data []byte, offset int) int

// Parser holds runtime state used by the parser.
// This is constructed by the Markdown function.
type parser struct {
r Renderer
refOverride ReferenceOverrideFunc
refs map[string]*reference
inlineCallback [256]inlineParser
flags int
nesting int
maxNesting int
insideLink bool

// Footnotes need to be ordered as well as available to quickly check for
// presence. If a ref is also a footnote, it's stored both in refs and here
// in notes. Slice is nil if footnotes not enabled.
notes []*reference
}

func (p *parser) getRef(refid string) (ref *reference, found bool) {
if p.refOverride != nil {
r, overridden := p.refOverride(refid)
if overridden {
if r == nil {
return nil, false
}
return &reference{
link: []byte(r.Link),
title: []byte(r.Title),
noteId: 0,
hasBlock: false,
text: []byte(r.Text)}, true
}
}
// refs are case insensitive
ref, found = p.refs[strings.ToLower(refid)]
return ref, found
}

//
//
// Public interface
//
//

// Reference represents the details of a link.
// See the documentation in Options for more details on use-case.
type Reference struct {
// Link is usually the URL the reference points to.
Link string
// Title is the alternate text describing the link in more detail.
Title string
// Text is the optional text to override the ref with if the syntax used was
// [refid][]
Text string
}

// ReferenceOverrideFunc is expected to be called with a reference string and
// return either a valid Reference type that the reference string maps to or
// nil. If overridden is false, the default reference logic will be executed.
// See the documentation in Options for more details on use-case.
type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool)

// Options represents configurable overrides and callbacks (in addition to the
// extension flag set) for configuring a Markdown parse.
type Options struct {
// Extensions is a flag set of bit-wise ORed extension bits. See the
// EXTENSION_* flags defined in this package.
Extensions int

// ReferenceOverride is an optional function callback that is called every
// time a reference is resolved.
//
// In Markdown, the link reference syntax can be made to resolve a link to
// a reference instead of an inline URL, in one of the following ways:
//
// * [link text][refid]
// * [refid][]
//
// Usually, the refid is defined at the bottom of the Markdown document. If
// this override function is provided, the refid is passed to the override
// function first, before consulting the defined refids at the bottom. If
// the override function indicates an override did not occur, the refids at
// the bottom will be used to fill in the link details.
ReferenceOverride ReferenceOverrideFunc
}

// MarkdownBasic is a convenience function for simple rendering.
// It processes markdown input with no extensions enabled.
func MarkdownBasic(input []byte) []byte {
// set up the HTML renderer
htmlFlags := HTML_USE_XHTML
renderer := HtmlRenderer(htmlFlags, "", "")

// set up the parser
return MarkdownOptions(input, renderer, Options{Extensions: 0})
}

// Call Markdown with most useful extensions enabled
// MarkdownCommon is a convenience function for simple rendering.
// It processes markdown input with common extensions enabled, including:
//
// * Smartypants processing with smart fractions and LaTeX dashes
//
// * Intra-word emphasis suppression
//
// * Tables
//
// * Fenced code blocks
//
// * Autolinking
//
// * Strikethrough support
//
// * Strict header parsing
//
// * Custom Header IDs
func MarkdownCommon(input []byte) []byte {
// set up the HTML renderer
renderer := HtmlRenderer(commonHtmlFlags, "", "")
return MarkdownOptions(input, renderer, Options{
Extensions: commonExtensions})
}

// Markdown is the main rendering function.
// It parses and renders a block of markdown-encoded text.
// The supplied Renderer is used to format the output, and extensions dictates
// which non-standard extensions are enabled.
//
// To use the supplied Html or LaTeX renderers, see HtmlRenderer and
// LatexRenderer, respectively.
func Markdown(input []byte, renderer Renderer, extensions int) []byte {
return MarkdownOptions(input, renderer, Options{
Extensions: extensions})
}

// MarkdownOptions is just like Markdown but takes additional options through
// the Options struct.
func MarkdownOptions(input []byte, renderer Renderer, opts Options) []byte {
// no point in parsing if we can't render
if renderer == nil {
return nil
}

extensions := opts.Extensions

// fill in the render structure
p := new(parser)
p.r = renderer
p.flags = extensions
p.refOverride = opts.ReferenceOverride
p.refs = make(map[string]*reference)
p.maxNesting = 16
p.insideLink = false

// register inline parsers
p.inlineCallback['*'] = emphasis
p.inlineCallback['_'] = emphasis
if extensions&EXTENSION_STRIKETHROUGH != 0 {
p.inlineCallback['~'] = emphasis
}
p.inlineCallback['`'] = codeSpan
p.inlineCallback['\n'] = lineBreak
p.inlineCallback['['] = link
p.inlineCallback['<'] = leftAngle
p.inlineCallback['\\'] = escape
p.inlineCallback['&'] = entity

if extensions&EXTENSION_AUTOLINK != 0 {
p.inlineCallback[':'] = autoLink
}

if extensions&EXTENSION_FOOTNOTES != 0 {
p.notes = make([]*reference, 0)
}

first := firstPass(p, input)
second := secondPass(p, first)
return second
}

// first pass:
// - normalize newlines
// - extract references (outside of fenced code blocks)
// - expand tabs (outside of fenced code blocks)
// - copy everything else
func firstPass(p *parser, input []byte) []byte {
var out bytes.Buffer
tabSize := TAB_SIZE_DEFAULT
if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
tabSize = TAB_SIZE_EIGHT
}
beg := 0
lastFencedCodeBlockEnd := 0
for beg < len(input) {
// Find end of this line, then process the line.
end := beg
for end < len(input) && input[end] != '\n' && input[end] != '\r' {
end++
}

if p.flags&EXTENSION_FENCED_CODE != 0 {
// track fenced code block boundaries to suppress tab expansion
// and reference extraction inside them:
if beg >= lastFencedCodeBlockEnd {
if i := p.fencedCodeBlock(&out, input[beg:], false); i > 0 {
lastFencedCodeBlockEnd = beg + i
}
}
}

// add the line body if present
if end > beg {
if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
out.Write(input[beg:end])
} else if refEnd := isReference(p, input[beg:], tabSize); refEnd > 0 {
beg += refEnd
continue
} else {
expandTabs(&out, input[beg:end], tabSize)
}
}

if end < len(input) && input[end] == '\r' {
end++
}
if end < len(input) && input[end] == '\n' {
end++
}
out.WriteByte('\n')

beg = end
}

// empty input?
if out.Len() == 0 {
out.WriteByte('\n')
}

return out.Bytes()
}

// second pass: actual rendering
func secondPass(p *parser, input []byte) []byte {
var output bytes.Buffer

p.r.DocumentHeader(&output)
p.block(&output, input)

if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 {
p.r.Footnotes(&output, func() bool {
flags := LIST_ITEM_BEGINNING_OF_LIST
for i := 0; i < len(p.notes); i += 1 {
ref := p.notes[i]
var buf bytes.Buffer
if ref.hasBlock {
flags |= LIST_ITEM_CONTAINS_BLOCK
p.block(&buf, ref.title)
} else {
p.inline(&buf, ref.title)
}
p.r.FootnoteItem(&output, ref.link, buf.Bytes(), flags)
flags &^= LIST_ITEM_BEGINNING_OF_LIST | LIST_ITEM_CONTAINS_BLOCK
}

return true
})
}

p.r.DocumentFooter(&output)

if p.nesting != 0 {
panic("Nesting level did not end at zero")
}

return output.Bytes()
}

//
// Link references
//
// This section implements support for references that (usually) appear
// as footnotes in a document, and can be referenced anywhere in the document.
// The basic format is:
//
// [1]: http://www.google.com/ "Google"
// [2]: http://www.github.com/ "Github"
//
// Anywhere in the document, the reference can be linked by referring to its
// label, i.e., 1 and 2 in this example, as in:
//
// This library is hosted on [Github][2], a git hosting site.
//
// Actual footnotes as specified in Pandoc and supported by some other Markdown
// libraries such as php-markdown are also taken care of. They look like this:
//
// This sentence needs a bit of further explanation.[^note]
//
// [^note]: This is the explanation.
//
// Footnotes should be placed at the end of the document in an ordered list.
// Inline footnotes such as:
//
// Inline footnotes^[Not supported.] also exist.
//
// are not yet supported.

// References are parsed and stored in this struct.
type reference struct {
link []byte
title []byte
noteId int // 0 if not a footnote ref
hasBlock bool
text []byte
}

func (r *reference) String() string {
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteId: %d, hasBlock: %v}",
r.link, r.title, r.text, r.noteId, r.hasBlock)
}

// Check whether or not data starts with a reference link.
// If so, it is parsed and stored in the list of references
// (in the render struct).
// Returns the number of bytes to skip to move past it,
// or zero if the first line is not a reference.
func isReference(p *parser, data []byte, tabSize int) int {
// up to 3 optional leading spaces
if len(data) < 4 {
return 0
}
i := 0
for i < 3 && data[i] == ' ' {
i++
}

noteId := 0

// id part: anything but a newline between brackets
if data[i] != '[' {
return 0
}
i++
if p.flags&EXTENSION_FOOTNOTES != 0 {
if i < len(data) && data[i] == '^' {
// we can set it to anything here because the proper noteIds will
// be assigned later during the second pass. It just has to be != 0
noteId = 1
i++
}
}
idOffset := i
for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' {
i++
}
if i >= len(data) || data[i] != ']' {
return 0
}
idEnd := i

// spacer: colon (space | tab)* newline? (space | tab)*
i++
if i >= len(data) || data[i] != ':' {
return 0
}
i++
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
i++
}
if i < len(data) && (data[i] == '\n' || data[i] == '\r') {
i++
if i < len(data) && data[i] == '\n' && data[i-1] == '\r' {
i++
}
}
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
i++
}
if i >= len(data) {
return 0
}

var (
linkOffset, linkEnd int
titleOffset, titleEnd int
lineEnd int
raw []byte
hasBlock bool
)

if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
lineEnd = linkEnd
} else {
linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i)
}
if lineEnd == 0 {
return 0
}

// a valid ref has been found

ref := &reference{
noteId: noteId,
hasBlock: hasBlock,
}

if noteId > 0 {
// reusing the link field for the id since footnotes don't have links
ref.link = data[idOffset:idEnd]
// if footnote, it's not really a title, it's the contained text
ref.title = raw
} else {
ref.link = data[linkOffset:linkEnd]
ref.title = data[titleOffset:titleEnd]
}

// id matches are case-insensitive
id := string(bytes.ToLower(data[idOffset:idEnd]))

p.refs[id] = ref

return lineEnd
}

func scanLinkRef(p *parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
// link: whitespace-free sequence, optionally between angle brackets
if data[i] == '<' {
i++
}
linkOffset = i
if i == len(data) {
return
}
for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' {
i++
}
linkEnd = i
if data[linkOffset] == '<' && data[linkEnd-1] == '>' {
linkOffset++
linkEnd--
}

// optional spacer: (space | tab)* (newline | '\'' | '"' | '(' )
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
i++
}
if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' {
return
}

// compute end-of-line
if i >= len(data) || data[i] == '\r' || data[i] == '\n' {
lineEnd = i
}
if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' {
lineEnd++
}

// optional (space|tab)* spacer after a newline
if lineEnd > 0 {
i = lineEnd + 1
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
i++
}
}

// optional title: any non-newline sequence enclosed in '"() alone on its line
if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') {
i++
titleOffset = i

// look for EOL
for i < len(data) && data[i] != '\n' && data[i] != '\r' {
i++
}
if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' {
titleEnd = i + 1
} else {
titleEnd = i
}

// step back
i--
for i > titleOffset && (data[i] == ' ' || data[i] == '\t') {
i--
}
if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') {
lineEnd = titleEnd
titleEnd = i
}
}

return
}

// The first bit of this logic is the same as (*parser).listItem, but the rest
// is much simpler. This function simply finds the entire block and shifts it
// over by one tab if it is indeed a block (just returns the line if it's not).
// blockEnd is the end of the section in the input buffer, and contents is the
// extracted text that was shifted over one tab. It will need to be rendered at
// the end of the document.
func scanFootnote(p *parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
if i == 0 || len(data) == 0 {
return
}

// skip leading whitespace on first line
for i < len(data) && data[i] == ' ' {
i++
}

blockStart = i

// find the end of the line
blockEnd = i
for i < len(data) && data[i-1] != '\n' {
i++
}

// get working buffer
var raw bytes.Buffer

// put the first line into the working buffer
raw.Write(data[blockEnd:i])
blockEnd = i

// process the following lines
containsBlankLine := false

gatherLines:
for blockEnd < len(data) {
i++

// find the end of this line
for i < len(data) && data[i-1] != '\n' {
i++
}

// if it is an empty line, guess that it is part of this item
// and move on to the next line
if p.isEmpty(data[blockEnd:i]) > 0 {
containsBlankLine = true
blockEnd = i
continue
}

n := 0
if n = isIndented(data[blockEnd:i], indentSize); n == 0 {
// this is the end of the block.
// we don't want to include this last line in the index.
break gatherLines
}

// if there were blank lines before this one, insert a new one now
if containsBlankLine {
raw.WriteByte('\n')
containsBlankLine = false
}

// get rid of that first tab, write to buffer
raw.Write(data[blockEnd+n : i])
hasBlock = true

blockEnd = i
}

if data[blockEnd-1] != '\n' {
raw.WriteByte('\n')
}

contents = raw.Bytes()

return
}

//
//
// Miscellaneous helper functions
//
//

// Test if a character is a punctuation symbol.
// Taken from a private function in regexp in the stdlib.
func ispunct(c byte) bool {
for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
if c == r {
return true
}
}
return false
}

// Test if a character is a whitespace character.
func isspace(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
}

// Test if a character is letter.
func isletter(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}

// Test if a character is a letter or a digit.
// TODO: check when this is looking for ASCII alnum and when it should use unicode
func isalnum(c byte) bool {
return (c >= '0' && c <= '9') || isletter(c)
}

// Replace tab characters with spaces, aligning to the next TAB_SIZE column.
// always ends output with a newline
func expandTabs(out *bytes.Buffer, line []byte, tabSize int) {
// first, check for common cases: no tabs, or only tabs at beginning of line
i, prefix := 0, 0
slowcase := false
for i = 0; i < len(line); i++ {
if line[i] == '\t' {
if prefix == i {
prefix++
} else {
slowcase = true
break
}
}
}

// no need to decode runes if all tabs are at the beginning of the line
if !slowcase {
for i = 0; i < prefix*tabSize; i++ {
out.WriteByte(' ')
}
out.Write(line[prefix:])
return
}

// the slow case: we need to count runes to figure out how
// many spaces to insert for each tab
column := 0
i = 0
for i < len(line) {
start := i
for i < len(line) && line[i] != '\t' {
_, size := utf8.DecodeRune(line[i:])
i += size
column++
}

if i > start {
out.Write(line[start:i])
}

if i >= len(line) {
break
}

for {
out.WriteByte(' ')
column++
if column%tabSize == 0 {
break
}
}

i++
}
}

// Find if a line counts as indented or not.
// Returns number of characters the indent is (0 = not indented).
func isIndented(data []byte, indentSize int) int {
if len(data) == 0 {
return 0
}
if data[0] == '\t' {
return 1
}
if len(data) < indentSize {
return 0
}
for i := 0; i < indentSize; i++ {
if data[i] != ' ' {
return 0
}
}
return indentSize
}

// Create a url-safe slug for fragments
func slugify(in []byte) []byte {
if len(in) == 0 {
return in
}
out := make([]byte, 0, len(in))
sym := false

for _, ch := range in {
if isalnum(ch) {
sym = false
out = append(out, ch)
} else if sym {
continue
} else {
out = append(out, '-')
sym = true
}
}
var a, b int
var ch byte
for a, ch = range out {
if ch != '-' {
break
}
}
for b = len(out) - 1; b > 0; b-- {
if out[b] != '-' {
break
}
}
return out[a : b+1]
}

+ 396
- 0
vendor/github.com/writeas/saturday/smartypants.go View File

@@ -0,0 +1,396 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//

//
//
// SmartyPants rendering
//
//

package blackfriday

import (
"bytes"
)

type smartypantsData struct {
inSingleQuote bool
inDoubleQuote bool
}

func wordBoundary(c byte) bool {
return c == 0 || isspace(c) || ispunct(c)
}

func tolower(c byte) byte {
if c >= 'A' && c <= 'Z' {
return c - 'A' + 'a'
}
return c
}

func isdigit(c byte) bool {
return c >= '0' && c <= '9'
}

func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool) bool {
// edge of the buffer is likely to be a tag that we don't get to see,
// so we treat it like text sometimes

// enumerate all sixteen possibilities for (previousChar, nextChar)
// each can be one of {0, space, punct, other}
switch {
case previousChar == 0 && nextChar == 0:
// context is not any help here, so toggle
*isOpen = !*isOpen
case isspace(previousChar) && nextChar == 0:
// [ "] might be [ "<code>foo...]
*isOpen = true
case ispunct(previousChar) && nextChar == 0:
// [!"] hmm... could be [Run!"] or [("<code>...]
*isOpen = false
case /* isnormal(previousChar) && */ nextChar == 0:
// [a"] is probably a close
*isOpen = false
case previousChar == 0 && isspace(nextChar):
// [" ] might be [...foo</code>" ]
*isOpen = false
case isspace(previousChar) && isspace(nextChar):
// [ " ] context is not any help here, so toggle
*isOpen = !*isOpen
case ispunct(previousChar) && isspace(nextChar):
// [!" ] is probably a close
*isOpen = false
case /* isnormal(previousChar) && */ isspace(nextChar):
// [a" ] this is one of the easy cases
*isOpen = false
case previousChar == 0 && ispunct(nextChar):
// ["!] hmm... could be ["$1.95] or [</code>"!...]
*isOpen = false
case isspace(previousChar) && ispunct(nextChar):
// [ "!] looks more like [ "$1.95]
*isOpen = true
case ispunct(previousChar) && ispunct(nextChar):
// [!"!] context is not any help here, so toggle
*isOpen = !*isOpen
case /* isnormal(previousChar) && */ ispunct(nextChar):
// [a"!] is probably a close
*isOpen = false
case previousChar == 0 /* && isnormal(nextChar) */ :
// ["a] is probably an open
*isOpen = true
case isspace(previousChar) /* && isnormal(nextChar) */ :
// [ "a] this is one of the easy cases
*isOpen = true
case ispunct(previousChar) /* && isnormal(nextChar) */ :
// [!"a] is probably an open
*isOpen = true
default:
// [a'b] maybe a contraction?
*isOpen = false
}

out.WriteByte('&')
if *isOpen {
out.WriteByte('l')
} else {
out.WriteByte('r')
}
out.WriteByte(quote)
out.WriteString("quo;")
return true
}

func smartSingleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 2 {
t1 := tolower(text[1])

if t1 == '\'' {
nextChar := byte(0)
if len(text) >= 3 {
nextChar = text[2]
}
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
return 1
}
}

if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) {
out.WriteString("&rsquo;")
return 0
}

if len(text) >= 3 {
t2 := tolower(text[2])

if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) &&
(len(text) < 4 || wordBoundary(text[3])) {
out.WriteString("&rsquo;")
return 0
}
}
}

nextChar := byte(0)
if len(text) > 1 {
nextChar = text[1]
}
if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote) {
return 0
}

out.WriteByte(text[0])
return 0
}

func smartParens(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 3 {
t1 := tolower(text[1])
t2 := tolower(text[2])

if t1 == 'c' && t2 == ')' {
out.WriteString("&copy;")
return 2
}

if t1 == 'r' && t2 == ')' {
out.WriteString("&reg;")
return 2
}

if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' {
out.WriteString("&trade;")
return 3
}
}

out.WriteByte(text[0])
return 0
}

func smartDash(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 2 {
if text[1] == '-' {
out.WriteString("&mdash;")
return 1
}

if wordBoundary(previousChar) && wordBoundary(text[1]) {
out.WriteString("&ndash;")
return 0
}
}

out.WriteByte(text[0])
return 0
}

func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
out.WriteString("&mdash;")
return 2
}
if len(text) >= 2 && text[1] == '-' {
out.WriteString("&ndash;")
return 1
}

out.WriteByte(text[0])
return 0
}

func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
if bytes.HasPrefix(text, []byte("&quot;")) {
nextChar := byte(0)
if len(text) >= 7 {
nextChar = text[6]
}
if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
return 5
}
}

if bytes.HasPrefix(text, []byte("&#0;")) {
return 3
}

out.WriteByte('&')
return 0
}

func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartAmpVariant(out, smrt, previousChar, text, 'd')
}

func smartAmpAngledQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartAmpVariant(out, smrt, previousChar, text, 'a')
}

func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
out.WriteString("&hellip;")
return 2
}

if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' {
out.WriteString("&hellip;")
return 4
}

out.WriteByte(text[0])
return 0
}

func smartBacktick(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 2 && text[1] == '`' {
nextChar := byte(0)
if len(text) >= 3 {
nextChar = text[2]
}
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
return 1
}
}

out.WriteByte(text[0])
return 0
}

func smartNumberGeneric(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
// is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
// note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8)
// and avoid changing dates like 1/23/2005 into fractions.
numEnd := 0
for len(text) > numEnd && isdigit(text[numEnd]) {
numEnd++
}
if numEnd == 0 {
out.WriteByte(text[0])
return 0
}
denStart := numEnd + 1
if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 {
denStart = numEnd + 3
} else if len(text) < numEnd+2 || text[numEnd] != '/' {
out.WriteByte(text[0])
return 0
}
denEnd := denStart
for len(text) > denEnd && isdigit(text[denEnd]) {
denEnd++
}
if denEnd == denStart {
out.WriteByte(text[0])
return 0
}
if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' {
out.WriteString("<sup>")
out.Write(text[:numEnd])
out.WriteString("</sup>&frasl;<sub>")
out.Write(text[denStart:denEnd])
out.WriteString("</sub>")
return denEnd - 1
}
}

out.WriteByte(text[0])
return 0
}

func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
if text[0] == '1' && text[1] == '/' && text[2] == '2' {
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
out.WriteString("&frac12;")
return 2
}
}

if text[0] == '1' && text[1] == '/' && text[2] == '4' {
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') {
out.WriteString("&frac14;")
return 2
}
}

if text[0] == '3' && text[1] == '/' && text[2] == '4' {
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') {
out.WriteString("&frac34;")
return 2
}
}
}

out.WriteByte(text[0])
return 0
}

func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
nextChar := byte(0)
if len(text) > 1 {
nextChar = text[1]
}
if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
out.WriteString("&quot;")
}

return 0
}

func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd')
}

func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a')
}

func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
i := 0

for i < len(text) && text[i] != '>' {
i++
}

out.Write(text[:i+1])
return i
}

type smartCallback func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int

type smartypantsRenderer [256]smartCallback

func smartypants(flags int) *smartypantsRenderer {
r := new(smartypantsRenderer)
if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 {
r['"'] = smartDoubleQuote
r['&'] = smartAmp
} else {
r['"'] = smartAngledDoubleQuote
r['&'] = smartAmpAngledQuote
}
r['('] = smartParens
if flags&HTML_SMARTYPANTS_DASHES != 0 {
if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 {
r['-'] = smartDash
} else {
r['-'] = smartDashLatex
}
}
if flags&HTML_SMARTYPANTS_FRACTIONS == 0 {
r['1'] = smartNumber
r['3'] = smartNumber
} else {
for ch := '1'; ch <= '9'; ch++ {
r[ch] = smartNumberGeneric
}
}
return r
}

+ 373
- 0
vendor/github.com/writeas/web-core/LICENSE View File

@@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================

1. Definitions
--------------

1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.

1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.

1.3. "Contribution"
means Covered Software of a particular Contributor.

1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.

1.5. "Incompatible With Secondary Licenses"
means

(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or

(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.

1.6. "Executable Form"
means any form of the work other than Source Code Form.

1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.

1.8. "License"
means this document.

1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.

1.10. "Modifications"
means any of the following:

(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or

(b) any new file in Source Code Form that contains any Covered
Software.

1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.

1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.

1.13. "Source Code Form"
means the form of the work preferred for making modifications.

1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.

2. License Grants and Conditions
--------------------------------

2.1. Grants

Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:

(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and

(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.

2.2. Effective Date

The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.

2.3. Limitations on Grant Scope

The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:

(a) for any code that a Contributor has removed from Covered Software;
or

(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or

(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.

This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).

2.4. Subsequent Licenses

No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).

2.5. Representation

Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.

2.6. Fair Use

This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.

2.7. Conditions

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.

3. Responsibilities
-------------------

3.1. Distribution of Source Form

All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.

3.2. Distribution of Executable Form

If You distribute Covered Software in Executable Form then:

(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and

(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.

3.3. Distribution of a Larger Work

You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).

3.4. Notices

You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.

3.5. Application of Additional Terms

You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.

4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------

If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.

5. Termination
--------------

5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.

5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.

5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.

************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************

************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************

8. Litigation
-------------

Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.

9. Miscellaneous
----------------

This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.

10. Versions of the License
---------------------------

10.1. New Versions

Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.

10.2. Effect of New Versions

You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.

10.3. Modified Versions

If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).

10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses

If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.

Exhibit A - Source Code Form License Notice
-------------------------------------------

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.

You may add additional accurate notices of copyright ownership.

Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------

This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

+ 19
- 0
vendor/github.com/writeas/web-core/posts/parse.go View File

@@ -0,0 +1,19 @@
package posts

import (
"strings"
)

func ExtractTitle(content string) (title string, body string) {
if hashIndex := strings.Index(content, "# "); hashIndex == 0 {
eol := strings.IndexRune(content, '\n')
// First line should start with # and end with \n
if eol != -1 {
body = strings.TrimLeft(content[eol:], " \t\n\r")
title = content[len("# "):eol]
return
}
}
body = content
return
}

+ 63
- 0
vendor/github.com/writeas/web-core/posts/render.go View File

@@ -0,0 +1,63 @@
package posts

import (
"github.com/microcosm-cc/bluemonday"
"github.com/writeas/saturday"
"regexp"
"strings"
"unicode"
)

var (
blockReg = regexp.MustCompile("<(ul|ol|blockquote)>\n")
endBlockReg = regexp.MustCompile("</([a-z]+)>\n</(ul|ol|blockquote)>")

markeddownReg = regexp.MustCompile("<p>(.+)</p>")
)

func ApplyMarkdown(data []byte) string {
mdExtensions := 0 |
blackfriday.EXTENSION_TABLES |
blackfriday.EXTENSION_FENCED_CODE |
blackfriday.EXTENSION_AUTOLINK |
blackfriday.EXTENSION_STRIKETHROUGH |
blackfriday.EXTENSION_SPACE_HEADERS |
blackfriday.EXTENSION_HEADER_IDS
htmlFlags := 0 |
blackfriday.HTML_USE_SMARTYPANTS |
blackfriday.HTML_SMARTYPANTS_DASHES

// Generate Markdown
md := blackfriday.Markdown([]byte(data), blackfriday.HtmlRenderer(htmlFlags, "", ""), mdExtensions)
// Strip out bad HTML
policy := bluemonday.UGCPolicy()
policy.AllowAttrs("class", "id").Globally()
outHTML := string(policy.SanitizeBytes(md))
// Strip newlines on certain block elements that render with them
outHTML = blockReg.ReplaceAllString(outHTML, "<$1>")
outHTML = endBlockReg.ReplaceAllString(outHTML, "</$1></$2>")

return outHTML
}

func ApplyBasicMarkdown(data []byte) string {
mdExtensions := 0 |
blackfriday.EXTENSION_STRIKETHROUGH |
blackfriday.EXTENSION_SPACE_HEADERS |
blackfriday.EXTENSION_HEADER_IDS
htmlFlags := 0 |
blackfriday.HTML_SKIP_HTML |
blackfriday.HTML_USE_SMARTYPANTS |
blackfriday.HTML_SMARTYPANTS_DASHES

// Generate Markdown
md := blackfriday.Markdown([]byte(data), blackfriday.HtmlRenderer(htmlFlags, "", ""), mdExtensions)
// Strip out bad HTML
policy := bluemonday.UGCPolicy()
policy.AllowAttrs("class", "id").Globally()
outHTML := string(policy.SanitizeBytes(md))
outHTML = markeddownReg.ReplaceAllString(outHTML, "$1")
outHTML = strings.TrimRightFunc(outHTML, unicode.IsSpace)

return outHTML
}

+ 3
- 0
vendor/golang.org/x/crypto/AUTHORS View File

@@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at https://tip.golang.org/AUTHORS.

+ 3
- 0
vendor/golang.org/x/crypto/CONTRIBUTORS View File

@@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at https://tip.golang.org/CONTRIBUTORS.

+ 27
- 0
vendor/golang.org/x/crypto/LICENSE View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 22
- 0
vendor/golang.org/x/crypto/PATENTS View File

@@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)

"This implementation" means the copyrightable works distributed by
Google as part of the Go project.

Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

+ 951
- 0
vendor/golang.org/x/crypto/ssh/terminal/terminal.go View File

@@ -0,0 +1,951 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package terminal

import (
"bytes"
"io"
"sync"
"unicode/utf8"
)

// EscapeCodes contains escape sequences that can be written to the terminal in
// order to achieve different styles of text.
type EscapeCodes struct {
// Foreground colors
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte

// Reset all attributes
Reset []byte
}

var vt100EscapeCodes = EscapeCodes{
Black: []byte{keyEscape, '[', '3', '0', 'm'},
Red: []byte{keyEscape, '[', '3', '1', 'm'},
Green: []byte{keyEscape, '[', '3', '2', 'm'},
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
White: []byte{keyEscape, '[', '3', '7', 'm'},

Reset: []byte{keyEscape, '[', '0', 'm'},
}

// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal struct {
// AutoCompleteCallback, if non-null, is called for each keypress with
// the full input line and the current position of the cursor (in
// bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line
// and the new cursor position.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)

// Escape contains a pointer to the escape codes for this terminal.
// It's always a valid pointer, although the escape codes themselves
// may be empty if the terminal doesn't support them.
Escape *EscapeCodes

// lock protects the terminal and the state in this object from
// concurrent processing of a key press and a Write() call.
lock sync.Mutex

c io.ReadWriter
prompt []rune

// line is the current line being entered.
line []rune
// pos is the logical position of the cursor in line
pos int
// echo is true if local echo is enabled
echo bool
// pasteActive is true iff there is a bracketed paste operation in
// progress.
pasteActive bool

// cursorX contains the current X value of the cursor where the left
// edge is 0. cursorY contains the row number where the first row of
// the current line is 0.
cursorX, cursorY int
// maxLine is the greatest value of cursorY so far.
maxLine int

termWidth, termHeight int

// outBuf contains the terminal data to be sent.
outBuf []byte
// remainder contains the remainder of any partial key sequences after
// a read. It aliases into inBuf.
remainder []byte
inBuf [256]byte

// history contains previously entered commands so that they can be
// accessed with the up and down keys.
history stRingBuffer
// historyIndex stores the currently accessed history entry, where zero
// means the immediately previous entry.
historyIndex int
// When navigating up and down the history it's possible to return to
// the incomplete, initial line. That value is stored in
// historyPending.
historyPending string
}

// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
// a local terminal, that terminal must first have been put into raw mode.
// prompt is a string that is written at the start of each input line (i.e.
// "> ").
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
return &Terminal{
Escape: &vt100EscapeCodes,
c: c,
prompt: []rune(prompt),
termWidth: 80,
termHeight: 24,
echo: true,
historyIndex: -1,
}
}

const (
keyCtrlD = 4
keyCtrlU = 21
keyEnter = '\r'
keyEscape = 27
keyBackspace = 127
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
keyUp
keyDown
keyLeft
keyRight
keyAltLeft
keyAltRight
keyHome
keyEnd
keyDeleteWord
keyDeleteLine
keyClearScreen
keyPasteStart
keyPasteEnd
)

var (
crlf = []byte{'\r', '\n'}
pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
)

// bytesToKey tries to parse a key sequence from b. If successful, it returns
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
if len(b) == 0 {
return utf8.RuneError, nil
}

if !pasteActive {
switch b[0] {
case 1: // ^A
return keyHome, b[1:]
case 5: // ^E
return keyEnd, b[1:]
case 8: // ^H
return keyBackspace, b[1:]
case 11: // ^K
return keyDeleteLine, b[1:]
case 12: // ^L
return keyClearScreen, b[1:]
case 23: // ^W
return keyDeleteWord, b[1:]
}
}

if b[0] != keyEscape {
if !utf8.FullRune(b) {
return utf8.RuneError, b
}
r, l := utf8.DecodeRune(b)
return r, b[l:]
}

if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
switch b[2] {
case 'A':
return keyUp, b[3:]
case 'B':
return keyDown, b[3:]
case 'C':
return keyRight, b[3:]
case 'D':
return keyLeft, b[3:]
case 'H':
return keyHome, b[3:]
case 'F':
return keyEnd, b[3:]
}
}

if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
switch b[5] {
case 'C':
return keyAltRight, b[6:]
case 'D':
return keyAltLeft, b[6:]
}
}

if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
return keyPasteStart, b[6:]
}

if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
return keyPasteEnd, b[6:]
}

// If we get here then we have a key that we don't recognise, or a
// partial sequence. It's not clear how one should find the end of a
// sequence without knowing them all, but it seems that [a-zA-Z~] only
// appears at the end of a sequence.
for i, c := range b[0:] {
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
return keyUnknown, b[i+1:]
}
}

return utf8.RuneError, b
}

// queue appends data to the end of t.outBuf
func (t *Terminal) queue(data []rune) {
t.outBuf = append(t.outBuf, []byte(string(data))...)
}

var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
var space = []rune{' '}

func isPrintable(key rune) bool {
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
return key >= 32 && !isInSurrogateArea
}

// moveCursorToPos appends data to t.outBuf which will move the cursor to the
// given, logical position in the text.
func (t *Terminal) moveCursorToPos(pos int) {
if !t.echo {
return
}

x := visualLength(t.prompt) + pos
y := x / t.termWidth
x = x % t.termWidth

up := 0
if y < t.cursorY {
up = t.cursorY - y
}

down := 0
if y > t.cursorY {
down = y - t.cursorY
}

left := 0
if x < t.cursorX {
left = t.cursorX - x
}

right := 0
if x > t.cursorX {
right = x - t.cursorX
}

t.cursorX = x
t.cursorY = y
t.move(up, down, left, right)
}

func (t *Terminal) move(up, down, left, right int) {
movement := make([]rune, 3*(up+down+left+right))
m := movement
for i := 0; i < up; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'A'
m = m[3:]
}
for i := 0; i < down; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'B'
m = m[3:]
}
for i := 0; i < left; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'D'
m = m[3:]
}
for i := 0; i < right; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'C'
m = m[3:]
}

t.queue(movement)
}

func (t *Terminal) clearLineToRight() {
op := []rune{keyEscape, '[', 'K'}
t.queue(op)
}

const maxLineLength = 4096

func (t *Terminal) setLine(newLine []rune, newPos int) {
if t.echo {
t.moveCursorToPos(0)
t.writeLine(newLine)
for i := len(newLine); i < len(t.line); i++ {
t.writeLine(space)
}
t.moveCursorToPos(newPos)
}
t.line = newLine
t.pos = newPos
}

func (t *Terminal) advanceCursor(places int) {
t.cursorX += places
t.cursorY += t.cursorX / t.termWidth
if t.cursorY > t.maxLine {
t.maxLine = t.cursorY
}
t.cursorX = t.cursorX % t.termWidth

if places > 0 && t.cursorX == 0 {
// Normally terminals will advance the current position
// when writing a character. But that doesn't happen
// for the last character in a line. However, when
// writing a character (except a new line) that causes
// a line wrap, the position will be advanced two
// places.
//
// So, if we are stopping at the end of a line, we
// need to write a newline so that our cursor can be
// advanced to the next line.
t.outBuf = append(t.outBuf, '\r', '\n')
}
}

func (t *Terminal) eraseNPreviousChars(n int) {
if n == 0 {
return
}

if t.pos < n {
n = t.pos
}
t.pos -= n
t.moveCursorToPos(t.pos)

copy(t.line[t.pos:], t.line[n+t.pos:])
t.line = t.line[:len(t.line)-n]
if t.echo {
t.writeLine(t.line[t.pos:])
for i := 0; i < n; i++ {
t.queue(space)
}
t.advanceCursor(n)
t.moveCursorToPos(t.pos)
}
}

// countToLeftWord returns then number of characters from the cursor to the
// start of the previous word.
func (t *Terminal) countToLeftWord() int {
if t.pos == 0 {
return 0
}

pos := t.pos - 1
for pos > 0 {
if t.line[pos] != ' ' {
break
}
pos--
}
for pos > 0 {
if t.line[pos] == ' ' {
pos++
break
}
pos--
}

return t.pos - pos
}

// countToRightWord returns then number of characters from the cursor to the
// start of the next word.
func (t *Terminal) countToRightWord() int {
pos := t.pos
for pos < len(t.line) {
if t.line[pos] == ' ' {
break
}
pos++
}
for pos < len(t.line) {
if t.line[pos] != ' ' {
break
}
pos++
}
return pos - t.pos
}

// visualLength returns the number of visible glyphs in s.
func visualLength(runes []rune) int {
inEscapeSeq := false
length := 0

for _, r := range runes {
switch {
case inEscapeSeq:
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
inEscapeSeq = false
}
case r == '\x1b':
inEscapeSeq = true
default:
length++
}
}

return length
}

// handleKey processes the given key and, optionally, returns a line of text
// that the user has entered.
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
if t.pasteActive && key != keyEnter {
t.addKeyToLine(key)
return
}

switch key {
case keyBackspace:
if t.pos == 0 {
return
}
t.eraseNPreviousChars(1)
case keyAltLeft:
// move left by a word.
t.pos -= t.countToLeftWord()
t.moveCursorToPos(t.pos)
case keyAltRight:
// move right by a word.
t.pos += t.countToRightWord()
t.moveCursorToPos(t.pos)
case keyLeft:
if t.pos == 0 {
return
}
t.pos--
t.moveCursorToPos(t.pos)
case keyRight:
if t.pos == len(t.line) {
return
}
t.pos++
t.moveCursorToPos(t.pos)
case keyHome:
if t.pos == 0 {
return
}
t.pos = 0
t.moveCursorToPos(t.pos)
case keyEnd:
if t.pos == len(t.line) {
return
}
t.pos = len(t.line)
t.moveCursorToPos(t.pos)
case keyUp:
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
if !ok {
return "", false
}
if t.historyIndex == -1 {
t.historyPending = string(t.line)
}
t.historyIndex++
runes := []rune(entry)
t.setLine(runes, len(runes))
case keyDown:
switch t.historyIndex {
case -1:
return
case 0:
runes := []rune(t.historyPending)
t.setLine(runes, len(runes))
t.historyIndex--
default:
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
if ok {
t.historyIndex--
runes := []rune(entry)
t.setLine(runes, len(runes))
}
}
case keyEnter:
t.moveCursorToPos(len(t.line))
t.queue([]rune("\r\n"))
line = string(t.line)
ok = true
t.line = t.line[:0]
t.pos = 0
t.cursorX = 0
t.cursorY = 0
t.maxLine = 0
case keyDeleteWord:
// Delete zero or more spaces and then one or more characters.
t.eraseNPreviousChars(t.countToLeftWord())
case keyDeleteLine:
// Delete everything from the current cursor position to the
// end of line.
for i := t.pos; i < len(t.line); i++ {
t.queue(space)
t.advanceCursor(1)
}
t.line = t.line[:t.pos]
t.moveCursorToPos(t.pos)
case keyCtrlD:
// Erase the character under the current position.
// The EOF case when the line is empty is handled in
// readLine().
if t.pos < len(t.line) {
t.pos++
t.eraseNPreviousChars(1)
}
case keyCtrlU:
t.eraseNPreviousChars(t.pos)
case keyClearScreen:
// Erases the screen and moves the cursor to the home position.
t.queue([]rune("\x1b[2J\x1b[H"))
t.queue(t.prompt)
t.cursorX, t.cursorY = 0, 0
t.advanceCursor(visualLength(t.prompt))
t.setLine(t.line, t.pos)
default:
if t.AutoCompleteCallback != nil {
prefix := string(t.line[:t.pos])
suffix := string(t.line[t.pos:])

t.lock.Unlock()
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
t.lock.Lock()

if completeOk {
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
return
}
}
if !isPrintable(key) {
return
}
if len(t.line) == maxLineLength {
return
}
t.addKeyToLine(key)
}
return
}

// addKeyToLine inserts the given key at the current position in the current
// line.
func (t *Terminal) addKeyToLine(key rune) {
if len(t.line) == cap(t.line) {
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
copy(newLine, t.line)
t.line = newLine
}
t.line = t.line[:len(t.line)+1]
copy(t.line[t.pos+1:], t.line[t.pos:])
t.line[t.pos] = key
if t.echo {
t.writeLine(t.line[t.pos:])
}
t.pos++
t.moveCursorToPos(t.pos)
}

func (t *Terminal) writeLine(line []rune) {
for len(line) != 0 {
remainingOnLine := t.termWidth - t.cursorX
todo := len(line)
if todo > remainingOnLine {
todo = remainingOnLine
}
t.queue(line[:todo])
t.advanceCursor(visualLength(line[:todo]))
line = line[todo:]
}
}

// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
for len(buf) > 0 {
i := bytes.IndexByte(buf, '\n')
todo := len(buf)
if i >= 0 {
todo = i
}

var nn int
nn, err = w.Write(buf[:todo])
n += nn
if err != nil {
return n, err
}
buf = buf[todo:]

if i >= 0 {
if _, err = w.Write(crlf); err != nil {
return n, err
}
n++
buf = buf[1:]
}
}

return n, nil
}

func (t *Terminal) Write(buf []byte) (n int, err error) {
t.lock.Lock()
defer t.lock.Unlock()

if t.cursorX == 0 && t.cursorY == 0 {
// This is the easy case: there's nothing on the screen that we
// have to move out of the way.
return writeWithCRLF(t.c, buf)
}

// We have a prompt and possibly user input on the screen. We
// have to clear it first.
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
t.cursorX = 0
t.clearLineToRight()

for t.cursorY > 0 {
t.move(1 /* up */, 0, 0, 0)
t.cursorY--
t.clearLineToRight()
}

if _, err = t.c.Write(t.outBuf); err != nil {
return
}
t.outBuf = t.outBuf[:0]

if n, err = writeWithCRLF(t.c, buf); err != nil {
return
}

t.writeLine(t.prompt)
if t.echo {
t.writeLine(t.line)
}

t.moveCursorToPos(t.pos)

if _, err = t.c.Write(t.outBuf); err != nil {
return
}
t.outBuf = t.outBuf[:0]
return
}

// ReadPassword temporarily changes the prompt and reads a password, without
// echo, from the terminal.
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()

oldPrompt := t.prompt
t.prompt = []rune(prompt)
t.echo = false

line, err = t.readLine()

t.prompt = oldPrompt
t.echo = true

return
}

// ReadLine returns a line of input from the terminal.
func (t *Terminal) ReadLine() (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()

return t.readLine()
}

func (t *Terminal) readLine() (line string, err error) {
// t.lock must be held at this point

if t.cursorX == 0 && t.cursorY == 0 {
t.writeLine(t.prompt)
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
}

lineIsPasted := t.pasteActive

for {
rest := t.remainder
lineOk := false
for !lineOk {
var key rune
key, rest = bytesToKey(rest, t.pasteActive)
if key == utf8.RuneError {
break
}
if !t.pasteActive {
if key == keyCtrlD {
if len(t.line) == 0 {
return "", io.EOF
}
}
if key == keyPasteStart {
t.pasteActive = true
if len(t.line) == 0 {
lineIsPasted = true
}
continue
}
} else if key == keyPasteEnd {
t.pasteActive = false
continue
}
if !t.pasteActive {
lineIsPasted = false
}
line, lineOk = t.handleKey(key)
}
if len(rest) > 0 {
n := copy(t.inBuf[:], rest)
t.remainder = t.inBuf[:n]
} else {
t.remainder = nil
}
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
if lineOk {
if t.echo {
t.historyIndex = -1
t.history.Add(line)
}
if lineIsPasted {
err = ErrPasteIndicator
}
return
}

// t.remainder is a slice at the beginning of t.inBuf
// containing a partial key sequence
readBuf := t.inBuf[len(t.remainder):]
var n int

t.lock.Unlock()
n, err = t.c.Read(readBuf)
t.lock.Lock()

if err != nil {
return
}

t.remainder = t.inBuf[:n+len(t.remainder)]
}
}

// SetPrompt sets the prompt to be used when reading subsequent lines.
func (t *Terminal) SetPrompt(prompt string) {
t.lock.Lock()
defer t.lock.Unlock()

t.prompt = []rune(prompt)
}

func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
// Move cursor to column zero at the start of the line.
t.move(t.cursorY, 0, t.cursorX, 0)
t.cursorX, t.cursorY = 0, 0
t.clearLineToRight()
for t.cursorY < numPrevLines {
// Move down a line
t.move(0, 1, 0, 0)
t.cursorY++
t.clearLineToRight()
}
// Move back to beginning.
t.move(t.cursorY, 0, 0, 0)
t.cursorX, t.cursorY = 0, 0

t.queue(t.prompt)
t.advanceCursor(visualLength(t.prompt))
t.writeLine(t.line)
t.moveCursorToPos(t.pos)
}

func (t *Terminal) SetSize(width, height int) error {
t.lock.Lock()
defer t.lock.Unlock()

if width == 0 {
width = 1
}

oldWidth := t.termWidth
t.termWidth, t.termHeight = width, height

switch {
case width == oldWidth:
// If the width didn't change then nothing else needs to be
// done.
return nil
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
// If there is nothing on current line and no prompt printed,
// just do nothing
return nil
case width < oldWidth:
// Some terminals (e.g. xterm) will truncate lines that were
// too long when shinking. Others, (e.g. gnome-terminal) will
// attempt to wrap them. For the former, repainting t.maxLine
// works great, but that behaviour goes badly wrong in the case
// of the latter because they have doubled every full line.

// We assume that we are working on a terminal that wraps lines
// and adjust the cursor position based on every previous line
// wrapping and turning into two. This causes the prompt on
// xterms to move upwards, which isn't great, but it avoids a
// huge mess with gnome-terminal.
if t.cursorX >= t.termWidth {
t.cursorX = t.termWidth - 1
}
t.cursorY *= 2
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
case width > oldWidth:
// If the terminal expands then our position calculations will
// be wrong in the future because we think the cursor is
// |t.pos| chars into the string, but there will be a gap at
// the end of any wrapped line.
//
// But the position will actually be correct until we move, so
// we can move back to the beginning and repaint everything.
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
}

_, err := t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
return err
}

type pasteIndicatorError struct{}

func (pasteIndicatorError) Error() string {
return "terminal: ErrPasteIndicator not correctly handled"
}

// ErrPasteIndicator may be returned from ReadLine as the error, in addition
// to valid line data. It indicates that bracketed paste mode is enabled and
// that the returned line consists only of pasted data. Programs may wish to
// interpret pasted data more literally than typed data.
var ErrPasteIndicator = pasteIndicatorError{}

// SetBracketedPasteMode requests that the terminal bracket paste operations
// with markers. Not all terminals support this but, if it is supported, then
// enabling this mode will stop any autocomplete callback from running due to
// pastes. Additionally, any lines that are completely pasted will be returned
// from ReadLine with the error set to ErrPasteIndicator.
func (t *Terminal) SetBracketedPasteMode(on bool) {
if on {
io.WriteString(t.c, "\x1b[?2004h")
} else {
io.WriteString(t.c, "\x1b[?2004l")
}
}

// stRingBuffer is a ring buffer of strings.
type stRingBuffer struct {
// entries contains max elements.
entries []string
max int
// head contains the index of the element most recently added to the ring.
head int
// size contains the number of elements in the ring.
size int
}

func (s *stRingBuffer) Add(a string) {
if s.entries == nil {
const defaultNumEntries = 100
s.entries = make([]string, defaultNumEntries)
s.max = defaultNumEntries
}

s.head = (s.head + 1) % s.max
s.entries[s.head] = a
if s.size < s.max {
s.size++
}
}

// NthPreviousEntry returns the value passed to the nth previous call to Add.
// If n is zero then the immediately prior value is returned, if one, then the
// next most recent, and so on. If such an element doesn't exist then ok is
// false.
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
if n >= s.size {
return "", false
}
index := s.head - n
if index < 0 {
index += s.max
}
return s.entries[index], true
}

// readPasswordLine reads from reader until it finds \n or io.EOF.
// The slice returned does not include the \n.
// readPasswordLine also ignores any \r it finds.
func readPasswordLine(reader io.Reader) ([]byte, error) {
var buf [1]byte
var ret []byte

for {
n, err := reader.Read(buf[:])
if n > 0 {
switch buf[0] {
case '\n':
return ret, nil
case '\r':
// remove \r from passwords on Windows
default:
ret = append(ret, buf[0])
}
continue
}
if err != nil {
if err == io.EOF && len(ret) > 0 {
return ret, nil
}
return ret, err
}
}
}

+ 114
- 0
vendor/golang.org/x/crypto/ssh/terminal/util.go View File

@@ -0,0 +1,114 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd

// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package terminal // import "golang.org/x/crypto/ssh/terminal"

import (
"golang.org/x/sys/unix"
)

// State contains the state of a terminal.
type State struct {
termios unix.Termios
}

// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
return err == nil
}

// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, err
}

oldState := State{termios: *termios}

// This attempts to replicate the behaviour documented for cfmakeraw in
// the termios(3) manpage.
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
termios.Oflag &^= unix.OPOST
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
termios.Cflag &^= unix.CSIZE | unix.PARENB
termios.Cflag |= unix.CS8
termios.Cc[unix.VMIN] = 1
termios.Cc[unix.VTIME] = 0
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
return nil, err
}

return &oldState, nil
}

// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, err
}

return &State{termios: *termios}, nil
}

// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
}

// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != nil {
return -1, -1, err
}
return int(ws.Col), int(ws.Row), nil
}

// passwordReader is an io.Reader that reads from a specific file descriptor.
type passwordReader int

func (r passwordReader) Read(buf []byte) (int, error) {
return unix.Read(int(r), buf)
}

// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, err
}

newState := *termios
newState.Lflag &^= unix.ECHO
newState.Lflag |= unix.ICANON | unix.ISIG
newState.Iflag |= unix.ICRNL
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
return nil, err
}

defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)

return readPasswordLine(passwordReader(fd))
}

+ 12
- 0
vendor/golang.org/x/crypto/ssh/terminal/util_aix.go View File

@@ -0,0 +1,12 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix

package terminal

import "golang.org/x/sys/unix"

const ioctlReadTermios = unix.TCGETS
const ioctlWriteTermios = unix.TCSETS

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save