<commit_before>// Package calendar generates and has utlilty functions to generate an HTML calendar for use in nlgids.
package calendar

import (
	"bytes"
	"fmt"
	"html/template"
	"sort"
	"time"
)

var (
	avail  = [...]string{"", "past", "busy", "free"}
	meta   = [...]string{"", " now", " prev", " next"} // spaces before each word
	months = [...]string{"boogie", "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"}
)

func (a Available) String() string { return avail[a] }
func (m Meta) String() string      { return meta[m] }

type (
	Available int
	Meta      int

	// The availabilty for a specific date.
	AvailMeta struct {
		Available
		Meta
	}
)

const (
	_ Available = iota
	Past
	Busy
	Free
)

const (
	_ Meta = iota
	Now
	Prev
	Next
)

const templ = `

		 {{.MonthNL}}

`

type header struct {
	Prev    string
	Next    string
	MonthEN string
	MonthNL string
}

func Date(t time.Time) string {
	date := fmt.Sprintf("%4d-%02d-%02d", t.Year(), t.Month(), t.Day())
	return date
}

// Calendar holds the HTML that makes up the calendar. Each
// day is indexed by the 12 o' clock night time as a time.Time.
// All date are in the UTC timezone.
type Calendar struct {
	days  map[time.Time]AvailMeta
	begin time.Time
	end   time.Time
	start time.Time // generated for this date

	subject string // who's calendar
	secret  string // service account client_secret.json
}

type times []time.Time

func (t times) Len() int           { return len(t) }
func (t times) Less(i, j int) bool { return t[i].Before(t[j]) }
func (t times) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }

// Days returns the days of this calendar.
func (c *Calendar) Days() map[time.Time]AvailMeta { return c.days }

func (c *Calendar) heading() string {
	s := `

`
	s += "
zo	ma	di	wo	do	vr	za
\n"
	return s
}

// Header returns the header of the calendar.
func (c *Calendar) Header() (string, error) {
	month := c.start.Month()

	prev := c.start.AddDate(0, -1, 0)
	next := c.start.AddDate(0, +1, 0)
	monthEN := fmt.Sprintf("%s %d", month.String(), c.start.Year())
	monthNL := fmt.Sprintf("%s %d", months[month], c.start.Year())
	head := &header{
		Prev:    Date(prev),
		Next:    Date(next),
		MonthEN: monthEN,
		MonthNL: monthNL,
	}

	t := template.New("Header template")
	t, err := t.Parse(templ)
	if err != nil {
		return "", err
	}
	buf := &bytes.Buffer{}
	err = t.Execute(buf, head)
	if err != nil {
		return "", err
	}
	return buf.String(), nil
}

func (c *Calendar) Footer() string {
	return `

`
}

func (c *Calendar) openTR() string  { return "
\n" }
func (c *Calendar) closeTR() string { return "
\n" }

func (c *Calendar) entry(t time.Time) string {
	am := c.days[t]
	class := fmt.Sprintf("\t", am.Available, am.Meta)
	close := "	\n"
	href := ""

	switch am.Available {
	case Free:
		href = fmt.Sprintf("%d", Date(t), t.Day()) // BookingDate is defined on the page/form itself
	case Busy, Past:
		href = fmt.Sprintf("%d", t.Day())
	}
	s := class + href + close
	return s
}

// HTML returns the calendar in a string containing HTML.
func (c *Calendar) HTML() string {
	s, _ := c.Header()
	s += c.html()
	s += c.Footer()
	return s
}

func (c *Calendar) sort() times {
	keys := times{}
	for k := range c.days {
		keys = append(keys, k)
	}

	sort.Sort(keys)
	return keys
}

func (c *Calendar) html() string {
	keys := c.sort()

	s := c.heading()
	i := 0
	for _, k := range keys {
		if i%7 == 0 {
			if i > 0 {
				s += c.closeTR()
			}
			s += c.openTR()
		}
		s += c.entry(k)
		i++
	}
	s += c.closeTR()
	return s
}

// New creates a new month calendar based on d, d must be in the form: YYYY-MM-DD.
// D can also be the empty string, then the current date is assumed.
func New(d, subject, secret string) (*Calendar, error) {
	date, now := time.Now(), time.Now()
	if d != "" {
		var err error
		date, err = time.Parse("2006-01-02", d)
		if err != nil {
			return nil, err
		}
	}

	cal := &Calendar{days: make(map[time.Time]AvailMeta), start: date, subject: subject, secret: secret}

	today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
	first := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, time.UTC)
	last := time.Date(date.Year(), date.Month()+1, 1, 0, 0, 0, 0, time.UTC)
	last = last.Add(-24 * time.Hour)

	// Add the remaining days of the previous month.
	for i := 0; i < int(first.Weekday()); i++ {
		lastMonthDay := first.AddDate(0, 0, -1*(i+1))
		cal.days[lastMonthDay] = AvailMeta{Available: Free, Meta: Prev}

		if lastMonthDay.Before(today) {
			cal.days[lastMonthDay] = AvailMeta{Available: Past, Meta: Prev}
		}
	}

	// Loop from i to lastDay and add the entire month.
	for i := 1; i <= last.Day(); i++ {
		day := time.Date(date.Year(), date.Month(), i, 0, 0, 0, 0, time.UTC)

		cal.days[day] = AvailMeta{Available: Free}

		if day.Before(today) {
			cal.days[day] = AvailMeta{Available: Past}
		}
	}

	// These are dates in the new month.
	j := 1
	for i := int(last.Weekday()) + 1; i < 7; i++ {
		nextMonthDay := last.AddDate(0, 0, j)
		cal.days[nextMonthDay] = AvailMeta{Available: Free, Meta: Next}

		if nextMonthDay.Before(today) {
			cal.days[nextMonthDay] = AvailMeta{Available: Past, Meta: Next}
		}

		j++
	}

	if cur, ok := cal.days[today]; ok {
		cur.Meta = Now
		cal.days[today] = cur
	}

	times := cal.sort()
	if len(times) > 0 {
		cal.begin = times[0]
		cal.end = times[len(times)-1]
	}

	return cal, nil
}
<commit_msg>some tweaks<commit_after>// Package calendar generates and has utlilty functions to generate an HTML calendar for use in nlgids.
package calendar

import (
	"bytes"
	"fmt"
	"html/template"
	"sort"
	"time"
)

var (
	avail  = [...]string{"", "past", "busy", "free"}
	meta   = [...]string{"", " now", " prev", " next"} // spaces before each word
	months = [...]string{"boogie", "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"}
)

func (a Available) String() string { return avail[a] }
func (m Meta) String() string      { return meta[m] }

type (
	Available int
	Meta      int

	// The availabilty for a specific date.
	AvailMeta struct {
		Available
		Meta
	}
)

const (
	_ Available = iota
	Past
	Busy
	Free
)

const (
	_ Meta = iota
	Now
	Prev
	Next
)

const templ = `

		 {{.MonthNL}}

`

type header struct {
	Prev    string
	Next    string
	MonthEN string
	MonthNL string
}

func Date(t time.Time) string {
	date := fmt.Sprintf("%4d-%02d-%02d", t.Year(), t.Month(), t.Day())
	return date
}

// Calendar holds the HTML that makes up the calendar. Each
// day is indexed by the 12 o' clock night time as a time.Time.
// All date are in the UTC timezone.
type Calendar struct {
	days     map[time.Time]AvailMeta
	begin    time.Time
	end      time.Time
	start    time.Time // generated for this date
	tourType string    // calendar for a specific tour
	id       string

	subject string // who's calendar
	secret  string // service account client_secret.json
}

type times []time.Time

func (t times) Len() int           { return len(t) }
func (t times) Less(i, j int) bool { return t[i].Before(t[j]) }
func (t times) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }

// Days returns the days of this calendar.
func (c *Calendar) Days() map[time.Time]AvailMeta { return c.days }

func (c *Calendar) heading() string {
	s := `

`
	s += "
zo	ma	di	wo	do	vr	za
\n"
	return s
}

// Header returns the header of the calendar.
func (c *Calendar) Header() (string, error) {
	month := c.start.Month()

	prev := c.start.AddDate(0, -1, 0)
	next := c.start.AddDate(0, +1, 0)
	monthEN := fmt.Sprintf("%s %d", month.String(), c.start.Year())
	monthNL := fmt.Sprintf("%s %d", months[month], c.start.Year())
	head := &header{
		Prev:    Date(prev),
		Next:    Date(next),
		MonthEN: monthEN,
		MonthNL: monthNL,
	}

	t := template.New("Header template")
	t, err := t.Parse(templ)
	if err != nil {
		return "", err
	}
	buf := &bytes.Buffer{}
	err = t.Execute(buf, head)
	if err != nil {
		return "", err
	}
	return buf.String(), nil
}

func (c *Calendar) Footer() string {
	return `

`
}

func (c *Calendar) openTR() string  { return "
\n" }
func (c *Calendar) closeTR() string { return "
\n" }

func (c *Calendar) entry(t time.Time) string {
	am := c.days[t]
	class := fmt.Sprintf("\t", am.Available, am.Meta)
	close := "	\n"
	href := ""

	switch am.Available {
	case Free:
		href = fmt.Sprintf("%d", Date(t), t.Day()) // BookingDate is defined on the page/form itself
	case Busy, Past:
		href = fmt.Sprintf("%d", t.Day())
	}
	s := class + href + close
	return s
}

// HTML returns the calendar in a string containing HTML.
func (c *Calendar) HTML() string {
	s, _ := c.Header()
	s += c.html()
	s += c.Footer()
	return s
}

func (c *Calendar) sort() times {
	keys := times{}
	for k := range c.days {
		keys = append(keys, k)
	}

	sort.Sort(keys)
	return keys
}

func (c *Calendar) html() string {
	keys := c.sort()

	s := c.heading()
	i := 0
	for _, k := range keys {
		if i%7 == 0 {
			if i > 0 {
				s += c.closeTR()
			}
			s += c.openTR()
		}
		s += c.entry(k)
		i++
	}
	s += c.closeTR()
	return s
}

// New creates a new month calendar based on d, d must be in the form: YYYY-MM-DD.
// D can also be the empty string, then the current date is assumed.
func New(d, subject, secret string) (*Calendar, error) {
	date, now := time.Now(), time.Now()
	if d != "" {
		var err error
		date, err = time.Parse("2006-01-02", d)
		if err != nil {
			return nil, err
		}
	}

	cal := &Calendar{days: make(map[time.Time]AvailMeta), start: date, subject: subject, secret: secret}

	today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
	first := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, time.UTC)
	last := time.Date(date.Year(), date.Month()+1, 1, 0, 0, 0, 0, time.UTC)
	last = last.Add(-24 * time.Hour)

	// Add the remaining days of the previous month.
	for i := 0; i < int(first.Weekday()); i++ {
		lastMonthDay := first.AddDate(0, 0, -1*(i+1))
		cal.days[lastMonthDay] = AvailMeta{Available: Free, Meta: Prev}

		if lastMonthDay.Before(today) {
			cal.days[lastMonthDay] = AvailMeta{Available: Past, Meta: Prev}
		}
	}

	// Loop from i to lastDay and add the entire month.
	for i := 1; i <= last.Day(); i++ {
		day := time.Date(date.Year(), date.Month(), i, 0, 0, 0, 0, time.UTC)

		cal.days[day] = AvailMeta{Available: Free}

		if day.Before(today) {
			cal.days[day] = AvailMeta{Available: Past}
		}
	}

	// These are dates in the new month.
	j := 1
	for i := int(last.Weekday()) + 1; i < 7; i++ {
		nextMonthDay := last.AddDate(0, 0, j)
		cal.days[nextMonthDay] = AvailMeta{Available: Free, Meta: Next}

		if nextMonthDay.Before(today) {
			cal.days[nextMonthDay] = AvailMeta{Available: Past, Meta: Next}
		}

		j++
	}

	if cur, ok := cal.days[today]; ok {
		cur.Meta = Now
		cal.days[today] = cur
	}

	times := cal.sort()
	if len(times) > 0 {
		cal.begin = times[0]
		cal.end = times[len(times)-1]
	}

	return cal, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"

	"os"

	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metrics.plugin.unicorn")

var graphdef = map[string](mp.Graphs){
	"unicorn.memory": mp.Graphs{
		Label: "Unicorn Memory",
		Unit:  "bytes",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "memory_workers", Label: "Workers", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_master", Label: "Master", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_workeravg", Label: "Worker Average", Diff: false, Stacked: false},
		},
	},
	"unicorn.workers": mp.Graphs{
		Label: "Unicorn Workers",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "worker_total", Label: "Worker Total", Diff: false, Stacked: false},
			mp.Metrics{Name: "worker_idles", Label: "Worker Idles", Diff: false, Stacked: false},
		},
	},
}

// UnicornPlugin mackerel plugin for Unicorn
type UnicornPlugin struct {
	MasterPid  string
	WorkerPids []string
	Tempfile   string
}

// FetchMetrics interface for mackerelplugin
func (u UnicornPlugin) FetchMetrics() (map[string]interface{}, error) {
	stat := make(map[string]interface{})

	workers := len(u.WorkerPids)
	stat["worker_total"] = fmt.Sprint(workers)

	idles, err := idleWorkerCount(u.WorkerPids)
	if err != nil {
		return stat, err
	}
	stat["worker_idles"] = fmt.Sprint(idles)

	workersM, err := workersMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_workers"] = workersM

	masterM, err := masterMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_master"] = masterM

	averageM, err := workersMemoryAvg()
	if err != nil {
		return stat, err
	}
	stat["memory_workeravg"] = averageM

	return stat, nil
}

// GraphDefinition interface for mackerelplugin
func (u UnicornPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

func main() {
	optPidFile := flag.String("pidfile", "", "Pid file name")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()
	var unicorn UnicornPlugin

	command = RealCommand{}
	pipedCommands = RealPipedCommands{}

	if *optPidFile == "" {
		logger.Errorf("Required unicorn pidfile.")
		os.Exit(1)
	} else {
		pid, err := ioutil.ReadFile(*optPidFile)
		if err != nil {
			logger.Errorf("Failed to load unicorn pid file. %s", err)
			os.Exit(1)
		}
		unicorn.MasterPid = strings.Replace(string(pid), "\n", "", 1)
	}

	workerPids, err := fetchUnicornWorkerPids(unicorn.MasterPid)
	if err != nil {
		logger.Errorf("Failed to fetch unicorn worker pids. %s", err)
		os.Exit(1)
	}
	unicorn.WorkerPids = workerPids

	helper := mp.NewMackerelPlugin(unicorn)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-unicorn")
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<commit_msg>to stacked charts<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"

	"os"

	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metrics.plugin.unicorn")

var graphdef = map[string](mp.Graphs){
	"unicorn.memory": mp.Graphs{
		Label: "Unicorn Memory",
		Unit:  "bytes",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "memory_workers", Label: "Workers", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_master", Label: "Master", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_workeravg", Label: "Worker Average", Diff: false, Stacked: false},
		},
	},
	"unicorn.workers": mp.Graphs{
		Label: "Unicorn Workers",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "busy_workers", Label: "Busy Workers", Diff: false, Stacked: true},
			mp.Metrics{Name: "idle_workers", Label: "Idle Workers", Diff: false, Stacked: true},
		},
	},
}

// UnicornPlugin mackerel plugin for Unicorn
type UnicornPlugin struct {
	MasterPid  string
	WorkerPids []string
	Tempfile   string
}

// FetchMetrics interface for mackerelplugin
func (u UnicornPlugin) FetchMetrics() (map[string]interface{}, error) {
	stat := make(map[string]interface{})

	workers := len(u.WorkerPids)
	idles, err := idleWorkerCount(u.WorkerPids)
	if err != nil {
		return stat, err
	}
	stat["idle_workers"] = fmt.Sprint(idles)
	stat["busy_workers"] = fmt.Sprint(workers - idles)

	workersM, err := workersMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_workers"] = workersM

	masterM, err := masterMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_master"] = masterM

	averageM, err := workersMemoryAvg()
	if err != nil {
		return stat, err
	}
	stat["memory_workeravg"] = averageM

	return stat, nil
}

// GraphDefinition interface for mackerelplugin
func (u UnicornPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

func main() {
	optPidFile := flag.String("pidfile", "", "Pid file name")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()
	var unicorn UnicornPlugin

	command = RealCommand{}
	pipedCommands = RealPipedCommands{}

	if *optPidFile == "" {
		logger.Errorf("Required unicorn pidfile.")
		os.Exit(1)
	} else {
		pid, err := ioutil.ReadFile(*optPidFile)
		if err != nil {
			logger.Errorf("Failed to load unicorn pid file. %s", err)
			os.Exit(1)
		}
		unicorn.MasterPid = strings.Replace(string(pid), "\n", "", 1)
	}

	workerPids, err := fetchUnicornWorkerPids(unicorn.MasterPid)
	if err != nil {
		logger.Errorf("Failed to fetch unicorn worker pids. %s", err)
		os.Exit(1)
	}
	unicorn.WorkerPids = workerPids

	helper := mp.NewMackerelPlugin(unicorn)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-unicorn")
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pbgh "github.com/brotherlogic/githubcard/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbs "github.com/brotherlogic/goserver/proto"
	"github.com/brotherlogic/goserver/utils"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
	disk   diskChecker
	jobs   map[string]*pb.JobDetails
}

func deliverCrashReport(job *runnerCommand, getter func(name string) (string, int)) {
     log.Printf("Crash Report sending")
	ip, port := getter("githubcard")
	log.Printf("Found %v", port)
	if port > 0 {
		conn, _ := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
		defer conn.Close()
		client := pbgh.NewGithubClient(conn)
		elems := strings.Split(job.details.Spec.GetName(), "/")
		log.Printf("SENDING: %v", &pbgh.Issue{Service: elems[len(elems)-1], Title: "CRASH REPORT", Body: job.output})
		if len(job.output) > 0 {
			client.AddIssue(context.Background(), &pbgh.Issue{Service: elems[len(elems)-1], Title: "CRASH REPORT", Body: job.output})
		}

	}
}

func (s *Server) monitor(job *pb.JobDetails) {
	for true {
		switch job.State {
		case pb.JobDetails_ACKNOWLEDGED:
			job.StartTime = 0
			job.State = pb.JobDetails_BUILDING
			s.runner.Checkout(job.GetSpec().Name)
			job.State = pb.JobDetails_BUILT
		case pb.JobDetails_BUILT:
			s.runner.Run(job)
			for job.StartTime == 0 {
				time.Sleep(waitTime)
			}
			job.State = pb.JobDetails_PENDING
		case pb.JobDetails_KILLING:
			s.runner.kill(job)
			if !isAlive(job.GetSpec()) {
				log.Printf("SET TO DEAD BECAUSE WE'RE KILLING: %v", job)
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_UPDATE_STARTING:
			s.runner.Update(job)
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_PENDING:
			time.Sleep(time.Minute)
			if isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_RUNNING
			} else {
				log.Printf("FOUND DEAD ON PENDING: %v", job)
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_RUNNING:
			time.Sleep(waitTime)
			if !isAlive(job.GetSpec()) {
				log.Printf("FOUND DEAD WHEN RUNNING: %v", job)
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_DEAD:
			log.Printf("RERUNNING BECAUSE WERE DEAD (%v)", job)
			job.State = pb.JobDetails_ACKNOWLEDGED
		}
	}
}

func getHash(file string) (string, error) {
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	gpath := home + "/gobuild"

	f, err := os.Open(strings.Replace(file, "$GOPATH", gpath, 1))
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}

	return string(h.Sum(nil)), nil
}

func getIP(name string, server string) (string, int) {
	conn, _ := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	entry := pbd.RegistryEntry{Name: name, Identifier: server}
	r, err := registry.Discover(context.Background(), &entry)

	if err != nil {
		return "", -1
	}

	return r.Ip, int(r.Port)
}

// updateState of the runner command
func isAlive(spec *pb.JobSpec) bool {
	elems := strings.Split(spec.Name, "/")
	dServer, dPort := getIP(elems[len(elems)-1], spec.Server)

	if dPort > 0 {
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			return false
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		resp, err := c.IsAlive(context.Background(), &pbs.Alive{})

		if err != nil || resp.Name != elems[len(elems)-1] {
			log.Printf("FOUND DEAD SERVER: (%v) %v -> %v", spec, err, resp)
			return false
		}

		return true
	}

	log.Printf("Failed to locate %v ->%v (%v, %v)", spec, elems[len(elems)-1], dServer, dPort)
	//Mark as false if we can't locate the job
	return false
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

// Mote promotes/demotes this server
func (s Server) Mote(master bool) error {
	return nil
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild", m: &sync.Mutex{}}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	if c == nil || c.command == nil {
		return
	}

	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	c.command.Env = envl

	out, err := c.command.StderrPipe()
	if err != nil {
		log.Printf("Problem getting stderr: %v", err)
	}

	log.Printf("RUNNING %v", c.command.Path)

	scanner := bufio.NewScanner(out)
	go func() {
		log.Printf("HERE")
		for scanner.Scan() {
			log.Printf("SCANNING!")
			c.output += scanner.Text()
		}
		log.Printf("Done scanning")
	}()

	err = c.command.Start()
	log.Printf("ERR = %v", err)

	if !c.background {
		str := ""

		if out != nil {
			buf := new(bytes.Buffer)
			buf.ReadFrom(out)
			str = buf.String()
		}

		c.command.Wait()
		c.output = str
		c.complete = true
	} else {
		log.Printf("Starting to track stuff %v", out)
		c.details.StartTime = time.Now().Unix()
	}
}

func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
	return diskUsage(path)
}

func (s *Server) rebuildLoop() {
	for true {
		time.Sleep(time.Minute * 60)

		var rebuildList []*pb.JobDetails
		var hashList []string
		for _, job := range s.runner.backgroundTasks {
			if time.Since(job.started) > time.Hour {
				rebuildList = append(rebuildList, job.details)
				hashList = append(hashList, job.hash)
			}
		}

		for i := range rebuildList {
			s.runner.Rebuild(rebuildList[i], hashList[i])
		}
	}
}

func main() {
	var quiet = flag.Bool("quiet", true, "Show all output")
	flag.Parse()

	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	s := Server{&goserver.GoServer{}, Init(), prodDiskChecker{}, make(map[string]*pb.JobDetails)}
	s.runner.getip = s.GetIP
	s.Register = s
	s.PrepServer()
	s.GoServer.Killme = false
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<commit_msg>Added scan output<commit_after>package main

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pbgh "github.com/brotherlogic/githubcard/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbs "github.com/brotherlogic/goserver/proto"
	"github.com/brotherlogic/goserver/utils"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
	disk   diskChecker
	jobs   map[string]*pb.JobDetails
}

func deliverCrashReport(job *runnerCommand, getter func(name string) (string, int)) {
     log.Printf("Crash Report sending")
	ip, port := getter("githubcard")
	log.Printf("Found %v", port)
	if port > 0 {
		conn, _ := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
		defer conn.Close()
		client := pbgh.NewGithubClient(conn)
		elems := strings.Split(job.details.Spec.GetName(), "/")
		log.Printf("SENDING: %v", &pbgh.Issue{Service: elems[len(elems)-1], Title: "CRASH REPORT", Body: job.output})
		if len(job.output) > 0 {
			client.AddIssue(context.Background(), &pbgh.Issue{Service: elems[len(elems)-1], Title: "CRASH REPORT", Body: job.output})
		}

	}
}

func (s *Server) monitor(job *pb.JobDetails) {
	for true {
		switch job.State {
		case pb.JobDetails_ACKNOWLEDGED:
			job.StartTime = 0
			job.State = pb.JobDetails_BUILDING
			s.runner.Checkout(job.GetSpec().Name)
			job.State = pb.JobDetails_BUILT
		case pb.JobDetails_BUILT:
			s.runner.Run(job)
			for job.StartTime == 0 {
				time.Sleep(waitTime)
			}
			job.State = pb.JobDetails_PENDING
		case pb.JobDetails_KILLING:
			s.runner.kill(job)
			if !isAlive(job.GetSpec()) {
				log.Printf("SET TO DEAD BECAUSE WE'RE KILLING: %v", job)
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_UPDATE_STARTING:
			s.runner.Update(job)
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_PENDING:
			time.Sleep(time.Minute)
			if isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_RUNNING
			} else {
				log.Printf("FOUND DEAD ON PENDING: %v", job)
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_RUNNING:
			time.Sleep(waitTime)
			if !isAlive(job.GetSpec()) {
				log.Printf("FOUND DEAD WHEN RUNNING: %v", job)
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_DEAD:
			log.Printf("RERUNNING BECAUSE WERE DEAD (%v)", job)
			job.State = pb.JobDetails_ACKNOWLEDGED
		}
	}
}

func getHash(file string) (string, error) {
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	gpath := home + "/gobuild"

	f, err := os.Open(strings.Replace(file, "$GOPATH", gpath, 1))
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}

	return string(h.Sum(nil)), nil
}

func getIP(name string, server string) (string, int) {
	conn, _ := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	entry := pbd.RegistryEntry{Name: name, Identifier: server}
	r, err := registry.Discover(context.Background(), &entry)

	if err != nil {
		return "", -1
	}

	return r.Ip, int(r.Port)
}

// updateState of the runner command
func isAlive(spec *pb.JobSpec) bool {
	elems := strings.Split(spec.Name, "/")
	dServer, dPort := getIP(elems[len(elems)-1], spec.Server)

	if dPort > 0 {
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			return false
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		resp, err := c.IsAlive(context.Background(), &pbs.Alive{})

		if err != nil || resp.Name != elems[len(elems)-1] {
			log.Printf("FOUND DEAD SERVER: (%v) %v -> %v", spec, err, resp)
			return false
		}

		return true
	}

	log.Printf("Failed to locate %v ->%v (%v, %v)", spec, elems[len(elems)-1], dServer, dPort)
	//Mark as false if we can't locate the job
	return false
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

// Mote promotes/demotes this server
func (s Server) Mote(master bool) error {
	return nil
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild", m: &sync.Mutex{}}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	if c == nil || c.command == nil {
		return
	}

	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	c.command.Env = envl

	out, err := c.command.StderrPipe()
	if err != nil {
		log.Printf("Problem getting stderr: %v", err)
	}

	log.Printf("RUNNING %v", c.command.Path)

	scanner := bufio.NewScanner(out)
	go func() {
		c.output += "Starting Scan"
		for scanner.Scan() {
			c.output += scanner.Text()
		}
		c.output += "Finishing Scan"
	}()

	err = c.command.Start()
	log.Printf("ERR = %v", err)

	if !c.background {
		str := ""

		if out != nil {
			buf := new(bytes.Buffer)
			buf.ReadFrom(out)
			str = buf.String()
		}

		c.command.Wait()
		c.output = str
		c.complete = true
	} else {
		log.Printf("Starting to track stuff %v", out)
		c.details.StartTime = time.Now().Unix()
	}
}

func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
	return diskUsage(path)
}

func (s *Server) rebuildLoop() {
	for true {
		time.Sleep(time.Minute * 60)

		var rebuildList []*pb.JobDetails
		var hashList []string
		for _, job := range s.runner.backgroundTasks {
			if time.Since(job.started) > time.Hour {
				rebuildList = append(rebuildList, job.details)
				hashList = append(hashList, job.hash)
			}
		}

		for i := range rebuildList {
			s.runner.Rebuild(rebuildList[i], hashList[i])
		}
	}
}

func main() {
	var quiet = flag.Bool("quiet", true, "Show all output")
	flag.Parse()

	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	s := Server{&goserver.GoServer{}, Init(), prodDiskChecker{}, make(map[string]*pb.JobDetails)}
	s.runner.getip = s.GetIP
	s.Register = s
	s.PrepServer()
	s.GoServer.Killme = false
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<|endoftext|>


<commit_before>package common

import (
	"bytes"
	"io"
	"regexp"
	"strconv"
	"strings"

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

func NewUGCPolicy() *bluemonday.Policy {
	p := bluemonday.UGCPolicy()
	return p
}

func NewStrictPolicy() *bluemonday.Policy {
	p := bluemonday.StrictPolicy()
	return p
}

var (
	secureStrictPolicy                = NewStrictPolicy()
	secureUGCPolicy                   = NewUGCPolicy()
	secureUGCPolicyAllowDataURIImages *bluemonday.Policy
	secureUGCPolicyNoLink             = NoLink()
)

func init() {
	secureUGCPolicyAllowDataURIImages = NewUGCPolicy()
	secureUGCPolicyAllowDataURIImages.AllowDataURIImages()
}

// ClearHTML 清除所有HTML标签及其属性，一般用处理文章标题等不含HTML标签的字符串
func ClearHTML(title string) string {
	return secureStrictPolicy.Sanitize(title)
}

// RemoveXSS 清除不安全的HTML标签和属性，一般用于处理文章内容
func RemoveXSS(content string, noLinks ...bool) string {
	if len(noLinks) > 0 && noLinks[0] {
		return secureUGCPolicyNoLink.Sanitize(content)
	}
	return secureUGCPolicy.Sanitize(content)
}

func NoLink() *bluemonday.Policy {
	p := HTMLFilter()
	p.AllowStandardAttributes()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	// "link" is not permitted

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

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

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

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

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

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

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

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

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

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

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

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

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

	p.AllowLists()

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

	p.AllowTables()

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

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

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

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

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

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

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

	return p
}

func RemoveBytesXSS(content []byte, noLinks ...bool) []byte {
	if len(noLinks) > 0 && noLinks[0] {
		return secureUGCPolicyNoLink.SanitizeBytes(content)
	}
	return secureUGCPolicy.SanitizeBytes(content)
}

func RemoveReaderXSS(reader io.Reader, noLinks ...bool) *bytes.Buffer {
	if len(noLinks) > 0 && noLinks[0] {
		return secureUGCPolicyNoLink.SanitizeReader(reader)
	}
	return secureUGCPolicy.SanitizeReader(reader)
}

// HTMLFilter 构建自定义的HTML标签过滤器
func HTMLFilter() *bluemonday.Policy {
	return bluemonday.NewPolicy()
}

func MyRemoveXSS(content string) string {
	return com.RemoveXSS(content)
}

func MyCleanText(value string) string {
	value = com.StripTags(value)
	value = com.RemoveEOL(value)
	return value
}

func MyCleanTags(value string) string {
	value = com.StripTags(value)
	return value
}

var (
	q                           = rune('`')
	markdownLinkWithDoubleQuote = regexp.MustCompile(`(\]\([^ \)]+ )"([^"\)]+)"(\))`)
	markdownLinkWithSingleQuote = regexp.MustCompile(`(\]\([^ \)]+ )'([^'\)]+)'(\))`)
	markdownLinkWithScript      = regexp.MustCompile(`(?i)(\]\()(javascript):([^\)]*\))`)
	markdownQuoteTag            = regexp.MustCompile("((\n|^)[ ]{0,3})>")
	markdownCodeBlock           = regexp.MustCompile("(?s)([\r\n]|^)```([\\w]*[\r\n].*?[\r\n])```([\r\n]|$)")
)

func MarkdownPickoutCodeblock(content string) (repl []string, newContent string) {
	newContent = markdownCodeBlock.ReplaceAllStringFunc(content, func(found string) string {
		placeholder := `{codeblock(` + strconv.Itoa(len(repl)) + `)}`
		leftIndex := strings.Index(found, "```")
		rightIndex := strings.LastIndex(found, "```")
		repl = append(repl, found[leftIndex+3:rightIndex])
		return found[0:leftIndex+3] + placeholder + found[rightIndex:]
	})
	//echo.Dump([]interface{}{repl, newContent, content})
	return
}

func MarkdownRestorePickout(repl []string, content string) string {
	for i, r := range repl {
		if strings.Count(r, "\n") < 2 {
			r = strings.TrimLeft(r, "\r")
			if !strings.HasPrefix(r, "\n") {
				r = "\n" + r
			}
		}
		if !strings.HasSuffix(r, "\n") {
			r += "\n"
		}
		find := "```{codeblock(" + strconv.Itoa(i) + ")}```"
		content = strings.Replace(content, find, "```"+r+"```", 1)
	}
	return content
}

func ContentEncode(content string, contypes ...string) string {
	if len(content) == 0 {
		return content
	}
	var contype string
	if len(contypes) > 0 {
		contype = contypes[0]
	}
	switch contype {
	case `html`:
		content = RemoveXSS(content)

	case `url`, `image`, `video`, `audio`, `file`, `id`:
		content = MyCleanText(content)

	case `text`:
		content = com.StripTags(content)

	case `json`:
		// pass

	case `markdown`:
		// 提取代码块
		var pick []string
		pick, content = MarkdownPickoutCodeblock(content)

		// - 删除XSS

		// 删除HTML中的XSS代码
		content = RemoveXSS(content)
		// 拦截Markdown链接中的“javascript:”
		content = markdownLinkWithScript.ReplaceAllString(content, `${1}-${2}-${3}`)

		// - 还原

		// 还原双引号
		content = markdownLinkWithDoubleQuote.ReplaceAllString(content, `${1}"${2}"${3}`)
		// 还原单引号
		content = markdownLinkWithSingleQuote.ReplaceAllString(content, `${1}'${2}'${3}`)
		// 还原引用标识
		content = markdownQuoteTag.ReplaceAllString(content, `${1}>`)
		// 还原代码块
		content = MarkdownRestorePickout(pick, content)

	case `list`:
		content = MyCleanText(content)
		content = strings.TrimSpace(content)
		content = strings.Trim(content, `,`)

	default:
		content = com.StripTags(content)
	}
	content = strings.TrimSpace(content)
	return content
}
<commit_msg>update<commit_after>package common

import (
	"bytes"
	"io"
	"regexp"
	"strconv"
	"strings"

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

func NewUGCPolicy() *bluemonday.Policy {
	p := bluemonday.UGCPolicy()
	return p
}

func NewStrictPolicy() *bluemonday.Policy {
	p := bluemonday.StrictPolicy()
	return p
}

var (
	secureStrictPolicy                = NewStrictPolicy()
	secureUGCPolicy                   = NewUGCPolicy()
	secureUGCPolicyAllowDataURIImages *bluemonday.Policy
	secureUGCPolicyNoLink             = NoLink()
)

func init() {
	secureUGCPolicyAllowDataURIImages = NewUGCPolicy()
	secureUGCPolicyAllowDataURIImages.AllowDataURIImages()
}

// ClearHTML 清除所有HTML标签及其属性，一般用处理文章标题等不含HTML标签的字符串
func ClearHTML(title string) string {
	return secureStrictPolicy.Sanitize(title)
}

// RemoveXSS 清除不安全的HTML标签和属性，一般用于处理文章内容
func RemoveXSS(content string, noLinks ...bool) string {
	if len(noLinks) > 0 && noLinks[0] {
		return secureUGCPolicyNoLink.Sanitize(content)
	}
	return secureUGCPolicy.Sanitize(content)
}

func NoLink() *bluemonday.Policy {
	p := HTMLFilter()
	p.AllowStandardAttributes()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	// "link" is not permitted

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

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

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

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

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

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

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

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

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

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

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

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

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

	p.AllowLists()

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

	p.AllowTables()

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

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

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

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

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

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

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

	return p
}

func RemoveBytesXSS(content []byte, noLinks ...bool) []byte {
	if len(noLinks) > 0 && noLinks[0] {
		return secureUGCPolicyNoLink.SanitizeBytes(content)
	}
	return secureUGCPolicy.SanitizeBytes(content)
}

func RemoveReaderXSS(reader io.Reader, noLinks ...bool) *bytes.Buffer {
	if len(noLinks) > 0 && noLinks[0] {
		return secureUGCPolicyNoLink.SanitizeReader(reader)
	}
	return secureUGCPolicy.SanitizeReader(reader)
}

// HTMLFilter 构建自定义的HTML标签过滤器
func HTMLFilter() *bluemonday.Policy {
	return bluemonday.NewPolicy()
}

func MyRemoveXSS(content string) string {
	return com.RemoveXSS(content)
}

func MyCleanText(value string) string {
	value = com.StripTags(value)
	value = com.RemoveEOL(value)
	return value
}

func MyCleanTags(value string) string {
	value = com.StripTags(value)
	return value
}

var (
	q                           = rune('`')
	markdownLinkWithDoubleQuote = regexp.MustCompile(`(\]\([^ \)]+ )"([^"\)]+)"(\))`)
	markdownLinkWithSingleQuote = regexp.MustCompile(`(\]\([^ \)]+ )'([^'\)]+)'(\))`)
	markdownLinkWithScript      = regexp.MustCompile(`(?i)(\]\()(javascript):([^\)]*\))`)
	markdownQuoteTag            = regexp.MustCompile("((\n|^)[ ]{0,3})>")
	markdownCodeBlock           = regexp.MustCompile("(?s)([\r\n]|^)```([\\w]*[\r\n].*?[\r\n])```([\r\n]|$)")
)

func MarkdownPickoutCodeblock(content string) (repl []string, newContent string) {
	newContent = markdownCodeBlock.ReplaceAllStringFunc(content, func(found string) string {
		placeholder := `{codeblock(` + strconv.Itoa(len(repl)) + `)}`
		leftIndex := strings.Index(found, "```")
		rightIndex := strings.LastIndex(found, "```")
		repl = append(repl, found[leftIndex+3:rightIndex])
		return found[0:leftIndex+3] + placeholder + found[rightIndex:]
	})
	//echo.Dump([]interface{}{repl, newContent, content})
	return
}

func MarkdownRestorePickout(repl []string, content string) string {
	for i, r := range repl {
		if strings.Count(r, "\n") < 2 {
			r = strings.TrimLeft(r, "\r")
			if !strings.HasPrefix(r, "\n") {
				r = "\n" + r
			}
		}
		if !strings.HasSuffix(r, "\n") {
			r += "\n"
		}
		find := "```{codeblock(" + strconv.Itoa(i) + ")}```"
		content = strings.Replace(content, find, "```"+r+"```", 1)
	}
	return content
}

func ContentEncode(content string, contypes ...string) string {
	if len(content) == 0 {
		return content
	}
	var contype string
	if len(contypes) > 0 {
		contype = contypes[0]
	}
	switch contype {
	case `html`:
		content = RemoveXSS(content)

	case `url`, `image`, `video`, `audio`, `file`, `id`:
		content = MyCleanText(content)

	case `text`:
		content = com.StripTags(content)

	case `json`:
		// pass

	case `markdown`:
		// 提取代码块
		var pick []string
		pick, content = MarkdownPickoutCodeblock(content)

		// - 删除XSS

		// 删除HTML中的XSS代码
		content = RemoveXSS(content)
		// 拦截Markdown链接中的“javascript:”
		content = markdownLinkWithScript.ReplaceAllString(content, `${1}-${2}-${3}`)

		// - 还原

		// 还原双引号
		content = markdownLinkWithDoubleQuote.ReplaceAllString(content, `${1}"${2}"${3}`)
		// 还原单引号
		content = markdownLinkWithSingleQuote.ReplaceAllString(content, `${1}'${2}'${3}`)
		// 还原引用标识
		content = markdownQuoteTag.ReplaceAllString(content, `${1}>`)
		// 还原代码块
		content = MarkdownRestorePickout(pick, content)

	case `list`:
		content = MyCleanText(content)
		content = strings.TrimSpace(content)
		content = strings.Trim(content, `,`)

	default:
		content = com.StripTags(content)
	}
	content = strings.TrimSpace(content)
	return content
}
<|endoftext|>


<commit_before>package shortuuid

import (
	"fmt"
	"math"
	"math/big"
	"strings"

	uuid "github.com/satori/go.uuid"
)

// UUID returns a new UUID v4.
func UUID() string {
	return New().UUID("")
}

type ShortUUID struct {
	// alphabet is the character set to construct the UUID from.
	alphabet alphabet
}

// New returns a new (short) UUID with the default alphabet.
func New() *ShortUUID {
	return &ShortUUID{newAlphabet(DefaultAlphabet)}
}

// New returns a new (short) UUID using alphabet.
// The alphabet will be sorted and if it contains duplicate characters, they
// will be removed.
func NewWithAlphabet(alphabet string) (*ShortUUID, error) {
	if alphabet == "" {
		return nil, fmt.Errorf("alphabet must not be empty")
	}

	return &ShortUUID{newAlphabet(alphabet)}, nil
}

// UUID returns a new (short) UUID. If name is non-empty, the namespace
// matching the name will be used to generate a UUID.
func (su *ShortUUID) UUID(name string) string {
	var u uuid.UUID

	switch {
	case name == "":
		u = uuid.NewV4()
	case strings.HasPrefix(name, "http"):
		u = uuid.NewV5(uuid.NamespaceDNS, name)
	default:
		u = uuid.NewV5(uuid.NamespaceURL, name)
	}

	return su.Encode(u)
}

// Encode encodes uuid.UUID into a string using the least significant bits
// (LSB) first according to the alphabet. if the most significant bits (MSB)
// are 0, the string might be shorter.
func (su *ShortUUID) Encode(u uuid.UUID) string {
	var num big.Int
	num.SetString(strings.Replace(u.String(), "-", "", 4), 16)
	return su.numToString(&num, su.encodedLength(len(u.Bytes())))
}

// Decode decodes a string according to the alphabet into a uuid.UUID. If s is
// too short, its most significant bits (MSB) will be padded with 0 (zero).
func (su *ShortUUID) Decode(u string) (uuid.UUID, error) {
	return uuid.FromString(su.stringToNum(u))
}

// String genreates a new (short) UUID v4. This is not deterministic, and will
// return a new value each time it's called.
// Implements the fmt.Stringer interface.
func (su *ShortUUID) String() string {
	return su.UUID("")
}

func (su *ShortUUID) numToString(number *big.Int, padToLen int) string {
	var (
		out   string
		digit *big.Int
	)

	for number.Uint64() > 0 {
		number, digit = new(big.Int).DivMod(number, big.NewInt(su.alphabet.Length()), new(big.Int))
		out += su.alphabet.chars[digit.Int64()]
	}

	if padToLen > 0 {
		remainder := math.Max(float64(padToLen-len(out)), 0)
		out = out + strings.Repeat(su.alphabet.chars[0], int(remainder))
	}

	return out
}

// stringToNum converts a string a number using the given alpabet.
func (su *ShortUUID) stringToNum(s string) string {
	n := big.NewInt(0)

	for i := len(s) - 1; i >= 0; i-- {
		n.Mul(n, big.NewInt(su.alphabet.Length()))
		n.Add(n, big.NewInt(su.alphabet.Index(string(s[i]))))
	}

	x := fmt.Sprintf("%x", n)

	// Pad the most significant bit (MSG) with 0 (zero) if the string is too short.
	if len(x) < 32 {
		x = strings.Repeat("0", 32-len(x)) + x
	}

	return fmt.Sprintf("%s-%s-%s-%s-%s", x[0:8], x[8:12], x[12:16], x[16:20], x[20:32])
}

func (su *ShortUUID) encodedLength(numBytes int) int {
	factor := math.Log(float64(25)) / math.Log(float64(su.alphabet.Length()))
	length := math.Ceil(factor * float64(numBytes))
	return int(length)
}
<commit_msg>Inline encodedLength()<commit_after>package shortuuid

import (
	"fmt"
	"math"
	"math/big"
	"strings"

	uuid "github.com/satori/go.uuid"
)

// UUID returns a new UUID v4.
func UUID() string {
	return New().UUID("")
}

type ShortUUID struct {
	// alphabet is the character set to construct the UUID from.
	alphabet alphabet
}

// New returns a new (short) UUID with the default alphabet.
func New() *ShortUUID {
	return &ShortUUID{newAlphabet(DefaultAlphabet)}
}

// New returns a new (short) UUID using alphabet.
// The alphabet will be sorted and if it contains duplicate characters, they
// will be removed.
func NewWithAlphabet(alphabet string) (*ShortUUID, error) {
	if alphabet == "" {
		return nil, fmt.Errorf("alphabet must not be empty")
	}

	return &ShortUUID{newAlphabet(alphabet)}, nil
}

// UUID returns a new (short) UUID. If name is non-empty, the namespace
// matching the name will be used to generate a UUID.
func (su *ShortUUID) UUID(name string) string {
	var u uuid.UUID

	switch {
	case name == "":
		u = uuid.NewV4()
	case strings.HasPrefix(name, "http"):
		u = uuid.NewV5(uuid.NamespaceDNS, name)
	default:
		u = uuid.NewV5(uuid.NamespaceURL, name)
	}

	return su.Encode(u)
}

// Encode encodes uuid.UUID into a string using the least significant bits
// (LSB) first according to the alphabet. if the most significant bits (MSB)
// are 0, the string might be shorter.
func (su *ShortUUID) Encode(u uuid.UUID) string {
	var num big.Int
	num.SetString(strings.Replace(u.String(), "-", "", 4), 16)

	// Calculate encoded length.
	factor := math.Log(float64(25)) / math.Log(float64(su.alphabet.Length()))
	length := math.Ceil(factor * float64(len(u.Bytes())))

	return su.numToString(&num, int(length))
}

// Decode decodes a string according to the alphabet into a uuid.UUID. If s is
// too short, its most significant bits (MSB) will be padded with 0 (zero).
func (su *ShortUUID) Decode(u string) (uuid.UUID, error) {
	return uuid.FromString(su.stringToNum(u))
}

// String genreates a new (short) UUID v4. This is not deterministic, and will
// return a new value each time it's called.
// Implements the fmt.Stringer interface.
func (su *ShortUUID) String() string {
	return su.UUID("")
}

func (su *ShortUUID) numToString(number *big.Int, padToLen int) string {
	var (
		out   string
		digit *big.Int
	)

	for number.Uint64() > 0 {
		number, digit = new(big.Int).DivMod(number, big.NewInt(su.alphabet.Length()), new(big.Int))
		out += su.alphabet.chars[digit.Int64()]
	}

	if padToLen > 0 {
		remainder := math.Max(float64(padToLen-len(out)), 0)
		out = out + strings.Repeat(su.alphabet.chars[0], int(remainder))
	}

	return out
}

// stringToNum converts a string a number using the given alpabet.
func (su *ShortUUID) stringToNum(s string) string {
	n := big.NewInt(0)

	for i := len(s) - 1; i >= 0; i-- {
		n.Mul(n, big.NewInt(su.alphabet.Length()))
		n.Add(n, big.NewInt(su.alphabet.Index(string(s[i]))))
	}

	x := fmt.Sprintf("%x", n)

	// Pad the most significant bit (MSG) with 0 (zero) if the string is too short.
	if len(x) < 32 {
		x = strings.Repeat("0", 32-len(x)) + x
	}

	return fmt.Sprintf("%s-%s-%s-%s-%s", x[0:8], x[8:12], x[12:16], x[16:20], x[20:32])
}
<|endoftext|>


<commit_before>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"github.com/globocom/docker-cluster/cluster"
	etesting "github.com/globocom/tsuru/exec/testing"
	"github.com/globocom/tsuru/provision"
	"labix.org/v2/mgo/bson"
	"launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"strings"
)

func (s *S) TestCollectStatusForStartedUnit(c *gocheck.C) {
	listener := startTestListener("127.0.0.1:9024")
	defer listener.Close()
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c5f",
			AppName:  "ashamed",
			Type:     "python",
			Status:   "running",
			IP:       "127.0.0.3",
			HostPort: "9024",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "ashamed"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c5f",
			AppName: "ashamed",
			Type:    "python",
			Machine: 0,
			Ip:      "127.0.0.1",
			Status:  provision.StatusStarted,
		},
	}
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func (s *S) TestCollectStatusForUnreachableUnit(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c4f",
			AppName:  "make-up",
			Type:     "python",
			Status:   "running",
			IP:       "127.0.0.4",
			HostPort: "9025",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "make-up"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c4f",
			AppName: "make-up",
			Type:    "python",
			Machine: 0,
			Ip:      "127.0.0.1",
			Status:  provision.StatusUnreachable,
		},
	}
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func startDocker() (func(), *httptest.Server) {
	output := `{
    "State": {
        "Running": true,
        "Pid": 2785,
        "ExitCode": 0,
        "StartedAt": "2013-08-15T03:38:45.709874216-03:00",
        "Ghost": false
    },
    "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
	"NetworkSettings": {
		"IpAddress": "127.0.0.9",
		"IpPrefixLen": 8,
		"Gateway": "10.65.41.1",
		"Ports": {
			"8888/tcp": [
				{
					"HostIp": "0.0.0.0",
					"HostPort": "9999"
				}
			]
		}
	}
}`
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if strings.Contains(r.URL.Path, "/containers/9930c24f1c4x") {
			w.Write([]byte(output))
		}
	}))
	var err error
	oldCluster := dockerCluster()
	dCluster, err = cluster.New(nil, &mapStorage{},
		cluster.Node{ID: "server", Address: server.URL},
	)
	if err != nil {
		panic(err)
	}
	return func() {
		server.Close()
		dCluster = oldCluster
	}, server
}

func (s *S) TestCollectStatusFixContainer(c *gocheck.C) {
	cleanup := createFakeContainers([]string{"9930c24f1c4x"}, c)
	defer cleanup()
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c4x",
			AppName:  "makea",
			Type:     "python",
			Status:   "running",
			IP:       "127.0.0.4",
			HostPort: "9025",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "makea"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c4x",
			AppName: "makea",
			Type:    "python",
			Machine: 0,
			Ip:      "127.0.0.1",
			Status:  provision.StatusUnreachable,
		},
	}
	cleanup, _ = startDocker()
	defer cleanup()
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
	cont, err := getContainer("9930c24f1c4x")
	c.Assert(err, gocheck.IsNil)
	c.Assert(cont.IP, gocheck.Equals, "127.0.0.9")
	c.Assert(cont.HostPort, gocheck.Equals, "9999")
}

func (s *S) TestCollectStatusForDownUnit(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c6f",
			AppName:  "make-up",
			Type:     "python",
			Status:   "error",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "make-up"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c6f",
			AppName: "make-up",
			Type:    "python",
			Status:  provision.StatusDown,
		},
	}
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func (s *S) TestProvisionCollectStatusEmpty(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	coll.RemoveAll(nil)
	output := map[string][][]byte{"ps -q": {[]byte("")}}
	fexec := &etesting.FakeExecutor{Output: output}
	setExecut(fexec)
	defer setExecut(nil)
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	c.Assert(units, gocheck.HasLen, 0)
}
<commit_msg>provision/docker: fix collector tests<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"github.com/globocom/docker-cluster/cluster"
	etesting "github.com/globocom/tsuru/exec/testing"
	"github.com/globocom/tsuru/provision"
	"labix.org/v2/mgo/bson"
	"launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"strings"
)

func (s *S) TestCollectStatusForStartedUnit(c *gocheck.C) {
	listener := startTestListener("127.0.0.1:9024")
	defer listener.Close()
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c5f",
			AppName:  "ashamed",
			Type:     "python",
			Status:   "running",
			IP:       "127.0.0.3",
			HostPort: "9024",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "ashamed"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c5f",
			AppName: "ashamed",
			Type:    "python",
			Machine: 0,
			Ip:      "127.0.0.1",
			Status:  provision.StatusStarted,
		},
	}
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func (s *S) TestCollectStatusForUnreachableUnit(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c4f",
			AppName:  "make-up",
			Type:     "python",
			Status:   "running",
			IP:       "127.0.0.4",
			HostPort: "9025",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "make-up"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c4f",
			AppName: "make-up",
			Type:    "python",
			Machine: 0,
			Ip:      "127.0.0.1",
			Status:  provision.StatusUnreachable,
		},
	}
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func startDocker() (func(), *httptest.Server) {
	output := `{
    "State": {
        "Running": true,
        "Pid": 2785,
        "ExitCode": 0,
        "StartedAt": "2013-08-15T03:38:45.709874216-03:00",
        "Ghost": false
    },
    "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
	"NetworkSettings": {
		"IpAddress": "127.0.0.9",
		"IpPrefixLen": 8,
		"Gateway": "10.65.41.1",
		"Ports": {
			"8888/tcp": [
				{
					"HostIp": "0.0.0.0",
					"HostPort": "9999"
				}
			]
		}
	}
}`
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if strings.Contains(r.URL.Path, "/containers/9930c24f1c4x") {
			w.Write([]byte(output))
		}
	}))
	var err error
	oldCluster := dockerCluster()
	dCluster, err = cluster.New(nil, &mapStorage{},
		cluster.Node{ID: "server", Address: server.URL},
	)
	if err != nil {
		panic(err)
	}
	return func() {
		server.Close()
		dCluster = oldCluster
	}, server
}

func (s *S) TestCollectStatusFixContainer(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c4x",
			AppName:  "makea",
			Type:     "python",
			Status:   "running",
			IP:       "127.0.0.4",
			HostPort: "9025",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "makea"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c4x",
			AppName: "makea",
			Type:    "python",
			Machine: 0,
			Ip:      "127.0.0.1",
			Status:  provision.StatusUnreachable,
		},
	}
	cleanup, server := startDocker()
	defer cleanup()
	var storage mapStorage
	storage.StoreContainer("9930c24f1c4x", "server0")
	cmutex.Lock()
	dCluster, err = cluster.New(nil, &storage,
		cluster.Node{ID: "server0", Address: server.URL},
	)
	cmutex.Unlock()
	c.Assert(err, gocheck.IsNil)
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
	cont, err := getContainer("9930c24f1c4x")
	c.Assert(err, gocheck.IsNil)
	c.Assert(cont.IP, gocheck.Equals, "127.0.0.9")
	c.Assert(cont.HostPort, gocheck.Equals, "9999")
}

func (s *S) TestCollectStatusForDownUnit(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	err := coll.Insert(
		container{
			ID:       "9930c24f1c6f",
			AppName:  "make-up",
			Type:     "python",
			Status:   "error",
			HostAddr: "127.0.0.1",
		},
	)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "make-up"})
	expected := []provision.Unit{
		{
			Name:    "9930c24f1c6f",
			AppName: "make-up",
			Type:    "python",
			Status:  provision.StatusDown,
		},
	}
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	sortUnits(units)
	sortUnits(expected)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func (s *S) TestProvisionCollectStatusEmpty(c *gocheck.C) {
	coll := collection()
	defer coll.Close()
	coll.RemoveAll(nil)
	output := map[string][][]byte{"ps -q": {[]byte("")}}
	fexec := &etesting.FakeExecutor{Output: output}
	setExecut(fexec)
	defer setExecut(nil)
	var p dockerProvisioner
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	c.Assert(units, gocheck.HasLen, 0)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Clinton Freeman 2014
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package main

import (
	"fmt"
	"github.com/gorilla/websocket"
	"net/http"
)

type Peer struct {
	Id     string          // The unique identifier of the peer.
	socket *websocket.Conn //The socket for writing to the peer.
}

type Room struct {
	Room string // The unique name of the room (id).
}

type SignalBox struct {
	Peers        map[string]*Peer            // All the peers currently inside this signalbox.
	Rooms        map[string]*Room            // All the rooms currently inside this signalbox.
	RoomContains map[string]map[string]*Peer // All the peers currently inside a room.
	PeerIsIn     map[string]map[string]*Room // All the rooms a peer is currently inside.
}

func main() {
	fmt.Printf("SignalBox Started!\n")

	s := SignalBox{make(map[string]*Peer),
		make(map[string]*Room),
		make(map[string]map[string]*Peer),
		make(map[string]map[string]*Room)}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			http.Error(w, "Method not allowed", 405)
			return
		}

		// Upgrade the HTTP server connection to the WebSocket protocol.
		ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
		if err != nil {
			fmt.Println(err)
			return
		}

		// TODO: Read messages from socket continuously.
		mt, message, err := ws.ReadMessage()
		switch mt {
		case websocket.TextMessage:
			fmt.Printf("Message: %s\n", message)
			action, messageBody, err := ParseMessage(string(message))
			if err != nil {
				fmt.Printf("Unable to parse message: %s!\n", message)
			}

			s, err = action(messageBody, ws, s)
			if err != nil {
				fmt.Printf("Error unable to alter signal box")
			}
		}
	})

	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		panic("ListenAndServe: " + err.Error())
	}
}
<commit_msg>Can read more than one message from a websocket.<commit_after>/*
 * Copyright (c) Clinton Freeman 2014
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package main

import (
	"fmt"
	"github.com/gorilla/websocket"
	"net/http"
)

type Peer struct {
	Id     string          // The unique identifier of the peer.
	socket *websocket.Conn //The socket for writing to the peer.
}

type Room struct {
	Room string // The unique name of the room (id).
}

type SignalBox struct {
	Peers        map[string]*Peer            // All the peers currently inside this signalbox.
	Rooms        map[string]*Room            // All the rooms currently inside this signalbox.
	RoomContains map[string]map[string]*Peer // All the peers currently inside a room.
	PeerIsIn     map[string]map[string]*Room // All the rooms a peer is currently inside.
}

type Message struct {
	msgSocket *websocket.Conn // The socket that the message was broadcast across.
	msgBody   string          // The body of the broadcasted message.
	msgType   int             // The type of the broadcasted message.
}

func startMessagePump(msg chan Message, ws *websocket.Conn) {
	for {
		mt, message, err := ws.ReadMessage()
		if err == nil {
			msg <- Message{ws, string(message), mt}
		}
	}
}

func signalbox(msg chan Message) {
	s := SignalBox{make(map[string]*Peer),
		make(map[string]*Room),
		make(map[string]map[string]*Peer),
		make(map[string]map[string]*Room)}

	for {
		m := <-msg

		switch m.msgType {
		case websocket.TextMessage:
			fmt.Printf("Message: %s\n", m.msgBody)
			action, messageBody, err := ParseMessage(m.msgBody)
			if err != nil {
				fmt.Printf("Unable to parse message: %s!\n", m.msgBody)
			}

			s, err = action(messageBody, m.msgSocket, s)
			if err != nil {
				fmt.Printf("Error unable to alter signal box")
			}
		}
	}
}

func main() {
	fmt.Printf("SignalBox Started!\n")
	msg := make(chan Message)
	go signalbox(msg)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			http.Error(w, "Method not allowed", 405)
			return
		}

		// Upgrade the HTTP server connection to the WebSocket protocol.
		ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
		if err != nil {
			fmt.Println(err)
			return
		}

		// Start pumping messages from this websocket into the signal box.
		go startMessagePump(msg, ws)
	})

	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		panic("ListenAndServe: " + err.Error())
	}
}
<|endoftext|>


<commit_before><commit_msg>With optimizable filter for outer/middle ear.<commit_after><|endoftext|>


<commit_before>package libkb

import (
	"errors"
	"fmt"
	"strings"

	keybase1 "github.com/keybase/client/go/protocol"
)

func GetKeybasePassphrase(g *GlobalContext, ui SecretUI, username, retryMsg string, allowSecretStore bool) (keybase1.GetPassphraseRes, error) {
	arg := DefaultPassphraseArg(allowSecretStore)
	arg.WindowTitle = "Keybase passphrase"
	arg.Type = keybase1.PassphraseType_PASS_PHRASE
	arg.Username = username
	arg.Prompt = fmt.Sprintf("Please enter the Keybase passphrase for %s (12+ characters)", username)
	arg.RetryLabel = retryMsg
	return GetPassphraseUntilCheckWithChecker(g, arg, newUIPrompter(ui), &CheckPassphraseSimple)
}

func GetSecret(g *GlobalContext, ui SecretUI, title, prompt, retryMsg string, allowSecretStore bool) (keybase1.GetPassphraseRes, error) {
	arg := DefaultPassphraseArg(allowSecretStore)
	arg.WindowTitle = title
	arg.Type = keybase1.PassphraseType_PASS_PHRASE
	arg.Prompt = prompt
	arg.RetryLabel = retryMsg
	// apparently allowSecretStore can be true even though HasSecretStore()
	// is false (in the case of mocked secret store tests on linux, for
	// example). So, pass this through:
	arg.Features.StoreSecret.Allow = allowSecretStore
	return GetPassphraseUntilCheckWithChecker(g, arg, newUIPrompter(ui), &CheckPassphraseSimple)
}

func GetPaperKeyPassphrase(g *GlobalContext, ui SecretUI, username string) (string, error) {
	arg := DefaultPassphraseArg(false)
	arg.WindowTitle = "Paper backup key passphrase"
	arg.Type = keybase1.PassphraseType_PAPER_KEY
	if len(username) == 0 {
		username = "your account"
	}
	arg.Prompt = fmt.Sprintf("Please enter a paper backup key passphrase for %s", username)
	arg.Username = username
	arg.Features.StoreSecret.Allow = false
	arg.Features.StoreSecret.Readonly = true
	arg.Features.ShowTyping.Allow = true
	arg.Features.ShowTyping.DefaultValue = true
	res, err := GetPassphraseUntilCheck(g, arg, newUIPrompter(ui), &PaperChecker{})
	if err != nil {
		return "", err
	}
	return res.Passphrase, nil
}

func GetPaperKeyForCryptoPassphrase(g *GlobalContext, ui SecretUI, reason string, devices []*Device) (string, error) {
	if len(devices) == 0 {
		return "", errors.New("empty device list")
	}
	arg := DefaultPassphraseArg(false)
	arg.WindowTitle = "Paper backup key passphrase"
	arg.Type = keybase1.PassphraseType_PAPER_KEY
	arg.Features.StoreSecret.Allow = false
	arg.Features.StoreSecret.Readonly = true
	if len(devices) == 1 {
		arg.Prompt = fmt.Sprintf("%s: please enter the paper key '%s...'", reason, *devices[0].Description)
	} else {
		descs := make([]string, len(devices))
		for i, dev := range devices {
			descs[i] = fmt.Sprintf("'%s...'", *dev.Description)
		}
		paperOpts := strings.Join(descs, " or ")
		arg.Prompt = fmt.Sprintf("%s: please enter one of the following paper keys %s", reason, paperOpts)
	}

	res, err := GetPassphraseUntilCheck(g, arg, newUIPrompter(ui), &PaperChecker{})
	if err != nil {
		return "", err
	}
	return res.Passphrase, nil
}

type PassphrasePrompter interface {
	Prompt(keybase1.GUIEntryArg) (keybase1.GetPassphraseRes, error)
}

type uiPrompter struct {
	ui SecretUI
}

var _ PassphrasePrompter = &uiPrompter{}

func newUIPrompter(ui SecretUI) *uiPrompter {
	return &uiPrompter{ui: ui}
}

func (u *uiPrompter) Prompt(arg keybase1.GUIEntryArg) (keybase1.GetPassphraseRes, error) {
	return u.ui.GetPassphrase(arg, nil)
}

func GetPassphraseUntilCheckWithChecker(g *GlobalContext, arg keybase1.GUIEntryArg, prompter PassphrasePrompter, checker *Checker) (keybase1.GetPassphraseRes, error) {
	if checker == nil {
		return keybase1.GetPassphraseRes{}, errors.New("nil passphrase checker")
	}
	w := &CheckerWrapper{checker: *checker}
	return GetPassphraseUntilCheck(g, arg, prompter, w)
}

func GetPassphraseUntilCheck(g *GlobalContext, arg keybase1.GUIEntryArg, prompter PassphrasePrompter, checker PassphraseChecker) (keybase1.GetPassphraseRes, error) {
	for i := 0; i < 10; i++ {
		res, err := prompter.Prompt(arg)
		if err != nil {
			return keybase1.GetPassphraseRes{}, err
		}
		if checker == nil {
			return res, nil
		}
		err = checker.Check(g, res.Passphrase)
		if err == nil {
			return res, nil
		}
		arg.RetryLabel = err.Error()
	}

	return keybase1.GetPassphraseRes{}, RetryExhaustedError{}
}

func DefaultPassphraseArg(allowSecretStore bool) keybase1.GUIEntryArg {
	return keybase1.GUIEntryArg{
		SubmitLabel: "Submit",
		CancelLabel: "Cancel",
		Features: keybase1.GUIEntryFeatures{
			ShowTyping: keybase1.Feature{
				Allow:        true,
				DefaultValue: false,
				Readonly:     true,
				Label:        "Show typing",
			},
			StoreSecret: keybase1.Feature{
				Allow:        allowSecretStore,
				DefaultValue: false,
				Readonly:     false,
				Label:        "Save in Keychain",
			},
		},
	}
}

// PassphraseChecker is an interface for checking the format of a
// passphrase. Returns nil if the format is ok, or a descriptive
// hint otherwise.
type PassphraseChecker interface {
	Check(*GlobalContext, string) error
}

// CheckerWrapper wraps a Checker type to make it conform to the
// PassphraseChecker interface.
type CheckerWrapper struct {
	checker Checker
}

// Check s using checker, respond with checker.Hint if check
// fails.
func (w *CheckerWrapper) Check(_ *GlobalContext, s string) error {
	if w.checker.F(s) {
		return nil
	}
	return errors.New(w.checker.Hint)
}

// PaperChecker implements PassphraseChecker for paper keys.
type PaperChecker struct{}

// Check a paper key format.  Will return a detailed error message
// specific to the problems found in s.
func (p *PaperChecker) Check(g *GlobalContext, s string) error {
	phrase := NewPaperKeyPhrase(s)

	// check for invalid words
	invalids := phrase.InvalidWords()
	if len(invalids) > 0 {
		g.Log.Debug("paper phrase has invalid word(s) in it")
		if len(invalids) > 1 {
			return fmt.Errorf("Please try again. These words are invalid: %s", strings.Join(invalids, ", "))
		}
		return fmt.Errorf("Please try again. This word is invalid: %s", invalids[0])
	}

	// check version
	version, err := phrase.Version()
	if err != nil {
		g.Log.Debug("error getting paper key version: %s", err)
		// despite the error, just tell the user there was a typo:
		return errors.New("It looks like there was a typo in the paper key. Please try again.")
	}
	if version != PaperKeyVersion {
		g.Log.Debug("paper key version mismatch: generated version = %d, libkb version = %d", version, PaperKeyVersion)
		return fmt.Errorf("It looks like there was a typo. The paper key you entered had an invalid version. Please try again.")
	}

	return nil
}
<commit_msg>Check for empty paper key<commit_after>package libkb

import (
	"errors"
	"fmt"
	"strings"

	keybase1 "github.com/keybase/client/go/protocol"
)

func GetKeybasePassphrase(g *GlobalContext, ui SecretUI, username, retryMsg string, allowSecretStore bool) (keybase1.GetPassphraseRes, error) {
	arg := DefaultPassphraseArg(allowSecretStore)
	arg.WindowTitle = "Keybase passphrase"
	arg.Type = keybase1.PassphraseType_PASS_PHRASE
	arg.Username = username
	arg.Prompt = fmt.Sprintf("Please enter the Keybase passphrase for %s (12+ characters)", username)
	arg.RetryLabel = retryMsg
	return GetPassphraseUntilCheckWithChecker(g, arg, newUIPrompter(ui), &CheckPassphraseSimple)
}

func GetSecret(g *GlobalContext, ui SecretUI, title, prompt, retryMsg string, allowSecretStore bool) (keybase1.GetPassphraseRes, error) {
	arg := DefaultPassphraseArg(allowSecretStore)
	arg.WindowTitle = title
	arg.Type = keybase1.PassphraseType_PASS_PHRASE
	arg.Prompt = prompt
	arg.RetryLabel = retryMsg
	// apparently allowSecretStore can be true even though HasSecretStore()
	// is false (in the case of mocked secret store tests on linux, for
	// example). So, pass this through:
	arg.Features.StoreSecret.Allow = allowSecretStore
	return GetPassphraseUntilCheckWithChecker(g, arg, newUIPrompter(ui), &CheckPassphraseSimple)
}

func GetPaperKeyPassphrase(g *GlobalContext, ui SecretUI, username string) (string, error) {
	arg := DefaultPassphraseArg(false)
	arg.WindowTitle = "Paper backup key passphrase"
	arg.Type = keybase1.PassphraseType_PAPER_KEY
	if len(username) == 0 {
		username = "your account"
	}
	arg.Prompt = fmt.Sprintf("Please enter a paper backup key passphrase for %s", username)
	arg.Username = username
	arg.Features.StoreSecret.Allow = false
	arg.Features.StoreSecret.Readonly = true
	arg.Features.ShowTyping.Allow = true
	arg.Features.ShowTyping.DefaultValue = true
	res, err := GetPassphraseUntilCheck(g, arg, newUIPrompter(ui), &PaperChecker{})
	if err != nil {
		return "", err
	}
	return res.Passphrase, nil
}

func GetPaperKeyForCryptoPassphrase(g *GlobalContext, ui SecretUI, reason string, devices []*Device) (string, error) {
	if len(devices) == 0 {
		return "", errors.New("empty device list")
	}
	arg := DefaultPassphraseArg(false)
	arg.WindowTitle = "Paper backup key passphrase"
	arg.Type = keybase1.PassphraseType_PAPER_KEY
	arg.Features.StoreSecret.Allow = false
	arg.Features.StoreSecret.Readonly = true
	if len(devices) == 1 {
		arg.Prompt = fmt.Sprintf("%s: please enter the paper key '%s...'", reason, *devices[0].Description)
	} else {
		descs := make([]string, len(devices))
		for i, dev := range devices {
			descs[i] = fmt.Sprintf("'%s...'", *dev.Description)
		}
		paperOpts := strings.Join(descs, " or ")
		arg.Prompt = fmt.Sprintf("%s: please enter one of the following paper keys %s", reason, paperOpts)
	}

	res, err := GetPassphraseUntilCheck(g, arg, newUIPrompter(ui), &PaperChecker{})
	if err != nil {
		return "", err
	}
	return res.Passphrase, nil
}

type PassphrasePrompter interface {
	Prompt(keybase1.GUIEntryArg) (keybase1.GetPassphraseRes, error)
}

type uiPrompter struct {
	ui SecretUI
}

var _ PassphrasePrompter = &uiPrompter{}

func newUIPrompter(ui SecretUI) *uiPrompter {
	return &uiPrompter{ui: ui}
}

func (u *uiPrompter) Prompt(arg keybase1.GUIEntryArg) (keybase1.GetPassphraseRes, error) {
	return u.ui.GetPassphrase(arg, nil)
}

func GetPassphraseUntilCheckWithChecker(g *GlobalContext, arg keybase1.GUIEntryArg, prompter PassphrasePrompter, checker *Checker) (keybase1.GetPassphraseRes, error) {
	if checker == nil {
		return keybase1.GetPassphraseRes{}, errors.New("nil passphrase checker")
	}
	w := &CheckerWrapper{checker: *checker}
	return GetPassphraseUntilCheck(g, arg, prompter, w)
}

func GetPassphraseUntilCheck(g *GlobalContext, arg keybase1.GUIEntryArg, prompter PassphrasePrompter, checker PassphraseChecker) (keybase1.GetPassphraseRes, error) {
	for i := 0; i < 10; i++ {
		res, err := prompter.Prompt(arg)
		if err != nil {
			return keybase1.GetPassphraseRes{}, err
		}
		if checker == nil {
			return res, nil
		}
		err = checker.Check(g, res.Passphrase)
		if err == nil {
			return res, nil
		}
		arg.RetryLabel = err.Error()
	}

	return keybase1.GetPassphraseRes{}, RetryExhaustedError{}
}

func DefaultPassphraseArg(allowSecretStore bool) keybase1.GUIEntryArg {
	return keybase1.GUIEntryArg{
		SubmitLabel: "Submit",
		CancelLabel: "Cancel",
		Features: keybase1.GUIEntryFeatures{
			ShowTyping: keybase1.Feature{
				Allow:        true,
				DefaultValue: false,
				Readonly:     true,
				Label:        "Show typing",
			},
			StoreSecret: keybase1.Feature{
				Allow:        allowSecretStore,
				DefaultValue: false,
				Readonly:     false,
				Label:        "Save in Keychain",
			},
		},
	}
}

// PassphraseChecker is an interface for checking the format of a
// passphrase. Returns nil if the format is ok, or a descriptive
// hint otherwise.
type PassphraseChecker interface {
	Check(*GlobalContext, string) error
}

// CheckerWrapper wraps a Checker type to make it conform to the
// PassphraseChecker interface.
type CheckerWrapper struct {
	checker Checker
}

// Check s using checker, respond with checker.Hint if check
// fails.
func (w *CheckerWrapper) Check(_ *GlobalContext, s string) error {
	if w.checker.F(s) {
		return nil
	}
	return errors.New(w.checker.Hint)
}

// PaperChecker implements PassphraseChecker for paper keys.
type PaperChecker struct{}

// Check a paper key format.  Will return a detailed error message
// specific to the problems found in s.
func (p *PaperChecker) Check(g *GlobalContext, s string) error {
	phrase := NewPaperKeyPhrase(s)

	// check for empty
	if len(phrase.String()) == 0 {
		g.Log.Debug("paper phrase is empty")
		return errors.New("Empty paper key. Please try again.")
	}

	// check for invalid words
	invalids := phrase.InvalidWords()
	if len(invalids) > 0 {
		g.Log.Debug("paper phrase has invalid word(s) in it")
		if len(invalids) > 1 {
			return fmt.Errorf("Please try again. These words are invalid: %s", strings.Join(invalids, ", "))
		}
		return fmt.Errorf("Please try again. This word is invalid: %s", invalids[0])
	}

	// check version
	version, err := phrase.Version()
	if err != nil {
		g.Log.Debug("error getting paper key version: %s", err)
		// despite the error, just tell the user there was a typo:
		return errors.New("It looks like there was a typo in the paper key. Please try again.")
	}
	if version != PaperKeyVersion {
		g.Log.Debug("paper key version mismatch: generated version = %d, libkb version = %d", version, PaperKeyVersion)
		return fmt.Errorf("It looks like there was a typo. The paper key you entered had an invalid version. Please try again.")
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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 agreedto 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 tlstest

import (
	"crypto/tls"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"testing"

	"vitess.io/vitess/go/vt/vttls"
)

// TestClientServer generates:
// - a root CA
// - a server intermediate CA, with a server.
// - a client intermediate CA, with a client.
// And then performs a few tests on them.
func TestClientServer(t *testing.T) {
	// Our test root.
	root, err := ioutil.TempDir("", "tlstest")
	if err != nil {
		t.Fatalf("TempDir failed: %v", err)
	}
	defer os.RemoveAll(root)

	// Create the certs and configs.
	CreateCA(root)

	CreateSignedCert(root, CA, "01", "servers", "Servers CA")
	CreateSignedCert(root, "servers", "01", "server-instance", "server.example.com")

	CreateSignedCert(root, CA, "02", "clients", "Clients CA")
	CreateSignedCert(root, "clients", "01", "client-instance", "Client Instance")
	serverConfig, err := vttls.ServerConfig(
		path.Join(root, "server-instance-cert.pem"),
		path.Join(root, "server-instance-key.pem"),
		path.Join(root, "clients-cert.pem"))
	if err != nil {
		t.Fatalf("TLSServerConfig failed: %v", err)
	}
	clientConfig, err := vttls.ClientConfig(
		path.Join(root, "client-instance-cert.pem"),
		path.Join(root, "client-instance-key.pem"),
		path.Join(root, "servers-cert.pem"),
		"server.example.com")
	if err != nil {
		t.Fatalf("TLSClientConfig failed: %v", err)
	}

	// Create a TLS server listener.
	listener, err := tls.Listen("tcp", ":0", serverConfig)
	if err != nil {
		t.Fatalf("Listen failed: %v", err)
	}
	addr := listener.Addr().String()
	defer listener.Close()

	wg := sync.WaitGroup{}

	//
	// Positive case: accept on server side, connect a client, send data.
	//

	wg.Add(1)
	go func() {
		defer wg.Done()
		clientConn, err := tls.Dial("tcp", addr, clientConfig)
		if err != nil {
			t.Fatalf("Dial failed: %v", err)
		}

		clientConn.Write([]byte{42})
		clientConn.Close()
	}()

	serverConn, err := listener.Accept()
	if err != nil {
		t.Fatalf("Accept failed: %v", err)
	}

	result := make([]byte, 1)
	if n, err := serverConn.Read(result); (err != nil && err != io.EOF) || n != 1 {
		t.Fatalf("Read failed: %v %v", n, err)
	}
	if result[0] != 42 {
		t.Fatalf("Read returned wrong result: %v", result)
	}
	serverConn.Close()

	wg.Wait()

	//
	// Negative case: connect a client with wrong cert (using the
	// server cert on the client side).
	//

	badClientConfig, err := vttls.ClientConfig(
		path.Join(root, "server-instance-cert.pem"),
		path.Join(root, "server-instance-key.pem"),
		path.Join(root, "servers-cert.pem"),
		"server.example.com")
	if err != nil {
		t.Fatalf("TLSClientConfig failed: %v", err)
	}

	wg.Add(1)
	go func() {
		// We expect the Accept to work, but the first read to fail.
		defer wg.Done()
		serverConn, err := listener.Accept()
		if err != nil {
			t.Fatalf("Connection failed: %v", err)
		}

		// This will fail.
		result := make([]byte, 1)
		if n, err := serverConn.Read(result); err == nil {
			fmt.Printf("Was able to read from server: %v\n", n)
		}
		serverConn.Close()
	}()

	if _, err = tls.Dial("tcp", addr, badClientConfig); err == nil {
		t.Fatalf("Dial was expected to fail")
	}
	if !strings.Contains(err.Error(), "bad certificate") {
		t.Errorf("Wrong error returned: %v", err)
	}
	t.Logf("Dial returned: %v", err)
}
<commit_msg>tlstest_test: Go 1.12 / TLS 1.3 fix<commit_after>/*
Copyright 2017 Google Inc.

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 agreedto 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 tlstest

import (
	"crypto/tls"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"testing"

	"vitess.io/vitess/go/vt/vttls"
)

// TestClientServer generates:
// - a root CA
// - a server intermediate CA, with a server.
// - a client intermediate CA, with a client.
// And then performs a few tests on them.
func TestClientServer(t *testing.T) {
	// Our test root.
	root, err := ioutil.TempDir("", "tlstest")
	if err != nil {
		t.Fatalf("TempDir failed: %v", err)
	}
	defer os.RemoveAll(root)

	// Create the certs and configs.
	CreateCA(root)

	CreateSignedCert(root, CA, "01", "servers", "Servers CA")
	CreateSignedCert(root, "servers", "01", "server-instance", "server.example.com")

	CreateSignedCert(root, CA, "02", "clients", "Clients CA")
	CreateSignedCert(root, "clients", "01", "client-instance", "Client Instance")
	serverConfig, err := vttls.ServerConfig(
		path.Join(root, "server-instance-cert.pem"),
		path.Join(root, "server-instance-key.pem"),
		path.Join(root, "clients-cert.pem"))
	if err != nil {
		t.Fatalf("TLSServerConfig failed: %v", err)
	}
	clientConfig, err := vttls.ClientConfig(
		path.Join(root, "client-instance-cert.pem"),
		path.Join(root, "client-instance-key.pem"),
		path.Join(root, "servers-cert.pem"),
		"server.example.com")
	if err != nil {
		t.Fatalf("TLSClientConfig failed: %v", err)
	}

	// Create a TLS server listener.
	listener, err := tls.Listen("tcp", ":0", serverConfig)
	if err != nil {
		t.Fatalf("Listen failed: %v", err)
	}
	addr := listener.Addr().String()
	defer listener.Close()

	wg := sync.WaitGroup{}

	//
	// Positive case: accept on server side, connect a client, send data.
	//

	wg.Add(1)
	go func() {
		defer wg.Done()
		clientConn, err := tls.Dial("tcp", addr, clientConfig)
		if err != nil {
			t.Fatalf("Dial failed: %v", err)
		}

		clientConn.Write([]byte{42})
		clientConn.Close()
	}()

	serverConn, err := listener.Accept()
	if err != nil {
		t.Fatalf("Accept failed: %v", err)
	}

	result := make([]byte, 1)
	if n, err := serverConn.Read(result); (err != nil && err != io.EOF) || n != 1 {
		t.Fatalf("Read failed: %v %v", n, err)
	}
	if result[0] != 42 {
		t.Fatalf("Read returned wrong result: %v", result)
	}
	serverConn.Close()

	wg.Wait()

	//
	// Negative case: connect a client with wrong cert (using the
	// server cert on the client side).
	//

	badClientConfig, err := vttls.ClientConfig(
		path.Join(root, "server-instance-cert.pem"),
		path.Join(root, "server-instance-key.pem"),
		path.Join(root, "servers-cert.pem"),
		"server.example.com")
	if err != nil {
		t.Fatalf("TLSClientConfig failed: %v", err)
	}

	wg.Add(1)
	go func() {
		// We expect the Accept to work, but the first read to fail.
		defer wg.Done()
		serverConn, err := listener.Accept()
		if err != nil {
			t.Fatalf("Connection failed: %v", err)
		}

		// This will fail.
		result := make([]byte, 1)
		if n, err := serverConn.Read(result); err == nil {
			fmt.Printf("Was able to read from server: %v\n", n)
		}
		serverConn.Close()
	}()

	// When using TLS 1.2, the Dial will fail.
	// With TLS 1.3, the Dial will succeed and the first Read will fail.
	clientConn, err := tls.Dial("tcp", addr, badClientConfig)
	if err != nil {
		if !strings.Contains(err.Error(), "bad certificate") {
			t.Errorf("Wrong error returned: %v", err)
		}
		return
	}
	data := make([]byte, 1)
	_, err = clientConn.Read(data)
	if err == nil {
		t.Fatalf("Dial or first Read was expected to fail")
	}
	if !strings.Contains(err.Error(), "bad certificate") {
		t.Errorf("Wrong error returned: %v", err)
	}
}
<|endoftext|>


<commit_before>package sliceflag

import (
	"bytes"
	"flag"
	"reflect"
	"testing"
)

func TestString(t *testing.T) {
	flagset := flag.NewFlagSet("test", flag.ContinueOnError)
	stringFlag1 := String(flagset, "string1", []string{}, "string1 value")
	stringFlag2 := String(flagset, "string2", []string{"ddd"}, "string2 value")
	stringFlag3 := String(flagset, "string3", []string{"eee"}, "string3 value")
	args := []string{
		"-string1", "aaa",
		"-string2", "ccc",
		"-string1", "bbb",
	}
	if err := flagset.Parse(args); err != nil {
		t.Fatal(err)
	}
	if !flagset.Parsed() {
		t.Error("flagset.Parsed() = false after Parse")
	}
	if e, g := []string{"aaa", "bbb"}, *stringFlag1; !reflect.DeepEqual(e, g) {
		t.Errorf("stringFlag1 expected %v got %v", e, g)
	}
	if e, g := []string{"ccc"}, *stringFlag2; !reflect.DeepEqual(e, g) {
		t.Errorf("stringFlag2 expected %v got %v", e, g)
	}
	if e, g := []string{"eee"}, *stringFlag3; !reflect.DeepEqual(e, g) {
		t.Errorf("stringFlag3 expected %v got %v", e, g)
	}

	var b bytes.Buffer
	flagset.SetOutput(&b)
	flagset.PrintDefaults()

	if e, g := `  -string1 value
    	string1 value (default [])
  -string2 value
    	string2 value (default [ddd])
  -string3 value
    	string3 value (default [eee])
`, b.String(); e != g {
		t.Errorf("defaults expected %v got %v", e, g)
	}
}
<commit_msg>flag lookup test<commit_after>package sliceflag

import (
	"bytes"
	"flag"
	"reflect"
	"testing"
)

func TestString(t *testing.T) {
	flagset := flag.NewFlagSet("test", flag.ContinueOnError)
	stringFlag1 := String(flagset, "string1", []string{}, "string1 value")
	stringFlag2 := String(flagset, "string2", []string{"ddd"}, "string2 value")
	stringFlag3 := String(flagset, "string3", []string{"eee"}, "string3 value")
	args := []string{
		"-string1", "aaa",
		"-string2", "ccc",
		"-string1", "bbb",
	}
	if err := flagset.Parse(args); err != nil {
		t.Fatal(err)
	}
	if !flagset.Parsed() {
		t.Error("flagset.Parsed() = false after Parse")
	}
	if e, g := []string{"aaa", "bbb"}, *stringFlag1; !reflect.DeepEqual(e, g) {
		t.Errorf("stringFlag1 expected %v got %v", e, g)
	}
	if e, g := []string{"ccc"}, *stringFlag2; !reflect.DeepEqual(e, g) {
		t.Errorf("stringFlag2 expected %v got %v", e, g)
	}
	if e, g := []string{"eee"}, *stringFlag3; !reflect.DeepEqual(e, g) {
		t.Errorf("stringFlag3 expected %v got %v", e, g)
	}

	var b bytes.Buffer
	flagset.SetOutput(&b)
	flagset.PrintDefaults()

	if e, g := `  -string1 value
    	string1 value (default [])
  -string2 value
    	string2 value (default [ddd])
  -string3 value
    	string3 value (default [eee])
`, b.String(); e != g {
		t.Errorf("defaults expected %v got %v", e, g)
	}

	if e, g := []string{"aaa", "bbb"}, flagset.Lookup("string1").Value.(flag.Getter).Get(); !reflect.DeepEqual(e, g) {
		t.Errorf("string1 lookup expected %v got %v", e, g)
	}
}
<|endoftext|>


<commit_before>package campaign

import (
	"crypto/hmac"
	"fmt"
	"log"
	"net/url"

	"github.com/toomore/mailbox/utils"
)

// MakeMac is to hmac data with campaign seed
func MakeMac(campaignID string, data url.Values) []byte {
	conn := utils.GetConn()
	rows, err := conn.Query(fmt.Sprintf(`SELECT seed FROM campaign WHERE id='%s' `, campaignID))
	defer rows.Close()
	if err != nil {
		log.Fatal(err)
	}
	var seed string
	for rows.Next() {
		rows.Scan(&seed)
	}
	return utils.GenHmac([]byte(seed), []byte(data.Encode()))
}

// CheckMac is to check hash mac
func CheckMac(hm []byte, campaignID string, data url.Values) bool {
	return hmac.Equal(hm, MakeMac(campaignID, data))
}
<commit_msg>Fixed syntax<commit_after>package campaign

import (
	"crypto/hmac"
	"log"
	"net/url"

	"github.com/toomore/mailbox/utils"
)

// MakeMac is to hmac data with campaign seed
func MakeMac(campaignID string, data url.Values) []byte {
	conn := utils.GetConn()
	rows, err := conn.Query(`SELECT seed FROM campaign WHERE id='?' `, campaignID)
	defer rows.Close()
	if err != nil {
		log.Fatal(err)
	}
	var seed string
	for rows.Next() {
		rows.Scan(&seed)
	}
	return utils.GenHmac([]byte(seed), []byte(data.Encode()))
}

// CheckMac is to check hash mac
func CheckMac(hm []byte, campaignID string, data url.Values) bool {
	return hmac.Equal(hm, MakeMac(campaignID, data))
}
<|endoftext|>