<commit_before>// Command deployctl implements single-command operator's interface to manage
// deployments running under deploy-registry and deploy-agent
package main

import (
	"archive/tar"
	"compress/gzip"
	"crypto/sha256"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"

	"github.com/artyom/autoflags"
	"github.com/artyom/deploy-tools/internal/shared"
	"github.com/pkg/errors"
	"github.com/pkg/sftp"
)

func main() {
	args := &runArgs{
		Addr: os.Getenv("DEPLOYCTL_ADDR"),
		Fp:   os.Getenv("DEPLOYCTL_FINGERPRINT"),
	}
	fs := flag.NewFlagSet("deployctl", flag.ExitOnError)
	fs.Usage = usageFunc(fs.PrintDefaults)
	autoflags.DefineFlagSet(fs, args)
	fs.Parse(os.Args[1:])
	if err := args.Validate(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n\n", err)
		fs.Usage()
		os.Exit(2)
	}
	if len(fs.Args()) == 0 {
		fs.Usage()
		os.Exit(2)
	}
	if err := dispatch(args.Addr, args.Fp, fs.Args()); err != nil {
		if err == errFlagParseError {
			os.Exit(2)
		}
		if _, ok := err.(*ssh.ExitError); !ok { // don't write "Process exited with status 1"
			fmt.Fprintln(os.Stderr, err)
		}
		os.Exit(1)
	}
}

func dispatch(addr, fingerprint string, rawArgs []string) error {
	if len(rawArgs) == 0 {
		return errors.New("nothing to do")
	}
	cmd, args := rawArgs[0], rawArgs[1:]
	switch cmd {
	case "components", "configurations":
		return proxyCommand(addr, fingerprint, rawArgs)
	case "addver":
		val := &shared.ArgsAddVersionByFile{}
		if err := parseArgs(cmd, val, os.Stderr, args); err != nil {
			return err
		}
		return uploadAndUpdate(addr, fingerprint, val)
	}
	val, err := validatorForCommand(cmd)
	if err != nil {
		return err
	}
	if err := parseArgs(cmd, val, os.Stderr, args); err != nil {
		return err
	}
	return proxyCommand(addr, fingerprint, rawArgs)
}

func uploadAndUpdate(addr, fingerprint string, args *shared.ArgsAddVersionByFile) error {
	src, err := os.Open(args.File)
	if err != nil {
		return err
	}
	defer src.Close()
	client, cancel, err := dialSSH(addr, fingerprint)
	if err != nil {
		return err
	}
	defer cancel()
	sftpconn, err := sftp.NewClient(client)
	if err != nil {
		return err
	}
	defer sftpconn.Close()
	dst, err := sftpconn.Create("upload")
	if err != nil {
		return err
	}
	defer dst.Close()
	pr, pw := io.Pipe()
	defer pw.Close()
	defer pr.Close()
	verifyErr := make(chan error)
	go func() {
		err := decodeArchive(pr)
		pr.CloseWithError(err)
		verifyErr <- err
	}()
	h := sha256.New()
	tr := io.TeeReader(src, h)
	if _, err := io.Copy(io.MultiWriter(pw, dst), tr); err != nil {
		return errors.WithMessage(err, "upload failure")
	}
	if err := dst.Close(); err != nil {
		return err
	}
	// decodeArchive buffers data, so it may not fail during io.Copy to
	// MultiWriter above if data is copied faster than decoded; ensure we
	// check decode result
	switch err := <-verifyErr; err {
	case io.EOF:
	default:
		return errors.WithMessage(err, "file validation failed")
	}
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	return session.Run(fmt.Sprintf("addver -name=%q -version=%q -hash=%x",
		args.Name, args.Version, h.Sum(nil)))
}

func dialSSH(addr, fingerprint string) (client *ssh.Client, closeFunc func(), err error) {
	agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		return nil, nil, errors.WithMessage(err, "cannot connect to ssh-agent, check if SSH_AUTH_SOCK is set")
	}
	defer func() {
		if err != nil {
			agentConn.Close()
		}
	}()
	sshAgent := agent.NewClient(agentConn)
	var signers []ssh.Signer
	signers, err = sshAgent.Signers()
	if err != nil {
		return nil, nil, err
	}
	config := &ssh.ClientConfig{
		User:    os.Getenv("USER"),
		Auth:    []ssh.AuthMethod{ssh.PublicKeys(signers...)},
		Timeout: 30 * time.Second,
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			if hostFp := ssh.FingerprintSHA256(key); hostFp != fingerprint {
				return errors.Errorf("host key fingerprint mismatch: %v", hostFp)
			}
			return nil
		},
	}
	client, err = ssh.Dial("tcp", addr, config)
	if err != nil {
		return nil, nil, err
	}
	closeFunc = func() { client.Close(); agentConn.Close() }
	return client, closeFunc, nil
}

func proxyCommand(addr, fingerprint string, args []string) error {
	client, cancel, err := dialSSH(addr, fingerprint)
	if err != nil {
		return err
	}
	defer cancel()
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	return session.Run(strings.Join(args, " "))
}

type validator interface {
	Validate() error
}

func validatorForCommand(name string) (validator, error) {
	switch name {
	case "delver":
		return &shared.ArgsDelVersion{}, nil
	case "delcomp":
		return &shared.ArgsDelComponent{}, nil
	case "addconf":
		return &shared.ArgsAddConfiguration{}, nil
	case "delconf":
		return &shared.ArgsDelConfiguration{}, nil
	case "changeconf":
		return &shared.ArgsUpdateConfiguration{}, nil
	case "showconf":
		return &shared.ArgsShowConfiguration{}, nil
	case "showcomp":
		return &shared.ArgsShowComponent{}, nil
	}
	return nil, errors.Errorf("unknown command: %q", name)
}

// errFlagParseError is a sentinel error value used to determine whether error
// originates from flagset that already reported error to stderr so its
// reporting can be omitted
var errFlagParseError = errors.New("flag parse error")

// parseArgs defines new flag set with flags from argStruct that writes its
// errors to w, then calls flag set Parse method on provided raw arguments and
// calls Validate() method on provided argStruct. If parseArgs returns
// errFlagParseError, it means that flag set already reported error to w.
func parseArgs(command string, argStruct validator, w io.Writer, raw []string) error {
	fs := flag.NewFlagSet(command, flag.ContinueOnError)
	fs.SetOutput(w)
	autoflags.DefineFlagSet(fs, argStruct)
	if err := fs.Parse(raw); err != nil {
		return errFlagParseError
	}
	return argStruct.Validate()
}

type runArgs struct {
	Addr string `flag:"addr,$DEPLOYCTL_ADDR, registry host address (host:port)"`
	Fp   string `flag:"fp,$DEPLOYCTL_FINGERPRINT, sha256 host key fingerprint (sha256:...)"`
}

func (a *runArgs) Validate() error {
	if a.Addr == "" || a.Fp == "" {
		return errors.New("both addr and fp should be set")
	}
	return nil
}

func usageFunc(printDefaults func()) func() {
	return func() {
		fmt.Fprintln(os.Stderr, "Usage: deployctl [flags] subcommand [subcommand flags]")
		printDefaults()
		fmt.Fprintln(os.Stderr, "\nSubcommands:\n")
		fmt.Fprintln(os.Stderr, strings.TrimSpace(shared.CommandsListing))
	}
}

// decodeArchive reads and unpacks rd as tar.gz stream, discarding data and
// returning first error it encounters
func decodeArchive(rd io.Reader) error {
	gr, err := gzip.NewReader(rd)
	if err != nil {
		return err
	}
	defer gr.Close()
	tr := tar.NewReader(gr)
	for {
		if _, err := tr.Next(); err != nil {
			return err
		}
		if _, err := io.Copy(ioutil.Discard, tr); err != nil {
			return err
		}
	}
}
<commit_msg>deployctl: make go vet happy<commit_after>// Command deployctl implements single-command operator's interface to manage
// deployments running under deploy-registry and deploy-agent
package main

import (
	"archive/tar"
	"compress/gzip"
	"crypto/sha256"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"

	"github.com/artyom/autoflags"
	"github.com/artyom/deploy-tools/internal/shared"
	"github.com/pkg/errors"
	"github.com/pkg/sftp"
)

func main() {
	args := &runArgs{
		Addr: os.Getenv("DEPLOYCTL_ADDR"),
		Fp:   os.Getenv("DEPLOYCTL_FINGERPRINT"),
	}
	fs := flag.NewFlagSet("deployctl", flag.ExitOnError)
	fs.Usage = usageFunc(fs.PrintDefaults)
	autoflags.DefineFlagSet(fs, args)
	fs.Parse(os.Args[1:])
	if err := args.Validate(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n\n", err)
		fs.Usage()
		os.Exit(2)
	}
	if len(fs.Args()) == 0 {
		fs.Usage()
		os.Exit(2)
	}
	if err := dispatch(args.Addr, args.Fp, fs.Args()); err != nil {
		if err == errFlagParseError {
			os.Exit(2)
		}
		if _, ok := err.(*ssh.ExitError); !ok { // don't write "Process exited with status 1"
			fmt.Fprintln(os.Stderr, err)
		}
		os.Exit(1)
	}
}

func dispatch(addr, fingerprint string, rawArgs []string) error {
	if len(rawArgs) == 0 {
		return errors.New("nothing to do")
	}
	cmd, args := rawArgs[0], rawArgs[1:]
	switch cmd {
	case "components", "configurations":
		return proxyCommand(addr, fingerprint, rawArgs)
	case "addver":
		val := &shared.ArgsAddVersionByFile{}
		if err := parseArgs(cmd, val, os.Stderr, args); err != nil {
			return err
		}
		return uploadAndUpdate(addr, fingerprint, val)
	}
	val, err := validatorForCommand(cmd)
	if err != nil {
		return err
	}
	if err := parseArgs(cmd, val, os.Stderr, args); err != nil {
		return err
	}
	return proxyCommand(addr, fingerprint, rawArgs)
}

func uploadAndUpdate(addr, fingerprint string, args *shared.ArgsAddVersionByFile) error {
	src, err := os.Open(args.File)
	if err != nil {
		return err
	}
	defer src.Close()
	client, cancel, err := dialSSH(addr, fingerprint)
	if err != nil {
		return err
	}
	defer cancel()
	sftpconn, err := sftp.NewClient(client)
	if err != nil {
		return err
	}
	defer sftpconn.Close()
	dst, err := sftpconn.Create("upload")
	if err != nil {
		return err
	}
	defer dst.Close()
	pr, pw := io.Pipe()
	defer pw.Close()
	defer pr.Close()
	verifyErr := make(chan error)
	go func() {
		err := decodeArchive(pr)
		pr.CloseWithError(err)
		verifyErr <- err
	}()
	h := sha256.New()
	tr := io.TeeReader(src, h)
	if _, err := io.Copy(io.MultiWriter(pw, dst), tr); err != nil {
		return errors.WithMessage(err, "upload failure")
	}
	if err := dst.Close(); err != nil {
		return err
	}
	// decodeArchive buffers data, so it may not fail during io.Copy to
	// MultiWriter above if data is copied faster than decoded; ensure we
	// check decode result
	switch err := <-verifyErr; err {
	case io.EOF:
	default:
		return errors.WithMessage(err, "file validation failed")
	}
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	return session.Run(fmt.Sprintf("addver -name=%q -version=%q -hash=%x",
		args.Name, args.Version, h.Sum(nil)))
}

func dialSSH(addr, fingerprint string) (client *ssh.Client, closeFunc func(), err error) {
	agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		return nil, nil, errors.WithMessage(err, "cannot connect to ssh-agent, check if SSH_AUTH_SOCK is set")
	}
	defer func() {
		if err != nil {
			agentConn.Close()
		}
	}()
	sshAgent := agent.NewClient(agentConn)
	var signers []ssh.Signer
	signers, err = sshAgent.Signers()
	if err != nil {
		return nil, nil, err
	}
	config := &ssh.ClientConfig{
		User:    os.Getenv("USER"),
		Auth:    []ssh.AuthMethod{ssh.PublicKeys(signers...)},
		Timeout: 30 * time.Second,
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			if hostFp := ssh.FingerprintSHA256(key); hostFp != fingerprint {
				return errors.Errorf("host key fingerprint mismatch: %v", hostFp)
			}
			return nil
		},
	}
	client, err = ssh.Dial("tcp", addr, config)
	if err != nil {
		return nil, nil, err
	}
	closeFunc = func() { client.Close(); agentConn.Close() }
	return client, closeFunc, nil
}

func proxyCommand(addr, fingerprint string, args []string) error {
	client, cancel, err := dialSSH(addr, fingerprint)
	if err != nil {
		return err
	}
	defer cancel()
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	return session.Run(strings.Join(args, " "))
}

type validator interface {
	Validate() error
}

func validatorForCommand(name string) (validator, error) {
	switch name {
	case "delver":
		return &shared.ArgsDelVersion{}, nil
	case "delcomp":
		return &shared.ArgsDelComponent{}, nil
	case "addconf":
		return &shared.ArgsAddConfiguration{}, nil
	case "delconf":
		return &shared.ArgsDelConfiguration{}, nil
	case "changeconf":
		return &shared.ArgsUpdateConfiguration{}, nil
	case "showconf":
		return &shared.ArgsShowConfiguration{}, nil
	case "showcomp":
		return &shared.ArgsShowComponent{}, nil
	}
	return nil, errors.Errorf("unknown command: %q", name)
}

// errFlagParseError is a sentinel error value used to determine whether error
// originates from flagset that already reported error to stderr so its
// reporting can be omitted
var errFlagParseError = errors.New("flag parse error")

// parseArgs defines new flag set with flags from argStruct that writes its
// errors to w, then calls flag set Parse method on provided raw arguments and
// calls Validate() method on provided argStruct. If parseArgs returns
// errFlagParseError, it means that flag set already reported error to w.
func parseArgs(command string, argStruct validator, w io.Writer, raw []string) error {
	fs := flag.NewFlagSet(command, flag.ContinueOnError)
	fs.SetOutput(w)
	autoflags.DefineFlagSet(fs, argStruct)
	if err := fs.Parse(raw); err != nil {
		return errFlagParseError
	}
	return argStruct.Validate()
}

type runArgs struct {
	Addr string `flag:"addr,$DEPLOYCTL_ADDR, registry host address (host:port)"`
	Fp   string `flag:"fp,$DEPLOYCTL_FINGERPRINT, sha256 host key fingerprint (sha256:...)"`
}

func (a *runArgs) Validate() error {
	if a.Addr == "" || a.Fp == "" {
		return errors.New("both addr and fp should be set")
	}
	return nil
}

func usageFunc(printDefaults func()) func() {
	return func() {
		fmt.Fprintln(os.Stderr, "Usage: deployctl [flags] subcommand [subcommand flags]")
		printDefaults()
		fmt.Fprintln(os.Stderr, "\nSubcommands:")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, strings.TrimSpace(shared.CommandsListing))
	}
}

// decodeArchive reads and unpacks rd as tar.gz stream, discarding data and
// returning first error it encounters
func decodeArchive(rd io.Reader) error {
	gr, err := gzip.NewReader(rd)
	if err != nil {
		return err
	}
	defer gr.Close()
	tr := tar.NewReader(gr)
	for {
		if _, err := tr.Next(); err != nil {
			return err
		}
		if _, err := io.Copy(ioutil.Discard, tr); err != nil {
			return err
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/msoap/html2data"
)

func main() {
	texts, err := html2data.GetData(os.Args[1], map[string]string{"one": os.Args[2]})
	if err != nil {
		log.Fatal(err)
	}

	for _, text := range texts["one"] {
		fmt.Println(text)
	}
}
<commit_msg>Fixed out if text not found<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/msoap/html2data"
)

func main() {
	texts, err := html2data.GetData(os.Args[1], map[string]string{"one": os.Args[2]})
	if err != nil {
		log.Fatal(err)
	}

	if textOne, ok := texts["one"]; ok {
		for _, text := range textOne {
			fmt.Println(text)
		}
	}
}
<|endoftext|>


<commit_before>// mailbox_sender - sender worker.
/*
Usage:

	mailbox_sender [flags]

The flags are:

	`-cid`: Campaign id
	`-g`: User groups
	`-p`: HTML file path
	`-t`: Mail Subject
	`-d`: Dry run all but not to send mail
	`-uid`: User ID

`-uid`, `-g` can't use together

Example:

	mailbox_sender -cid cbc6eb46 -g testuser -p ./email_1.html -t "#1 New Paper!" -d

*/
package main

import (
	"bytes"
	"crypto/md5"
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"regexp"

	_ "github.com/go-sql-driver/mysql"
	"github.com/toomore/mailbox/campaign"
	"github.com/toomore/mailbox/mails"
	"github.com/toomore/mailbox/utils"
)

var (
	cid         = flag.String("cid", "", "campaign ID")
	dryRun      = flag.Bool("d", false, "Dry run")
	replaceLink = flag.Bool("rl", true, "Replace A tag links")
	groups      = flag.String("g", "", "User groups")
	path        = flag.String("p", "", "HTML file path")
	subject     = flag.String("t", "", "mail subject")
	uid         = flag.String("uid", "", "User ID")
	areg        = regexp.MustCompile(`href="(http[s]?://[a-zA-z0-9/\.:?=,-]+)"`)
)

func replaceReader(html *[]byte, cid string, seed string, uid string) {
	data := url.Values{}
	data.Set("c", cid)
	data.Set("u", uid)
	hm := campaign.MakeMacSeed(seed, data)
	*html = bytes.Replace(
		*html,
		[]byte("{{READER}}"),
		[]byte(fmt.Sprintf("https://%s/read/%x?%s", os.Getenv("mailbox_web_site"), hm, data.Encode())),
		1)
}

func replaceFname(html *[]byte, fname string) {
	*html = bytes.Replace(*html, []byte("{{FNAME}}"), []byte(fname), -1)
}

func replaceATag(html *[]byte, allATags []linksData, cid string, seed string, uid string) {
	for _, v := range allATags {
		data := url.Values{}
		data.Set("c", cid)
		data.Set("u", uid)
		data.Set("l", v.linkID)
		data.Set("t", "a")
		hm := campaign.MakeMacSeed(seed, data)

		*html = bytes.Replace(*html, v.url,
			[]byte(fmt.Sprintf("https://%s/door/%x?%s", os.Getenv("mailbox_web_site"), hm, data.Encode())), -1)
	}
}

type linksData struct {
	md5h   string
	linkID string
	url    []byte
}

func filterATags(body []byte) []linksData {
	allATags := areg.FindAllSubmatch(body, -1)
	result := make([]linksData, len(allATags))
	for i, v := range allATags {
		md5h := md5.New()
		md5h.Write(v[1])
		md5hstr := fmt.Sprintf("%x", md5h.Sum(nil))
		linkID := fmt.Sprintf("%s", utils.GenSeed())
		_, err := utils.GetConn().Query(`INSERT INTO links(id,cid,url,urlhash) VALUES(?,?,?,?)`, linkID, *cid, v[1], md5hstr)
		if err != nil {
			rows, _ := utils.GetConn().Query(`SELECT id FROM links WHERE cid=? AND urlhash=?`, *cid, md5hstr)
			for rows.Next() {
				rows.Scan(&linkID)
			}
		}
		result[i].md5h = md5hstr
		result[i].linkID = linkID
		result[i].url = v[1]
	}
	return result
}

func main() {
	flag.Parse()
	file, err := os.Open(*path)
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}
	seed := campaign.GetSeed(*cid)
	var rows *sql.Rows
	if *uid != "" {
		rows, err = utils.GetConn().Query(`SELECT id,email,f_name,l_name FROM user WHERE alive=1 AND id=?`, *uid)
	} else {
		rows, err = utils.GetConn().Query(`SELECT id,email,f_name,l_name FROM user WHERE alive=1 AND groups=?`, *groups)
	}
	defer rows.Close()
	if err != nil {
		log.Fatal(err)
	}

	var allATags []linksData
	if *replaceLink {
		allATags = filterATags(body)
	}

	var count int
	for rows.Next() {
		var (
			email string
			fname string
			lname string
			msg   []byte
			no    string
		)
		rows.Scan(&no, &email, &fname, &lname)

		msg = body
		if *replaceLink {
			replaceATag(&msg, allATags, *cid, seed, *uid)
		}
		replaceFname(&msg, fname)
		replaceReader(&msg, *cid, seed, no)
		params := mails.GenParams(
			fmt.Sprintf("%s %s <%s>", fname, lname, email),
			string(msg),
			*subject)
		if *dryRun {
			log.Printf("%s\n", msg)
			for i, v := range allATags {
				fmt.Printf("%d => [%s] %s\n", i, v.linkID, v.url)
			}
		} else {
			mails.Send(params)
		}
		count++
	}
	if *uid != "" {
		log.Printf("\n  cid: %s, uid: %s, count: %d\n  Subject: `%s`\n", *cid, *uid, count, *subject)
	} else {
		log.Printf("\n  cid: %s, groups: %s, count: %d\n  Subject: `%s`\n", *cid, *groups, count, *subject)
	}
}
<commit_msg>Fixed lost data<commit_after>// mailbox_sender - sender worker.
/*
Usage:

	mailbox_sender [flags]

The flags are:

	`-cid`: Campaign id
	`-g`: User groups
	`-p`: HTML file path
	`-t`: Mail Subject
	`-d`: Dry run all but not to send mail
	`-uid`: User ID

`-uid`, `-g` can't use together

Example:

	mailbox_sender -cid cbc6eb46 -g testuser -p ./email_1.html -t "#1 New Paper!" -d

*/
package main

import (
	"bytes"
	"crypto/md5"
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"regexp"

	_ "github.com/go-sql-driver/mysql"
	"github.com/toomore/mailbox/campaign"
	"github.com/toomore/mailbox/mails"
	"github.com/toomore/mailbox/utils"
)

var (
	cid         = flag.String("cid", "", "campaign ID")
	dryRun      = flag.Bool("d", false, "Dry run")
	replaceLink = flag.Bool("rl", true, "Replace A tag links")
	groups      = flag.String("g", "", "User groups")
	path        = flag.String("p", "", "HTML file path")
	subject     = flag.String("t", "", "mail subject")
	uid         = flag.String("uid", "", "User ID")
	areg        = regexp.MustCompile(`href="(http[s]?://[a-zA-z0-9/\.:?=,-@]+)"`)
)

func replaceReader(html *[]byte, cid string, seed string, uid string) {
	data := url.Values{}
	data.Set("c", cid)
	data.Set("u", uid)
	hm := campaign.MakeMacSeed(seed, data)
	*html = bytes.Replace(
		*html,
		[]byte("{{READER}}"),
		[]byte(fmt.Sprintf("https://%s/read/%x?%s", os.Getenv("mailbox_web_site"), hm, data.Encode())),
		1)
}

func replaceFname(html *[]byte, fname string) {
	*html = bytes.Replace(*html, []byte("{{FNAME}}"), []byte(fname), -1)
}

func replaceATag(html *[]byte, allATags []linksData, cid string, seed string, uid string) {
	for _, v := range allATags {
		data := url.Values{}
		data.Set("c", cid)
		data.Set("u", uid)
		data.Set("l", v.linkID)
		data.Set("t", "a")
		hm := campaign.MakeMacSeed(seed, data)

		*html = bytes.Replace(*html, v.url,
			[]byte(fmt.Sprintf("https://%s/door/%x?%s", os.Getenv("mailbox_web_site"), hm, data.Encode())), -1)
	}
}

type linksData struct {
	md5h   string
	linkID string
	url    []byte
}

func filterATags(body []byte) []linksData {
	allATags := areg.FindAllSubmatch(body, -1)
	result := make([]linksData, len(allATags))
	for i, v := range allATags {
		md5h := md5.New()
		md5h.Write(v[1])
		md5hstr := fmt.Sprintf("%x", md5h.Sum(nil))
		linkID := fmt.Sprintf("%s", utils.GenSeed())
		_, err := utils.GetConn().Query(`INSERT INTO links(id,cid,url,urlhash) VALUES(?,?,?,?)`, linkID, *cid, v[1], md5hstr)
		if err != nil {
			rows, _ := utils.GetConn().Query(`SELECT id FROM links WHERE cid=? AND urlhash=?`, *cid, md5hstr)
			for rows.Next() {
				rows.Scan(&linkID)
			}
		}
		result[i].md5h = md5hstr
		result[i].linkID = linkID
		result[i].url = v[1]
	}
	return result
}

func main() {
	flag.Parse()
	file, err := os.Open(*path)
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}
	seed := campaign.GetSeed(*cid)
	var rows *sql.Rows
	if *uid != "" {
		rows, err = utils.GetConn().Query(`SELECT id,email,f_name,l_name FROM user WHERE alive=1 AND id=?`, *uid)
	} else {
		rows, err = utils.GetConn().Query(`SELECT id,email,f_name,l_name FROM user WHERE alive=1 AND groups=?`, *groups)
	}
	defer rows.Close()
	if err != nil {
		log.Fatal(err)
	}

	var allATags []linksData
	if *replaceLink {
		allATags = filterATags(body)
	}

	var count int
	for rows.Next() {
		var (
			email string
			fname string
			lname string
			msg   []byte
			no    string
		)
		rows.Scan(&no, &email, &fname, &lname)

		msg = body
		if *replaceLink {
			replaceATag(&msg, allATags, *cid, seed, no)
		}
		replaceFname(&msg, fname)
		replaceReader(&msg, *cid, seed, no)
		params := mails.GenParams(
			fmt.Sprintf("%s %s <%s>", fname, lname, email),
			string(msg),
			*subject)
		if *dryRun {
			log.Printf("%s\n", msg)
			for i, v := range allATags {
				fmt.Printf("%d => [%s] %s\n", i, v.linkID, v.url)
			}
		} else {
			mails.Send(params)
		}
		count++
	}
	if *uid != "" {
		log.Printf("\n  cid: %s, uid: %s, count: %d\n  Subject: `%s`\n", *cid, *uid, count, *subject)
	} else {
		log.Printf("\n  cid: %s, groups: %s, count: %d\n  Subject: `%s`\n", *cid, *groups, count, *subject)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/urfave/cli"
)

func TestCmdToot(t *testing.T) {
	toot := ""
	testWithServer(
		func(w http.ResponseWriter, r *http.Request) {
			switch r.URL.Path {
			case "/api/v1/statuses":
				toot = r.FormValue("status")
				fmt.Fprintln(w, `{"ID": 2345}`)
				return
			}
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		},
		func(app *cli.App) {
			app.Run([]string{"mstdn", "toot", "foo"})
		},
	)
	if toot != "foo" {
		t.Fatalf("want %q, got %q", "foo", toot)
	}
}
<commit_msg>Fix test json property name again<commit_after>package main

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/urfave/cli"
)

func TestCmdToot(t *testing.T) {
	toot := ""
	testWithServer(
		func(w http.ResponseWriter, r *http.Request) {
			switch r.URL.Path {
			case "/api/v1/statuses":
				toot = r.FormValue("status")
				fmt.Fprintln(w, `{"id": 2345}`)
				return
			}
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		},
		func(app *cli.App) {
			app.Run([]string{"mstdn", "toot", "foo"})
		},
	)
	if toot != "foo" {
		t.Fatalf("want %q, got %q", "foo", toot)
	}
}
<|endoftext|>


<commit_before>package graphite

import (
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/influxdb/influxdb/models"
)

var (
	defaultTemplate *template
	MinDate         = time.Date(1901, 12, 13, 0, 0, 0, 0, time.UTC)
	MaxDate         = time.Date(2038, 1, 19, 0, 0, 0, 0, time.UTC)
)

func init() {
	var err error
	defaultTemplate, err = NewTemplate("measurement*", nil, DefaultSeparator)
	if err != nil {
		panic(err)
	}
}

// Parser encapsulates a Graphite Parser.
type Parser struct {
	matcher *matcher
	tags    models.Tags
}

// Options are configurable values that can be provided to a Parser
type Options struct {
	Separator   string
	Templates   []string
	DefaultTags models.Tags
}

// NewParserWithOptions returns a graphite parser using the given options
func NewParserWithOptions(options Options) (*Parser, error) {

	matcher := newMatcher()
	matcher.AddDefaultTemplate(defaultTemplate)

	for _, pattern := range options.Templates {

		template := pattern
		filter := ""
		// Format is [filter] <template> [tag1=value1,tag2=value2]
		parts := strings.Fields(pattern)
		if len(parts) >= 2 {
			if strings.Contains(parts[1], "=") {
				template = parts[0]
			} else {
				filter = parts[0]
				template = parts[1]
			}
		}

		// Parse out the default tags specific to this template
		tags := models.Tags{}
		if strings.Contains(parts[len(parts)-1], "=") {
			tagStrs := strings.Split(parts[len(parts)-1], ",")
			for _, kv := range tagStrs {
				parts := strings.Split(kv, "=")
				tags[parts[0]] = parts[1]
			}
		}

		tmpl, err := NewTemplate(template, tags, options.Separator)
		if err != nil {
			return nil, err
		}
		matcher.Add(filter, tmpl)
	}
	return &Parser{matcher: matcher, tags: options.DefaultTags}, nil
}

// NewParser returns a GraphiteParser instance.
func NewParser(templates []string, defaultTags models.Tags) (*Parser, error) {
	return NewParserWithOptions(
		Options{
			Templates:   templates,
			DefaultTags: defaultTags,
			Separator:   DefaultSeparator,
		})
}

// Parse performs Graphite parsing of a single line.
func (p *Parser) Parse(line string) (models.Point, error) {
	// Break into 3 fields (name, value, timestamp).
	fields := strings.Fields(line)
	if len(fields) != 2 && len(fields) != 3 {
		return nil, fmt.Errorf("received %q which doesn't have required fields", line)
	}

	// decode the name and tags
	matcher := p.matcher.Match(fields[0])
	measurement, tags, field := matcher.Apply(fields[0])

	// Could not extract measurement, use the raw value
	if measurement == "" {
		measurement = fields[0]
	}

	// Parse value.
	v, err := strconv.ParseFloat(fields[1], 64)
	if err != nil {
		return nil, fmt.Errorf(`field "%s" value: %s`, fields[0], err)
	}

	if field != "" {
		fieldValues := map[string]interface{}{field: v}
	} else {
		fieldValues := map[string]interface{}{"value": v}
	}

	// If no 3rd field, use now as timestamp
	timestamp := time.Now().UTC()

	if len(fields) == 3 {
		// Parse timestamp.
		unixTime, err := strconv.ParseFloat(fields[2], 64)
		if err != nil {
			return nil, fmt.Errorf(`field "%s" time: %s`, fields[0], err)
		}

		// -1 is a special value that gets converted to current UTC time
		// See https://github.com/graphite-project/carbon/issues/54
		if unixTime != float64(-1) {
			// Check if we have fractional seconds
			timestamp = time.Unix(int64(unixTime), int64((unixTime-math.Floor(unixTime))*float64(time.Second)))
			if timestamp.Before(MinDate) || timestamp.After(MaxDate) {
				return nil, fmt.Errorf("timestamp out of range")
			}
		}
	}

	// Set the default tags on the point if they are not already set
	for k, v := range p.tags {
		if _, ok := tags[k]; !ok {
			tags[k] = v
		}
	}
	point := models.NewPoint(measurement, tags, fieldValues, timestamp)

	return point, nil
}

// template represents a pattern and tags to map a graphite metric string to a influxdb Point
type template struct {
	tags              []string
	defaultTags       models.Tags
	greedyMeasurement bool
	separator         string
}

func NewTemplate(pattern string, defaultTags models.Tags, separator string) (*template, error) {
	tags := strings.Split(pattern, ".")
	hasMeasurement := false
	template := &template{tags: tags, defaultTags: defaultTags, separator: separator}

	for _, tag := range tags {
		if strings.HasPrefix(tag, "measurement") {
			hasMeasurement = true
		}
		if tag == "measurement*" {
			template.greedyMeasurement = true
		}
	}

	if !hasMeasurement {
		return nil, fmt.Errorf("no measurement specified for template. %q", pattern)
	}

	return template, nil
}

// Apply extracts the template fields form the given line and returns the measurement
// name and tags
func (t *template) Apply(line string) (string, map[string]string, string) {
	fields := strings.Split(line, ".")
	var (
		measurement []string
		tags        = make(map[string]string)
		field       string
	)

	// Set any default tags
	for k, v := range t.defaultTags {
		tags[k] = v
	}

	for i, tag := range t.tags {
		if i >= len(fields) {
			continue
		}

		if tag == "measurement" {
			measurement = append(measurement, fields[i])
		} else if tag == "field" {
			if field != "" {
				return nil, fmt.Errorf(`template can only have one field defined: %s`, line)
			}
			field = field
		} else if tag == "measurement*" {
			measurement = append(measurement, fields[i:]...)
			break
		} else if tag != "" {
			tags[tag] = fields[i]
		}
	}

	return strings.Join(measurement, t.separator), tags, field
}

// matcher determines which template should be applied to a given metric
// based on a filter tree.
type matcher struct {
	root            *node
	defaultTemplate *template
}

func newMatcher() *matcher {
	return &matcher{
		root: &node{},
	}
}

// Add inserts the template in the filter tree based the given filter
func (m *matcher) Add(filter string, template *template) {
	if filter == "" {
		m.AddDefaultTemplate(template)
		return
	}
	m.root.Insert(filter, template)
}

func (m *matcher) AddDefaultTemplate(template *template) {
	m.defaultTemplate = template
}

// Match returns the template that matches the given graphite line
func (m *matcher) Match(line string) *template {
	tmpl := m.root.Search(line)
	if tmpl != nil {
		return tmpl
	}

	return m.defaultTemplate
}

// node is an item in a sorted k-ary tree.  Each child is sorted by its value.
// The special value of "*", is always last.
type node struct {
	value    string
	children nodes
	template *template
}

func (n *node) insert(values []string, template *template) {
	// Add the end, set the template
	if len(values) == 0 {
		n.template = template
		return
	}

	// See if the the current element already exists in the tree. If so, insert the
	// into that sub-tree
	for _, v := range n.children {
		if v.value == values[0] {
			v.insert(values[1:], template)
			return
		}
	}

	// New element, add it to the tree and sort the children
	newNode := &node{value: values[0]}
	n.children = append(n.children, newNode)
	sort.Sort(&n.children)

	// Now insert the rest of the tree into the new element
	newNode.insert(values[1:], template)
}

// Insert inserts the given string template into the tree.  The filter string is separated
// on "." and each part is used as the path in the tree.
func (n *node) Insert(filter string, template *template) {
	n.insert(strings.Split(filter, "."), template)
}

func (n *node) search(lineParts []string) *template {
	// Nothing to search
	if len(lineParts) == 0 || len(n.children) == 0 {
		return n.template
	}

	// If last element is a wildcard, don't include in this search since it's sorted
	// to the end but lexicographically it would not always be and sort.Search assumes
	// the slice is sorted.
	length := len(n.children)
	if n.children[length-1].value == "*" {
		length -= 1
	}

	// Find the index of child with an exact match
	i := sort.Search(length, func(i int) bool {
		return n.children[i].value >= lineParts[0]
	})

	// Found an exact match, so search that child sub-tree
	if i < len(n.children) && n.children[i].value == lineParts[0] {
		return n.children[i].search(lineParts[1:])
	}
	// Not an exact match, see if we have a wildcard child to search
	if n.children[len(n.children)-1].value == "*" {
		return n.children[len(n.children)-1].search(lineParts[1:])
	}
	return n.template
}

func (n *node) Search(line string) *template {
	return n.search(strings.Split(line, "."))
}

type nodes []*node

// Less returns a boolean indicating whether the filter at position j
// is less than the filter at position k.  Filters are order by string
// comparison of each component parts.  A wildcard value "*" is never
// less than a non-wildcard value.
//
// For example, the filters:
//             "*.*"
//             "servers.*"
//             "servers.localhost"
//             "*.localhost"
//
// Would be sorted as:
//             "servers.localhost"
//             "servers.*"
//             "*.localhost"
//             "*.*"
func (n *nodes) Less(j, k int) bool {
	if (*n)[j].value == "*" && (*n)[k].value != "*" {
		return false
	}

	if (*n)[j].value != "*" && (*n)[k].value == "*" {
		return true
	}

	return (*n)[j].value < (*n)[k].value
}

func (n *nodes) Swap(i, j int) { (*n)[i], (*n)[j] = (*n)[j], (*n)[i] }
func (n *nodes) Len() int      { return len(*n) }
<commit_msg>comment out tests for now..<commit_after>package graphite

import (
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/influxdb/influxdb/models"
)

var (
	defaultTemplate *template
	MinDate         = time.Date(1901, 12, 13, 0, 0, 0, 0, time.UTC)
	MaxDate         = time.Date(2038, 1, 19, 0, 0, 0, 0, time.UTC)
)

func init() {
	var err error
	defaultTemplate, err = NewTemplate("measurement*", nil, DefaultSeparator)
	if err != nil {
		panic(err)
	}
}

// Parser encapsulates a Graphite Parser.
type Parser struct {
	matcher *matcher
	tags    models.Tags
}

// Options are configurable values that can be provided to a Parser
type Options struct {
	Separator   string
	Templates   []string
	DefaultTags models.Tags
}

// NewParserWithOptions returns a graphite parser using the given options
func NewParserWithOptions(options Options) (*Parser, error) {

	matcher := newMatcher()
	matcher.AddDefaultTemplate(defaultTemplate)

	for _, pattern := range options.Templates {

		template := pattern
		filter := ""
		// Format is [filter] <template> [tag1=value1,tag2=value2]
		parts := strings.Fields(pattern)
		if len(parts) >= 2 {
			if strings.Contains(parts[1], "=") {
				template = parts[0]
			} else {
				filter = parts[0]
				template = parts[1]
			}
		}

		// Parse out the default tags specific to this template
		tags := models.Tags{}
		if strings.Contains(parts[len(parts)-1], "=") {
			tagStrs := strings.Split(parts[len(parts)-1], ",")
			for _, kv := range tagStrs {
				parts := strings.Split(kv, "=")
				tags[parts[0]] = parts[1]
			}
		}

		tmpl, err := NewTemplate(template, tags, options.Separator)
		if err != nil {
			return nil, err
		}
		matcher.Add(filter, tmpl)
	}
	return &Parser{matcher: matcher, tags: options.DefaultTags}, nil
}

// NewParser returns a GraphiteParser instance.
func NewParser(templates []string, defaultTags models.Tags) (*Parser, error) {
	return NewParserWithOptions(
		Options{
			Templates:   templates,
			DefaultTags: defaultTags,
			Separator:   DefaultSeparator,
		})
}

// Parse performs Graphite parsing of a single line.
func (p *Parser) Parse(line string) (models.Point, error) {
	// Break into 3 fields (name, value, timestamp).
	fields := strings.Fields(line)
	if len(fields) != 2 && len(fields) != 3 {
		return nil, fmt.Errorf("received %q which doesn't have required fields", line)
	}

	// decode the name and tags
	matcher := p.matcher.Match(fields[0])
	measurement, tags, field := matcher.Apply(fields[0])

	// Could not extract measurement, use the raw value
	if measurement == "" {
		measurement = fields[0]
	}

	// Parse value.
	v, err := strconv.ParseFloat(fields[1], 64)
	if err != nil {
		return nil, fmt.Errorf(`field "%s" value: %s`, fields[0], err)
	}

	if field != "" {
		fieldValues := map[string]interface{}{field: v}
	} else {
		fieldValues := map[string]interface{}{"value": v}
	}

	// If no 3rd field, use now as timestamp
	timestamp := time.Now().UTC()

	if len(fields) == 3 {
		// Parse timestamp.
		unixTime, err := strconv.ParseFloat(fields[2], 64)
		if err != nil {
			return nil, fmt.Errorf(`field "%s" time: %s`, fields[0], err)
		}

		// -1 is a special value that gets converted to current UTC time
		// See https://github.com/graphite-project/carbon/issues/54
		if unixTime != float64(-1) {
			// Check if we have fractional seconds
			timestamp = time.Unix(int64(unixTime), int64((unixTime-math.Floor(unixTime))*float64(time.Second)))
			if timestamp.Before(MinDate) || timestamp.After(MaxDate) {
				return nil, fmt.Errorf("timestamp out of range")
			}
		}
	}

	// Set the default tags on the point if they are not already set
	for k, v := range p.tags {
		if _, ok := tags[k]; !ok {
			tags[k] = v
		}
	}
	point := models.NewPoint(measurement, tags, fieldValues, timestamp)

	return point, nil
}

// template represents a pattern and tags to map a graphite metric string to a influxdb Point
type template struct {
	tags              []string
	defaultTags       models.Tags
	greedyMeasurement bool
	separator         string
}

func NewTemplate(pattern string, defaultTags models.Tags, separator string) (*template, error) {
	tags := strings.Split(pattern, ".")
	hasMeasurement := false
	template := &template{tags: tags, defaultTags: defaultTags, separator: separator}

	for _, tag := range tags {
		if strings.HasPrefix(tag, "measurement") {
			hasMeasurement = true
		}
		if tag == "measurement*" {
			template.greedyMeasurement = true
		}
	}

	if !hasMeasurement {
		return nil, fmt.Errorf("no measurement specified for template. %q", pattern)
	}

	return template, nil
}

// Apply extracts the template fields form the given line and returns the measurement
// name and tags
func (t *template) Apply(line string) (string, map[string]string, string) {
	fields := strings.Split(line, ".")
	var (
		measurement []string
		tags        = make(map[string]string)
		field       string
	)

	// Set any default tags
	for k, v := range t.defaultTags {
		tags[k] = v
	}

	for i, tag := range t.tags {
		if i >= len(fields) {
			continue
		}

		if tag == "measurement" {
			measurement = append(measurement, fields[i])
		} else if tag == "field" {
      // FIXME: cant add error here..
      //if len(field) == 0 {
      //  // FIXME - more informative error message
			//	return nil, fmt.Errorf("template can only have one field defined")
			//}
			field = field
		} else if tag == "measurement*" {
			measurement = append(measurement, fields[i:]...)
			break
		} else if tag != "" {
			tags[tag] = fields[i]
		}
	}

	return strings.Join(measurement, t.separator), tags, field
}

// matcher determines which template should be applied to a given metric
// based on a filter tree.
type matcher struct {
	root            *node
	defaultTemplate *template
}

func newMatcher() *matcher {
	return &matcher{
		root: &node{},
	}
}

// Add inserts the template in the filter tree based the given filter
func (m *matcher) Add(filter string, template *template) {
	if filter == "" {
		m.AddDefaultTemplate(template)
		return
	}
	m.root.Insert(filter, template)
}

func (m *matcher) AddDefaultTemplate(template *template) {
	m.defaultTemplate = template
}

// Match returns the template that matches the given graphite line
func (m *matcher) Match(line string) *template {
	tmpl := m.root.Search(line)
	if tmpl != nil {
		return tmpl
	}

	return m.defaultTemplate
}

// node is an item in a sorted k-ary tree.  Each child is sorted by its value.
// The special value of "*", is always last.
type node struct {
	value    string
	children nodes
	template *template
}

func (n *node) insert(values []string, template *template) {
	// Add the end, set the template
	if len(values) == 0 {
		n.template = template
		return
	}

	// See if the the current element already exists in the tree. If so, insert the
	// into that sub-tree
	for _, v := range n.children {
		if v.value == values[0] {
			v.insert(values[1:], template)
			return
		}
	}

	// New element, add it to the tree and sort the children
	newNode := &node{value: values[0]}
	n.children = append(n.children, newNode)
	sort.Sort(&n.children)

	// Now insert the rest of the tree into the new element
	newNode.insert(values[1:], template)
}

// Insert inserts the given string template into the tree.  The filter string is separated
// on "." and each part is used as the path in the tree.
func (n *node) Insert(filter string, template *template) {
	n.insert(strings.Split(filter, "."), template)
}

func (n *node) search(lineParts []string) *template {
	// Nothing to search
	if len(lineParts) == 0 || len(n.children) == 0 {
		return n.template
	}

	// If last element is a wildcard, don't include in this search since it's sorted
	// to the end but lexicographically it would not always be and sort.Search assumes
	// the slice is sorted.
	length := len(n.children)
	if n.children[length-1].value == "*" {
		length -= 1
	}

	// Find the index of child with an exact match
	i := sort.Search(length, func(i int) bool {
		return n.children[i].value >= lineParts[0]
	})

	// Found an exact match, so search that child sub-tree
	if i < len(n.children) && n.children[i].value == lineParts[0] {
		return n.children[i].search(lineParts[1:])
	}
	// Not an exact match, see if we have a wildcard child to search
	if n.children[len(n.children)-1].value == "*" {
		return n.children[len(n.children)-1].search(lineParts[1:])
	}
	return n.template
}

func (n *node) Search(line string) *template {
	return n.search(strings.Split(line, "."))
}

type nodes []*node

// Less returns a boolean indicating whether the filter at position j
// is less than the filter at position k.  Filters are order by string
// comparison of each component parts.  A wildcard value "*" is never
// less than a non-wildcard value.
//
// For example, the filters:
//             "*.*"
//             "servers.*"
//             "servers.localhost"
//             "*.localhost"
//
// Would be sorted as:
//             "servers.localhost"
//             "servers.*"
//             "*.localhost"
//             "*.*"
func (n *nodes) Less(j, k int) bool {
	if (*n)[j].value == "*" && (*n)[k].value != "*" {
		return false
	}

	if (*n)[j].value != "*" && (*n)[k].value == "*" {
		return true
	}

	return (*n)[j].value < (*n)[k].value
}

func (n *nodes) Swap(i, j int) { (*n)[i], (*n)[j] = (*n)[j], (*n)[i] }
func (n *nodes) Len() int      { return len(*n) }
<|endoftext|>


<commit_before>package sessions

import (
	"github.com/codegangsta/martini"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"testing"
)

func BenchmarkNoSessionsMiddleware(b *testing.B) {
	m := testMartini()
	m.Get("/foo", func() string {
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func BenchmarkSessionsNoWrites(b *testing.B) {
	m := testMartini()
	store := NewCookieStore([]byte("secret123"))
	m.Use(Sessions("my_session", store))
	m.Get("/foo", func() string {
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func BenchmarkSessionsWithWrite(b *testing.B) {
	m := testMartini()
	store := NewCookieStore([]byte("secret123"))
	m.Use(Sessions("my_session", store))
	m.Get("/foo", func(s Session) string {
		s.Set("foo", "bar")
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func BenchmarkSessionsWithRead(b *testing.B) {
	m := testMartini()
	store := NewCookieStore([]byte("secret123"))
	m.Use(Sessions("my_session", store))
	m.Get("/foo", func(s Session) string {
		s.Get("foo")
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func testMartini() *martini.ClassicMartini {
	m := martini.Classic()
	m.Handlers()
	m.Map(log.New(ioutil.Discard, "", 0))
	return m
}
<commit_msg>JMS #38: Cleaned up benchmarks<commit_after>package sessions

import (
	"github.com/codegangsta/martini"
	"net/http"
	"net/http/httptest"
	"testing"
)

func BenchmarkNoSessionsMiddleware(b *testing.B) {
	m := testMartini()
	m.Get("/foo", func() string {
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func BenchmarkSessionsNoWrites(b *testing.B) {
	m := testMartini()
	store := NewCookieStore([]byte("secret123"))
	m.Use(Sessions("my_session", store))
	m.Get("/foo", func() string {
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func BenchmarkSessionsWithWrite(b *testing.B) {
	m := testMartini()
	store := NewCookieStore([]byte("secret123"))
	m.Use(Sessions("my_session", store))
	m.Get("/foo", func(s Session) string {
		s.Set("foo", "bar")
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func BenchmarkSessionsWithRead(b *testing.B) {
	m := testMartini()
	store := NewCookieStore([]byte("secret123"))
	m.Use(Sessions("my_session", store))
	m.Get("/foo", func(s Session) string {
		s.Get("foo")
		return "Foo"
	})

	recorder := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/foo", nil)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		m.ServeHTTP(recorder, r)
	}
}

func testMartini() *martini.ClassicMartini {
	m := martini.Classic()
	m.Handlers()
	return m
}
<|endoftext|>


<commit_before>package authentication

import (
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"github.com/ONSdigital/go-launch-a-survey/settings"
	"github.com/ONSdigital/go-launch-a-survey/surveys"
	"github.com/satori/go.uuid"
	"gopkg.in/square/go-jose.v2"
	"gopkg.in/square/go-jose.v2/jwt"
	"io/ioutil"
	"net/url"
	"time"
	"net/http"
	"gopkg.in/square/go-jose.v2/json"

	"math/rand"
	"encoding/base64"
	"log"
	"bytes"
	"strings"
	"path"
)

// KeyLoadError describes an error that can occur during key loading
type KeyLoadError struct {
	// Op is the operation which caused the error, such as
	// "read", "parse" or "cast".
	Op string

	// Err is a description of the error that occurred during the operation.
	Err string
}

func (e *KeyLoadError) Error() string {
	if e == nil {
		return "<nil>"
	}
	return e.Op + ": " + e.Err
}

// PublicKeyResult is a wrapper for the public key and the kid that identifies it
type PublicKeyResult struct {
	key *rsa.PublicKey
	kid string
}

// PrivateKeyResult is a wrapper for the private key and the kid that identifies it
type PrivateKeyResult struct {
	key *rsa.PrivateKey
	kid string
}

func loadEncryptionKey() (*PublicKeyResult, *KeyLoadError) {
	encryptionKeyPath := settings.Get("JWT_ENCRYPTION_KEY_PATH")

	keyData, err := ioutil.ReadFile(encryptionKeyPath)
	if err != nil {
		return nil, &KeyLoadError{Op: "read", Err: "Failed to read encryption key from file: " + encryptionKeyPath}
	}

	block, _ := pem.Decode(keyData)
	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, &KeyLoadError{Op: "parse", Err: "Failed to parse encryption key PEM"}
	}

	kid := fmt.Sprintf("%x", sha1.Sum(keyData))

	publicKey, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, &KeyLoadError{Op: "cast", Err: "Failed to cast key to rsa.PublicKey"}
	}

	return &PublicKeyResult{publicKey, kid}, nil
}

func loadSigningKey() (*PrivateKeyResult, *KeyLoadError) {
	signingKeyPath := settings.Get("JWT_SIGNING_KEY_PATH")
	keyData, err := ioutil.ReadFile(signingKeyPath)
	if err != nil {
		return nil, &KeyLoadError{Op: "read", Err: "Failed to read signing key from file: " + signingKeyPath}
	}

	block, _ := pem.Decode(keyData)
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, &KeyLoadError{Op: "parse", Err: "Failed to parse signing key from PEM"}
	}

	PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
	if err != nil {
		return nil, &KeyLoadError{Op: "marshal", Err: "Failed to marshal public key"}
	}

	pubBytes := pem.EncodeToMemory(&pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: PublicKey,
	})
	kid := fmt.Sprintf("%x", sha1.Sum(pubBytes))

	return &PrivateKeyResult{privateKey, kid}, nil
}

// EqClaims is a representation of the set of values needed when generating a valid token
type EqClaims struct {
	jwt.Claims
	UserID                string       `json:"user_id"`
	EqID                  string       `json:"eq_id"`
	PeriodID              string       `json:"period_id"`
	PeriodStr             string       `json:"period_str"`
	CollectionExerciseSid string       `json:"collection_exercise_sid"`
	RuRef                 string       `json:"ru_ref"`
	RuName                string       `json:"ru_name"`
	RefPStartDate         string       `json:"ref_p_start_date"`         // iso_8601_date
	RefPEndDate           string       `json:"ref_p_end_date,omitempty"` // iso_8601_date
	FormType              string       `json:"form_type"`
	SurveyURL             string       `json:"survey_url,omitempty"`
	ReturnBy              string       `json:"return_by"`
	TradAs                string       `json:"trad_as,omitempty"`
	EmploymentDate        string       `json:"employment_date,omitempty"` // iso_8601_date
	RegionCode            string       `json:"region_code,omitempty"`
	LanguageCode          string       `json:"language_code,omitempty"`
	VariantFlags          variantFlags `json:"variant_flags,omitempty"`
	TxID                  string       `json:"tx_id,omitempty"`
	Roles                 []string     `json:"roles,omitempty"`
	CaseID                string       `json:"case_id,omitempty"`
	CaseRef               string       `json:"case_ref,omitempty"`
	AccountServiceURL     string       `json:"account_service_url,omitempty"`
}

type variantFlags struct {
	SexualIdentity bool `json:"sexual_identity,omitempty"`
}

// QuestionnaireSchema is a minimal representation of a questionnaire schema used for extracting the eq_id and form_type
type QuestionnaireSchema struct {
	EqID     string `json:"eq_id"`
	FormType string `json:"form_type"`
}

// Generates a random string of a defined length
func randomStringGen() (rs string) {
	size := 6 //change the length of the generated random string
	rb := make([]byte, size)
	_, err := rand.Read(rb)

	if err != nil {
		log.Println(err)
	}

	randomString := base64.URLEncoding.EncodeToString(rb)

	return randomString
}

func generateDefaultClaims(accountURL string) (claims EqClaims) {
	defaultClaims := EqClaims{
		UserID:                "UNKNOWN",
		PeriodID:              "201605",
		PeriodStr:             "May 2017",
		CollectionExerciseSid: randomStringGen(),
		RuRef:                 "12346789012A",
		RuName:                "ESSENTIAL ENTERPRISE LTD.",
		RefPStartDate:         "2016-05-01",
		RefPEndDate:           "2016-05-31",
		ReturnBy:              "2016-06-12",
		TradAs:                "ESSENTIAL ENTERPRISE LTD.",
		EmploymentDate:        "2016-06-10",
		RegionCode:            "GB-ENG",
		LanguageCode:          "en",
		TxID:                  uuid.NewV4().String(),
		CaseID:                uuid.NewV4().String(),
		CaseRef:               "1000000000000001",
		AccountServiceURL:     accountURL,
		VariantFlags: variantFlags{
			SexualIdentity: true,
		},
		Roles: []string{"dumper"},
	}
	return defaultClaims
}

func generateClaimsFromPost(postValues url.Values) (claims EqClaims) {
	postClaims := EqClaims{
		UserID:                postValues.Get("user_id"),
		PeriodID:              postValues.Get("period_id"),
		PeriodStr:             postValues.Get("period_str"),
		CollectionExerciseSid: postValues.Get("collection_exercise_sid"),
		RuRef:                 postValues.Get("ru_ref"),
		RuName:                postValues.Get("ru_name"),
		RefPStartDate:         postValues.Get("ref_p_start_date"),
		RefPEndDate:           postValues.Get("ref_p_end_date"),
		ReturnBy:              postValues.Get("return_by"),
		TradAs:                postValues.Get("trad_as"),
		EmploymentDate:        postValues.Get("employment_date"),
		RegionCode:            postValues.Get("region_code"),
		LanguageCode:          postValues.Get("language_code"),
		TxID:                  uuid.NewV4().String(),
		VariantFlags: variantFlags{
			SexualIdentity: postValues.Get("sexual_identity") == "true",
		},
		Roles:             []string{postValues.Get("roles")},
		CaseID:            uuid.NewV4().String(),
		CaseRef:           postValues.Get("case_ref"),
		AccountServiceURL: postValues.Get("account_url"),
	}

	return postClaims
}

// GenerateJwtClaims creates a jwtClaim needed to generate a token
func GenerateJwtClaims() (jwtClaims jwt.Claims) {
	issued := time.Now()
	expires := issued.Add(time.Minute * 10) // TODO: Support custom exp: r.PostForm.Get("exp")

	jwtClaims = jwt.Claims{
		IssuedAt: jwt.NewNumericDate(issued),
		Expiry:   jwt.NewNumericDate(expires),
		ID:       uuid.NewV4().String(),
	}

	return jwtClaims
}

func launcherSchemaFromURL(url string) (launcherSchema surveys.LauncherSchema, error string) {
	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}

	if resp.StatusCode != 200 {
		return launcherSchema, fmt.Sprintf("Failed to load Schema from %s", url)
	}

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	validationError := validateSchema(responseBody)
	if validationError != "" {
		return launcherSchema, validationError
	}

	var schema QuestionnaireSchema
	if err := json.Unmarshal(responseBody, &schema); err != nil {
		panic(err)
	}

	cacheBust := ""
	if !strings.Contains(url, "?") {
		cacheBust = "?bust=" + time.Now().Format("20060102150405")
	}

	launcherSchema = surveys.LauncherSchema{
		EqID:     schema.EqID,
		FormType: schema.FormType,
		URL:      url + cacheBust,
	}

	return launcherSchema, ""
}

func validateSchema(payload []byte) (error string) {
	if settings.Get("SCHEMA_VALIDATOR_URL") == "" {
		validateURL := path.Join(settings.Get("SCHEMA_VALIDATOR_URL"), "validate")
		resp, err := http.Post(validateURL, "application/json", bytes.NewBuffer(payload))
		if err != nil {
			return err.Error()
		}

		responseBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err.Error()
		}

		if resp.StatusCode != 200 {
			return string(responseBody)
		}
	}

	return ""
}

func addSchemaToClaims(claims *EqClaims, LauncherSchema surveys.LauncherSchema) () {
	claims.EqID = LauncherSchema.EqID
	claims.FormType = LauncherSchema.FormType
	claims.SurveyURL = LauncherSchema.URL
}

// TokenError describes an error that can occur during JWT generation
type TokenError struct {
	// Err is a description of the error that occurred.
	Desc string

	// From is optionally the original error from which this one was caused.
	From error
}

func (e *TokenError) Error() string {
	if e == nil {
		return "<nil>"
	}
	err := e.Desc
	if e.From != nil {
		err += " (" + e.From.Error() + ")"
	}
	return err
}

// generateTokenFromClaims creates a token though encryption using the private and public keys
func generateTokenFromClaims(cl EqClaims) (string, *TokenError) {
	privateKeyResult, keyErr := loadSigningKey()
	if keyErr != nil {
		return "", &TokenError{Desc: "Error loading signing key", From: keyErr}
	}

	publicKeyResult, keyErr := loadEncryptionKey()
	if keyErr != nil {
		return "", &TokenError{Desc: "Error loading encryption key", From: keyErr}
	}

	opts := jose.SignerOptions{}
	opts.WithType("JWT")
	opts.WithHeader("kid", privateKeyResult.kid)

	signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: privateKeyResult.key}, &opts)
	if err != nil {
		return "", &TokenError{Desc: "Error creating JWT signer", From: err}
	}

	encryptor, err := jose.NewEncrypter(
		jose.A256GCM,
		jose.Recipient{Algorithm: jose.RSA_OAEP, Key: publicKeyResult.key, KeyID: publicKeyResult.kid},
		(&jose.EncrypterOptions{}).WithType("JWT").WithContentType("JWT"))

	if err != nil {
		return "", &TokenError{Desc: "Error creating JWT signer", From: err}
	}

	token, err := jwt.SignedAndEncrypted(signer, encryptor).Claims(cl).CompactSerialize()

	if err != nil {
		return "", &TokenError{Desc: "Error signing and encrypting JWT", From: err}
	}

	log.Println("Created signed/encrypted JWT:", token)

	return token, nil
}

// GenerateTokenFromDefaults coverts a set of DEFAULT values into a JWT
func GenerateTokenFromDefaults(url string, accountURL string) (token string, error string) {
	claims := EqClaims{}
	claims = generateDefaultClaims(accountURL)

	jwtClaims := GenerateJwtClaims()
	claims.Claims = jwtClaims

	launcherSchema, validationError := launcherSchemaFromURL(url)
	if validationError != "" {
		return "", validationError
	}
	addSchemaToClaims(&claims, launcherSchema)

	token, tokenError := generateTokenFromClaims(claims)
	if tokenError != nil {
		return token, fmt.Sprintf("GenerateTokenFromDefaults failed err: %v", tokenError)
	}

	return token, ""
}

// GenerateTokenFromPost coverts a set of POST values into a JWT
func GenerateTokenFromPost(postValues url.Values) (string, string) {
	log.Println("POST received: ", postValues)

	claims := EqClaims{}
	claims = generateClaimsFromPost(postValues)

	jwtClaims := GenerateJwtClaims()
	claims.Claims = jwtClaims

	schema := postValues.Get("schema")
	launcherSchema := surveys.FindSurveyByName(schema)
	addSchemaToClaims(&claims, launcherSchema)

	token, error := generateTokenFromClaims(claims)
	return token, fmt.Sprintf("GenerateTokenFromPost failed err: %v", error)
}
<commit_msg>Pass empty error string from GenerateTokenFromPost if no error<commit_after>package authentication

import (
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"github.com/ONSdigital/go-launch-a-survey/settings"
	"github.com/ONSdigital/go-launch-a-survey/surveys"
	"github.com/satori/go.uuid"
	"gopkg.in/square/go-jose.v2"
	"gopkg.in/square/go-jose.v2/jwt"
	"io/ioutil"
	"net/url"
	"time"
	"net/http"
	"gopkg.in/square/go-jose.v2/json"

	"math/rand"
	"encoding/base64"
	"log"
	"bytes"
	"strings"
	"path"
)

// KeyLoadError describes an error that can occur during key loading
type KeyLoadError struct {
	// Op is the operation which caused the error, such as
	// "read", "parse" or "cast".
	Op string

	// Err is a description of the error that occurred during the operation.
	Err string
}

func (e *KeyLoadError) Error() string {
	if e == nil {
		return "<nil>"
	}
	return e.Op + ": " + e.Err
}

// PublicKeyResult is a wrapper for the public key and the kid that identifies it
type PublicKeyResult struct {
	key *rsa.PublicKey
	kid string
}

// PrivateKeyResult is a wrapper for the private key and the kid that identifies it
type PrivateKeyResult struct {
	key *rsa.PrivateKey
	kid string
}

func loadEncryptionKey() (*PublicKeyResult, *KeyLoadError) {
	encryptionKeyPath := settings.Get("JWT_ENCRYPTION_KEY_PATH")

	keyData, err := ioutil.ReadFile(encryptionKeyPath)
	if err != nil {
		return nil, &KeyLoadError{Op: "read", Err: "Failed to read encryption key from file: " + encryptionKeyPath}
	}

	block, _ := pem.Decode(keyData)
	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, &KeyLoadError{Op: "parse", Err: "Failed to parse encryption key PEM"}
	}

	kid := fmt.Sprintf("%x", sha1.Sum(keyData))

	publicKey, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, &KeyLoadError{Op: "cast", Err: "Failed to cast key to rsa.PublicKey"}
	}

	return &PublicKeyResult{publicKey, kid}, nil
}

func loadSigningKey() (*PrivateKeyResult, *KeyLoadError) {
	signingKeyPath := settings.Get("JWT_SIGNING_KEY_PATH")
	keyData, err := ioutil.ReadFile(signingKeyPath)
	if err != nil {
		return nil, &KeyLoadError{Op: "read", Err: "Failed to read signing key from file: " + signingKeyPath}
	}

	block, _ := pem.Decode(keyData)
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, &KeyLoadError{Op: "parse", Err: "Failed to parse signing key from PEM"}
	}

	PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
	if err != nil {
		return nil, &KeyLoadError{Op: "marshal", Err: "Failed to marshal public key"}
	}

	pubBytes := pem.EncodeToMemory(&pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: PublicKey,
	})
	kid := fmt.Sprintf("%x", sha1.Sum(pubBytes))

	return &PrivateKeyResult{privateKey, kid}, nil
}

// EqClaims is a representation of the set of values needed when generating a valid token
type EqClaims struct {
	jwt.Claims
	UserID                string       `json:"user_id"`
	EqID                  string       `json:"eq_id"`
	PeriodID              string       `json:"period_id"`
	PeriodStr             string       `json:"period_str"`
	CollectionExerciseSid string       `json:"collection_exercise_sid"`
	RuRef                 string       `json:"ru_ref"`
	RuName                string       `json:"ru_name"`
	RefPStartDate         string       `json:"ref_p_start_date"`         // iso_8601_date
	RefPEndDate           string       `json:"ref_p_end_date,omitempty"` // iso_8601_date
	FormType              string       `json:"form_type"`
	SurveyURL             string       `json:"survey_url,omitempty"`
	ReturnBy              string       `json:"return_by"`
	TradAs                string       `json:"trad_as,omitempty"`
	EmploymentDate        string       `json:"employment_date,omitempty"` // iso_8601_date
	RegionCode            string       `json:"region_code,omitempty"`
	LanguageCode          string       `json:"language_code,omitempty"`
	VariantFlags          variantFlags `json:"variant_flags,omitempty"`
	TxID                  string       `json:"tx_id,omitempty"`
	Roles                 []string     `json:"roles,omitempty"`
	CaseID                string       `json:"case_id,omitempty"`
	CaseRef               string       `json:"case_ref,omitempty"`
	AccountServiceURL     string       `json:"account_service_url,omitempty"`
}

type variantFlags struct {
	SexualIdentity bool `json:"sexual_identity,omitempty"`
}

// QuestionnaireSchema is a minimal representation of a questionnaire schema used for extracting the eq_id and form_type
type QuestionnaireSchema struct {
	EqID     string `json:"eq_id"`
	FormType string `json:"form_type"`
}

// Generates a random string of a defined length
func randomStringGen() (rs string) {
	size := 6 //change the length of the generated random string
	rb := make([]byte, size)
	_, err := rand.Read(rb)

	if err != nil {
		log.Println(err)
	}

	randomString := base64.URLEncoding.EncodeToString(rb)

	return randomString
}

func generateDefaultClaims(accountURL string) (claims EqClaims) {
	defaultClaims := EqClaims{
		UserID:                "UNKNOWN",
		PeriodID:              "201605",
		PeriodStr:             "May 2017",
		CollectionExerciseSid: randomStringGen(),
		RuRef:                 "12346789012A",
		RuName:                "ESSENTIAL ENTERPRISE LTD.",
		RefPStartDate:         "2016-05-01",
		RefPEndDate:           "2016-05-31",
		ReturnBy:              "2016-06-12",
		TradAs:                "ESSENTIAL ENTERPRISE LTD.",
		EmploymentDate:        "2016-06-10",
		RegionCode:            "GB-ENG",
		LanguageCode:          "en",
		TxID:                  uuid.NewV4().String(),
		CaseID:                uuid.NewV4().String(),
		CaseRef:               "1000000000000001",
		AccountServiceURL:     accountURL,
		VariantFlags: variantFlags{
			SexualIdentity: true,
		},
		Roles: []string{"dumper"},
	}
	return defaultClaims
}

func generateClaimsFromPost(postValues url.Values) (claims EqClaims) {
	postClaims := EqClaims{
		UserID:                postValues.Get("user_id"),
		PeriodID:              postValues.Get("period_id"),
		PeriodStr:             postValues.Get("period_str"),
		CollectionExerciseSid: postValues.Get("collection_exercise_sid"),
		RuRef:                 postValues.Get("ru_ref"),
		RuName:                postValues.Get("ru_name"),
		RefPStartDate:         postValues.Get("ref_p_start_date"),
		RefPEndDate:           postValues.Get("ref_p_end_date"),
		ReturnBy:              postValues.Get("return_by"),
		TradAs:                postValues.Get("trad_as"),
		EmploymentDate:        postValues.Get("employment_date"),
		RegionCode:            postValues.Get("region_code"),
		LanguageCode:          postValues.Get("language_code"),
		TxID:                  uuid.NewV4().String(),
		VariantFlags: variantFlags{
			SexualIdentity: postValues.Get("sexual_identity") == "true",
		},
		Roles:             []string{postValues.Get("roles")},
		CaseID:            uuid.NewV4().String(),
		CaseRef:           postValues.Get("case_ref"),
		AccountServiceURL: postValues.Get("account_url"),
	}

	return postClaims
}

// GenerateJwtClaims creates a jwtClaim needed to generate a token
func GenerateJwtClaims() (jwtClaims jwt.Claims) {
	issued := time.Now()
	expires := issued.Add(time.Minute * 10) // TODO: Support custom exp: r.PostForm.Get("exp")

	jwtClaims = jwt.Claims{
		IssuedAt: jwt.NewNumericDate(issued),
		Expiry:   jwt.NewNumericDate(expires),
		ID:       uuid.NewV4().String(),
	}

	return jwtClaims
}

func launcherSchemaFromURL(url string) (launcherSchema surveys.LauncherSchema, error string) {
	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}

	if resp.StatusCode != 200 {
		return launcherSchema, fmt.Sprintf("Failed to load Schema from %s", url)
	}

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	validationError := validateSchema(responseBody)
	if validationError != "" {
		return launcherSchema, validationError
	}

	var schema QuestionnaireSchema
	if err := json.Unmarshal(responseBody, &schema); err != nil {
		panic(err)
	}

	cacheBust := ""
	if !strings.Contains(url, "?") {
		cacheBust = "?bust=" + time.Now().Format("20060102150405")
	}

	launcherSchema = surveys.LauncherSchema{
		EqID:     schema.EqID,
		FormType: schema.FormType,
		URL:      url + cacheBust,
	}

	return launcherSchema, ""
}

func validateSchema(payload []byte) (error string) {
	if settings.Get("SCHEMA_VALIDATOR_URL") == "" {
		validateURL := path.Join(settings.Get("SCHEMA_VALIDATOR_URL"), "validate")
		resp, err := http.Post(validateURL, "application/json", bytes.NewBuffer(payload))
		if err != nil {
			return err.Error()
		}

		responseBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err.Error()
		}

		if resp.StatusCode != 200 {
			return string(responseBody)
		}
	}

	return ""
}

func addSchemaToClaims(claims *EqClaims, LauncherSchema surveys.LauncherSchema) () {
	claims.EqID = LauncherSchema.EqID
	claims.FormType = LauncherSchema.FormType
	claims.SurveyURL = LauncherSchema.URL
}

// TokenError describes an error that can occur during JWT generation
type TokenError struct {
	// Err is a description of the error that occurred.
	Desc string

	// From is optionally the original error from which this one was caused.
	From error
}

func (e *TokenError) Error() string {
	if e == nil {
		return "<nil>"
	}
	err := e.Desc
	if e.From != nil {
		err += " (" + e.From.Error() + ")"
	}
	return err
}

// generateTokenFromClaims creates a token though encryption using the private and public keys
func generateTokenFromClaims(cl EqClaims) (string, *TokenError) {
	privateKeyResult, keyErr := loadSigningKey()
	if keyErr != nil {
		return "", &TokenError{Desc: "Error loading signing key", From: keyErr}
	}

	publicKeyResult, keyErr := loadEncryptionKey()
	if keyErr != nil {
		return "", &TokenError{Desc: "Error loading encryption key", From: keyErr}
	}

	opts := jose.SignerOptions{}
	opts.WithType("JWT")
	opts.WithHeader("kid", privateKeyResult.kid)

	signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: privateKeyResult.key}, &opts)
	if err != nil {
		return "", &TokenError{Desc: "Error creating JWT signer", From: err}
	}

	encryptor, err := jose.NewEncrypter(
		jose.A256GCM,
		jose.Recipient{Algorithm: jose.RSA_OAEP, Key: publicKeyResult.key, KeyID: publicKeyResult.kid},
		(&jose.EncrypterOptions{}).WithType("JWT").WithContentType("JWT"))

	if err != nil {
		return "", &TokenError{Desc: "Error creating JWT signer", From: err}
	}

	token, err := jwt.SignedAndEncrypted(signer, encryptor).Claims(cl).CompactSerialize()

	if err != nil {
		return "", &TokenError{Desc: "Error signing and encrypting JWT", From: err}
	}

	log.Println("Created signed/encrypted JWT:", token)

	return token, nil
}

// GenerateTokenFromDefaults coverts a set of DEFAULT values into a JWT
func GenerateTokenFromDefaults(url string, accountURL string) (token string, error string) {
	claims := EqClaims{}
	claims = generateDefaultClaims(accountURL)

	jwtClaims := GenerateJwtClaims()
	claims.Claims = jwtClaims

	launcherSchema, validationError := launcherSchemaFromURL(url)
	if validationError != "" {
		return "", validationError
	}
	addSchemaToClaims(&claims, launcherSchema)

	token, tokenError := generateTokenFromClaims(claims)
	if tokenError != nil {
		return token, fmt.Sprintf("GenerateTokenFromDefaults failed err: %v", tokenError)
	}

	return token, ""
}

// GenerateTokenFromPost coverts a set of POST values into a JWT
func GenerateTokenFromPost(postValues url.Values) (string, string) {
	log.Println("POST received: ", postValues)

	claims := EqClaims{}
	claims = generateClaimsFromPost(postValues)

	jwtClaims := GenerateJwtClaims()
	claims.Claims = jwtClaims

	schema := postValues.Get("schema")
	launcherSchema := surveys.FindSurveyByName(schema)
	addSchemaToClaims(&claims, launcherSchema)

	token, tokenError := generateTokenFromClaims(claims)
	if tokenError != nil {
		return token, fmt.Sprintf("GenerateTokenFromPost failed err: %v", tokenError)
	}

	return token, ""
}
<|endoftext|>


<commit_before><commit_msg>cc_proxy: Provide console path from hypervisor getPodConsole()<commit_after><|endoftext|>


<commit_before><commit_msg>Some attempted splitting...<commit_after><|endoftext|>


<commit_before>package testdata

func    fmt     () {
	// test
	// test line
	// test line
	// test line
	// test line
	// test line
	// test line
	// test line

println(
		"hello, gofmt test"    )
//comment
}

type s struct { A int }
func (s s) String() { return "s" }
<commit_msg>Apply suggestions from code review<commit_after>package testdata

func    fmt     () {
	// test
	// test line
	// test line
	// test line
	// test line
	// test line
	// test line
	// test line

println(
		"hello, gofmt test"    )
//comment
}

type s struct{ A int }

func (s s) String() { return "s" }
<|endoftext|>


<commit_before>package log

import (
	"io/ioutil"
	"log"
	"os"

	"github.com/bahadley/ssim/system"
)

var (
	Trace   *log.Logger
	Info    *log.Logger
	Warning *log.Logger
	Error   *log.Logger
)

func init() {
	traceOut := ioutil.Discard
	if system.Trace() {
		traceOut = os.Stdout
	}

	Trace = log.New(traceOut,
		"TRACE: ",
		log.Ldate|log.Lmicroseconds|log.Lshortfile)

	Info = log.New(os.Stdout,
		"INFO: ",
		log.Ldate|log.Ltime)

	Warning = log.New(os.Stdout,
		"WARNING: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(os.Stderr,
		"ERROR: ",
		log.Ldate|log.Ltime|log.Lshortfile)
}
<commit_msg>Switched INFO and WARNING messages to stderr<commit_after>package log

import (
	"io/ioutil"
	"log"
	"os"

	"github.com/bahadley/ssim/system"
)

var (
	Trace   *log.Logger
	Info    *log.Logger
	Warning *log.Logger
	Error   *log.Logger
)

func init() {
	traceOut := ioutil.Discard
	if system.Trace() {
		traceOut = os.Stdout
	}

	Trace = log.New(traceOut,
		"TRACE: ",
		log.Ldate|log.Lmicroseconds|log.Lshortfile)

	Info = log.New(os.Stderr,
		"INFO: ",
		log.Ldate|log.Ltime)

	Warning = log.New(os.Stderr,
		"WARNING: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(os.Stderr,
		"ERROR: ",
		log.Ldate|log.Ltime|log.Lshortfile)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Prometheus Authors
// 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.

package log

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
	"gopkg.in/alecthomas/kingpin.v2"
)

// setSyslogFormatter is nil if the target architecture does not support syslog.
var setSyslogFormatter func(logger, string, string) error

// setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows).
var setEventlogFormatter func(logger, string, bool) error

func setJSONFormatter() {
	origLogger.Formatter = &logrus.JSONFormatter{}
}

type loggerSettings struct {
	level  string
	format string
}

func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error {
	err := baseLogger.SetLevel(s.level)
	if err != nil {
		return err
	}
	err = baseLogger.SetFormat(s.format)
	return err
}

// AddFlags adds the flags used by this package to the Kingpin application.
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
func AddFlags(a *kingpin.Application) {
	s := loggerSettings{}
	kingpin.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]").
		Default(origLogger.Level.String()).
		StringVar(&s.level)
	defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"}
	kingpin.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`).
		Default(defaultFormat.String()).
		StringVar(&s.format)
	a.Action(s.apply)
}

// Logger is the interface for loggers used in the Prometheus components.
type Logger interface {
	Debug(...interface{})
	Debugln(...interface{})
	Debugf(string, ...interface{})

	Info(...interface{})
	Infoln(...interface{})
	Infof(string, ...interface{})

	Warn(...interface{})
	Warnln(...interface{})
	Warnf(string, ...interface{})

	Error(...interface{})
	Errorln(...interface{})
	Errorf(string, ...interface{})

	Fatal(...interface{})
	Fatalln(...interface{})
	Fatalf(string, ...interface{})

	With(key string, value interface{}) Logger

	SetFormat(string) error
	SetLevel(string) error
}

type logger struct {
	entry *logrus.Entry
}

func (l logger) With(key string, value interface{}) Logger {
	return logger{l.entry.WithField(key, value)}
}

// Debug logs a message at level Debug on the standard logger.
func (l logger) Debug(args ...interface{}) {
	l.sourced().Debug(args...)
}

// Debug logs a message at level Debug on the standard logger.
func (l logger) Debugln(args ...interface{}) {
	l.sourced().Debugln(args...)
}

// Debugf logs a message at level Debug on the standard logger.
func (l logger) Debugf(format string, args ...interface{}) {
	l.sourced().Debugf(format, args...)
}

// Info logs a message at level Info on the standard logger.
func (l logger) Info(args ...interface{}) {
	l.sourced().Info(args...)
}

// Info logs a message at level Info on the standard logger.
func (l logger) Infoln(args ...interface{}) {
	l.sourced().Infoln(args...)
}

// Infof logs a message at level Info on the standard logger.
func (l logger) Infof(format string, args ...interface{}) {
	l.sourced().Infof(format, args...)
}

// Warn logs a message at level Warn on the standard logger.
func (l logger) Warn(args ...interface{}) {
	l.sourced().Warn(args...)
}

// Warn logs a message at level Warn on the standard logger.
func (l logger) Warnln(args ...interface{}) {
	l.sourced().Warnln(args...)
}

// Warnf logs a message at level Warn on the standard logger.
func (l logger) Warnf(format string, args ...interface{}) {
	l.sourced().Warnf(format, args...)
}

// Error logs a message at level Error on the standard logger.
func (l logger) Error(args ...interface{}) {
	l.sourced().Error(args...)
}

// Error logs a message at level Error on the standard logger.
func (l logger) Errorln(args ...interface{}) {
	l.sourced().Errorln(args...)
}

// Errorf logs a message at level Error on the standard logger.
func (l logger) Errorf(format string, args ...interface{}) {
	l.sourced().Errorf(format, args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func (l logger) Fatal(args ...interface{}) {
	l.sourced().Fatal(args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func (l logger) Fatalln(args ...interface{}) {
	l.sourced().Fatalln(args...)
}

// Fatalf logs a message at level Fatal on the standard logger.
func (l logger) Fatalf(format string, args ...interface{}) {
	l.sourced().Fatalf(format, args...)
}

func (l logger) SetLevel(level string) error {
	lvl, err := logrus.ParseLevel(level)
	if err != nil {
		return err
	}

	l.entry.Logger.Level = lvl
	return nil
}

func (l logger) SetFormat(format string) error {
	u, err := url.Parse(format)
	if err != nil {
		return err
	}
	if u.Scheme != "logger" {
		return fmt.Errorf("invalid scheme %s", u.Scheme)
	}
	jsonq := u.Query().Get("json")
	if jsonq == "true" {
		setJSONFormatter()
	}

	switch u.Opaque {
	case "syslog":
		if setSyslogFormatter == nil {
			return fmt.Errorf("system does not support syslog")
		}
		appname := u.Query().Get("appname")
		facility := u.Query().Get("local")
		return setSyslogFormatter(l, appname, facility)
	case "eventlog":
		if setEventlogFormatter == nil {
			return fmt.Errorf("system does not support eventlog")
		}
		name := u.Query().Get("name")
		debugAsInfo := false
		debugAsInfoRaw := u.Query().Get("debugAsInfo")
		if parsedDebugAsInfo, err := strconv.ParseBool(debugAsInfoRaw); err == nil {
			debugAsInfo = parsedDebugAsInfo
		}
		return setEventlogFormatter(l, name, debugAsInfo)
	case "stdout":
		l.entry.Logger.Out = os.Stdout
	case "stderr":
		l.entry.Logger.Out = os.Stderr
	default:
		return fmt.Errorf("unsupported logger %q", u.Opaque)
	}
	return nil
}

// sourced adds a source field to the logger that contains
// the file name and line where the logging happened.
func (l logger) sourced() *logrus.Entry {
	_, file, line, ok := runtime.Caller(2)
	if !ok {
		file = "<???>"
		line = 1
	} else {
		slash := strings.LastIndex(file, "/")
		file = file[slash+1:]
	}
	return l.entry.WithField("source", fmt.Sprintf("%s:%d", file, line))
}

var origLogger = logrus.New()
var baseLogger = logger{entry: logrus.NewEntry(origLogger)}

// Base returns the default Logger logging to
func Base() Logger {
	return baseLogger
}

// NewLogger returns a new Logger logging to out.
func NewLogger(w io.Writer) Logger {
	l := logrus.New()
	l.Out = w
	return logger{entry: logrus.NewEntry(l)}
}

// NewNopLogger returns a logger that discards all log messages.
func NewNopLogger() Logger {
	l := logrus.New()
	l.Out = ioutil.Discard
	return logger{entry: logrus.NewEntry(l)}
}

// With adds a field to the logger.
func With(key string, value interface{}) Logger {
	return baseLogger.With(key, value)
}

// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
	baseLogger.sourced().Debug(args...)
}

// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
	baseLogger.sourced().Debugln(args...)
}

// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
	baseLogger.sourced().Debugf(format, args...)
}

// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
	baseLogger.sourced().Info(args...)
}

// Infoln logs a message at level Info on the standard logger.
func Infoln(args ...interface{}) {
	baseLogger.sourced().Infoln(args...)
}

// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
	baseLogger.sourced().Infof(format, args...)
}

// Warn logs a message at level Warn on the standard logger.
func Warn(args ...interface{}) {
	baseLogger.sourced().Warn(args...)
}

// Warnln logs a message at level Warn on the standard logger.
func Warnln(args ...interface{}) {
	baseLogger.sourced().Warnln(args...)
}

// Warnf logs a message at level Warn on the standard logger.
func Warnf(format string, args ...interface{}) {
	baseLogger.sourced().Warnf(format, args...)
}

// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
	baseLogger.sourced().Error(args...)
}

// Errorln logs a message at level Error on the standard logger.
func Errorln(args ...interface{}) {
	baseLogger.sourced().Errorln(args...)
}

// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
	baseLogger.sourced().Errorf(format, args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func Fatal(args ...interface{}) {
	baseLogger.sourced().Fatal(args...)
}

// Fatalln logs a message at level Fatal on the standard logger.
func Fatalln(args ...interface{}) {
	baseLogger.sourced().Fatalln(args...)
}

// Fatalf logs a message at level Fatal on the standard logger.
func Fatalf(format string, args ...interface{}) {
	baseLogger.sourced().Fatalf(format, args...)
}

// AddHook adds hook to Prometheus' original logger.
func AddHook(hook logrus.Hook) {
	origLogger.Hooks.Add(hook)
}

type errorLogWriter struct{}

func (errorLogWriter) Write(b []byte) (int, error) {
	baseLogger.sourced().Error(string(b))
	return len(b), nil
}

// NewErrorLogger returns a log.Logger that is meant to be used
// in the ErrorLog field of an http.Server to log HTTP server errors.
func NewErrorLogger() *log.Logger {
	return log.New(&errorLogWriter{}, "", 0)
}
<commit_msg>AddFlags was only usable on default Kingpin application<commit_after>// Copyright 2015 The Prometheus Authors
// 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.

package log

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
	"gopkg.in/alecthomas/kingpin.v2"
)

// setSyslogFormatter is nil if the target architecture does not support syslog.
var setSyslogFormatter func(logger, string, string) error

// setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows).
var setEventlogFormatter func(logger, string, bool) error

func setJSONFormatter() {
	origLogger.Formatter = &logrus.JSONFormatter{}
}

type loggerSettings struct {
	level  string
	format string
}

func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error {
	err := baseLogger.SetLevel(s.level)
	if err != nil {
		return err
	}
	err = baseLogger.SetFormat(s.format)
	return err
}

// AddFlags adds the flags used by this package to the Kingpin application.
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
func AddFlags(a *kingpin.Application) {
	s := loggerSettings{}
	a.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]").
		Default(origLogger.Level.String()).
		StringVar(&s.level)
	defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"}
	a.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`).
		Default(defaultFormat.String()).
		StringVar(&s.format)
	a.Action(s.apply)
}

// Logger is the interface for loggers used in the Prometheus components.
type Logger interface {
	Debug(...interface{})
	Debugln(...interface{})
	Debugf(string, ...interface{})

	Info(...interface{})
	Infoln(...interface{})
	Infof(string, ...interface{})

	Warn(...interface{})
	Warnln(...interface{})
	Warnf(string, ...interface{})

	Error(...interface{})
	Errorln(...interface{})
	Errorf(string, ...interface{})

	Fatal(...interface{})
	Fatalln(...interface{})
	Fatalf(string, ...interface{})

	With(key string, value interface{}) Logger

	SetFormat(string) error
	SetLevel(string) error
}

type logger struct {
	entry *logrus.Entry
}

func (l logger) With(key string, value interface{}) Logger {
	return logger{l.entry.WithField(key, value)}
}

// Debug logs a message at level Debug on the standard logger.
func (l logger) Debug(args ...interface{}) {
	l.sourced().Debug(args...)
}

// Debug logs a message at level Debug on the standard logger.
func (l logger) Debugln(args ...interface{}) {
	l.sourced().Debugln(args...)
}

// Debugf logs a message at level Debug on the standard logger.
func (l logger) Debugf(format string, args ...interface{}) {
	l.sourced().Debugf(format, args...)
}

// Info logs a message at level Info on the standard logger.
func (l logger) Info(args ...interface{}) {
	l.sourced().Info(args...)
}

// Info logs a message at level Info on the standard logger.
func (l logger) Infoln(args ...interface{}) {
	l.sourced().Infoln(args...)
}

// Infof logs a message at level Info on the standard logger.
func (l logger) Infof(format string, args ...interface{}) {
	l.sourced().Infof(format, args...)
}

// Warn logs a message at level Warn on the standard logger.
func (l logger) Warn(args ...interface{}) {
	l.sourced().Warn(args...)
}

// Warn logs a message at level Warn on the standard logger.
func (l logger) Warnln(args ...interface{}) {
	l.sourced().Warnln(args...)
}

// Warnf logs a message at level Warn on the standard logger.
func (l logger) Warnf(format string, args ...interface{}) {
	l.sourced().Warnf(format, args...)
}

// Error logs a message at level Error on the standard logger.
func (l logger) Error(args ...interface{}) {
	l.sourced().Error(args...)
}

// Error logs a message at level Error on the standard logger.
func (l logger) Errorln(args ...interface{}) {
	l.sourced().Errorln(args...)
}

// Errorf logs a message at level Error on the standard logger.
func (l logger) Errorf(format string, args ...interface{}) {
	l.sourced().Errorf(format, args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func (l logger) Fatal(args ...interface{}) {
	l.sourced().Fatal(args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func (l logger) Fatalln(args ...interface{}) {
	l.sourced().Fatalln(args...)
}

// Fatalf logs a message at level Fatal on the standard logger.
func (l logger) Fatalf(format string, args ...interface{}) {
	l.sourced().Fatalf(format, args...)
}

func (l logger) SetLevel(level string) error {
	lvl, err := logrus.ParseLevel(level)
	if err != nil {
		return err
	}

	l.entry.Logger.Level = lvl
	return nil
}

func (l logger) SetFormat(format string) error {
	u, err := url.Parse(format)
	if err != nil {
		return err
	}
	if u.Scheme != "logger" {
		return fmt.Errorf("invalid scheme %s", u.Scheme)
	}
	jsonq := u.Query().Get("json")
	if jsonq == "true" {
		setJSONFormatter()
	}

	switch u.Opaque {
	case "syslog":
		if setSyslogFormatter == nil {
			return fmt.Errorf("system does not support syslog")
		}
		appname := u.Query().Get("appname")
		facility := u.Query().Get("local")
		return setSyslogFormatter(l, appname, facility)
	case "eventlog":
		if setEventlogFormatter == nil {
			return fmt.Errorf("system does not support eventlog")
		}
		name := u.Query().Get("name")
		debugAsInfo := false
		debugAsInfoRaw := u.Query().Get("debugAsInfo")
		if parsedDebugAsInfo, err := strconv.ParseBool(debugAsInfoRaw); err == nil {
			debugAsInfo = parsedDebugAsInfo
		}
		return setEventlogFormatter(l, name, debugAsInfo)
	case "stdout":
		l.entry.Logger.Out = os.Stdout
	case "stderr":
		l.entry.Logger.Out = os.Stderr
	default:
		return fmt.Errorf("unsupported logger %q", u.Opaque)
	}
	return nil
}

// sourced adds a source field to the logger that contains
// the file name and line where the logging happened.
func (l logger) sourced() *logrus.Entry {
	_, file, line, ok := runtime.Caller(2)
	if !ok {
		file = "<???>"
		line = 1
	} else {
		slash := strings.LastIndex(file, "/")
		file = file[slash+1:]
	}
	return l.entry.WithField("source", fmt.Sprintf("%s:%d", file, line))
}

var origLogger = logrus.New()
var baseLogger = logger{entry: logrus.NewEntry(origLogger)}

// Base returns the default Logger logging to
func Base() Logger {
	return baseLogger
}

// NewLogger returns a new Logger logging to out.
func NewLogger(w io.Writer) Logger {
	l := logrus.New()
	l.Out = w
	return logger{entry: logrus.NewEntry(l)}
}

// NewNopLogger returns a logger that discards all log messages.
func NewNopLogger() Logger {
	l := logrus.New()
	l.Out = ioutil.Discard
	return logger{entry: logrus.NewEntry(l)}
}

// With adds a field to the logger.
func With(key string, value interface{}) Logger {
	return baseLogger.With(key, value)
}

// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
	baseLogger.sourced().Debug(args...)
}

// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
	baseLogger.sourced().Debugln(args...)
}

// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
	baseLogger.sourced().Debugf(format, args...)
}

// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
	baseLogger.sourced().Info(args...)
}

// Infoln logs a message at level Info on the standard logger.
func Infoln(args ...interface{}) {
	baseLogger.sourced().Infoln(args...)
}

// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
	baseLogger.sourced().Infof(format, args...)
}

// Warn logs a message at level Warn on the standard logger.
func Warn(args ...interface{}) {
	baseLogger.sourced().Warn(args...)
}

// Warnln logs a message at level Warn on the standard logger.
func Warnln(args ...interface{}) {
	baseLogger.sourced().Warnln(args...)
}

// Warnf logs a message at level Warn on the standard logger.
func Warnf(format string, args ...interface{}) {
	baseLogger.sourced().Warnf(format, args...)
}

// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
	baseLogger.sourced().Error(args...)
}

// Errorln logs a message at level Error on the standard logger.
func Errorln(args ...interface{}) {
	baseLogger.sourced().Errorln(args...)
}

// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
	baseLogger.sourced().Errorf(format, args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func Fatal(args ...interface{}) {
	baseLogger.sourced().Fatal(args...)
}

// Fatalln logs a message at level Fatal on the standard logger.
func Fatalln(args ...interface{}) {
	baseLogger.sourced().Fatalln(args...)
}

// Fatalf logs a message at level Fatal on the standard logger.
func Fatalf(format string, args ...interface{}) {
	baseLogger.sourced().Fatalf(format, args...)
}

// AddHook adds hook to Prometheus' original logger.
func AddHook(hook logrus.Hook) {
	origLogger.Hooks.Add(hook)
}

type errorLogWriter struct{}

func (errorLogWriter) Write(b []byte) (int, error) {
	baseLogger.sourced().Error(string(b))
	return len(b), nil
}

// NewErrorLogger returns a log.Logger that is meant to be used
// in the ErrorLog field of an http.Server to log HTTP server errors.
func NewErrorLogger() *log.Logger {
	return log.New(&errorLogWriter{}, "", 0)
}
<|endoftext|>