<commit_before>package luddite

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"

	log "github.com/SpirentOrion/logrus"
	"github.com/julienschmidt/httprouter"
	"github.com/prometheus/client_golang/prometheus"
)

const (
	DefaultMetricsURIPath  = "/metrics"
	DefaultProfilerURIPath = "/debug/pprof"
)

// Service is an interface that implements a standalone RESTful web service.
type Service interface {
	// AddHandler adds a context-aware middleware handler to the
	// middleware stack. All handlers must be added before Run is
	// called.
	AddHandler(h Handler)

	// AddSingletonResource registers a singleton-style resource
	// (supporting GET and PUT methods only).
	AddSingletonResource(itemPath string, r Resource)

	// AddCollectionResource registers a collection-style resource
	// (supporting GET, POST, PUT, and DELETE methods).
	AddCollectionResource(basePath string, r Resource)

	// Config returns the service's ServiceConfig instance.
	Config() *ServiceConfig

	// Logger returns the service's log.Logger instance.
	Logger() *log.Logger

	// Router returns the service's httprouter.Router instance.
	Router() *httprouter.Router

	// Run is a convenience function that runs the service as an
	// HTTP server. The address is taken from the ServiceConfig
	// passed to NewService.
	Run() error
}

type service struct {
	config        *ServiceConfig
	defaultLogger *log.Logger
	accessLogger  *log.Logger
	router        *httprouter.Router
	handlers      []Handler
	middleware    *middleware
	schema        *SchemaHandler
}

func NewService(config *ServiceConfig) (Service, error) {
	var err error

	// Create the service
	s := &service{
		config: config,
		router: httprouter.New(),
	}

	s.defaultLogger = log.New()
	s.defaultLogger.SetFormatter(&log.JSONFormatter{})
	if config.Log.ServiceLogPath != "" {
		openLogFile(s.defaultLogger, config.Log.ServiceLogPath)
	} else {
		s.defaultLogger.SetOutput(os.Stdout)
	}

	switch strings.ToLower(config.Log.ServiceLogLevel) {
	case "debug":
		s.defaultLogger.SetLevel(log.DebugLevel)
	default:
		fallthrough
	case "info":
		s.defaultLogger.SetLevel(log.InfoLevel)
	case "warn":
		s.defaultLogger.SetLevel(log.WarnLevel)
	case "error":
		s.defaultLogger.SetLevel(log.ErrorLevel)
	}

	s.accessLogger = log.New()
	s.accessLogger.SetFormatter(&log.JSONFormatter{})
	if config.Log.AccessLogPath != "" {
		openLogFile(s.accessLogger, config.Log.AccessLogPath)
	} else {
		s.accessLogger.SetOutput(os.Stdout)
		s.accessLogger.SetLevel(log.DebugLevel)
	}

	s.router.NotFound = http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
		rw.WriteHeader(http.StatusNotFound)
	})

	s.router.MethodNotAllowed = http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
		rw.WriteHeader(http.StatusMethodNotAllowed)
	})

	// Create default middleware handlers
	bottom, err := s.newBottomHandler()
	if err != nil {
		return nil, err
	}

	negotiator, err := s.newNegotiatorHandler()
	if err != nil {
		return nil, err
	}

	version, err := s.newVersionHandler()
	if err != nil {
		return nil, err
	}

	// Build middleware stack
	s.handlers = []Handler{bottom, negotiator, version}
	s.middleware = buildMiddleware(s.handlers)

	// Install default http handlers
	if s.config.Metrics.Enabled {
		s.addMetricsRoute()
	}
	if s.config.Profiler.Enabled {
		s.addProfilerRoutes()
	}
	if config.Schema.Enabled {
		s.addSchemaRoutes()
	}

	// Dump goroutine stacks on demand
	dumpGoroutineStacks(s.defaultLogger)
	return s, nil
}

func (s *service) AddHandler(h Handler) {
	s.handlers = append(s.handlers, h)
	s.middleware = buildMiddleware(s.handlers)
}

func (s *service) AddSingletonResource(basePath string, r Resource) {
	// GET /basePath
	AddGetRoute(s.router, basePath, false, r)

	// PUT /basePath
	AddUpdateRoute(s.router, basePath, false, r)

	// POST /basePath/{action}
	AddActionRoute(s.router, basePath, false, r)
}

func (s *service) AddCollectionResource(basePath string, r Resource) {
	// GET /basePath
	AddListRoute(s.router, basePath, r)

	// GET /basePath/{id}
	AddGetRoute(s.router, basePath, true, r)

	// POST /basePath
	AddCreateRoute(s.router, basePath, r)

	// PUT /basePath/{id}
	AddUpdateRoute(s.router, basePath, true, r)

	// DELETE /basePath
	AddDeleteRoute(s.router, basePath, false, r)

	// DELETE /basePath/{id}
	AddDeleteRoute(s.router, basePath, true, r)

	// POST /basePath/{id}/{action}
	AddActionRoute(s.router, basePath, true, r)
}

func (s *service) Config() *ServiceConfig {
	return s.config
}

func (s *service) Logger() *log.Logger {
	return s.defaultLogger
}

func (s *service) Router() *httprouter.Router {
	return s.router
}

func (s *service) Run() error {
	// Add the router as the final middleware handler
	h, err := s.newRouterHandler()
	if err != nil {
		return err
	}
	s.AddHandler(h)

	var middleware http.Handler = s.middleware
	if s.config.Metrics.Enabled {
		middleware = prometheus.InstrumentHandler("service", middleware)
	}

	// Serve HTTP or HTTPS, depending on config. Use stoppable listener
	// so we can exit gracefully if signaled to do so.
	var stoppableListener net.Listener
	if s.config.Transport.TLS {
		s.defaultLogger.Debugf("HTTPS listening on %s", s.config.Addr)
		stoppableListener, err = NewStoppableTLSListener(s.config.Addr, true, s.config.Transport.CertFilePath, s.config.Transport.KeyFilePath)
	} else {
		s.defaultLogger.Debugf("HTTP listening on %s", s.config.Addr)
		stoppableListener, err = NewStoppableTCPListener(s.config.Addr, true)
	}
	if err != nil {
		return err
	}

	if err = http.Serve(stoppableListener, middleware); err != nil {
		if _, ok := err.(*ListenerStoppedError); !ok {
			return err
		}
	}
	return nil
}

func (s *service) newBottomHandler() (Handler, error) {
	return NewBottom(s, s.defaultLogger, s.accessLogger), nil
}

func (s *service) newNegotiatorHandler() (Handler, error) {
	return NewNegotiator([]string{
		ContentTypeJson,
		ContentTypeCss,
		ContentTypePlain,
		ContentTypeXml,
		ContentTypeHtml,
		ContentTypeGif,
		ContentTypePng,
		ContentTypeOctetStream},
	), nil
}

func (s *service) newVersionHandler() (Handler, error) {
	if s.config.Version.Min < 1 {
		return nil, errors.New("service's minimum API version must be greater than zero")
	}
	if s.config.Version.Max < 1 {
		return nil, errors.New("service's maximum API version must be greater than zero")
	}

	return NewVersion(s.config.Version.Min, s.config.Version.Max), nil
}

func (s *service) newRouterHandler() (Handler, error) {
	// No more middleware handlers: remaining dispatch happens via httprouter
	return WrapHttpHandler(s.router), nil
}

func (s *service) addMetricsRoute() {
	uriPath := s.config.Metrics.UriPath
	if uriPath == "" {
		uriPath = DefaultMetricsURIPath
	}

	h := prometheus.UninstrumentedHandler()
	s.router.GET(uriPath, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { h.ServeHTTP(rw, req) })
}

func (s *service) addProfilerRoutes() {
	uriPath := s.config.Profiler.UriPath
	if uriPath == "" {
		uriPath = DefaultProfilerURIPath
	}

	s.router.GET(path.Join(uriPath, "/"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Index(rw, req) })
	s.router.GET(path.Join(uriPath, "/cmdline"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Cmdline(rw, req) })
	s.router.GET(path.Join(uriPath, "/profile"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Profile(rw, req) })
	s.router.POST(path.Join(uriPath, "/profile"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Profile(rw, req) })
	s.router.GET(path.Join(uriPath, "/symbol"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Symbol(rw, req) })
	s.router.POST(path.Join(uriPath, "/symbol"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Symbol(rw, req) })
	s.router.GET(path.Join(uriPath, "/trace"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Trace(rw, req) })
	s.router.POST(path.Join(uriPath, "/trace"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Trace(rw, req) })
}

func (s *service) addSchemaRoutes() {
	config := s.config

	// Serve the various schemas, e.g. /schema/v1, /schema/v2, etc.
	s.schema = NewSchemaHandler(config.Schema.FilePath)

	s.router.GET(path.Join(config.Schema.UriPath, "/v:version/", "*filepath"), s.schema.ServeHTTP)

	// Temporarily redirect (307) the base schema path to the default schema file, e.g. /schema -> /schema/v2/fileName
	defaultSchemaPath := path.Join(config.Schema.UriPath, fmt.Sprintf("v%d", config.Version.Max), config.Schema.FileName)

	s.router.GET(config.Schema.UriPath, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
		http.Redirect(rw, req, defaultSchemaPath, http.StatusTemporaryRedirect)
	})

	// Temporarily redirect (307) the version schema path to the default schema file, e.g. /schema/v2 -> /schema/v2/fileName
	s.router.GET(path.Join(config.Schema.UriPath, "/v:version/"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
		http.Redirect(rw, req, defaultSchemaPath, http.StatusTemporaryRedirect)
	})

	// Optionally temporarily redirect (307) the root to the base schema path, e.g. / -> /schema
	if config.Schema.RootRedirect {
		s.router.GET("/", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
			http.Redirect(rw, req, config.Schema.UriPath, http.StatusTemporaryRedirect)
		})
	}
}

func openLogFile(logger *log.Logger, logPath string) {
	sigs := make(chan os.Signal, 1)
	logging := make(chan bool, 1)

	go func() {
		var curLog, priorLog *os.File
		for {
			// Open and begin using a new log file
			curLog, _ = os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
			logger.SetOutput(curLog)

			if priorLog == nil {
				// First log, signal the outer goroutine that we're running
				logging <- true
			} else {
				// Follow-on log, close the prior log file
				priorLog.Close()
				priorLog = nil
			}

			// Wait for a SIGHUP
			<-sigs

			// Setup for the next iteration
			priorLog = curLog
		}
	}()

	signal.Notify(sigs, syscall.SIGHUP)
	<-logging
}
<commit_msg>Revert "Add image/gif and image/png to content negotiation"<commit_after>package luddite

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"

	log "github.com/SpirentOrion/logrus"
	"github.com/julienschmidt/httprouter"
	"github.com/prometheus/client_golang/prometheus"
)

const (
	DefaultMetricsURIPath  = "/metrics"
	DefaultProfilerURIPath = "/debug/pprof"
)

// Service is an interface that implements a standalone RESTful web service.
type Service interface {
	// AddHandler adds a context-aware middleware handler to the
	// middleware stack. All handlers must be added before Run is
	// called.
	AddHandler(h Handler)

	// AddSingletonResource registers a singleton-style resource
	// (supporting GET and PUT methods only).
	AddSingletonResource(itemPath string, r Resource)

	// AddCollectionResource registers a collection-style resource
	// (supporting GET, POST, PUT, and DELETE methods).
	AddCollectionResource(basePath string, r Resource)

	// Config returns the service's ServiceConfig instance.
	Config() *ServiceConfig

	// Logger returns the service's log.Logger instance.
	Logger() *log.Logger

	// Router returns the service's httprouter.Router instance.
	Router() *httprouter.Router

	// Run is a convenience function that runs the service as an
	// HTTP server. The address is taken from the ServiceConfig
	// passed to NewService.
	Run() error
}

type service struct {
	config        *ServiceConfig
	defaultLogger *log.Logger
	accessLogger  *log.Logger
	router        *httprouter.Router
	handlers      []Handler
	middleware    *middleware
	schema        *SchemaHandler
}

func NewService(config *ServiceConfig) (Service, error) {
	var err error

	// Create the service
	s := &service{
		config: config,
		router: httprouter.New(),
	}

	s.defaultLogger = log.New()
	s.defaultLogger.SetFormatter(&log.JSONFormatter{})
	if config.Log.ServiceLogPath != "" {
		openLogFile(s.defaultLogger, config.Log.ServiceLogPath)
	} else {
		s.defaultLogger.SetOutput(os.Stdout)
	}

	switch strings.ToLower(config.Log.ServiceLogLevel) {
	case "debug":
		s.defaultLogger.SetLevel(log.DebugLevel)
	default:
		fallthrough
	case "info":
		s.defaultLogger.SetLevel(log.InfoLevel)
	case "warn":
		s.defaultLogger.SetLevel(log.WarnLevel)
	case "error":
		s.defaultLogger.SetLevel(log.ErrorLevel)
	}

	s.accessLogger = log.New()
	s.accessLogger.SetFormatter(&log.JSONFormatter{})
	if config.Log.AccessLogPath != "" {
		openLogFile(s.accessLogger, config.Log.AccessLogPath)
	} else {
		s.accessLogger.SetOutput(os.Stdout)
		s.accessLogger.SetLevel(log.DebugLevel)
	}

	s.router.NotFound = http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
		rw.WriteHeader(http.StatusNotFound)
	})

	s.router.MethodNotAllowed = http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
		rw.WriteHeader(http.StatusMethodNotAllowed)
	})

	// Create default middleware handlers
	bottom, err := s.newBottomHandler()
	if err != nil {
		return nil, err
	}

	negotiator, err := s.newNegotiatorHandler()
	if err != nil {
		return nil, err
	}

	version, err := s.newVersionHandler()
	if err != nil {
		return nil, err
	}

	// Build middleware stack
	s.handlers = []Handler{bottom, negotiator, version}
	s.middleware = buildMiddleware(s.handlers)

	// Install default http handlers
	if s.config.Metrics.Enabled {
		s.addMetricsRoute()
	}
	if s.config.Profiler.Enabled {
		s.addProfilerRoutes()
	}
	if config.Schema.Enabled {
		s.addSchemaRoutes()
	}

	// Dump goroutine stacks on demand
	dumpGoroutineStacks(s.defaultLogger)
	return s, nil
}

func (s *service) AddHandler(h Handler) {
	s.handlers = append(s.handlers, h)
	s.middleware = buildMiddleware(s.handlers)
}

func (s *service) AddSingletonResource(basePath string, r Resource) {
	// GET /basePath
	AddGetRoute(s.router, basePath, false, r)

	// PUT /basePath
	AddUpdateRoute(s.router, basePath, false, r)

	// POST /basePath/{action}
	AddActionRoute(s.router, basePath, false, r)
}

func (s *service) AddCollectionResource(basePath string, r Resource) {
	// GET /basePath
	AddListRoute(s.router, basePath, r)

	// GET /basePath/{id}
	AddGetRoute(s.router, basePath, true, r)

	// POST /basePath
	AddCreateRoute(s.router, basePath, r)

	// PUT /basePath/{id}
	AddUpdateRoute(s.router, basePath, true, r)

	// DELETE /basePath
	AddDeleteRoute(s.router, basePath, false, r)

	// DELETE /basePath/{id}
	AddDeleteRoute(s.router, basePath, true, r)

	// POST /basePath/{id}/{action}
	AddActionRoute(s.router, basePath, true, r)
}

func (s *service) Config() *ServiceConfig {
	return s.config
}

func (s *service) Logger() *log.Logger {
	return s.defaultLogger
}

func (s *service) Router() *httprouter.Router {
	return s.router
}

func (s *service) Run() error {
	// Add the router as the final middleware handler
	h, err := s.newRouterHandler()
	if err != nil {
		return err
	}
	s.AddHandler(h)

	var middleware http.Handler = s.middleware
	if s.config.Metrics.Enabled {
		middleware = prometheus.InstrumentHandler("service", middleware)
	}

	// Serve HTTP or HTTPS, depending on config. Use stoppable listener
	// so we can exit gracefully if signaled to do so.
	var stoppableListener net.Listener
	if s.config.Transport.TLS {
		s.defaultLogger.Debugf("HTTPS listening on %s", s.config.Addr)
		stoppableListener, err = NewStoppableTLSListener(s.config.Addr, true, s.config.Transport.CertFilePath, s.config.Transport.KeyFilePath)
	} else {
		s.defaultLogger.Debugf("HTTP listening on %s", s.config.Addr)
		stoppableListener, err = NewStoppableTCPListener(s.config.Addr, true)
	}
	if err != nil {
		return err
	}

	if err = http.Serve(stoppableListener, middleware); err != nil {
		if _, ok := err.(*ListenerStoppedError); !ok {
			return err
		}
	}
	return nil
}

func (s *service) newBottomHandler() (Handler, error) {
	return NewBottom(s, s.defaultLogger, s.accessLogger), nil
}

func (s *service) newNegotiatorHandler() (Handler, error) {
	return NewNegotiator([]string{
		ContentTypeJson,
		ContentTypeCss,
		ContentTypePlain,
		ContentTypeXml,
		ContentTypeHtml,
		ContentTypeOctetStream},
	), nil
}

func (s *service) newVersionHandler() (Handler, error) {
	if s.config.Version.Min < 1 {
		return nil, errors.New("service's minimum API version must be greater than zero")
	}
	if s.config.Version.Max < 1 {
		return nil, errors.New("service's maximum API version must be greater than zero")
	}

	return NewVersion(s.config.Version.Min, s.config.Version.Max), nil
}

func (s *service) newRouterHandler() (Handler, error) {
	// No more middleware handlers: remaining dispatch happens via httprouter
	return WrapHttpHandler(s.router), nil
}

func (s *service) addMetricsRoute() {
	uriPath := s.config.Metrics.UriPath
	if uriPath == "" {
		uriPath = DefaultMetricsURIPath
	}

	h := prometheus.UninstrumentedHandler()
	s.router.GET(uriPath, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { h.ServeHTTP(rw, req) })
}

func (s *service) addProfilerRoutes() {
	uriPath := s.config.Profiler.UriPath
	if uriPath == "" {
		uriPath = DefaultProfilerURIPath
	}

	s.router.GET(path.Join(uriPath, "/"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Index(rw, req) })
	s.router.GET(path.Join(uriPath, "/cmdline"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Cmdline(rw, req) })
	s.router.GET(path.Join(uriPath, "/profile"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Profile(rw, req) })
	s.router.POST(path.Join(uriPath, "/profile"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Profile(rw, req) })
	s.router.GET(path.Join(uriPath, "/symbol"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Symbol(rw, req) })
	s.router.POST(path.Join(uriPath, "/symbol"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Symbol(rw, req) })
	s.router.GET(path.Join(uriPath, "/trace"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Trace(rw, req) })
	s.router.POST(path.Join(uriPath, "/trace"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { pprof.Trace(rw, req) })
}

func (s *service) addSchemaRoutes() {
	config := s.config

	// Serve the various schemas, e.g. /schema/v1, /schema/v2, etc.
	s.schema = NewSchemaHandler(config.Schema.FilePath)

	s.router.GET(path.Join(config.Schema.UriPath, "/v:version/", "*filepath"), s.schema.ServeHTTP)

	// Temporarily redirect (307) the base schema path to the default schema file, e.g. /schema -> /schema/v2/fileName
	defaultSchemaPath := path.Join(config.Schema.UriPath, fmt.Sprintf("v%d", config.Version.Max), config.Schema.FileName)

	s.router.GET(config.Schema.UriPath, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
		http.Redirect(rw, req, defaultSchemaPath, http.StatusTemporaryRedirect)
	})

	// Temporarily redirect (307) the version schema path to the default schema file, e.g. /schema/v2 -> /schema/v2/fileName
	s.router.GET(path.Join(config.Schema.UriPath, "/v:version/"), func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
		http.Redirect(rw, req, defaultSchemaPath, http.StatusTemporaryRedirect)
	})

	// Optionally temporarily redirect (307) the root to the base schema path, e.g. / -> /schema
	if config.Schema.RootRedirect {
		s.router.GET("/", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
			http.Redirect(rw, req, config.Schema.UriPath, http.StatusTemporaryRedirect)
		})
	}
}

func openLogFile(logger *log.Logger, logPath string) {
	sigs := make(chan os.Signal, 1)
	logging := make(chan bool, 1)

	go func() {
		var curLog, priorLog *os.File
		for {
			// Open and begin using a new log file
			curLog, _ = os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
			logger.SetOutput(curLog)

			if priorLog == nil {
				// First log, signal the outer goroutine that we're running
				logging <- true
			} else {
				// Follow-on log, close the prior log file
				priorLog.Close()
				priorLog = nil
			}

			// Wait for a SIGHUP
			<-sigs

			// Setup for the next iteration
			priorLog = curLog
		}
	}()

	signal.Notify(sigs, syscall.SIGHUP)
	<-logging
}
<|endoftext|>


<commit_before>package session

import (
	"log"
	"net/http"

	"github.com/gorilla/sessions"
	"github.com/labstack/echo"
)

const (
	DefaultKey  = "github.com/ipfans/echo-session"
	errorFormat = "[sessions] ERROR! %s\n"
)

type Store interface {
	sessions.Store
	Options(Options)
	MaxAge(int)
}

// Options stores configuration for a session or session store.
// Fields are a subset of http.Cookie fields.
type Options struct {
	Path   string
	Domain string
	// MaxAge=0 means no 'Max-Age' attribute specified.
	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
	// MaxAge>0 means Max-Age attribute present and given in seconds.
	MaxAge   int
	Secure   bool
	HttpOnly bool
}

// Wraps thinly gorilla-session methods.

// Session stores the values and optional configuration for a session.
type Session interface {
	// Get returns the session value associated to the given key.
	Get(key interface{}) interface{}
	// Set sets the session value associated to the given key.
	Set(key interface{}, val interface{})
	// Delete removes the session value associated to the given key.
	Delete(key interface{})
	// Clear deletes all values in the session.
	Clear()
	// AddFlash adds a flash message to the session.
	// A single variadic argument is accepted, and it is optional: it defines the flash key.
	// If not defined "_flash" is used by default.
	AddFlash(value interface{}, vars ...string)
	// Flashes returns a slice of flash messages from the session.
	// A single variadic argument is accepted, and it is optional: it defines the flash key.
	// If not defined "_flash" is used by default.
	Flashes(vars ...string) []interface{}
	// Options sets confuguration for a session.
	Options(Options)
	// Save saves all sessions used during the current request.
	Save() error
}

func Sessions(name string, store Store) echo.MiddlewareFunc {
	return func(h echo.HandlerFunc) echo.HandlerFunc {
		return func(ctx echo.Context) error {
			rq := ctx.Request()
			rs := ctx.Response()
			s := &session{name, rq, store, nil, false, rs.Writer()}
			ctx.Set(DefaultKey, s)
			return h(ctx)
		}
	}
}

type session struct {
	name    string
	request *http.Request
	store   Store
	session *sessions.Session
	written bool
	writer  http.ResponseWriter
}

func (s *session) Get(key interface{}) interface{} {
	return s.Session().Values[key]
}

func (s *session) Set(key interface{}, val interface{}) {
	s.Session().Values[key] = val
	s.written = true
}

func (s *session) Delete(key interface{}) {
	delete(s.Session().Values, key)
	s.written = true
}

func (s *session) Clear() {
	for key := range s.Session().Values {
		s.Delete(key)
	}
}

func (s *session) AddFlash(value interface{}, vars ...string) {
	s.Session().AddFlash(value, vars...)
	s.written = true
}

func (s *session) Flashes(vars ...string) []interface{} {
	s.written = true
	return s.Session().Flashes(vars...)
}

func (s *session) Options(options Options) {
	s.Session().Options = &sessions.Options{
		Path:     options.Path,
		Domain:   options.Domain,
		MaxAge:   options.MaxAge,
		Secure:   options.Secure,
		HttpOnly: options.HttpOnly,
	}
}

func (s *session) Save() error {
	if s.Written() {
		e := s.Session().Save(s.request, s.writer)
		if e == nil {
			s.written = false
		}
		return e
	}
	return nil
}

func (s *session) Session() *sessions.Session {
	if s.session == nil {
		var err error
		s.session, err = s.store.Get(s.request, s.name)
		if err != nil {
			log.Printf(errorFormat, err)
		}
	}
	return s.session
}

func (s *session) Written() bool {
	return s.written
}

// shortcut to get session
func Default(ctx echo.Context) Session {
	session := ctx.Get(DefaultKey)
	if session == nil {
		return nil
	}
	return ctx.Get(DefaultKey).(Session)
}
<commit_msg>fix last echo version<commit_after>package session

import (
	"log"
	"net/http"

	"github.com/gorilla/sessions"
	"github.com/labstack/echo"
)

const (
	DefaultKey  = "github.com/ipfans/echo-session"
	errorFormat = "[sessions] ERROR! %s\n"
)

type Store interface {
	sessions.Store
	Options(Options)
	MaxAge(int)
}

// Options stores configuration for a session or session store.
// Fields are a subset of http.Cookie fields.
type Options struct {
	Path   string
	Domain string
	// MaxAge=0 means no 'Max-Age' attribute specified.
	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
	// MaxAge>0 means Max-Age attribute present and given in seconds.
	MaxAge   int
	Secure   bool
	HttpOnly bool
}

// Wraps thinly gorilla-session methods.

// Session stores the values and optional configuration for a session.
type Session interface {
	// Get returns the session value associated to the given key.
	Get(key interface{}) interface{}
	// Set sets the session value associated to the given key.
	Set(key interface{}, val interface{})
	// Delete removes the session value associated to the given key.
	Delete(key interface{})
	// Clear deletes all values in the session.
	Clear()
	// AddFlash adds a flash message to the session.
	// A single variadic argument is accepted, and it is optional: it defines the flash key.
	// If not defined "_flash" is used by default.
	AddFlash(value interface{}, vars ...string)
	// Flashes returns a slice of flash messages from the session.
	// A single variadic argument is accepted, and it is optional: it defines the flash key.
	// If not defined "_flash" is used by default.
	Flashes(vars ...string) []interface{}
	// Options sets confuguration for a session.
	Options(Options)
	// Save saves all sessions used during the current request.
	Save() error
}

func Sessions(name string, store Store) echo.MiddlewareFunc {
	return func(h echo.HandlerFunc) echo.HandlerFunc {
		return func(ctx echo.Context) error {
			rq := ctx.Request()
			rs := ctx.Response()
			s := &session{name, rq, store, nil, false, rs.Writer}
			ctx.Set(DefaultKey, s)
			return h(ctx)
		}
	}
}

type session struct {
	name    string
	request *http.Request
	store   Store
	session *sessions.Session
	written bool
	writer  http.ResponseWriter
}

func (s *session) Get(key interface{}) interface{} {
	return s.Session().Values[key]
}

func (s *session) Set(key interface{}, val interface{}) {
	s.Session().Values[key] = val
	s.written = true
}

func (s *session) Delete(key interface{}) {
	delete(s.Session().Values, key)
	s.written = true
}

func (s *session) Clear() {
	for key := range s.Session().Values {
		s.Delete(key)
	}
}

func (s *session) AddFlash(value interface{}, vars ...string) {
	s.Session().AddFlash(value, vars...)
	s.written = true
}

func (s *session) Flashes(vars ...string) []interface{} {
	s.written = true
	return s.Session().Flashes(vars...)
}

func (s *session) Options(options Options) {
	s.Session().Options = &sessions.Options{
		Path:     options.Path,
		Domain:   options.Domain,
		MaxAge:   options.MaxAge,
		Secure:   options.Secure,
		HttpOnly: options.HttpOnly,
	}
}

func (s *session) Save() error {
	if s.Written() {
		e := s.Session().Save(s.request, s.writer)
		if e == nil {
			s.written = false
		}
		return e
	}
	return nil
}

func (s *session) Session() *sessions.Session {
	if s.session == nil {
		var err error
		s.session, err = s.store.Get(s.request, s.name)
		if err != nil {
			log.Printf(errorFormat, err)
		}
	}
	return s.session
}

func (s *session) Written() bool {
	return s.written
}

// shortcut to get session
func Default(ctx echo.Context) Session {
	session := ctx.Get(DefaultKey)
	if session == nil {
		return nil
	}
	return ctx.Get(DefaultKey).(Session)
}
<|endoftext|>


<commit_before>package framework

import (
	"net/http"
)

type Sessioner interface {
	Sessions() Sessions
	Session(string) (Session, error)
	SetSessionValue(string, interface{}, interface{}) error
	GetSessionValue(string, interface{}) (Value, error)
}

type SessionStore interface {
	SessionNames() []string
	Get(*http.Request, string) (Session, error)
	GetAll(*http.Request) (Sessions, error)
	GetMany(*http.Request, ...string) (Sessions, error)
	New(*http.Request, string) (Session, error)
	Save(Response, Session) error
}

type Sessions []Session

func (s Sessions) Get(name string) (Session, error) {
	for _, se := range s {
		if se.Name() == name {
			return se, nil
		}
	}
	return nil, nil
}

func (s *Sessions) Add(ns Session) {
	if ns == nil {
		return
	}
	for i, se := range *s {
		if se.Name() == ns.Name() {
			(*s)[i] = ns
			return
		}
	}
	*s = append(*s, ns)
}

func (s *Sessions) AddMany(nses ...Session) {
	for _, ns := range nses {
		if ns == nil {
			continue
		}
		for i, se := range *s {
			if se.Name() == ns.Name() {
				(*s)[i] = ns
				continue
			}
		}
		*s = append(*s, ns)
	}
}

func (s Sessions) Save(c Context) error {
	var err error
	for _, se := range s {
		err = se.Save(c)
		if err != nil {
			return err
		}
	}
	return nil
}

type Session interface {
	Flashes(vars ...string) []Value
	AddFlash(value interface{}, vars ...string)
	Save(Context) error
	Name() string
	Store() SessionStore
}
<commit_msg>Updated Session interfaces<commit_after>package framework

import (
	"net/http"
)

type Sessioner interface {
	Sessions() Sessions
	Session(string) Session
	SetSessionValue(string, interface{}, interface{}) error
	GetSessionValue(string, interface{}) (Value, error)
}

type SessionStore interface {
	Names() []string
	Get(*http.Request, string) (Session, error)
	GetAll(*http.Request) (Sessions, error)
	GetMany(*http.Request, ...string) (Sessions, error)
	New(*http.Request, string) (Session, error)
	Save(*http.Request, http.ResponseWriter, Session) error
}

type Sessions []Session

func (s Sessions) Get(name string) Session {
	for _, se := range s {
		if se.Name() == name {
			return se
		}
	}
	return nil
}

func (s *Sessions) Append(nses ...Session) {
	for _, ns := range nses {
		if ns == nil {
			continue
		}
		for i, se := range *s {
			if se.Name() == ns.Name() {
				(*s)[i] = ns
				continue
			}
		}
		*s = append(*s, ns)
	}
}

func (s Sessions) Save(r *http.Request, w http.ResponseWriter) error {
	var err error
	for _, se := range s {
		if !se.Changed() {
			continue
		}
		err = se.Save(r, w)
		if err != nil {
			return err
		}
	}
	return nil
}

type Session interface {
	Set(interface{}, interface{})
	Get(interface{}) Value
	GetOr(interface{}, interface{}) Value
	Unset(interface{}) bool
	ID() string
	Flashes(vars ...string) []Value
	AddFlash(value interface{}, vars ...string)
	Save(*http.Request, http.ResponseWriter) error
	Name() string
	Store() SessionStore
	Values() Values
	Changed() bool
}
<|endoftext|>


<commit_before>package ssh

import (
	"bytes"
	"fmt"
	"net"

	"github.com/anmitsu/go-shlex"
	gossh "golang.org/x/crypto/ssh"
)

// Session provides access to information about an SSH session and methods
// to read and write to the SSH channel with an embedded Channel interface from
// cypto/ssh.
//
// When Command() returns an empty slice, the user requested a shell. Otherwise
// the user is performing an exec with those command arguments.
//
// TODO: Signals
type Session interface {
	gossh.Channel

	// User returns the username used when establishing the SSH connection.
	User() string

	// RemoteAddr returns the net.Addr of the client side of the connection.
	RemoteAddr() net.Addr

	// Environ returns a copy of strings representing the environment set by the
	// user for this session, in the form "key=value".
	Environ() []string

	// Exit sends an exit status and then closes the session.
	Exit(code int) error

	// Command returns a shell parsed slice of arguments that were provided by the
	// user. Shell parsing splits the command string according to POSIX shell rules,
	// which considers quoting not just whitespace.
	Command() []string

	// PublicKey returns the PublicKey used to authenticate. If a public key was not
	// used it will return nil.
	PublicKey() PublicKey

	// Pty returns PTY information, a channel of window size changes, and a boolean
	// of whether or not a PTY was accepted for this session.
	Pty() (Pty, <-chan Window, bool)

	// TODO: Signals(c chan<- Signal)
}

type session struct {
	gossh.Channel
	conn    *gossh.ServerConn
	handler Handler
	handled bool
	pty     *Pty
	winch   chan Window
	env     []string
	ptyCb   PtyCallback
	cmd     []string
}

func (sess *session) Write(p []byte) (n int, err error) {
	if sess.pty != nil {
		// normalize \n to \r\n when pty is accepted
		p = bytes.Replace(p, []byte{'\n'}, []byte{'\r', '\n'}, -1)
		p = bytes.Replace(p, []byte{'\r', '\r', '\n'}, []byte{'\r', '\n'}, -1)
	}
	return sess.Channel.Write(p)
}

func (sess *session) PublicKey() PublicKey {
	if sess.conn.Permissions == nil {
		return nil
	}
	s, ok := sess.conn.Permissions.Extensions["_publickey"]
	if !ok {
		return nil
	}
	key, err := ParsePublicKey([]byte(s))
	if err != nil {
		return nil
	}
	return key
}

func (sess *session) Exit(code int) error {
	status := struct{ Status uint32 }{uint32(code)}
	_, err := sess.SendRequest("exit-status", false, gossh.Marshal(&status))
	if err != nil {
		return err
	}
	return sess.Close()
}

func (sess *session) User() string {
	return sess.conn.User()
}

func (sess *session) RemoteAddr() net.Addr {
	return sess.conn.RemoteAddr()
}

func (sess *session) Environ() []string {
	return append([]string(nil), sess.env...)
}

func (sess *session) Command() []string {
	return append([]string(nil), sess.cmd...)
}

func (sess *session) Pty() (Pty, <-chan Window, bool) {
	if sess.pty != nil {
		return *sess.pty, sess.winch, true
	}
	return Pty{}, sess.winch, false
}

func (sess *session) handleRequests(reqs <-chan *gossh.Request) {
	for req := range reqs {
		var width, height int
		var ok bool
		switch req.Type {
		case "shell", "exec":
			if sess.handled {
				req.Reply(false, nil)
				continue
			}
			var payload = struct{ Value string }{}
			gossh.Unmarshal(req.Payload, &payload)
			sess.cmd, _ = shlex.Split(payload.Value, true)
			go func() {
				sess.handler(sess)
				sess.Exit(0)
			}()
			sess.handled = true
			req.Reply(true, nil)
		case "env":
			if sess.handled {
				req.Reply(false, nil)
				continue
			}
			var kv = struct{ Key, Value string }{}
			gossh.Unmarshal(req.Payload, &kv)
			sess.env = append(sess.env, fmt.Sprintf("%s=%s", kv.Key, kv.Value))
		case "pty-req":
			if sess.handled {
				req.Reply(false, nil)
				continue
			}
			if sess.ptyCb != nil {
				ok := sess.ptyCb(sess.conn.User(), &Permissions{sess.conn.Permissions})
				if !ok {
					req.Reply(false, nil)
					continue
				}
			}
			width, height, ok = parsePtyRequest(req.Payload)
			if ok {
				sess.pty = &Pty{Window{width, height}}
				sess.winch = make(chan Window)
				req.Reply(true, nil)
			}
		case "window-change":
			if sess.pty == nil {
				req.Reply(false, nil)
				continue
			}
			width, height, ok = parseWinchRequest(req.Payload)
			if ok {
				sess.pty.Window = Window{width, height}
				sess.winch <- sess.pty.Window
			}
		}
	}
}
<commit_msg>Always respond to PTY requests<commit_after>package ssh

import (
	"bytes"
	"fmt"
	"net"

	"github.com/anmitsu/go-shlex"
	gossh "golang.org/x/crypto/ssh"
)

// Session provides access to information about an SSH session and methods
// to read and write to the SSH channel with an embedded Channel interface from
// cypto/ssh.
//
// When Command() returns an empty slice, the user requested a shell. Otherwise
// the user is performing an exec with those command arguments.
//
// TODO: Signals
type Session interface {
	gossh.Channel

	// User returns the username used when establishing the SSH connection.
	User() string

	// RemoteAddr returns the net.Addr of the client side of the connection.
	RemoteAddr() net.Addr

	// Environ returns a copy of strings representing the environment set by the
	// user for this session, in the form "key=value".
	Environ() []string

	// Exit sends an exit status and then closes the session.
	Exit(code int) error

	// Command returns a shell parsed slice of arguments that were provided by the
	// user. Shell parsing splits the command string according to POSIX shell rules,
	// which considers quoting not just whitespace.
	Command() []string

	// PublicKey returns the PublicKey used to authenticate. If a public key was not
	// used it will return nil.
	PublicKey() PublicKey

	// Pty returns PTY information, a channel of window size changes, and a boolean
	// of whether or not a PTY was accepted for this session.
	Pty() (Pty, <-chan Window, bool)

	// TODO: Signals(c chan<- Signal)
}

type session struct {
	gossh.Channel
	conn    *gossh.ServerConn
	handler Handler
	handled bool
	pty     *Pty
	winch   chan Window
	env     []string
	ptyCb   PtyCallback
	cmd     []string
}

func (sess *session) Write(p []byte) (n int, err error) {
	if sess.pty != nil {
		// normalize \n to \r\n when pty is accepted
		p = bytes.Replace(p, []byte{'\n'}, []byte{'\r', '\n'}, -1)
		p = bytes.Replace(p, []byte{'\r', '\r', '\n'}, []byte{'\r', '\n'}, -1)
	}
	return sess.Channel.Write(p)
}

func (sess *session) PublicKey() PublicKey {
	if sess.conn.Permissions == nil {
		return nil
	}
	s, ok := sess.conn.Permissions.Extensions["_publickey"]
	if !ok {
		return nil
	}
	key, err := ParsePublicKey([]byte(s))
	if err != nil {
		return nil
	}
	return key
}

func (sess *session) Exit(code int) error {
	status := struct{ Status uint32 }{uint32(code)}
	_, err := sess.SendRequest("exit-status", false, gossh.Marshal(&status))
	if err != nil {
		return err
	}
	return sess.Close()
}

func (sess *session) User() string {
	return sess.conn.User()
}

func (sess *session) RemoteAddr() net.Addr {
	return sess.conn.RemoteAddr()
}

func (sess *session) Environ() []string {
	return append([]string(nil), sess.env...)
}

func (sess *session) Command() []string {
	return append([]string(nil), sess.cmd...)
}

func (sess *session) Pty() (Pty, <-chan Window, bool) {
	if sess.pty != nil {
		return *sess.pty, sess.winch, true
	}
	return Pty{}, sess.winch, false
}

func (sess *session) handleRequests(reqs <-chan *gossh.Request) {
	for req := range reqs {
		var width, height int
		var ok bool
		switch req.Type {
		case "shell", "exec":
			if sess.handled {
				req.Reply(false, nil)
				continue
			}
			var payload = struct{ Value string }{}
			gossh.Unmarshal(req.Payload, &payload)
			sess.cmd, _ = shlex.Split(payload.Value, true)
			go func() {
				sess.handler(sess)
				sess.Exit(0)
			}()
			sess.handled = true
			req.Reply(true, nil)
		case "env":
			if sess.handled {
				req.Reply(false, nil)
				continue
			}
			var kv = struct{ Key, Value string }{}
			gossh.Unmarshal(req.Payload, &kv)
			sess.env = append(sess.env, fmt.Sprintf("%s=%s", kv.Key, kv.Value))
		case "pty-req":
			if sess.handled {
				req.Reply(false, nil)
				continue
			}
			if sess.ptyCb != nil {
				ok := sess.ptyCb(sess.conn.User(), &Permissions{sess.conn.Permissions})
				if !ok {
					req.Reply(false, nil)
					continue
				}
			}
			width, height, ok = parsePtyRequest(req.Payload)
			if ok {
				sess.pty = &Pty{Window{width, height}}
				sess.winch = make(chan Window)
			}

			req.Reply(ok, nil)
		case "window-change":
			if sess.pty == nil {
				req.Reply(false, nil)
				continue
			}
			width, height, ok = parseWinchRequest(req.Payload)
			if ok {
				sess.pty.Window = Window{width, height}
				sess.winch <- sess.pty.Window
			}
		}
	}
}
<|endoftext|>


<commit_before>package data

import (
	"encoding/binary"
	"fmt"
	"io"
	"reflect"
)

type Decoder struct {
	r Reader
}

func NewDecoder(r Reader) *Decoder {
	return &Decoder{r}
}

func (dec *Decoder) Wire(typ NodeType) (Hashable, error) {
	version, err := dec.HashPrefix()
	if err != nil {
		return nil, err
	}
	switch version {
	case HP_LEAF_NODE:
		return dec.LedgerEntry()
	case HP_TRANSACTION_NODE:
		return dec.TransactionWithMetadata()
	case HP_INNER_NODE:
		return dec.CompressedInnerNode(typ)
	default:
		return nil, fmt.Errorf("Unknown hash prefix: %s", version.String())
	}
}

func (dec *Decoder) Prefix() (Hashable, error) {
	header, err := dec.Header()
	if err != nil {
		return nil, err
	}
	version, err := dec.HashPrefix()
	if err != nil {
		return nil, err
	}
	switch {
	case version == HP_INNER_NODE:
		return dec.InnerNode(header.NodeType)
	case header.NodeType == NT_LEDGER:
		return dec.Ledger()
	case header.NodeType == NT_TRANSACTION:
		return dec.Transaction()
	case header.NodeType == NT_TRANSACTION_NODE:
		return dec.TransactionWithMetadata()
	case header.NodeType == NT_ACCOUNT_NODE:
		return dec.LedgerEntry()
	default:
		return nil, fmt.Errorf("Unknown node type")
	}
}

func (dec *Decoder) Ledger() (*Ledger, error) {
	ledger := new(Ledger)
	return ledger, dec.read(&ledger.LedgerHeader)
}

func (dec *Decoder) Validation() (*Validation, error) {
	validation := new(Validation)
	v := reflect.ValueOf(validation)
	if err := dec.readObject(&v); err != nil {
		return nil, err
	}
	return validation, nil
}

func (dec *Decoder) HashPrefix() (HashPrefix, error) {
	var version HashPrefix
	return version, dec.read(&version)
}

func (dec *Decoder) Header() (*NodeHeader, error) {
	header := new(NodeHeader)
	return header, dec.read(header)
}

func (dec *Decoder) Hash() (*Hash256, error) {
	var h Hash256
	n, err := dec.r.Read(h[:])
	switch {
	case err != nil:
		return nil, err
	case n != len(h):
		return nil, fmt.Errorf("Bad hash")
	default:
		return &h, nil
	}
}

func (dec *Decoder) InnerNode(typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	for i := range inner.Children {
		if _, err := dec.r.Read(inner.Children[i][:]); err != nil {
			return nil, err
		}
	}
	return &inner, nil
}

func (dec *Decoder) CompressedInnerNode(typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	var entry CompressedNodeEntry
	for dec.read(&entry) == nil {
		inner.Children[entry.Pos] = entry.Hash
	}
	return &inner, nil
}

func (dec *Decoder) TransactionWithMetadata() (*TransactionWithMetaData, error) {
	br, err := NewVariableByteReader(dec.r)
	if err != nil {
		return nil, err
	}
	tx, err := NewDecoder(br).Transaction()
	if err != nil {
		return nil, err
	}
	txMeta := &TransactionWithMetaData{
		Transaction: tx,
	}
	br, err = NewVariableByteReader(dec.r)
	if err != nil {
		return nil, err
	}
	meta := reflect.ValueOf(&txMeta.MetaData)
	if err := NewDecoder(br).readObject(&meta); err != nil {
		return nil, err
	}
	return txMeta, nil
}

func (dec *Decoder) Transaction() (Transaction, error) {
	txType, err := dec.expectType("TransactionType")
	if err != nil {
		return nil, err
	}
	tx := TxFactory[txType]()
	v := reflect.ValueOf(tx)
	if err := dec.readObject(&v); err != nil {
		return nil, err
	}
	return tx, nil
}

func (dec *Decoder) LedgerEntry() (LedgerEntry, error) {
	leType, err := dec.expectType("LedgerEntryType")
	if err != nil {
		return nil, err
	}
	le := LedgerEntryFactory[leType]()
	v := reflect.ValueOf(le)
	// LedgerEntries have 32 bytes of hash suffixed
	// but don't have a variable bytes indicator
	lr := LimitedByteReader(dec.r, int64(dec.r.Len()-32))
	if err := NewDecoder(lr).readObject(&v); err != nil {
		return nil, err
	}
	return le, nil
}

func (dec *Decoder) next() (string, error) {
	var e enc
	if b, err := dec.r.ReadByte(); err != nil {
		return "", err
	} else {
		e.typ = b >> 4
		e.field = b & 0xF
	}
	var err error
	if e.typ == 0 {
		if e.typ, err = dec.r.ReadByte(); err != nil {
			return "", err
		}
	}
	if e.field == 0 {
		if e.field, err = dec.r.ReadByte(); err != nil {
			return "", err
		}
	}
	return encodings[e], nil
}

func (dec *Decoder) expectType(expected string) (uint16, error) {
	name, err := dec.next()
	if err != nil {
		return 0, err
	}
	if name != expected {
		return 0, fmt.Errorf("Unexpected type: %s expected: %s", name, expected)
	}
	var typ uint16
	return typ, dec.read(&typ)
}

func (dec *Decoder) read(dest interface{}) error {
	return binary.Read(dec.r, binary.BigEndian, dest)
}

func (dec *Decoder) readObject(v *reflect.Value) error {
	var err error
	for name, err := dec.next(); err == nil; name, err = dec.next() {
		fmt.Println(name, v, v.IsValid())
		switch name {
		case "EndOfObject":
			return nil
		case "EndOfArray":
			continue
		case "PreviousFields", "NewFields", "FinalFields":
			ledgerEntryType := uint16(v.Elem().FieldByName("LedgerEntryType").Uint())
			le := fieldsFactory[ledgerEntryType]()
			lePtr := reflect.ValueOf(le)
			if err := dec.readObject(&lePtr); err != nil {
				return err
			}
			v.Elem().FieldByName(name).Set(lePtr)
		case "ModifiedNode", "DeletedNode", "CreatedNode":
			var node AffectedNode
			n := reflect.ValueOf(&node)
			if err := dec.readObject(&n); err != nil {
				return err
			}
			var effect NodeEffect
			e := reflect.ValueOf(&effect)
			e.Elem().FieldByName(name).Set(n)
			affected := v.Elem().FieldByName("AffectedNodes")
			affected.Set(reflect.Append(affected, e.Elem()))
		case "Memo":
			var memo Memo
			m := reflect.ValueOf(&memo.Memo)
			if err := dec.readObject(&m); err != nil {
				return err
			}
			memos := v.Elem().FieldByName("Memos")
			memos.Set(reflect.Append(memos, reflect.ValueOf(memo)))
		default:
			// fmt.Println(v, name)
			field := v.Elem().FieldByName(name)
			if field.Kind() == reflect.Ptr {
				field.Set(reflect.New(field.Type().Elem()))
				field = field.Elem()
			}
			if !field.IsValid() {
				return fmt.Errorf("Unknown Field: %s", name)
			}
			switch f := field.Addr().Interface().(type) {
			case Wire:
				if err := f.Unmarshal(dec.r); err != nil {
					return err
				}
			case *uint64, *uint32, *uint16, *uint8, *TransactionResult, *LedgerEntryType, *TransactionType, *Index:
				if err := dec.read(f); err != nil {
					return err
				}
			default:
				if err := dec.readObject(&field); err != nil {
					return err
				}
			}
		}
	}
	if err == io.EOF {
		return nil
	}
	return err
}
<commit_msg>Remove debug line<commit_after>package data

import (
	"encoding/binary"
	"fmt"
	"io"
	"reflect"
)

type Decoder struct {
	r Reader
}

func NewDecoder(r Reader) *Decoder {
	return &Decoder{r}
}

func (dec *Decoder) Wire(typ NodeType) (Hashable, error) {
	version, err := dec.HashPrefix()
	if err != nil {
		return nil, err
	}
	switch version {
	case HP_LEAF_NODE:
		return dec.LedgerEntry()
	case HP_TRANSACTION_NODE:
		return dec.TransactionWithMetadata()
	case HP_INNER_NODE:
		return dec.CompressedInnerNode(typ)
	default:
		return nil, fmt.Errorf("Unknown hash prefix: %s", version.String())
	}
}

func (dec *Decoder) Prefix() (Hashable, error) {
	header, err := dec.Header()
	if err != nil {
		return nil, err
	}
	version, err := dec.HashPrefix()
	if err != nil {
		return nil, err
	}
	switch {
	case version == HP_INNER_NODE:
		return dec.InnerNode(header.NodeType)
	case header.NodeType == NT_LEDGER:
		return dec.Ledger()
	case header.NodeType == NT_TRANSACTION:
		return dec.Transaction()
	case header.NodeType == NT_TRANSACTION_NODE:
		return dec.TransactionWithMetadata()
	case header.NodeType == NT_ACCOUNT_NODE:
		return dec.LedgerEntry()
	default:
		return nil, fmt.Errorf("Unknown node type")
	}
}

func (dec *Decoder) Ledger() (*Ledger, error) {
	ledger := new(Ledger)
	return ledger, dec.read(&ledger.LedgerHeader)
}

func (dec *Decoder) Validation() (*Validation, error) {
	validation := new(Validation)
	v := reflect.ValueOf(validation)
	if err := dec.readObject(&v); err != nil {
		return nil, err
	}
	return validation, nil
}

func (dec *Decoder) HashPrefix() (HashPrefix, error) {
	var version HashPrefix
	return version, dec.read(&version)
}

func (dec *Decoder) Header() (*NodeHeader, error) {
	header := new(NodeHeader)
	return header, dec.read(header)
}

func (dec *Decoder) Hash() (*Hash256, error) {
	var h Hash256
	n, err := dec.r.Read(h[:])
	switch {
	case err != nil:
		return nil, err
	case n != len(h):
		return nil, fmt.Errorf("Bad hash")
	default:
		return &h, nil
	}
}

func (dec *Decoder) InnerNode(typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	for i := range inner.Children {
		if _, err := dec.r.Read(inner.Children[i][:]); err != nil {
			return nil, err
		}
	}
	return &inner, nil
}

func (dec *Decoder) CompressedInnerNode(typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	var entry CompressedNodeEntry
	for dec.read(&entry) == nil {
		inner.Children[entry.Pos] = entry.Hash
	}
	return &inner, nil
}

func (dec *Decoder) TransactionWithMetadata() (*TransactionWithMetaData, error) {
	br, err := NewVariableByteReader(dec.r)
	if err != nil {
		return nil, err
	}
	tx, err := NewDecoder(br).Transaction()
	if err != nil {
		return nil, err
	}
	txMeta := &TransactionWithMetaData{
		Transaction: tx,
	}
	br, err = NewVariableByteReader(dec.r)
	if err != nil {
		return nil, err
	}
	meta := reflect.ValueOf(&txMeta.MetaData)
	if err := NewDecoder(br).readObject(&meta); err != nil {
		return nil, err
	}
	return txMeta, nil
}

func (dec *Decoder) Transaction() (Transaction, error) {
	txType, err := dec.expectType("TransactionType")
	if err != nil {
		return nil, err
	}
	tx := TxFactory[txType]()
	v := reflect.ValueOf(tx)
	if err := dec.readObject(&v); err != nil {
		return nil, err
	}
	return tx, nil
}

func (dec *Decoder) LedgerEntry() (LedgerEntry, error) {
	leType, err := dec.expectType("LedgerEntryType")
	if err != nil {
		return nil, err
	}
	le := LedgerEntryFactory[leType]()
	v := reflect.ValueOf(le)
	// LedgerEntries have 32 bytes of hash suffixed
	// but don't have a variable bytes indicator
	lr := LimitedByteReader(dec.r, int64(dec.r.Len()-32))
	if err := NewDecoder(lr).readObject(&v); err != nil {
		return nil, err
	}
	return le, nil
}

func (dec *Decoder) next() (string, error) {
	var e enc
	if b, err := dec.r.ReadByte(); err != nil {
		return "", err
	} else {
		e.typ = b >> 4
		e.field = b & 0xF
	}
	var err error
	if e.typ == 0 {
		if e.typ, err = dec.r.ReadByte(); err != nil {
			return "", err
		}
	}
	if e.field == 0 {
		if e.field, err = dec.r.ReadByte(); err != nil {
			return "", err
		}
	}
	return encodings[e], nil
}

func (dec *Decoder) expectType(expected string) (uint16, error) {
	name, err := dec.next()
	if err != nil {
		return 0, err
	}
	if name != expected {
		return 0, fmt.Errorf("Unexpected type: %s expected: %s", name, expected)
	}
	var typ uint16
	return typ, dec.read(&typ)
}

func (dec *Decoder) read(dest interface{}) error {
	return binary.Read(dec.r, binary.BigEndian, dest)
}

func (dec *Decoder) readObject(v *reflect.Value) error {
	var err error
	for name, err := dec.next(); err == nil; name, err = dec.next() {
		// fmt.Println(name, v, v.IsValid())
		switch name {
		case "EndOfObject":
			return nil
		case "EndOfArray":
			continue
		case "PreviousFields", "NewFields", "FinalFields":
			ledgerEntryType := uint16(v.Elem().FieldByName("LedgerEntryType").Uint())
			le := fieldsFactory[ledgerEntryType]()
			lePtr := reflect.ValueOf(le)
			if err := dec.readObject(&lePtr); err != nil {
				return err
			}
			v.Elem().FieldByName(name).Set(lePtr)
		case "ModifiedNode", "DeletedNode", "CreatedNode":
			var node AffectedNode
			n := reflect.ValueOf(&node)
			if err := dec.readObject(&n); err != nil {
				return err
			}
			var effect NodeEffect
			e := reflect.ValueOf(&effect)
			e.Elem().FieldByName(name).Set(n)
			affected := v.Elem().FieldByName("AffectedNodes")
			affected.Set(reflect.Append(affected, e.Elem()))
		case "Memo":
			var memo Memo
			m := reflect.ValueOf(&memo.Memo)
			if err := dec.readObject(&m); err != nil {
				return err
			}
			memos := v.Elem().FieldByName("Memos")
			memos.Set(reflect.Append(memos, reflect.ValueOf(memo)))
		default:
			// fmt.Println(v, name)
			field := v.Elem().FieldByName(name)
			if field.Kind() == reflect.Ptr {
				field.Set(reflect.New(field.Type().Elem()))
				field = field.Elem()
			}
			if !field.IsValid() {
				return fmt.Errorf("Unknown Field: %s", name)
			}
			switch f := field.Addr().Interface().(type) {
			case Wire:
				if err := f.Unmarshal(dec.r); err != nil {
					return err
				}
			case *uint64, *uint32, *uint16, *uint8, *TransactionResult, *LedgerEntryType, *TransactionType, *Index:
				if err := dec.read(f); err != nil {
					return err
				}
			default:
				if err := dec.readObject(&field); err != nil {
					return err
				}
			}
		}
	}
	if err == io.EOF {
		return nil
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/droundy/goopt"
    "github.com/steakknife/keccak"
    "github.com/steakknife/securecompare"
    "bufio"
    "encoding/hex"
    "fmt"
    "hash"
    "io"
    "os"
    "regexp"
    "strconv"
)

// sha3sum [options] [files...]
//
//
// With no FILE, or when FILE is -, read standard input.
//
// -a 224
// -a 256 (default)
// -a 384
// -a 512
//
// -b binary (windows default)
// -t text (default)
//
// -c check
//
// -s silent
//

func die(msg string) {
    fmt.Fprintln(os.Stderr, msg)
    os.Exit(1)
}

func dieerr(err error) {
    die(fmt.Sprint(err))
}

const BUF_SIZE = 256*1024

var windows bool = func() bool {
    return os.Getenv("WINDIR") != ""
}()

func hashFile(filename string, algorithm int, portable, binary bool) (result string, err error) {
    var f *os.File
    if filename == "-" {
        f = os.Stdin
    } else {
        f, err = os.Open(filename)
        if err != nil {
            dieerr(err)
        }
    }
    defer f.Close()

    var h hash.Hash
    switch algorithm {
        case 224: h = keccak.New224()
        case 256: h = keccak.New256()
        case 384: h = keccak.New384()
        case 512: h = keccak.New512()
    }

    if binary || portable || !windows { // binary || portable
        buf := make([]byte, BUF_SIZE)
        for {
            n, err2 := f.Read(buf)
            if err2 != nil {
                if err2 != io.EOF {
                    err = err2
                }
                break
            }
            if n > 0 {
                h.Write(buf[:n])
            }
        }
    } else { // text on windows
        reader := bufio.NewReader(f)
        for {
            line, err2 := reader.ReadString('\n')
            if err2 != nil {
                if err2 != io.EOF {
                    err = err2
                }
                break
            }
            linelen := len(line)
            if (line[:linelen] == "\r") {
                line = line[:linelen-1]
            }
            h.Write([]byte(line))
        }
    }

    if err != nil {
        dieerr(err)
    }

    result = ""
    sum := h.Sum(nil)
    for _, b := range sum {
        result += fmt.Sprintf("%02x", b)
    }
    return
}

var tagRegexp = regexp.MustCompile("^SHA3-([0-9][0-9][0-9]) \\(([^)])\\)[ ]*=[ ]*([0-9A-Fa-f][0-9A-Fa-f]*)$")

// SHA3-XXX (filename) = hex
func parseTagHash(line string) (hash, fname string, algorithm int, portable, binary bool, err error) {
    if ! tagRegexp.MatchString(line) {
        err = fmt.Errorf("bad checksum line")
        return
    }
    // 0 = algorithm
    // 1 = filename
    // 2 = hash
    matches := tagRegexp.FindStringSubmatch(line)
    if len(matches) != 4 {
        err = fmt.Errorf("bad line")
        return
    }
    algorithm, err = strconv.Atoi(matches[1])
    if err != nil {
        return
    }
    if ! validAlgorithm(algorithm) {
        err = fmt.Errorf("bad algorithm")
        return
    }
    fname = matches[2]
    if len(fname) == 0 {
        err = fmt.Errorf("bad filename")
        return
    }
    hash = matches[3]
    if len(hash) != algorithm/4 {
        err = fmt.Errorf("bad hash")
        return
    }
    return
}

var normalRegexp = regexp.MustCompile("^([0-9A-Fa-f][0-9A-Fa-f]*)[ ][ ]*([*?])?(.+)$")

// hex filename
func parseNormalHash(line string) (hash, fname string, algorithm int, portable, binary bool, err error) {
    if ! normalRegexp.MatchString(line) {
        err = fmt.Errorf("bad checksum line")
        return
    }
    matches := normalRegexp.FindStringSubmatch(line)
    if len(matches) != 4 {
        err = fmt.Errorf("bad line")
        return
    }
    hash = matches[1]
    hashlen := len(hash)
    switch hashlen {
        case 224/4, 256/4, 384/4, 512/4: algorithm = hashlen*4
        default:
            err = fmt.Errorf("bad hash")
            return
    }
    portable = (matches[2] == "?")
    binary = (matches[2] == "*")
    fname = matches[3]
    if len(fname) == 0 {
        err = fmt.Errorf("bad filename")
        return
    }
    return
}

func parseHash(line string, tag bool) (hash, fname string, algorithm int, portable, binary bool, err error) {
    if tag {
        return parseTagHash(line)
    } else {
        return parseNormalHash(line)
    }
}

func validAlgorithm(algorithm int) bool {
    switch algorithm {
        case 224, 256, 384, 512: return true
        default:                 return false
    }
}

func readHashes(hashesFilename string, tag, strict bool) (hashes, filenames []string, algorithms []int, portables, binaries []bool) {
    f, err := os.Open(hashesFilename)
    if err != nil {
        dieerr(err)
    }
    defer f.Close()

    reader := bufio.NewReader(f)
    line := ""
    for {
        part, prefix, err := reader.ReadLine()
        if err != nil {
            if err == io.EOF {
                err = nil
            }
            return
        }

        line += string(part)
        if ! prefix {
            hash, fname, algorithm, portable, binary, err := parseHash(line, tag)
            if err != nil && strict {
                dieerr(err)
            }
            hashes = append(hashes, hash)
            filenames = append(filenames, fname)
            algorithms = append(algorithms, algorithm)
            portables = append(portables, portable)
            binaries = append(binaries, binary)
            line = ""
        }
    }
    return
}

func hashFiles(files []string, algorithm int, portable, binary, tag bool) (err error) {
    if len(files) == 0 {
        err = fmt.Errorf("missing files to check")
        return
    }
    for _, filename := range files {
        hash, err2 := hashFile(filename, algorithm, portable, binary)
        if err2 != nil {
            err = err2
            continue
        }
        if tag{
            fmt.Printf("SHA3-%d (%s) = %s\n", algorithm, filename, hash)
        } else {
            fmt.Printf("%s  ", hash)
            if portable {
                fmt.Print("?")
            } else if binary {
                fmt.Print("*")
            }
            fmt.Println(filename)
        }
    }
    return
}

func checkFiles(checkFilename string, binaryFlag, portableFlag, tagFlag, strictFlag, statusFlag bool) error {
    fmt.Println("checking ", checkFilename)
    bad := 0
    good := 0
    expectedHexHashes, filenames, algorithms, portables, binaries := readHashes(checkFilename, tagFlag, strictFlag)
    fmt.Println("checking files" , filenames)
    for i, filename := range filenames {
        actualHashHex, err := hashFile(filename, algorithms[i], portableFlag || portables[i], binaryFlag || binaries[i])
        if err != nil {
            if strictFlag {
                return err
            } else {
                continue
            }
        }

        actualHash, err := hex.DecodeString(actualHashHex)
        if err != nil {
            if strictFlag {
                return err
            } else {
                continue
            }
        }
        expectedHash, err := hex.DecodeString(expectedHexHashes[i])
        if err != nil {
            if strictFlag {
                return err
            } else {
                continue
            }
        }
        if securecompare.Equal(actualHash, expectedHash) {
            if ! statusFlag {
                fmt.Printf("%s: OK\n", filename)
            }
            good++
        } else {
            if ! statusFlag {
                fmt.Printf("%s: FAILED\n", filename)
            }
            bad++
        }
    }
    if ! statusFlag && bad > 0 {
        fmt.Fprintf(os.Stderr, "sha3sum: WARNING %d of %d computed checksums did NOT match\n", bad, (good+bad))
    }
    return nil
}

func main() {
    goopt.Summary = "Print or check SHA3 checksums"

    algorithm := goopt.Int([]string{"-a", "--algorithm"}, 256, "224, 256 (default), 384, 512")
    binary    := goopt.Flag([]string{"-b", "--binary"},  []string{}, "read files in binary mode (default on DOS/Windows)", "")
    check     := goopt.String([]string{"-c", "--check"}, "", "check SHA3 sums against given list")
    portable  := goopt.Flag([]string{"-p", "--portable"}, []string{}, "read files in portable mode (same digest on Windows/Unix/Mac)", "")
    text      := goopt.Flag([]string{"-t", "--text"}, []string{}, "read files in text mode (default)", "")

    tag       := goopt.Flag([]string{"--tag"}, []string{}, "create a BSD-style checksum", "")

    // check options

    status    := goopt.Flag([]string{"-s", "--status", "-w", "--warn"}, []string{}, "don't output anything, status code shows success", "")
    quiet     := goopt.Flag([]string{"-q", "--quiet"}, []string{}, "don't print OK for each successfully verified file", "")
    strict    := goopt.Flag([]string{"--strict"}, []string{}, "with --check, exit non-zero for any invalid input", "")

    version   := goopt.Flag([]string{"-v", "--version"}, []string{}, "output version information and exit", "")

    goopt.Parse(nil)

    if algorithm == nil && ! validAlgorithm(*algorithm) {
        die("bad algorithm")
    }

    binaryFlag := (binary != nil && *binary)
    portableFlag := (portable != nil && *portable)
    textFlag := (text != nil && *text)

    tagFlag := (tag != nil && *tag)

    statusFlag := (status != nil && *status)
    quietFlag := (quiet != nil && *quiet)
    strictFlag := (strict != nil && *strict)

    versionFlag := (version != nil && *version)

    if textFlag && binaryFlag {
        die("cannot specify both text and binary")
    }

    if (check == nil && *check != "") && (statusFlag || quietFlag || strictFlag) {
        die("silent, warn, strict and/or quiet can only be used with check")
    }

    var files []string
    if len(goopt.Args) == 0 {
        files = []string{"-"}
    } else {
        files = goopt.Args
    }

    if versionFlag {
        fmt.Println("sha3sum 1.0")
        return
    }

    var err error
    if *check == "" {
        err = hashFiles(files, *algorithm, portableFlag, binaryFlag, tagFlag)
    } else {
        checkFilename := *check
        err = checkFiles(checkFilename, binaryFlag, portableFlag, tagFlag, strictFlag, statusFlag)
    }
    if err != nil {
        os.Exit(1)
    }
}
<commit_msg>binary only<commit_after>package main

import (
    "github.com/droundy/goopt"
    "github.com/steakknife/keccak"
    "github.com/steakknife/securecompare"
    "bufio"
    "encoding/hex"
    "fmt"
    "hash"
    "io"
    "os"
    "regexp"
    "strconv"
)

// sha3sum [options] [files...]
//
//
// With no FILE, or when FILE is -, read standard input.
//
// -a 224
// -a 256 (default)
// -a 384
// -a 512
//
// -b binary (windows default)
// -t text (default)
//
// -c check
//
// -s silent
//

func die(msg string) {
    fmt.Fprintln(os.Stderr, msg)
    os.Exit(1)
}

func dieerr(err error) {
    die(fmt.Sprint(err))
}

const BUF_SIZE = 256*1024

func hashFile(filename string, algorithm int) (result string, err error) {
    var f *os.File
    if filename == "-" {
        f = os.Stdin
    } else {
        f, err = os.Open(filename)
        if err != nil {
            dieerr(err)
        }
    }
    defer f.Close()

    var h hash.Hash
    switch algorithm {
        case 224: h = keccak.New224()
        case 256: h = keccak.New256()
        case 384: h = keccak.New384()
        case 512: h = keccak.New512()
    }

    buf := make([]byte, BUF_SIZE)
    for {
        n, err2 := f.Read(buf)
        if err2 != nil {
            if err2 != io.EOF {
                err = err2
            }
            break
        }
        if n > 0 {
            h.Write(buf[:n])
        }
    }

    if err != nil {
        dieerr(err)
    }

    result = ""
    sum := h.Sum(nil)
    for _, b := range sum {
        result += fmt.Sprintf("%02x", b)
    }
    return
}

var tagRegexp = regexp.MustCompile("^SHA3-([0-9][0-9][0-9]) \\(([^)])\\)[ ]*=[ ]*([0-9A-Fa-f][0-9A-Fa-f]*)$")

// SHA3-XXX (filename) = hex
func parseTagHash(line string) (hash, fname string, algorithm int, err error) {
    if ! tagRegexp.MatchString(line) {
        err = fmt.Errorf("bad checksum line")
        return
    }
    // 0 = algorithm
    // 1 = filename
    // 2 = hash
    matches := tagRegexp.FindStringSubmatch(line)
    if len(matches) != 4 {
        err = fmt.Errorf("bad line")
        return
    }
    algorithm, err = strconv.Atoi(matches[1])
    if err != nil {
        return
    }
    if ! validAlgorithm(algorithm) {
        err = fmt.Errorf("bad algorithm")
        return
    }
    fname = matches[2]
    if len(fname) == 0 {
        err = fmt.Errorf("bad filename")
        return
    }
    hash = matches[3]
    if len(hash) != algorithm/4 {
        err = fmt.Errorf("bad hash")
        return
    }
    return
}

var normalRegexp = regexp.MustCompile("^([0-9A-Fa-f][0-9A-Fa-f]*)[ ][ ]*(.+)$")

// hex filename
func parseNormalHash(line string) (hash, fname string, algorithm int, err error) {
    if ! normalRegexp.MatchString(line) {
        err = fmt.Errorf("bad checksum line")
        return
    }
    matches := normalRegexp.FindStringSubmatch(line)
    if len(matches) != 4 {
        err = fmt.Errorf("bad line")
        return
    }
    hash = matches[1]
    hashlen := len(hash)
    switch hashlen {
        case 224/4, 256/4, 384/4, 512/4: algorithm = hashlen*4
        default:
            err = fmt.Errorf("bad hash")
            return
    }
    fname = matches[2]
    if len(fname) == 0 {
        err = fmt.Errorf("bad filename")
        return
    }
    return
}

func parseHash(line string, tag bool) (hash, fname string, algorithm int, err error) {
    if tag {
        return parseTagHash(line)
    } else {
        return parseNormalHash(line)
    }
}

func validAlgorithm(algorithm int) bool {
    switch algorithm {
        case 224, 256, 384, 512: return true
        default:                 return false
    }
}

func readHashes(hashesFilename string, tag, strict bool) (hashes, filenames []string, algorithms []int) {
    f, err := os.Open(hashesFilename)
    if err != nil {
        dieerr(err)
    }
    defer f.Close()

    reader := bufio.NewReader(f)
    line := ""
    for {
        part, prefix, err := reader.ReadLine()
        if err != nil {
            if err == io.EOF {
                err = nil
            }
            return
        }

        line += string(part)
        if ! prefix {
            hash, fname, algorithm, err := parseHash(line, tag)
            if err != nil && strict {
                dieerr(err)
            }
            hashes = append(hashes, hash)
            filenames = append(filenames, fname)
            algorithms = append(algorithms, algorithm)
            line = ""
        }
    }
    return
}

func hashFiles(files []string, algorithm int, tag bool) (err error) {
    if len(files) == 0 {
        err = fmt.Errorf("missing files to check")
        return
    }
    for _, filename := range files {
        hash, err2 := hashFile(filename, algorithm)
        if err2 != nil {
            err = err2
            continue
        }
        if tag{
            fmt.Printf("SHA3-%d (%s) = %s\n", algorithm, filename, hash)
        } else {
            fmt.Printf("%s  %s\n", hash, filename)
        }
    }
    return
}

func checkFiles(checkFilename string, tagFlag, strictFlag, statusFlag bool) error {
    fmt.Println("checking ", checkFilename)
    bad := 0
    good := 0
    expectedHexHashes, filenames, algorithms := readHashes(checkFilename, tagFlag, strictFlag)
    fmt.Println("checking files" , filenames)
    for i, filename := range filenames {
        actualHashHex, err := hashFile(filename, algorithms[i])
        if err != nil {
            if strictFlag {
                return err
            } else {
                continue
            }
        }

        actualHash, err := hex.DecodeString(actualHashHex)
        if err != nil {
            if strictFlag {
                return err
            } else {
                continue
            }
        }
        expectedHash, err := hex.DecodeString(expectedHexHashes[i])
        if err != nil {
            if strictFlag {
                return err
            } else {
                continue
            }
        }
        if securecompare.Equal(actualHash, expectedHash) {
            if ! statusFlag {
                fmt.Printf("%s: OK\n", filename)
            }
            good++
        } else {
            if ! statusFlag {
                fmt.Printf("%s: FAILED\n", filename)
            }
            bad++
        }
    }
    if ! statusFlag && bad > 0 {
        fmt.Fprintf(os.Stderr, "sha3sum: WARNING %d of %d computed checksums did NOT match\n", bad, (good+bad))
    }
    return nil
}

func main() {
    goopt.Summary = "Print or check SHA3 checksums"

    algorithm := goopt.Int([]string{"-a", "--algorithm"}, 256, "224, 256 (default), 384, 512")
    check     := goopt.String([]string{"-c", "--check"}, "", "check SHA3 sums against given list")

    tag       := goopt.Flag([]string{"--tag"}, []string{}, "create a BSD-style checksum", "")

    // check options

    status    := goopt.Flag([]string{"-s", "--status", "-w", "--warn"}, []string{}, "don't output anything, status code shows success", "")
    quiet     := goopt.Flag([]string{"-q", "--quiet"}, []string{}, "don't print OK for each successfully verified file", "")
    strict    := goopt.Flag([]string{"--strict"}, []string{}, "with --check, exit non-zero for any invalid input", "")

    version   := goopt.Flag([]string{"-v", "--version"}, []string{}, "output version information and exit", "")

    goopt.Parse(nil)

    if algorithm == nil && ! validAlgorithm(*algorithm) {
        die("bad algorithm")
    }

    tagFlag := (tag != nil && *tag)

    statusFlag := (status != nil && *status)
    quietFlag := (quiet != nil && *quiet)
    strictFlag := (strict != nil && *strict)

    versionFlag := (version != nil && *version)

    if (check == nil && *check != "") && (statusFlag || quietFlag || strictFlag) {
        die("silent, warn, strict and/or quiet can only be used with check")
    }

    var files []string
    if len(goopt.Args) == 0 {
        files = []string{"-"}
    } else {
        files = goopt.Args
    }

    if versionFlag {
        fmt.Println("sha3sum 1.0")
        return
    }

    var err error
    if *check == "" {
        err = hashFiles(files, *algorithm, tagFlag)
    } else {
        checkFilename := *check
        err = checkFiles(checkFilename, tagFlag, strictFlag, statusFlag)
    }
    if err != nil {
        os.Exit(1)
    }
}
<|endoftext|>


<commit_before>package signify

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/agl/ed25519"
)

const (
	commentHdr = "untrusted comment: "
)

var (
	algoEd     = []byte{'E', 'd'}
	algoBcrypt = []byte{'B', 'K'}
)

type PrivateKey [ed25519.PrivateKeySize]byte
type PublicKey [ed25519.PublicKeySize]byte
type Signature [ed25519.SignatureSize]byte

type rawEncryptedKey struct {
	PKAlgo      [2]byte
	KDFAlgo     [2]byte
	KDFRounds   uint32
	Salt        [16]byte
	Checksum    [8]byte
	Fingerprint [8]byte
	PrivateKey  [ed25519.PrivateKeySize]byte
}

type rawPublicKey struct {
	PKAlgo      [2]byte
	Fingerprint [8]byte
	PublicKey   [ed25519.PublicKeySize]byte
}

type rawSignature struct {
	PKAlgo      [2]byte
	Fingerprint [8]byte
	Signature   [ed25519.SignatureSize]byte
}

func ReadFile(r io.Reader) (comment string, content []byte, err error) {
	sc := bufio.NewScanner(r)

	if !sc.Scan() {
		return "", nil, fmt.Errorf("signify: read error %s", sc.Err())
	}
	comment = sc.Text()
	if !strings.HasPrefix(comment, commentHdr) {
		return "", nil, errors.New("signify: missing header")
	}
	comment = comment[len(commentHdr):]

	if !sc.Scan() {
		return "", nil, fmt.Errorf("signify: read error %s", sc.Err())
	}
	content, err = base64.StdEncoding.DecodeString(sc.Text())

	return
}

func parseRawEncryptedKey(data []byte) (*rawEncryptedKey, error) {
	var ek rawEncryptedKey
	if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &ek); err != nil {
		return nil, err
	}
	return &ek, nil
}

func parseRawPublicKey(data []byte) (*rawPublicKey, error) {
	var pub rawPublicKey
	if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &pub); err != nil {
		return nil, err
	}
	return &pub, nil
}

func parseRawSignature(data []byte) (*rawSignature, error) {
	var sig rawSignature
	if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &sig); err != nil {
		return nil, err
	}
	return &sig, nil
}

func ParsePrivateKey(data, passphrase []byte) (*PrivateKey, error) {
	if !bytes.Equal(algoEd, data[:2]) {
		return nil, errors.New("signify: unknown public key algorithm")
	}
	if !bytes.Equal(algoBcrypt, data[2:4]) {
		return nil, errors.New("signify: unknown kdf algorithm")
	}

	rek, err := parseRawEncryptedKey(data)
	if err != nil {
		return nil, err
	}

	priv := PrivateKey(rek.PrivateKey)
	return &priv, nil
}

func ParsePublicKey(data []byte) (*PublicKey, error) {
	if !bytes.Equal(algoEd, data[:2]) {
		return nil, errors.New("signify: unknown public key algorithm")
	}

	rpk, err := parseRawPublicKey(data)
	if err != nil {
		return nil, err
	}

	pk := PublicKey(rpk.PublicKey)
	return &pk, nil
}

func ParseSignature(data []byte) (*Signature, error) {
	if !bytes.Equal(algoEd, data[:2]) {
		return nil, errors.New("signify: unknown public key algorithm")
	}

	rs, err := parseRawSignature(data)
	if err != nil {
		return nil, err
	}

	sig := Signature(rs.Signature)
	return &sig, nil
}
<commit_msg>PrivateKey decryption<commit_after>package signify

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/agl/ed25519"
	"github.com/ebfe/bcrypt_pbkdf"
)

const (
	commentHdr = "untrusted comment: "
)

var (
	algoEd     = []byte{'E', 'd'}
	algoBcrypt = []byte{'B', 'K'}
)

type PrivateKey [ed25519.PrivateKeySize]byte
type PublicKey [ed25519.PublicKeySize]byte
type Signature [ed25519.SignatureSize]byte

type rawEncryptedKey struct {
	PKAlgo      [2]byte
	KDFAlgo     [2]byte
	KDFRounds   uint32
	Salt        [16]byte
	Checksum    [8]byte
	Fingerprint [8]byte
	PrivateKey  [ed25519.PrivateKeySize]byte
}

type rawPublicKey struct {
	PKAlgo      [2]byte
	Fingerprint [8]byte
	PublicKey   [ed25519.PublicKeySize]byte
}

type rawSignature struct {
	PKAlgo      [2]byte
	Fingerprint [8]byte
	Signature   [ed25519.SignatureSize]byte
}

func ReadFile(r io.Reader) (comment string, content []byte, err error) {
	sc := bufio.NewScanner(r)

	if !sc.Scan() {
		return "", nil, fmt.Errorf("signify: read error %s", sc.Err())
	}
	comment = sc.Text()
	if !strings.HasPrefix(comment, commentHdr) {
		return "", nil, errors.New("signify: missing header")
	}
	comment = comment[len(commentHdr):]

	if !sc.Scan() {
		return "", nil, fmt.Errorf("signify: read error %s", sc.Err())
	}
	content, err = base64.StdEncoding.DecodeString(sc.Text())

	return
}

func parseRawEncryptedKey(data []byte) (*rawEncryptedKey, error) {
	var ek rawEncryptedKey
	if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &ek); err != nil {
		return nil, err
	}
	return &ek, nil
}

func parseRawPublicKey(data []byte) (*rawPublicKey, error) {
	var pub rawPublicKey
	if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &pub); err != nil {
		return nil, err
	}
	return &pub, nil
}

func parseRawSignature(data []byte) (*rawSignature, error) {
	var sig rawSignature
	if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &sig); err != nil {
		return nil, err
	}
	return &sig, nil
}

func decryptPrivateKey(ek *[ed25519.PrivateKeySize]byte, passphrase, salt []byte, rounds int) *PrivateKey {
	var priv PrivateKey
	if rounds > 0 {
		xorkey := bcrypt_pbkdf.Key(passphrase, salt, rounds, ed25519.PrivateKeySize)
		for i := range priv {
			priv[i] = ek[i] ^ xorkey[i]
		}
	} else {
		priv = PrivateKey(*ek)
	}
	return &priv
}

func ParsePrivateKey(data, passphrase []byte) (*PrivateKey, error) {
	if !bytes.Equal(algoEd, data[:2]) {
		return nil, errors.New("signify: unknown public key algorithm")
	}
	if !bytes.Equal(algoBcrypt, data[2:4]) {
		return nil, errors.New("signify: unknown kdf algorithm")
	}

	rek, err := parseRawEncryptedKey(data)
	if err != nil {
		return nil, err
	}

	priv := decryptPrivateKey(&rek.PrivateKey, passphrase, rek.Salt[:], int(rek.KDFRounds))
	return priv, nil
}

func ParsePublicKey(data []byte) (*PublicKey, error) {
	if !bytes.Equal(algoEd, data[:2]) {
		return nil, errors.New("signify: unknown public key algorithm")
	}

	rpk, err := parseRawPublicKey(data)
	if err != nil {
		return nil, err
	}

	pk := PublicKey(rpk.PublicKey)
	return &pk, nil
}

func ParseSignature(data []byte) (*Signature, error) {
	if !bytes.Equal(algoEd, data[:2]) {
		return nil, errors.New("signify: unknown public key algorithm")
	}

	rs, err := parseRawSignature(data)
	if err != nil {
		return nil, err
	}

	sig := Signature(rs.Signature)
	return &sig, nil
}
<|endoftext|>


<commit_before>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx goa.Context) []{{$typeName}}
	Get(ctx goa.Context, id int) ({{$typeName}}, error)
	Add(ctx goa.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx goa.Context, o {{$typeName}}) (error)
	Delete(ctx goa.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx goa.Context, parentid int) []{{$typeName}} {

	var objs []{{$typeName}}
    {{ if ne $belongsto "" }}m.DB.Scopes({{$typeName}}Filter(ctx.{{demodel $belongsto}}ID, &m.DB)).Find(&objs){{ else }} m.DB.Find(&objs) {{end}}
	return objs
}

func (m *{{$typeName}}DB) Get(ctx goa.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx goa.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx goa.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx goa.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx goa.Context)  error {
	var obj {{$typeName}}

	assoc_id := ctx.{{index $pieces 1}}ID
	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = assoc_id
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx goa.Context) error {
	var obj {{$typeName}}
	assoc_id, err  := strconv.Atoi(ctx.Payload.{{index $pieces 1}}Id)
	if err != nil {
		return err
	}
	var assoc {{index $pieces 1}}
	assoc.ID = assoc_id
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx goa.Context)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = ctx.{{$typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}

type Mock{{$typeName}}Storage struct {
	{{$typeName}}List  map[int]{{$typeName}}
	nextID int
	mut sync.Mutex
}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}

func NewMock{{$typeName}}Storage() *Mock{{$typeName}}Storage {
	ml := make(map[int]{{$typeName}}, 0)
	return &Mock{{$typeName}}Storage{ {{$typeName}}List: ml}
}

func (db *Mock{{$typeName}}Storage) List(ctx goa.Context) []{{$typeName}} {
	var list []{{$typeName}} = make([]{{$typeName}}, 0)
	for _, v := range db.{{$typeName}}List {
		list = append(list, v)
	}
{{if ne $belongsto ""}}
return filter{{$typeName}}By{{$belongsto}}(ctx.{{$belongsto}}ID, list) {{else}}return list{{end}}
}

func (db *Mock{{$typeName}}Storage) Get(ctx goa.Context) ({{$typeName}}, error) {

	var obj {{$typeName}}

	obj, ok := db.{{$typeName}}List[int(ctx.{{demodel $typeName}}ID)]
	if ok {
		return obj, nil
	} else {
		return obj, errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Add(ctx goa.Context)  ({{$typeName}}, error) {
	u := {{$typeName}}FromCreatePayload(ctx)
	db.mut.Lock()
	db.nextID = db.nextID + 1
	u.ID = db.nextID
	db.mut.Unlock()

	db.{{$typeName}}List[u.ID] = u
	return u, nil
}

func (db *Mock{{$typeName}}Storage) Update(ctx goa.Context) error {
	id := int(ctx.{{demodel $typeName}}ID)
	_, ok := db.{{$typeName}}List[id]
	if ok {
		db.{{$typeName}}List[id] = {{$typeName}}FromUpdatePayload(ctx)
		return  nil
	} else {
		return errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Delete(ctx goa.Context)  error {
	_, ok := db.{{$typeName}}List[int(ctx.{{demodel $typeName}}ID)]
	if ok {
		delete(db.{{$typeName}}List, int(ctx.{{demodel $typeName}}ID))
		return  nil
	} else {
		return  errors.New("Could not delete this user")
	}
}
`
<commit_msg>decouple contexts<commit_after>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx goa.Context) []{{$typeName}}
	Get(ctx goa.Context, id int) ({{$typeName}}, error)
	Add(ctx goa.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx goa.Context, o {{$typeName}}) (error)
	Delete(ctx goa.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx goa.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx goa.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx goa.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx goa.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx goa.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx goa.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx goa.Context, {{$lower}}ID int) error {
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err = m.DB.Model(&{{$lower}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx goa.Context)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = ctx.{{$typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}

type Mock{{$typeName}}Storage struct {
	{{$typeName}}List  map[int]{{$typeName}}
	nextID int
	mut sync.Mutex
}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}

func NewMock{{$typeName}}Storage() *Mock{{$typeName}}Storage {
	ml := make(map[int]{{$typeName}}, 0)
	return &Mock{{$typeName}}Storage{ {{$typeName}}List: ml}
}

func (db *Mock{{$typeName}}Storage) List(ctx goa.Context) []{{$typeName}} {
	var list []{{$typeName}} = make([]{{$typeName}}, 0)
	for _, v := range db.{{$typeName}}List {
		list = append(list, v)
	}
{{if ne $belongsto ""}}
return Filter{{$typeName}}By{{$belongsto}}(ctx.{{$belongsto}}ID, list) {{else}}return list{{end}}
}

func (db *Mock{{$typeName}}Storage) Get(ctx goa.Context) ({{$typeName}}, error) {

	var obj {{$typeName}}

	obj, ok := db.{{$typeName}}List[int(ctx.{{demodel $typeName}}ID)]
	if ok {
		return obj, nil
	} else {
		return obj, errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Add(ctx goa.Context)  ({{$typeName}}, error) {
	u := {{$typeName}}FromCreatePayload(ctx)
	db.mut.Lock()
	db.nextID = db.nextID + 1
	u.ID = db.nextID
	db.mut.Unlock()

	db.{{$typeName}}List[u.ID] = u
	return u, nil
}

func (db *Mock{{$typeName}}Storage) Update(ctx goa.Context) error {
	id := int(ctx.{{demodel $typeName}}ID)
	_, ok := db.{{$typeName}}List[id]
	if ok {
		db.{{$typeName}}List[id] = {{$typeName}}FromUpdatePayload(ctx)
		return  nil
	} else {
		return errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Delete(ctx goa.Context)  error {
	_, ok := db.{{$typeName}}List[int(ctx.{{demodel $typeName}}ID)]
	if ok {
		delete(db.{{$typeName}}List, int(ctx.{{demodel $typeName}}ID))
		return  nil
	} else {
		return  errors.New("Could not delete this user")
	}
}
`
<|endoftext|>


<commit_before>/**
 * @file team_test.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU AGPLv3
 * @date November, 2015
 * @brief test work with team table
 */

package db

import (
	"errors"
	"fmt"
	"testing"
)

func TestCreateTeamTable(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	err = createTeamTable(db)
	if err != nil {
		panic(err)
	}
}

func TestAddTeam(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	team := Team{255, "n", "e", "d", "l", false}

	err = AddTeam(db, &team)
	if err != nil {
		panic(err)
	}

	if team.ID != 1 {
		panic(errors.New("Team id not correct"))
	}
}

// Test add team with closed database
func TestFailAddTeam(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	db.Close()

	err = AddTeam(db, &Team{})
	if err == nil {
		panic(err)
	}
}

func TestGetTeams(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	nteams := 150

	for i := 0; i < nteams; i++ {

		team := Team{255, fmt.Sprintf("%d", i),
			"e", "d", "l", false}

		err = AddTeam(db, &team)
		if err != nil {
			panic(err)
		}
	}

	teams, err := GetTeams(db)
	if err != nil {
		panic(err)
	}

	if len(teams) != nteams {
		panic(errors.New("Mismatch get teams length"))
	}

	for i := 0; i < nteams; i++ {

		if teams[i].Name != fmt.Sprintf("%d", i) && teams[i].ID != i {
			panic(errors.New("Get invalid team"))
		}
	}
}

// Test get teams with closed database
func TestFailGetTeams(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	db.Close()

	_, err = GetTeams(db)
	if err == nil {
		panic(err)
	}
}
<commit_msg>Add test for GetTeamIDByToken<commit_after>/**
 * @file team_test.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU AGPLv3
 * @date November, 2015
 * @brief test work with team table
 */

package db

import (
	"errors"
	"fmt"
	"testing"
)

func TestCreateTeamTable(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	err = createTeamTable(db)
	if err != nil {
		panic(err)
	}
}

func TestAddTeam(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	team := Team{255, "n", "e", "d", "l", false}

	err = AddTeam(db, &team)
	if err != nil {
		panic(err)
	}

	if team.ID != 1 {
		panic(errors.New("Team id not correct"))
	}
}

// Test add team with closed database
func TestFailAddTeam(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	db.Close()

	err = AddTeam(db, &Team{})
	if err == nil {
		panic(err)
	}
}

func TestGetTeams(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	nteams := 150

	for i := 0; i < nteams; i++ {

		team := Team{255, fmt.Sprintf("%d", i),
			"e", "d", "l", false}

		err = AddTeam(db, &team)
		if err != nil {
			panic(err)
		}
	}

	teams, err := GetTeams(db)
	if err != nil {
		panic(err)
	}

	if len(teams) != nteams {
		panic(errors.New("Mismatch get teams length"))
	}

	for i := 0; i < nteams; i++ {

		if teams[i].Name != fmt.Sprintf("%d", i) && teams[i].ID != i {
			panic(errors.New("Get invalid team"))
		}
	}
}

// Test get teams with closed database
func TestFailGetTeams(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	db.Close()

	_, err = GetTeams(db)
	if err == nil {
		panic(err)
	}
}

func TestGetTeamIDByToken(*testing.T) {

	db, err := InitDatabase(dbPath)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	token := "TOKEN_TOKEN_TOKEN"

	team := Team{ID: 255, Name: "n", Email: "e", Desc: "d",
		Token: token, Test: false}

	err = AddTeam(db, &team)
	if err != nil {
		panic(err)
	}

	teamID, err := GetTeamIDByToken(db, token)
	if err != nil {
		panic(err)
	}

	if teamID != team.ID {
		panic("team id mismatch")
	}
}
<|endoftext|>