<commit_before>package conn

import (
	"fmt"
	"math/rand"
	"strings"

	addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
	transport "gx/ipfs/QmRHqYZs3Diy8YC3bW16zvs8VDDwS2ARKBuKwALxEMqibc/go-libp2p-transport"
	manet "gx/ipfs/QmTrxSBY8Wqd5aBB4MeizeSzS5xFbK8dQBrYaMsiGnCBhb/go-multiaddr-net"
	ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto"
	msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
	lgbl "gx/ipfs/QmYqiDbGUGqatbPFie11Py8cnyduoJYqcgKtjfhu1SQLh1/go-libp2p-loggables"
	peer "gx/ipfs/QmZwZjMVGss5rqYsJVGy18gNbkTJffFyq2x1uJ4e4p3ZAt/go-libp2p-peer"
	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
	ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
)

type WrapFunc func(transport.Conn) transport.Conn

func NewDialer(p peer.ID, pk ci.PrivKey, wrap WrapFunc) *Dialer {
	return &Dialer{
		LocalPeer:  p,
		PrivateKey: pk,
		Wrapper:    wrap,
		fallback:   new(transport.FallbackDialer),
	}
}

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s ...>", d.LocalPeer)
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {
	logdial := lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr)
	logdial["encrypted"] = (d.PrivateKey != nil) // log wether this will be an encrypted dial or not.
	defer log.EventBegin(ctx, "connDial", logdial).Done()

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() {
			select {
			case done <- struct{}{}:
			case <-ctx.Done():
			}
		}()

		maconn, err := d.rawConnDial(ctx, raddr, remote)
		if err != nil {
			errOut = err
			return
		}

		if d.Wrapper != nil {
			maconn = d.Wrapper(maconn)
		}

		cryptoProtoChoice := SecioTag
		if !EncryptConnections {
			cryptoProtoChoice = NoEncryptionTag
		}

		err = msmux.SelectProtoOrFail(cryptoProtoChoice, maconn)
		if err != nil {
			errOut = err
			return
		}

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			maconn.Close()
			errOut = err
			return
		}

		if d.PrivateKey == nil || EncryptConnections == false {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}

		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		logdial["error"] = ctx.Err()
		logdial["dial"] = "failure"
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	if errOut != nil {
		logdial["error"] = errOut
		logdial["dial"] = "failure"
		return nil, errOut
	}

	logdial["dial"] = "success"
	return connOut, nil
}

func (d *Dialer) AddDialer(pd transport.Dialer) {
	d.Dialers = append(d.Dialers, pd)
}

// returns dialer that can dial the given address
func (d *Dialer) subDialerForAddr(raddr ma.Multiaddr) transport.Dialer {
	for _, pd := range d.Dialers {
		if pd.Matches(raddr) {
			return pd
		}
	}

	if d.fallback.Matches(raddr) {
		return d.fallback
	}

	return nil
}

// rawConnDial dials the underlying net.Conn + manet.Conns
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (transport.Conn, error) {
	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		log.Event(ctx, "connDialZeroAddr", lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr))
		return nil, fmt.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	sd := d.subDialerForAddr(raddr)
	if sd == nil {
		return nil, fmt.Errorf("no dialer for %s", raddr)
	}

	return sd.Dial(raddr)
}

func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that match the remote addr.
	laddrs = manet.AddrMatch(raddr, laddrs)
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that CAN dial the remote addr.
	// filter out all the local addrs that aren't capable
	raddrIPLayer := ma.Split(raddr)[0]
	raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
	raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
	laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
		laddrIPLayer := ma.Split(a)[0]
		laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
		laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
		if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
			return raddrIsLoopback
		}
		if laddrIsLinkLocal {
			return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
		}
		return true
	})

	// TODO pick with a good heuristic
	// we use a random one for now to prevent bad addresses from making nodes unreachable
	// with a random selection, multiple tries may work.
	return laddrs[rand.Intn(len(laddrs))]
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
		if api.Code != bp[i].Code {
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}
<commit_msg>add a read deadline for the multistream select on dial<commit_after>package conn

import (
	"fmt"
	"math/rand"
	"strings"
	"time"

	addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
	transport "gx/ipfs/QmRHqYZs3Diy8YC3bW16zvs8VDDwS2ARKBuKwALxEMqibc/go-libp2p-transport"
	manet "gx/ipfs/QmTrxSBY8Wqd5aBB4MeizeSzS5xFbK8dQBrYaMsiGnCBhb/go-multiaddr-net"
	ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto"
	msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
	lgbl "gx/ipfs/QmYqiDbGUGqatbPFie11Py8cnyduoJYqcgKtjfhu1SQLh1/go-libp2p-loggables"
	peer "gx/ipfs/QmZwZjMVGss5rqYsJVGy18gNbkTJffFyq2x1uJ4e4p3ZAt/go-libp2p-peer"
	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
	ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
)

type WrapFunc func(transport.Conn) transport.Conn

func NewDialer(p peer.ID, pk ci.PrivKey, wrap WrapFunc) *Dialer {
	return &Dialer{
		LocalPeer:  p,
		PrivateKey: pk,
		Wrapper:    wrap,
		fallback:   new(transport.FallbackDialer),
	}
}

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s ...>", d.LocalPeer)
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {
	logdial := lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr)
	logdial["encrypted"] = (d.PrivateKey != nil) // log wether this will be an encrypted dial or not.
	defer log.EventBegin(ctx, "connDial", logdial).Done()

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() {
			select {
			case done <- struct{}{}:
			case <-ctx.Done():
			}
		}()

		maconn, err := d.rawConnDial(ctx, raddr, remote)
		if err != nil {
			errOut = err
			return
		}

		if d.Wrapper != nil {
			maconn = d.Wrapper(maconn)
		}

		cryptoProtoChoice := SecioTag
		if !EncryptConnections {
			cryptoProtoChoice = NoEncryptionTag
		}

		maconn.SetReadDeadline(time.Now().Add(NegotiateReadTimeout))

		err = msmux.SelectProtoOrFail(cryptoProtoChoice, maconn)
		if err != nil {
			errOut = err
			return
		}

		maconn.SetReadDeadline(time.Time{})

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			maconn.Close()
			errOut = err
			return
		}

		if d.PrivateKey == nil || EncryptConnections == false {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}

		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		logdial["error"] = ctx.Err()
		logdial["dial"] = "failure"
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	if errOut != nil {
		logdial["error"] = errOut
		logdial["dial"] = "failure"
		return nil, errOut
	}

	logdial["dial"] = "success"
	return connOut, nil
}

func (d *Dialer) AddDialer(pd transport.Dialer) {
	d.Dialers = append(d.Dialers, pd)
}

// returns dialer that can dial the given address
func (d *Dialer) subDialerForAddr(raddr ma.Multiaddr) transport.Dialer {
	for _, pd := range d.Dialers {
		if pd.Matches(raddr) {
			return pd
		}
	}

	if d.fallback.Matches(raddr) {
		return d.fallback
	}

	return nil
}

// rawConnDial dials the underlying net.Conn + manet.Conns
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (transport.Conn, error) {
	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		log.Event(ctx, "connDialZeroAddr", lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr))
		return nil, fmt.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	sd := d.subDialerForAddr(raddr)
	if sd == nil {
		return nil, fmt.Errorf("no dialer for %s", raddr)
	}

	return sd.Dial(raddr)
}

func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that match the remote addr.
	laddrs = manet.AddrMatch(raddr, laddrs)
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that CAN dial the remote addr.
	// filter out all the local addrs that aren't capable
	raddrIPLayer := ma.Split(raddr)[0]
	raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
	raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
	laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
		laddrIPLayer := ma.Split(a)[0]
		laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
		laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
		if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
			return raddrIsLoopback
		}
		if laddrIsLinkLocal {
			return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
		}
		return true
	})

	// TODO pick with a good heuristic
	// we use a random one for now to prevent bad addresses from making nodes unreachable
	// with a random selection, multiple tries may work.
	return laddrs[rand.Intn(len(laddrs))]
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
		if api.Code != bp[i].Code {
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package cas // import "github.com/chronos-tachyon/go-cas"

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

const diskSpecDefaultLimit = 1048576 // 1TiB

// NewLocalDiskFunc is an internal type for use by
// "github.com/chronos-tachyon/go-cas/localdisk".
type NewLocalDiskFunc func(string, int64, Mode) (CAS, error)

// NewLocalDisk is an internal global variable for use by
// "github.com/chronos-tachyon/go-cas/localdisk".
var NewLocalDisk NewLocalDiskFunc = func(_ string, _ int64, _ Mode) (CAS, error) {
	panic(errors.New(`Please add this import line:
	import _ "github.com/chronos-tachyon/go-cas/localdisk"`))
}

type diskSpec struct {
	Dir   string
	Limit int64
}

// LocalDisk returns a Spec for a CAS on local disk.
//
// While you can always create this Spec, you cannot Open() by default.
// To support local disks, add the following import for its side effects:
//	import _ "github.com/chronos-tachyon/go-cas/localdisk"
func LocalDisk(dir string, limit int64) Spec {
	return diskSpec{dir, limit}
}

var diskSpecRE = regexp.MustCompile(`^disk:([^,:\[\]]*),([^,\[\]]*)$`)

func parseDiskSpec(input string) (Spec, error) {
	if !strings.HasPrefix(input, "disk:") {
		return nil, errNoMatch
	}
	match := diskSpecRE.FindStringSubmatch(input)
	if match == nil {
		return nil, SpecParseError{
			Input:   input,
			Problem: fmt.Errorf("does not match %s", diskSpecRE),
		}
	}
	limit, err := strconv.ParseInt(match[1], 0, 64)
	if err != nil {
		if match[1] != "" && match[1] != "auto" {
			return nil, SpecParseError{Input: input, Problem: err}
		}
		limit = diskSpecDefaultLimit
	}
	dir := match[2]
	return LocalDisk(dir, limit), nil
}

func (spec diskSpec) Open(mode Mode) (CAS, error) {
	return NewLocalDisk(spec.Dir, spec.Limit, mode)
}

func (spec diskSpec) String() string {
	return fmt.Sprintf("disk:%d,%s", spec.Limit, spec.Dir)
}
<commit_msg>Don't Panic if no disk support, just return an error.<commit_after>package cas // import "github.com/chronos-tachyon/go-cas"

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

const diskSpecDefaultLimit = 1048576 // 1TiB

// NewLocalDiskFunc is an internal type for use by
// "github.com/chronos-tachyon/go-cas/localdisk".
type NewLocalDiskFunc func(string, int64, Mode) (CAS, error)

// NewLocalDisk is an internal global variable for use by
// "github.com/chronos-tachyon/go-cas/localdisk".
var NewLocalDisk NewLocalDiskFunc = func(_ string, _ int64, _ Mode) (CAS, error) {
	return nil, errors.New(`Please add this import line:
	import _ "github.com/chronos-tachyon/go-cas/localdisk"`)
}

type diskSpec struct {
	Dir   string
	Limit int64
}

// LocalDisk returns a Spec for a CAS on local disk.
//
// While you can always create this Spec, you cannot Open() by default.
// To support local disks, add the following import for its side effects:
//	import _ "github.com/chronos-tachyon/go-cas/localdisk"
func LocalDisk(dir string, limit int64) Spec {
	return diskSpec{dir, limit}
}

var diskSpecRE = regexp.MustCompile(`^disk:([^,:\[\]]*),([^,\[\]]*)$`)

func parseDiskSpec(input string) (Spec, error) {
	if !strings.HasPrefix(input, "disk:") {
		return nil, errNoMatch
	}
	match := diskSpecRE.FindStringSubmatch(input)
	if match == nil {
		return nil, SpecParseError{
			Input:   input,
			Problem: fmt.Errorf("does not match %s", diskSpecRE),
		}
	}
	limit, err := strconv.ParseInt(match[1], 0, 64)
	if err != nil {
		if match[1] != "" && match[1] != "auto" {
			return nil, SpecParseError{Input: input, Problem: err}
		}
		limit = diskSpecDefaultLimit
	}
	dir := match[2]
	return LocalDisk(dir, limit), nil
}

func (spec diskSpec) Open(mode Mode) (CAS, error) {
	return NewLocalDisk(spec.Dir, spec.Limit, mode)
}

func (spec diskSpec) String() string {
	return fmt.Sprintf("disk:%d,%s", spec.Limit, spec.Dir)
}
<|endoftext|>


<commit_before>// +build !windows

package opendkim

/*
#cgo LDFLAGS: -L/opt/local/lib -L/usr/lib -lopendkim
#cgo CFLAGS: -g -O2 -I/opt/local/include/opendkim/ -I/usr/include/opendkim/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dkim.h>
*/
import "C"

import (
	"bytes"
	"fmt"
	"unsafe"
)

type (
	Canon  int
	Sign   int
	Status int
	Op     int
	Option int
)

const (
	CanonUNKNOWN Canon = (-1) // unknown method
	CanonSIMPLE  Canon = 0    // as specified in DKIM spec
	CanonRELAXED Canon = 1    // as specified in DKIM spec
)

const (
	SignUNKNOWN   Sign = -2 // unknown method
	SignDEFAULT   Sign = -1 // use internal default
	SignRSASHA1   Sign = 0  // an RSA-signed SHA1 digest
	SignRSASHA256 Sign = 1  // an RSA-signed SHA256 digest
)

const (
	StatusOK            Status = 0  // function completed successfully
	StatusBADSIG        Status = 1  // signature available but failed
	StatusNOSIG         Status = 2  // no signature available
	StatusNOKEY         Status = 3  // public key not found
	StatusCANTVRFY      Status = 4  // can't get domain key to verify
	StatusSYNTAX        Status = 5  // message is not valid syntax
	StatusNORESOURCE    Status = 6  // resource unavailable
	StatusINTERNAL      Status = 7  // internal error
	StatusREVOKED       Status = 8  // key found, but revoked
	StatusINVALID       Status = 9  // invalid function parameter
	StatusNOTIMPLEMENT  Status = 10 // function not implemented
	StatusKEYFAIL       Status = 11 // key retrieval failed
	StatusCBREJECT      Status = 12 // callback requested reject
	StatusCBINVALID     Status = 13 // callback gave invalid result
	StatusCBTRYAGAIN    Status = 14 // callback says try again later
	StatusCBERROR       Status = 15 // callback error
	StatusMULTIDNSREPLY Status = 16 // multiple DNS replies
	StatusSIGGEN        Status = 17 // signature generation failed
)

const (
	OptionFLAGS        Option = 0
	OptionTMPDIR       Option = 1
	OptionTIMEOUT      Option = 2
	OptionSENDERHDRS   Option = 3
	OptionSIGNHDRS     Option = 4
	OptionOVERSIGNHDRS Option = 5
	OptionQUERYMETHOD  Option = 6
	OptionQUERYINFO    Option = 7
	OptionFIXEDTIME    Option = 8
	OptionSKIPHDRS     Option = 9
	OptionALWAYSHDRS   Option = 10 // obsolete
	OptionSIGNATURETTL Option = 11
	OptionCLOCKDRIFT   Option = 12
	OptionMUSTBESIGNED Option = 13
	OptionMINKEYBITS   Option = 14
	OptionREQUIREDHDRS Option = 15
)

const (
	LibflagsNONE          Option = 0x0000
	LibflagsTMPFILES      Option = 0x0001
	LibflagsKEEPFILES     Option = 0x0002
	LibflagsSIGNLEN       Option = 0x0004
	LibflagsCACHE         Option = 0x0008
	LibflagsZTAGS         Option = 0x0010
	LibflagsDELAYSIGPROC  Option = 0x0020
	LibflagsEOHCHECK      Option = 0x0040
	LibflagsACCEPTV05     Option = 0x0080
	LibflagsFIXCRLF       Option = 0x0100
	LibflagsACCEPTDK      Option = 0x0200
	LibflagsBADSIGHANDLES Option = 0x0400
	LibflagsVERIFYONE     Option = 0x0800
	LibflagsSTRICTHDRS    Option = 0x1000
	LibflagsREPORTBADADSP Option = 0x2000
	LibflagsDROPSIGNER    Option = 0x4000
	LibflagsSTRICTRESIGN  Option = 0x8000
)

const (
	GetOpt Op = 0
	SetOpt Op = 1
)

var lib *C.struct_DKIM_LIB

func init() {
	lib = C.dkim_init(nil, nil)
	if lib == nil {
		panic("could not init libopendkim")
	}
}

func SetOption(opt Option, data []byte) {
	C.dkim_options(lib, C.int(SetOpt), C.dkim_opts_t(opt), unsafe.Pointer(&data[0]), C.size_t(len(data)))
}

type Dkim struct {
	dkim *C.DKIM
	stat C.DKIM_STAT
}

// NewSigner creates a new DKIM handle for message signing.
// If -1 is specified for bytesToSign, the whole message body will be signed.
func NewSigner(secret, selector, domain string, hdrCanon, bodyCanon Canon, algo Sign, bytesToSign int64) *Dkim {
	signer := new(Dkim)
	signer.dkim = C.dkim_sign(
		lib,
		nil,
		nil,
		(*C.uchar)(unsafe.Pointer(C.CString(secret))),
		(*C.uchar)(unsafe.Pointer(C.CString(selector))),
		(*C.uchar)(unsafe.Pointer(C.CString(domain))),
		C.dkim_canon_t(hdrCanon),
		C.dkim_canon_t(bodyCanon),
		C.dkim_alg_t(algo),
		C.ssize_t(bytesToSign),
		&signer.stat,
	)
	if signer.dkim == nil {
		panic("could not create DKIM handle")
	}
	return signer
}

// Header processes a single header line.
// May be invoked multiple times.
func (d *Dkim) Header(line string) error {
	data := []byte(line)
	var stat C.DKIM_STAT
	stat = C.dkim_header(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing header (%s)", getErr(stat))
	}
	return nil
}

// Eoh is called to signal end of header.
func (d *Dkim) Eoh() error {
	var stat C.DKIM_STAT
	stat = C.dkim_eoh(d.dkim)
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing header (%s)", getErr(stat))
	}
	return nil
}

// Body processes the message body.
func (d *Dkim) Body(data []byte) error {
	var stat C.DKIM_STAT
	stat = C.dkim_body(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing body (%s)", getErr(stat))
	}
	return nil
}

// Eom is called to signal end of message.
func (d *Dkim) Eom(testKey *bool) error {
	var stat C.DKIM_STAT
	stat = C.dkim_eom(d.dkim, (*C._Bool)(testKey))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing message (%s)", getErr(stat))
	}
	return nil
}

// Chunk processes a chunk of message data.
// Can include header and body data.
//
// TODO: disabled until I figure out what's fould here
//
// func (d *Dkim) Chunk(data []byte) error {
// 	var stat C.DKIM_STAT
// 	stat = C.dkim_chunk(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 	if Status(stat) != StatusOK {
// 		return fmt.Errorf("error processing chunk (%s)", getErr(stat))
// 	}
// 	return nil
// }

// GetSigHdr computes the signature header for a message.
func (d *Dkim) GetSigHdr() (string, error) {
	var stat C.DKIM_STAT
	var buf = make([]byte, 1024)
	stat = C.dkim_getsighdr(d.dkim, (*C.u_char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), C.size_t(0))
	if Status(stat) != StatusOK {
		return "", fmt.Errorf("error computing signature header (%s)", (&dkimError{stat}).Error())
	}
	i := bytes.Index(buf, []byte{0x0})
	if i >= 0 {
		return string(buf[:i]), nil
	}
	return string(buf), nil
}

func (d *Dkim) GetError() string {
	return C.GoString(C.dkim_geterror(d.dkim))
}

func getErr(s C.DKIM_STAT) string {
	return (&dkimError{s}).Error()
}

type dkimError struct {
	stat C.DKIM_STAT
}

func (err *dkimError) Error() string {
	return fmt.Sprintf("%d: %s", err.stat, C.GoString(C.dkim_getresultstr(err.stat)))
}
<commit_msg>Free dkim handle<commit_after>// +build !windows

package opendkim

/*
#cgo LDFLAGS: -L/opt/local/lib -L/usr/lib -lopendkim
#cgo CFLAGS: -g -O2 -I/opt/local/include/opendkim/ -I/usr/include/opendkim/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dkim.h>
*/
import "C"

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"unsafe"
)

type (
	Canon  int
	Sign   int
	Status int
	Op     int
	Option int
)

const (
	CanonUNKNOWN Canon = (-1) // unknown method
	CanonSIMPLE  Canon = 0    // as specified in DKIM spec
	CanonRELAXED Canon = 1    // as specified in DKIM spec
)

const (
	SignUNKNOWN   Sign = -2 // unknown method
	SignDEFAULT   Sign = -1 // use internal default
	SignRSASHA1   Sign = 0  // an RSA-signed SHA1 digest
	SignRSASHA256 Sign = 1  // an RSA-signed SHA256 digest
)

const (
	StatusOK            Status = 0  // function completed successfully
	StatusBADSIG        Status = 1  // signature available but failed
	StatusNOSIG         Status = 2  // no signature available
	StatusNOKEY         Status = 3  // public key not found
	StatusCANTVRFY      Status = 4  // can't get domain key to verify
	StatusSYNTAX        Status = 5  // message is not valid syntax
	StatusNORESOURCE    Status = 6  // resource unavailable
	StatusINTERNAL      Status = 7  // internal error
	StatusREVOKED       Status = 8  // key found, but revoked
	StatusINVALID       Status = 9  // invalid function parameter
	StatusNOTIMPLEMENT  Status = 10 // function not implemented
	StatusKEYFAIL       Status = 11 // key retrieval failed
	StatusCBREJECT      Status = 12 // callback requested reject
	StatusCBINVALID     Status = 13 // callback gave invalid result
	StatusCBTRYAGAIN    Status = 14 // callback says try again later
	StatusCBERROR       Status = 15 // callback error
	StatusMULTIDNSREPLY Status = 16 // multiple DNS replies
	StatusSIGGEN        Status = 17 // signature generation failed
)

const (
	OptionFLAGS        Option = 0
	OptionTMPDIR       Option = 1
	OptionTIMEOUT      Option = 2
	OptionSENDERHDRS   Option = 3
	OptionSIGNHDRS     Option = 4
	OptionOVERSIGNHDRS Option = 5
	OptionQUERYMETHOD  Option = 6
	OptionQUERYINFO    Option = 7
	OptionFIXEDTIME    Option = 8
	OptionSKIPHDRS     Option = 9
	OptionALWAYSHDRS   Option = 10 // obsolete
	OptionSIGNATURETTL Option = 11
	OptionCLOCKDRIFT   Option = 12
	OptionMUSTBESIGNED Option = 13
	OptionMINKEYBITS   Option = 14
	OptionREQUIREDHDRS Option = 15
)

const (
	LibflagsNONE          Option = 0x0000
	LibflagsTMPFILES      Option = 0x0001
	LibflagsKEEPFILES     Option = 0x0002
	LibflagsSIGNLEN       Option = 0x0004
	LibflagsCACHE         Option = 0x0008
	LibflagsZTAGS         Option = 0x0010
	LibflagsDELAYSIGPROC  Option = 0x0020
	LibflagsEOHCHECK      Option = 0x0040
	LibflagsACCEPTV05     Option = 0x0080
	LibflagsFIXCRLF       Option = 0x0100
	LibflagsACCEPTDK      Option = 0x0200
	LibflagsBADSIGHANDLES Option = 0x0400
	LibflagsVERIFYONE     Option = 0x0800
	LibflagsSTRICTHDRS    Option = 0x1000
	LibflagsREPORTBADADSP Option = 0x2000
	LibflagsDROPSIGNER    Option = 0x4000
	LibflagsSTRICTRESIGN  Option = 0x8000
)

const (
	GetOpt Op = 0
	SetOpt Op = 1
)

var lib *C.struct_DKIM_LIB

func init() {
	lib = C.dkim_init(nil, nil)
	if lib == nil {
		panic("could not init libopendkim")
	}
}

func SetOption(opt Option, data []byte) {
	C.dkim_options(lib, C.int(SetOpt), C.dkim_opts_t(opt), unsafe.Pointer(&data[0]), C.size_t(len(data)))
}

type Dkim struct {
	dkim *C.DKIM
	stat C.DKIM_STAT
	mtx  sync.Mutex
}

// NewSigner creates a new DKIM handle for message signing.
// If -1 is specified for bytesToSign, the whole message body will be signed.
func NewSigner(secret, selector, domain string, hdrCanon, bodyCanon Canon, algo Sign, bytesToSign int64) *Dkim {
	signer := new(Dkim)
	signer.dkim = C.dkim_sign(
		lib,
		nil,
		nil,
		(*C.uchar)(unsafe.Pointer(C.CString(secret))),
		(*C.uchar)(unsafe.Pointer(C.CString(selector))),
		(*C.uchar)(unsafe.Pointer(C.CString(domain))),
		C.dkim_canon_t(hdrCanon),
		C.dkim_canon_t(bodyCanon),
		C.dkim_alg_t(algo),
		C.ssize_t(bytesToSign),
		&signer.stat,
	)
	if signer.dkim == nil {
		panic("could not create DKIM handle")
	}
	runtime.SetFinalizer(signer, func(s *Dkim) {
		s.Destroy()
	})
	return signer
}

// Header processes a single header line.
// May be invoked multiple times.
func (d *Dkim) Header(line string) error {
	data := []byte(line)
	var stat C.DKIM_STAT
	stat = C.dkim_header(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing header (%s)", getErr(stat))
	}
	return nil
}

// Eoh is called to signal end of header.
func (d *Dkim) Eoh() error {
	var stat C.DKIM_STAT
	stat = C.dkim_eoh(d.dkim)
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing header (%s)", getErr(stat))
	}
	return nil
}

// Body processes the message body.
func (d *Dkim) Body(data []byte) error {
	var stat C.DKIM_STAT
	stat = C.dkim_body(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing body (%s)", getErr(stat))
	}
	return nil
}

// Eom is called to signal end of message.
func (d *Dkim) Eom(testKey *bool) error {
	var stat C.DKIM_STAT
	stat = C.dkim_eom(d.dkim, (*C._Bool)(testKey))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing message (%s)", getErr(stat))
	}
	return nil
}

// Chunk processes a chunk of message data.
// Can include header and body data.
//
// TODO: disabled until I figure out what's fould here
//
// func (d *Dkim) Chunk(data []byte) error {
// 	var stat C.DKIM_STAT
// 	stat = C.dkim_chunk(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 	if Status(stat) != StatusOK {
// 		return fmt.Errorf("error processing chunk (%s)", getErr(stat))
// 	}
// 	return nil
// }

// GetSigHdr computes the signature header for a message.
func (d *Dkim) GetSigHdr() (string, error) {
	var stat C.DKIM_STAT
	var buf = make([]byte, 1024)
	stat = C.dkim_getsighdr(d.dkim, (*C.u_char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), C.size_t(0))
	if Status(stat) != StatusOK {
		return "", fmt.Errorf("error computing signature header (%s)", getErr(stat))
	}
	i := bytes.Index(buf, []byte{0x0})
	if i >= 0 {
		return string(buf[:i]), nil
	}
	return string(buf), nil
}

// GetError gets the last error for the dkim handle
func (d *Dkim) GetError() string {
	return C.GoString(C.dkim_geterror(d.dkim))
}

// Destroy destroys the dkim handle
func (d *Dkim) Destroy() error {
	d.mtx.Lock()
	defer d.mtx.Unlock()
	if d.dkim != nil {
		var stat C.DKIM_STAT
		stat = C.dkim_free(d.dkim)
		if Status(stat) != StatusOK {
			return fmt.Errorf("could not destroy DKIM handle (%s)", getErr(stat))
		}
		d.dkim = nil
	}
	return nil
}

func getErr(s C.DKIM_STAT) string {
	return (&dkimError{s}).Error()
}

type dkimError struct {
	stat C.DKIM_STAT
}

func (err *dkimError) Error() string {
	return fmt.Sprintf("%d: %s", err.stat, C.GoString(C.dkim_getresultstr(err.stat)))
}
<|endoftext|>


<commit_before>// tgotop project main.go

package main

import (
	"fmt"
	ui "github.com/gizak/termui"
	tm "github.com/nsf/termbox-go"
	"os"
	"os/signal"
	"syscall"
	"time"
)

//DIV is size of divider, in this case - MiB
const DIV uint64 = 1024 * 1024

//DIVname is a name of unit that we ends up after dividing bytes by DIV
const DIVname = "MiB"

func main() {
	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer ui.Close()

	qMess := ui.NewPar(":PRESS q TO QUIT")
	qMess.Height = 3

	gSwap := ui.NewGauge()
	gSwap.Height = 3

	gMem := ui.NewGauge()
	gMem.Height = 3

	//getting ready to close stuff on command
	evt := make(chan tm.Event)
	go func() {
		for {
			evt <- tm.PollEvent()
		}
	}()
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGABRT, syscall.SIGTERM)

	draw := func() {
		var m memData
		err := m.Update()
		if err != nil {
			panic(err)
		}

		gMem.Percent = m.memPercent
		gMem.Border.Label = fillfmt("Memory", m.memUse, m.memTotal)

		gSwap.Percent = m.swapPercent
		gSwap.Border.Label = fillfmt("Swap", m.swapUse, m.swapTotal)
		ui.Render(ui.Body)
	}

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(6, 0, gMem, gSwap)),
		ui.NewRow(ui.NewCol(12, 0, qMess)))

	ui.Body.Align()

	for {
		select {
		case e := <-evt:
			go dealwithevents(e)
		case <-sig:
			return
		default:
			go draw()
			time.Sleep(time.Second / 2)
		}
	}
}

func fillfmt(s string, u uint64, t uint64) string {
	return fmt.Sprintf("%v used: %d / %d %v", s, u/DIV, t/DIV, DIVname)
}

func dealwithevents(e tm.Event) {
	if e.Type == tm.EventKey && e.Ch == 'q' {
		enditgood()
	}
	if e.Type == tm.EventKey && e.Key == tm.KeyCtrlC {
		enditgood()
	}
	if e.Type == tm.EventResize {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
	}
}

func enditgood() {
	ui.Close()
	os.Exit(0)
}
<commit_msg>Decoupled UI from updates of info.<commit_after>// tgotop project main.go

package main

import (
	"fmt"
	ui "github.com/gizak/termui"
	tm "github.com/nsf/termbox-go"
	"os"
	"os/signal"
	"syscall"
	"time"
)

//DIV is size of divider, in this case - MiB
const DIV uint64 = 1024 * 1024

//DIVname is a name of unit that we ends up after dividing bytes by DIV
const DIVname = "MiB"

func main() {
	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer ui.Close()

	qMess := ui.NewPar(":PRESS q TO QUIT")
	qMess.Height = 3

	gSwap := ui.NewGauge()
	gSwap.Height = 3

	gMem := ui.NewGauge()
	gMem.Height = 3

	//getting ready to close stuff on command
	evt := make(chan tm.Event)
	go func() {
		for {
			evt <- tm.PollEvent()
		}
	}()
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGABRT, syscall.SIGTERM)

	go func() {
		for {
			var m memData
			err := m.Update()
			if err != nil {
				panic(err)
			}

			gMem.Percent = m.memPercent
			gMem.Border.Label = fillfmt("Memory", m.memUse, m.memTotal)

			gSwap.Percent = m.swapPercent
			gSwap.Border.Label = fillfmt("Swap", m.swapUse, m.swapTotal)
			time.Sleep(time.Second / 2)
		}
	}()

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(6, 0, gMem, gSwap)),
		ui.NewRow(ui.NewCol(12, 0, qMess)))

	ui.Body.Align()

	for {
		select {
		case e := <-evt:
			if dealwithevents(e) {
				return
			}
		case <-sig:
			return
		default:
			ui.Render(ui.Body)
		}
	}
}

func fillfmt(s string, u uint64, t uint64) string {
	return fmt.Sprintf("%v used: %d / %d %v", s, u/DIV, t/DIV, DIVname)
}

func dealwithevents(e tm.Event) bool {
	if e.Type == tm.EventKey && e.Ch == 'q' {
		return true
	}
	if e.Type == tm.EventKey && e.Key == tm.KeyCtrlC {
		return true
	}
	if e.Type == tm.EventResize {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
	}
	return false
}
<|endoftext|>


<commit_before>/* Package ed2k implements an ed2k hasher as explained in http://wiki.anidb.net/w/Ed2k-hash#How_is_an_ed2k_hash_calculated_exactly.3F */
package ed2k

import (
	"code.google.com/p/go.crypto/md4"
	"fmt"
	"hash"
	"strings"
)

// The size of the ed2k checksum in bytes
const Size = md4.Size

// The chunk size in bytes
const BlockSize = 9728000

type digest struct {
	currentChunk     []byte
	endWithNullChunk bool

	reqCurrentHashes chan bool
	currentHashes    chan []byte
	addHash          chan chan []byte
	quitLoop         chan bool
}

func (d *digest) hashLoop() {
	var (
		notify        bool
		hashList      = make([]byte, 0)
		runningHashes = make([]chan []byte, 0)
	)
	for {
		var nextHash <-chan []byte
		if len(runningHashes) > 0 {
			nextHash = runningHashes[0]
		} else if notify {
			notify = false
			list := make([]byte, len(hashList))
			copy(list, hashList)
			d.currentHashes <- list
		}

		select {
		case c := <-d.addHash:
			runningHashes = append(runningHashes, c)
		case hash := <-nextHash:
			hashList = append(hashList, hash...)
			runningHashes = runningHashes[1:]
		case <-d.reqCurrentHashes:
			notify = true
		case <-d.quitLoop:
			// flush the running hashes
			go func() {
				for _, c := range runningHashes {
					<-c
				}
			}()
			if notify {
				d.currentHashes <- []byte{}
			}
			d.quitLoop <- true
			return
		}
	}
}

func (d *digest) Reset() {
	d.currentChunk = make([]byte, 0, BlockSize)

	if d.quitLoop != nil {
		d.quitLoop <- true
		<-d.quitLoop
		close(d.quitLoop)
	}
	d.reqCurrentHashes = make(chan bool)
	d.quitLoop = make(chan bool)
	d.currentHashes = make(chan []byte)
	d.addHash = make(chan chan []byte)

	go d.hashLoop()
}

// New returns a new hash.Hash computing the ed2k checksum.
// The bool argument chooses between the new (false) or old (true) blockchain finishing algorithm.
// In the page given in the package description, false picks the "blue" method, true picks the "red" method.
func New(endWithNullChunk bool) hash.Hash {
	d := &digest{endWithNullChunk: endWithNullChunk}
	d.Reset()
	return d
}

func (d *digest) Size() int      { return Size }
func (d *digest) BlockSize() int { return BlockSize }

func (d *digest) Write(p []byte) (i int, err error) {
	for i = 0; i < len(p); {
		count := copy(d.currentChunk[len(d.currentChunk):cap(d.currentChunk)], p[i:])
		d.currentChunk = d.currentChunk[:len(d.currentChunk)+count]
		i += count
		if len(d.currentChunk) == cap(d.currentChunk) && len(p[i:]) > 0 {
			d.addHash <- md4SumAsync(d.currentChunk)
			// the old currentChunk now belongs to the md4 goroutine, make a new one
			d.currentChunk = make([]byte, 0, BlockSize)
		}
	}
	return
}

func (d *digest) Sum(p []byte) []byte {
	currentChunk := d.currentChunk

	d.reqCurrentHashes <- true
	hashList := <-d.currentHashes

	if d.endWithNullChunk && len(currentChunk) == cap(currentChunk) {
		hashList = md4Sum(currentChunk, hashList)
		currentChunk = currentChunk[:0] // Leave a null chunk for appending
	} else if len(hashList) == 0 {
		// We just hash the data itself, instead of "chunking"
		return md4Sum(currentChunk, nil)
	}
	// We always append a chunk if d.endWithNullChunk, regardless of length
	if d.endWithNullChunk || len(currentChunk) > 0 {
		hashList = md4Sum(currentChunk, hashList)
	}

	return md4Sum(hashList, p)
}

// Returns an hexadecimal representation of the hash
func (d *digest) String() string {
	sum := d.Sum(nil)
	parts := make([]string, 0, 2*Size)
	for _, b := range sum {
		parts = append(parts, fmt.Sprintf("%02x", b))
	}
	return strings.Join(parts, "")
}

func md4Sum(data []byte, list []byte) []byte {
	md4 := md4.New()
	md4.Write(data)
	return md4.Sum(list)
}

func md4SumAsync(data []byte) chan []byte {
	c := make(chan []byte)
	go func() {
		c <- md4Sum(data, nil)
	}()
	return c
}
<commit_msg>Don't reinvent encoding/hex<commit_after>/* Package ed2k implements an ed2k hasher as explained in http://wiki.anidb.net/w/Ed2k-hash#How_is_an_ed2k_hash_calculated_exactly.3F */
package ed2k

import (
	"code.google.com/p/go.crypto/md4"
	"encoding/hex"
	"hash"
)

// The size of the ed2k checksum in bytes
const Size = md4.Size

// The chunk size in bytes
const BlockSize = 9728000

type digest struct {
	currentChunk     []byte
	endWithNullChunk bool

	reqCurrentHashes chan bool
	currentHashes    chan []byte
	addHash          chan chan []byte
	quitLoop         chan bool
}

func (d *digest) hashLoop() {
	var (
		notify        bool
		hashList      = make([]byte, 0)
		runningHashes = make([]chan []byte, 0)
	)
	for {
		var nextHash <-chan []byte
		if len(runningHashes) > 0 {
			nextHash = runningHashes[0]
		} else if notify {
			notify = false
			list := make([]byte, len(hashList))
			copy(list, hashList)
			d.currentHashes <- list
		}

		select {
		case c := <-d.addHash:
			runningHashes = append(runningHashes, c)
		case hash := <-nextHash:
			hashList = append(hashList, hash...)
			runningHashes = runningHashes[1:]
		case <-d.reqCurrentHashes:
			notify = true
		case <-d.quitLoop:
			// flush the running hashes
			go func() {
				for _, c := range runningHashes {
					<-c
				}
			}()
			if notify {
				d.currentHashes <- []byte{}
			}
			d.quitLoop <- true
			return
		}
	}
}

func (d *digest) Reset() {
	d.currentChunk = make([]byte, 0, BlockSize)

	if d.quitLoop != nil {
		d.quitLoop <- true
		<-d.quitLoop
		close(d.quitLoop)
	}
	d.reqCurrentHashes = make(chan bool)
	d.quitLoop = make(chan bool)
	d.currentHashes = make(chan []byte)
	d.addHash = make(chan chan []byte)

	go d.hashLoop()
}

// New returns a new hash.Hash computing the ed2k checksum.
// The bool argument chooses between the new (false) or old (true) blockchain finishing algorithm.
// In the page given in the package description, false picks the "blue" method, true picks the "red" method.
func New(endWithNullChunk bool) hash.Hash {
	d := &digest{endWithNullChunk: endWithNullChunk}
	d.Reset()
	return d
}

func (d *digest) Size() int      { return Size }
func (d *digest) BlockSize() int { return BlockSize }

func (d *digest) Write(p []byte) (i int, err error) {
	for i = 0; i < len(p); {
		count := copy(d.currentChunk[len(d.currentChunk):cap(d.currentChunk)], p[i:])
		d.currentChunk = d.currentChunk[:len(d.currentChunk)+count]
		i += count
		if len(d.currentChunk) == cap(d.currentChunk) && len(p[i:]) > 0 {
			d.addHash <- md4SumAsync(d.currentChunk)
			// the old currentChunk now belongs to the md4 goroutine, make a new one
			d.currentChunk = make([]byte, 0, BlockSize)
		}
	}
	return
}

func (d *digest) Sum(p []byte) []byte {
	currentChunk := d.currentChunk

	d.reqCurrentHashes <- true
	hashList := <-d.currentHashes

	if d.endWithNullChunk && len(currentChunk) == cap(currentChunk) {
		hashList = md4Sum(currentChunk, hashList)
		currentChunk = currentChunk[:0] // Leave a null chunk for appending
	} else if len(hashList) == 0 {
		// We just hash the data itself, instead of "chunking"
		return md4Sum(currentChunk, nil)
	}
	// We always append a chunk if d.endWithNullChunk, regardless of length
	if d.endWithNullChunk || len(currentChunk) > 0 {
		hashList = md4Sum(currentChunk, hashList)
	}

	return md4Sum(hashList, p)
}

// Returns an hexadecimal representation of the hash
func (d *digest) String() string {
	return hex.EncodeToString(d.Sum(nil))
}

func md4Sum(data []byte, list []byte) []byte {
	md4 := md4.New()
	md4.Write(data)
	return md4.Sum(list)
}

func md4SumAsync(data []byte) chan []byte {
	c := make(chan []byte)
	go func() {
		c <- md4Sum(data, nil)
	}()
	return c
}
<|endoftext|>


<commit_before>package repository

import (
	"fmt"

	"gopkg.in/asaskevich/govalidator.v6"
)

func ValidateCreate(r *Repository) error {
	if err := validateName(r.Name); err != nil {
		return err
	}

	if err := validateDescription(r.Description); err != nil {
		return err
	}

	if err := validateWebsite(r.Website); err != nil {
		return err
	}

	return nil
}

func validateID(id string) error {
	if ok := govalidator.IsUUIDv4(id); !ok {
		return fmt.Errorf("id is not a valid uuid v4")
	}
	return nil
}

func validateName(name string) error {
	if ok := govalidator.IsAlphanumeric(name); !ok {
		return fmt.Errorf("username is not alphanumeric")
	}
	if ok := govalidator.IsByteLength(name, 4, 32); !ok {
		return fmt.Errorf("username is not between 4 and 32 characters long")
	}
	return nil
}

func validateDescription(description string) error {
	return nil
}

func validateWebsite(website string) error {
	if ok := govalidator.IsURL(website); !ok {
		return fmt.Errorf("%s is not a url", website)
	}

	return nil
}
<commit_msg>Fix typo in repository name validator errors<commit_after>package repository

import (
	"fmt"

	"gopkg.in/asaskevich/govalidator.v6"
)

func ValidateCreate(r *Repository) error {
	if err := validateName(r.Name); err != nil {
		return err
	}

	if err := validateDescription(r.Description); err != nil {
		return err
	}

	if err := validateWebsite(r.Website); err != nil {
		return err
	}

	return nil
}

func validateID(id string) error {
	if ok := govalidator.IsUUIDv4(id); !ok {
		return fmt.Errorf("id is not a valid uuid v4")
	}
	return nil
}

func validateName(name string) error {
	if ok := govalidator.IsAlphanumeric(name); !ok {
		return fmt.Errorf("name is not alphanumeric")
	}
	if ok := govalidator.IsByteLength(name, 4, 32); !ok {
		return fmt.Errorf("name is not between 4 and 32 characters long")
	}
	return nil
}

func validateDescription(description string) error {
	return nil
}

func validateWebsite(website string) error {
	if ok := govalidator.IsURL(website); !ok {
		return fmt.Errorf("%s is not a url", website)
	}

	return nil
}
<|endoftext|>


<commit_before>package sftp

import (
	"fmt"
	"io"
	"net"
	"os"
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

var _ = fmt.Print

type csPair struct {
	cli *Client
	svr *RequestServer
}

// these must be closed in order, else client.Close will hang
func (cs csPair) Close() {
	cs.svr.Close()
	cs.cli.Close()
	os.Remove(sock)
}

func (cs csPair) testHandler() *root {
	return cs.svr.Handlers.FileGet.(*root)
}

const sock = "/tmp/rstest.sock"

func clientRequestServerPair(t *testing.T) *csPair {
	ready := make(chan bool)
	os.Remove(sock) // either this or signal handling
	var server *RequestServer
	go func() {
		l, err := net.Listen("unix", sock)
		if err != nil {
			// neither assert nor t.Fatal reliably exit before Accept errors
			panic(err)
		}
		ready <- true
		fd, err := l.Accept()
		assert.Nil(t, err)
		handlers := InMemHandler()
		server = NewRequestServer(fd, handlers)
		server.Serve()
	}()
	<-ready
	defer os.Remove(sock)
	c, err := net.Dial("unix", sock)
	assert.Nil(t, err)
	client, err := NewClientPipe(c, c)
	if err != nil {
		t.Fatalf("%+v\n", err)
	}
	return &csPair{client, server}
}

// after adding logging, maybe check log to make sure packet handling
// was split over more than one worker
func TestRequestSplitWrite(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	w, err := p.cli.Create("/foo")
	assert.Nil(t, err)
	p.cli.maxPacket = 3 // force it to send in small chunks
	contents := "one two three four five six seven eight nine ten"
	w.Write([]byte(contents))
	w.Close()
	r := p.testHandler()
	f, _ := r.fetch("/foo")
	assert.Equal(t, contents, string(f.content))
}

func TestRequestCache(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	foo := NewRequest("", "foo")
	bar := NewRequest("", "bar")
	fh := p.svr.nextRequest(foo)
	bh := p.svr.nextRequest(bar)
	assert.Len(t, p.svr.openRequests, 2)
	_foo, ok := p.svr.getRequest(fh)
	assert.Equal(t, foo, _foo)
	assert.True(t, ok)
	_, ok = p.svr.getRequest("zed")
	assert.False(t, ok)
	p.svr.closeRequest(fh)
	p.svr.closeRequest(bh)
	assert.Len(t, p.svr.openRequests, 0)
}

func TestRequestCacheState(t *testing.T) {
	// test operation that uses open/close
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	assert.Len(t, p.svr.openRequests, 0)
	// test operation that doesn't open/close
	err = p.cli.Remove("/foo")
	assert.Nil(t, err)
	assert.Len(t, p.svr.openRequests, 0)
}

func putTestFile(cli *Client, path, content string) (int, error) {
	w, err := cli.Create(path)
	if err == nil {
		defer w.Close()
		return w.Write([]byte(content))
	}
	return 0, err
}

func TestRequestWrite(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	n, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	assert.Equal(t, 5, n)
	r := p.testHandler()
	f, err := r.fetch("/foo")
	assert.Nil(t, err)
	assert.False(t, f.isdir)
	assert.Equal(t, f.content, []byte("hello"))
}

// needs fail check
func TestRequestFilename(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	r := p.testHandler()
	f, err := r.fetch("/foo")
	assert.Nil(t, err)
	assert.Equal(t, f.Name(), "foo")
}

func TestRequestRead(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	rf, err := p.cli.Open("/foo")
	assert.Nil(t, err)
	defer rf.Close()
	contents := make([]byte, 5)
	n, err := rf.Read(contents)
	if err != nil && err != io.EOF {
		t.Fatalf("err: %v", err)
	}
	assert.Equal(t, 5, n)
	assert.Equal(t, "hello", string(contents[0:5]))
}

func TestRequestReadFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	rf, err := p.cli.Open("/foo")
	assert.Nil(t, err)
	contents := make([]byte, 5)
	n, err := rf.Read(contents)
	assert.Equal(t, n, 0)
	assert.Exactly(t, os.ErrNotExist, err)
}

func TestRequestOpen(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	fh, err := p.cli.Open("foo")
	assert.Nil(t, err)
	err = fh.Close()
	assert.Nil(t, err)
}

func TestRequestMkdir(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	err := p.cli.Mkdir("/foo")
	assert.Nil(t, err)
	r := p.testHandler()
	f, err := r.fetch("/foo")
	assert.Nil(t, err)
	assert.True(t, f.isdir)
}

func TestRequestRemove(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	r := p.testHandler()
	_, err = r.fetch("/foo")
	assert.Nil(t, err)
	err = p.cli.Remove("/foo")
	assert.Nil(t, err)
	_, err = r.fetch("/foo")
	assert.Equal(t, err, os.ErrNotExist)
}

func TestRequestRename(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	r := p.testHandler()
	_, err = r.fetch("/foo")
	assert.Nil(t, err)
	err = p.cli.Rename("/foo", "/bar")
	assert.Nil(t, err)
	_, err = r.fetch("/bar")
	assert.Nil(t, err)
	_, err = r.fetch("/foo")
	assert.Equal(t, err, os.ErrNotExist)
}

func TestRequestRenameFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	_, err = putTestFile(p.cli, "/bar", "goodbye")
	assert.Nil(t, err)
	err = p.cli.Rename("/foo", "/bar")
	assert.IsType(t, &StatusError{}, err)
}

func TestRequestStat(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	fi, err := p.cli.Stat("/foo")
	assert.Equal(t, fi.Name(), "foo")
	assert.Equal(t, fi.Size(), int64(5))
	assert.Equal(t, fi.Mode(), os.FileMode(0644))
	assert.NoError(t, testOsSys(fi.Sys()))
}

// NOTE: Setstat is a noop in the request server tests, but we want to test
// that is does nothing without crapping out.
func TestRequestSetstat(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	mode := os.FileMode(0644)
	err = p.cli.Chmod("/foo", mode)
	assert.Nil(t, err)
	fi, err := p.cli.Stat("/foo")
	assert.Nil(t, err)
	assert.Equal(t, fi.Name(), "foo")
	assert.Equal(t, fi.Size(), int64(5))
	assert.Equal(t, fi.Mode(), os.FileMode(0644))
	assert.NoError(t, testOsSys(fi.Sys()))
}

func TestRequestStatFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	fi, err := p.cli.Stat("/foo")
	assert.Nil(t, fi)
	assert.True(t, os.IsNotExist(err))
}

func TestRequestSymlink(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	err = p.cli.Symlink("/foo", "/bar")
	assert.Nil(t, err)
	r := p.testHandler()
	fi, err := r.fetch("/bar")
	assert.Nil(t, err)
	assert.True(t, fi.Mode()&os.ModeSymlink == os.ModeSymlink)
}

func TestRequestSymlinkFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	err := p.cli.Symlink("/foo", "/bar")
	assert.True(t, os.IsNotExist(err))
}

func TestRequestReadlink(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	err = p.cli.Symlink("/foo", "/bar")
	assert.Nil(t, err)
	rl, err := p.cli.ReadLink("/bar")
	assert.Nil(t, err)
	assert.Equal(t, "foo", rl)
}

func TestRequestReaddir(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	_, err = putTestFile(p.cli, "/bar", "goodbye")
	assert.Nil(t, err)
	di, err := p.cli.ReadDir("/")
	assert.Nil(t, err)
	assert.Len(t, di, 2)
	names := []string{di[0].Name(), di[1].Name()}
	sort.Strings(names)
	assert.Equal(t, []string{"bar", "foo"}, names)
}
<commit_msg>Add test to replicate fstat hang<commit_after>package sftp

import (
	"fmt"
	"io"
	"net"
	"os"
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

var _ = fmt.Print

type csPair struct {
	cli *Client
	svr *RequestServer
}

// these must be closed in order, else client.Close will hang
func (cs csPair) Close() {
	cs.svr.Close()
	cs.cli.Close()
	os.Remove(sock)
}

func (cs csPair) testHandler() *root {
	return cs.svr.Handlers.FileGet.(*root)
}

const sock = "/tmp/rstest.sock"

func clientRequestServerPair(t *testing.T) *csPair {
	ready := make(chan bool)
	os.Remove(sock) // either this or signal handling
	var server *RequestServer
	go func() {
		l, err := net.Listen("unix", sock)
		if err != nil {
			// neither assert nor t.Fatal reliably exit before Accept errors
			panic(err)
		}
		ready <- true
		fd, err := l.Accept()
		assert.Nil(t, err)
		handlers := InMemHandler()
		server = NewRequestServer(fd, handlers)
		server.Serve()
	}()
	<-ready
	defer os.Remove(sock)
	c, err := net.Dial("unix", sock)
	assert.Nil(t, err)
	client, err := NewClientPipe(c, c)
	if err != nil {
		t.Fatalf("%+v\n", err)
	}
	return &csPair{client, server}
}

// after adding logging, maybe check log to make sure packet handling
// was split over more than one worker
func TestRequestSplitWrite(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	w, err := p.cli.Create("/foo")
	assert.Nil(t, err)
	p.cli.maxPacket = 3 // force it to send in small chunks
	contents := "one two three four five six seven eight nine ten"
	w.Write([]byte(contents))
	w.Close()
	r := p.testHandler()
	f, _ := r.fetch("/foo")
	assert.Equal(t, contents, string(f.content))
}

func TestRequestCache(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	foo := NewRequest("", "foo")
	bar := NewRequest("", "bar")
	fh := p.svr.nextRequest(foo)
	bh := p.svr.nextRequest(bar)
	assert.Len(t, p.svr.openRequests, 2)
	_foo, ok := p.svr.getRequest(fh)
	assert.Equal(t, foo, _foo)
	assert.True(t, ok)
	_, ok = p.svr.getRequest("zed")
	assert.False(t, ok)
	p.svr.closeRequest(fh)
	p.svr.closeRequest(bh)
	assert.Len(t, p.svr.openRequests, 0)
}

func TestRequestCacheState(t *testing.T) {
	// test operation that uses open/close
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	assert.Len(t, p.svr.openRequests, 0)
	// test operation that doesn't open/close
	err = p.cli.Remove("/foo")
	assert.Nil(t, err)
	assert.Len(t, p.svr.openRequests, 0)
}

func putTestFile(cli *Client, path, content string) (int, error) {
	w, err := cli.Create(path)
	if err == nil {
		defer w.Close()
		return w.Write([]byte(content))
	}
	return 0, err
}

func TestRequestWrite(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	n, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	assert.Equal(t, 5, n)
	r := p.testHandler()
	f, err := r.fetch("/foo")
	assert.Nil(t, err)
	assert.False(t, f.isdir)
	assert.Equal(t, f.content, []byte("hello"))
}

// needs fail check
func TestRequestFilename(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	r := p.testHandler()
	f, err := r.fetch("/foo")
	assert.Nil(t, err)
	assert.Equal(t, f.Name(), "foo")
}

func TestRequestRead(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	rf, err := p.cli.Open("/foo")
	assert.Nil(t, err)
	defer rf.Close()
	contents := make([]byte, 5)
	n, err := rf.Read(contents)
	if err != nil && err != io.EOF {
		t.Fatalf("err: %v", err)
	}
	assert.Equal(t, 5, n)
	assert.Equal(t, "hello", string(contents[0:5]))
}

func TestRequestReadFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	rf, err := p.cli.Open("/foo")
	assert.Nil(t, err)
	contents := make([]byte, 5)
	n, err := rf.Read(contents)
	assert.Equal(t, n, 0)
	assert.Exactly(t, os.ErrNotExist, err)
}

func TestRequestOpen(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	fh, err := p.cli.Open("foo")
	assert.Nil(t, err)
	err = fh.Close()
	assert.Nil(t, err)
}

func TestRequestMkdir(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	err := p.cli.Mkdir("/foo")
	assert.Nil(t, err)
	r := p.testHandler()
	f, err := r.fetch("/foo")
	assert.Nil(t, err)
	assert.True(t, f.isdir)
}

func TestRequestRemove(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	r := p.testHandler()
	_, err = r.fetch("/foo")
	assert.Nil(t, err)
	err = p.cli.Remove("/foo")
	assert.Nil(t, err)
	_, err = r.fetch("/foo")
	assert.Equal(t, err, os.ErrNotExist)
}

func TestRequestRename(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	r := p.testHandler()
	_, err = r.fetch("/foo")
	assert.Nil(t, err)
	err = p.cli.Rename("/foo", "/bar")
	assert.Nil(t, err)
	_, err = r.fetch("/bar")
	assert.Nil(t, err)
	_, err = r.fetch("/foo")
	assert.Equal(t, err, os.ErrNotExist)
}

func TestRequestRenameFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	_, err = putTestFile(p.cli, "/bar", "goodbye")
	assert.Nil(t, err)
	err = p.cli.Rename("/foo", "/bar")
	assert.IsType(t, &StatusError{}, err)
}

func TestRequestStat(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	fi, err := p.cli.Stat("/foo")
	assert.Equal(t, fi.Name(), "foo")
	assert.Equal(t, fi.Size(), int64(5))
	assert.Equal(t, fi.Mode(), os.FileMode(0644))
	assert.NoError(t, testOsSys(fi.Sys()))
}

// NOTE: Setstat is a noop in the request server tests, but we want to test
// that is does nothing without crapping out.
func TestRequestSetstat(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	mode := os.FileMode(0644)
	err = p.cli.Chmod("/foo", mode)
	assert.Nil(t, err)
	fi, err := p.cli.Stat("/foo")
	assert.Nil(t, err)
	assert.Equal(t, fi.Name(), "foo")
	assert.Equal(t, fi.Size(), int64(5))
	assert.Equal(t, fi.Mode(), os.FileMode(0644))
	assert.NoError(t, testOsSys(fi.Sys()))
}

func TestRequestFstat(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	fp, err := p.cli.Open("/foo")
	assert.Nil(t, err)
	fi, err := fp.Stat()
	assert.Nil(t, err)
	assert.Equal(t, fi.Name(), "foo")
	assert.Equal(t, fi.Size(), int64(5))
	assert.Equal(t, fi.Mode(), os.FileMode(0644))
	assert.NoError(t, testOsSys(fi.Sys()))
}

func TestRequestStatFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	fi, err := p.cli.Stat("/foo")
	assert.Nil(t, fi)
	assert.True(t, os.IsNotExist(err))
}

func TestRequestSymlink(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	err = p.cli.Symlink("/foo", "/bar")
	assert.Nil(t, err)
	r := p.testHandler()
	fi, err := r.fetch("/bar")
	assert.Nil(t, err)
	assert.True(t, fi.Mode()&os.ModeSymlink == os.ModeSymlink)
}

func TestRequestSymlinkFail(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	err := p.cli.Symlink("/foo", "/bar")
	assert.True(t, os.IsNotExist(err))
}

func TestRequestReadlink(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	err = p.cli.Symlink("/foo", "/bar")
	assert.Nil(t, err)
	rl, err := p.cli.ReadLink("/bar")
	assert.Nil(t, err)
	assert.Equal(t, "foo", rl)
}

func TestRequestReaddir(t *testing.T) {
	p := clientRequestServerPair(t)
	defer p.Close()
	_, err := putTestFile(p.cli, "/foo", "hello")
	assert.Nil(t, err)
	_, err = putTestFile(p.cli, "/bar", "goodbye")
	assert.Nil(t, err)
	di, err := p.cli.ReadDir("/")
	assert.Nil(t, err)
	assert.Len(t, di, 2)
	names := []string{di[0].Name(), di[1].Name()}
	sort.Strings(names)
	assert.Equal(t, []string{"bar", "foo"}, names)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"github.com/99designs/aws-vault/keyring"
	"github.com/aws/aws-sdk-go/aws/awserr"
)

type ExecCommandInput struct {
	Profile  string
	Command  string
	Args     []string
	Keyring  keyring.Keyring
	Duration time.Duration
	WriteEnv bool
	MfaToken string
	Signals  chan os.Signal
}

func ExecCommand(ui Ui, input ExecCommandInput) {
	creds, err := NewVaultCredentials(input.Keyring, input.Profile, VaultOptions{
		SessionDuration: input.Duration,
		WriteEnv:        input.WriteEnv,
		MfaToken:        input.MfaToken,
	})
	if err != nil {
		ui.Error.Fatal(err)
	}

	val, err := creds.Get()
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
			ui.Error.Fatalf("No credentials found for profile %q", input.Profile)
		} else {
			ui.Error.Fatal(err)
		}
	}

	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		ui.Error.Fatal(err)
	}

	go func() {
		log.Printf("Metadata server listening on %s", l.Addr().String())
		ui.Error.Fatal(http.Serve(l, proxyHandler(NewMetadataHandler(creds))))
	}()

	profs, err := parseProfiles()
	if err != nil {
		ui.Error.Fatal(err)
	}

	cfg, err := writeTempConfig(input.Profile, profs)
	if err != nil {
		ui.Error.Fatal(err)
	}

	env := os.Environ()
	env = overwriteEnv(env, "http_proxy", "http://"+l.Addr().String())
	env = overwriteEnv(env, "no_proxy", "amazonaws.com")
	env = overwriteEnv(env, "AWS_CONFIG_FILE", cfg.Name())
	env = overwriteEnv(env, "AWS_DEFAULT_PROFILE", input.Profile)
	env = overwriteEnv(env, "AWS_PROFILE", input.Profile)

	env = unsetEnv(env, "AWS_ACCESS_KEY_ID")
	env = unsetEnv(env, "AWS_SECRET_ACCESS_KEY")
	env = unsetEnv(env, "AWS_CREDENTIAL_FILE")

	if region, ok := profs[input.Profile]["region"]; ok {
		env = overwriteEnv(env, "AWS_DEFAULT_REGION", region)
		env = overwriteEnv(env, "AWS_REGION", region)
	}

	if input.WriteEnv {
		env = overwriteEnv(env, "AWS_ACCESS_KEY_ID", val.AccessKeyID)
		env = overwriteEnv(env, "AWS_SECRET_ACCESS_KEY", val.SecretAccessKey)

		if val.SessionToken != "" {
			env = overwriteEnv(env, "AWS_SESSION_TOKEN", val.SessionToken)
			env = overwriteEnv(env, "AWS_SECURITY_TOKEN", val.SessionToken)
		}
	}

	cmd := exec.Command(input.Command, input.Args...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	go func() {
		sig := <-input.Signals
		if cmd.Process != nil {
			cmd.Process.Signal(sig)
		}
	}()

	var waitStatus syscall.WaitStatus
	if err := cmd.Run(); err != nil {
		if err != nil {
			ui.Error.Println(err)
		}
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			os.Exit(waitStatus.ExitStatus())
		}
	}

}

// write out a config excluding role switching keys
func writeTempConfig(profile string, conf profiles) (*os.File, error) {
	tmpConfig, err := ioutil.TempFile(os.TempDir(), "aws-vault")
	if err != nil {
		return nil, err
	}

	// allow some time for keychain prompt
	newConfig := map[string]string{
		"metadata_service_timeout":      "15",
		"metadata_service_num_attempts": "2",
	}

	for k, v := range conf[profile] {
		if k != "source_profile" && k != "role_arn" {
			newConfig[k] = v
		}
	}

	return tmpConfig, writeProfiles(tmpConfig, profiles{profile: newConfig})
}

func unsetEnv(env []string, key string) []string {
	envCopy := []string{}

	for _, e := range env {
		if !strings.HasPrefix(key+"=", e) {
			envCopy = append(envCopy, e)
		}
	}

	return envCopy
}

func overwriteEnv(env []string, key, val string) []string {
	var found bool

	for idx, e := range env {
		if strings.HasPrefix(key+"=", e) {
			env[idx] = key + "=" + val
			found = true
		} else {
			env[idx] = e
		}
	}

	if !found {
		env = append(env, key+"="+val)
	}

	return env
}

func connectProxy(w http.ResponseWriter, r *http.Request) error {
	d, err := net.Dial("tcp", r.RequestURI)
	if err != nil {
		return err
	}
	hj, ok := w.(http.Hijacker)
	if !ok {
		return err
	}
	conn, bufrw, err := hj.Hijack()
	if err != nil {
		return err
	}
	defer conn.Close()
	defer d.Close()

	bufrw.WriteString("HTTP/1.0 200 Connection established\r\n\r\n")
	bufrw.Flush()

	go io.Copy(d, conn)
	io.Copy(conn, d)

	return nil
}

func proxyHandler(upstream http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s", r.Method, r.RequestURI)
		if r.Method == "GET" && strings.HasPrefix(r.URL.Path, "/latest/meta-data") {
			upstream.ServeHTTP(w, r)
		} else if r.Method == "CONNECT" {
			if err := connectProxy(w, r); err != nil {
				http.Error(w, "Error connecting to proxy: "+err.Error(), http.StatusGatewayTimeout)
			}
		} else {
			proxy := &httputil.ReverseProxy{Director: func(req *http.Request) {
				req.Method = "GET"
				req.URL.Scheme = "http"
				req.URL.Host = r.Host
			}}
			proxy.ServeHTTP(w, r)
		}
	})
}
<commit_msg>Remove metadata service config, too many aws-cli bugs<commit_after>package main

import (
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"github.com/99designs/aws-vault/keyring"
	"github.com/aws/aws-sdk-go/aws/awserr"
)

type ExecCommandInput struct {
	Profile  string
	Command  string
	Args     []string
	Keyring  keyring.Keyring
	Duration time.Duration
	WriteEnv bool
	MfaToken string
	Signals  chan os.Signal
}

func ExecCommand(ui Ui, input ExecCommandInput) {
	creds, err := NewVaultCredentials(input.Keyring, input.Profile, VaultOptions{
		SessionDuration: input.Duration,
		WriteEnv:        input.WriteEnv,
		MfaToken:        input.MfaToken,
	})
	if err != nil {
		ui.Error.Fatal(err)
	}

	val, err := creds.Get()
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
			ui.Error.Fatalf("No credentials found for profile %q", input.Profile)
		} else {
			ui.Error.Fatal(err)
		}
	}

	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		ui.Error.Fatal(err)
	}

	go func() {
		log.Printf("Metadata server listening on %s", l.Addr().String())
		ui.Error.Fatal(http.Serve(l, proxyHandler(NewMetadataHandler(creds))))
	}()

	profs, err := parseProfiles()
	if err != nil {
		ui.Error.Fatal(err)
	}

	cfg, err := writeTempConfig(input.Profile, profs)
	if err != nil {
		ui.Error.Fatal(err)
	}

	env := os.Environ()
	env = overwriteEnv(env, "http_proxy", "http://"+l.Addr().String())
	env = overwriteEnv(env, "no_proxy", "amazonaws.com")
	env = overwriteEnv(env, "AWS_CONFIG_FILE", cfg.Name())
	env = overwriteEnv(env, "AWS_DEFAULT_PROFILE", input.Profile)
	env = overwriteEnv(env, "AWS_PROFILE", input.Profile)

	env = unsetEnv(env, "AWS_ACCESS_KEY_ID")
	env = unsetEnv(env, "AWS_SECRET_ACCESS_KEY")
	env = unsetEnv(env, "AWS_CREDENTIAL_FILE")

	if region, ok := profs[input.Profile]["region"]; ok {
		env = overwriteEnv(env, "AWS_DEFAULT_REGION", region)
		env = overwriteEnv(env, "AWS_REGION", region)
	}

	if input.WriteEnv {
		env = overwriteEnv(env, "AWS_ACCESS_KEY_ID", val.AccessKeyID)
		env = overwriteEnv(env, "AWS_SECRET_ACCESS_KEY", val.SecretAccessKey)

		if val.SessionToken != "" {
			env = overwriteEnv(env, "AWS_SESSION_TOKEN", val.SessionToken)
			env = overwriteEnv(env, "AWS_SECURITY_TOKEN", val.SessionToken)
		}
	}

	cmd := exec.Command(input.Command, input.Args...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	go func() {
		sig := <-input.Signals
		if cmd.Process != nil {
			cmd.Process.Signal(sig)
		}
	}()

	var waitStatus syscall.WaitStatus
	if err := cmd.Run(); err != nil {
		if err != nil {
			ui.Error.Println(err)
		}
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			os.Exit(waitStatus.ExitStatus())
		}
	}

}

// write out a config excluding role switching keys
func writeTempConfig(profile string, conf profiles) (*os.File, error) {
	tmpConfig, err := ioutil.TempFile(os.TempDir(), "aws-vault")
	if err != nil {
		return nil, err
	}

	newConfig := map[string]string{}

	for k, v := range conf[profile] {
		if k != "source_profile" && k != "role_arn" {
			newConfig[k] = v
		}
	}

	return tmpConfig, writeProfiles(tmpConfig, profiles{profile: newConfig})
}

func unsetEnv(env []string, key string) []string {
	envCopy := []string{}

	for _, e := range env {
		if !strings.HasPrefix(key+"=", e) {
			envCopy = append(envCopy, e)
		}
	}

	return envCopy
}

func overwriteEnv(env []string, key, val string) []string {
	var found bool

	for idx, e := range env {
		if strings.HasPrefix(key+"=", e) {
			env[idx] = key + "=" + val
			found = true
		} else {
			env[idx] = e
		}
	}

	if !found {
		env = append(env, key+"="+val)
	}

	return env
}

func connectProxy(w http.ResponseWriter, r *http.Request) error {
	d, err := net.Dial("tcp", r.RequestURI)
	if err != nil {
		return err
	}
	hj, ok := w.(http.Hijacker)
	if !ok {
		return err
	}
	conn, bufrw, err := hj.Hijack()
	if err != nil {
		return err
	}
	defer conn.Close()
	defer d.Close()

	bufrw.WriteString("HTTP/1.0 200 Connection established\r\n\r\n")
	bufrw.Flush()

	go io.Copy(d, conn)
	io.Copy(conn, d)

	return nil
}

func proxyHandler(upstream http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s", r.Method, r.RequestURI)
		if r.Method == "GET" && strings.HasPrefix(r.URL.Path, "/latest/meta-data") {
			upstream.ServeHTTP(w, r)
		} else if r.Method == "CONNECT" {
			if err := connectProxy(w, r); err != nil {
				http.Error(w, "Error connecting to proxy: "+err.Error(), http.StatusGatewayTimeout)
			}
		} else {
			proxy := &httputil.ReverseProxy{Director: func(req *http.Request) {
				req.Method = "GET"
				req.URL.Scheme = "http"
				req.URL.Host = r.Host
			}}
			proxy.ServeHTTP(w, r)
		}
	})
}
<|endoftext|>


<commit_before>package goque

import (
	"os"
	"path/filepath"
)

// goqueType defines the type of Goque data structure used.
type goqueType uint8

// The possible Goque types, used to determine compatibility when
// one stored type is trying to be opened by a different type.
const (
	goqueStack goqueType = iota
	goqueQueue
	goquePriorityQueue
)

// checkGoqueType checks if the type of Goque data structure
// trying to be opened is compatible with the opener type.
//
// A file named 'GOQUE' within the data directory used by
// the structure stored the structure type, using the constants
// declared above.
//
// Stacks and Queues are 100% compatible with eachother, while
// a PriorityQueue is incompatible with both.
//
// Returns true if types are compatible and false if incompatible.
func checkGoqueType(dataDir string, gt goqueType) (bool, error) {
	// Set the path and gtype byte slice used when saving to a file.
	path := filepath.Join(dataDir, "GOQUE")
	gtb := make([]byte, 1)
	gtb[0] = byte(gt)

	// Read 'GOQUE' file for this directory.
	f, err := os.OpenFile(path, os.O_RDONLY, 0)
	if os.IsNotExist(err) {
		f, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
		if err != nil {
			return false, err
		}

		_, err = f.Write(gtb)
		if err != nil {
			return false, err
		}

		f.Close()
		return true, nil
	}
	if err != nil {
		return false, err
	}

	// Get the saved type from the file.
	fb := make([]byte, 1)
	_, err = f.Read(fb)
	if err != nil {
		return false, err
	}
	f.Close()

	// Convert the file byte to its goqueType.
	filegt := goqueType(fb[0])

	// Compare the types.
	if filegt == gt {
		return true, nil
	} else if filegt == goqueStack && gt == goqueQueue {
		return true, nil
	} else if filegt == goqueQueue && gt == goqueStack {
		return true, nil
	} else {
		return false, nil
	}
}
<commit_msg>Fixed golint for file.go<commit_after>package goque

import (
	"os"
	"path/filepath"
)

// goqueType defines the type of Goque data structure used.
type goqueType uint8

// The possible Goque types, used to determine compatibility when
// one stored type is trying to be opened by a different type.
const (
	goqueStack goqueType = iota
	goqueQueue
	goquePriorityQueue
)

// checkGoqueType checks if the type of Goque data structure
// trying to be opened is compatible with the opener type.
//
// A file named 'GOQUE' within the data directory used by
// the structure stored the structure type, using the constants
// declared above.
//
// Stacks and Queues are 100% compatible with eachother, while
// a PriorityQueue is incompatible with both.
//
// Returns true if types are compatible and false if incompatible.
func checkGoqueType(dataDir string, gt goqueType) (bool, error) {
	// Set the path and gtype byte slice used when saving to a file.
	path := filepath.Join(dataDir, "GOQUE")
	gtb := make([]byte, 1)
	gtb[0] = byte(gt)

	// Read 'GOQUE' file for this directory.
	f, err := os.OpenFile(path, os.O_RDONLY, 0)
	if os.IsNotExist(err) {
		f, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
		if err != nil {
			return false, err
		}

		_, err = f.Write(gtb)
		if err != nil {
			return false, err
		}

		f.Close()
		return true, nil
	}
	if err != nil {
		return false, err
	}

	// Get the saved type from the file.
	fb := make([]byte, 1)
	_, err = f.Read(fb)
	if err != nil {
		return false, err
	}
	f.Close()

	// Convert the file byte to its goqueType.
	filegt := goqueType(fb[0])

	// Compare the types.
	if filegt == gt {
		return true, nil
	} else if filegt == goqueStack && gt == goqueQueue {
		return true, nil
	} else if filegt == goqueQueue && gt == goqueStack {
		return true, nil
	}

	return false, nil
}
<|endoftext|>


<commit_before>package sshmux

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

// read a list of hosts to run command on
func GetHostsByFile(file string) []string {
	var hosts []string
	fr, _ := os.Open(file)
	defer fr.Close()
	r := bufio.NewReader(fr)
	for {
		readline, _ := r.ReadString('\n')
		// ignore 'comment' lines
		if !strings.Contains(readline, "#") {
			// add host to list
			if readline != "" {
				hosts = append(hosts, strings.Trim(readline, "\n"))
			}
		}
		// check for end of file
		var err error
		if err == io.EOF {
			break
		}
	}
	return hosts
}
<commit_msg>reverting the io.EOF<commit_after>package sshmux

import (
	"bufio"
	"os"
	"strings"
)

// read a list of hosts to run command on
func GetHostsByFile(file string) []string {
	var hosts []string
	fr, _ := os.Open(file)
	defer fr.Close()
	r := bufio.NewReader(fr)
	for {
		readline, _ := r.ReadString('\n')
		// ignore 'comment' lines
		if !strings.Contains(readline, "#") {
			// add host to list
			if readline != "" {
				hosts = append(hosts, strings.Trim(readline, "\n"))
			}
		}
		// check for end of file
		if readline == "" {
			break
		}

	}
	return hosts
}
<|endoftext|>


<commit_before>package filemanager

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"hash"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"github.com/gohugoio/hugo/parser"
)

// File contains the information about a particular file or directory.
type File struct {
	// Indicates the Kind of view on the front-end (Listing, editor or preview).
	Kind string `json:"kind"`
	// The name of the file.
	Name string `json:"name"`
	// The Size of the file.
	Size int64 `json:"size"`
	// The absolute URL.
	URL string `json:"url"`
	// The extension of the file.
	Extension string `json:"extension"`
	// The last modified time.
	ModTime time.Time `json:"modified"`
	// The File Mode.
	Mode os.FileMode `json:"mode"`
	// Indicates if this file is a directory.
	IsDir bool `json:"isDir"`
	// Absolute path.
	Path string `json:"path"`
	// Relative path to user's virtual File System.
	VirtualPath string `json:"virtualPath"`
	// Indicates the file content type: video, text, image, music or blob.
	Type string `json:"type"`
	// Stores the content of a text file.
	Content string `json:"content,omitempty"`

	*Listing `json:",omitempty"`

	Metadata string `json:"metadata,omitempty"`
	Language string `json:"language,omitempty"`
}

// A Listing is the context used to fill out a template.
type Listing struct {
	// The items (files and folders) in the path.
	Items []*File `json:"items"`
	// The number of directories in the Listing.
	NumDirs int `json:"numDirs"`
	// The number of files (items that aren't directories) in the Listing.
	NumFiles int `json:"numFiles"`
	// Which sorting order is used.
	Sort string `json:"sort"`
	// And which order.
	Order string `json:"order"`
}

// GetInfo gets the file information and, in case of error, returns the
// respective HTTP error code
func GetInfo(url *url.URL, c *FileManager, u *User) (*File, error) {
	var err error

	i := &File{
		URL:         "/files" + url.String(),
		VirtualPath: url.Path,
		Path:        filepath.Join(u.Scope, url.Path),
	}

	info, err := u.FileSystem.Stat(url.Path)
	if err != nil {
		return i, err
	}

	i.Name = info.Name()
	i.ModTime = info.ModTime()
	i.Mode = info.Mode()
	i.IsDir = info.IsDir()
	i.Size = info.Size()
	i.Extension = filepath.Ext(i.Name)

	if i.IsDir && !strings.HasSuffix(i.URL, "/") {
		i.URL += "/"
	}

	return i, nil
}

// GetListing gets the information about a specific directory and its files.
func (i *File) GetListing(u *User, r *http.Request) error {
	// Gets the directory information using the Virtual File System of
	// the user configuration.
	f, err := u.FileSystem.OpenFile(i.VirtualPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer f.Close()

	// Reads the directory and gets the information about the files.
	files, err := f.Readdir(-1)
	if err != nil {
		return err
	}

	var (
		fileinfos           []*File
		dirCount, fileCount int
	)

	baseurl, err := url.PathUnescape(i.URL)
	if err != nil {
		return err
	}

	for _, f := range files {
		name := f.Name()
		allowed := u.Allowed("/" + name)

		if !allowed {
			continue
		}

		if strings.HasPrefix(f.Mode().String(), "L") {
			// It's a symbolic link
			// The FileInfo from Readdir treats symbolic link as a file only.
			info, err := os.Stat(f.Name())
			if err != nil {
				return err
			}
			f = info
		}

		if f.IsDir() {
			name += "/"
			dirCount++
		} else {
			fileCount++
		}

		// Absolute URL
		url := url.URL{Path: baseurl + name}

		i := &File{
			Name:        f.Name(),
			Size:        f.Size(),
			ModTime:     f.ModTime(),
			Mode:        f.Mode(),
			IsDir:       f.IsDir(),
			URL:         url.String(),
			Extension:   filepath.Ext(name),
			VirtualPath: filepath.Join(i.VirtualPath, name),
			Path:        filepath.Join(i.Path, name),
		}

		i.GetFileType(false)
		fileinfos = append(fileinfos, i)
	}

	i.Listing = &Listing{
		Items:    fileinfos,
		NumDirs:  dirCount,
		NumFiles: fileCount,
	}

	return nil
}

// GetEditor gets the editor based on a Info struct
func (i *File) GetEditor() error {
	i.Language = editorLanguage(i.Extension)
	// If the editor will hold only content, leave now.
	if editorMode(i.Language) == "content" {
		return nil
	}

	// If the file doesn't have any kind of metadata, leave now.
	if !hasRune(i.Content) {
		return nil
	}

	buffer := bytes.NewBuffer([]byte(i.Content))
	page, err := parser.ReadFrom(buffer)

	// If there is an error, just ignore it and return nil.
	// This way, the file can be served for editing.
	if err != nil {

		return nil
	}

	i.Content = strings.TrimSpace(string(page.Content()))
	i.Metadata = strings.TrimSpace(string(page.FrontMatter()))
	return nil
}

// GetFileType obtains the mimetype and converts it to a simple
// type nomenclature.
func (i *File) GetFileType(checkContent bool) error {
	var content []byte
	var err error

	// Tries to get the file mimetype using its extension.
	mimetype := mime.TypeByExtension(i.Extension)

	if mimetype == "" && checkContent {
		file, err := os.Open(i.Path)
		if err != nil {
			return err
		}
		defer file.Close()

		// Only the first 512 bytes are used to sniff the content type.
		buffer := make([]byte, 512)
		_, err = file.Read(buffer)
		if err != nil && err != io.EOF {
			return err
		}

		// Tries to get the file mimetype using its first
		// 512 bytes.
		mimetype = http.DetectContentType(buffer)
	}

	if strings.HasPrefix(mimetype, "video") {
		i.Type = "video"
		return nil
	}

	if strings.HasPrefix(mimetype, "audio") {
		i.Type = "audio"
		return nil
	}

	if strings.HasPrefix(mimetype, "image") {
		i.Type = "image"
		return nil
	}

	if strings.HasPrefix(mimetype, "text") {
		i.Type = "text"
		goto End
	}

	if strings.HasPrefix(mimetype, "application/javascript") {
		i.Type = "text"
		goto End
	}

	// If the type isn't text (and is blob for example), it will check some
	// common types that are mistaken not to be text.
	for _, extension := range textExtensions {
		if strings.HasSuffix(i.Name, extension) {
			i.Type = "text"
			goto End
		}
	}

	i.Type = "blob"

End:
	// If the file type is text, save its content.
	if i.Type == "text" {
		if len(content) == 0 {
			content, err = ioutil.ReadFile(i.Path)
			if err != nil {
				return err
			}
		}

		i.Content = string(content)
	}

	return nil
}

// Checksum retrieves the checksum of a file.
func (i File) Checksum(algo string) (string, error) {
	file, err := os.Open(i.Path)
	if err != nil {
		return "", err
	}

	defer file.Close()

	var h hash.Hash

	switch algo {
	case "md5":
		h = md5.New()
	case "sha1":
		h = sha1.New()
	case "sha256":
		h = sha256.New()
	case "sha512":
		h = sha512.New()
	default:
		return "", ErrInvalidOption
	}

	_, err = io.Copy(h, file)
	if err != nil {
		return "", err
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}

// CanBeEdited checks if the extension of a file is supported by the editor
func (i File) CanBeEdited() bool {
	return i.Type == "text"
}

// ApplySort applies the sort order using .Order and .Sort
func (l Listing) ApplySort() {
	// Check '.Order' to know how to sort
	if l.Order == "desc" {
		switch l.Sort {
		case "name":
			sort.Sort(sort.Reverse(byName(l)))
		case "size":
			sort.Sort(sort.Reverse(bySize(l)))
		case "modified":
			sort.Sort(sort.Reverse(byModified(l)))
		default:
			// If not one of the above, do nothing
			return
		}
	} else { // If we had more Orderings we could add them here
		switch l.Sort {
		case "name":
			sort.Sort(byName(l))
		case "size":
			sort.Sort(bySize(l))
		case "modified":
			sort.Sort(byModified(l))
		default:
			sort.Sort(byName(l))
			return
		}
	}
}

// Implement sorting for Listing
type byName Listing
type bySize Listing
type byModified Listing

// By Name
func (l byName) Len() int {
	return len(l.Items)
}

func (l byName) Swap(i, j int) {
	l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
}

// Treat upper and lower case equally
func (l byName) Less(i, j int) bool {
	if l.Items[i].IsDir && !l.Items[j].IsDir {
		return true
	}

	if !l.Items[i].IsDir && l.Items[j].IsDir {
		return false
	}

	return strings.ToLower(l.Items[i].Name) < strings.ToLower(l.Items[j].Name)
}

// By Size
func (l bySize) Len() int {
	return len(l.Items)
}

func (l bySize) Swap(i, j int) {
	l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
}

const directoryOffset = -1 << 31 // = math.MinInt32
func (l bySize) Less(i, j int) bool {
	iSize, jSize := l.Items[i].Size, l.Items[j].Size
	if l.Items[i].IsDir {
		iSize = directoryOffset + iSize
	}
	if l.Items[j].IsDir {
		jSize = directoryOffset + jSize
	}
	return iSize < jSize
}

// By Modified
func (l byModified) Len() int {
	return len(l.Items)
}

func (l byModified) Swap(i, j int) {
	l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
}

func (l byModified) Less(i, j int) bool {
	iModified, jModified := l.Items[i].ModTime, l.Items[j].ModTime
	return iModified.Sub(jModified) < 0
}

var textExtensions = [...]string{
	".md", ".markdown", ".mdown", ".mmark",
	".asciidoc", ".adoc", ".ad",
	".rst",
	".json", ".toml", ".yaml", ".csv", ".xml", ".rss", ".conf", ".ini",
	".tex", ".sty",
	".css", ".sass", ".scss",
	".js",
	".html",
	".txt", ".rtf",
	".sh", ".bash", ".ps1", ".bat", ".cmd",
	".php", ".pl", ".py",
	"Caddyfile",
	".htaccess",
	".c", ".cc", ".h", ".hh", ".cpp", ".hpp", ".f90",
	".f", ".bas", ".d", ".ada", ".nim", ".cr", ".java", ".cs", ".vala", ".vapi",
}

// hasRune checks if the file has the frontmatter rune
func hasRune(file string) bool {
	return strings.HasPrefix(file, "---") ||
		strings.HasPrefix(file, "+++") ||
		strings.HasPrefix(file, "{")
}

func editorMode(language string) string {
	switch language {
	case "markdown", "asciidoc", "rst":
		return "content+metadata"
	}

	return "content"
}

func editorLanguage(mode string) string {
	mode = strings.TrimPrefix(mode, ".")

	switch mode {
	case "md", "markdown", "mdown", "mmark":
		mode = "markdown"
	case "yml":
		mode = "yaml"
	case "asciidoc", "adoc", "ad":
		mode = "asciidoc"
	case "rst":
		mode = "rst"
	case "html", "htm", "xml":
		mode = "htmlmixed"
	case "js":
		mode = "javascript"
	case "go":
		mode = "golang"
	case "":
		mode = "text"
	}

	return mode
}
<commit_msg>Whitelist yml and tml extensions<commit_after>package filemanager

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"hash"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"github.com/gohugoio/hugo/parser"
)

// File contains the information about a particular file or directory.
type File struct {
	// Indicates the Kind of view on the front-end (Listing, editor or preview).
	Kind string `json:"kind"`
	// The name of the file.
	Name string `json:"name"`
	// The Size of the file.
	Size int64 `json:"size"`
	// The absolute URL.
	URL string `json:"url"`
	// The extension of the file.
	Extension string `json:"extension"`
	// The last modified time.
	ModTime time.Time `json:"modified"`
	// The File Mode.
	Mode os.FileMode `json:"mode"`
	// Indicates if this file is a directory.
	IsDir bool `json:"isDir"`
	// Absolute path.
	Path string `json:"path"`
	// Relative path to user's virtual File System.
	VirtualPath string `json:"virtualPath"`
	// Indicates the file content type: video, text, image, music or blob.
	Type string `json:"type"`
	// Stores the content of a text file.
	Content string `json:"content,omitempty"`

	*Listing `json:",omitempty"`

	Metadata string `json:"metadata,omitempty"`
	Language string `json:"language,omitempty"`
}

// A Listing is the context used to fill out a template.
type Listing struct {
	// The items (files and folders) in the path.
	Items []*File `json:"items"`
	// The number of directories in the Listing.
	NumDirs int `json:"numDirs"`
	// The number of files (items that aren't directories) in the Listing.
	NumFiles int `json:"numFiles"`
	// Which sorting order is used.
	Sort string `json:"sort"`
	// And which order.
	Order string `json:"order"`
}

// GetInfo gets the file information and, in case of error, returns the
// respective HTTP error code
func GetInfo(url *url.URL, c *FileManager, u *User) (*File, error) {
	var err error

	i := &File{
		URL:         "/files" + url.String(),
		VirtualPath: url.Path,
		Path:        filepath.Join(u.Scope, url.Path),
	}

	info, err := u.FileSystem.Stat(url.Path)
	if err != nil {
		return i, err
	}

	i.Name = info.Name()
	i.ModTime = info.ModTime()
	i.Mode = info.Mode()
	i.IsDir = info.IsDir()
	i.Size = info.Size()
	i.Extension = filepath.Ext(i.Name)

	if i.IsDir && !strings.HasSuffix(i.URL, "/") {
		i.URL += "/"
	}

	return i, nil
}

// GetListing gets the information about a specific directory and its files.
func (i *File) GetListing(u *User, r *http.Request) error {
	// Gets the directory information using the Virtual File System of
	// the user configuration.
	f, err := u.FileSystem.OpenFile(i.VirtualPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer f.Close()

	// Reads the directory and gets the information about the files.
	files, err := f.Readdir(-1)
	if err != nil {
		return err
	}

	var (
		fileinfos           []*File
		dirCount, fileCount int
	)

	baseurl, err := url.PathUnescape(i.URL)
	if err != nil {
		return err
	}

	for _, f := range files {
		name := f.Name()
		allowed := u.Allowed("/" + name)

		if !allowed {
			continue
		}

		if strings.HasPrefix(f.Mode().String(), "L") {
			// It's a symbolic link
			// The FileInfo from Readdir treats symbolic link as a file only.
			info, err := os.Stat(f.Name())
			if err != nil {
				return err
			}
			f = info
		}

		if f.IsDir() {
			name += "/"
			dirCount++
		} else {
			fileCount++
		}

		// Absolute URL
		url := url.URL{Path: baseurl + name}

		i := &File{
			Name:        f.Name(),
			Size:        f.Size(),
			ModTime:     f.ModTime(),
			Mode:        f.Mode(),
			IsDir:       f.IsDir(),
			URL:         url.String(),
			Extension:   filepath.Ext(name),
			VirtualPath: filepath.Join(i.VirtualPath, name),
			Path:        filepath.Join(i.Path, name),
		}

		i.GetFileType(false)
		fileinfos = append(fileinfos, i)
	}

	i.Listing = &Listing{
		Items:    fileinfos,
		NumDirs:  dirCount,
		NumFiles: fileCount,
	}

	return nil
}

// GetEditor gets the editor based on a Info struct
func (i *File) GetEditor() error {
	i.Language = editorLanguage(i.Extension)
	// If the editor will hold only content, leave now.
	if editorMode(i.Language) == "content" {
		return nil
	}

	// If the file doesn't have any kind of metadata, leave now.
	if !hasRune(i.Content) {
		return nil
	}

	buffer := bytes.NewBuffer([]byte(i.Content))
	page, err := parser.ReadFrom(buffer)

	// If there is an error, just ignore it and return nil.
	// This way, the file can be served for editing.
	if err != nil {

		return nil
	}

	i.Content = strings.TrimSpace(string(page.Content()))
	i.Metadata = strings.TrimSpace(string(page.FrontMatter()))
	return nil
}

// GetFileType obtains the mimetype and converts it to a simple
// type nomenclature.
func (i *File) GetFileType(checkContent bool) error {
	var content []byte
	var err error

	// Tries to get the file mimetype using its extension.
	mimetype := mime.TypeByExtension(i.Extension)

	if mimetype == "" && checkContent {
		file, err := os.Open(i.Path)
		if err != nil {
			return err
		}
		defer file.Close()

		// Only the first 512 bytes are used to sniff the content type.
		buffer := make([]byte, 512)
		_, err = file.Read(buffer)
		if err != nil && err != io.EOF {
			return err
		}

		// Tries to get the file mimetype using its first
		// 512 bytes.
		mimetype = http.DetectContentType(buffer)
	}

	if strings.HasPrefix(mimetype, "video") {
		i.Type = "video"
		return nil
	}

	if strings.HasPrefix(mimetype, "audio") {
		i.Type = "audio"
		return nil
	}

	if strings.HasPrefix(mimetype, "image") {
		i.Type = "image"
		return nil
	}

	if strings.HasPrefix(mimetype, "text") {
		i.Type = "text"
		goto End
	}

	if strings.HasPrefix(mimetype, "application/javascript") {
		i.Type = "text"
		goto End
	}

	// If the type isn't text (and is blob for example), it will check some
	// common types that are mistaken not to be text.
	for _, extension := range textExtensions {
		if strings.HasSuffix(i.Name, extension) {
			i.Type = "text"
			goto End
		}
	}

	i.Type = "blob"

End:
	// If the file type is text, save its content.
	if i.Type == "text" {
		if len(content) == 0 {
			content, err = ioutil.ReadFile(i.Path)
			if err != nil {
				return err
			}
		}

		i.Content = string(content)
	}

	return nil
}

// Checksum retrieves the checksum of a file.
func (i File) Checksum(algo string) (string, error) {
	file, err := os.Open(i.Path)
	if err != nil {
		return "", err
	}

	defer file.Close()

	var h hash.Hash

	switch algo {
	case "md5":
		h = md5.New()
	case "sha1":
		h = sha1.New()
	case "sha256":
		h = sha256.New()
	case "sha512":
		h = sha512.New()
	default:
		return "", ErrInvalidOption
	}

	_, err = io.Copy(h, file)
	if err != nil {
		return "", err
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}

// CanBeEdited checks if the extension of a file is supported by the editor
func (i File) CanBeEdited() bool {
	return i.Type == "text"
}

// ApplySort applies the sort order using .Order and .Sort
func (l Listing) ApplySort() {
	// Check '.Order' to know how to sort
	if l.Order == "desc" {
		switch l.Sort {
		case "name":
			sort.Sort(sort.Reverse(byName(l)))
		case "size":
			sort.Sort(sort.Reverse(bySize(l)))
		case "modified":
			sort.Sort(sort.Reverse(byModified(l)))
		default:
			// If not one of the above, do nothing
			return
		}
	} else { // If we had more Orderings we could add them here
		switch l.Sort {
		case "name":
			sort.Sort(byName(l))
		case "size":
			sort.Sort(bySize(l))
		case "modified":
			sort.Sort(byModified(l))
		default:
			sort.Sort(byName(l))
			return
		}
	}
}

// Implement sorting for Listing
type byName Listing
type bySize Listing
type byModified Listing

// By Name
func (l byName) Len() int {
	return len(l.Items)
}

func (l byName) Swap(i, j int) {
	l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
}

// Treat upper and lower case equally
func (l byName) Less(i, j int) bool {
	if l.Items[i].IsDir && !l.Items[j].IsDir {
		return true
	}

	if !l.Items[i].IsDir && l.Items[j].IsDir {
		return false
	}

	return strings.ToLower(l.Items[i].Name) < strings.ToLower(l.Items[j].Name)
}

// By Size
func (l bySize) Len() int {
	return len(l.Items)
}

func (l bySize) Swap(i, j int) {
	l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
}

const directoryOffset = -1 << 31 // = math.MinInt32
func (l bySize) Less(i, j int) bool {
	iSize, jSize := l.Items[i].Size, l.Items[j].Size
	if l.Items[i].IsDir {
		iSize = directoryOffset + iSize
	}
	if l.Items[j].IsDir {
		jSize = directoryOffset + jSize
	}
	return iSize < jSize
}

// By Modified
func (l byModified) Len() int {
	return len(l.Items)
}

func (l byModified) Swap(i, j int) {
	l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
}

func (l byModified) Less(i, j int) bool {
	iModified, jModified := l.Items[i].ModTime, l.Items[j].ModTime
	return iModified.Sub(jModified) < 0
}

var textExtensions = [...]string{
	".md", ".markdown", ".mdown", ".mmark",
	".asciidoc", ".adoc", ".ad",
	".rst",
	".tml", ".yml",
	".json", ".toml", ".yaml", ".csv", ".xml", ".rss", ".conf", ".ini",
	".tex", ".sty",
	".css", ".sass", ".scss",
	".js",
	".html",
	".txt", ".rtf",
	".sh", ".bash", ".ps1", ".bat", ".cmd",
	".php", ".pl", ".py",
	"Caddyfile",
	".htaccess",
	".c", ".cc", ".h", ".hh", ".cpp", ".hpp", ".f90",
	".f", ".bas", ".d", ".ada", ".nim", ".cr", ".java", ".cs", ".vala", ".vapi",
}

// hasRune checks if the file has the frontmatter rune
func hasRune(file string) bool {
	return strings.HasPrefix(file, "---") ||
		strings.HasPrefix(file, "+++") ||
		strings.HasPrefix(file, "{")
}

func editorMode(language string) string {
	switch language {
	case "markdown", "asciidoc", "rst":
		return "content+metadata"
	}

	return "content"
}

func editorLanguage(mode string) string {
	mode = strings.TrimPrefix(mode, ".")

	switch mode {
	case "md", "markdown", "mdown", "mmark":
		mode = "markdown"
	case "yml":
		mode = "yaml"
	case "asciidoc", "adoc", "ad":
		mode = "asciidoc"
	case "rst":
		mode = "rst"
	case "html", "htm", "xml":
		mode = "htmlmixed"
	case "js":
		mode = "javascript"
	case "go":
		mode = "golang"
	case "":
		mode = "text"
	}

	return mode
}
<|endoftext|>