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

// TRANSACTION SIGNATURE (TSIG)
//
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
// The supported algorithms include: HmacMD5, HmacSHA1 and HmacSHA256.
//
// Basic use pattern when querying with a TSIG name "axfr." (note that these key names
// must be fully qualified - as they are domain names) and the base64 secret
// "so6ZGir4GPAqINNh9U5c3A==":
//
//	c := new(dns.Client)
//	c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
//	m := new(dns.Msg)
//	m.SetQuestion("miek.nl.", dns.TypeMX)
//	m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
//	...
//	// When sending the TSIG RR is calculated and filled in before sending
//
// When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
// TSIG, this is the basic use pattern. In this example we request an AXFR for
// miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
// and using the server 176.58.119.54:
//
//	t := new(dns.Transfer)
//	m := new(dns.Msg)
//	t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
//	m.SetAxfr("miek.nl.")
//	m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
//	c, err := t.In(m, "176.58.119.54:53")
//	for r := range c { /* r.RR */ }
//
// You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
// If something is not correct an error is returned.
//
// Basic use pattern validating and replying to a message that has TSIG set.
//
//	server := &dns.Server{Addr: ":53", Net: "udp"}
//	server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
//	go server.ListenAndServe()
//	dns.HandleFunc(".", handleRequest)
//
// 	func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
//		m := new(Msg)
//		m.SetReply(r)
//		if r.IsTsig() {
//			if w.TsigStatus() == nil {
//				// *Msg r has an TSIG record and it was validated
//				m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
//			} else {
//				// *Msg r has an TSIG records and it was not valided
//			}
//		}
//		w.WriteMsg(m)
//	}
package dns

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"hash"
	"io"
	"strconv"
	"strings"
	"time"
)

// HMAC hashing codes. These are transmitted as domain names.
const (
	HmacMD5    = "hmac-md5.sig-alg.reg.int."
	HmacSHA1   = "hmac-sha1."
	HmacSHA256 = "hmac-sha256."
)

type TSIG struct {
	Hdr        RR_Header
	Algorithm  string `dns:"domain-name"`
	TimeSigned uint64 `dns:"uint48"`
	Fudge      uint16
	MACSize    uint16
	MAC        string `dns:"size-hex"`
	OrigId     uint16
	Error      uint16
	OtherLen   uint16
	OtherData  string `dns:"size-hex"`
}

func (rr *TSIG) Header() *RR_Header {
	return &rr.Hdr
}

// TSIG has no official presentation format, but this will suffice.

func (rr *TSIG) String() string {
	s := "\n;; TSIG PSEUDOSECTION:\n"
	s += rr.Hdr.String() +
		" " + rr.Algorithm +
		" " + tsigTimeToString(rr.TimeSigned) +
		" " + strconv.Itoa(int(rr.Fudge)) +
		" " + strconv.Itoa(int(rr.MACSize)) +
		" " + strings.ToUpper(rr.MAC) +
		" " + strconv.Itoa(int(rr.OrigId)) +
		" " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
		" " + strconv.Itoa(int(rr.OtherLen)) +
		" " + rr.OtherData
	return s
}

func (rr *TSIG) len() int {
	return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
		4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
}

func (rr *TSIG) copy() RR {
	return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
}

// The following values must be put in wireformat, so that the MAC can be calculated.
// RFC 2845, section 3.4.2. TSIG Variables.
type tsigWireFmt struct {
	// From RR_Header
	Name  string `dns:"domain-name"`
	Class uint16
	Ttl   uint32
	// Rdata of the TSIG
	Algorithm  string `dns:"domain-name"`
	TimeSigned uint64 `dns:"uint48"`
	Fudge      uint16
	// MACSize, MAC and OrigId excluded
	Error     uint16
	OtherLen  uint16
	OtherData string `dns:"size-hex"`
}

// If we have the MAC use this type to convert it to wiredata.
// Section 3.4.3. Request MAC
type macWireFmt struct {
	MACSize uint16
	MAC     string `dns:"size-hex"`
}

// 3.3. Time values used in TSIG calculations
type timerWireFmt struct {
	TimeSigned uint64 `dns:"uint48"`
	Fudge      uint16
}

// TsigGenerate fills out the TSIG record attached to the message.
// The message should contain
// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
// time fudge (defaults to 300 seconds) and the current time
// The TSIG MAC is saved in that Tsig RR.
// When TsigGenerate is called for the first time requestMAC is set to the empty string and
// timersOnly is false.
// If something goes wrong an error is returned, otherwise it is nil.
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
	if m.IsTsig() == nil {
		panic("dns: TSIG not last RR in additional")
	}
	// If we barf here, the caller is to blame
	rawsecret, err := packBase64([]byte(secret))
	if err != nil {
		return nil, "", err
	}

	rr := m.Extra[len(m.Extra)-1].(*TSIG)
	m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
	mbuf, err := m.Pack()
	if err != nil {
		return nil, "", err
	}
	buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)

	t := new(TSIG)
	var h hash.Hash
	switch rr.Algorithm {
	case HmacMD5:
		h = hmac.New(md5.New, []byte(rawsecret))
	case HmacSHA1:
		h = hmac.New(sha1.New, []byte(rawsecret))
	case HmacSHA256:
		h = hmac.New(sha256.New, []byte(rawsecret))
	default:
		return nil, "", ErrKeyAlg
	}
	io.WriteString(h, string(buf))
	t.MAC = hex.EncodeToString(h.Sum(nil))
	t.MACSize = uint16(len(t.MAC) / 2) // Size is half!

	t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
	t.Fudge = rr.Fudge
	t.TimeSigned = rr.TimeSigned
	t.Algorithm = rr.Algorithm
	t.OrigId = m.Id

	tbuf := make([]byte, t.len())
	if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
		tbuf = tbuf[:off] // reset to actual size used
	} else {
		return nil, "", err
	}
	mbuf = append(mbuf, tbuf...)
	rawSetExtraLen(mbuf, uint16(len(m.Extra)+1))
	return mbuf, t.MAC, nil
}

// TsigVerify verifies the TSIG on a message.
// If the signature does not validate err contains the
// error, otherwise it is nil.
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
	rawsecret, err := packBase64([]byte(secret))
	if err != nil {
		return err
	}
	// Strip the TSIG from the incoming msg
	stripped, tsig, err := stripTsig(msg)
	if err != nil {
		return err
	}

	msgMAC, err := hex.DecodeString(tsig.MAC)
	if err != nil {
		return err
	}

	buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
	ti := uint64(time.Now().Unix()) - tsig.TimeSigned
	if uint64(tsig.Fudge) < ti {
		return ErrTime
	}

	var h hash.Hash
	switch tsig.Algorithm {
	case HmacMD5:
		h = hmac.New(md5.New, rawsecret)
	case HmacSHA1:
		h = hmac.New(sha1.New, rawsecret)
	case HmacSHA256:
		h = hmac.New(sha256.New, rawsecret)
	default:
		return ErrKeyAlg
	}
	h.Write(buf)
	if !hmac.Equal(h.Sum(nil), msgMAC) {
		return ErrSig
	}
	return nil
}

// Create a wiredata buffer for the MAC calculation.
func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
	var buf []byte
	if rr.TimeSigned == 0 {
		rr.TimeSigned = uint64(time.Now().Unix())
	}
	if rr.Fudge == 0 {
		rr.Fudge = 300 // Standard (RFC) default.
	}

	if requestMAC != "" {
		m := new(macWireFmt)
		m.MACSize = uint16(len(requestMAC) / 2)
		m.MAC = requestMAC
		buf = make([]byte, len(requestMAC)) // long enough
		n, _ := PackStruct(m, buf, 0)
		buf = buf[:n]
	}

	tsigvar := make([]byte, DefaultMsgSize)
	if timersOnly {
		tsig := new(timerWireFmt)
		tsig.TimeSigned = rr.TimeSigned
		tsig.Fudge = rr.Fudge
		n, _ := PackStruct(tsig, tsigvar, 0)
		tsigvar = tsigvar[:n]
	} else {
		tsig := new(tsigWireFmt)
		tsig.Name = strings.ToLower(rr.Hdr.Name)
		tsig.Class = ClassANY
		tsig.Ttl = rr.Hdr.Ttl
		tsig.Algorithm = strings.ToLower(rr.Algorithm)
		tsig.TimeSigned = rr.TimeSigned
		tsig.Fudge = rr.Fudge
		tsig.Error = rr.Error
		tsig.OtherLen = rr.OtherLen
		tsig.OtherData = rr.OtherData
		n, _ := PackStruct(tsig, tsigvar, 0)
		tsigvar = tsigvar[:n]
	}

	if requestMAC != "" {
		x := append(buf, msgbuf...)
		buf = append(x, tsigvar...)
	} else {
		buf = append(msgbuf, tsigvar...)
	}
	return buf
}

// Strip the TSIG from the raw message
func stripTsig(msg []byte) ([]byte, *TSIG, error) {
	// Copied from msg.go's Unpack()
	// Header.
	var dh Header
	var err error
	dns := new(Msg)
	rr := new(TSIG)
	off := 0
	tsigoff := 0
	if off, err = UnpackStruct(&dh, msg, off); err != nil {
		return nil, nil, err
	}
	if dh.Arcount == 0 {
		return nil, nil, ErrNoSig
	}
	// Rcode, see msg.go Unpack()
	if int(dh.Bits&0xF) == RcodeNotAuth {
		return nil, nil, ErrAuth
	}

	// Arrays.
	dns.Question = make([]Question, dh.Qdcount)
	dns.Answer = make([]RR, dh.Ancount)
	dns.Ns = make([]RR, dh.Nscount)
	dns.Extra = make([]RR, dh.Arcount)

	for i := 0; i < len(dns.Question); i++ {
		off, err = UnpackStruct(&dns.Question[i], msg, off)
		if err != nil {
			return nil, nil, err
		}
	}
	for i := 0; i < len(dns.Answer); i++ {
		dns.Answer[i], off, err = UnpackRR(msg, off)
		if err != nil {
			return nil, nil, err
		}
	}
	for i := 0; i < len(dns.Ns); i++ {
		dns.Ns[i], off, err = UnpackRR(msg, off)
		if err != nil {
			return nil, nil, err
		}
	}
	for i := 0; i < len(dns.Extra); i++ {
		tsigoff = off
		dns.Extra[i], off, err = UnpackRR(msg, off)
		if err != nil {
			return nil, nil, err
		}
		if dns.Extra[i].Header().Rrtype == TypeTSIG {
			rr = dns.Extra[i].(*TSIG)
			// Adjust Arcount.
			arcount, _ := unpackUint16(msg, 10)
			msg[10], msg[11] = packUint16(arcount - 1)
			break
		}
	}
	if rr == nil {
		return nil, nil, ErrNoSig
	}
	return msg[:tsigoff], rr, nil
}

// Translate the TSIG time signed into a date. There is no
// need for RFC1982 calculations as this date is 48 bits.
func tsigTimeToString(t uint64) string {
	ti := time.Unix(int64(t), 0).UTC()
	return ti.Format("20060102150405")
}
<commit_msg>Update TSIG doc header to avoid godoc oddity<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TRANSACTION SIGNATURE
//
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
// The supported algorithms include: HmacMD5, HmacSHA1 and HmacSHA256.
//
// Basic use pattern when querying with a TSIG name "axfr." (note that these key names
// must be fully qualified - as they are domain names) and the base64 secret
// "so6ZGir4GPAqINNh9U5c3A==":
//
//	c := new(dns.Client)
//	c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
//	m := new(dns.Msg)
//	m.SetQuestion("miek.nl.", dns.TypeMX)
//	m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
//	...
//	// When sending the TSIG RR is calculated and filled in before sending
//
// When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
// TSIG, this is the basic use pattern. In this example we request an AXFR for
// miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
// and using the server 176.58.119.54:
//
//	t := new(dns.Transfer)
//	m := new(dns.Msg)
//	t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
//	m.SetAxfr("miek.nl.")
//	m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
//	c, err := t.In(m, "176.58.119.54:53")
//	for r := range c { /* r.RR */ }
//
// You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
// If something is not correct an error is returned.
//
// Basic use pattern validating and replying to a message that has TSIG set.
//
//	server := &dns.Server{Addr: ":53", Net: "udp"}
//	server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
//	go server.ListenAndServe()
//	dns.HandleFunc(".", handleRequest)
//
// 	func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
//		m := new(Msg)
//		m.SetReply(r)
//		if r.IsTsig() {
//			if w.TsigStatus() == nil {
//				// *Msg r has an TSIG record and it was validated
//				m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
//			} else {
//				// *Msg r has an TSIG records and it was not valided
//			}
//		}
//		w.WriteMsg(m)
//	}
package dns

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"hash"
	"io"
	"strconv"
	"strings"
	"time"
)

// HMAC hashing codes. These are transmitted as domain names.
const (
	HmacMD5    = "hmac-md5.sig-alg.reg.int."
	HmacSHA1   = "hmac-sha1."
	HmacSHA256 = "hmac-sha256."
)

type TSIG struct {
	Hdr        RR_Header
	Algorithm  string `dns:"domain-name"`
	TimeSigned uint64 `dns:"uint48"`
	Fudge      uint16
	MACSize    uint16
	MAC        string `dns:"size-hex"`
	OrigId     uint16
	Error      uint16
	OtherLen   uint16
	OtherData  string `dns:"size-hex"`
}

func (rr *TSIG) Header() *RR_Header {
	return &rr.Hdr
}

// TSIG has no official presentation format, but this will suffice.

func (rr *TSIG) String() string {
	s := "\n;; TSIG PSEUDOSECTION:\n"
	s += rr.Hdr.String() +
		" " + rr.Algorithm +
		" " + tsigTimeToString(rr.TimeSigned) +
		" " + strconv.Itoa(int(rr.Fudge)) +
		" " + strconv.Itoa(int(rr.MACSize)) +
		" " + strings.ToUpper(rr.MAC) +
		" " + strconv.Itoa(int(rr.OrigId)) +
		" " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
		" " + strconv.Itoa(int(rr.OtherLen)) +
		" " + rr.OtherData
	return s
}

func (rr *TSIG) len() int {
	return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
		4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
}

func (rr *TSIG) copy() RR {
	return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
}

// The following values must be put in wireformat, so that the MAC can be calculated.
// RFC 2845, section 3.4.2. TSIG Variables.
type tsigWireFmt struct {
	// From RR_Header
	Name  string `dns:"domain-name"`
	Class uint16
	Ttl   uint32
	// Rdata of the TSIG
	Algorithm  string `dns:"domain-name"`
	TimeSigned uint64 `dns:"uint48"`
	Fudge      uint16
	// MACSize, MAC and OrigId excluded
	Error     uint16
	OtherLen  uint16
	OtherData string `dns:"size-hex"`
}

// If we have the MAC use this type to convert it to wiredata.
// Section 3.4.3. Request MAC
type macWireFmt struct {
	MACSize uint16
	MAC     string `dns:"size-hex"`
}

// 3.3. Time values used in TSIG calculations
type timerWireFmt struct {
	TimeSigned uint64 `dns:"uint48"`
	Fudge      uint16
}

// TsigGenerate fills out the TSIG record attached to the message.
// The message should contain
// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
// time fudge (defaults to 300 seconds) and the current time
// The TSIG MAC is saved in that Tsig RR.
// When TsigGenerate is called for the first time requestMAC is set to the empty string and
// timersOnly is false.
// If something goes wrong an error is returned, otherwise it is nil.
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
	if m.IsTsig() == nil {
		panic("dns: TSIG not last RR in additional")
	}
	// If we barf here, the caller is to blame
	rawsecret, err := packBase64([]byte(secret))
	if err != nil {
		return nil, "", err
	}

	rr := m.Extra[len(m.Extra)-1].(*TSIG)
	m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
	mbuf, err := m.Pack()
	if err != nil {
		return nil, "", err
	}
	buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)

	t := new(TSIG)
	var h hash.Hash
	switch rr.Algorithm {
	case HmacMD5:
		h = hmac.New(md5.New, []byte(rawsecret))
	case HmacSHA1:
		h = hmac.New(sha1.New, []byte(rawsecret))
	case HmacSHA256:
		h = hmac.New(sha256.New, []byte(rawsecret))
	default:
		return nil, "", ErrKeyAlg
	}
	io.WriteString(h, string(buf))
	t.MAC = hex.EncodeToString(h.Sum(nil))
	t.MACSize = uint16(len(t.MAC) / 2) // Size is half!

	t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
	t.Fudge = rr.Fudge
	t.TimeSigned = rr.TimeSigned
	t.Algorithm = rr.Algorithm
	t.OrigId = m.Id

	tbuf := make([]byte, t.len())
	if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
		tbuf = tbuf[:off] // reset to actual size used
	} else {
		return nil, "", err
	}
	mbuf = append(mbuf, tbuf...)
	rawSetExtraLen(mbuf, uint16(len(m.Extra)+1))
	return mbuf, t.MAC, nil
}

// TsigVerify verifies the TSIG on a message.
// If the signature does not validate err contains the
// error, otherwise it is nil.
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
	rawsecret, err := packBase64([]byte(secret))
	if err != nil {
		return err
	}
	// Strip the TSIG from the incoming msg
	stripped, tsig, err := stripTsig(msg)
	if err != nil {
		return err
	}

	msgMAC, err := hex.DecodeString(tsig.MAC)
	if err != nil {
		return err
	}

	buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
	ti := uint64(time.Now().Unix()) - tsig.TimeSigned
	if uint64(tsig.Fudge) < ti {
		return ErrTime
	}

	var h hash.Hash
	switch tsig.Algorithm {
	case HmacMD5:
		h = hmac.New(md5.New, rawsecret)
	case HmacSHA1:
		h = hmac.New(sha1.New, rawsecret)
	case HmacSHA256:
		h = hmac.New(sha256.New, rawsecret)
	default:
		return ErrKeyAlg
	}
	h.Write(buf)
	if !hmac.Equal(h.Sum(nil), msgMAC) {
		return ErrSig
	}
	return nil
}

// Create a wiredata buffer for the MAC calculation.
func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
	var buf []byte
	if rr.TimeSigned == 0 {
		rr.TimeSigned = uint64(time.Now().Unix())
	}
	if rr.Fudge == 0 {
		rr.Fudge = 300 // Standard (RFC) default.
	}

	if requestMAC != "" {
		m := new(macWireFmt)
		m.MACSize = uint16(len(requestMAC) / 2)
		m.MAC = requestMAC
		buf = make([]byte, len(requestMAC)) // long enough
		n, _ := PackStruct(m, buf, 0)
		buf = buf[:n]
	}

	tsigvar := make([]byte, DefaultMsgSize)
	if timersOnly {
		tsig := new(timerWireFmt)
		tsig.TimeSigned = rr.TimeSigned
		tsig.Fudge = rr.Fudge
		n, _ := PackStruct(tsig, tsigvar, 0)
		tsigvar = tsigvar[:n]
	} else {
		tsig := new(tsigWireFmt)
		tsig.Name = strings.ToLower(rr.Hdr.Name)
		tsig.Class = ClassANY
		tsig.Ttl = rr.Hdr.Ttl
		tsig.Algorithm = strings.ToLower(rr.Algorithm)
		tsig.TimeSigned = rr.TimeSigned
		tsig.Fudge = rr.Fudge
		tsig.Error = rr.Error
		tsig.OtherLen = rr.OtherLen
		tsig.OtherData = rr.OtherData
		n, _ := PackStruct(tsig, tsigvar, 0)
		tsigvar = tsigvar[:n]
	}

	if requestMAC != "" {
		x := append(buf, msgbuf...)
		buf = append(x, tsigvar...)
	} else {
		buf = append(msgbuf, tsigvar...)
	}
	return buf
}

// Strip the TSIG from the raw message
func stripTsig(msg []byte) ([]byte, *TSIG, error) {
	// Copied from msg.go's Unpack()
	// Header.
	var dh Header
	var err error
	dns := new(Msg)
	rr := new(TSIG)
	off := 0
	tsigoff := 0
	if off, err = UnpackStruct(&dh, msg, off); err != nil {
		return nil, nil, err
	}
	if dh.Arcount == 0 {
		return nil, nil, ErrNoSig
	}
	// Rcode, see msg.go Unpack()
	if int(dh.Bits&0xF) == RcodeNotAuth {
		return nil, nil, ErrAuth
	}

	// Arrays.
	dns.Question = make([]Question, dh.Qdcount)
	dns.Answer = make([]RR, dh.Ancount)
	dns.Ns = make([]RR, dh.Nscount)
	dns.Extra = make([]RR, dh.Arcount)

	for i := 0; i < len(dns.Question); i++ {
		off, err = UnpackStruct(&dns.Question[i], msg, off)
		if err != nil {
			return nil, nil, err
		}
	}
	for i := 0; i < len(dns.Answer); i++ {
		dns.Answer[i], off, err = UnpackRR(msg, off)
		if err != nil {
			return nil, nil, err
		}
	}
	for i := 0; i < len(dns.Ns); i++ {
		dns.Ns[i], off, err = UnpackRR(msg, off)
		if err != nil {
			return nil, nil, err
		}
	}
	for i := 0; i < len(dns.Extra); i++ {
		tsigoff = off
		dns.Extra[i], off, err = UnpackRR(msg, off)
		if err != nil {
			return nil, nil, err
		}
		if dns.Extra[i].Header().Rrtype == TypeTSIG {
			rr = dns.Extra[i].(*TSIG)
			// Adjust Arcount.
			arcount, _ := unpackUint16(msg, 10)
			msg[10], msg[11] = packUint16(arcount - 1)
			break
		}
	}
	if rr == nil {
		return nil, nil, ErrNoSig
	}
	return msg[:tsigoff], rr, nil
}

// Translate the TSIG time signed into a date. There is no
// need for RFC1982 calculations as this date is 48 bits.
func tsigTimeToString(t uint64) string {
	ti := time.Unix(int64(t), 0).UTC()
	return ti.Format("20060102150405")
}
<|endoftext|>


<commit_before>package discordgo

import "strings"

// UserFlags is the flags of "user" (see UserFlags* consts)
// https://discord.com/developers/docs/resources/user#user-object-user-flags
type UserFlags int

// Valid UserFlags values
const (
	UserFlagDiscordEmployee      UserFlags = 1 << 0
	UserFlagDiscordPartner                 = 1 << 1
	UserFlagHypeSquadEvents                = 1 << 2
	UserFlagBugHunterLevel1                = 1 << 3
	UserFlagHouseBravery                   = 1 << 6
	UserFlagHouseBrilliance                = 1 << 7
	UserFlagHouseBalance                   = 1 << 8
	UserFlagEarlySupporter                 = 1 << 9
	UserFlagTeamUser                       = 1 << 10
	UserFlagSystem                         = 1 << 12
	UserFlagBugHunterLevel2                = 1 << 14
	UserFlagVerifiedBot                    = 1 << 16
	UserFlagVerifiedBotDeveloper           = 1 << 17
)

// A User stores all data for an individual Discord user.
type User struct {
	// The ID of the user.
	ID string `json:"id"`

	// The email of the user. This is only present when
	// the application possesses the email scope for the user.
	Email string `json:"email"`

	// The user's username.
	Username string `json:"username"`

	// The hash of the user's avatar. Use Session.UserAvatar
	// to retrieve the avatar itself.
	Avatar string `json:"avatar"`

	// The user's chosen language option.
	Locale string `json:"locale"`

	// The discriminator of the user (4 numbers after name).
	Discriminator string `json:"discriminator"`

	// The token of the user. This is only present for
	// the user represented by the current session.
	Token string `json:"token"`

	// Whether the user's email is verified.
	Verified bool `json:"verified"`

	// Whether the user has multi-factor authentication enabled.
	MFAEnabled bool `json:"mfa_enabled"`

	// Whether the user is a bot.
	Bot bool `json:"bot"`

	// The public flags on a user's account.
	// This is a combination of bit masks; the presence of a certain flag can
	// be checked by performing a bitwise AND between this int and the flag.
	PublicFlags UserFlags `json:"public_flags"`

	// The type of Nitro subscription on a user's account.
	// Only available when the request is authorized via a Bearer token.
	PremiumType int `json:"premium_type"`

	// Whether the user is an Official Discord System user (part of the urgent message system).
	System bool `json:"system"`

	// The flags on a user's account.
	// Only available when the request is authorized via a Bearer token.
	Flags int `json:"flags"`
}

// String returns a unique identifier of the form username#discriminator
func (u *User) String() string {
	return u.Username + "#" + u.Discriminator
}

// Mention return a string which mentions the user
func (u *User) Mention() string {
	return "<@" + u.ID + ">"
}

// AvatarURL returns a URL to the user's avatar.
//    size:    The size of the user's avatar as a power of two
//             if size is an empty string, no size parameter will
//             be added to the URL.
func (u *User) AvatarURL(size string) string {
	var URL string
	if u.Avatar == "" {
		URL = EndpointDefaultUserAvatar(u.Discriminator)
	} else if strings.HasPrefix(u.Avatar, "a_") {
		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
	} else {
		URL = EndpointUserAvatar(u.ID, u.Avatar)
	}

	if size != "" {
		return URL + "?size=" + size
	}
	return URL
}
<commit_msg>Update user.go (#934)<commit_after>package discordgo

import "strings"

// UserFlags is the flags of "user" (see UserFlags* consts)
// https://discord.com/developers/docs/resources/user#user-object-user-flags
type UserFlags int

// Valid UserFlags values
const (
	UserFlagDiscordEmployee      UserFlags = 1 << 0
	UserFlagDiscordPartner                 = 1 << 1
	UserFlagHypeSquadEvents                = 1 << 2
	UserFlagBugHunterLevel1                = 1 << 3
	UserFlagHouseBravery                   = 1 << 6
	UserFlagHouseBrilliance                = 1 << 7
	UserFlagHouseBalance                   = 1 << 8
	UserFlagEarlySupporter                 = 1 << 9
	UserFlagTeamUser                       = 1 << 10
	UserFlagSystem                         = 1 << 12
	UserFlagBugHunterLevel2                = 1 << 14
	UserFlagVerifiedBot                    = 1 << 16
	UserFlagVerifiedBotDeveloper           = 1 << 17
	UserFlagDiscordCertifiedModerator      = 1 << 18
)

// A User stores all data for an individual Discord user.
type User struct {
	// The ID of the user.
	ID string `json:"id"`

	// The email of the user. This is only present when
	// the application possesses the email scope for the user.
	Email string `json:"email"`

	// The user's username.
	Username string `json:"username"`

	// The hash of the user's avatar. Use Session.UserAvatar
	// to retrieve the avatar itself.
	Avatar string `json:"avatar"`

	// The user's chosen language option.
	Locale string `json:"locale"`

	// The discriminator of the user (4 numbers after name).
	Discriminator string `json:"discriminator"`

	// The token of the user. This is only present for
	// the user represented by the current session.
	Token string `json:"token"`

	// Whether the user's email is verified.
	Verified bool `json:"verified"`

	// Whether the user has multi-factor authentication enabled.
	MFAEnabled bool `json:"mfa_enabled"`

	// Whether the user is a bot.
	Bot bool `json:"bot"`

	// The public flags on a user's account.
	// This is a combination of bit masks; the presence of a certain flag can
	// be checked by performing a bitwise AND between this int and the flag.
	PublicFlags UserFlags `json:"public_flags"`

	// The type of Nitro subscription on a user's account.
	// Only available when the request is authorized via a Bearer token.
	PremiumType int `json:"premium_type"`

	// Whether the user is an Official Discord System user (part of the urgent message system).
	System bool `json:"system"`

	// The flags on a user's account.
	// Only available when the request is authorized via a Bearer token.
	Flags int `json:"flags"`
}

// String returns a unique identifier of the form username#discriminator
func (u *User) String() string {
	return u.Username + "#" + u.Discriminator
}

// Mention return a string which mentions the user
func (u *User) Mention() string {
	return "<@" + u.ID + ">"
}

// AvatarURL returns a URL to the user's avatar.
//    size:    The size of the user's avatar as a power of two
//             if size is an empty string, no size parameter will
//             be added to the URL.
func (u *User) AvatarURL(size string) string {
	var URL string
	if u.Avatar == "" {
		URL = EndpointDefaultUserAvatar(u.Discriminator)
	} else if strings.HasPrefix(u.Avatar, "a_") {
		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
	} else {
		URL = EndpointUserAvatar(u.ID, u.Avatar)
	}

	if size != "" {
		return URL + "?size=" + size
	}
	return URL
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"time"
)

const (
	ZeroHash = "0000000000000000000000000000000000000000000000000000000000000000"
)

var (
	server    = "localhost:8088"
	serverFct = "localhost:8089"
)

func SetServer(s string) {
	server = s
}

// milliTime returns a 6 byte slice representing the unix time in milliseconds
func milliTime() (r []byte) {
	buf := new(bytes.Buffer)
	t := time.Now().UnixNano()
	m := t / 1e6
	binary.Write(buf, binary.BigEndian, m)
	return buf.Bytes()[2:]
}

// shad Double Sha256 Hash; sha256(sha256(data))
func shad(data []byte) []byte {
	h1 := sha256.Sum256(data)
	h2 := sha256.Sum256(h1[:])
	return h2[:]
}

// sha52
func sha52(data []byte) []byte {
	h1 := sha512.Sum512(data)
	h2 := sha256.Sum256(append(h1[:], data...))
	return h2[:]
}
<commit_msg>added methods for specifying factomd and fctwallet api servers<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"time"
)

const (
	ZeroHash = "0000000000000000000000000000000000000000000000000000000000000000"
)

var (
	server    = "localhost:8088"
	serverFct = "localhost:8089"
)

// SetServer sets the gloabal target for the factomd server
func SetServer(s string) {
	server = s
}

// SetWallet sets the global target for the fctwallet server
func SetWallet(s string) {
	serverFct = s
}

// Server() returns the global server string for debugging
func Server() string {
	return server
}

// milliTime returns a 6 byte slice representing the unix time in milliseconds
func milliTime() (r []byte) {
	buf := new(bytes.Buffer)
	t := time.Now().UnixNano()
	m := t / 1e6
	binary.Write(buf, binary.BigEndian, m)
	return buf.Bytes()[2:]
}

// shad Double Sha256 Hash; sha256(sha256(data))
func shad(data []byte) []byte {
	h1 := sha256.Sum256(data)
	h2 := sha256.Sum256(h1[:])
	return h2[:]
}

// sha52
func sha52(data []byte) []byte {
	h1 := sha512.Sum512(data)
	h2 := sha256.Sum256(append(h1[:], data...))
	return h2[:]
}
<|endoftext|>


<commit_before>package s3gof3r

import (
	"bytes"

	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

// convenience multipliers
const (
	_        = iota
	kb int64 = 1 << (10 * iota)
	mb
	gb
	tb
	pb
	eb
)

// Min and Max functions
func min64(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func max64(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

// Error type and functions for http response
// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
type respError struct {
	Code       string
	Message    string
	Resource   string
	RequestId  string
	StatusCode int
}

func newRespError(r *http.Response) *respError {
	e := new(respError)
	e.StatusCode = r.StatusCode
	b, _ := ioutil.ReadAll(r.Body)
	xml.NewDecoder(bytes.NewReader(b)).Decode(e) // parse error from response
	r.Body.Close()
	return e
}

func (e *respError) Error() string {
	return fmt.Sprintf(
		"%d: %q",
		e.StatusCode,
		e.Message,
	)
}

func bucketFromUrl(subdomain string) string {
	s := strings.Split(subdomain, ".")
	return strings.Join(s[:len(s)-1], ".")
}

func checkClose(c io.Closer, err *error) {
	cerr := c.Close()
	if *err == nil {
		*err = cerr
	}
}
<commit_msg>Remove bucketfromUrl (unused).<commit_after>package s3gof3r

import (
	"bytes"

	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

// convenience multipliers
const (
	_        = iota
	kb int64 = 1 << (10 * iota)
	mb
	gb
	tb
	pb
	eb
)

// Min and Max functions
func min64(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func max64(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

// Error type and functions for http response
// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
type respError struct {
	Code       string
	Message    string
	Resource   string
	RequestId  string
	StatusCode int
}

func newRespError(r *http.Response) *respError {
	e := new(respError)
	e.StatusCode = r.StatusCode
	b, _ := ioutil.ReadAll(r.Body)
	xml.NewDecoder(bytes.NewReader(b)).Decode(e) // parse error from response
	r.Body.Close()
	return e
}

func (e *respError) Error() string {
	return fmt.Sprintf(
		"%d: %q",
		e.StatusCode,
		e.Message,
	)
}

func checkClose(c io.Closer, err *error) {
	cerr := c.Close()
	if *err == nil {
		*err = cerr
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	"golang.org/x/net/context"
	"k8s.io/kubernetes/pkg/api"
	apierrors "k8s.io/kubernetes/pkg/api/errors"
	unversionedAPI "k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
	"k8s.io/kubernetes/pkg/watch"
)

func createEtcdService(kclient *unversioned.Client, etcdName, clusterName string) error {
	svc := makeEtcdService(etcdName, clusterName)
	if _, err := kclient.Services("default").Create(svc); err != nil {
		return err
	}
	return nil
}

// todo: use a struct to replace the huge arg list.
func createEtcdPod(kclient *unversioned.Client, initialCluster []string, m *Member, clusterName, state string, antiAffinity bool) error {
	pod := makeEtcdPod(m, initialCluster, clusterName, state, antiAffinity)
	if _, err := kclient.Pods("default").Create(pod); err != nil {
		return err
	}
	w, err := kclient.Pods("default").Watch(api.SingleObject(api.ObjectMeta{Name: m.Name}))
	if err != nil {
		return err
	}
	_, err = watch.Until(100*time.Second, w, unversioned.PodRunningAndReady)
	return err
}

// TODO: converge the port logic with member ClientAddr() and PeerAddr()
func makeEtcdService(etcdName, clusterName string) *api.Service {
	labels := map[string]string{
		"etcd_node":    etcdName,
		"etcd_cluster": clusterName,
	}
	svc := &api.Service{
		ObjectMeta: api.ObjectMeta{
			Name:   etcdName,
			Labels: labels,
		},
		Spec: api.ServiceSpec{
			Ports: []api.ServicePort{
				{
					Name:       "server",
					Port:       2380,
					TargetPort: intstr.FromInt(2380),
					Protocol:   api.ProtocolTCP,
				},
				{
					Name:       "client",
					Port:       2379,
					TargetPort: intstr.FromInt(2379),
					Protocol:   api.ProtocolTCP,
				},
			},
			Selector: labels,
		},
	}
	return svc
}

// todo: use a struct to replace the huge arg list.
func makeEtcdPod(m *Member, initialCluster []string, clusterName, state string, antiAffinity bool) *api.Pod {
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: m.Name,
			Labels: map[string]string{
				"app":          "etcd",
				"etcd_node":    m.Name,
				"etcd_cluster": clusterName,
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Command: []string{
						"/usr/local/bin/etcd",
						"--name",
						m.Name,
						"--initial-advertise-peer-urls",
						m.PeerAddr(),
						"--listen-peer-urls",
						"http://0.0.0.0:2380",
						"--listen-client-urls",
						"http://0.0.0.0:2379",
						"--advertise-client-urls",
						m.ClientAddr(),
						"--initial-cluster",
						strings.Join(initialCluster, ","),
						"--initial-cluster-state",
						state,
					},
					Name:  m.Name,
					Image: "gcr.io/coreos-k8s-scale-testing/etcd-amd64:3.0.6",
					Ports: []api.ContainerPort{
						{
							Name:          "server",
							ContainerPort: int32(2380),
							Protocol:      api.ProtocolTCP,
						},
					},
				},
			},
			RestartPolicy: api.RestartPolicyNever,
		},
	}

	if !antiAffinity {
		return pod
	}

	// set pod anti-affinity with the pods that belongs to the same etcd cluster
	affinity := api.Affinity{
		PodAntiAffinity: &api.PodAntiAffinity{
			RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
				api.PodAffinityTerm{
					LabelSelector: &unversionedAPI.LabelSelector{
						MatchLabels: map[string]string{
							"etcd_cluster": clusterName,
						},
					},
				},
			},
		},
	}

	affinityb, err := json.Marshal(affinity)
	if err != nil {
		panic("failed to marshal affinty struct")
	}

	pod.Annotations[api.AffinityAnnotationKey] = string(affinityb)

	return pod
}

func mustCreateClient(host string) *unversioned.Client {
	if len(host) == 0 {
		cfg, err := restclient.InClusterConfig()
		if err != nil {
			panic(err)
		}
		c, err := unversioned.NewInCluster()
		if err != nil {
			panic(err)
		}
		masterHost = cfg.Host
		return c
	}

	hostUrl, err := url.Parse(host)
	if err != nil {
		panic(fmt.Sprintf("error parsing host url %s : %v", host, err))
	}
	cfg := &restclient.Config{
		Host:  host,
		QPS:   100,
		Burst: 100,
	}
	if hostUrl.Scheme == "https" {
		cfg.TLSClientConfig = tlsConfig
		cfg.Insecure = tlsInsecure
	}
	c, err := unversioned.New(cfg)
	if err != nil {
		panic(err)
	}
	return c
}

func isKubernetesResourceAlreadyExistError(err error) bool {
	se, ok := err.(*apierrors.StatusError)
	if !ok {
		return false
	}
	if se.Status().Code == http.StatusConflict && se.Status().Reason == unversionedAPI.StatusReasonAlreadyExists {
		return true
	}
	return false
}

func isKubernetesResourceNotFoundError(err error) bool {
	se, ok := err.(*apierrors.StatusError)
	if !ok {
		return false
	}
	if se.Status().Code == http.StatusNotFound && se.Status().Reason == unversionedAPI.StatusReasonNotFound {
		return true
	}
	return false
}

func waitMemberReady(cli *clientv3.Client) error {
	for {
		_, err := cli.Get(context.TODO(), "/")
		if err == rpctypes.ErrNotCapable {
			continue
		}
		return err
	}
}

func listETCDCluster(httpClient *http.Client) (*http.Response, error) {
	return httpClient.Get(masterHost + "/apis/coreos.com/v1/namespaces/default/etcdclusters")
}

func watchETCDCluster(httpClient *http.Client, resourceVersion string) (*http.Response, error) {
	return httpClient.Get(masterHost + "/apis/coreos.com/v1/namespaces/default/etcdclusters?watch=true&resourceVersion=" + resourceVersion)
}
<commit_msg>set etcd initial cluster token<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	"github.com/pborman/uuid"
	"golang.org/x/net/context"
	"k8s.io/kubernetes/pkg/api"
	apierrors "k8s.io/kubernetes/pkg/api/errors"
	unversionedAPI "k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
	"k8s.io/kubernetes/pkg/watch"
)

func createEtcdService(kclient *unversioned.Client, etcdName, clusterName string) error {
	svc := makeEtcdService(etcdName, clusterName)
	if _, err := kclient.Services("default").Create(svc); err != nil {
		return err
	}
	return nil
}

// todo: use a struct to replace the huge arg list.
func createEtcdPod(kclient *unversioned.Client, initialCluster []string, m *Member, clusterName, state string, antiAffinity bool) error {
	pod := makeEtcdPod(m, initialCluster, clusterName, state, antiAffinity)
	if _, err := kclient.Pods("default").Create(pod); err != nil {
		return err
	}
	w, err := kclient.Pods("default").Watch(api.SingleObject(api.ObjectMeta{Name: m.Name}))
	if err != nil {
		return err
	}
	_, err = watch.Until(100*time.Second, w, unversioned.PodRunningAndReady)
	return err
}

// TODO: converge the port logic with member ClientAddr() and PeerAddr()
func makeEtcdService(etcdName, clusterName string) *api.Service {
	labels := map[string]string{
		"etcd_node":    etcdName,
		"etcd_cluster": clusterName,
	}
	svc := &api.Service{
		ObjectMeta: api.ObjectMeta{
			Name:   etcdName,
			Labels: labels,
		},
		Spec: api.ServiceSpec{
			Ports: []api.ServicePort{
				{
					Name:       "server",
					Port:       2380,
					TargetPort: intstr.FromInt(2380),
					Protocol:   api.ProtocolTCP,
				},
				{
					Name:       "client",
					Port:       2379,
					TargetPort: intstr.FromInt(2379),
					Protocol:   api.ProtocolTCP,
				},
			},
			Selector: labels,
		},
	}
	return svc
}

// todo: use a struct to replace the huge arg list.
func makeEtcdPod(m *Member, initialCluster []string, clusterName, state string, antiAffinity bool) *api.Pod {
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: m.Name,
			Labels: map[string]string{
				"app":          "etcd",
				"etcd_node":    m.Name,
				"etcd_cluster": clusterName,
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Command: []string{
						"/usr/local/bin/etcd",
						"--name",
						m.Name,
						"--initial-advertise-peer-urls",
						m.PeerAddr(),
						"--listen-peer-urls",
						"http://0.0.0.0:2380",
						"--listen-client-urls",
						"http://0.0.0.0:2379",
						"--advertise-client-urls",
						m.ClientAddr(),
						"--initial-cluster",
						strings.Join(initialCluster, ","),
						"--initial-cluster-state",
						state,
						"--initial-cluster-token",
						uuid.New(),
					},
					Name:  m.Name,
					Image: "gcr.io/coreos-k8s-scale-testing/etcd-amd64:3.0.6",
					Ports: []api.ContainerPort{
						{
							Name:          "server",
							ContainerPort: int32(2380),
							Protocol:      api.ProtocolTCP,
						},
					},
				},
			},
			RestartPolicy: api.RestartPolicyNever,
		},
	}

	if !antiAffinity {
		return pod
	}

	// set pod anti-affinity with the pods that belongs to the same etcd cluster
	affinity := api.Affinity{
		PodAntiAffinity: &api.PodAntiAffinity{
			RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
				api.PodAffinityTerm{
					LabelSelector: &unversionedAPI.LabelSelector{
						MatchLabels: map[string]string{
							"etcd_cluster": clusterName,
						},
					},
				},
			},
		},
	}

	affinityb, err := json.Marshal(affinity)
	if err != nil {
		panic("failed to marshal affinty struct")
	}

	pod.Annotations[api.AffinityAnnotationKey] = string(affinityb)

	return pod
}

func mustCreateClient(host string) *unversioned.Client {
	if len(host) == 0 {
		cfg, err := restclient.InClusterConfig()
		if err != nil {
			panic(err)
		}
		c, err := unversioned.NewInCluster()
		if err != nil {
			panic(err)
		}
		masterHost = cfg.Host
		return c
	}

	hostUrl, err := url.Parse(host)
	if err != nil {
		panic(fmt.Sprintf("error parsing host url %s : %v", host, err))
	}
	cfg := &restclient.Config{
		Host:  host,
		QPS:   100,
		Burst: 100,
	}
	if hostUrl.Scheme == "https" {
		cfg.TLSClientConfig = tlsConfig
		cfg.Insecure = tlsInsecure
	}
	c, err := unversioned.New(cfg)
	if err != nil {
		panic(err)
	}
	return c
}

func isKubernetesResourceAlreadyExistError(err error) bool {
	se, ok := err.(*apierrors.StatusError)
	if !ok {
		return false
	}
	if se.Status().Code == http.StatusConflict && se.Status().Reason == unversionedAPI.StatusReasonAlreadyExists {
		return true
	}
	return false
}

func isKubernetesResourceNotFoundError(err error) bool {
	se, ok := err.(*apierrors.StatusError)
	if !ok {
		return false
	}
	if se.Status().Code == http.StatusNotFound && se.Status().Reason == unversionedAPI.StatusReasonNotFound {
		return true
	}
	return false
}

func waitMemberReady(cli *clientv3.Client) error {
	for {
		_, err := cli.Get(context.TODO(), "/")
		if err == rpctypes.ErrNotCapable {
			continue
		}
		return err
	}
}

func listETCDCluster(httpClient *http.Client) (*http.Response, error) {
	return httpClient.Get(masterHost + "/apis/coreos.com/v1/namespaces/default/etcdclusters")
}

func watchETCDCluster(httpClient *http.Client, resourceVersion string) (*http.Response, error) {
	return httpClient.Get(masterHost + "/apis/coreos.com/v1/namespaces/default/etcdclusters?watch=true&resourceVersion=" + resourceVersion)
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/boot2docker/boot2docker-cli/driver"
)

var (
	// We're looking to get e.g. "1.2.0" from "Docker version 1.2.0, build fa7b24f"
	versionRe = regexp.MustCompile(`(\d+\.?){3}`)
)

// Try if addr tcp://addr is readable for n times at wait interval.
func read(addr string, n int, wait time.Duration) error {
	var lastErr error
	for i := 0; i < n; i++ {
		if B2D.Verbose {
			fmt.Printf("Connecting to tcp://%v (attempt #%d)", addr, i)
		}
		conn, err := net.DialTimeout("tcp", addr, 1*time.Second)
		if err != nil {
			lastErr = err
			time.Sleep(wait)
			continue
		}
		defer conn.Close()
		conn.SetDeadline(time.Now().Add(1 * time.Second))
		if _, err = conn.Read(make([]byte, 1)); err != nil {
			lastErr = err
			time.Sleep(wait)
			continue
		}
		return nil
	}
	return lastErr
}

// Check if an addr can be successfully connected.
func ping(addr string) bool {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return false
	}
	defer conn.Close()
	return true
}

// Download the url to the dest path.
func download(dest, url string) error {
	rsp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer rsp.Body.Close()

	// Create the dest dir.
	if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
		return err
	}

	f, err := os.Create(fmt.Sprintf("%s.download", dest))
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())

	if _, err := io.Copy(f, rsp.Body); err != nil {
		// TODO: display download progress?
		return err
	}
	if err := f.Close(); err != nil {
		return err
	}

	if _, err := os.Stat(dest); err == nil {
		backup_dest := dest + ".bak"
		os.Remove(backup_dest)
		if err := os.Rename(dest, backup_dest); err != nil {
			return err
		}
	}
	if err := os.Rename(f.Name(), dest); err != nil {
		return err
	}
	return nil
}

// Get latest release tag name (e.g. "v0.6.0") from a repo on GitHub.
func getLatestReleaseName(url string) (string, error) {
	rsp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer rsp.Body.Close()

	var t []struct {
		Name    string `json:"name"`
		TagName string `json:"tag_name"`
	}
	body, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return "", err
	}

	if err := json.Unmarshal(body, &t); err != nil {
		var e struct {
			Message          string
			DocumentationUrl string
		}
		if err := json.Unmarshal(body, &e); err != nil {
			return "", fmt.Errorf("Error decoding %s\nbody: %s", err, body)
		}
		return "", fmt.Errorf("Error getting releases: %s\n see %s", e.Message, e.DocumentationUrl)
	}
	if len(t) == 0 {
		return "", fmt.Errorf("no releases found")
	}

	// Looking up by tag instead of release.
	// Github API call for docker releases yields nothing,
	// so we use tags API call in this case.
	name := ""
	if strings.Contains(url, "tags") {
		name = t[0].Name
	} else {
		name = t[0].TagName
	}
	return name, nil
}

func getLocalClientVersion() (string, error) {
	versionOutput, err := exec.Command("docker", "-v").Output()
	if err != nil {
		return "", err
	}
	versionNumber := versionRe.FindString(string(versionOutput))

	return versionNumber, nil
}

func cmdInteractive(m driver.Machine, args ...string) error {
	cmd := getSSHCommand(m, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

//swiped from dotcloud/docker/utils/utils.go
func CopyFile(src, dst string) (int64, error) {
	if src == dst {
		return 0, nil
	}
	sf, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer sf.Close()
	if err := os.Remove(dst); err != nil && !os.IsNotExist(err) {
		return 0, err
	}
	df, err := os.Create(dst)
	if err != nil {
		return 0, err
	}
	defer df.Close()
	return io.Copy(df, sf)
}

func reader(r io.Reader) {
	buf := make([]byte, 1024)
	for {
		_, err := io.ReadAtLeast(r, buf[:], 20)
		if err != nil {
			return
		}
	}
}

func getSSHCommand(m driver.Machine, args ...string) *exec.Cmd {

	DefaultSSHArgs := []string{
		"-o", "IdentitiesOnly=yes",
		"-o", "StrictHostKeyChecking=no",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
		"-p", fmt.Sprintf("%d", m.GetSSHPort()),
		"-i", B2D.SSHKey,
		"docker@localhost",
	}

	sshArgs := append(DefaultSSHArgs, args...)
	cmd := exec.Command(B2D.SSH, sshArgs...)
	if B2D.Verbose {
		cmd.Stderr = os.Stderr
		log.Printf("executing: %v %v", cmd.Path, strings.Join(cmd.Args, " "))
	}

	return cmd
}

func RequestIPFromSSH(m driver.Machine) (string, error) {
	cmd := getSSHCommand(m, "ip addr show dev eth1")

	b, err := cmd.Output()
	if err != nil {
		return "", err
	}
	out := string(b)
	if B2D.Verbose {
		fmt.Printf("SSH returned: %s\nEND SSH\n", out)
	}
	// parse to find: inet 192.168.59.103/24 brd 192.168.59.255 scope global eth1
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		vals := strings.Split(strings.TrimSpace(line), " ")
		if len(vals) >= 2 && vals[0] == "inet" {
			return vals[1][:strings.Index(vals[1], "/")], nil
		}
	}

	return "", fmt.Errorf("No IP address found %s", out)
}

func RequestSocketFromSSH(m driver.Machine) (string, error) {
	cmd := getSSHCommand(m, "grep tcp:// /proc/$(cat /var/run/docker.pid)/cmdline")

	b, err := cmd.Output()
	if err != nil {
		return "", err
	}
	out := string(b)
	if B2D.Verbose {
		fmt.Printf("SSH returned: %s\nEND SSH\n", out)
	}
	// Lets only use the first one - its possible to specify more than one...
	lines := strings.Split(out, "\n")
	tcpRE := regexp.MustCompile(`^(tcp://)(0.0.0.0)(:.*)`)
	if s := tcpRE.FindStringSubmatch(lines[0]); s != nil {
		IP, err := RequestIPFromSSH(m)
		if err != nil {
			return "", err
		}
		return s[1] + IP + s[3], nil
	}
	if !strings.HasPrefix(lines[0], "tcp://") {
		return "", fmt.Errorf("Error requesting Docker Socket: %s", lines[0])
	}
	return lines[0], nil
}

// use the serial port socket to ask what the VM's host only IP is
func RequestIPFromSerialPort(socket string) (string, error) {
	c, err := net.Dial("unix", socket)

	if err != nil {
		return "", err
	}
	defer c.Close()
	c.SetDeadline(time.Now().Add(time.Second))

	line := ""
	_, err = c.Write([]byte("\r"))
	_, err = c.Write([]byte("docker\r"))

	IP := ""
	fullLog := ""

	for IP == "" {
		_, err := c.Write([]byte("ip addr show dev eth1\r"))
		if err != nil {
			return "", err
		}
		time.Sleep(1 * time.Second)
		buf := make([]byte, 1024)
		for {
			n, err := c.Read(buf[:])
			if err != nil {
				return "", err
			}
			line = line + string(buf[0:n])
			fullLog += string(buf[0:n])
			if strings.Contains(line, "\n") {
				//go looking for the string we want, and chomp line to after the \n
				if i := strings.IndexAny(line, "\n"); i != -1 {
					//     inet 10.180.1.3/16 brd 10.180.255.255 scope global wlan0
					inetRE := regexp.MustCompile(`^[\t ]*inet ([0-9.]*).*$`)
					if ip := inetRE.FindStringSubmatch(line[:i]); ip != nil {
						IP = ip[1]
						// clean up
						break
					} else {
						line = line[i+1:]
					}
				}
			}
		}

	}
	go reader(c)
	//give us time reader clean up
	time.Sleep(1 * time.Second)
	if IP == "" && B2D.Verbose {
		fmt.Printf(fullLog)
	}

	return IP, nil
}

// TODO: need to add or abstract to get a Serial coms version
// RequestCertsUsingSSH requests certs using SSH.
// The assumption is that if the certs are in b2d:/home/docker/.docker
// then the daemon is using TLS. We can't assume that because there are
// certs in the local host's user dir, that the server is using them, so
// for now, make sure things are updated from the server. (for `docker shellinit`)
func RequestCertsUsingSSH(m driver.Machine) (string, error) {
	cmd := getSSHCommand(m, "tar c /home/docker/.docker/*.pem")

	certDir := ""

	b, err := cmd.Output()
	if err == nil {
		dir, err := cfgDir(".boot2docker")
		if err != nil {
			return "", err
		}

		certDir = filepath.Join(dir, "certs", m.GetName())

		// Open the tar archive for reading.
		r := bytes.NewReader(b)
		tr := tar.NewReader(r)

		// Iterate through the files in the archive.
		for {
			hdr, err := tr.Next()
			if err == io.EOF {
				// end of tar archive
				break
			}
			if err != nil {
				return "", err
			}
			filename := filepath.Base(hdr.Name)
			if err := os.MkdirAll(certDir, 0755); err != nil {
				return "", err
			}
			certFile := filepath.Join(certDir, filename)
			fmt.Fprintf(os.Stderr, "Writing %s\n", certFile)
			f, err := os.Create(certFile)
			if err != nil {
				return "", err
			}
			w := bufio.NewWriter(f)
			if _, err := io.Copy(w, tr); err != nil {
				return "", err
			}
			w.Flush()
		}
	}
	return certDir, nil
}
<commit_msg>util: add missing newline at end of debug message<commit_after>package main

import (
	"archive/tar"
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/boot2docker/boot2docker-cli/driver"
)

var (
	// We're looking to get e.g. "1.2.0" from "Docker version 1.2.0, build fa7b24f"
	versionRe = regexp.MustCompile(`(\d+\.?){3}`)
)

// Try if addr tcp://addr is readable for n times at wait interval.
func read(addr string, n int, wait time.Duration) error {
	var lastErr error
	for i := 0; i < n; i++ {
		if B2D.Verbose {
			fmt.Printf("Connecting to tcp://%v (attempt #%d)\n", addr, i)
		}
		conn, err := net.DialTimeout("tcp", addr, 1*time.Second)
		if err != nil {
			lastErr = err
			time.Sleep(wait)
			continue
		}
		defer conn.Close()
		conn.SetDeadline(time.Now().Add(1 * time.Second))
		if _, err = conn.Read(make([]byte, 1)); err != nil {
			lastErr = err
			time.Sleep(wait)
			continue
		}
		return nil
	}
	return lastErr
}

// Check if an addr can be successfully connected.
func ping(addr string) bool {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return false
	}
	defer conn.Close()
	return true
}

// Download the url to the dest path.
func download(dest, url string) error {
	rsp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer rsp.Body.Close()

	// Create the dest dir.
	if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
		return err
	}

	f, err := os.Create(fmt.Sprintf("%s.download", dest))
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())

	if _, err := io.Copy(f, rsp.Body); err != nil {
		// TODO: display download progress?
		return err
	}
	if err := f.Close(); err != nil {
		return err
	}

	if _, err := os.Stat(dest); err == nil {
		backup_dest := dest + ".bak"
		os.Remove(backup_dest)
		if err := os.Rename(dest, backup_dest); err != nil {
			return err
		}
	}
	if err := os.Rename(f.Name(), dest); err != nil {
		return err
	}
	return nil
}

// Get latest release tag name (e.g. "v0.6.0") from a repo on GitHub.
func getLatestReleaseName(url string) (string, error) {
	rsp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer rsp.Body.Close()

	var t []struct {
		Name    string `json:"name"`
		TagName string `json:"tag_name"`
	}
	body, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return "", err
	}

	if err := json.Unmarshal(body, &t); err != nil {
		var e struct {
			Message          string
			DocumentationUrl string
		}
		if err := json.Unmarshal(body, &e); err != nil {
			return "", fmt.Errorf("Error decoding %s\nbody: %s", err, body)
		}
		return "", fmt.Errorf("Error getting releases: %s\n see %s", e.Message, e.DocumentationUrl)
	}
	if len(t) == 0 {
		return "", fmt.Errorf("no releases found")
	}

	// Looking up by tag instead of release.
	// Github API call for docker releases yields nothing,
	// so we use tags API call in this case.
	name := ""
	if strings.Contains(url, "tags") {
		name = t[0].Name
	} else {
		name = t[0].TagName
	}
	return name, nil
}

func getLocalClientVersion() (string, error) {
	versionOutput, err := exec.Command("docker", "-v").Output()
	if err != nil {
		return "", err
	}
	versionNumber := versionRe.FindString(string(versionOutput))

	return versionNumber, nil
}

func cmdInteractive(m driver.Machine, args ...string) error {
	cmd := getSSHCommand(m, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

//swiped from dotcloud/docker/utils/utils.go
func CopyFile(src, dst string) (int64, error) {
	if src == dst {
		return 0, nil
	}
	sf, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer sf.Close()
	if err := os.Remove(dst); err != nil && !os.IsNotExist(err) {
		return 0, err
	}
	df, err := os.Create(dst)
	if err != nil {
		return 0, err
	}
	defer df.Close()
	return io.Copy(df, sf)
}

func reader(r io.Reader) {
	buf := make([]byte, 1024)
	for {
		_, err := io.ReadAtLeast(r, buf[:], 20)
		if err != nil {
			return
		}
	}
}

func getSSHCommand(m driver.Machine, args ...string) *exec.Cmd {

	DefaultSSHArgs := []string{
		"-o", "IdentitiesOnly=yes",
		"-o", "StrictHostKeyChecking=no",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
		"-p", fmt.Sprintf("%d", m.GetSSHPort()),
		"-i", B2D.SSHKey,
		"docker@localhost",
	}

	sshArgs := append(DefaultSSHArgs, args...)
	cmd := exec.Command(B2D.SSH, sshArgs...)
	if B2D.Verbose {
		cmd.Stderr = os.Stderr
		log.Printf("executing: %v %v", cmd.Path, strings.Join(cmd.Args, " "))
	}

	return cmd
}

func RequestIPFromSSH(m driver.Machine) (string, error) {
	cmd := getSSHCommand(m, "ip addr show dev eth1")

	b, err := cmd.Output()
	if err != nil {
		return "", err
	}
	out := string(b)
	if B2D.Verbose {
		fmt.Printf("SSH returned: %s\nEND SSH\n", out)
	}
	// parse to find: inet 192.168.59.103/24 brd 192.168.59.255 scope global eth1
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		vals := strings.Split(strings.TrimSpace(line), " ")
		if len(vals) >= 2 && vals[0] == "inet" {
			return vals[1][:strings.Index(vals[1], "/")], nil
		}
	}

	return "", fmt.Errorf("No IP address found %s", out)
}

func RequestSocketFromSSH(m driver.Machine) (string, error) {
	cmd := getSSHCommand(m, "grep tcp:// /proc/$(cat /var/run/docker.pid)/cmdline")

	b, err := cmd.Output()
	if err != nil {
		return "", err
	}
	out := string(b)
	if B2D.Verbose {
		fmt.Printf("SSH returned: %s\nEND SSH\n", out)
	}
	// Lets only use the first one - its possible to specify more than one...
	lines := strings.Split(out, "\n")
	tcpRE := regexp.MustCompile(`^(tcp://)(0.0.0.0)(:.*)`)
	if s := tcpRE.FindStringSubmatch(lines[0]); s != nil {
		IP, err := RequestIPFromSSH(m)
		if err != nil {
			return "", err
		}
		return s[1] + IP + s[3], nil
	}
	if !strings.HasPrefix(lines[0], "tcp://") {
		return "", fmt.Errorf("Error requesting Docker Socket: %s", lines[0])
	}
	return lines[0], nil
}

// use the serial port socket to ask what the VM's host only IP is
func RequestIPFromSerialPort(socket string) (string, error) {
	c, err := net.Dial("unix", socket)

	if err != nil {
		return "", err
	}
	defer c.Close()
	c.SetDeadline(time.Now().Add(time.Second))

	line := ""
	_, err = c.Write([]byte("\r"))
	_, err = c.Write([]byte("docker\r"))

	IP := ""
	fullLog := ""

	for IP == "" {
		_, err := c.Write([]byte("ip addr show dev eth1\r"))
		if err != nil {
			return "", err
		}
		time.Sleep(1 * time.Second)
		buf := make([]byte, 1024)
		for {
			n, err := c.Read(buf[:])
			if err != nil {
				return "", err
			}
			line = line + string(buf[0:n])
			fullLog += string(buf[0:n])
			if strings.Contains(line, "\n") {
				//go looking for the string we want, and chomp line to after the \n
				if i := strings.IndexAny(line, "\n"); i != -1 {
					//     inet 10.180.1.3/16 brd 10.180.255.255 scope global wlan0
					inetRE := regexp.MustCompile(`^[\t ]*inet ([0-9.]*).*$`)
					if ip := inetRE.FindStringSubmatch(line[:i]); ip != nil {
						IP = ip[1]
						// clean up
						break
					} else {
						line = line[i+1:]
					}
				}
			}
		}

	}
	go reader(c)
	//give us time reader clean up
	time.Sleep(1 * time.Second)
	if IP == "" && B2D.Verbose {
		fmt.Printf(fullLog)
	}

	return IP, nil
}

// TODO: need to add or abstract to get a Serial coms version
// RequestCertsUsingSSH requests certs using SSH.
// The assumption is that if the certs are in b2d:/home/docker/.docker
// then the daemon is using TLS. We can't assume that because there are
// certs in the local host's user dir, that the server is using them, so
// for now, make sure things are updated from the server. (for `docker shellinit`)
func RequestCertsUsingSSH(m driver.Machine) (string, error) {
	cmd := getSSHCommand(m, "tar c /home/docker/.docker/*.pem")

	certDir := ""

	b, err := cmd.Output()
	if err == nil {
		dir, err := cfgDir(".boot2docker")
		if err != nil {
			return "", err
		}

		certDir = filepath.Join(dir, "certs", m.GetName())

		// Open the tar archive for reading.
		r := bytes.NewReader(b)
		tr := tar.NewReader(r)

		// Iterate through the files in the archive.
		for {
			hdr, err := tr.Next()
			if err == io.EOF {
				// end of tar archive
				break
			}
			if err != nil {
				return "", err
			}
			filename := filepath.Base(hdr.Name)
			if err := os.MkdirAll(certDir, 0755); err != nil {
				return "", err
			}
			certFile := filepath.Join(certDir, filename)
			fmt.Fprintf(os.Stderr, "Writing %s\n", certFile)
			f, err := os.Create(certFile)
			if err != nil {
				return "", err
			}
			w := bufio.NewWriter(f)
			if _, err := io.Copy(w, tr); err != nil {
				return "", err
			}
			w.Flush()
		}
	}
	return certDir, nil
}
<|endoftext|>


<commit_before>// Package util provides some helpers for working with GopherJS.
package util

import "github.com/gopherjs/gopherjs/js"

func Float64Slice(o js.Object) []float64 {
	if o.IsNull() {
		return nil
	}
	d := o.Interface().([]interface{})
	ret := make([]float64, len(d))
	for i, e := range d {
		ret[i] = e.(float64)
	}
	return ret
}

func IntSlice(o js.Object) []int {
	if o.IsNull() {
		return nil
	}
	d := o.Interface().([]interface{})
	ret := make([]int, len(d))
	for i, e := range d {
		ret[i] = int(e.(float64))
	}
	return ret
}

func StringSlice(o js.Object) []string {
	if o.IsNull() {
		return nil
	}
	d := o.Interface().([]interface{})
	ret := make([]string, len(d))
	for i, e := range d {
		ret[i] = e.(string)
	}
	return ret
}

type Err struct {
	js.Object
	Message string `js:"message"`
	Name    string `js:"name"`
	File    string `js:"fileName"`   // Mozilla extension
	Line    int    `js:"lineNumber"` // Mozilla extension
	Stack   string `js:"stack"`      // Chrome/Microsoft extension
}

func (err Err) Error() string {
	return err.Message
}

func Error(o js.Object) error {
	if o.IsNull() {
		return nil
	}
	return Err{Object: o}
}

type EventTarget struct {
	js.Object
}

func (t EventTarget) AddEventListener(typ string, useCapture bool, listener func(js.Object)) {
	t.Call("addEventListener", typ, listener, useCapture)
}

func (t EventTarget) RemoveEventListener(typ string, useCapture bool, listener func(js.Object)) {
	t.Call("removeEventListener", typ, listener, useCapture)
}
<commit_msg>enforce vanity import path<commit_after>// Package util provides some helpers for working with GopherJS.
package util // import "honnef.co/go/js/util"

import "github.com/gopherjs/gopherjs/js"

func Float64Slice(o js.Object) []float64 {
	if o.IsNull() {
		return nil
	}
	d := o.Interface().([]interface{})
	ret := make([]float64, len(d))
	for i, e := range d {
		ret[i] = e.(float64)
	}
	return ret
}

func IntSlice(o js.Object) []int {
	if o.IsNull() {
		return nil
	}
	d := o.Interface().([]interface{})
	ret := make([]int, len(d))
	for i, e := range d {
		ret[i] = int(e.(float64))
	}
	return ret
}

func StringSlice(o js.Object) []string {
	if o.IsNull() {
		return nil
	}
	d := o.Interface().([]interface{})
	ret := make([]string, len(d))
	for i, e := range d {
		ret[i] = e.(string)
	}
	return ret
}

type Err struct {
	js.Object
	Message string `js:"message"`
	Name    string `js:"name"`
	File    string `js:"fileName"`   // Mozilla extension
	Line    int    `js:"lineNumber"` // Mozilla extension
	Stack   string `js:"stack"`      // Chrome/Microsoft extension
}

func (err Err) Error() string {
	return err.Message
}

func Error(o js.Object) error {
	if o.IsNull() {
		return nil
	}
	return Err{Object: o}
}

type EventTarget struct {
	js.Object
}

func (t EventTarget) AddEventListener(typ string, useCapture bool, listener func(js.Object)) {
	t.Call("addEventListener", typ, listener, useCapture)
}

func (t EventTarget) RemoveEventListener(typ string, useCapture bool, listener func(js.Object)) {
	t.Call("removeEventListener", typ, listener, useCapture)
}
<|endoftext|>


<commit_before>package decimal

import (
	"math/big"

	"github.com/ericlagergren/decimal/internal/arith"
	"github.com/ericlagergren/decimal/internal/arith/checked"
	"github.com/ericlagergren/decimal/internal/arith/pow"
)

// cmpNorm compares x and y in the range [0.1, 0.999...] and returns true if x
// > y.
func cmpNorm(x int64, xs int, y int64, ys int) (ok bool) {
	goodx, goody := true, true

	// xs, ys > 0, so no overflow
	if diff := xs - ys; diff != 0 {
		if diff < 0 {
			x, goodx = checked.MulPow10(x, -uint64(diff))
		} else {
			y, goody = checked.MulPow10(y, uint64(diff))
		}
	}
	if goodx {
		if goody {
			return arith.AbsCmp(x, y) > 0
		}
		return false
	}
	return true
}

// cmpNormBig compares x and y in the range [0.1, 0.999...] and returns true if
// x > y.
func cmpNormBig(x *big.Int, xs int, y *big.Int, ys int) (ok bool) {
	if diff := xs - ys; diff != 0 {
		if diff < 0 {
			x = checked.MulBigPow10(new(big.Int).Set(x), uint64(-diff))
		} else {
			y = checked.MulBigPow10(new(big.Int).Set(y), uint64(diff))
		}
	}
	return arith.BigAbsCmp(x, y) > 0
}

// scalex adjusts x by scale. If scale < 0, x = x * 10^-scale, otherwise
// x = x / 10^scale.
func scalex(x int64, scale int32) (sx int64, ok bool) {
	if scale < 0 {
		sx, ok = checked.MulPow10(x, -uint64(scale))
		if !ok {
			return 0, false
		}
		return sx, true
	}
	p, ok := pow.TenInt(uint64(scale))
	if !ok {
		return 0, false
	}
	return x / p, true
}
<commit_msg>update call to BigCmpAbs<commit_after>package decimal

import (
	"math/big"

	"github.com/ericlagergren/decimal/internal/arith"
	"github.com/ericlagergren/decimal/internal/arith/checked"
	"github.com/ericlagergren/decimal/internal/arith/pow"
	"github.com/ericlagergren/decimal/internal/compat"
)

// cmpNorm compares x and y in the range [0.1, 0.999...] and returns true if x
// > y.
func cmpNorm(x int64, xs int, y int64, ys int) (ok bool) {
	goodx, goody := true, true

	// xs, ys > 0, so no overflow
	if diff := xs - ys; diff != 0 {
		if diff < 0 {
			x, goodx = checked.MulPow10(x, -uint64(diff))
		} else {
			y, goody = checked.MulPow10(y, uint64(diff))
		}
	}
	if goodx {
		if goody {
			return arith.AbsCmp(x, y) > 0
		}
		return false
	}
	return true
}

// cmpNormBig compares x and y in the range [0.1, 0.999...] and returns true if
// x > y.
func cmpNormBig(x *big.Int, xs int, y *big.Int, ys int) (ok bool) {
	if diff := xs - ys; diff != 0 {
		if diff < 0 {
			x = checked.MulBigPow10(new(big.Int).Set(x), uint64(-diff))
		} else {
			y = checked.MulBigPow10(new(big.Int).Set(y), uint64(diff))
		}
	}
	return compat.BigCmpAbs(x, y) > 0
}

// scalex adjusts x by scale. If scale < 0, x = x * 10^-scale, otherwise
// x = x / 10^scale.
func scalex(x int64, scale int32) (sx int64, ok bool) {
	if scale < 0 {
		sx, ok = checked.MulPow10(x, -uint64(scale))
		if !ok {
			return 0, false
		}
		return sx, true
	}
	p, ok := pow.TenInt(uint64(scale))
	if !ok {
		return 0, false
	}
	return x / p, true
}
<|endoftext|>


<commit_before>package shell

// Fish is the fish shell integration.
var Fish = Shell(`# Put the line below in ~/.config/fish/config.fish:
#
#   status --is-interactive; and . (jump shell fish | psub)
#
# The following lines are autogenerated:

function __jump_add --on-variable PWD
  status --is-command-substitution; and return
  jump chdir
end

function j
  set -l dir (jump cd $argv)
  test -d "$dir"; and cd "$dir"
end

complete --command j --exclusive --arguments '(jump hint)'
`)
<commit_msg>Use a modern fish shell integration hint<commit_after>package shell

// Fish is the fish shell integration.
var Fish = Shell(`# Put the line below in ~/.config/fish/config.fish:
#
#   status --is-interactive; and source (jump shell fish | psub)
#
# The following lines are autogenerated:

function __jump_add --on-variable PWD
  status --is-command-substitution; and return
  jump chdir
end

function j
  set -l dir (jump cd $argv)
  test -d "$dir"; and cd "$dir"
end

complete --command j --exclusive --arguments '(jump hint)'
`)
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	lgr := log.New(os.Stderr, "", 0)

	err := run(os.Stdin, os.Stdout)
	if err != nil {
		lgr.Printf("run: %v", err)
		os.Exit(1)
	}
}

func run(stdin io.Reader, stdout io.Writer) error {
	s := bufio.NewScanner(stdin)
	for s.Scan() {
		// Read the keyboad input.
		line := s.Text()
		cmd := strings.TrimSpace(line)
		if cmd == "exit" {
			break
		}

		_, err := fmt.Fprintln(stdout, line)
		if err != nil {
			return err
		}
	}

	err := s.Err()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>shell: use fscan<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	lgr := log.New(os.Stderr, "", 0)

	err := run(os.Stdin, os.Stdout)
	if err != nil {
		lgr.Printf("run: %v", err)
		os.Exit(1)
	}
}

func run(stdin io.Reader, stdout io.Writer) error {
	var raw string
	for {
		_, err := fmt.Fprintf(stdout, "> ")
		if err != nil {
			return err
		}

		_, err = fmt.Fscanf(stdin, "%s", &raw)
		if err != nil {
			return err
		}

		cmd := strings.TrimSpace(raw)
		if cmd == "exit" {
			break
		}

		_, err = fmt.Fprintln(stdout, cmd)
		if err != nil {
			return fmt.Errorf("write: %v", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Executing shell commands via simple http server.
Settings through 2 command line arguments, path and shell command.
By default bind to :8080.

Install/update:
	go get -u github.com/msoap/shell2http
	ln -s $GOPATH/bin/shell2http ~/bin/shell2http

Usage:
	shell2http [options] /path "shell command" /path2 "shell command2" ...
	options:
		-host="host"    : host for http server, default - all interfaces
		-port=NNNN      : port for http server, default - 8080
		-form           : parse query into environment vars
		-cgi            : set some CGI variables in environment
		                  write POST-data to STDIN (if not set -form)
		-export-vars=var: export environment vars ("VAR1,VAR2,...")
		-export-all-vars: export all current environment vars
		-no-index       : dont generate index page
		-add-exit       : add /exit command
		-log=filename   : log filename, default - STDOUT
		-version
		-help

Examples:
	shell2http /top "top -l 1 | head -10"
	shell2http /date date /ps "ps aux"
	shell2http /env 'printenv | sort' /env/path 'echo $PATH' /env/gopath 'echo $GOPATH'
	shell2http /shell_vars_json 'perl -MJSON -E "say to_json(\%ENV)"'
	shell2http /cal_html 'echo "
Calendar
Date: $(date)

$(cal $(date +%Y))
"'
	shell2http -form /form 'echo $v_from, $v_to'
	shell2http -cgi /user_agent 'echo $HTTP_USER_AGENT'
	shell2http -export-vars=GOPATH /get 'echo $GOPATH'

More complex examples:

simple http-proxy server (for logging all URLs)
	# setup proxy as "http://localhost:8080/"
	shell2http \
		-log=/dev/null \
		-cgi \
		/ 'echo $REQUEST_URI 1>&2; [ "$REQUEST_METHOD" == "POST" ] && post_param="-d@-"; curl -L -s $post_param "$REQUEST_URI" -A "$HTTP_USER_AGENT"'

test slow connection
	# http://localhost:8080/slow?duration=10
	shell2http -form /slow 'sleep ${v_duration:-1}; echo "sleep ${v_duration:-1} seconds"'

proxy with cache in files (for debug with production API with rate limit)
	# get "http://localhost:8080/url=http://api.url/"
	shell2http \
		-form \
		/form 'echo "<form action=/get>URL: <input name=url><input type=submit>"' \
		/get 'MD5=$(printf "%s" $v_url | md5); cat cache_$MD5 || (curl -s $v_url | tee cache_$MD5)'

remote sound volume control (Mac OS)
	shell2http \
		/get  'osascript -e "output volume of (get volume settings)"' \
		/up   'osascript -e "set volume output volume (($(osascript -e "output volume of (get volume settings)")+10))"' \
		/down 'osascript -e "set volume output volume (($(osascript -e "output volume of (get volume settings)")-10))"'

remote control for Vox.app player (Mac OS)
	shell2http \
		/play_pause 'osascript -e "tell application \"Vox\" to playpause" && echo ok' \
		/get_info 'osascript -e "tell application \"Vox\"" -e "\"Artist: \" & artist & \"\n\" & \"Album: \" & album & \"\n\" & \"Track: \" & track" -e "end tell"'

get four random OS X wallpapers
	shell2http \
		/img 'cat "$(ls "/Library/Desktop Pictures/"*.jpg | ruby -e "puts STDIN.readlines.shuffle[0]")"' \
		/wallpapers 'echo "
OS X Wallpapers
"; seq 4 | xargs -I@ echo ""'
*/
package main

import (
	"flag"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

// version
const VERSION = 1.3

// default port for http-server
const PORT = 8080

// ------------------------------------------------------------------
const INDEX_HTML = `<!DOCTYPE html>

	<title>shell2http</title>

shell2http

		%s

	Get from: github.com/msoap/shell2http

`

// ------------------------------------------------------------------

// Command - one command type
type Command struct {
	path string
	cmd  string
}

// Config - config struct
type Config struct {
	host          string // server host
	port          int    // server port
	setCGI        bool   // set CGI variables
	setForm       bool   // parse form from URL
	noIndex       bool   // dont generate index page
	addExit       bool   // add /exit command
	exportVars    string // list of environment vars for export to script
	exportAllVars bool   // export all current environment vars
}

// ------------------------------------------------------------------
// parse arguments
func getConfig() (cmd_handlers []Command, app_config Config, err error) {
	var log_filename string
	flag.StringVar(&log_filename, "log", "", "log filename, default - STDOUT")
	flag.IntVar(&app_config.port, "port", PORT, "port for http server")
	flag.StringVar(&app_config.host, "host", "", "host for http server")
	flag.BoolVar(&app_config.setCGI, "cgi", false, "set some CGI variables in environment")
	flag.StringVar(&app_config.exportVars, "export-vars", "", "export environment vars (\"VAR1,VAR2,...\")")
	flag.BoolVar(&app_config.exportAllVars, "export-all-vars", false, "export all current environment vars")
	flag.BoolVar(&app_config.setForm, "form", false, "parse query into environment vars")
	flag.BoolVar(&app_config.noIndex, "no-index", false, "dont generate index page")
	flag.BoolVar(&app_config.addExit, "add-exit", false, "add /exit command")
	flag.Usage = func() {
		fmt.Printf("usage: %s [options] /path \"shell command\" /path2 \"shell command2\"\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}
	version := flag.Bool("version", false, "get version")
	flag.Parse()
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	// setup log file
	if len(log_filename) > 0 {
		fh_log, err := os.OpenFile(log_filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatalf("error opening log file: %v", err)
		}
		log.SetOutput(fh_log)
	}

	// need >= 2 arguments and count of it must be even
	args := flag.Args()
	if len(args) < 2 || len(args)%2 == 1 {
		return nil, Config{}, fmt.Errorf("error: need pairs of path and shell command")
	}

	for i := 0; i < len(args); i += 2 {
		path, cmd := args[i], args[i+1]
		if path[0] != '/' {
			return nil, Config{}, fmt.Errorf("error: path %s dont starts with /", path)
		}
		cmd_handlers = append(cmd_handlers, Command{path: path, cmd: cmd})
	}

	return cmd_handlers, app_config, nil
}

// ------------------------------------------------------------------
// setup http handlers
func setupHandlers(cmd_handlers []Command, app_config Config) {
	index_li_html := ""
	exists_root_path := false

	for _, row := range cmd_handlers {
		path, cmd := row.path, row.cmd
		shell_handler := func(rw http.ResponseWriter, req *http.Request) {
			log.Println(req.Method, path)

			shell, params := "sh", []string{"-c", cmd}
			if runtime.GOOS == "windows" {
				shell, params = "cmd", []string{"/C", cmd}
			}
			os_exec_command := exec.Command(shell, params...)

			proxySystemEnv(os_exec_command, app_config)
			if app_config.setForm {
				getForm(os_exec_command, req)
			}

			if app_config.setCGI {
				setCGIEnv(os_exec_command, req, app_config)

				// get POST data to stdin of script (if not parse form vars above)
				if req.Method == "POST" && !app_config.setForm {

					stdin, err := os_exec_command.StdinPipe()
					if err != nil {
						log.Println("get STDIN error: ", err)
						return
					}

					post_body, err := ioutil.ReadAll(req.Body)
					if err != nil {
						log.Println("read POST data error: ", err)
						return
					}

					io.WriteString(stdin, string(post_body))
					stdin.Close()
				}
			}

			os_exec_command.Stderr = os.Stderr
			shell_out, err := os_exec_command.Output()

			if err != nil {
				log.Println("exec error: ", err)
				fmt.Fprint(rw, "exec error: ", err)
			} else {
				fmt.Fprint(rw, string(shell_out))
			}

			return
		}

		http.HandleFunc(path, shell_handler)
		exists_root_path = exists_root_path || path == "/"

		log.Printf("register: %s (%s)\n", path, cmd)
		index_li_html += fmt.Sprintf(`<li><a href="%s">%s</a> <span style="color: #888">- %s<span></li>`, path, path, html.EscapeString(cmd))
	}

	// --------------
	if app_config.addExit {
		http.HandleFunc("/exit", func(rw http.ResponseWriter, req *http.Request) {
			log.Println("GET /exit")
			fmt.Fprint(rw, "Bye...")
			go os.Exit(0)

			return
		})

		log.Printf("register: %s (%s)\n", "/exit", "/exit")
		index_li_html += fmt.Sprintf(`<li><a href="%s">%s</a></li>`, "/exit", "/exit")
	}

	// --------------
	if !app_config.noIndex && !exists_root_path {
		index_html := fmt.Sprintf(INDEX_HTML, index_li_html)
		http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
			if req.URL.Path != "/" {
				log.Println("404")
				http.NotFound(rw, req)
				return
			}
			log.Println("GET /")
			fmt.Fprint(rw, index_html)

			return
		})
	}
}

// ------------------------------------------------------------------
// set some CGI variables
func setCGIEnv(cmd *exec.Cmd, req *http.Request, app_config Config) {
	// set HTTP_* variables
	for header_name, header_value := range req.Header {
		env_name := strings.ToUpper(strings.Replace(header_name, "-", "_", -1))
		cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_%s=%s", env_name, header_value[0]))
	}

	remote_addr := strings.Split(req.RemoteAddr, ":")
	CGI_vars := [...]struct {
		cgi_name, value string
	}{
		{"PATH_INFO", req.URL.Path},
		{"QUERY_STRING", req.URL.RawQuery},
		{"REMOTE_ADDR", remote_addr[0]},
		{"REMOTE_PORT", remote_addr[1]},
		{"REQUEST_METHOD", req.Method},
		{"REQUEST_URI", req.RequestURI},
		{"SCRIPT_NAME", req.URL.Path},
		{"SERVER_NAME", app_config.host},
		{"SERVER_PORT", fmt.Sprintf("%d", app_config.port)},
		{"SERVER_PROTOCOL", req.Proto},
		{"SERVER_SOFTWARE", "shell2http"},
	}

	for _, row := range CGI_vars {
		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", row.cgi_name, row.value))
	}
}

// ------------------------------------------------------------------
// parse form into environment vars
func getForm(cmd *exec.Cmd, req *http.Request) {
	err := req.ParseForm()
	if err != nil {
		log.Println(err)
		return
	}

	for key, value := range req.Form {
		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "v_"+key, strings.Join(value, ",")))
	}
}

// ------------------------------------------------------------------
// proxy some system vars
func proxySystemEnv(cmd *exec.Cmd, app_config Config) {
	vars_names := []string{"PATH", "HOME", "LANG", "USER", "TMPDIR"}

	if app_config.exportVars != "" {
		vars_names = append(vars_names, strings.Split(app_config.exportVars, ",")...)
	}

	for _, env_raw := range os.Environ() {
		env := strings.SplitN(env_raw, "=", 2)
		if app_config.exportAllVars {
			cmd.Env = append(cmd.Env, env_raw)
		} else {
			for _, env_var_name := range vars_names {
				if env[0] == env_var_name {
					cmd.Env = append(cmd.Env, env_raw)
				}
			}
		}
	}
}

// ------------------------------------------------------------------
func main() {
	cmd_handlers, app_config, err := getConfig()
	if err != nil {
		log.Fatal(err)
	}
	setupHandlers(cmd_handlers, app_config)

	adress := fmt.Sprintf("%s:%d", app_config.host, app_config.port)
	log.Printf("listen http://%s/\n", adress)
	err = http.ListenAndServe(adress, nil)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Refactoring setCGIEnv()<commit_after>/*
Executing shell commands via simple http server.
Settings through 2 command line arguments, path and shell command.
By default bind to :8080.

Install/update:
	go get -u github.com/msoap/shell2http
	ln -s $GOPATH/bin/shell2http ~/bin/shell2http

Usage:
	shell2http [options] /path "shell command" /path2 "shell command2" ...
	options:
		-host="host"    : host for http server, default - all interfaces
		-port=NNNN      : port for http server, default - 8080
		-form           : parse query into environment vars
		-cgi            : set some CGI variables in environment
		                  write POST-data to STDIN (if not set -form)
		-export-vars=var: export environment vars ("VAR1,VAR2,...")
		-export-all-vars: export all current environment vars
		-no-index       : dont generate index page
		-add-exit       : add /exit command
		-log=filename   : log filename, default - STDOUT
		-version
		-help

Examples:
	shell2http /top "top -l 1 | head -10"
	shell2http /date date /ps "ps aux"
	shell2http /env 'printenv | sort' /env/path 'echo $PATH' /env/gopath 'echo $GOPATH'
	shell2http /shell_vars_json 'perl -MJSON -E "say to_json(\%ENV)"'
	shell2http /cal_html 'echo "
Calendar
Date: $(date)

$(cal $(date +%Y))
"'
	shell2http -form /form 'echo $v_from, $v_to'
	shell2http -cgi /user_agent 'echo $HTTP_USER_AGENT'
	shell2http -export-vars=GOPATH /get 'echo $GOPATH'

More complex examples:

simple http-proxy server (for logging all URLs)
	# setup proxy as "http://localhost:8080/"
	shell2http \
		-log=/dev/null \
		-cgi \
		/ 'echo $REQUEST_URI 1>&2; [ "$REQUEST_METHOD" == "POST" ] && post_param="-d@-"; curl -L -s $post_param "$REQUEST_URI" -A "$HTTP_USER_AGENT"'

test slow connection
	# http://localhost:8080/slow?duration=10
	shell2http -form /slow 'sleep ${v_duration:-1}; echo "sleep ${v_duration:-1} seconds"'

proxy with cache in files (for debug with production API with rate limit)
	# get "http://localhost:8080/url=http://api.url/"
	shell2http \
		-form \
		/form 'echo "<form action=/get>URL: <input name=url><input type=submit>"' \
		/get 'MD5=$(printf "%s" $v_url | md5); cat cache_$MD5 || (curl -s $v_url | tee cache_$MD5)'

remote sound volume control (Mac OS)
	shell2http \
		/get  'osascript -e "output volume of (get volume settings)"' \
		/up   'osascript -e "set volume output volume (($(osascript -e "output volume of (get volume settings)")+10))"' \
		/down 'osascript -e "set volume output volume (($(osascript -e "output volume of (get volume settings)")-10))"'

remote control for Vox.app player (Mac OS)
	shell2http \
		/play_pause 'osascript -e "tell application \"Vox\" to playpause" && echo ok' \
		/get_info 'osascript -e "tell application \"Vox\"" -e "\"Artist: \" & artist & \"\n\" & \"Album: \" & album & \"\n\" & \"Track: \" & track" -e "end tell"'

get four random OS X wallpapers
	shell2http \
		/img 'cat "$(ls "/Library/Desktop Pictures/"*.jpg | ruby -e "puts STDIN.readlines.shuffle[0]")"' \
		/wallpapers 'echo "
OS X Wallpapers
"; seq 4 | xargs -I@ echo ""'
*/
package main

import (
	"flag"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

// version
const VERSION = 1.3

// default port for http-server
const PORT = 8080

// ------------------------------------------------------------------
const INDEX_HTML = `<!DOCTYPE html>

	<title>shell2http</title>

shell2http

		%s

	Get from: github.com/msoap/shell2http

`

// ------------------------------------------------------------------

// Command - one command type
type Command struct {
	path string
	cmd  string
}

// Config - config struct
type Config struct {
	host          string // server host
	port          int    // server port
	setCGI        bool   // set CGI variables
	setForm       bool   // parse form from URL
	noIndex       bool   // dont generate index page
	addExit       bool   // add /exit command
	exportVars    string // list of environment vars for export to script
	exportAllVars bool   // export all current environment vars
}

// ------------------------------------------------------------------
// parse arguments
func getConfig() (cmd_handlers []Command, app_config Config, err error) {
	var log_filename string
	flag.StringVar(&log_filename, "log", "", "log filename, default - STDOUT")
	flag.IntVar(&app_config.port, "port", PORT, "port for http server")
	flag.StringVar(&app_config.host, "host", "", "host for http server")
	flag.BoolVar(&app_config.setCGI, "cgi", false, "set some CGI variables in environment")
	flag.StringVar(&app_config.exportVars, "export-vars", "", "export environment vars (\"VAR1,VAR2,...\")")
	flag.BoolVar(&app_config.exportAllVars, "export-all-vars", false, "export all current environment vars")
	flag.BoolVar(&app_config.setForm, "form", false, "parse query into environment vars")
	flag.BoolVar(&app_config.noIndex, "no-index", false, "dont generate index page")
	flag.BoolVar(&app_config.addExit, "add-exit", false, "add /exit command")
	flag.Usage = func() {
		fmt.Printf("usage: %s [options] /path \"shell command\" /path2 \"shell command2\"\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}
	version := flag.Bool("version", false, "get version")
	flag.Parse()
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	// setup log file
	if len(log_filename) > 0 {
		fh_log, err := os.OpenFile(log_filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatalf("error opening log file: %v", err)
		}
		log.SetOutput(fh_log)
	}

	// need >= 2 arguments and count of it must be even
	args := flag.Args()
	if len(args) < 2 || len(args)%2 == 1 {
		return nil, Config{}, fmt.Errorf("error: need pairs of path and shell command")
	}

	for i := 0; i < len(args); i += 2 {
		path, cmd := args[i], args[i+1]
		if path[0] != '/' {
			return nil, Config{}, fmt.Errorf("error: path %s dont starts with /", path)
		}
		cmd_handlers = append(cmd_handlers, Command{path: path, cmd: cmd})
	}

	return cmd_handlers, app_config, nil
}

// ------------------------------------------------------------------
// setup http handlers
func setupHandlers(cmd_handlers []Command, app_config Config) {
	index_li_html := ""
	exists_root_path := false

	for _, row := range cmd_handlers {
		path, cmd := row.path, row.cmd
		shell_handler := func(rw http.ResponseWriter, req *http.Request) {
			log.Println(req.Method, path)

			shell, params := "sh", []string{"-c", cmd}
			if runtime.GOOS == "windows" {
				shell, params = "cmd", []string{"/C", cmd}
			}
			os_exec_command := exec.Command(shell, params...)

			proxySystemEnv(os_exec_command, app_config)
			if app_config.setForm {
				getForm(os_exec_command, req)
			}

			if app_config.setCGI {
				setCGIEnv(os_exec_command, req, app_config)
			}

			os_exec_command.Stderr = os.Stderr
			shell_out, err := os_exec_command.Output()

			if err != nil {
				log.Println("exec error: ", err)
				fmt.Fprint(rw, "exec error: ", err)
			} else {
				fmt.Fprint(rw, string(shell_out))
			}

			return
		}

		http.HandleFunc(path, shell_handler)
		exists_root_path = exists_root_path || path == "/"

		log.Printf("register: %s (%s)\n", path, cmd)
		index_li_html += fmt.Sprintf(`<li><a href="%s">%s</a> <span style="color: #888">- %s<span></li>`, path, path, html.EscapeString(cmd))
	}

	// --------------
	if app_config.addExit {
		http.HandleFunc("/exit", func(rw http.ResponseWriter, req *http.Request) {
			log.Println("GET /exit")
			fmt.Fprint(rw, "Bye...")
			go os.Exit(0)

			return
		})

		log.Printf("register: %s (%s)\n", "/exit", "/exit")
		index_li_html += fmt.Sprintf(`<li><a href="%s">%s</a></li>`, "/exit", "/exit")
	}

	// --------------
	if !app_config.noIndex && !exists_root_path {
		index_html := fmt.Sprintf(INDEX_HTML, index_li_html)
		http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
			if req.URL.Path != "/" {
				log.Println("404")
				http.NotFound(rw, req)
				return
			}
			log.Println("GET /")
			fmt.Fprint(rw, index_html)

			return
		})
	}
}

// ------------------------------------------------------------------
// set some CGI variables
func setCGIEnv(cmd *exec.Cmd, req *http.Request, app_config Config) {
	// set HTTP_* variables
	for header_name, header_value := range req.Header {
		env_name := strings.ToUpper(strings.Replace(header_name, "-", "_", -1))
		cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_%s=%s", env_name, header_value[0]))
	}

	remote_addr := strings.Split(req.RemoteAddr, ":")
	CGI_vars := [...]struct {
		cgi_name, value string
	}{
		{"PATH_INFO", req.URL.Path},
		{"QUERY_STRING", req.URL.RawQuery},
		{"REMOTE_ADDR", remote_addr[0]},
		{"REMOTE_PORT", remote_addr[1]},
		{"REQUEST_METHOD", req.Method},
		{"REQUEST_URI", req.RequestURI},
		{"SCRIPT_NAME", req.URL.Path},
		{"SERVER_NAME", app_config.host},
		{"SERVER_PORT", fmt.Sprintf("%d", app_config.port)},
		{"SERVER_PROTOCOL", req.Proto},
		{"SERVER_SOFTWARE", "shell2http"},
	}

	for _, row := range CGI_vars {
		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", row.cgi_name, row.value))
	}

	// get POST data to stdin of script (if not parse form vars above)
	if req.Method == "POST" && !app_config.setForm {

		stdin, err := cmd.StdinPipe()
		if err != nil {
			log.Println("get STDIN error: ", err)
			return
		}

		post_body, err := ioutil.ReadAll(req.Body)
		fmt.Println("post_body:", string(post_body))
		if err != nil {
			log.Println("read POST data error: ", err)
			return
		}

		io.WriteString(stdin, string(post_body))
		stdin.Close()
	}
}

// ------------------------------------------------------------------
// parse form into environment vars
func getForm(cmd *exec.Cmd, req *http.Request) {
	err := req.ParseForm()
	if err != nil {
		log.Println(err)
		return
	}

	for key, value := range req.Form {
		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "v_"+key, strings.Join(value, ",")))
	}
}

// ------------------------------------------------------------------
// proxy some system vars
func proxySystemEnv(cmd *exec.Cmd, app_config Config) {
	vars_names := []string{"PATH", "HOME", "LANG", "USER", "TMPDIR"}

	if app_config.exportVars != "" {
		vars_names = append(vars_names, strings.Split(app_config.exportVars, ",")...)
	}

	for _, env_raw := range os.Environ() {
		env := strings.SplitN(env_raw, "=", 2)
		if app_config.exportAllVars {
			cmd.Env = append(cmd.Env, env_raw)
		} else {
			for _, env_var_name := range vars_names {
				if env[0] == env_var_name {
					cmd.Env = append(cmd.Env, env_raw)
				}
			}
		}
	}
}

// ------------------------------------------------------------------
func main() {
	cmd_handlers, app_config, err := getConfig()
	if err != nil {
		log.Fatal(err)
	}
	setupHandlers(cmd_handlers, app_config)

	adress := fmt.Sprintf("%s:%d", app_config.host, app_config.port)
	log.Printf("listen http://%s/\n", adress)
	err = http.ListenAndServe(adress, nil)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

type fish int

var FISH fish

func (f fish) Hook() string {
	return `
function direnv-export --on-event fish_prompt;
	eval (direnv export fish)
end
`
}

func (f fish) Escape(str string) string {
	if str == "" {
		return "''"
	}
	in := []byte(str)
	out := ""
	i := 0
	l := len(in)

	hex := func(char byte) {
		out += fmt.Sprintf("\\x%02x", char)
	}

	backslash := func(char byte) {
		out += string([]byte{BACKSLASH, char})
	}

	escaped := func(str string) {
		out += str
	}

	quoted := func(char byte) {
		out += string([]byte{char})
	}

	literal := func(char byte) {
		out += string([]byte{char})
	}

	for i < l {
		char := in[i]
		switch {
		case char == TAB:
			escaped(`\t`)
		case char == LF:
			escaped(`\n`)
		case char == CR:
			escaped(`\r`)
		case char <= US:
			hex(char)
		case char <= AMPERSTAND:
			quoted(char)
		case char == SINGLE_QUOTE:
			backslash(char)
		case char <= PLUS:
			quoted(char)
		case char <= NINE:
			literal(char)
		case char <= QUESTION:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char == OPEN_BRACKET:
			quoted(char)
		case char == BACKSLASH:
			backslash(char)
		case char <= CLOSE_BRACKET:
			quoted(char)
		case char == UNDERSCORE:
			literal(char)
		case char <= BACKTICK:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char <= TILDA:
			quoted(char)
		case char == DEL:
			hex(char)
		default:
			hex(char)
		}
		i += 1
	}

	return out
}

func (f fish) Export(key, value string) string {
	return "set -x -g " + f.Escape(key) + " " + f.Escape(value) + ";"
}

func (f fish) Unset(key string) string {
	return "set -e -g " + f.Escape(key) + ";"
}
<commit_msg>Fixes `direnv hook fish`<commit_after>package main

import (
	"fmt"
)

type fish int

var FISH fish

func (f fish) Hook() string {
	return `
function __direnv_export_eval --on-event fish_prompt;
	eval (direnv export fish);
end
`
}

func (f fish) Escape(str string) string {
	if str == "" {
		return "''"
	}
	in := []byte(str)
	out := ""
	i := 0
	l := len(in)

	hex := func(char byte) {
		out += fmt.Sprintf("\\x%02x", char)
	}

	backslash := func(char byte) {
		out += string([]byte{BACKSLASH, char})
	}

	escaped := func(str string) {
		out += str
	}

	quoted := func(char byte) {
		out += string([]byte{char})
	}

	literal := func(char byte) {
		out += string([]byte{char})
	}

	for i < l {
		char := in[i]
		switch {
		case char == TAB:
			escaped(`\t`)
		case char == LF:
			escaped(`\n`)
		case char == CR:
			escaped(`\r`)
		case char <= US:
			hex(char)
		case char <= AMPERSTAND:
			quoted(char)
		case char == SINGLE_QUOTE:
			backslash(char)
		case char <= PLUS:
			quoted(char)
		case char <= NINE:
			literal(char)
		case char <= QUESTION:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char == OPEN_BRACKET:
			quoted(char)
		case char == BACKSLASH:
			backslash(char)
		case char <= CLOSE_BRACKET:
			quoted(char)
		case char == UNDERSCORE:
			literal(char)
		case char <= BACKTICK:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char <= TILDA:
			quoted(char)
		case char == DEL:
			hex(char)
		default:
			hex(char)
		}
		i += 1
	}

	return out
}

func (f fish) Export(key, value string) string {
	return "set -x -g " + f.Escape(key) + " " + f.Escape(value) + ";"
}

func (f fish) Unset(key string) string {
	return "set -e -g " + f.Escape(key) + ";"
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"log"
	"net/http"
)

type Post struct {
	Id    int
	Title string
	Body  string
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/posts", postsHandler).Methods("GET")
	r.HandleFunc("/", postsHandler).Methods("GET")

	http.Handle("/", r)

	log.Println("Server started. Listening...")
	http.ListenAndServe(":3000", nil)
}

func postsHandler(w http.ResponseWriter, r *http.Request) {
	post := Post{Id: 1, Title: "This is a test post", Body: "This is the body."}

	out, err := json.Marshal(post)
	if err != nil {
		panic(err)
	}

	log.Println("Post: " + string(out))

	w.Write([]byte(out))
}
<commit_msg>Changed log.<commit_after>package main

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"log"
	"net/http"
)

type Post struct {
	Id    int
	Title string
	Body  string
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/posts", postsHandler).Methods("GET")
	r.HandleFunc("/", postsHandler).Methods("GET")

	http.Handle("/", r)

	log.Println("Server started. Listening...")
	http.ListenAndServe(":3000", nil)
}

func postsHandler(w http.ResponseWriter, r *http.Request) {
	post := Post{Id: 1, Title: "This is a test post", Body: "This is the body."}

	out, err := json.Marshal(post)
	if err != nil {
		panic(err)
	}

	log.Printf("Post: %v", string(out))

	w.Write([]byte(out))
}
<|endoftext|>