<commit_before>package tlc

import (
	"archive/zip"
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/go-errors/errors"
	"github.com/itchio/wharf/sync"
)

// ContainerZipPool implements the sync.ZipPool interface based on a Container
type ContainerZipPool struct {
	container *Container
	fmap      map[string]*zip.File

	fileIndex int64
	reader    io.ReadCloser

	seekFileIndex int64
	readSeeker    ReadCloseSeeker
}

var _ sync.FilePool = (*ContainerZipPool)(nil)

// NewZipPool creates a new ContainerZipPool from the given Container
// metadata and a base path on-disk to allow reading from files.
func (c *Container) NewZipPool(zipReader *zip.Reader) *ContainerZipPool {
	fmap := make(map[string]*zip.File)
	for _, f := range zipReader.File {
		info := f.FileInfo()

		if info.IsDir() {
			// muffin
		} else if (info.Mode() & os.ModeSymlink) > 0 {
			// muffin ether
		} else {
			key := filepath.Clean(filepath.ToSlash(f.Name))
			fmap[key] = f
		}
	}

	return &ContainerZipPool{
		container: c,
		fmap:      fmap,

		fileIndex: int64(-1),
		reader:    nil,

		seekFileIndex: int64(-1),
		readSeeker:    nil,
	}
}

// GetSize returns the size of the file at index fileIndex
func (cfp *ContainerZipPool) GetSize(fileIndex int64) int64 {
	return cfp.container.Files[fileIndex].Size
}

// GetRelativePath returns the slashed path of a file, relative to
// the container's root.
func (cfp *ContainerZipPool) GetRelativePath(fileIndex int64) string {
	return cfp.container.Files[fileIndex].Path
}

// GetPath returns the native path of a file (with slashes or backslashes)
// on-disk, based on the ContainerZipPool's base path
func (cfp *ContainerZipPool) GetPath(fileIndex int64) string {
	panic("ContainerZipPool does not support GetPath")
}

// GetReader returns an io.Reader for the file at index fileIndex
// Successive calls to `GetReader` will attempt to re-use the last
// returned reader if the file index is similar. The cache size is 1, so
// reading in parallel from different files is not supported.
func (cfp *ContainerZipPool) GetReader(fileIndex int64) (io.Reader, error) {
	if cfp.fileIndex != fileIndex {
		if cfp.reader != nil {
			err := cfp.reader.Close()
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			cfp.reader = nil
			cfp.fileIndex = -1
		}

		f := cfp.fmap[cfp.GetRelativePath(fileIndex)]
		if f == nil {
			return nil, errors.Wrap(os.ErrNotExist, 1)
		}

		reader, err := f.Open()

		if err != nil {
			return nil, errors.Wrap(err, 1)
		}
		cfp.reader = reader
		cfp.fileIndex = fileIndex
	}

	return cfp.reader, nil
}

// GetReadSeeker is like GetReader but the returned object allows seeking
func (cfp *ContainerZipPool) GetReadSeeker(fileIndex int64) (io.ReadSeeker, error) {
	if cfp.seekFileIndex != fileIndex {
		if cfp.readSeeker != nil {
			err := cfp.readSeeker.Close()
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			cfp.readSeeker = nil
			cfp.seekFileIndex = -1
		}

		key := cfp.GetRelativePath(fileIndex)
		f := cfp.fmap[key]
		if f == nil {
			return nil, errors.Wrap(os.ErrNotExist, 1)
		}

		reader, err := f.Open()
		if err != nil {
			return nil, errors.Wrap(err, 1)
		}
		defer reader.Close()

		buf, err := ioutil.ReadAll(reader)
		if err != nil {
			return nil, errors.Wrap(err, 1)
		}

		cfp.readSeeker = &closableBuf{bytes.NewReader(buf)}
		cfp.seekFileIndex = fileIndex
	}

	return cfp.readSeeker, nil
}

// Close closes all reader belonging to this ContainerZipPool
func (cfp *ContainerZipPool) Close() error {
	if cfp.reader != nil {
		err := cfp.reader.Close()
		if err != nil {
			return errors.Wrap(err, 1)
		}

		cfp.reader = nil
		cfp.fileIndex = -1
	}

	if cfp.readSeeker != nil {
		err := cfp.readSeeker.Close()
		if err != nil {
			return errors.Wrap(err, 1)
		}

		cfp.readSeeker = nil
		cfp.seekFileIndex = -1
	}

	return nil
}

type closableBuf struct {
	rs io.ReadSeeker
}

var _ ReadCloseSeeker = (*closableBuf)(nil)

func (cb *closableBuf) Read(buf []byte) (int, error) {
	return cb.rs.Read(buf)
}

func (cb *closableBuf) Seek(offset int64, whence int) (int64, error) {
	return cb.rs.Seek(offset, whence)
}

func (cb *closableBuf) Close() error {
	return nil
}
<commit_msg>Change zip path normalization strategy on win32. Closes https://github.com/itchio/butler/issues/62<commit_after>package tlc

import (
	"archive/zip"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/go-errors/errors"
	"github.com/itchio/wharf/sync"
)

// ContainerZipPool implements the sync.ZipPool interface based on a Container
type ContainerZipPool struct {
	container *Container
	fmap      map[string]*zip.File

	fileIndex int64
	reader    io.ReadCloser

	seekFileIndex int64
	readSeeker    ReadCloseSeeker
}

var _ sync.FilePool = (*ContainerZipPool)(nil)

// NewZipPool creates a new ContainerZipPool from the given Container
// metadata and a base path on-disk to allow reading from files.
func (c *Container) NewZipPool(zipReader *zip.Reader) *ContainerZipPool {
	fmap := make(map[string]*zip.File)
	for _, f := range zipReader.File {
		info := f.FileInfo()

		if info.IsDir() {
			// muffin
		} else if (info.Mode() & os.ModeSymlink) > 0 {
			// muffin ether
		} else {
			key := filepath.ToSlash(filepath.Clean(f.Name))
			fmap[key] = f
		}
	}

	return &ContainerZipPool{
		container: c,
		fmap:      fmap,

		fileIndex: int64(-1),
		reader:    nil,

		seekFileIndex: int64(-1),
		readSeeker:    nil,
	}
}

// GetSize returns the size of the file at index fileIndex
func (cfp *ContainerZipPool) GetSize(fileIndex int64) int64 {
	return cfp.container.Files[fileIndex].Size
}

// GetRelativePath returns the slashed path of a file, relative to
// the container's root.
func (cfp *ContainerZipPool) GetRelativePath(fileIndex int64) string {
	return cfp.container.Files[fileIndex].Path
}

// GetPath returns the native path of a file (with slashes or backslashes)
// on-disk, based on the ContainerZipPool's base path
func (cfp *ContainerZipPool) GetPath(fileIndex int64) string {
	panic("ContainerZipPool does not support GetPath")
}

// GetReader returns an io.Reader for the file at index fileIndex
// Successive calls to `GetReader` will attempt to re-use the last
// returned reader if the file index is similar. The cache size is 1, so
// reading in parallel from different files is not supported.
func (cfp *ContainerZipPool) GetReader(fileIndex int64) (io.Reader, error) {
	if cfp.fileIndex != fileIndex {
		if cfp.reader != nil {
			err := cfp.reader.Close()
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			cfp.reader = nil
			cfp.fileIndex = -1
		}

		relPath := cfp.GetRelativePath(fileIndex)
		f := cfp.fmap[relPath]
		if f == nil {
			if os.Getenv("VERBOSE_ZIP_POOL") != "" {
				fmt.Printf("\nzip contents:\n")
				for k := range cfp.fmap {
					fmt.Printf("\n- %s", k)
				}
				fmt.Println()
			}
			return nil, errors.WrapPrefix(os.ErrNotExist, relPath, 1)
		}

		reader, err := f.Open()

		if err != nil {
			return nil, errors.Wrap(err, 1)
		}
		cfp.reader = reader
		cfp.fileIndex = fileIndex
	}

	return cfp.reader, nil
}

// GetReadSeeker is like GetReader but the returned object allows seeking
func (cfp *ContainerZipPool) GetReadSeeker(fileIndex int64) (io.ReadSeeker, error) {
	if cfp.seekFileIndex != fileIndex {
		if cfp.readSeeker != nil {
			err := cfp.readSeeker.Close()
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			cfp.readSeeker = nil
			cfp.seekFileIndex = -1
		}

		key := cfp.GetRelativePath(fileIndex)
		f := cfp.fmap[key]
		if f == nil {
			return nil, errors.Wrap(os.ErrNotExist, 1)
		}

		reader, err := f.Open()
		if err != nil {
			return nil, errors.Wrap(err, 1)
		}
		defer reader.Close()

		buf, err := ioutil.ReadAll(reader)
		if err != nil {
			return nil, errors.Wrap(err, 1)
		}

		cfp.readSeeker = &closableBuf{bytes.NewReader(buf)}
		cfp.seekFileIndex = fileIndex
	}

	return cfp.readSeeker, nil
}

// Close closes all reader belonging to this ContainerZipPool
func (cfp *ContainerZipPool) Close() error {
	if cfp.reader != nil {
		err := cfp.reader.Close()
		if err != nil {
			return errors.Wrap(err, 1)
		}

		cfp.reader = nil
		cfp.fileIndex = -1
	}

	if cfp.readSeeker != nil {
		err := cfp.readSeeker.Close()
		if err != nil {
			return errors.Wrap(err, 1)
		}

		cfp.readSeeker = nil
		cfp.seekFileIndex = -1
	}

	return nil
}

type closableBuf struct {
	rs io.ReadSeeker
}

var _ ReadCloseSeeker = (*closableBuf)(nil)

func (cb *closableBuf) Read(buf []byte) (int, error) {
	return cb.rs.Read(buf)
}

func (cb *closableBuf) Seek(offset int64, whence int) (int64, error) {
	return cb.rs.Seek(offset, whence)
}

func (cb *closableBuf) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"sync/atomic"
	"unsafe"

	r "github.com/dancannon/gorethink"
	"github.com/jaracil/ei"
)

func (nc *NexusConn) handleSysReq(req *JsonRpcReq) {
	switch req.Method {
	case "sys.ping":
		req.Result("pong")
	case "sys.watchdog":
		wdt := ei.N(req.Params).Int64Z()
		if wdt < 10 {
			wdt = 10
		}
		atomic.StoreInt64(&nc.wdog, wdt)
		req.Result(ei.M{"ok": true, "watchdog": wdt})
	case "sys.login":
		user, err := ei.N(req.Params).M("user").String()
		if err != nil {
			req.Error(ErrInvalidParams, "user", nil)
			return
		}
		pass, err := ei.N(req.Params).M("pass").String()
		if err != nil {
			req.Error(ErrInvalidParams, "pass", nil)
			return
		}
		var suser string
		split := strings.Split(user, ">")
		switch len(split) {
		case 1:
		case 2:
			if len(split[0]) > 0 && len(split[1]) > 0 {
				user = split[0]
				suser = split[1]
			} else {
				req.Error(ErrInvalidParams, "", nil)
				return
			}
		default:
			req.Error(ErrInvalidParams, "", nil)
			return
		}
		ud := &UserData{}
		cur, err := r.Table("users").Get(strings.ToLower(user)).Run(db)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		defer cur.Close()
		err = cur.One(ud)
		if err != nil {
			if err == r.ErrEmptyResult {
				req.Error(ErrPermissionDenied, "", nil)
				return
			}
			req.Error(ErrInternal, "", nil)
			return
		}
		dk, err := HashPass(pass, ud.Salt)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		if ud.Pass != dk {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}
		atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&nc.user)), unsafe.Pointer(ud))

		if suser != "" {
			tags := nc.getTags(suser)
			if !(ei.N(tags).M("@admin").BoolZ()) {
				req.Error(ErrPermissionDenied, "", nil)
				return
			}
			sud := &UserData{}
			scur, err := r.Table("users").Get(strings.ToLower(suser)).Run(db)
			if err != nil {
				req.Error(ErrInternal, "", nil)
				return
			}
			defer scur.Close()
			err = scur.One(sud)
			if err != nil {
				if err == r.ErrEmptyResult {
					req.Error(ErrPermissionDenied, "", nil)
					return
				}
				req.Error(ErrInternal, "", nil)
				return
			}
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&nc.user)), unsafe.Pointer(sud))
		}
		nc.updateSession()
		req.Result(ei.M{"ok": true, "user": nc.user.User})
	case "sys.nodes":
		tags := nc.getTags("")
		if !(ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		cur, err := r.Table("nodes").Pluck("id", "clients", "load").Run(db)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		var all []interface{}
		cur.All(&all)
		req.Result(all)
	case "sys.sessions":
		prefix := ei.N(req.Params).M("prefix").StringZ()

		tags := nc.getTags(prefix)
		if !(ei.N(tags).M("@session.list").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}
		cur, err := r.Table("sessions").
			Between(prefix, prefix+"\uffff", r.BetweenOpts{Index: "users"}).
			Group("user").
			Pluck("id", "nodeId", "remoteAddress", "creationTime", "protocol").
			Ungroup().
			Map(func(row r.Term) interface{} {
				return ei.M{"user": row.Field("group"), "sessions": row.Field("reduction"), "n": row.Field("reduction").Count()}
			}).Run(db)
		if err != nil {
			req.Error(ErrInternal, err.Error(), nil)
			return
		}
		var all []interface{}
		cur.All(&all)
		req.Result(all)

	default:
		req.Error(ErrMethodNotFound, "", nil)
	}
}
<commit_msg>Change sys.nodes and sys.sessions permissions<commit_after>package main

import (
	"strings"
	"sync/atomic"
	"unsafe"

	r "github.com/dancannon/gorethink"
	"github.com/jaracil/ei"
)

func (nc *NexusConn) handleSysReq(req *JsonRpcReq) {
	switch req.Method {
	case "sys.ping":
		req.Result("pong")
	case "sys.watchdog":
		wdt := ei.N(req.Params).Int64Z()
		if wdt < 10 {
			wdt = 10
		}
		atomic.StoreInt64(&nc.wdog, wdt)
		req.Result(ei.M{"ok": true, "watchdog": wdt})
	case "sys.login":
		user, err := ei.N(req.Params).M("user").String()
		if err != nil {
			req.Error(ErrInvalidParams, "user", nil)
			return
		}
		pass, err := ei.N(req.Params).M("pass").String()
		if err != nil {
			req.Error(ErrInvalidParams, "pass", nil)
			return
		}
		var suser string
		split := strings.Split(user, ">")
		switch len(split) {
		case 1:
		case 2:
			if len(split[0]) > 0 && len(split[1]) > 0 {
				user = split[0]
				suser = split[1]
			} else {
				req.Error(ErrInvalidParams, "", nil)
				return
			}
		default:
			req.Error(ErrInvalidParams, "", nil)
			return
		}
		ud := &UserData{}
		cur, err := r.Table("users").Get(strings.ToLower(user)).Run(db)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		defer cur.Close()
		err = cur.One(ud)
		if err != nil {
			if err == r.ErrEmptyResult {
				req.Error(ErrPermissionDenied, "", nil)
				return
			}
			req.Error(ErrInternal, "", nil)
			return
		}
		dk, err := HashPass(pass, ud.Salt)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		if ud.Pass != dk {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}
		atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&nc.user)), unsafe.Pointer(ud))

		if suser != "" {
			tags := nc.getTags(suser)
			if !(ei.N(tags).M("@admin").BoolZ()) {
				req.Error(ErrPermissionDenied, "", nil)
				return
			}
			sud := &UserData{}
			scur, err := r.Table("users").Get(strings.ToLower(suser)).Run(db)
			if err != nil {
				req.Error(ErrInternal, "", nil)
				return
			}
			defer scur.Close()
			err = scur.One(sud)
			if err != nil {
				if err == r.ErrEmptyResult {
					req.Error(ErrPermissionDenied, "", nil)
					return
				}
				req.Error(ErrInternal, "", nil)
				return
			}
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&nc.user)), unsafe.Pointer(sud))
		}
		nc.updateSession()
		req.Result(ei.M{"ok": true, "user": nc.user.User})
	case "sys.nodes":
		tags := nc.getTags("sys.nodes")
		if !(ei.N(tags).M("@sys.nodes").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}
		cur, err := r.Table("nodes").Pluck("id", "clients", "load").Run(db)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		var all []interface{}
		cur.All(&all)
		req.Result(all)
	case "sys.sessions":
		prefix := ei.N(req.Params).M("prefix").StringZ()

		tags := nc.getTags(prefix)
		if !(ei.N(tags).M("@sys.sessions").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}
		cur, err := r.Table("sessions").
			Between(prefix, prefix+"\uffff", r.BetweenOpts{Index: "users"}).
			Group("user").
			Pluck("id", "nodeId", "remoteAddress", "creationTime", "protocol").
			Ungroup().
			Map(func(row r.Term) interface{} {
				return ei.M{"user": row.Field("group"), "sessions": row.Field("reduction"), "n": row.Field("reduction").Count()}
			}).Run(db)
		if err != nil {
			req.Error(ErrInternal, err.Error(), nil)
			return
		}
		var all []interface{}
		cur.All(&all)
		req.Result(all)

	default:
		req.Error(ErrMethodNotFound, "", nil)
	}
}
<|endoftext|>


<commit_before>package glutton

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"strconv"

	"github.com/kung-foo/freki"
	"go.uber.org/zap"
)

func storePayload(data []byte, handler string, g *Glutton) error {
	sum := sha256.Sum256(data)
	if err := os.MkdirAll("payloads", os.ModePerm); err != nil {
		return err
	}
	sha256Hash := hex.EncodeToString(sum[:])
	path := filepath.Join("payloads", sha256Hash)
	if _, err := os.Stat(path); err == nil {
		return nil
	}
	out, err := os.Create(path)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = out.Write(data)
	if err != nil {
		return err
	}
	g.logger.Info(
		fmt.Sprintf("new payload stored from %s", handler),
		zap.String("handler", handler),
		zap.String("sha256", sha256Hash),
	)
	return nil
}

// HandleTCP takes a net.Conn and peeks at the data send
func (g *Glutton) HandleTCP(ctx context.Context, conn net.Conn) (err error) {
	defer func() {
		err = conn.Close()
		if err != nil {
			g.logger.Error(fmt.Sprintf("[log.tcp ] error: %v", err))
		}
	}()
	host, port, err := net.SplitHostPort(conn.RemoteAddr().String())
	if err != nil {
		g.logger.Error(fmt.Sprintf("[log.tcp ] error: %v", err))
	}
	ck := freki.NewConnKeyByString(host, port)
	md := g.processor.Connections.GetByFlow(ck)
	buffer := make([]byte, 1024)
	n, err := conn.Read(buffer)
	if err != nil {
		g.logger.Error(fmt.Sprintf("[log.tcp ] error: %v", err))
	}
	if n > 0 && n < 1024 {
		g.logger.Info(
			fmt.Sprintf("Packet got handled by TCP handler"),
			zap.String("dest_port", strconv.Itoa(int(md.TargetPort))),
			zap.String("src_ip", host),
			zap.String("src_port", port),
			zap.String("handler", "tcp"),
			zap.String("payload_hex", hex.EncodeToString(buffer[0:n])),
		)
	}
	return storePayload(buffer, "tcp", g)
}
<commit_msg>adding the payload hash to the tcp log message<commit_after>package glutton

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"strconv"

	"github.com/kung-foo/freki"
	"go.uber.org/zap"
)

func storePayload(data []byte, g *Glutton) (string, error) {
	sum := sha256.Sum256(data)
	if err := os.MkdirAll("payloads", os.ModePerm); err != nil {
		return "", err
	}
	sha256Hash := hex.EncodeToString(sum[:])
	path := filepath.Join("payloads", sha256Hash)
	if _, err := os.Stat(path); err == nil {
		return "", nil
	}
	out, err := os.Create(path)
	if err != nil {
		return "", err
	}
	defer out.Close()
	_, err = out.Write(data)
	if err != nil {
		return "", err
	}
	return sha256Hash, nil
}

// HandleTCP takes a net.Conn and peeks at the data send
func (g *Glutton) HandleTCP(ctx context.Context, conn net.Conn) (err error) {
	defer func() {
		err = conn.Close()
		if err != nil {
			g.logger.Error(fmt.Sprintf("[log.tcp ] error: %v", err))
		}
	}()
	host, port, err := net.SplitHostPort(conn.RemoteAddr().String())
	if err != nil {
		g.logger.Error(fmt.Sprintf("[log.tcp ] error: %v", err))
	}
	ck := freki.NewConnKeyByString(host, port)
	md := g.processor.Connections.GetByFlow(ck)
	buffer := make([]byte, 1024)
	n, err := conn.Read(buffer)
	if err != nil {
		g.logger.Error(fmt.Sprintf("[log.tcp ] error: %v", err))
	}

	payloadHash, err := storePayload(buffer, g)

	if n > 0 && n < 1024 {
		g.logger.Info(
			fmt.Sprintf("Packet got handled by TCP handler"),
			zap.String("dest_port", strconv.Itoa(int(md.TargetPort))),
			zap.String("src_ip", host),
			zap.String("src_port", port),
			zap.String("handler", "tcp"),
			zap.String("payload_hex", hex.EncodeToString(buffer[0:n])),
			zap.String("payload_hash", payloadHash),
		)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
)

// Intercept TLS (HTTPS) connections.

var certFile = flag.String("tls-cert", "", "path to certificate for serving HTTPS")
var keyFile = flag.String("tls-key", "", "path to TLS certificate key")

var tlsCert tls.Certificate
var parsedTLSCert *x509.Certificate
var tlsReady bool

// unverifiedClientConfig is a TLS configuration that doesn't verify server
// certificates.
var unverifiedClientConfig = &tls.Config{
	InsecureSkipVerify: true,
}

// unverifiedTransport is an http.Transport that doesn't verify server
// certificates.
var unverifiedTransport = http.Transport{
	TLSClientConfig: unverifiedClientConfig,
	Proxy:           http.ProxyFromEnvironment,
}

// loadCertificate loads the TLS certificate specified by certFile and keyFile
// into tlsCert.
func loadCertificate() {
	if *certFile != "" && *keyFile != "" {
		cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)
		if err != nil {
			log.Println("Error loading TLS certificate:", err)
			return
		}
		tlsCert = cert
		parsed, err := x509.ParseCertificate(cert.Certificate[0])
		if err != nil {
			log.Println("Error parsing X509 certificate:", err)
			return
		}
		parsedTLSCert = parsed
		tlsReady = true

		go cacheCertificates()
	}
}

// SSLBump performs a man-in-the-middle attack on conn, to filter the HTTPS
// traffic. serverAddr is the address (host:port) of the server the client was
// trying to connect to.
func SSLBump(conn net.Conn, serverAddr string) {
	cert, err := getCertificate(serverAddr)
	if err != nil {
		panic(fmt.Errorf("could not generate TLS certificate for %s: %s", serverAddr, err))
	}

	config := &tls.Config{
		NextProtos:   []string{"http/1.1"},
		Certificates: []tls.Certificate{cert, tlsCert},
	}
	_, port, err := net.SplitHostPort(serverAddr)
	if err != nil {
		port = ""
	}
	listener := &singleListener{conn: conn}
	tlsListener := tls.NewListener(listener, config)
	server := http.Server{
		Handler: proxyHandler{
			TLS:         true,
			connectPort: port,
		},
	}
	server.Serve(tlsListener)
}

// A singleListener is a net.Listener that returns a single connection, then
// gives the error io.EOF.
type singleListener struct {
	conn net.Conn
	once sync.Once
}

func (s *singleListener) Accept() (net.Conn, error) {
	var c net.Conn
	s.once.Do(func() {
		c = s.conn
	})
	if c != nil {
		return c, nil
	}
	return nil, io.EOF
}

func (s *singleListener) Close() error {
	s.once.Do(func() {
		s.conn.Close()
	})
	return nil
}

func (s *singleListener) Addr() net.Addr {
	return s.conn.LocalAddr()
}

// generateCertificate connects to the server at addr, gets its TLS
// certificate, and returns a new certificate to be used when proxying
// connections to that server.
func generateCertificate(addr string) (tls.Certificate, error) {
	conn, err := tls.Dial("tcp", addr, unverifiedClientConfig)
	if err != nil {
		return tls.Certificate{}, err
	}
	defer conn.Close()
	state := conn.ConnectionState()
	serverCert := state.PeerCertificates[0]

	priv, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		return tls.Certificate{}, fmt.Errorf("failed to generate private key: %s", err)
	}

	newCertBytes, err := x509.CreateCertificate(rand.Reader, serverCert, parsedTLSCert, &priv.PublicKey, tlsCert.PrivateKey)
	if err != nil {
		return tls.Certificate{}, err
	}

	certBuf := new(bytes.Buffer)
	pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: newCertBytes})
	keyBuf := new(bytes.Buffer)
	pem.Encode(keyBuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	return tls.X509KeyPair(certBuf.Bytes(), keyBuf.Bytes())
}
<commit_msg>Disable KeepAlives<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
)

// Intercept TLS (HTTPS) connections.

var certFile = flag.String("tls-cert", "", "path to certificate for serving HTTPS")
var keyFile = flag.String("tls-key", "", "path to TLS certificate key")

var tlsCert tls.Certificate
var parsedTLSCert *x509.Certificate
var tlsReady bool

// unverifiedClientConfig is a TLS configuration that doesn't verify server
// certificates.
var unverifiedClientConfig = &tls.Config{
	InsecureSkipVerify: true,
}

// unverifiedTransport is an http.Transport that doesn't verify server
// certificates.
var unverifiedTransport = http.Transport{
	TLSClientConfig:   unverifiedClientConfig,
	Proxy:             http.ProxyFromEnvironment,
	DisableKeepAlives: true,
}

// loadCertificate loads the TLS certificate specified by certFile and keyFile
// into tlsCert.
func loadCertificate() {
	if *certFile != "" && *keyFile != "" {
		cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)
		if err != nil {
			log.Println("Error loading TLS certificate:", err)
			return
		}
		tlsCert = cert
		parsed, err := x509.ParseCertificate(cert.Certificate[0])
		if err != nil {
			log.Println("Error parsing X509 certificate:", err)
			return
		}
		parsedTLSCert = parsed
		tlsReady = true

		go cacheCertificates()
	}
}

// SSLBump performs a man-in-the-middle attack on conn, to filter the HTTPS
// traffic. serverAddr is the address (host:port) of the server the client was
// trying to connect to.
func SSLBump(conn net.Conn, serverAddr string) {
	cert, err := getCertificate(serverAddr)
	if err != nil {
		panic(fmt.Errorf("could not generate TLS certificate for %s: %s", serverAddr, err))
	}

	config := &tls.Config{
		NextProtos:   []string{"http/1.1"},
		Certificates: []tls.Certificate{cert, tlsCert},
	}
	_, port, err := net.SplitHostPort(serverAddr)
	if err != nil {
		port = ""
	}
	listener := &singleListener{conn: conn}
	tlsListener := tls.NewListener(listener, config)
	server := http.Server{
		Handler: proxyHandler{
			TLS:         true,
			connectPort: port,
		},
	}
	server.Serve(tlsListener)
}

// A singleListener is a net.Listener that returns a single connection, then
// gives the error io.EOF.
type singleListener struct {
	conn net.Conn
	once sync.Once
}

func (s *singleListener) Accept() (net.Conn, error) {
	var c net.Conn
	s.once.Do(func() {
		c = s.conn
	})
	if c != nil {
		return c, nil
	}
	return nil, io.EOF
}

func (s *singleListener) Close() error {
	s.once.Do(func() {
		s.conn.Close()
	})
	return nil
}

func (s *singleListener) Addr() net.Addr {
	return s.conn.LocalAddr()
}

// generateCertificate connects to the server at addr, gets its TLS
// certificate, and returns a new certificate to be used when proxying
// connections to that server.
func generateCertificate(addr string) (tls.Certificate, error) {
	conn, err := tls.Dial("tcp", addr, unverifiedClientConfig)
	if err != nil {
		return tls.Certificate{}, err
	}
	defer conn.Close()
	state := conn.ConnectionState()
	serverCert := state.PeerCertificates[0]

	priv, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		return tls.Certificate{}, fmt.Errorf("failed to generate private key: %s", err)
	}

	newCertBytes, err := x509.CreateCertificate(rand.Reader, serverCert, parsedTLSCert, &priv.PublicKey, tlsCert.PrivateKey)
	if err != nil {
		return tls.Certificate{}, err
	}

	certBuf := new(bytes.Buffer)
	pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: newCertBytes})
	keyBuf := new(bytes.Buffer)
	pem.Encode(keyBuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	return tls.X509KeyPair(certBuf.Bytes(), keyBuf.Bytes())
}
<|endoftext|>


<commit_before>/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides an API for compiling and manipulating BPF filters. A filter can be
// either compiled from tcpdump-like expressions, or created from basic BPF
// instructions. Filters can then be either applied to packet sources (see the
// capture package) or directly run against binary data.
package filter

// #include <stdlib.h>
// #include "bpf_filter.h"
import "C"

import "fmt"
import "strings"
import "syscall"
import "unsafe"

type Filter struct {
	program C.struct_bpf_program
}

type Code uint16

const (
	LD Code = syscall.BPF_LD
	LDX     = syscall.BPF_LDX
	ST      = syscall.BPF_ST
	STX     = syscall.BPF_STX
	ALU     = syscall.BPF_ALU
	JMP     = syscall.BPF_JMP
	RET     = syscall.BPF_RET
	MISC    = syscall.BPF_MISC
)

type Size uint16

const (
	Word Size = syscall.BPF_W
	Half      = syscall.BPF_H
	Byte      = syscall.BPF_B
)

type Mode uint16

const (
	IMM Mode = syscall.BPF_IMM
	ABS      = syscall.BPF_ABS
	IND      = syscall.BPF_IND
	MEM      = syscall.BPF_MEM
	LEN      = syscall.BPF_LEN
	MSH      = syscall.BPF_MSH
)

type Src uint16

const (
	Const Src = syscall.BPF_K
	Index     = syscall.BPF_X
	Acc       = syscall.BPF_A
)

// Try to match the given buffer against the filter.
func (f *Filter) Match(buf []byte) bool {
	cbuf := (*C.char)(unsafe.Pointer(&buf[0]))
	blen := C.uint(len(buf))

	if C.bpf_filter(f.program.bf_insns, cbuf, blen, blen) > 0 {
		return true
	}

	return false
}

// Validate the filter. The constraints are that each jump be forward and to a
// valid code. The code must terminate with either an accept or reject.
func (f *Filter) Validate() bool {
	if C.bpf_validate(f.program.bf_insns, C.int(f.program.bf_len)) > 0 {
		return true
	}

	return false
}

// Deallocate the filter.
func (f *Filter) Cleanup() {
	f.program.bf_len = 0

	if f.program.bf_insns != nil {
		C.free(unsafe.Pointer(f.program.bf_insns))
		f.program.bf_insns = nil
	}
}

// Return the number of instructions in the filter.
func (f *Filter) Len() int {
	prog := (*C.struct_bpf_program)(f.Program())
	flen := C.bpf_get_len(prog)
	return int(flen)
}

// Return the compiled BPF program.
func (f *Filter) Program() unsafe.Pointer {
	return unsafe.Pointer(&f.program)
}

func (f *Filter) String() string {
	var insns []string

	prog := (*C.struct_bpf_program)(f.Program())
	flen := C.bpf_get_len(prog)

	for i := C.int(0); i < flen; i++ {
		insn := C.bpf_get_insn(prog, i)

		str := fmt.Sprintf(
			"{ 0x%.2x, %3d, %3d, 0x%.8x },",
			insn.code, insn.jt, insn.jf, insn.k,
		)

		insns = append(insns, str)
	}

	return strings.Join(insns, "\n")
}

func (f *Filter) append_insn(code Code, jt, jf uint8, k uint32) {
	prog := (*C.struct_bpf_program)(f.Program())
	C.bpf_append_insn(
		prog, C.ushort(code), C.uchar(jt), C.uchar(jf), C.uint(k),
	)
}
<commit_msg>filter: add Filter() method<commit_after>/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides an API for compiling and manipulating BPF filters. A filter can be
// either compiled from tcpdump-like expressions, or created from basic BPF
// instructions. Filters can then be either applied to packet sources (see the
// capture package) or directly run against binary data.
package filter

// #include <stdlib.h>
// #include "bpf_filter.h"
import "C"

import "fmt"
import "strings"
import "syscall"
import "unsafe"

type Filter struct {
	program C.struct_bpf_program
}

type Code uint16

const (
	LD Code = syscall.BPF_LD
	LDX     = syscall.BPF_LDX
	ST      = syscall.BPF_ST
	STX     = syscall.BPF_STX
	ALU     = syscall.BPF_ALU
	JMP     = syscall.BPF_JMP
	RET     = syscall.BPF_RET
	MISC    = syscall.BPF_MISC
)

type Size uint16

const (
	Word Size = syscall.BPF_W
	Half      = syscall.BPF_H
	Byte      = syscall.BPF_B
)

type Mode uint16

const (
	IMM Mode = syscall.BPF_IMM
	ABS      = syscall.BPF_ABS
	IND      = syscall.BPF_IND
	MEM      = syscall.BPF_MEM
	LEN      = syscall.BPF_LEN
	MSH      = syscall.BPF_MSH
)

type Src uint16

const (
	Const Src = syscall.BPF_K
	Index     = syscall.BPF_X
	Acc       = syscall.BPF_A
)

// Try to match the given buffer against the filter.
func (f *Filter) Match(buf []byte) bool {
	cbuf := (*C.char)(unsafe.Pointer(&buf[0]))
	blen := C.uint(len(buf))

	if C.bpf_filter(f.program.bf_insns, cbuf, blen, blen) > 0 {
		return true
	}

	return false
}

// Run filter on the given buffer and return its result.
func (f *Filter) Filter(buf []byte) uint {
	cbuf := (*C.char)(unsafe.Pointer(&buf[0]))
	blen := C.uint(len(buf))

	rc := C.bpf_filter(f.program.bf_insns, cbuf, blen, blen)
	return uint(rc)
}

// Validate the filter. The constraints are that each jump be forward and to a
// valid code. The code must terminate with either an accept or reject.
func (f *Filter) Validate() bool {
	if C.bpf_validate(f.program.bf_insns, C.int(f.program.bf_len)) > 0 {
		return true
	}

	return false
}

// Deallocate the filter.
func (f *Filter) Cleanup() {
	f.program.bf_len = 0

	if f.program.bf_insns != nil {
		C.free(unsafe.Pointer(f.program.bf_insns))
		f.program.bf_insns = nil
	}
}

// Return the number of instructions in the filter.
func (f *Filter) Len() int {
	prog := (*C.struct_bpf_program)(f.Program())
	flen := C.bpf_get_len(prog)
	return int(flen)
}

// Return the compiled BPF program.
func (f *Filter) Program() unsafe.Pointer {
	return unsafe.Pointer(&f.program)
}

func (f *Filter) String() string {
	var insns []string

	prog := (*C.struct_bpf_program)(f.Program())
	flen := C.bpf_get_len(prog)

	for i := C.int(0); i < flen; i++ {
		insn := C.bpf_get_insn(prog, i)

		str := fmt.Sprintf(
			"{ 0x%.2x, %3d, %3d, 0x%.8x },",
			insn.code, insn.jt, insn.jf, insn.k,
		)

		insns = append(insns, str)
	}

	return strings.Join(insns, "\n")
}

func (f *Filter) append_insn(code Code, jt, jf uint8, k uint32) {
	prog := (*C.struct_bpf_program)(f.Program())
	C.bpf_append_insn(
		prog, C.ushort(code), C.uchar(jt), C.uchar(jf), C.uint(k),
	)
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 Go Fightclub Authors

package alsa

import (
  "fmt"
  "unsafe"
  "afp"
  "os"
)

// #include <alsa/asoundlib.h>
import "C"

/////
// Alsa Source
// Listens to a microphone
type AlsaSource struct {
    ctx *afp.Context
    header afp.StreamHeader
    capture *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t
}

func NewAlsaSource() afp.Filter {
    return &AlsaSource{}
}

func (self *AlsaSource) GetType() int {
    return afp.PIPE_SOURCE
}

func (self *AlsaSource) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSource) Start() {

    self.header = afp.StreamHeader {
        Version: 1,
        Channels: 1,
        SampleSize: 32,
        SampleRate: 44100,
        FrameSize: 4096,
    }

    self.ctx.HeaderSink <- self.header

    retval := self.prepare()
    if ( retval != nil) {
        panic(retval)
    }

    for {
		cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
		buff := make([][]float32, self.header.FrameSize)
        length := len(cbuf)

        //first off, grab some data from alsa
        read := C.snd_pcm_readi(self.capture, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
        if read < C.snd_pcm_sframes_t(length) {
            errno := C.snd_pcm_recover(self.capture, C.int(read), 0)
            if errno < 0 {
                panic(fmt.Sprint( "While reading from ALSA device, failed to recover from error: ", errno))
            }
        }

        // snd_pcm_readi gives us a one dimensional array of interleaved data
        // but what we want is a two dimensional array of samples
        chans := int(self.header.Channels)
		for slice, i := 0, 0; i < length; slice, i = slice + 1, i + chans {
			buff[slice] = make([]float32, chans)
			buff[slice] = cbuf[i : i + chans]
        }

        //send it on down the line
        self.ctx.Sink <- buff
    }

}

func (self *AlsaSource) Stop() os.Error {
    C.snd_pcm_close(self.capture)
    close(self.ctx.Sink)
    return nil
}

/////
// Alsa Sink
// Outputs to speakers via ALSA
type AlsaSink struct {
    ctx *afp.Context
    header afp.StreamHeader
    playback *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t

}

func NewAlsaSink() afp.Filter {
    return &AlsaSink{}
}

func (self *AlsaSink) GetType() int {
    return afp.PIPE_SINK
}

func (self *AlsaSink) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSink) Start() {
    self.header = <-self.ctx.HeaderSource

    retval := self.prepare()
    if (retval != nil) {
        panic(retval)
    }
    cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)

    for buffer := range self.ctx.Source { //reading a [][]float32
        length := int(self.header.FrameSize)
        chans := int(self.header.Channels)

	    streamOffset := 0
        //interleave the channels
        for i := 0; i < length; i ++ {
            for j := 0; j < chans; j++ {
                cbuf[streamOffset] = buffer[i][j]
		        streamOffset++
            }
        }

        //write some data to alsa
        error := C.snd_pcm_writei(self.playback, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))

        fmt.Print(".")

        //check our return
        if int(error) < 0 {
            //we are in an error state
            //panic(fmt.Sprintf("Could not write data to ALSA device, error: %d", error))
            if error == C.snd_pcm_sframes_t(0) - C.EBADFD {
                panic(fmt.Sprintf("Error initializing the ALSA device"))
            } else if error == C.snd_pcm_sframes_t(0) - C.ESTRPIPE {
                fmt.Printf("A suspend event has occurred")
            } else if error == C.snd_pcm_sframes_t(0) - C.EPIPE {
                fmt.Printf("ALSA buffer underrun")
                error2 := C.snd_pcm_recover(self.playback, C.EPIPE, 0)
                if error2 != C.int(0) {
                    panic(fmt.Sprintf("Could not recover from buffer underrun, error: %d", error2))
                }
            } else {
                //fmt.Println("FD: %v\t Str Pipe: %v\t Pipe: %v\n",C.EBADFD,C.ESTRPIPE,C.EPIPE)
                panic(fmt.Sprintf("Unkown ALSA error: %d", error))
            }
        } else if int(error) < length {
            //not all the data was written to the device
            panic(fmt.Sprintf("Could not write all data to ALSA device, wrote: %d", error))
        }
    }

    return
}

func (self *AlsaSink) Stop() os.Error {
    C.snd_pcm_close(self.playback)
    return nil
}

// Ugly bastardized C code follows
func (self *AlsaSink) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.playback, C.CString("default"), C.SND_PCM_STREAM_PLAYBACK, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.playback, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access type. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.playback, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.playback, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.playback, self.params, C.uint(self.header.Channels)); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set hardware parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.playback); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio device for use. Error %d", errno) )
    }

    return nil
}

//this one is slightly different
//note the change in scope
func (self *AlsaSource) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.capture, C.CString("default"), C.SND_PCM_STREAM_CAPTURE, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameters. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.capture, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.capture, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.capture, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.capture, self.params, 1); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.capture); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio interface for use. Error %d", errno) )
    }

    return nil
}
<commit_msg>Silly output, you should be commented<commit_after>// Copyright (c) 2010 Go Fightclub Authors

package alsa

import (
  "fmt"
  "unsafe"
  "afp"
  "os"
)

// #include <alsa/asoundlib.h>
import "C"

/////
// Alsa Source
// Listens to a microphone
type AlsaSource struct {
    ctx *afp.Context
    header afp.StreamHeader
    capture *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t
}

func NewAlsaSource() afp.Filter {
    return &AlsaSource{}
}

func (self *AlsaSource) GetType() int {
    return afp.PIPE_SOURCE
}

func (self *AlsaSource) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSource) Start() {

    self.header = afp.StreamHeader {
        Version: 1,
        Channels: 1,
        SampleSize: 32,
        SampleRate: 44100,
        FrameSize: 4096,
    }

    self.ctx.HeaderSink <- self.header

    retval := self.prepare()
    if ( retval != nil) {
        panic(retval)
    }

    for {
		cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
		buff := make([][]float32, self.header.FrameSize)
        length := len(cbuf)

        //first off, grab some data from alsa
        read := C.snd_pcm_readi(self.capture, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
        if read < C.snd_pcm_sframes_t(length) {
            errno := C.snd_pcm_recover(self.capture, C.int(read), 0)
            if errno < 0 {
                panic(fmt.Sprint( "While reading from ALSA device, failed to recover from error: ", errno))
            }
        }

        // snd_pcm_readi gives us a one dimensional array of interleaved data
        // but what we want is a two dimensional array of samples
        chans := int(self.header.Channels)
		for slice, i := 0, 0; i < length; slice, i = slice + 1, i + chans {
			buff[slice] = make([]float32, chans)
			buff[slice] = cbuf[i : i + chans]
        }

        //send it on down the line
        self.ctx.Sink <- buff
    }

}

func (self *AlsaSource) Stop() os.Error {
    C.snd_pcm_close(self.capture)
    close(self.ctx.Sink)
    return nil
}

/////
// Alsa Sink
// Outputs to speakers via ALSA
type AlsaSink struct {
    ctx *afp.Context
    header afp.StreamHeader
    playback *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t

}

func NewAlsaSink() afp.Filter {
    return &AlsaSink{}
}

func (self *AlsaSink) GetType() int {
    return afp.PIPE_SINK
}

func (self *AlsaSink) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSink) Start() {
    self.header = <-self.ctx.HeaderSource

    retval := self.prepare()
    if (retval != nil) {
        panic(retval)
    }
    cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)

    for buffer := range self.ctx.Source { //reading a [][]float32
        length := int(self.header.FrameSize)
        chans := int(self.header.Channels)

	    streamOffset := 0
        //interleave the channels
        for i := 0; i < length; i ++ {
            for j := 0; j < chans; j++ {
                cbuf[streamOffset] = buffer[i][j]
		        streamOffset++
            }
        }

        //write some data to alsa
        error := C.snd_pcm_writei(self.playback, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))

        //fmt.Print(".")

        //check our return
        if int(error) < 0 {
            //we are in an error state
            //panic(fmt.Sprintf("Could not write data to ALSA device, error: %d", error))
            if error == C.snd_pcm_sframes_t(0) - C.EBADFD {
                panic(fmt.Sprintf("Error initializing the ALSA device"))
            } else if error == C.snd_pcm_sframes_t(0) - C.ESTRPIPE {
                fmt.Printf("A suspend event has occurred")
            } else if error == C.snd_pcm_sframes_t(0) - C.EPIPE {
                fmt.Printf("ALSA buffer underrun")
                error2 := C.snd_pcm_recover(self.playback, C.EPIPE, 0)
                if error2 != C.int(0) {
                    panic(fmt.Sprintf("Could not recover from buffer underrun, error: %d", error2))
                }
            } else {
                //fmt.Println("FD: %v\t Str Pipe: %v\t Pipe: %v\n",C.EBADFD,C.ESTRPIPE,C.EPIPE)
                panic(fmt.Sprintf("Unkown ALSA error: %d", error))
            }
        } else if int(error) < length {
            //not all the data was written to the device
            panic(fmt.Sprintf("Could not write all data to ALSA device, wrote: %d", error))
        }
    }

    return
}

func (self *AlsaSink) Stop() os.Error {
    C.snd_pcm_close(self.playback)
    return nil
}

// Ugly bastardized C code follows
func (self *AlsaSink) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.playback, C.CString("default"), C.SND_PCM_STREAM_PLAYBACK, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.playback, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access type. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.playback, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.playback, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.playback, self.params, C.uint(self.header.Channels)); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set hardware parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.playback); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio device for use. Error %d", errno) )
    }

    return nil
}

//this one is slightly different
//note the change in scope
func (self *AlsaSource) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.capture, C.CString("default"), C.SND_PCM_STREAM_CAPTURE, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameters. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.capture, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.capture, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.capture, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.capture, self.params, 1); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.capture); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio interface for use. Error %d", errno) )
    }

    return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 AFP Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

//inspired by http://www.musicdsp.org/

package echo

import (
    "afp"
    "os"
)

type EchoFilter struct {
    //standard filter stuff
    context *afp.Context
    header afp.StreamHeader

    //decay attenuation: between 0 and 1
    decay float32

    //input and output buffers
    drySignal [][]float32
    wetSignal [][]float32
}

func (self *EchoFilter) GetType() int {
    return afp.PIPE_LINK
}

func NewEchoFilter() afp.Filter {
    return &EchoFilter{}
}

func (self *EchoFilter) Usage() {
    //TODO: add usage
}

func (self *EchoFilter) Init(ctx *afp.Context, args []string) os.Error {
    self.context = ctx
    //TODO: add argument parsing for decay rate
    self.decay = .35

    return nil
}

func (self *EchoFilter) Start() {
    self.header = <-self.context.HeaderSource
    self.context.HeaderSink <- self.header

    //delay offsets for 3 reflections
    offset1 := int32(100) //magic number
    offset2 := int32(250) //magic number
    offset3 := int32(420) //magic number

    //make the input buffer twice the frame size
    self.drySignal = <-self.context.Source
    self.drySignal = append(self.drySignal, <-self.context.Source...)
    length := 2 * self.header.FrameSize

    //a couple of empty buffers with the same dimensions as our input signal
    var zero []float32 = make([]float32, self.header.Channels)
    var zeros [][]float32
    for i := int32(0); i < self.header.FrameSize; i++ {
        zeros = append(zeros, zero)
    }

    self.wetSignal = makeBuffer(self.header.FrameSize*2, self.header.Channels)

    for nextFrame := range self.context.Source {

        outBuffer := makeBuffer(self.header.FrameSize, self.header.Channels)

        for i := int32(0); i < self.header.FrameSize; i++ {
            for j := int8(0); j < self.header.Channels; j++ {
                //three reflections
                self.wetSignal[i+offset1][j] += (self.drySignal[i][j] * self.decay )
                //self.wetSignal[i+offset2][j] += (self.drySignal[i][j] * self.decay )
                //self.wetSignal[i+offset3][j] += (self.drySignal[i][j] * self.decay )

                self.wetSignal[i][j] += self.drySignal[i][j]
                self.wetSignal[i][j] += (self.wetSignal[i+offset1][j] * self.decay)
                self.wetSignal[i][j] += (self.wetSignal[i+offset2][j] * self.decay)
                self.wetSignal[i][j] += (self.wetSignal[i+offset3][j] * self.decay)
                self.wetSignal[i][j] /= 4

                outBuffer[i][j] = self.wetSignal[i][j]
            }
        }

        self.context.Sink <- outBuffer

        self.wetSignal = self.wetSignal[self.header.FrameSize:]
        self.wetSignal = append(self.wetSignal, zeros...)

        self.drySignal = self.drySignal[self.header.FrameSize:]
        self.drySignal = append(self.drySignal, nextFrame...)
    }

    //TODO: pad with silence

    //flush the signals
    for i := int32(0); i < length; i++ {

        outBuffer := makeBuffer(self.header.FrameSize, self.header.Channels)

        //apply echo/reverb
        for j := int8(0); j < self.header.Channels; j++ {
            self.wetSignal[i][j] += self.drySignal[i][j]

            //three reflections
            self.wetSignal[i+offset1][j] += (self.drySignal[i][j] * self.decay )
            //self.wetSignal[i+offset2][j] += (self.drySignal[i][j] * self.decay )
            //self.wetSignal[i+offset3][j] += (self.drySignal[i][j] * self.decay )

            outBuffer[i][j] = self.wetSignal[i][j]
        }

        //wrap
        if i == self.header.FrameSize {
            self.context.Sink <- outBuffer
            outBuffer = makeBuffer(self.header.FrameSize, self.header.Channels)

            self.wetSignal = self.wetSignal[self.header.FrameSize:]
            self.drySignal = self.drySignal[self.header.FrameSize:]

            i = 0
            length -= self.header.FrameSize
        }
    }
}

func (self *EchoFilter) Stop() os.Error {
    //TODO
    return nil
}

// allocate a buffer for samples
func makeBuffer(size int32, channels int8) [][]float32 {
	b := make([][]float32, size)
	for i, _ := range b {
		b[i] = make([]float32, channels)
	}

	return b
}

<commit_msg>Added option parsing for decay gain.<commit_after>// Copyright (c) 2010 AFP Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

//inspired by http://www.musicdsp.org/

package echo

import (
    "afp"
    "afp/flags"
    "os"
)

type EchoFilter struct {
    //standard filter stuff
    context *afp.Context
    header afp.StreamHeader

    //decay attenuation: between 0 and 1
    decay float32

    //input and output buffers
    drySignal [][]float32
    wetSignal [][]float32
}

func (self *EchoFilter) GetType() int {
    return afp.PIPE_LINK
}

func NewEchoFilter() afp.Filter {
    return &EchoFilter{}
}

func (self *EchoFilter) Usage() {
    //TODO: add usage
}

func (self *EchoFilter) Init(ctx *afp.Context, args []string) os.Error {
    self.context = ctx

    //TODO: add tuning for the offset spread
    parser := flags.FlagParser(args)
    var d *float = parser.Float("d", .35, "The decay attenuation (0 - 1.0)")
    parser.Parse()

    self.decay = float32(*d)

    return nil
}

func (self *EchoFilter) Start() {
    self.header = <-self.context.HeaderSource
    self.context.HeaderSink <- self.header

    //TODO: add tuning for the offset spread
    //delay offsets for 3 reflections
    offset1 := int32(100) //magic number
    offset2 := int32(250) //magic number
    offset3 := int32(420) //magic number

    //make the input buffer twice the frame size
    self.drySignal = <-self.context.Source
    self.drySignal = append(self.drySignal, <-self.context.Source...)
    length := 2 * self.header.FrameSize

    //a couple of empty buffers with the same dimensions as our input signal
    var zero []float32 = make([]float32, self.header.Channels)
    var zeros [][]float32
    for i := int32(0); i < self.header.FrameSize; i++ {
        zeros = append(zeros, zero)
    }

    self.wetSignal = makeBuffer(self.header.FrameSize*2, self.header.Channels)

    for nextFrame := range self.context.Source {

        outBuffer := makeBuffer(self.header.FrameSize, self.header.Channels)

        for i := int32(0); i < self.header.FrameSize; i++ {
            for j := int8(0); j < self.header.Channels; j++ {
                //three reflections
                self.wetSignal[i+offset1][j] += (self.drySignal[i][j] * self.decay )
                //self.wetSignal[i+offset2][j] += (self.drySignal[i][j] * self.decay )
                //self.wetSignal[i+offset3][j] += (self.drySignal[i][j] * self.decay )

                self.wetSignal[i][j] += self.drySignal[i][j]
                self.wetSignal[i][j] += (self.wetSignal[i+offset1][j] * self.decay)
                self.wetSignal[i][j] += (self.wetSignal[i+offset2][j] * self.decay)
                self.wetSignal[i][j] += (self.wetSignal[i+offset3][j] * self.decay)

                //TODO: add proper normalization
                self.wetSignal[i][j] /= 4

                outBuffer[i][j] = self.wetSignal[i][j]
            }
        }

        self.context.Sink <- outBuffer

        self.wetSignal = self.wetSignal[self.header.FrameSize:]
        self.wetSignal = append(self.wetSignal, zeros...)

        self.drySignal = self.drySignal[self.header.FrameSize:]
        self.drySignal = append(self.drySignal, nextFrame...)
    }

    //TODO: pad with silence

    //flush the signals
    for i := int32(0); i < length; i++ {

        outBuffer := makeBuffer(self.header.FrameSize, self.header.Channels)

        //apply echo/reverb
        for j := int8(0); j < self.header.Channels; j++ {
            self.wetSignal[i][j] += self.drySignal[i][j]

            //three reflections
            self.wetSignal[i+offset1][j] += (self.drySignal[i][j] * self.decay )
            //self.wetSignal[i+offset2][j] += (self.drySignal[i][j] * self.decay )
            //self.wetSignal[i+offset3][j] += (self.drySignal[i][j] * self.decay )

            outBuffer[i][j] = self.wetSignal[i][j]
        }

        //wrap
        if i == self.header.FrameSize {
            self.context.Sink <- outBuffer
            outBuffer = makeBuffer(self.header.FrameSize, self.header.Channels)

            self.wetSignal = self.wetSignal[self.header.FrameSize:]
            self.drySignal = self.drySignal[self.header.FrameSize:]

            i = 0
            length -= self.header.FrameSize
        }
    }
}

func (self *EchoFilter) Stop() os.Error {
    //TODO
    return nil
}

// allocate a buffer for samples
func makeBuffer(size int32, channels int8) [][]float32 {
	b := make([][]float32, size)
	for i, _ := range b {
		b[i] = make([]float32, channels)
	}

	return b
}

<|endoftext|>


<commit_before>// Copyright (c) 2010 AFP Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

package pass

import (
	"afp"
	"afp/flags"
	"afp/fftw"
	"afp/matrix"
	"os"
)

type LowPassFilter struct {
	context               *afp.Context
	header                afp.StreamHeader
	cutoffFrequency		  float32
}

func NewLowPassFilter() afp.Filter {
	return &LowPassFilter{}
}

func (self *LowPassFilter) GetType() int {
	return afp.PIPE_LINK
}

func (self *LowPassFilter) Init(ctx *afp.Context, args []string) os.Error {
	self.context = ctx

	parser := flags.FlagParser(args)
	var f *float = parser.Float("f", 440, "The cutoff frequency")
	parser.Parse()

	self.cutoffFrequency = float32(*f)

	if self.cutoffFrequency < 0 {
		return os.NewError("The cutoff frequency must be greater than zero")
	}

	return nil
}

func (self *LowPassFilter) Start() {
	self.header = <-self.context.HeaderSource
	self.context.HeaderSink <- self.header

	self.process()
}

func (self *LowPassFilter) process() {
	// loop over all input data
	for audio := range self.context.Source {

		interleaved := matrix.Interleave(audio)

		_ = fftw.RealToReal1D_32(interleaved, true, 3, fftw.MEASURE, fftw.R2HC)

/*		for f, _ := range(interleaved) {
			if f < 60 {
				interleaved[f] = 0
			}
		}
*/
		_ = fftw.RealToReal1D_32(interleaved, true, 3, fftw.MEASURE, fftw.HC2R)

		for t, amp := range(interleaved) {
			interleaved[t] = amp/float32(512 * len(audio) * len(audio[0]))
/*			print(interleaved[t], " ")*/
		}

		deinterleaved := matrix.Deinterleave(interleaved, len(audio), len(audio[0]))

		// send the mixed audio down the pipe
		self.context.Sink <- deinterleaved
	}

}

func (self *LowPassFilter) Stop() os.Error {
	return nil
}
<commit_msg>Change imports in pass to reflect new util pkg<commit_after>// Copyright (c) 2010 AFP Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

package pass

import (
	"afp"
	"afp/flags"
	"afp/fftw"
    matrix "afp/lib/util"
	"os"
)

type LowPassFilter struct {
	context               *afp.Context
	header                afp.StreamHeader
	cutoffFrequency		  float32
}

func NewLowPassFilter() afp.Filter {
	return &LowPassFilter{}
}

func (self *LowPassFilter) GetType() int {
	return afp.PIPE_LINK
}

func (self *LowPassFilter) Init(ctx *afp.Context, args []string) os.Error {
	self.context = ctx

	parser := flags.FlagParser(args)
	var f *float = parser.Float("f", 440, "The cutoff frequency")
	parser.Parse()

	self.cutoffFrequency = float32(*f)

	if self.cutoffFrequency < 0 {
		return os.NewError("The cutoff frequency must be greater than zero")
	}

	return nil
}

func (self *LowPassFilter) Start() {
	self.header = <-self.context.HeaderSource
	self.context.HeaderSink <- self.header

	self.process()
}

func (self *LowPassFilter) process() {
	// loop over all input data
	for audio := range self.context.Source {

		interleaved := matrix.Interleave(audio)

		_ = fftw.RealToReal1D_32(interleaved, true, 3, fftw.MEASURE, fftw.R2HC)

/*		for f, _ := range(interleaved) {
			if f < 60 {
				interleaved[f] = 0
			}
		}
*/
		_ = fftw.RealToReal1D_32(interleaved, true, 3, fftw.MEASURE, fftw.HC2R)

		for t, amp := range(interleaved) {
			interleaved[t] = amp/float32(512 * len(audio) * len(audio[0]))
/*			print(interleaved[t], " ")*/
		}

		deinterleaved := matrix.Deinterleave(interleaved, len(audio), len(audio[0]))

		// send the mixed audio down the pipe
		self.context.Sink <- deinterleaved
	}

}

func (self *LowPassFilter) Stop() os.Error {
	return nil
}
<|endoftext|>


<commit_before>package timebox

import (
	"crypto/rand"
	"time"

	"golang.org/x/crypto/nacl/secretbox"
)

func Seal(data []byte, expires time.Time, key *[32]byte) ([]byte, error) {
	var nonce [24]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		return nil, err
	}

	tb, err := expires.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// The data is encoded as follows.
	//
	// [0, 1):      Length of the following binary encoded time.Time value. (N)
	// [1, N]:      Through the prefixed length (byte 0) is the binary encoded
	// 		        time.Time value.
	// (N, N+24]:   Nonce
	// (N+24, ...]: Sealed data

	outlen := 1 + len(tb) + len(nonce)

	out := make([]byte, outlen, outlen+len(data)+secretbox.Overhead)

	// Encode the length of the marshaled time.Time value in the first byte
	// since time.Time.UnmarshalBinary panics if its argument isn't the correct
	// length.
	out[0] = byte(len(tb))
	copy(out[1:], tb)
	copy(out[1+len(tb):], nonce[:])

	return secretbox.Seal(out, data, &nonce, key), nil
}

func Open(data []byte, key *[32]byte) ([]byte, bool) {
	return OpenAt(time.Now(), data, key)
}

func OpenAt(when time.Time, data []byte, key *[32]byte) (out []byte, ok bool) {
	end := int(data[0]) + 1

	var t time.Time
	err := t.UnmarshalBinary(data[1:end])
	if err != nil || !when.Before(t) {
		return nil, false
	}
	data = data[end:]

	var nonce [24]byte
	n := copy(nonce[:], data)
	return secretbox.Open(out, data[n:], &nonce, key)
}
<commit_msg>timebox: add basic docs<commit_after>// Timebox is a thin wrapper around nacl/secretbox for time-based secrets.
package timebox

import (
	"crypto/rand"
	"time"

	"golang.org/x/crypto/nacl/secretbox"
)

// Seal encrypts data the time-sensitive using nacl/secretbox.
func Seal(data []byte, expires time.Time, key *[32]byte) ([]byte, error) {
	var nonce [24]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		return nil, err
	}

	tb, err := expires.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// The data is encoded as follows.
	//
	// [0, 1):      Length of the following binary encoded time.Time value. (N)
	// [1, N]:      Through the prefixed length (byte 0) is the binary encoded
	// 		        time.Time value.
	// (N, N+24]:   Nonce
	// (N+24, ...]: Sealed data

	outlen := 1 + len(tb) + len(nonce)

	out := make([]byte, outlen, outlen+len(data)+secretbox.Overhead)

	// Encode the length of the marshaled time.Time value in the first byte
	// since time.Time.UnmarshalBinary panics if its argument isn't the correct
	// length.
	out[0] = byte(len(tb))
	copy(out[1:], tb)
	copy(out[1+len(tb):], nonce[:])

	return secretbox.Seal(out, data, &nonce, key), nil
}

// Open is shorthand for calling OpenAt with time.Now as its first argument.
func Open(data []byte, key *[32]byte) ([]byte, bool) {
	return OpenAt(time.Now(), data, key)
}

// OpenAt attempts to unseal the sealed data, returning false if the data has
// expired.
func OpenAt(when time.Time, data []byte, key *[32]byte) (out []byte, ok bool) {
	end := int(data[0]) + 1

	var t time.Time
	err := t.UnmarshalBinary(data[1:end])
	if err != nil || !when.Before(t) {
		return nil, false
	}
	data = data[end:]

	var nonce [24]byte
	n := copy(nonce[:], data)
	return secretbox.Open(out, data[n:], &nonce, key)
}
<|endoftext|>


<commit_before>package dominos

import (
	"errors"
	"fmt"
	"math/rand"
	"time"
)

func init() {
	rand.Seed(time.Now().Unix())
}

// Domino is a single tile with two sides. This is a game piece.
type Domino struct {
	Left, Right int // The values of each "side" of the domino.
}

// IsDouble checks if both of the tile values are the same.
func (d Domino) IsDouble() bool {
	return d.Left == d.Right
}

// IsPlayable returns true if d2 can be played on d1.
func (d Domino) IsPlayable(d2 Domino) bool {
	return d.Left == d2.Left ||
		d.Left == d2.Right ||
		d.Right == d2.Left ||
		d.Right == d2.Right
}

// Value returns how many "points" a tile is worth.
func (d Domino) Value() int {
	return d.Left + d.Right
}

// Display gives a human-readable version of this struct for debugging purposes.
func (d Domino) Display() string {
	return fmt.Sprintf("[%d|%d]", d.Left, d.Right)
}

// Game represents the total state for a single game
type Game struct {
	TilePool []Domino
	Trains   []*Path
	Players  []*Player
	Center   Domino

	UnresolvedDouble bool
	ActivePlayer     int
}

// Path represents a single player's path. If no player is set,
// the path is treated as the Mexican train.
type Path struct {
	Player   string
	Train    bool // If true, other players can play on it
	Elements []Element

	UnresolvedDouble bool
	MexicanTrain     bool
}

// Display shows the player's hand for debugging purposes.
func (p *Player) Display() string {
	result := "YOUR HAND:"
	for i, e := range p.Hand {
		result = result + fmt.Sprintf(" %d:%s", i, e.Display())
	}
	return result
}

// Display a path for debugging purposes.
func (p *Path) Display() string {
	result := ""

	if p.MexicanTrain {
		result = result + "M>>"
	} else {
		result = result + fmt.Sprintf("%s>>", p.Player)
	}

	for i, e := range p.Elements {
		result = result + fmt.Sprintf(" %d:%s", i, e.Display())
	}
	if p.Train {
		result = result + " *"
	}
	if p.UnresolvedDouble {
		result = result + " <!>"
	}
	return result
}

// Element is a wrapper for Domino that indicates if the Domino
// is flipped or not. This is for later UI implementation.
type Element struct {
	Domino
	Flipped bool
}

// Display gives a human-readable version of this struct for debugging purposes.
func (e Element) Display() string {
	if e.Flipped {
		d := Domino{
			Left:  e.Right,
			Right: e.Left,
		}

		return d.Display()
	}

	return e.Domino.Display()
}

// NewGame creates a new game board out of a list of
// players.
func NewGame(players []string) *Game {
	g := &Game{
		Trains: make([]*Path, len(players)+1),
	}

	mexicanTrain := &Path{
		Train:        true,
		Player:       "",
		MexicanTrain: true,
	}
	g.Trains[len(players)] = mexicanTrain

	// Generate the pool of tiles for the game
	var doms []Domino
	for i := 0; i <= dominoCount(len(players)); i++ {
		for j := 0; j <= i; j++ {
			doms = append(doms, Domino{i, j})
		}
	}

	// Randomize the order of the tiles
	for _, i := range rand.Perm(len(doms)) {
		g.TilePool = append(g.TilePool, doms[i])
	}

	// How many times should be pre-populated into a player's hand
	hc := handCount(len(players))

	// Create player structures
	for i, p := range players {
		newPlayer := &Player{
			ID: p,
		}
		g.Players = append(g.Players, newPlayer)

		path := &Path{
			Player: p,
		}
		newPlayer.Path = path

		g.Trains[i] = path

		for i := 0; i <= hc; i++ {
			err := g.Draw(newPlayer)
			if err != nil {
				panic(err)
			}
		}
	}

	// Find largest piece in player hands
	// XXX TODO find a better way to do this?
	var largest Domino
	var starter int
	var handIndex int

	for i, player := range g.Players {
		for j, dom := range player.Hand {
			if dom.Left == dom.Right { // XXX maybe Domino.IsDouble :: Domino -> bool
				if dom.Left > largest.Left {
					largest = dom
					starter = i
					handIndex = j
				}
			}
		}
	}
	g.Center = largest
	g.ActivePlayer = starter
	d := g.GetActivePlayer().RemoveFromHand(handIndex)
	if g.Center != d {
		panic("should be impossible")
	}

	return g
}

// Player is a single player in the game
type Player struct {
	Hand    []Domino
	BigPlay bool
	Knocked bool
	ID      string
	Path    *Path
}

func removeHandAtIndex(hand []Domino, i int) []Domino {
	hand[len(hand)-1], hand[i] = hand[i], hand[len(hand)-1]
	return hand[:len(hand)-1]
}

// RemoveFromHand when given index `at` will remove that element from the player's
// hand, returning it for future use.
func (p *Player) RemoveFromHand(at int) Domino {
	result := p.Hand[at]
	p.Hand = removeHandAtIndex(p.Hand, at)
	return result
}

// Draw adds a single tile from the game's tile pool to a player's hand.
func (g *Game) Draw(p *Player) error {
	if len(g.TilePool) == 0 {
		return errors.New("no tiles left")
	}

	t := g.TilePool[0]
	g.TilePool = g.TilePool[1:]
	p.Hand = append(p.Hand, t)

	return nil
}

// Place sets given Domino d from Player pl to the Path target if it fits.
func (g *Game) Place(pl *Player, d Domino, target *Path) bool {
	var last Element
	if len(target.Elements) == 0 {
		if !g.Center.IsPlayable(d) {
			return false
		}
	} else {
		last = target.Elements[len(target.Elements)-1]
		if !last.IsPlayable(d) {
			return false // Given domino d is not playable on the given Path.
		}
	}
	if target.Player != pl.ID && !target.Train && !target.MexicanTrain {
		return false // Cannot play on a train you don't own
	}

	e := Element{
		Domino:  d,
		Flipped: last.Left == d.Left || last.Right == d.Right,
	}

	target.Elements = append(target.Elements, e)

	return true
}

// Knock sets the knocked flag if a player has one tile left in their hand.
func (g *Game) Knock(p *Player) bool {
	if len(p.Hand) == 1 {
		p.Knocked = true
	}

	return p.Knocked
}

// NextTurn marks the next player as "up", adding two tiles to their hand if
// they only have one tile in their hand and haven't explicitly knocked.
func (g *Game) NextTurn() (*Player, string) {
	nextPlayer := (g.ActivePlayer + 1) % len(g.Players)
	p := g.Players[nextPlayer]
	g.ActivePlayer = nextPlayer
	status := ""
	if len(p.Hand) == 1 && !p.Knocked {
		g.Draw(p)
		g.Draw(p)
		p.Knocked = false
		status = "noknock"
	}

	return p, status
}

// GetActivePlayer returns the currently active Player structure.
func (g *Game) GetActivePlayer() *Player {
	return g.Players[g.ActivePlayer]
}

func handCount(playernum int) int {
	switch playernum {
	case 2:
		return 6
	case 3, 4:
		return 10
	case 5, 6:
		return 9
	case 7, 8:
		return 7
	default:
		return 6
	}
}

func dominoCount(playernum int) int {
	switch playernum {
	case 1, 2:
		return 6
	case 3, 4:
		return 9
	case 5, 6, 7, 8:
		return 12
	case 9, 10, 11, 12:
		return 15
	default:
		return 18
	}
}
<commit_msg>dominos: fix off-by-one error where players draw too many tiles<commit_after>package dominos

import (
	"errors"
	"fmt"
	"math/rand"
	"time"
)

func init() {
	rand.Seed(time.Now().Unix())
}

// Domino is a single tile with two sides. This is a game piece.
type Domino struct {
	Left, Right int // The values of each "side" of the domino.
}

// IsDouble checks if both of the tile values are the same.
func (d Domino) IsDouble() bool {
	return d.Left == d.Right
}

// IsPlayable returns true if d2 can be played on d1.
func (d Domino) IsPlayable(d2 Domino) bool {
	return d.Left == d2.Left ||
		d.Left == d2.Right ||
		d.Right == d2.Left ||
		d.Right == d2.Right
}

// Value returns how many "points" a tile is worth.
func (d Domino) Value() int {
	return d.Left + d.Right
}

// Display gives a human-readable version of this struct for debugging purposes.
func (d Domino) Display() string {
	return fmt.Sprintf("[%d|%d]", d.Left, d.Right)
}

// Game represents the total state for a single game
type Game struct {
	TilePool []Domino
	Trains   []*Path
	Players  []*Player
	Center   Domino

	UnresolvedDouble bool
	ActivePlayer     int
}

// Path represents a single player's path. If no player is set,
// the path is treated as the Mexican train.
type Path struct {
	Player   string
	Train    bool // If true, other players can play on it
	Elements []Element

	UnresolvedDouble bool
	MexicanTrain     bool
}

// Display shows the player's hand for debugging purposes.
func (p *Player) Display() string {
	result := "YOUR HAND:"
	for i, e := range p.Hand {
		result = result + fmt.Sprintf(" %d:%s", i, e.Display())
	}
	return result
}

// Display a path for debugging purposes.
func (p *Path) Display() string {
	result := ""

	if p.MexicanTrain {
		result = result + "M>>"
	} else {
		result = result + fmt.Sprintf("%s>>", p.Player)
	}

	for i, e := range p.Elements {
		result = result + fmt.Sprintf(" %d:%s", i, e.Display())
	}
	if p.Train {
		result = result + " *"
	}
	if p.UnresolvedDouble {
		result = result + " <!>"
	}
	return result
}

// Element is a wrapper for Domino that indicates if the Domino
// is flipped or not. This is for later UI implementation.
type Element struct {
	Domino
	Flipped bool
}

// Display gives a human-readable version of this struct for debugging purposes.
func (e Element) Display() string {
	if e.Flipped {
		d := Domino{
			Left:  e.Right,
			Right: e.Left,
		}

		return d.Display()
	}

	return e.Domino.Display()
}

// NewGame creates a new game board out of a list of
// players.
func NewGame(players []string) *Game {
	g := &Game{
		Trains: make([]*Path, len(players)+1),
	}

	mexicanTrain := &Path{
		Train:        true,
		Player:       "",
		MexicanTrain: true,
	}
	g.Trains[len(players)] = mexicanTrain

	// Generate the pool of tiles for the game
	var doms []Domino
	for i := 0; i <= dominoCount(len(players)); i++ {
		for j := 0; j <= i; j++ {
			doms = append(doms, Domino{i, j})
		}
	}

	// Randomize the order of the tiles
	for _, i := range rand.Perm(len(doms)) {
		g.TilePool = append(g.TilePool, doms[i])
	}

	// How many times should be pre-populated into a player's hand
	hc := handCount(len(players))

	// Create player structures
	for i, p := range players {
		newPlayer := &Player{
			ID: p,
		}
		g.Players = append(g.Players, newPlayer)

		path := &Path{
			Player: p,
		}
		newPlayer.Path = path

		g.Trains[i] = path

		for i := 0; i < hc; i++ {
			err := g.Draw(newPlayer)
			if err != nil {
				panic(err)
			}
		}
	}

	// Find largest piece in player hands
	// XXX TODO find a better way to do this?
	var largest Domino
	var starter int
	var handIndex int

	for i, player := range g.Players {
		for j, dom := range player.Hand {
			if dom.Left == dom.Right { // XXX maybe Domino.IsDouble :: Domino -> bool
				if dom.Left > largest.Left {
					largest = dom
					starter = i
					handIndex = j
				}
			}
		}
	}
	g.Center = largest
	g.ActivePlayer = starter
	d := g.GetActivePlayer().RemoveFromHand(handIndex)
	if g.Center != d {
		panic("should be impossible")
	}

	return g
}

// Player is a single player in the game
type Player struct {
	Hand    []Domino
	BigPlay bool
	Knocked bool
	ID      string
	Path    *Path
}

func removeHandAtIndex(hand []Domino, i int) []Domino {
	hand[len(hand)-1], hand[i] = hand[i], hand[len(hand)-1]
	return hand[:len(hand)-1]
}

// RemoveFromHand when given index `at` will remove that element from the player's
// hand, returning it for future use.
func (p *Player) RemoveFromHand(at int) Domino {
	result := p.Hand[at]
	p.Hand = removeHandAtIndex(p.Hand, at)
	return result
}

// Draw adds a single tile from the game's tile pool to a player's hand.
func (g *Game) Draw(p *Player) error {
	if len(g.TilePool) == 0 {
		return errors.New("no tiles left")
	}

	t := g.TilePool[0]
	g.TilePool = g.TilePool[1:]
	p.Hand = append(p.Hand, t)

	return nil
}

// Place sets given Domino d from Player pl to the Path target if it fits.
func (g *Game) Place(pl *Player, d Domino, target *Path) bool {
	var last Element
	if len(target.Elements) == 0 {
		if !g.Center.IsPlayable(d) {
			return false
		}
	} else {
		last = target.Elements[len(target.Elements)-1]
		if !last.IsPlayable(d) {
			return false // Given domino d is not playable on the given Path.
		}
	}
	if target.Player != pl.ID && !target.Train && !target.MexicanTrain {
		return false // Cannot play on a train you don't own
	}

	e := Element{
		Domino:  d,
		Flipped: last.Left == d.Left || last.Right == d.Right,
	}

	target.Elements = append(target.Elements, e)

	return true
}

// Knock sets the knocked flag if a player has one tile left in their hand.
func (g *Game) Knock(p *Player) bool {
	if len(p.Hand) == 1 {
		p.Knocked = true
	}

	return p.Knocked
}

// NextTurn marks the next player as "up", adding two tiles to their hand if
// they only have one tile in their hand and haven't explicitly knocked.
func (g *Game) NextTurn() (*Player, string) {
	nextPlayer := (g.ActivePlayer + 1) % len(g.Players)
	p := g.Players[nextPlayer]
	g.ActivePlayer = nextPlayer
	status := ""
	if len(p.Hand) == 1 && !p.Knocked {
		g.Draw(p)
		g.Draw(p)
		p.Knocked = false
		status = "noknock"
	}

	return p, status
}

// GetActivePlayer returns the currently active Player structure.
func (g *Game) GetActivePlayer() *Player {
	return g.Players[g.ActivePlayer]
}

func handCount(playernum int) int {
	switch playernum {
	case 2:
		return 6
	case 3, 4:
		return 10
	case 5, 6:
		return 9
	case 7, 8:
		return 7
	default:
		return 6
	}
}

func dominoCount(playernum int) int {
	switch playernum {
	case 1, 2:
		return 6
	case 3, 4:
		return 9
	case 5, 6, 7, 8:
		return 12
	case 9, 10, 11, 12:
		return 15
	default:
		return 18
	}
}
<|endoftext|>