<commit_before>package dsl

import (
	"strings"
	"time"

	"github.com/emicklei/melrose"
	"github.com/emicklei/melrose/notify"
)

// Syntax tells what language version this package is supporting.
const Syntax = "1.0" // major,minor

func IsCompatibleSyntax(s string) bool {
	if len(s) == 0 {
		// ignore syntax ; you are on your own
		return true
	}
	mm := strings.Split(Syntax, ".")
	ss := strings.Split(s, ".")
	return mm[0] == ss[0] && ss[1] <= mm[1]
}

type Function struct {
	Title         string
	Description   string
	Prefix        string // for autocomplete
	Sample        string
	ControlsAudio bool
	Func          interface{}
}

func EvalFunctions(storage VariableStorage) map[string]Function {
	eval := map[string]Function{}
	eval["chord"] = Function{
		Title:       "Chord creator",
		Description: "create a Chord",
		Prefix:      "cho",
		Sample:      `chord('${1:note}')`,
		Func: func(chord string) interface{} {
			c, err := melrose.ParseChord(chord)
			if err != nil {
				notify.Print(notify.Errorf("%v", err))
				return nil
			}
			return c
		}}

	eval["pitch"] = Function{
		Title:       "Pitch modifier",
		Description: "change the pitch with a delta of semitones",
		Prefix:      "pit",
		Sample:      `pitch(${1:semitones},${2:sequenceable})`,
		Func: func(semitones, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot pitch (%T) %v", m, m))
				return nil
			}
			return melrose.Pitch{Target: s, Semitones: getValueable(semitones)}
		}}

	eval["reverse"] = Function{
		Title:       "Reverse modifier",
		Description: "reverse the (groups of) notes in a sequence",
		Prefix:      "rev",
		Sample:      `reverse(${1:sequenceable})`,
		Func: func(m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot reverse (%T) %v", m, m))
				return nil
			}
			return melrose.Reverse{Target: s}
		}}

	eval["repeat"] = Function{
		Title:       "Repeat modifier",
		Description: "repeat the musical object a number of times",
		Prefix:      "rep",
		Sample:      `repeat(${1:times},${2:sequenceable})`,
		Func: func(howMany int, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot repeat (%T) %v", m, m))
				return nil
			}
			return melrose.Repeat{Target: s, Times: howMany}
		}}

	eval["join"] = Function{
		Title:       "Join modifier",
		Description: "join two or more musical objects",
		Prefix:      "joi",
		Sample:      `join(${1:first},${2:second})`,
		Func: func(playables ...interface{}) interface{} { // Note: return type cannot be EvaluationResult
			joined := []melrose.Sequenceable{}
			for _, p := range playables {
				if s, ok := getSequenceable(p); !ok {
					notify.Print(notify.Warningf("cannot join (%T) %v", p, p))
					return nil
				} else {
					joined = append(joined, s)
				}
			}
			return melrose.Join{List: joined}
		}}

	eval["bpm"] = Function{
		Title:         "Beats Per Minute",
		Description:   "get or set the Beats Per Minute value [1..300], default is 120",
		ControlsAudio: true,
		Prefix:        "bpm",
		Sample:        `bpm(${1:beats-per-minute})`,
		Func: func(f ...float64) interface{} {
			if len(f) == 0 {
				return melrose.CurrentDevice().BeatsPerMinute()
			}
			melrose.CurrentDevice().SetBeatsPerMinute(f[0])
			return nil
		}}

	eval["sequence"] = Function{
		Title:       "Sequence creator",
		Description: "create a Sequence from a string of notes",
		Prefix:      "seq",
		Sample:      `sequence('${1:space-separated-notes}')`,
		Func: func(s string) interface{} {
			sq, err := melrose.ParseSequence(s)
			if err != nil {
				notify.Print(notify.Error(err))
				return nil
			}
			return sq
		}}

	eval["note"] = Function{
		Title:       "Note creator",
		Prefix:      "no",
		Description: "Note, e.g. C 2G#5. =",
		Sample:      `note('${1:letter}')`,
		Func: func(s string) interface{} {
			n, err := melrose.ParseNote(s)
			if err != nil {
				notify.Print(notify.Error(err))
				return nil
			}
			return n
		}}

	eval["play"] = Function{
		Title:         "Player (foreground)",
		Description:   "play musical objects such as Note,Chord,Sequence,...",
		ControlsAudio: true,
		Prefix:        "pla",
		Sample:        `play(${1:sequenceable})`,
		Func: func(playables ...interface{}) interface{} {
			for _, p := range playables {
				if s, ok := getSequenceable(p); ok {
					melrose.CurrentDevice().Play(s, true)
				} else {
					notify.Print(notify.Warningf("cannot play (%T) %v", p, p))
				}
			}
			return nil
		}}

	eval["go"] = Function{
		Title:         "Player (background)",
		Description:   "play all musical objects in parallel",
		ControlsAudio: true,
		Prefix:        "go",
		Sample:        `go(${1:sequenceable})`,
		Func: func(playables ...interface{}) interface{} {
			for _, p := range playables {
				if s, ok := getSequenceable(p); ok {
					go melrose.CurrentDevice().Play(s, false)
				}
			}
			return nil
		}}

	eval["serial"] = Function{
		Title:       "Serial modifier",
		Description: "serialise any parallelisation of notes in a musical object",
		Prefix:      "ser",
		Sample:      `serial(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot serial (%T) %v", value, value))
				return nil
			} else {
				return melrose.Serial{Target: s}
			}
		}}

	eval["record"] = Function{
		Title:         "Recorder",
		Description:   "creates a recorded sequence of notes from device ID and stop after T seconds of inactivity",
		ControlsAudio: true,
		Prefix:        "rec",
		Sample:        `record(${1:input-device-id},${1:seconds-inactivity})`,
		Func: func(deviceID int, secondsInactivity int) interface{} {
			seq, err := melrose.CurrentDevice().Record(deviceID, time.Duration(secondsInactivity)*time.Second)
			if err != nil {
				notify.Print(notify.Error(err))
				return nil
			}
			return seq
		}}
	eval["undynamic"] = Function{
		Title:       "Undo Dynamic modifier",
		Description: "undynamic all the notes in a musical object",
		Prefix:      "und",
		Sample:      `undynamic(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot undynamic (%T) %v", value, value))
				return nil
			} else {
				return melrose.Undynamic{Target: s}
			}
		}}

	eval["flatten"] = Function{
		Title:       "Flatten modifier",
		Description: "flatten all operations on a musical object to a new sequence",
		Prefix:      "flat",
		Sample:      `flatten(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot flatten (%T) %v", value, value))
				return nil
			} else {
				return s.S()
			}
		}}

	eval["parallel"] = Function{
		Title:       "Parallel modifier",
		Description: "create a new sequence in which all notes of a musical object will be played in parallel",
		Prefix:      "par",
		Sample:      `parallel(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot parallel (%T) %v", value, value))
				return nil
			} else {
				return melrose.Parallel{Target: s}
			}
		}}
	// BEGIN Loop and control
	eval["loop"] = Function{
		Title:       "Loop creator",
		Description: "create a new loop",
		Prefix:      "loo",
		Sample:      `loop(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot loop (%T) %v", value, value))
				return nil
			} else {
				return &melrose.Loop{Target: s}
			}
		}}
	eval["run"] = Function{
		Title:         "Loop runner",
		Description:   "start loop(s). Ignore if it was running.",
		ControlsAudio: true,
		Prefix:        "run",
		Sample:        `run(${1:loop})`,
		Func: func(vars ...variable) interface{} {
			for _, each := range vars {
				l, ok := each.Value().(*melrose.Loop)
				if !ok {
					notify.Print(notify.Warningf("cannot start (%T) %v", l, l))
					continue
				}
				l.Start(melrose.CurrentDevice())
				notify.Print(notify.Infof("started loop: %s", each.Name))
			}
			return nil
		}}
	eval["stop"] = Function{
		Title:         "Loop stopper",
		Description:   "stop running loop(s). Ignore if it was stopped.",
		ControlsAudio: true,
		Prefix:        "sto",
		Sample:        `stop(${1:loop-or-empty})`,
		Func: func(vars ...variable) interface{} {
			if len(vars) == 0 {
				StopAllLoops(storage)
				return nil
			}
			for _, each := range vars {
				l, ok := each.Value().(*melrose.Loop)
				if !ok {
					notify.Print(notify.Warningf("cannot stop (%T) %v", l, l))
					continue
				}
				notify.Print(notify.Infof("stopping loop: %s", each.Name))
				l.Stop()
			}
			return nil
		}}
	// END Loop and control
	eval["channel"] = Function{
		Title:         "MIDI channel modifier",
		Description:   "select a MIDI channel, must be in [0..16]",
		ControlsAudio: true,
		Prefix:        "chan",
		Sample:        `channel(${1:number},${2:sequenceable})`,
		Func: func(midiChannel, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot decorate with channel (%T) %v", m, m))
				return nil
			}
			return melrose.ChannelSelector{Target: s, Number: getValueable(midiChannel)}
		}}
	eval["interval"] = Function{
		Title:         "Integer Interval creator",
		Description:   "create an integer repeating interval (from,to,by)",
		ControlsAudio: true,
		Prefix:        "int",
		Sample:        `interval(${1:from},${2:to},${3:by})`,
		Func: func(from, to, by interface{}) *melrose.Interval {
			return melrose.NewInterval(melrose.ToValueable(from), melrose.ToValueable(to), melrose.ToValueable(by))
		}}
	eval["indexmap"] = Function{
		Title:         "Integer Index Map modifier",
		Description:   "create a Mapper of Notes by index (1-based)",
		ControlsAudio: true,
		Prefix:        "ind",
		Sample:        `indexmap('${0:space-separated-1-based-indices}',${1:sequenceable})`,
		Func: func(indices string, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot create index mapper on (%T) %v", m, m))
				return nil
			}
			return melrose.NewIndexMapper(s, indices)
		}}
	return eval
}

func getSequenceable(v interface{}) (melrose.Sequenceable, bool) {
	if s, ok := v.(melrose.Sequenceable); ok {
		return s, ok
	}
	return nil, false
}

func getValueable(val interface{}) melrose.Valueable {
	if v, ok := val.(melrose.Valueable); ok {
		return v
	}
	return melrose.On(val)
}
<commit_msg>add stop to sample of loop<commit_after>package dsl

import (
	"strings"
	"time"

	"github.com/emicklei/melrose"
	"github.com/emicklei/melrose/notify"
)

// Syntax tells what language version this package is supporting.
const Syntax = "1.0" // major,minor

func IsCompatibleSyntax(s string) bool {
	if len(s) == 0 {
		// ignore syntax ; you are on your own
		return true
	}
	mm := strings.Split(Syntax, ".")
	ss := strings.Split(s, ".")
	return mm[0] == ss[0] && ss[1] <= mm[1]
}

type Function struct {
	Title         string
	Description   string
	Prefix        string // for autocomplete
	Sample        string
	ControlsAudio bool
	Func          interface{}
}

func EvalFunctions(storage VariableStorage) map[string]Function {
	eval := map[string]Function{}
	eval["chord"] = Function{
		Title:       "Chord creator",
		Description: "create a Chord",
		Prefix:      "cho",
		Sample:      `chord('${1:note}')`,
		Func: func(chord string) interface{} {
			c, err := melrose.ParseChord(chord)
			if err != nil {
				notify.Print(notify.Errorf("%v", err))
				return nil
			}
			return c
		}}

	eval["pitch"] = Function{
		Title:       "Pitch modifier",
		Description: "change the pitch with a delta of semitones",
		Prefix:      "pit",
		Sample:      `pitch(${1:semitones},${2:sequenceable})`,
		Func: func(semitones, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot pitch (%T) %v", m, m))
				return nil
			}
			return melrose.Pitch{Target: s, Semitones: getValueable(semitones)}
		}}

	eval["reverse"] = Function{
		Title:       "Reverse modifier",
		Description: "reverse the (groups of) notes in a sequence",
		Prefix:      "rev",
		Sample:      `reverse(${1:sequenceable})`,
		Func: func(m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot reverse (%T) %v", m, m))
				return nil
			}
			return melrose.Reverse{Target: s}
		}}

	eval["repeat"] = Function{
		Title:       "Repeat modifier",
		Description: "repeat the musical object a number of times",
		Prefix:      "rep",
		Sample:      `repeat(${1:times},${2:sequenceable})`,
		Func: func(howMany int, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot repeat (%T) %v", m, m))
				return nil
			}
			return melrose.Repeat{Target: s, Times: howMany}
		}}

	eval["join"] = Function{
		Title:       "Join modifier",
		Description: "join two or more musical objects",
		Prefix:      "joi",
		Sample:      `join(${1:first},${2:second})`,
		Func: func(playables ...interface{}) interface{} { // Note: return type cannot be EvaluationResult
			joined := []melrose.Sequenceable{}
			for _, p := range playables {
				if s, ok := getSequenceable(p); !ok {
					notify.Print(notify.Warningf("cannot join (%T) %v", p, p))
					return nil
				} else {
					joined = append(joined, s)
				}
			}
			return melrose.Join{List: joined}
		}}

	eval["bpm"] = Function{
		Title:         "Beats Per Minute",
		Description:   "get or set the Beats Per Minute value [1..300], default is 120",
		ControlsAudio: true,
		Prefix:        "bpm",
		Sample:        `bpm(${1:beats-per-minute})`,
		Func: func(f ...float64) interface{} {
			if len(f) == 0 {
				return melrose.CurrentDevice().BeatsPerMinute()
			}
			melrose.CurrentDevice().SetBeatsPerMinute(f[0])
			return nil
		}}

	eval["sequence"] = Function{
		Title:       "Sequence creator",
		Description: "create a Sequence from a string of notes",
		Prefix:      "seq",
		Sample:      `sequence('${1:space-separated-notes}')`,
		Func: func(s string) interface{} {
			sq, err := melrose.ParseSequence(s)
			if err != nil {
				notify.Print(notify.Error(err))
				return nil
			}
			return sq
		}}

	eval["note"] = Function{
		Title:       "Note creator",
		Prefix:      "no",
		Description: "Note, e.g. C 2G#5. =",
		Sample:      `note('${1:letter}')`,
		Func: func(s string) interface{} {
			n, err := melrose.ParseNote(s)
			if err != nil {
				notify.Print(notify.Error(err))
				return nil
			}
			return n
		}}

	eval["play"] = Function{
		Title:         "Player (foreground)",
		Description:   "play musical objects such as Note,Chord,Sequence,...",
		ControlsAudio: true,
		Prefix:        "pla",
		Sample:        `play(${1:sequenceable})`,
		Func: func(playables ...interface{}) interface{} {
			for _, p := range playables {
				if s, ok := getSequenceable(p); ok {
					melrose.CurrentDevice().Play(s, true)
				} else {
					notify.Print(notify.Warningf("cannot play (%T) %v", p, p))
				}
			}
			return nil
		}}

	eval["go"] = Function{
		Title:         "Player (background)",
		Description:   "play all musical objects in parallel",
		ControlsAudio: true,
		Prefix:        "go",
		Sample:        `go(${1:sequenceable})`,
		Func: func(playables ...interface{}) interface{} {
			for _, p := range playables {
				if s, ok := getSequenceable(p); ok {
					go melrose.CurrentDevice().Play(s, false)
				}
			}
			return nil
		}}

	eval["serial"] = Function{
		Title:       "Serial modifier",
		Description: "serialise any parallelisation of notes in a musical object",
		Prefix:      "ser",
		Sample:      `serial(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot serial (%T) %v", value, value))
				return nil
			} else {
				return melrose.Serial{Target: s}
			}
		}}

	eval["record"] = Function{
		Title:         "Recorder",
		Description:   "creates a recorded sequence of notes from device ID and stop after T seconds of inactivity",
		ControlsAudio: true,
		Prefix:        "rec",
		Sample:        `record(${1:input-device-id},${1:seconds-inactivity})`,
		Func: func(deviceID int, secondsInactivity int) interface{} {
			seq, err := melrose.CurrentDevice().Record(deviceID, time.Duration(secondsInactivity)*time.Second)
			if err != nil {
				notify.Print(notify.Error(err))
				return nil
			}
			return seq
		}}
	eval["undynamic"] = Function{
		Title:       "Undo Dynamic modifier",
		Description: "undynamic all the notes in a musical object",
		Prefix:      "und",
		Sample:      `undynamic(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot undynamic (%T) %v", value, value))
				return nil
			} else {
				return melrose.Undynamic{Target: s}
			}
		}}

	eval["flatten"] = Function{
		Title:       "Flatten modifier",
		Description: "flatten all operations on a musical object to a new sequence",
		Prefix:      "flat",
		Sample:      `flatten(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot flatten (%T) %v", value, value))
				return nil
			} else {
				return s.S()
			}
		}}

	eval["parallel"] = Function{
		Title:       "Parallel modifier",
		Description: "create a new sequence in which all notes of a musical object will be played in parallel",
		Prefix:      "par",
		Sample:      `parallel(${1:sequenceable})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot parallel (%T) %v", value, value))
				return nil
			} else {
				return melrose.Parallel{Target: s}
			}
		}}
	// BEGIN Loop and control
	eval["loop"] = Function{
		Title:       "Loop creator",
		Description: "create a new loop",
		Prefix:      "loo",
		Sample:      `loop(${1:sequenceable}) // stop(${2:variablename})`,
		Func: func(value interface{}) interface{} {
			if s, ok := getSequenceable(value); !ok {
				notify.Print(notify.Warningf("cannot loop (%T) %v", value, value))
				return nil
			} else {
				return &melrose.Loop{Target: s}
			}
		}}
	eval["run"] = Function{
		Title:         "Loop runner",
		Description:   "start loop(s). Ignore if it was running.",
		ControlsAudio: true,
		Prefix:        "run",
		Sample:        `run(${1:loop})`,
		Func: func(vars ...variable) interface{} {
			for _, each := range vars {
				l, ok := each.Value().(*melrose.Loop)
				if !ok {
					notify.Print(notify.Warningf("cannot start (%T) %v", l, l))
					continue
				}
				l.Start(melrose.CurrentDevice())
				notify.Print(notify.Infof("started loop: %s", each.Name))
			}
			return nil
		}}
	eval["stop"] = Function{
		Title:         "Loop stopper",
		Description:   "stop running loop(s). Ignore if it was stopped.",
		ControlsAudio: true,
		Prefix:        "sto",
		Sample:        `stop(${1:loop-or-empty})`,
		Func: func(vars ...variable) interface{} {
			if len(vars) == 0 {
				StopAllLoops(storage)
				return nil
			}
			for _, each := range vars {
				l, ok := each.Value().(*melrose.Loop)
				if !ok {
					notify.Print(notify.Warningf("cannot stop (%T) %v", l, l))
					continue
				}
				notify.Print(notify.Infof("stopping loop: %s", each.Name))
				l.Stop()
			}
			return nil
		}}
	// END Loop and control
	eval["channel"] = Function{
		Title:         "MIDI channel modifier",
		Description:   "select a MIDI channel, must be in [0..16]",
		ControlsAudio: true,
		Prefix:        "chan",
		Sample:        `channel(${1:number},${2:sequenceable})`,
		Func: func(midiChannel, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot decorate with channel (%T) %v", m, m))
				return nil
			}
			return melrose.ChannelSelector{Target: s, Number: getValueable(midiChannel)}
		}}
	eval["interval"] = Function{
		Title:         "Integer Interval creator",
		Description:   "create an integer repeating interval (from,to,by)",
		ControlsAudio: true,
		Prefix:        "int",
		Sample:        `interval(${1:from},${2:to},${3:by})`,
		Func: func(from, to, by interface{}) *melrose.Interval {
			return melrose.NewInterval(melrose.ToValueable(from), melrose.ToValueable(to), melrose.ToValueable(by))
		}}
	eval["indexmap"] = Function{
		Title:         "Integer Index Map modifier",
		Description:   "create a Mapper of Notes by index (1-based)",
		ControlsAudio: true,
		Prefix:        "ind",
		Sample:        `indexmap('${0:space-separated-1-based-indices}',${1:sequenceable})`,
		Func: func(indices string, m interface{}) interface{} {
			s, ok := getSequenceable(m)
			if !ok {
				notify.Print(notify.Warningf("cannot create index mapper on (%T) %v", m, m))
				return nil
			}
			return melrose.NewIndexMapper(s, indices)
		}}
	return eval
}

func getSequenceable(v interface{}) (melrose.Sequenceable, bool) {
	if s, ok := v.(melrose.Sequenceable); ok {
		return s, ok
	}
	return nil, false
}

func getValueable(val interface{}) melrose.Valueable {
	if v, ok := val.(melrose.Valueable); ok {
		return v
	}
	return melrose.On(val)
}
<|endoftext|>


<commit_before>package dtls

import (
	"testing"
	"net"
)

func TestClientWithOpenSSL(t *testing.T) {
	conn, err := net.Dial("udp", "127.0.0.1:4444")
	if err != nil {
		t.Fatal(err)
	}
	_, err = NewClient(conn, nil)
	if err != nil {
		t.Fatal(err)
	}
}

/*
func generateCerts() error {
	pk, err := rsa.GenerateKey(rand.Reader, 4096)
	if err != nil {
		return err
	}
	sn, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
	if err != nil {
		return err
	}
	tpl := x509.Certificate{
		SerialNumber: sn,
		Subject: pkix.Name{
			CommonName: "go-dtls",
		},
		IsCA: true,

		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(time.Minute),
		KeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		DNSNames: []string{"go-dtls"},
	}
	der, err := x509.CreateCertificate(rand.Reader, &tpl, &tpl, pk.PublicKey, pk)
	if err != nil {
		return err
	}
	dir, err := ioutil.TempDir("", "test")
	defer os.RemoveAll(dir)
}
*/
<commit_msg>disable openssl test<commit_after>package dtls

import (
	"testing"
	"net"
)

func _TestClientWithOpenSSL(t *testing.T) {
	conn, err := net.Dial("udp", "127.0.0.1:4444")
	if err != nil {
		t.Fatal(err)
	}
	_, err = NewClient(conn, nil)
	if err != nil {
		t.Fatal(err)
	}
}

/*
func generateCerts() error {
	pk, err := rsa.GenerateKey(rand.Reader, 4096)
	if err != nil {
		return err
	}
	sn, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
	if err != nil {
		return err
	}
	tpl := x509.Certificate{
		SerialNumber: sn,
		Subject: pkix.Name{
			CommonName: "go-dtls",
		},
		IsCA: true,

		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(time.Minute),
		KeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		DNSNames: []string{"go-dtls"},
	}
	der, err := x509.CreateCertificate(rand.Reader, &tpl, &tpl, pk.PublicKey, pk)
	if err != nil {
		return err
	}
	dir, err := ioutil.TempDir("", "test")
	defer os.RemoveAll(dir)
}
*/
<|endoftext|>


<commit_before>// (C) 1990-2016.  Robert W Solomon.  All rights reserved.
// ShowUtf-8 codes.  Based on utf8toascii, based on nocr.go

package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode/utf8"
	//
	"getcommandline"
)

const lastCompiled = "6 May 17"

//const openQuoteRune = 0xe2809c
//const closeQuoteRune = 0xe2809d
//const squoteRune = 0xe28099
//const emdashRune = 0xe28094
const openQuoteRune = 8220
const closeQuoteRune = 8221
const squoteRune = 8217
const opensquoteRune = 8216
const emdashRune = 8212
const endashRune = 8211
const bulletpointRune = 8226
const threedotsRune = 8230
const hyphenRune = 8208

const quoteString = "\""
const squoteString = "'"
const emdashStr = " -- "
const bulletpointStr = "--"

/*
   REVISION HISTORY
   ----------------
   17 Apr 17 -- Started writing nocr, based on rpn.go
   18 Apr 17 -- It worked yesterday.  Now I'll rename files as in Modula-2.
    5 May 17 -- Now will convert utf8 to ascii, based on nocr.go
	6 May 17 -- Need to know the utf8 codes before I can convert 'em.
	6 May 17 -- Added a flag -b for before to see the prev string to give me context for a new rune.
*/

func main() {
	var instr string
	//	var err error

	fmt.Println(" ShowUtf8.  Last compiled ", lastCompiled)
	fmt.Println()

	if len(os.Args) <= 1 {
		fmt.Println(" Usage: utf8toascii <filename> ")
		os.Exit(1)
	}

	commandline := getcommandline.GetCommandLineString()
	BaseFilename := filepath.Clean(commandline)
	InFilename := ""
	InFileExists := false
	Ext1Default := ".txt"
	//	OutFileSuffix := ".out"

	if strings.Contains(BaseFilename, ".") {
		InFilename = BaseFilename
		_, err := os.Stat(InFilename)
		if err == nil {
			InFileExists = true
		}
	} else {
		InFilename = BaseFilename + Ext1Default
		_, err := os.Stat(InFilename)
		if err == nil {
			InFileExists = true
		}
	}

	if !InFileExists {
		fmt.Println(" File ", BaseFilename, " or ", InFilename, " does not exist.  Exiting.")
		os.Exit(1)
	}

	InputFile, err := os.Open(InFilename)
	if err != nil {
		fmt.Println(" Error while opening ", InFilename, ".  Exiting.")
		os.Exit(1)
	}
	defer InputFile.Close()
	InBufioScanner := bufio.NewScanner(InputFile)
	linecounter := 0
	for InBufioScanner.Scan() {
		instr = InBufioScanner.Text() // does not include the trailing EOL char
		linecounter++
		runecount := utf8.RuneCountInString(instr)
		if len(instr) == runecount {
			continue
		} else { // a mismatch btwn instr length and rune count means that a multibyte rune is in this instr
			fmt.Print(" Line ", linecounter, " : ")
			for dnctr := runecount; dnctr > 0; dnctr-- {
				r, siz := utf8.DecodeRuneInString(instr) // front rune in r
				instr = instr[siz:]                      // chop off the first rune
				if r > 128 {
					fmt.Print(" r: ", r, ", siz: ", siz, "; ")
					if r == openQuoteRune {
						fmt.Print(" rune is opening", quoteString, "; ")
					} else if r == closeQuoteRune {
						fmt.Print(" rune is closing", quoteString, "; ")
					} else if r == squoteRune || r == opensquoteRune {
						fmt.Print(" rune is ", squoteString, "; ")
					} else if r == emdashRune || r == endashRune {
						fmt.Print(" rune is ", emdashStr, "; ")
					} else if r == bulletpointRune {
						fmt.Print(" rune is bulletpoint; ")
					} else if r == threedotsRune {
						fmt.Print(" rune is ... ; ")
					} else if r == hyphenRune {
						fmt.Print(" rune is hyphen; ")
					} else {
						fmt.Print(" rune is new ")
					}
				}
			}
			fmt.Println()
		}
	}

	//	InputFile.Close()
	fmt.Println()

} // main in ShowUtf8.go
/*
func check(e error) {
	if e != nil {
		panic(e)
	}
}
*/
<commit_msg>modified:   showutf8/showutf8.go -- still testing after flag code<commit_after>// (C) 1990-2016.  Robert W Solomon.  All rights reserved.
// ShowUtf-8 codes.  Based on utf8toascii, based on nocr.go

package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode/utf8"
	//
)

const lastCompiled = "6 May 17"

//const openQuoteRune = 0xe2809c
//const closeQuoteRune = 0xe2809d
//const squoteRune = 0xe28099
//const emdashRune = 0xe28094
const openQuoteRune = 8220
const closeQuoteRune = 8221
const squoteRune = 8217
const opensquoteRune = 8216
const emdashRune = 8212
const endashRune = 8211
const bulletpointRune = 8226
const threedotsRune = 8230
const hyphenRune = 8208

const quoteString = "\""
const squoteString = "'"
const emdashStr = " -- "
const bulletpointStr = "--"

/*
   REVISION HISTORY
   ----------------
   17 Apr 17 -- Started writing nocr, based on rpn.go
   18 Apr 17 -- It worked yesterday.  Now I'll rename files as in Modula-2.
    5 May 17 -- Now will convert utf8 to ascii, based on nocr.go
	6 May 17 -- Need to know the utf8 codes before I can convert 'em.
	6 May 17 -- Added a flag -a for after to see the rest of the string to give me context for a new rune.
*/

func main() {
	var instr string
	//	var err error

	fmt.Println(" ShowUtf8.  Last compiled ", lastCompiled)
	fmt.Println()

	if len(os.Args) <= 1 {
		fmt.Println(" Usage: utf8toascii <filename> ")
		os.Exit(1)
	}

	var afterflag = flag.Bool("a", false, "afterflag -- show string after rune.")
	var AfterFlag bool
	flag.BoolVar(&AfterFlag, "A", false, "AfterFlag -- show string after rune.")

	flag.Parse()

	After := *afterflag || AfterFlag

	commandline := flag.Arg(0)
	BaseFilename := filepath.Clean(commandline)
	InFilename := ""
	InFileExists := false
	Ext1Default := ".txt"
	//	OutFileSuffix := ".out"

	if strings.Contains(BaseFilename, ".") {
		InFilename = BaseFilename
		_, err := os.Stat(InFilename)
		if err == nil {
			InFileExists = true
		}
	} else {
		InFilename = BaseFilename + Ext1Default
		_, err := os.Stat(InFilename)
		if err == nil {
			InFileExists = true
		}
	}

	if !InFileExists {
		fmt.Println(" File ", BaseFilename, " or ", InFilename, " does not exist.  Exiting.")
		os.Exit(1)
	}

	InputFile, err := os.Open(InFilename)
	if err != nil {
		fmt.Println(" Error while opening ", InFilename, ".  Exiting.")
		os.Exit(1)
	}
	defer InputFile.Close()
	InBufioScanner := bufio.NewScanner(InputFile)
	linecounter := 0
	for InBufioScanner.Scan() {
		instr = InBufioScanner.Text() // does not include the trailing EOL char
		linecounter++
		runecount := utf8.RuneCountInString(instr)
		if len(instr) == runecount {
			continue
		} else { // a mismatch btwn instr length and rune count means that a multibyte rune is in this instr
			fmt.Print(" Line ", linecounter, " : ")
			for dnctr := runecount; dnctr > 0; dnctr-- {
				r, siz := utf8.DecodeRuneInString(instr) // front rune in r
				instr = instr[siz:]                      // chop off the first rune
				if r > 128 {
					fmt.Print(" r: ", r, ", siz: ", siz, "; ")
					if r == openQuoteRune {
						fmt.Print(" rune is opening", quoteString, "; ")
					} else if r == closeQuoteRune {
						fmt.Print(" rune is closing", quoteString, "; ")
					} else if r == squoteRune || r == opensquoteRune {
						fmt.Print(" rune is ", squoteString, "; ")
					} else if r == emdashRune || r == endashRune {
						fmt.Print(" rune is ", emdashStr, "; ")
					} else if r == bulletpointRune {
						fmt.Print(" rune is bulletpoint; ")
					} else if r == threedotsRune {
						fmt.Print(" rune is ... ; ")
					} else if r == hyphenRune {
						fmt.Print(" rune is hyphen; ")
					} else {
						fmt.Print(" rune is new, rest of input line is: ")
						if After {
							fmt.Println(instr)
						}
					}
				}
			}
			fmt.Println()
		}
	}

	//	InputFile.Close()
	fmt.Println()

} // main in ShowUtf8.go
/*
func check(e error) {
	if e != nil {
		panic(e)
	}
}
*/
<|endoftext|>


<commit_before>package dynamic

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
)

type Driver struct {
	builtin bool
	url     string
	hash    string
	name    string
}

func NewDriver(builtin bool, name, url, hash string) *Driver {
	d := &Driver{
		builtin: builtin,
		name:    name,
		url:     url,
		hash:    hash,
	}
	if d.builtin && !strings.HasPrefix(d.name, "docker-machine-driver-") {
		d.name = "docker-machine-driver-" + d.name
	}
	return d
}

func (d *Driver) Name() string {
	return d.name
}

func (d *Driver) Hash() string {
	return d.hash
}

func (d *Driver) Checksum() string {
	return d.name
}

func (d *Driver) FriendlyName() string {
	return strings.TrimPrefix(d.name, "docker-machine-driver-")
}

func (d *Driver) Remove() error {
	cacheFilePrefix := d.cacheFile()
	content, err := ioutil.ReadFile(cacheFilePrefix)
	if os.IsNotExist(err) {
		return nil
	}

	if err != nil {
		return err
	}

	dest := path.Join(binDir(), string(content))
	os.Remove(dest)
	os.Remove(cacheFilePrefix + "-" + string(content))
	os.Remove(cacheFilePrefix)

	return nil
}

func (d *Driver) Stage() error {
	if err := d.getError(); err != nil {
		return err
	}

	return d.setError(d.stage())
}

func (d *Driver) setError(err error) error {
	errFile := d.cacheFile() + ".error"

	if err != nil {
		ioutil.WriteFile(errFile, []byte(err.Error()), 0600)
	}
	return err
}

func (d *Driver) getError() error {
	errFile := d.cacheFile() + ".error"

	if content, err := ioutil.ReadFile(errFile); err == nil {
		logrus.Errorf("Returning previous error: %s", content)
		d.ClearError()
		return errors.New(string(content))
	}

	return nil
}

func (d *Driver) ClearError() {
	errFile := d.cacheFile() + ".error"
	os.Remove(errFile)
}

func (d *Driver) stage() error {
	if d.builtin {
		return nil
	}

	cacheFilePrefix := d.cacheFile()

	driverName, err := isInstalled(cacheFilePrefix)
	if err != nil || driverName != "" {
		d.name = driverName
		return err
	}

	tempFile, err := ioutil.TempFile("", "machine-driver")
	if err != nil {
		return err
	}
	defer os.Remove(tempFile.Name())
	defer tempFile.Close()

	hasher, err := getHasher(d.hash)
	if err != nil {
		return err
	}

	downloadDest := io.Writer(tempFile)
	if hasher != nil {
		downloadDest = io.MultiWriter(tempFile, hasher)
	}

	if err := d.download(downloadDest); err != nil {
		return err
	}

	if got, ok := compare(hasher, d.hash); !ok {
		return fmt.Errorf("Hash does not match, got %s, expected %s", got, d.hash)
	}

	if err := tempFile.Close(); err != nil {
		return err
	}

	driverName, err = d.copyBinary(cacheFilePrefix, tempFile.Name())
	if err != nil {
		return err
	}

	d.name = driverName
	return nil
}

func (d *Driver) Install() error {
	if d.builtin {
		return nil
	}

	f, err := os.OpenFile(path.Join(binDir(), d.name), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
	if err != nil {
		return err
	}
	defer f.Close()

	src, err := os.Open(d.srcBinName())
	if err != nil {
		return err
	}
	defer src.Close()

	logrus.Infof("Copying %s => %s", d.srcBinName(), path.Join(binDir(), d.name))
	_, err = io.Copy(f, src)
	return err
}

func isElf(input string) bool {
	f, err := os.Open(input)
	if err != nil {
		return false
	}
	defer f.Close()

	elf := make([]byte, 4)
	if _, err := f.Read(elf); err != nil {
		return false
	}

	return bytes.Compare(elf, []byte{0x7f, 0x45, 0x4c, 0x46}) == 0
}

func (d *Driver) copyBinary(cacheFile, input string) (string, error) {
	temp, err := ioutil.TempDir("", "machine-driver-extract")
	if err != nil {
		return "", err
	}
	defer os.RemoveAll(temp)

	file := ""
	driverName := ""

	if isElf(input) {
		file = input
		u, err := url.Parse(d.url)
		if err != nil {
			return "", err
		}
		driverName = strings.Split(path.Base(u.Path), "_")[0]
		if !strings.HasPrefix(driverName, "docker-machine-driver-") {
			return "", fmt.Errorf("Invalid URL %s, path should be of the format docker-machine-driver-*", d.url)
		}
	} else {
		if err := exec.Command("tar", "xvf", input, "-C", temp).Run(); err != nil {
			if err := exec.Command("unzip", "-o", input, "-d", temp).Run(); err != nil {
				return "", fmt.Errorf("Failed to extract")
			}
		}
	}

	filepath.Walk(temp, filepath.WalkFunc(func(p string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}

		if strings.HasPrefix(path.Base(p), "docker-machine-driver-") {
			file = p
		}

		return nil
	}))

	if file == "" {
		return "", fmt.Errorf("Failed to find machine driver in archive. There must be a file of form docker-machine-driver*")
	}

	if driverName == "" {
		driverName = path.Base(file)
	}
	f, err := os.Open(file)
	if err != nil {
		return "", err
	}
	defer f.Close()

	if err := os.MkdirAll(path.Dir(cacheFile), 0755); err != nil {
		return "", err
	}

	dest, err := os.Create(cacheFile + "-" + driverName)
	if err != nil {
		return "", err
	}
	defer dest.Close()

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

	logrus.Infof("Found driver %s", driverName)
	return driverName, ioutil.WriteFile(cacheFile, []byte(driverName), 0644)
}

func (d *Driver) srcBinName() string {
	return d.cacheFile() + "-" + d.name
}

func binDir() string {
	dest := os.Getenv("GMS_BIN_DIR")
	if dest != "" {
		return dest
	}
	return "/usr/local/bin"
}

func compare(hash hash.Hash, value string) (string, bool) {
	if hash == nil {
		return "", true
	}

	got := hex.EncodeToString(hash.Sum([]byte{}))
	expected := strings.TrimSpace(strings.ToLower(value))

	return got, got == expected
}

func getHasher(hash string) (hash.Hash, error) {
	switch len(hash) {
	case 0:
		return nil, nil
	case 32:
		return md5.New(), nil
	case 40:
		return sha1.New(), nil
	case 64:
		return sha256.New(), nil
	case 128:
		return sha512.New(), nil
	}

	return nil, fmt.Errorf("Invalid hash format: %s", hash)
}

func (d *Driver) download(dest io.Writer) error {
	logrus.Infof("Download %s", d.url)
	resp, err := http.Get(d.url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	_, err = io.Copy(dest, resp.Body)
	return err
}

func (d *Driver) cacheFile() string {
	key := sha256Bytes([]byte(d.url + d.hash))

	base := os.Getenv("CATTLE_HOME")
	if base == "" {
		base = "/var/lib/cattle"
	}

	return path.Join(base, "machine-drivers", key)
}

func isInstalled(file string) (string, error) {
	content, err := ioutil.ReadFile(file)
	if os.IsNotExist(err) {
		return "", nil
	}
	return strings.TrimSpace(string(content)), err
}

func sha256Bytes(content []byte) string {
	hash := sha256.New()
	io.Copy(hash, bytes.NewBuffer(content))
	return hex.EncodeToString(hash.Sum([]byte{}))
}
<commit_msg>Create /var/lib/cattle/machine-drivers on error<commit_after>package dynamic

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
)

type Driver struct {
	builtin bool
	url     string
	hash    string
	name    string
}

func NewDriver(builtin bool, name, url, hash string) *Driver {
	d := &Driver{
		builtin: builtin,
		name:    name,
		url:     url,
		hash:    hash,
	}
	if d.builtin && !strings.HasPrefix(d.name, "docker-machine-driver-") {
		d.name = "docker-machine-driver-" + d.name
	}
	return d
}

func (d *Driver) Name() string {
	return d.name
}

func (d *Driver) Hash() string {
	return d.hash
}

func (d *Driver) Checksum() string {
	return d.name
}

func (d *Driver) FriendlyName() string {
	return strings.TrimPrefix(d.name, "docker-machine-driver-")
}

func (d *Driver) Remove() error {
	cacheFilePrefix := d.cacheFile()
	content, err := ioutil.ReadFile(cacheFilePrefix)
	if os.IsNotExist(err) {
		return nil
	}

	if err != nil {
		return err
	}

	dest := path.Join(binDir(), string(content))
	os.Remove(dest)
	os.Remove(cacheFilePrefix + "-" + string(content))
	os.Remove(cacheFilePrefix)

	return nil
}

func (d *Driver) Stage() error {
	if err := d.getError(); err != nil {
		return err
	}

	return d.setError(d.stage())
}

func (d *Driver) setError(err error) error {
	errFile := d.cacheFile() + ".error"

	if err != nil {
		os.MkdirAll(path.Dir(errFile))
		ioutil.WriteFile(errFile, []byte(err.Error()), 0600)
	}
	return err
}

func (d *Driver) getError() error {
	errFile := d.cacheFile() + ".error"

	if content, err := ioutil.ReadFile(errFile); err == nil {
		logrus.Errorf("Returning previous error: %s", content)
		d.ClearError()
		return errors.New(string(content))
	}

	return nil
}

func (d *Driver) ClearError() {
	errFile := d.cacheFile() + ".error"
	os.Remove(errFile)
}

func (d *Driver) stage() error {
	if d.builtin {
		return nil
	}

	cacheFilePrefix := d.cacheFile()

	driverName, err := isInstalled(cacheFilePrefix)
	if err != nil || driverName != "" {
		d.name = driverName
		return err
	}

	tempFile, err := ioutil.TempFile("", "machine-driver")
	if err != nil {
		return err
	}
	defer os.Remove(tempFile.Name())
	defer tempFile.Close()

	hasher, err := getHasher(d.hash)
	if err != nil {
		return err
	}

	downloadDest := io.Writer(tempFile)
	if hasher != nil {
		downloadDest = io.MultiWriter(tempFile, hasher)
	}

	if err := d.download(downloadDest); err != nil {
		return err
	}

	if got, ok := compare(hasher, d.hash); !ok {
		return fmt.Errorf("Hash does not match, got %s, expected %s", got, d.hash)
	}

	if err := tempFile.Close(); err != nil {
		return err
	}

	driverName, err = d.copyBinary(cacheFilePrefix, tempFile.Name())
	if err != nil {
		return err
	}

	d.name = driverName
	return nil
}

func (d *Driver) Install() error {
	if d.builtin {
		return nil
	}

	f, err := os.OpenFile(path.Join(binDir(), d.name), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
	if err != nil {
		return err
	}
	defer f.Close()

	src, err := os.Open(d.srcBinName())
	if err != nil {
		return err
	}
	defer src.Close()

	logrus.Infof("Copying %s => %s", d.srcBinName(), path.Join(binDir(), d.name))
	_, err = io.Copy(f, src)
	return err
}

func isElf(input string) bool {
	f, err := os.Open(input)
	if err != nil {
		return false
	}
	defer f.Close()

	elf := make([]byte, 4)
	if _, err := f.Read(elf); err != nil {
		return false
	}

	return bytes.Compare(elf, []byte{0x7f, 0x45, 0x4c, 0x46}) == 0
}

func (d *Driver) copyBinary(cacheFile, input string) (string, error) {
	temp, err := ioutil.TempDir("", "machine-driver-extract")
	if err != nil {
		return "", err
	}
	defer os.RemoveAll(temp)

	file := ""
	driverName := ""

	if isElf(input) {
		file = input
		u, err := url.Parse(d.url)
		if err != nil {
			return "", err
		}
		driverName = strings.Split(path.Base(u.Path), "_")[0]
		if !strings.HasPrefix(driverName, "docker-machine-driver-") {
			return "", fmt.Errorf("Invalid URL %s, path should be of the format docker-machine-driver-*", d.url)
		}
	} else {
		if err := exec.Command("tar", "xvf", input, "-C", temp).Run(); err != nil {
			if err := exec.Command("unzip", "-o", input, "-d", temp).Run(); err != nil {
				return "", fmt.Errorf("Failed to extract")
			}
		}
	}

	filepath.Walk(temp, filepath.WalkFunc(func(p string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}

		if strings.HasPrefix(path.Base(p), "docker-machine-driver-") {
			file = p
		}

		return nil
	}))

	if file == "" {
		return "", fmt.Errorf("Failed to find machine driver in archive. There must be a file of form docker-machine-driver*")
	}

	if driverName == "" {
		driverName = path.Base(file)
	}
	f, err := os.Open(file)
	if err != nil {
		return "", err
	}
	defer f.Close()

	if err := os.MkdirAll(path.Dir(cacheFile), 0755); err != nil {
		return "", err
	}

	dest, err := os.Create(cacheFile + "-" + driverName)
	if err != nil {
		return "", err
	}
	defer dest.Close()

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

	logrus.Infof("Found driver %s", driverName)
	return driverName, ioutil.WriteFile(cacheFile, []byte(driverName), 0644)
}

func (d *Driver) srcBinName() string {
	return d.cacheFile() + "-" + d.name
}

func binDir() string {
	dest := os.Getenv("GMS_BIN_DIR")
	if dest != "" {
		return dest
	}
	return "/usr/local/bin"
}

func compare(hash hash.Hash, value string) (string, bool) {
	if hash == nil {
		return "", true
	}

	got := hex.EncodeToString(hash.Sum([]byte{}))
	expected := strings.TrimSpace(strings.ToLower(value))

	return got, got == expected
}

func getHasher(hash string) (hash.Hash, error) {
	switch len(hash) {
	case 0:
		return nil, nil
	case 32:
		return md5.New(), nil
	case 40:
		return sha1.New(), nil
	case 64:
		return sha256.New(), nil
	case 128:
		return sha512.New(), nil
	}

	return nil, fmt.Errorf("Invalid hash format: %s", hash)
}

func (d *Driver) download(dest io.Writer) error {
	logrus.Infof("Download %s", d.url)
	resp, err := http.Get(d.url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	_, err = io.Copy(dest, resp.Body)
	return err
}

func (d *Driver) cacheFile() string {
	key := sha256Bytes([]byte(d.url + d.hash))

	base := os.Getenv("CATTLE_HOME")
	if base == "" {
		base = "/var/lib/cattle"
	}

	return path.Join(base, "machine-drivers", key)
}

func isInstalled(file string) (string, error) {
	content, err := ioutil.ReadFile(file)
	if os.IsNotExist(err) {
		return "", nil
	}
	return strings.TrimSpace(string(content)), err
}

func sha256Bytes(content []byte) string {
	hash := sha256.New()
	io.Copy(hash, bytes.NewBuffer(content))
	return hex.EncodeToString(hash.Sum([]byte{}))
}
<|endoftext|>


<commit_before>package doozer

import (
	"doozer/ack"
	"doozer/client"
	"doozer/gc"
	"doozer/lock"
	"doozer/member"
	"doozer/paxos"
	"doozer/server"
	"doozer/session"
	"doozer/store"
	"doozer/util"
	"doozer/web"
	"net"
	"os"
)

const (
	alpha           = 50
	pulseInterval   = 1e9
	timeout         = 60e9 // 60s
)

const slot = "/doozer/slot"

var slots = store.MustCompileGlob("/doozer/slot/*")

func Main(clusterName, attachAddr string, udpConn net.PacketConn, listener, webListener net.Listener) {
	logger := util.NewLogger("main")

	var err os.Error

	listenAddr := listener.Addr().String()

	var activateSeqn int64
	cal := make(chan bool, 1)
	useSelf := make(chan bool, 1)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	if attachAddr == "" { // we are the only node in a new cluster
		set(st, "/doozer/info/"+self+"/public-addr", listenAddr, store.Missing)
		set(st, "/doozer/info/"+self+"/hostname", os.Getenv("HOSTNAME"), store.Missing)
		set(st, "/doozer/members/"+self, listenAddr, store.Missing)
		set(st, "/doozer/slot/"+"1", self, store.Missing)
		set(st, "/ping", "pong", store.Missing)

		cal <- true
		useSelf <- true

		cl = client.New("local", listenAddr) // TODO use real cluster name
	} else {
		cl = client.New("local", attachAddr) // TODO use real cluster name

		path := "/doozer/info/" + self + "/public-addr"
		_, err = cl.Set(path, store.Clobber, []byte(listenAddr))
		if err != nil {
			panic(err)
		}

		path = "/doozer/info/" + self + "/hostname"
		_, err = cl.Set(path, store.Clobber, []byte(os.Getenv("HOSTNAME")))
		if err != nil {
			panic(err)
		}

		joinSeqn, snap, err := cl.Join(self, listenAddr)
		if err != nil {
			panic(err)
		}

		done := make(chan int)
		st.Ops <- store.Op{1, snap}

		go advanceUntil(cl, done)

		go func() {
			st.Sync(joinSeqn + alpha)
			close(done)

			activateSeqn = activate(st, self, cl)
			cal <- true

			done = make(chan int)
			go advanceUntil(cl, done)
			st.Sync(activateSeqn + alpha)
			close(done)
			useSelf <- true
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}

	acker := ack.Ackify(udpConn)

	mg := paxos.NewManager(self, alpha, st, paxos.Encoder{acker})

	if attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		n := <-st.Seqns
		for i := n + 1; i < n+alpha; i++ {
			st.Ops <- store.Op{i, store.Nop}
		}
	}

	live := make(chan string, 64)
	shun := make(chan string, 3) // sufficient for a cluster of 7

	go member.Clean(shun, st, mg)
	go member.Timeout(live, shun, listenAddr, timeout)

	go func() {
		<-cal
		go lock.Clean(st, mg)
		go session.Clean(st, mg)
		go gc.Pulse(self, st.Seqns, mg, pulseInterval)
		go gc.Clean(st)
	}()

	sv := &server.Server{listenAddr, st, mg, self}

	go sv.Serve(listener, useSelf)

	if webListener != nil {
		web.Store = st
		web.ClusterName = clusterName
		go web.Serve(webListener)
	}

	decoder := paxos.Decoder{mg}
	for {
		data, addr, err := acker.ReadFrom()
		if err == os.EINVAL {
			break
		}
		if err != nil {
			logger.Println(err)
			continue
		}

		// Update liveness time stamp for this addr
		live <- addr

		decoder.WriteFrom(addr, data)
	}
}

func activate(st *store.Store, self string, c *client.Client) (seqn int64) {
	logger := util.NewLogger("activate")
	w := store.NewWatch(st, slots)
	var err os.Error

	for _, base := range store.Getdir(st, slot) {
		p := slot + "/" + base
		v, cas := st.Get(p)
		if cas != store.Dir && v[0] == "" {
			seqn, err = c.Set(p, cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}

			w.Stop()
			close(w.C)
			break
		}
	}

	for ev := range w.C {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			seqn, err = c.Set(ev.Path, ev.Cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}
			w.Stop()
			close(w.C)
		}
	}

	return seqn
}

func advanceUntil(cl *client.Client, done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		cl.Noop()
	}
}

func set(st *store.Store, path, body string, cas int64) {
	mut := store.MustEncodeSet(path, body, cas)
	st.Ops <- store.Op{1 + <-st.Seqns, mut}
}
<commit_msg>indicate version in node info<commit_after>package doozer

import (
	"doozer/ack"
	"doozer/client"
	"doozer/gc"
	"doozer/lock"
	"doozer/member"
	"doozer/paxos"
	"doozer/server"
	"doozer/session"
	"doozer/store"
	"doozer/util"
	"doozer/web"
	"net"
	"os"
)

const (
	alpha           = 50
	pulseInterval   = 1e9
	timeout         = 60e9 // 60s
)

const slot = "/doozer/slot"

var slots = store.MustCompileGlob("/doozer/slot/*")

func Main(clusterName, attachAddr string, udpConn net.PacketConn, listener, webListener net.Listener) {
	logger := util.NewLogger("main")

	var err os.Error

	listenAddr := listener.Addr().String()

	var activateSeqn int64
	cal := make(chan bool, 1)
	useSelf := make(chan bool, 1)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	if attachAddr == "" { // we are the only node in a new cluster
		set(st, "/doozer/info/"+self+"/public-addr", listenAddr, store.Missing)
		set(st, "/doozer/info/"+self+"/hostname", os.Getenv("HOSTNAME"), store.Missing)
		set(st, "/doozer/info/"+self+"/version", Version, store.Missing)
		set(st, "/doozer/members/"+self, listenAddr, store.Missing)
		set(st, "/doozer/slot/"+"1", self, store.Missing)
		set(st, "/ping", "pong", store.Missing)

		cal <- true
		useSelf <- true

		cl = client.New("local", listenAddr) // TODO use real cluster name
	} else {
		cl = client.New("local", attachAddr) // TODO use real cluster name

		path := "/doozer/info/" + self + "/public-addr"
		_, err = cl.Set(path, store.Clobber, []byte(listenAddr))
		if err != nil {
			panic(err)
		}

		path = "/doozer/info/" + self + "/hostname"
		_, err = cl.Set(path, store.Clobber, []byte(os.Getenv("HOSTNAME")))
		if err != nil {
			panic(err)
		}

		path = "/doozer/info/" + self + "/version"
		_, err = cl.Set(path, store.Clobber, []byte(Version))
		if err != nil {
			panic(err)
		}

		joinSeqn, snap, err := cl.Join(self, listenAddr)
		if err != nil {
			panic(err)
		}

		done := make(chan int)
		st.Ops <- store.Op{1, snap}

		go advanceUntil(cl, done)

		go func() {
			st.Sync(joinSeqn + alpha)
			close(done)

			activateSeqn = activate(st, self, cl)
			cal <- true

			done = make(chan int)
			go advanceUntil(cl, done)
			st.Sync(activateSeqn + alpha)
			close(done)
			useSelf <- true
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}

	acker := ack.Ackify(udpConn)

	mg := paxos.NewManager(self, alpha, st, paxos.Encoder{acker})

	if attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		n := <-st.Seqns
		for i := n + 1; i < n+alpha; i++ {
			st.Ops <- store.Op{i, store.Nop}
		}
	}

	live := make(chan string, 64)
	shun := make(chan string, 3) // sufficient for a cluster of 7

	go member.Clean(shun, st, mg)
	go member.Timeout(live, shun, listenAddr, timeout)

	go func() {
		<-cal
		go lock.Clean(st, mg)
		go session.Clean(st, mg)
		go gc.Pulse(self, st.Seqns, mg, pulseInterval)
		go gc.Clean(st)
	}()

	sv := &server.Server{listenAddr, st, mg, self}

	go sv.Serve(listener, useSelf)

	if webListener != nil {
		web.Store = st
		web.ClusterName = clusterName
		go web.Serve(webListener)
	}

	decoder := paxos.Decoder{mg}
	for {
		data, addr, err := acker.ReadFrom()
		if err == os.EINVAL {
			break
		}
		if err != nil {
			logger.Println(err)
			continue
		}

		// Update liveness time stamp for this addr
		live <- addr

		decoder.WriteFrom(addr, data)
	}
}

func activate(st *store.Store, self string, c *client.Client) (seqn int64) {
	logger := util.NewLogger("activate")
	w := store.NewWatch(st, slots)
	var err os.Error

	for _, base := range store.Getdir(st, slot) {
		p := slot + "/" + base
		v, cas := st.Get(p)
		if cas != store.Dir && v[0] == "" {
			seqn, err = c.Set(p, cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}

			w.Stop()
			close(w.C)
			break
		}
	}

	for ev := range w.C {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			seqn, err = c.Set(ev.Path, ev.Cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}
			w.Stop()
			close(w.C)
		}
	}

	return seqn
}

func advanceUntil(cl *client.Client, done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		cl.Noop()
	}
}

func set(st *store.Store, path, body string, cas int64) {
	mut := store.MustEncodeSet(path, body, cas)
	st.Ops <- store.Op{1 + <-st.Seqns, mut}
}
<|endoftext|>


<commit_before>package time

import (
	"github.com/ready-steady/simulation/system"
)

// List represents a list scheduler.
type List struct {
	platform    *system.Platform
	application *system.Application
	roots       []uint
}

// NewList creates a new list scheduler for the given platform and application.
func NewList(platform *system.Platform, application *system.Application) *List {
	return &List{
		platform:    platform,
		application: application,
		roots:       application.Roots(),
	}
}

// Compute constructs a schedule according to the given priority vector.
// The length of this vector equals to the number of tasks in the system, and
// smaller values correspond to higher priorities.
func (l *List) Compute(priority []float64) *Schedule {
	cores := l.platform.Cores
	tasks := l.application.Tasks

	nc := uint(len(cores))
	nt := uint(len(tasks))

	mapping := make([]uint, nt)
	order := make([]uint, nt)
	start := make([]float64, nt)
	finish := make([]float64, nt)

	scheduled := make([]bool, nt)

	ctime := make([]float64, nc)
	ttime := make([]float64, nt)

	var i, j, k, cid, tid, kid, pid uint
	var span float64
	var ready bool

	size := uint(len(l.roots))

	// According to the benchmarks, keeping it sorted is not worth it.
	pool := make([]uint, size, nt)
	copy(pool, l.roots)

	for size > 0 {
		// Find the earliest available core.
		cid = 0
		for i = 1; i < nc; i++ {
			if ctime[i] < ctime[cid] {
				cid = i
			}
		}

		// Find the highest priority task.
		j, tid = 0, pool[0]
		for i = 1; i < size; i++ {
			if priority[pool[i]] < priority[tid] {
				j, tid = i, pool[i]
			}
		}

		// Remove the task from the pool.
		copy(pool[j:], pool[j+1:])
		pool = pool[:size-1]

		mapping[tid] = cid
		order[k] = tid
		k++
		if ctime[cid] > ttime[tid] {
			start[tid] = ctime[cid]
		} else {
			start[tid] = ttime[tid]
		}
		finish[tid] = start[tid] + cores[cid].Time[tasks[tid].Type]

		scheduled[tid] = true

		// Update the time when the core is again available.
		ctime[cid] = finish[tid]

		if span < finish[tid] {
			span = finish[tid]
		}

		for _, kid = range tasks[tid].Children {
			// Update the time when the child can potentially start executing.
			if ttime[kid] < finish[tid] {
				ttime[kid] = finish[tid]
			}

			// Push the child into the pool if it has become ready for
			// scheduling, that is, if all its parents have been scheduled.
			ready = true

			for _, pid = range tasks[kid].Parents {
				if !scheduled[pid] {
					ready = false
					break
				}
			}

			if !ready {
				continue
			}

			pool = append(pool, kid)
		}

		size = uint(len(pool))
	}

	return &Schedule{
		Mapping: mapping,
		Order:   order,
		Start:   start,
		Finish:  finish,
		Span:    span,
	}
}

// Delay constructs a new schedule based on an old one by adding a delay to the
// execution time of the tasks.
func (l *List) Delay(schedule *Schedule, delay []float64) *Schedule {
	cores := l.platform.Cores
	tasks := l.application.Tasks

	nt := uint(len(tasks))

	duration := make([]float64, nt)

	for i := uint(0); i < nt; i++ {
		tid := schedule.Order[i]
		cid := schedule.Mapping[tid]
		duration[tid] = cores[cid].Time[tasks[tid].Type] + delay[tid]
	}

	return l.Update(schedule, duration)
}

// Update constructs a new schedule based on an old one by setting the fixing
// the execution times of the tasks to new values.
func (l *List) Update(schedule *Schedule, duration []float64) *Schedule {
	tasks := l.application.Tasks

	nc := uint(len(l.platform.Cores))
	nt := uint(len(tasks))

	start := make([]float64, nt)
	finish := make([]float64, nt)

	ctime := make([]float64, nc)
	ttime := make([]float64, nt)

	span := 0.0

	for i := uint(0); i < nt; i++ {
		tid := schedule.Order[i]
		cid := schedule.Mapping[tid]

		if ctime[cid] > ttime[tid] {
			start[tid] = ctime[cid]
		} else {
			start[tid] = ttime[tid]
		}
		finish[tid] = start[tid] + duration[tid]

		ctime[cid] = finish[tid]
		if span < finish[tid] {
			span = finish[tid]
		}

		for _, kid := range tasks[tid].Children {
			if ttime[kid] < finish[tid] {
				ttime[kid] = finish[tid]
			}
		}
	}

	return &Schedule{
		// FIXME: Do not be greedy! Make a copy!
		Mapping: schedule.Mapping,
		Order:   schedule.Order,
		Start:   start,
		Finish:  finish,
		Span:    span,
	}
}
<commit_msg>time: fix typos in descriptions<commit_after>package time

import (
	"github.com/ready-steady/simulation/system"
)

// List represents a list scheduler.
type List struct {
	platform    *system.Platform
	application *system.Application
	roots       []uint
}

// NewList creates a new list scheduler for the given platform and application.
func NewList(platform *system.Platform, application *system.Application) *List {
	return &List{
		platform:    platform,
		application: application,
		roots:       application.Roots(),
	}
}

// Compute constructs a schedule according to the given priority vector. The
// length of this vector equals to the number of tasks in the system, and
// smaller values correspond to higher priorities.
func (l *List) Compute(priority []float64) *Schedule {
	cores := l.platform.Cores
	tasks := l.application.Tasks

	nc := uint(len(cores))
	nt := uint(len(tasks))

	mapping := make([]uint, nt)
	order := make([]uint, nt)
	start := make([]float64, nt)
	finish := make([]float64, nt)

	scheduled := make([]bool, nt)

	ctime := make([]float64, nc)
	ttime := make([]float64, nt)

	var i, j, k, cid, tid, kid, pid uint
	var span float64
	var ready bool

	size := uint(len(l.roots))

	// According to the benchmarks, keeping it sorted is not worth it.
	pool := make([]uint, size, nt)
	copy(pool, l.roots)

	for size > 0 {
		// Find the earliest available core.
		cid = 0
		for i = 1; i < nc; i++ {
			if ctime[i] < ctime[cid] {
				cid = i
			}
		}

		// Find the highest priority task.
		j, tid = 0, pool[0]
		for i = 1; i < size; i++ {
			if priority[pool[i]] < priority[tid] {
				j, tid = i, pool[i]
			}
		}

		// Remove the task from the pool.
		copy(pool[j:], pool[j+1:])
		pool = pool[:size-1]

		mapping[tid] = cid
		order[k] = tid
		k++
		if ctime[cid] > ttime[tid] {
			start[tid] = ctime[cid]
		} else {
			start[tid] = ttime[tid]
		}
		finish[tid] = start[tid] + cores[cid].Time[tasks[tid].Type]

		scheduled[tid] = true

		// Update the time when the core is again available.
		ctime[cid] = finish[tid]

		if span < finish[tid] {
			span = finish[tid]
		}

		for _, kid = range tasks[tid].Children {
			// Update the time when the child can potentially start executing.
			if ttime[kid] < finish[tid] {
				ttime[kid] = finish[tid]
			}

			// Push the child into the pool if it has become ready for
			// scheduling, that is, if all its parents have been scheduled.
			ready = true

			for _, pid = range tasks[kid].Parents {
				if !scheduled[pid] {
					ready = false
					break
				}
			}

			if !ready {
				continue
			}

			pool = append(pool, kid)
		}

		size = uint(len(pool))
	}

	return &Schedule{
		Mapping: mapping,
		Order:   order,
		Start:   start,
		Finish:  finish,
		Span:    span,
	}
}

// Delay constructs a new schedule based on an old one by adding a delay to the
// execution time of the tasks.
func (l *List) Delay(schedule *Schedule, delay []float64) *Schedule {
	cores := l.platform.Cores
	tasks := l.application.Tasks

	nt := uint(len(tasks))

	duration := make([]float64, nt)

	for i := uint(0); i < nt; i++ {
		tid := schedule.Order[i]
		cid := schedule.Mapping[tid]
		duration[tid] = cores[cid].Time[tasks[tid].Type] + delay[tid]
	}

	return l.Update(schedule, duration)
}

// Update constructs a new schedule based on an old one by setting the execution
// times of the tasks to new values.
func (l *List) Update(schedule *Schedule, duration []float64) *Schedule {
	tasks := l.application.Tasks

	nc := uint(len(l.platform.Cores))
	nt := uint(len(tasks))

	start := make([]float64, nt)
	finish := make([]float64, nt)

	ctime := make([]float64, nc)
	ttime := make([]float64, nt)

	span := 0.0

	for i := uint(0); i < nt; i++ {
		tid := schedule.Order[i]
		cid := schedule.Mapping[tid]

		if ctime[cid] > ttime[tid] {
			start[tid] = ctime[cid]
		} else {
			start[tid] = ttime[tid]
		}
		finish[tid] = start[tid] + duration[tid]

		ctime[cid] = finish[tid]
		if span < finish[tid] {
			span = finish[tid]
		}

		for _, kid := range tasks[tid].Children {
			if ttime[kid] < finish[tid] {
				ttime[kid] = finish[tid]
			}
		}
	}

	return &Schedule{
		// FIXME: Do not be greedy! Make a copy!
		Mapping: schedule.Mapping,
		Order:   schedule.Order,
		Start:   start,
		Finish:  finish,
		Span:    span,
	}
}
<|endoftext|>


<commit_before>//+build !windows

/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.

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

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

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

package simulator

import "syscall"

func (ds *Datastore) stat() error {
	info := ds.Info.GetDatastoreInfo()
	var stat syscall.Statfs_t

	err := syscall.Statfs(info.Url, &stat)
	if err != nil {
		return err
	}

	bsize := uint64(stat.Bsize) / 512

	info.FreeSpace = int64(stat.Bfree*bsize) >> 1

	ds.Summary.FreeSpace = info.FreeSpace
	ds.Summary.Capacity = int64(stat.Blocks*bsize) >> 1

	return nil
}
<commit_msg>update datastore capacity and free space when it is started<commit_after>//+build !windows

/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.

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

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

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

package simulator

import "syscall"

func (ds *Datastore) stat() error {
	info := ds.Info.GetDatastoreInfo()
	var stat syscall.Statfs_t

	err := syscall.Statfs(info.Url, &stat)
	if err != nil {
		return err
	}

	info.FreeSpace = int64(stat.Bfree * uint64(stat.Bsize))

	ds.Summary.FreeSpace = info.FreeSpace
	ds.Summary.Capacity = int64(stat.Blocks * uint64(stat.Bsize))

	return nil
}
<|endoftext|>


<commit_before>package main

/*
 * Addresses:
 * Can be used in conjunction with below fix to start ansible with extra-vars parameter without falling over.
 * https://github.com/mitchellh/vagrant/issues/6726
 *
 * References:
 * http://nathanleclaire.com/blog/2014/12/29/shelled-out-commands-in-golang/
 * http://www.darrencoxall.com/golang/executing-commands-in-go/
 * https://groups.google.com/forum/#!msg/golang-nuts/cnG-N3KcoUU/4vR5MIuFDjYJ
 *
 */

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func main() {

	var wrapperExecutableName = filepath.Base(os.Args[0])
	var extension = filepath.Ext(wrapperExecutableName)
	var executable = wrapperExecutableName[0 : len(wrapperExecutableName)-len(extension)]
	//	pwd, err := os.Getwd()

	args := make([]string, len(os.Args[1:])+1, len(os.Args[1:])+1)
	args[0] = "/usr/bin/" + executable
	for i, a := range os.Args[1:] {
		// fmt.Printf("arg[%d] is: %s\n", i+1, a)
		args[i+1] = a
	}
	cmd := exec.Command("c:\\cygwin\\bin\\bash.exe", "-c", strings.Join(args[:], " "))

	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating "+executable+" wrapper stdout pipeline", err)
		os.Exit(1)
	}

	// echo stdin back to console
	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			fmt.Printf("%s\n", scanner.Text())
		}
	}()

	err = cmd.Start()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error starting "+executable+" wrapper", err)
		os.Exit(1)
	}

	err = cmd.Wait()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error waiting for "+executable+" wrapper to finish", err)
		os.Exit(1)
	}

	// all good can finish now
	os.Exit(0)

}
<commit_msg>fixed stderr output<commit_after>package main

/*
 * Addresses:
 * Can be used in conjunction with below fix to start ansible with extra-vars parameter without falling over.
 * https://github.com/mitchellh/vagrant/issues/6726
 *
 * References:
 * http://nathanleclaire.com/blog/2014/12/29/shelled-out-commands-in-golang/
 * http://www.darrencoxall.com/golang/executing-commands-in-go/
 * https://groups.google.com/forum/#!msg/golang-nuts/cnG-N3KcoUU/4vR5MIuFDjYJ
 *
 */

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func main() {

	var wrapperExecutableName = filepath.Base(os.Args[0])
	var extension = filepath.Ext(wrapperExecutableName)
	var executable = wrapperExecutableName[0 : len(wrapperExecutableName)-len(extension)]
	//	pwd, err := os.Getwd()

	args := make([]string, len(os.Args[1:])+1, len(os.Args[1:])+1)
	args[0] = "/usr/bin/" + executable
	for i, a := range os.Args[1:] {
		// fmt.Printf("arg[%d] is: %s\n", i+1, a)
		args[i+1] = a
	}
	cmd := exec.Command("c:\\cygwin\\bin\\bash.exe", "-c", strings.Join(args[:], " "))

	// echo stdin back to console
	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating "+executable+" wrapper stdout pipeline", err)
		os.Exit(1)
	}

	outScanner := bufio.NewScanner(cmdReader)
	go func() {
		for outScanner.Scan() {
			fmt.Printf("%s\n", outScanner.Text())
		}
	}()

	// echo stderr back to console
	errReader, err := cmd.StderrPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating "+executable+" wrapper stderr pipeline", err)
		os.Exit(1)
	}

	errScanner := bufio.NewScanner(errReader)
	go func() {
		for errScanner.Scan() {
			fmt.Fprintln(os.Stderr, errScanner.Text())
		}
	}()

	err = cmd.Start()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error starting "+executable+" wrapper", err)
		os.Exit(1)
	}

	err = cmd.Wait()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error waiting for "+executable+" wrapper to finish", err)
		os.Exit(1)
	}

	// all good can finish now
	os.Exit(0)

}
<|endoftext|>


<commit_before>package tokenex

import "encoding/json"

type (
	TokenExResponse struct {
		Error           string
		ReferenceNumber string
		Success         bool
	}

	TokenResponse struct {
		TokenExResponse
		Token string
	}

	ValueResponse struct {
		TokenExResponse
		Value string
	}

	ValidateResponse struct {
		TokenExResponse
		Valid bool
	}

	DeleteResponse struct {
		TokenExResponse
	}
)

func Tokenize(data string, tokenScheme int) TokenResponse {
	tData := map[string]interface{}{
		"Data":        data,
		"TokenScheme": tokenScheme,
	}
	data = request("Tokenize", tData)
	response := TokenResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Detokenize(token string) ValueResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("Detokenize", tData)
	response := ValueResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Validate(token string) ValidateResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("ValidateToken", tData)
	response := ValidateResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Delete(token string) DeleteResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("DeleteToken", tData)
	response := DeleteResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}
<commit_msg>:penguin: more cleanups<commit_after>package tokenex

import "encoding/json"

type (
	tokenexResponse struct {
		Error           string
		ReferenceNumber string
		Success         bool
	}

	tokenResponse struct {
		tokenexResponse
		Token string
	}

	valueResponse struct {
		tokenexResponse
		Value string
	}

	validateResponse struct {
		tokenexResponse
		Valid bool
	}

	deleteResponse struct {
		tokenexResponse
	}
)

func Tokenize(data string, tokenScheme int) tokenResponse {
	tData := map[string]interface{}{
		"Data":        data,
		"TokenScheme": tokenScheme,
	}
	data = request("Tokenize", tData)
	response := tokenResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Detokenize(token string) valueResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("Detokenize", tData)
	response := valueResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Validate(token string) validateResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("ValidateToken", tData)
	response := validateResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Delete(token string) deleteResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("DeleteToken", tData)
	response := deleteResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}
<|endoftext|>


<commit_before>package multipass

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/mholt/caddy/caddyhttp/httpserver"

	jose "gopkg.in/square/go-jose.v1"
)

// Portable errors
var (
	ErrInvalidToken = errors.New("invalid token")
)

// Auth wraps a Multipass instance to be used by the caddy web server.
type Auth struct {
	*Multipass
	Next httpserver.Handler
}

// Rule holds the directive options parsed from a Caddyfile.
type Rule struct {
	Basepath  string
	Expires   time.Duration
	Resources []string
	Handles   []string

	SMTPAddr, SMTPUser, SMTPPass string
	MailFrom, MailTmpl           string
}

// Multipass implements the http.Handler interface which can handle
// authentication and authorization of users and resources using signed JWT.
type Multipass struct {
	Resources []string
	Basepath  string
	SiteAddr  string
	Expires   time.Duration

	Handler HandleService
	signer  jose.Signer
	key     *rsa.PrivateKey
	tmpl    *template.Template
	mux     *http.ServeMux
}

// NewMultipassFromRule return a new instance of Multipass from the given Rule.
// Returned error will most likely be parser errors.
func NewMultipassFromRule(r Rule) (*Multipass, error) {
	m, err := NewMultipass()
	if err != nil {
		return nil, err
	}
	if len(r.Resources) > 0 {
		m.Resources = r.Resources
	}
	if len(r.Basepath) > 0 {
		m.Basepath = path.Join("/", r.Basepath)
	}
	if r.Expires > 0 {
		m.Expires = r.Expires
	}

	// Set EmailHandler options
	opt := &EmailOptions{
		r.SMTPAddr,
		r.SMTPUser,
		r.SMTPPass,
		r.MailFrom,
	}
	handler, err := NewEmailHandler(opt)
	if err != nil {
		return nil, err
	}

	for _, handle := range r.Handles {
		handler.Register(handle)
	}
	m.Handler = handler

	mux := http.NewServeMux()
	mux.HandleFunc(path.Join(m.Basepath, "/"), m.rootHandler)
	mux.HandleFunc(path.Join(m.Basepath, "/login"), m.loginHandler)
	mux.HandleFunc(path.Join(m.Basepath, "/confirm"), m.confirmHandler)
	mux.HandleFunc(path.Join(m.Basepath, "/signout"), m.signoutHandler)
	mux.HandleFunc(path.Join(m.Basepath, "/pub.cer"), m.publickeyHandler)
	m.mux = mux

	tmpl, err := loadTemplates()
	if err != nil {
		return nil, err
	}
	m.tmpl = tmpl

	return m, nil
}

// NewMultipass returns a new instance of Multipass with reasonalble defaults
// like a 2048 bit RSA key pair, /multipass as basepath, 24 hours before a
// token will expire.
func NewMultipass() (*Multipass, error) {
	pk, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}
	signer, err := jose.NewSigner(jose.PS512, pk)
	if err != nil {
		return nil, err
	}
	return &Multipass{
		Resources: []string{"/"},
		Basepath:  "/multipass",
		Expires:   time.Hour * 24,
		key:       pk,
		signer:    signer,
	}, nil
}

// Claims are part of the JSON web token
type Claims struct {
	Handle    string   `json:"handle"`
	Resources []string `json:"resources"`
	Expires   int64    `json:"exp"`
}

// ServeHTTP satisfies the ServeHTTP interface
func (m *Multipass) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h, p := m.mux.Handler(r); len(p) > 0 {
		h.ServeHTTP(w, r)
		return
	}
	http.NotFound(w, r)
}

// rootHandler handles the "/" path of the Multipass handler.
// Shows login page when no JWT present
// Show continue or signout page when JWT is valid
// Show token invalid page when JWT is invalid
func (m *Multipass) rootHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {

		// Regular login page
		p := &page{
			Page:        loginPage,
			LoginPath:   path.Join(m.Basepath, "login"),
			SignoutPath: path.Join(m.Basepath, "signout"),
		}

		// Show login page when there is no token
		tokenStr, err := extractToken(r)
		if err != nil {
			if s := r.Referer(); !httpserver.Path(s).Matches(m.Basepath) {
				p.NextURL = s
			}
			m.tmpl.ExecuteTemplate(w, "page", p)
			return
		}
		var claims *Claims
		if claims, err = validateToken(tokenStr, m.key.PublicKey); err != nil {
			p.Page = tokenInvalidPage
			if s := r.Referer(); !httpserver.Path(s).Matches(m.Basepath) {
				p.NextURL = s
			}
			m.tmpl.ExecuteTemplate(w, "page", p)
			return
		}
		// Authorize handle claim
		if ok := m.Handler.Listed(claims.Handle); !ok {
			p.Page = tokenInvalidPage
			m.tmpl.ExecuteTemplate(w, "page", p)
			return
		}
		if cookie, err := r.Cookie("next_url"); err == nil {
			p.NextURL = cookie.Value
		}
		p.Page = continueOrSignoutPage
		m.tmpl.ExecuteTemplate(w, "page", p)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

func (m *Multipass) loginHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		if tokenStr := r.URL.Query().Get("token"); len(tokenStr) > 0 {
			cookie := &http.Cookie{
				Name:  "jwt_token",
				Value: tokenStr,
				Path:  "/",
			}
			http.SetCookie(w, cookie)
		}
		if nexturl := r.URL.Query().Get("url"); len(nexturl) > 0 {
			cookie := &http.Cookie{
				Name:  "next_url",
				Value: nexturl,
				Path:  "/",
			}
			http.SetCookie(w, cookie)
		}
		http.Redirect(w, r, m.Basepath, http.StatusSeeOther)
		return
	}
	if r.Method == "POST" {
		r.ParseForm()
		handle := r.PostForm.Get("handle")
		if len(handle) > 0 {
			if m.Handler.Listed(handle) {
				token, err := m.AccessToken(handle)
				if err != nil {
					log.Print(err)
				}
				values := url.Values{}
				if s := r.PostForm.Get("url"); len(s) > 0 {
					values.Set("url", s)
				}
				loginURL, err := NewLoginURL(m.SiteAddr, m.Basepath, token, values)
				if err != nil {
					log.Print(err)
				}
				if err := m.Handler.Notify(handle, loginURL.String()); err != nil {
					log.Print(err)
				}
			}
			// Redirect even when the handle is not listed in order to prevent guessing
			location := path.Join(m.Basepath, "confirm")
			http.Redirect(w, r, location, http.StatusSeeOther)
			return
		}
		http.Redirect(w, r, m.Basepath, http.StatusSeeOther)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

func (m *Multipass) confirmHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		w.Header().Add("Content-Type", "text/html; charset=utf-8")
		p := &page{
			Page: tokenSentPage,
		}
		m.tmpl.ExecuteTemplate(w, "page", p)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

// signoutHandler deletes the jwt_token cookie and redirect to the login
// location.
func (m *Multipass) signoutHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		if cookie, err := r.Cookie("jwt_token"); err == nil {
			cookie.Expires = time.Now().AddDate(-1, 0, 0)
			cookie.MaxAge = -1
			cookie.Path = "/"
			http.SetCookie(w, cookie)
		}
		http.Redirect(w, r, m.Basepath, http.StatusSeeOther)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

// publickeyHandler writes the public key to the given ResponseWriter to allow
// other to validate Multipass signed tokens.
func (m *Multipass) publickeyHandler(w http.ResponseWriter, r *http.Request) {
	data, err := x509.MarshalPKIXPublicKey(&m.key.PublicKey)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	block := &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: data,
	}
	w.Header().Set("Content-Type", "application/pkix-cert")
	if err := pem.Encode(w, block); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

// AccessToken returns a new signed and serialized token with the given handle
// as a claim.
func (m *Multipass) AccessToken(handle string) (tokenStr string, err error) {
	exp := time.Now().Add(m.Expires)
	claims := &Claims{
		Handle:    handle,
		Resources: m.Resources,
		Expires:   exp.Unix(),
	}
	payload, err := json.Marshal(claims)
	if err != nil {
		return "", err
	}
	jws, err := m.signer.Sign(payload)
	if err != nil {
		return "", err
	}

	return jws.CompactSerialize()
}

// NewLoginURL returns a login url which can be used as a time limited login.
// Optional values will be encoded in the login URL.
func NewLoginURL(siteaddr, basepath, token string, v url.Values) (*url.URL, error) {
	u, err := url.Parse(siteaddr)
	if err != nil {
		return u, err
	}
	u.Path = path.Join(basepath, "login")
	v.Set("token", token)
	u.RawQuery = v.Encode()
	return u, nil
}

func tokenHandler(w http.ResponseWriter, r *http.Request, m *Multipass) (int, error) {
	// Extract token from HTTP header, query parameter or cookie
	tokenStr, err := extractToken(r)
	if err != nil {
		return http.StatusUnauthorized, ErrInvalidToken
	}
	var claims *Claims
	if claims, err = validateToken(tokenStr, m.key.PublicKey); err != nil {
		return http.StatusUnauthorized, ErrInvalidToken
	}
	// Authorize handle claim
	if ok := m.Handler.Listed(claims.Handle); !ok {
		return http.StatusUnauthorized, ErrInvalidToken
	}
	// Verify path claim
	var match bool
	for _, path := range claims.Resources {
		if httpserver.Path(r.URL.Path).Matches(path) {
			match = true
			continue
		}
	}
	if !match {
		return http.StatusUnauthorized, ErrInvalidToken
	}

	// Pass on authorized handle to downstream handlers
	r.Header.Set("Multipass-Handle", claims.Handle)
	return http.StatusOK, nil
}

// ServeHTTP implements the httpserver.ServeHTTP interface from caddy.
func (a *Auth) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	m := a.Multipass

	if httpserver.Path(r.URL.Path).Matches(m.Basepath) {
		m.ServeHTTP(w, r)
		return 0, nil
	}

	for _, path := range m.Resources {
		if httpserver.Path(r.URL.Path).Matches(path) {
			if _, err := tokenHandler(w, r, m); err != nil {
				r.Header.Set("Referer", r.URL.String())
				m.rootHandler(w, r)
				return 0, nil
			}
		}
	}

	return a.Next.ServeHTTP(w, r)
}

// extractToken returns the JWT token embedded in the given request.
// JWT tokens can be embedded in the header prefixed with "Bearer ", with a
// "token" key query parameter or a cookie named "jwt_token".
func extractToken(r *http.Request) (string, error) {
	//from header
	if h := r.Header.Get("Authorization"); strings.HasPrefix(h, "Bearer ") {
		if len(h) > 7 {
			return h[7:], nil
		}
	}

	//from query parameter
	if token := r.URL.Query().Get("token"); len(token) > 0 {
		return token, nil
	}

	//from cookie
	if cookie, err := r.Cookie("jwt_token"); err == nil {
		return cookie.Value, nil
	}

	return "", fmt.Errorf("no token found")
}

func validateToken(token string, key rsa.PublicKey) (*Claims, error) {
	claims := &Claims{}

	// Verify token signature
	payload, err := verifyToken(token, key)
	if err != nil {
		return nil, err
	}
	// Unmarshal token claims
	if err := json.Unmarshal(payload, claims); err != nil {
		return nil, err
	}
	// Verify expire claim
	if time.Unix(claims.Expires, 0).Before(time.Now()) {
		return nil, errors.New("Token expired")
	}
	return claims, nil
}

func verifyToken(token string, key rsa.PublicKey) ([]byte, error) {
	var data []byte

	obj, err := jose.ParseSigned(token)
	if err != nil {
		return data, err
	}
	data, err = obj.Verify(&key)
	if err != nil {
		return data, err
	}
	return data, nil
}
<commit_msg>Refactor NewMultipass() to include basic initialization<commit_after>package multipass

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/mholt/caddy/caddyhttp/httpserver"

	jose "gopkg.in/square/go-jose.v1"
)

// Portable errors
var (
	ErrInvalidToken = errors.New("invalid token")
)

// Auth wraps a Multipass instance to be used by the caddy web server.
type Auth struct {
	*Multipass
	Next httpserver.Handler
}

// Rule holds the directive options parsed from a Caddyfile.
type Rule struct {
	Basepath  string
	Expires   time.Duration
	Resources []string
	Handles   []string

	SMTPAddr, SMTPUser, SMTPPass string
	MailFrom, MailTmpl           string
}

// Multipass implements the http.Handler interface which can handle
// authentication and authorization of users and resources using signed JWT.
type Multipass struct {
	Resources []string
	Basepath  string
	SiteAddr  string
	Expires   time.Duration

	Handler HandleService
	signer  jose.Signer
	key     *rsa.PrivateKey
	tmpl    *template.Template
	mux     *http.ServeMux
}

// NewMultipassFromRule return a new instance of Multipass from the given Rule.
// Returned error will most likely be parser errors.
func NewMultipassFromRule(r Rule) (*Multipass, error) {
	m, err := NewMultipass(r.Basepath)
	if err != nil {
		return nil, err
	}

	if len(r.Resources) > 0 {
		m.Resources = r.Resources
	}
	if r.Expires > 0 {
		m.Expires = r.Expires
	}

	// Set EmailHandler options
	opt := &EmailOptions{
		r.SMTPAddr,
		r.SMTPUser,
		r.SMTPPass,
		r.MailFrom,
	}
	handler, err := NewEmailHandler(opt)
	if err != nil {
		return nil, err
	}
	for _, handle := range r.Handles {
		handler.Register(handle)
	}
	m.Handler = handler

	return m, nil
}

// NewMultipass returns a new instance of Multipass with reasonalble defaults
// like a 2048 bit RSA key pair, /multipass as basepath, 24 hours before a
// token will expire.
func NewMultipass(basepath string) (*Multipass, error) {
	// Absolute the given basepath or set a default
	if len(basepath) > 0 {
		basepath = path.Join("/", basepath)
	} else {
		basepath = "/multipass"
	}

	// Generate the RSA key pari
	pk, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}
	signer, err := jose.NewSigner(jose.PS512, pk)
	if err != nil {
		return nil, err
	}

	// Load HTML templates
	tmpl, err := loadTemplates()
	if err != nil {
		return nil, err
	}

	m := &Multipass{
		Resources: []string{"/"},
		Basepath:  basepath,
		Expires:   time.Hour * 24,
		key:       pk,
		signer:    signer,
		tmpl:      tmpl,
	}

	// Create the router
	mux := http.NewServeMux()
	mux.HandleFunc(path.Join(basepath, "/"), m.rootHandler)
	mux.HandleFunc(path.Join(basepath, "/login"), m.loginHandler)
	mux.HandleFunc(path.Join(basepath, "/confirm"), m.confirmHandler)
	mux.HandleFunc(path.Join(basepath, "/signout"), m.signoutHandler)
	mux.HandleFunc(path.Join(basepath, "/pub.cer"), m.publickeyHandler)
	m.mux = mux

	return m, nil
}

// Claims are part of the JSON web token
type Claims struct {
	Handle    string   `json:"handle"`
	Resources []string `json:"resources"`
	Expires   int64    `json:"exp"`
}

// ServeHTTP satisfies the ServeHTTP interface
func (m *Multipass) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h, p := m.mux.Handler(r); len(p) > 0 {
		h.ServeHTTP(w, r)
		return
	}
	http.NotFound(w, r)
}

// rootHandler handles the "/" path of the Multipass handler.
// Shows login page when no JWT present
// Show continue or signout page when JWT is valid
// Show token invalid page when JWT is invalid
func (m *Multipass) rootHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {

		// Regular login page
		p := &page{
			Page:        loginPage,
			LoginPath:   path.Join(m.Basepath, "login"),
			SignoutPath: path.Join(m.Basepath, "signout"),
		}

		// Show login page when there is no token
		tokenStr, err := extractToken(r)
		if err != nil {
			if s := r.Referer(); !httpserver.Path(s).Matches(m.Basepath) {
				p.NextURL = s
			}
			m.tmpl.ExecuteTemplate(w, "page", p)
			return
		}
		var claims *Claims
		if claims, err = validateToken(tokenStr, m.key.PublicKey); err != nil {
			p.Page = tokenInvalidPage
			if s := r.Referer(); !httpserver.Path(s).Matches(m.Basepath) {
				p.NextURL = s
			}
			m.tmpl.ExecuteTemplate(w, "page", p)
			return
		}
		// Authorize handle claim
		if ok := m.Handler.Listed(claims.Handle); !ok {
			p.Page = tokenInvalidPage
			m.tmpl.ExecuteTemplate(w, "page", p)
			return
		}
		if cookie, err := r.Cookie("next_url"); err == nil {
			p.NextURL = cookie.Value
		}
		p.Page = continueOrSignoutPage
		m.tmpl.ExecuteTemplate(w, "page", p)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

func (m *Multipass) loginHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		if tokenStr := r.URL.Query().Get("token"); len(tokenStr) > 0 {
			cookie := &http.Cookie{
				Name:  "jwt_token",
				Value: tokenStr,
				Path:  "/",
			}
			http.SetCookie(w, cookie)
		}
		if nexturl := r.URL.Query().Get("url"); len(nexturl) > 0 {
			cookie := &http.Cookie{
				Name:  "next_url",
				Value: nexturl,
				Path:  "/",
			}
			http.SetCookie(w, cookie)
		}
		http.Redirect(w, r, m.Basepath, http.StatusSeeOther)
		return
	}
	if r.Method == "POST" {
		r.ParseForm()
		handle := r.PostForm.Get("handle")
		if len(handle) > 0 {
			if m.Handler.Listed(handle) {
				token, err := m.AccessToken(handle)
				if err != nil {
					log.Print(err)
				}
				values := url.Values{}
				if s := r.PostForm.Get("url"); len(s) > 0 {
					values.Set("url", s)
				}
				loginURL, err := NewLoginURL(m.SiteAddr, m.Basepath, token, values)
				if err != nil {
					log.Print(err)
				}
				if err := m.Handler.Notify(handle, loginURL.String()); err != nil {
					log.Print(err)
				}
			}
			// Redirect even when the handle is not listed in order to prevent guessing
			location := path.Join(m.Basepath, "confirm")
			http.Redirect(w, r, location, http.StatusSeeOther)
			return
		}
		http.Redirect(w, r, m.Basepath, http.StatusSeeOther)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

func (m *Multipass) confirmHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		w.Header().Add("Content-Type", "text/html; charset=utf-8")
		p := &page{
			Page: tokenSentPage,
		}
		m.tmpl.ExecuteTemplate(w, "page", p)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

// signoutHandler deletes the jwt_token cookie and redirect to the login
// location.
func (m *Multipass) signoutHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		if cookie, err := r.Cookie("jwt_token"); err == nil {
			cookie.Expires = time.Now().AddDate(-1, 0, 0)
			cookie.MaxAge = -1
			cookie.Path = "/"
			http.SetCookie(w, cookie)
		}
		http.Redirect(w, r, m.Basepath, http.StatusSeeOther)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

// publickeyHandler writes the public key to the given ResponseWriter to allow
// other to validate Multipass signed tokens.
func (m *Multipass) publickeyHandler(w http.ResponseWriter, r *http.Request) {
	data, err := x509.MarshalPKIXPublicKey(&m.key.PublicKey)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	block := &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: data,
	}
	w.Header().Set("Content-Type", "application/pkix-cert")
	if err := pem.Encode(w, block); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

// AccessToken returns a new signed and serialized token with the given handle
// as a claim.
func (m *Multipass) AccessToken(handle string) (tokenStr string, err error) {
	exp := time.Now().Add(m.Expires)
	claims := &Claims{
		Handle:    handle,
		Resources: m.Resources,
		Expires:   exp.Unix(),
	}
	payload, err := json.Marshal(claims)
	if err != nil {
		return "", err
	}
	jws, err := m.signer.Sign(payload)
	if err != nil {
		return "", err
	}

	return jws.CompactSerialize()
}

// NewLoginURL returns a login url which can be used as a time limited login.
// Optional values will be encoded in the login URL.
func NewLoginURL(siteaddr, basepath, token string, v url.Values) (*url.URL, error) {
	u, err := url.Parse(siteaddr)
	if err != nil {
		return u, err
	}
	u.Path = path.Join(basepath, "login")
	v.Set("token", token)
	u.RawQuery = v.Encode()
	return u, nil
}

func tokenHandler(w http.ResponseWriter, r *http.Request, m *Multipass) (int, error) {
	// Extract token from HTTP header, query parameter or cookie
	tokenStr, err := extractToken(r)
	if err != nil {
		return http.StatusUnauthorized, ErrInvalidToken
	}
	var claims *Claims
	if claims, err = validateToken(tokenStr, m.key.PublicKey); err != nil {
		return http.StatusUnauthorized, ErrInvalidToken
	}
	// Authorize handle claim
	if ok := m.Handler.Listed(claims.Handle); !ok {
		return http.StatusUnauthorized, ErrInvalidToken
	}
	// Verify path claim
	var match bool
	for _, path := range claims.Resources {
		if httpserver.Path(r.URL.Path).Matches(path) {
			match = true
			continue
		}
	}
	if !match {
		return http.StatusUnauthorized, ErrInvalidToken
	}

	// Pass on authorized handle to downstream handlers
	r.Header.Set("Multipass-Handle", claims.Handle)
	return http.StatusOK, nil
}

// ServeHTTP implements the httpserver.ServeHTTP interface from caddy.
func (a *Auth) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	m := a.Multipass

	if httpserver.Path(r.URL.Path).Matches(m.Basepath) {
		m.ServeHTTP(w, r)
		return 0, nil
	}

	for _, path := range m.Resources {
		if httpserver.Path(r.URL.Path).Matches(path) {
			if _, err := tokenHandler(w, r, m); err != nil {
				r.Header.Set("Referer", r.URL.String())
				m.rootHandler(w, r)
				return 0, nil
			}
		}
	}

	return a.Next.ServeHTTP(w, r)
}

// extractToken returns the JWT token embedded in the given request.
// JWT tokens can be embedded in the header prefixed with "Bearer ", with a
// "token" key query parameter or a cookie named "jwt_token".
func extractToken(r *http.Request) (string, error) {
	//from header
	if h := r.Header.Get("Authorization"); strings.HasPrefix(h, "Bearer ") {
		if len(h) > 7 {
			return h[7:], nil
		}
	}

	//from query parameter
	if token := r.URL.Query().Get("token"); len(token) > 0 {
		return token, nil
	}

	//from cookie
	if cookie, err := r.Cookie("jwt_token"); err == nil {
		return cookie.Value, nil
	}

	return "", fmt.Errorf("no token found")
}

func validateToken(token string, key rsa.PublicKey) (*Claims, error) {
	claims := &Claims{}

	// Verify token signature
	payload, err := verifyToken(token, key)
	if err != nil {
		return nil, err
	}
	// Unmarshal token claims
	if err := json.Unmarshal(payload, claims); err != nil {
		return nil, err
	}
	// Verify expire claim
	if time.Unix(claims.Expires, 0).Before(time.Now()) {
		return nil, errors.New("Token expired")
	}
	return claims, nil
}

func verifyToken(token string, key rsa.PublicKey) ([]byte, error) {
	var data []byte

	obj, err := jose.ParseSigned(token)
	if err != nil {
		return data, err
	}
	data, err = obj.Verify(&key)
	if err != nil {
		return data, err
	}
	return data, nil
}
<|endoftext|>