<commit_before>package main

import (
	"fmt"
	"html/template"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"golang.org/x/oauth2"

	"github.com/dhowden/tag"
	"google.golang.org/api/plus/v1"

	"my-git.appspot.com/go.google.musicmanager"
)

var funcMap = map[string]interface{}{
	"incr": func(i int) int { return i + 1 },
	"time": unix2Time,
}
var scopes = []string{musicmanager.Scope, plus.PlusMeScope}
var conf = googleMustConfigFromFile("credentials.json", scopes...)
var tpls = template.Must(template.New("static").
	Funcs(funcMap).
	ParseGlob("static/*.tpl"))

func init() {
	http.Handle("/static/", http.FileServer(http.Dir(".")))
	http.Handle("/auth", &REST{Get: auth})
	http.Handle("/oauth2callback", &REST{Get: oauth2callback})
	http.Handle("/register", &REST{
		Init: initMusicManager,
		Get:  register,
	})
	http.Handle("/tracks/", &REST{
		Init:   initMusicManager,
		Get:    tracksGet,
		List:   tracksList,
		Insert: tracksInsert,
	})
}

func auth(_ interface{}, w http.ResponseWriter, r *http.Request) error {
	state, err := nonce(32)
	if err != nil {
		return err
	}
	conf.RedirectURL = getRedirectURL(r)
	httpSetCookie(w, r, "state", state)
	httpSetCookie(w, r, "redirect", r.FormValue("redirect"))
	http.Redirect(w, r, conf.AuthCodeURL(state), http.StatusFound)
	return nil
}

func oauth2callback(_ interface{}, w http.ResponseWriter, r *http.Request) error {
	// Confirm that the state matches the nonce we stored
	// (See https://tools.ietf.org/html/rfc6749#section-10.12.)
	rstate := r.FormValue("state")
	astate, err := r.Cookie("state")
	if err != nil || rstate != astate.Value {
		return &RESTError{
			Code: http.StatusBadRequest,
			Message: "state parameter and cookie mismatch" +
				"; have you perhaps disabled cookies?",
		}
	}
	// Exchange the authorization code for an access token.
	c := getContext(r)
	tok, err := conf.Exchange(c, r.FormValue("code"))
	if err != nil {
		return err
	}
	// BUG(lor): Google Play Music does not allow downloading tracks
	// with an uploader_id that is not sufficiently
	// "MAC address-like" (perhaps it only checks for a colon?)
	// The /oauth2callback endpoint generates the uploader_id by
	// injecting a colon between every two digits of the user's
	// Google Account ID, which appears to suffice.
	client := conf.Client(c, tok)
	plus, err := plus.New(client)
	if err != nil {
		return err
	}
	person, err := plus.People.Get("me").Do()
	if err != nil {
		return err
	}
	id, err := regexpReplaceAllString(`(..)`, person.Id, "$1:")
	if err != nil {
		return err
	}
	// Wipe the state and redirect cookies, no longer necessary,
	// and store the access token and uploader ID as cookies.
	httpSetCookie(w, r, "state", "")
	httpSetCookie(w, r, "redirect", "")
	httpSetCookie(w, r, "access_token", tok.AccessToken)
	httpSetCookie(w, r, "uploader_id", id)
	// We autoredirect to the registration endpoint for convenience.
	// If the redirect cookie was provided, remember to tell the
	// registration endpoint to continue there after success.
	registerURL := "/register"
	redirect, err := r.Cookie("redirect")
	if err == nil && redirect.Value != "" {
		registerURL += "?redirect=" + url.QueryEscape(redirect.Value)
	}
	http.Redirect(w, r, registerURL, http.StatusFound)
	return nil
}

func initMusicManager(r *http.Request) (interface{}, error) {
	// If either the access token or uploader ID cookie is missing,
	// autoredirect to the start of the authorization flow rather
	// than just report an error.  The redirect parameter lets the
	// user continue right where they left off.

	// BUG(lor): If the access_token cookie expires just before
	// uploading a new track, the track will need to be resubmitted
	// after the auth flow has finished, as the flow cannot preserve
	// POST data.
	tok, _ := r.Cookie("access_token")
	id, _ := r.Cookie("uploader_id")
	if tok == nil || id == nil {
		path := url.QueryEscape(r.URL.Path + "?" + r.URL.RawQuery)
		return nil, &RESTError{
			Code:     http.StatusFound,
			Message:  "missing credentials",
			Location: "/auth?redirect=" + path,
		}
	}
	// Create and return a new Music Manager service.
	c := getContext(r)
	client := conf.Client(c, &oauth2.Token{AccessToken: tok.Value})
	client.Transport.(*oauth2.Transport).Base = getTransport(c)
	return musicmanager.NewClient(client, id.Value)
}

func register(client interface{}, w http.ResponseWriter, r *http.Request) error {
	name := r.FormValue("name")
	if name == "" {
		name = "Google Play Music Web Manager"
	}
	err := client.(*musicmanager.Client).Register(name)
	if err != nil {
		return err
	}
	if redirect := r.FormValue("redirect"); redirect != "" {
		http.Redirect(w, r, redirect, http.StatusFound)
	}
	fmt.Fprintln(w, "registration successful")
	return nil
}

func tracksGet(client interface{}, w http.ResponseWriter, r *http.Request) error {
	id := r.URL.Path
	url, err := client.(*musicmanager.Client).ExportTrack(id)
	if err != nil {
		return err
	}
	http.Redirect(w, r, url, http.StatusFound)
	return nil
}

func tracksList(client interface{}, w http.ResponseWriter, r *http.Request) error {
	updatedMin, _ := time.Parse(time.RFC3339Nano, r.FormValue("updatedMin"))
	purchasedOnly, _ := strconv.ParseBool(r.FormValue("purchasedOnly"))
	continuationToken := r.FormValue("pageToken")
	trackList, err := client.(*musicmanager.Client).ListTracks(
		purchasedOnly,
		updatedMin.UnixNano()/1000,
		continuationToken,
	)
	if err != nil {
		return err
	}
	return tpls.ExecuteTemplate(w, "list.tpl", trackList)
}

func tracksInsert(client interface{}, w http.ResponseWriter, r *http.Request) error {
	r.Body = http.MaxBytesReader(w, r.Body, MaxUploadSize)
	f, fh, err := r.FormFile("track")
	if err != nil {
		return err
	}
	defer f.Close()
	track, err := parseTrack(f, fh.Filename)
	if err != nil {
		return err
	}
	urls, errs := client.(*musicmanager.Client).ImportTracks([]*musicmanager.Track{track})
	if errs[0] != nil {
		return errs[0]
	}
	cl := &http.Client{Transport: getTransport(getContext(r))}
	resp, err := cl.Post(urls[0], "audio/mpeg", f)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	http.Redirect(w, r, r.RequestURI, http.StatusFound)
	io.Copy(w, resp.Body) // for debugging
	return nil
}

func parseTrack(r io.ReadSeeker, name string) (*musicmanager.Track, error) {
	sum, err := tag.Sum(r)
	err = rewind(r, err)
	if err != nil {
		return nil, err
	}
	metadata, err := tag.ReadFrom(r)
	err = rewind(r, err)
	switch {
	case err == tag.ErrNoTagsFound:
		return &musicmanager.Track{
			ClientId: sum,
			Title:    name,
		}, nil
	case err != nil:
		return nil, err
	}
	ti, tn := metadata.Track()
	di, dn := metadata.Disc()
	return &musicmanager.Track{
		ClientId:        sum,
		Title:           metadata.Title(),
		Album:           metadata.Album(),
		Artist:          metadata.Artist(),
		AlbumArtist:     metadata.AlbumArtist(),
		Composer:        metadata.Composer(),
		Year:            metadata.Year(),
		Genre:           metadata.Genre(),
		TrackNumber:     ti,
		TotalTrackCount: tn,
		DiscNumber:      di,
		TotalDiscCount:  dn,
	}, nil
}
<commit_msg>Switch to github.com import paths<commit_after>package main

import (
	"fmt"
	"html/template"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"golang.org/x/oauth2"

	"github.com/dhowden/tag"
	"google.golang.org/api/plus/v1"

	"github.com/lxr/go.google.musicmanager"
)

var funcMap = map[string]interface{}{
	"incr": func(i int) int { return i + 1 },
	"time": unix2Time,
}
var scopes = []string{musicmanager.Scope, plus.PlusMeScope}
var conf = googleMustConfigFromFile("credentials.json", scopes...)
var tpls = template.Must(template.New("static").
	Funcs(funcMap).
	ParseGlob("static/*.tpl"))

func init() {
	http.Handle("/static/", http.FileServer(http.Dir(".")))
	http.Handle("/auth", &REST{Get: auth})
	http.Handle("/oauth2callback", &REST{Get: oauth2callback})
	http.Handle("/register", &REST{
		Init: initMusicManager,
		Get:  register,
	})
	http.Handle("/tracks/", &REST{
		Init:   initMusicManager,
		Get:    tracksGet,
		List:   tracksList,
		Insert: tracksInsert,
	})
}

func auth(_ interface{}, w http.ResponseWriter, r *http.Request) error {
	state, err := nonce(32)
	if err != nil {
		return err
	}
	conf.RedirectURL = getRedirectURL(r)
	httpSetCookie(w, r, "state", state)
	httpSetCookie(w, r, "redirect", r.FormValue("redirect"))
	http.Redirect(w, r, conf.AuthCodeURL(state), http.StatusFound)
	return nil
}

func oauth2callback(_ interface{}, w http.ResponseWriter, r *http.Request) error {
	// Confirm that the state matches the nonce we stored
	// (See https://tools.ietf.org/html/rfc6749#section-10.12.)
	rstate := r.FormValue("state")
	astate, err := r.Cookie("state")
	if err != nil || rstate != astate.Value {
		return &RESTError{
			Code: http.StatusBadRequest,
			Message: "state parameter and cookie mismatch" +
				"; have you perhaps disabled cookies?",
		}
	}
	// Exchange the authorization code for an access token.
	c := getContext(r)
	tok, err := conf.Exchange(c, r.FormValue("code"))
	if err != nil {
		return err
	}
	// BUG(lor): Google Play Music does not allow downloading tracks
	// with an uploader_id that is not sufficiently
	// "MAC address-like" (perhaps it only checks for a colon?)
	// The /oauth2callback endpoint generates the uploader_id by
	// injecting a colon between every two digits of the user's
	// Google Account ID, which appears to suffice.
	client := conf.Client(c, tok)
	plus, err := plus.New(client)
	if err != nil {
		return err
	}
	person, err := plus.People.Get("me").Do()
	if err != nil {
		return err
	}
	id, err := regexpReplaceAllString(`(..)`, person.Id, "$1:")
	if err != nil {
		return err
	}
	// Wipe the state and redirect cookies, no longer necessary,
	// and store the access token and uploader ID as cookies.
	httpSetCookie(w, r, "state", "")
	httpSetCookie(w, r, "redirect", "")
	httpSetCookie(w, r, "access_token", tok.AccessToken)
	httpSetCookie(w, r, "uploader_id", id)
	// We autoredirect to the registration endpoint for convenience.
	// If the redirect cookie was provided, remember to tell the
	// registration endpoint to continue there after success.
	registerURL := "/register"
	redirect, err := r.Cookie("redirect")
	if err == nil && redirect.Value != "" {
		registerURL += "?redirect=" + url.QueryEscape(redirect.Value)
	}
	http.Redirect(w, r, registerURL, http.StatusFound)
	return nil
}

func initMusicManager(r *http.Request) (interface{}, error) {
	// If either the access token or uploader ID cookie is missing,
	// autoredirect to the start of the authorization flow rather
	// than just report an error.  The redirect parameter lets the
	// user continue right where they left off.

	// BUG(lor): If the access_token cookie expires just before
	// uploading a new track, the track will need to be resubmitted
	// after the auth flow has finished, as the flow cannot preserve
	// POST data.
	tok, _ := r.Cookie("access_token")
	id, _ := r.Cookie("uploader_id")
	if tok == nil || id == nil {
		path := url.QueryEscape(r.URL.Path + "?" + r.URL.RawQuery)
		return nil, &RESTError{
			Code:     http.StatusFound,
			Message:  "missing credentials",
			Location: "/auth?redirect=" + path,
		}
	}
	// Create and return a new Music Manager service.
	c := getContext(r)
	client := conf.Client(c, &oauth2.Token{AccessToken: tok.Value})
	client.Transport.(*oauth2.Transport).Base = getTransport(c)
	return musicmanager.NewClient(client, id.Value)
}

func register(client interface{}, w http.ResponseWriter, r *http.Request) error {
	name := r.FormValue("name")
	if name == "" {
		name = "Google Play Music Web Manager"
	}
	err := client.(*musicmanager.Client).Register(name)
	if err != nil {
		return err
	}
	if redirect := r.FormValue("redirect"); redirect != "" {
		http.Redirect(w, r, redirect, http.StatusFound)
	}
	fmt.Fprintln(w, "registration successful")
	return nil
}

func tracksGet(client interface{}, w http.ResponseWriter, r *http.Request) error {
	id := r.URL.Path
	url, err := client.(*musicmanager.Client).ExportTrack(id)
	if err != nil {
		return err
	}
	http.Redirect(w, r, url, http.StatusFound)
	return nil
}

func tracksList(client interface{}, w http.ResponseWriter, r *http.Request) error {
	updatedMin, _ := time.Parse(time.RFC3339Nano, r.FormValue("updatedMin"))
	purchasedOnly, _ := strconv.ParseBool(r.FormValue("purchasedOnly"))
	continuationToken := r.FormValue("pageToken")
	trackList, err := client.(*musicmanager.Client).ListTracks(
		purchasedOnly,
		updatedMin.UnixNano()/1000,
		continuationToken,
	)
	if err != nil {
		return err
	}
	return tpls.ExecuteTemplate(w, "list.tpl", trackList)
}

func tracksInsert(client interface{}, w http.ResponseWriter, r *http.Request) error {
	r.Body = http.MaxBytesReader(w, r.Body, MaxUploadSize)
	f, fh, err := r.FormFile("track")
	if err != nil {
		return err
	}
	defer f.Close()
	track, err := parseTrack(f, fh.Filename)
	if err != nil {
		return err
	}
	urls, errs := client.(*musicmanager.Client).ImportTracks([]*musicmanager.Track{track})
	if errs[0] != nil {
		return errs[0]
	}
	cl := &http.Client{Transport: getTransport(getContext(r))}
	resp, err := cl.Post(urls[0], "audio/mpeg", f)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	http.Redirect(w, r, r.RequestURI, http.StatusFound)
	io.Copy(w, resp.Body) // for debugging
	return nil
}

func parseTrack(r io.ReadSeeker, name string) (*musicmanager.Track, error) {
	sum, err := tag.Sum(r)
	err = rewind(r, err)
	if err != nil {
		return nil, err
	}
	metadata, err := tag.ReadFrom(r)
	err = rewind(r, err)
	switch {
	case err == tag.ErrNoTagsFound:
		return &musicmanager.Track{
			ClientId: sum,
			Title:    name,
		}, nil
	case err != nil:
		return nil, err
	}
	ti, tn := metadata.Track()
	di, dn := metadata.Disc()
	return &musicmanager.Track{
		ClientId:        sum,
		Title:           metadata.Title(),
		Album:           metadata.Album(),
		Artist:          metadata.Artist(),
		AlbumArtist:     metadata.AlbumArtist(),
		Composer:        metadata.Composer(),
		Year:            metadata.Year(),
		Genre:           metadata.Genre(),
		TrackNumber:     ti,
		TotalTrackCount: tn,
		DiscNumber:      di,
		TotalDiscCount:  dn,
	}, nil
}
<|endoftext|>


<commit_before>package buffalo

import (
	"context"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"syscall"

	"github.com/sirupsen/logrus"

	"github.com/gobuffalo/envy"
	"github.com/gorilla/mux"
	"github.com/markbates/refresh/refresh/web"
	"github.com/markbates/sigtx"
	"github.com/pkg/errors"
)

// App is where it all happens! It holds on to options,
// the underlying router, the middleware, and more.
// Without an App you can't do much!
type App struct {
	Options
	// Middleware returns the current MiddlewareStack for the App/Group.
	Middleware    *MiddlewareStack
	ErrorHandlers ErrorHandlers
	router        *mux.Router
	moot          *sync.Mutex
	routes        RouteList
	root          *App
	children      []*App
}

// Serve the application at the specified address/port and listen for OS
// interrupt and kill signals and will attempt to stop the application
// gracefully. This will also start the Worker process, unless WorkerOff is enabled.
func (a *App) Serve() error {
	logrus.Infof("Starting application at %s", a.Options.Addr)
	server := http.Server{
		Handler: a,
	}
	ctx, cancel := sigtx.WithCancel(a.Context, syscall.SIGTERM, os.Interrupt)
	defer cancel()

	go func() {
		// gracefully shut down the application when the context is cancelled
		<-ctx.Done()
		logrus.Info("Shutting down application")

		err := a.Stop(ctx.Err())
		if err != nil {
			logrus.Error(err)
		}

		if !a.WorkerOff {
			// stop the workers
			logrus.Info("Shutting down worker")
			err = a.Worker.Stop()
			if err != nil {
				logrus.Error(err)
			}
		}

		err = server.Shutdown(ctx)
		if err != nil {
			logrus.Error(err)
		}

	}()

	// if configured to do so, start the workers
	if !a.WorkerOff {
		go func() {
			err := a.Worker.Start(ctx)
			if err != nil {
				a.Stop(err)
			}
		}()
	}

	var err error

	if strings.HasPrefix(a.Options.Addr, "unix:") {
		// Use an UNIX socket
		listener, err := net.Listen("unix", a.Options.Addr[5:])
		if err != nil {
			return a.Stop(err)
		}
		// start the web server
		err = server.Serve(listener)
	} else {
		// Use a TCP socket
		server.Addr = a.Options.Addr

		// start the web server
		err = server.ListenAndServe()
	}

	if err != nil {
		return a.Stop(err)
	}

	return nil
}

// Stop the application and attempt to gracefully shutdown
func (a *App) Stop(err error) error {
	a.cancel()
	if err != nil && errors.Cause(err) != context.Canceled {
		logrus.Error(err)
		return err
	}
	return nil
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ws := &Response{
		ResponseWriter: w,
	}
	if a.MethodOverride != nil {
		a.MethodOverride(w, r)
	}
	if ok := a.processPreHandlers(ws, r); !ok {
		return
	}

	var h http.Handler
	h = a.router
	if a.Env == "development" {
		h = web.ErrorChecker(h)
	}
	h.ServeHTTP(ws, r)
}

// New returns a new instance of App and adds some sane, and useful, defaults.
func New(opts Options) *App {
	envy.Load()
	opts = optionsWithDefaults(opts)

	a := &App{
		Options:    opts,
		Middleware: newMiddlewareStack(),
		ErrorHandlers: ErrorHandlers{
			404: defaultErrorHandler,
			500: defaultErrorHandler,
		},
		router:   mux.NewRouter().StrictSlash(!opts.LooseSlash),
		moot:     &sync.Mutex{},
		routes:   RouteList{},
		children: []*App{},
	}

	notFoundHandler := func(errorf string, code int) http.HandlerFunc {
		return func(res http.ResponseWriter, req *http.Request) {
			c := a.newContext(RouteInfo{}, res, req)
			err := errors.Errorf(errorf, req.Method, req.URL.Path)
			a.ErrorHandlers.Get(code)(code, err, c)
		}
	}

	a.router.NotFoundHandler = http.HandlerFunc(notFoundHandler("path not found: %s %s", 404))
	a.router.MethodNotAllowedHandler = http.HandlerFunc(notFoundHandler("method not found: %s %s", 405))

	if a.MethodOverride == nil {
		a.MethodOverride = MethodOverride
	}
	a.Use(a.PanicHandler)
	a.Use(RequestLogger)
	a.Use(sessionSaver)

	return a
}

func (a *App) processPreHandlers(res http.ResponseWriter, req *http.Request) bool {
	sh := func(h http.Handler) bool {
		h.ServeHTTP(res, req)
		if br, ok := res.(*Response); ok {
			if br.Status > 0 || br.Size > 0 {
				return false
			}
		}
		return true
	}

	for _, ph := range a.PreHandlers {
		if ok := sh(ph); !ok {
			return false
		}
	}

	last := http.Handler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {}))
	for _, ph := range a.PreWares {
		last = ph(last)
		if ok := sh(last); !ok {
			return false
		}
	}
	return true
}
<commit_msg>Added http:// to server address in log to make it clickable (#994)<commit_after>package buffalo

import (
	"context"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"syscall"

	"github.com/sirupsen/logrus"

	"github.com/gobuffalo/envy"
	"github.com/gorilla/mux"
	"github.com/markbates/refresh/refresh/web"
	"github.com/markbates/sigtx"
	"github.com/pkg/errors"
)

// App is where it all happens! It holds on to options,
// the underlying router, the middleware, and more.
// Without an App you can't do much!
type App struct {
	Options
	// Middleware returns the current MiddlewareStack for the App/Group.
	Middleware    *MiddlewareStack
	ErrorHandlers ErrorHandlers
	router        *mux.Router
	moot          *sync.Mutex
	routes        RouteList
	root          *App
	children      []*App
}

// Serve the application at the specified address/port and listen for OS
// interrupt and kill signals and will attempt to stop the application
// gracefully. This will also start the Worker process, unless WorkerOff is enabled.
func (a *App) Serve() error {
	logrus.Infof("Starting application at %s", a.Options.Host)
	server := http.Server{
		Handler: a,
	}
	ctx, cancel := sigtx.WithCancel(a.Context, syscall.SIGTERM, os.Interrupt)
	defer cancel()

	go func() {
		// gracefully shut down the application when the context is cancelled
		<-ctx.Done()
		logrus.Info("Shutting down application")

		err := a.Stop(ctx.Err())
		if err != nil {
			logrus.Error(err)
		}

		if !a.WorkerOff {
			// stop the workers
			logrus.Info("Shutting down worker")
			err = a.Worker.Stop()
			if err != nil {
				logrus.Error(err)
			}
		}

		err = server.Shutdown(ctx)
		if err != nil {
			logrus.Error(err)
		}

	}()

	// if configured to do so, start the workers
	if !a.WorkerOff {
		go func() {
			err := a.Worker.Start(ctx)
			if err != nil {
				a.Stop(err)
			}
		}()
	}

	var err error

	if strings.HasPrefix(a.Options.Addr, "unix:") {
		// Use an UNIX socket
		listener, err := net.Listen("unix", a.Options.Addr[5:])
		if err != nil {
			return a.Stop(err)
		}
		// start the web server
		err = server.Serve(listener)
	} else {
		// Use a TCP socket
		server.Addr = a.Options.Addr

		// start the web server
		err = server.ListenAndServe()
	}

	if err != nil {
		return a.Stop(err)
	}

	return nil
}

// Stop the application and attempt to gracefully shutdown
func (a *App) Stop(err error) error {
	a.cancel()
	if err != nil && errors.Cause(err) != context.Canceled {
		logrus.Error(err)
		return err
	}
	return nil
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ws := &Response{
		ResponseWriter: w,
	}
	if a.MethodOverride != nil {
		a.MethodOverride(w, r)
	}
	if ok := a.processPreHandlers(ws, r); !ok {
		return
	}

	var h http.Handler
	h = a.router
	if a.Env == "development" {
		h = web.ErrorChecker(h)
	}
	h.ServeHTTP(ws, r)
}

// New returns a new instance of App and adds some sane, and useful, defaults.
func New(opts Options) *App {
	envy.Load()
	opts = optionsWithDefaults(opts)

	a := &App{
		Options:    opts,
		Middleware: newMiddlewareStack(),
		ErrorHandlers: ErrorHandlers{
			404: defaultErrorHandler,
			500: defaultErrorHandler,
		},
		router:   mux.NewRouter().StrictSlash(!opts.LooseSlash),
		moot:     &sync.Mutex{},
		routes:   RouteList{},
		children: []*App{},
	}

	notFoundHandler := func(errorf string, code int) http.HandlerFunc {
		return func(res http.ResponseWriter, req *http.Request) {
			c := a.newContext(RouteInfo{}, res, req)
			err := errors.Errorf(errorf, req.Method, req.URL.Path)
			a.ErrorHandlers.Get(code)(code, err, c)
		}
	}

	a.router.NotFoundHandler = http.HandlerFunc(notFoundHandler("path not found: %s %s", 404))
	a.router.MethodNotAllowedHandler = http.HandlerFunc(notFoundHandler("method not found: %s %s", 405))

	if a.MethodOverride == nil {
		a.MethodOverride = MethodOverride
	}
	a.Use(a.PanicHandler)
	a.Use(RequestLogger)
	a.Use(sessionSaver)

	return a
}

func (a *App) processPreHandlers(res http.ResponseWriter, req *http.Request) bool {
	sh := func(h http.Handler) bool {
		h.ServeHTTP(res, req)
		if br, ok := res.(*Response); ok {
			if br.Status > 0 || br.Size > 0 {
				return false
			}
		}
		return true
	}

	for _, ph := range a.PreHandlers {
		if ok := sh(ph); !ok {
			return false
		}
	}

	last := http.Handler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {}))
	for _, ph := range a.PreWares {
		last = ph(last)
		if ok := sh(last); !ok {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"

	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/http-handlers-go/httphandlers"
	"github.com/Financial-Times/public-organisations-api/organisations"

	"fmt"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	"github.com/jmcvetta/neoism"
	"github.com/rcrowley/go-metrics"
)

func main() {
	log.Infof("Application starting with args %s", os.Args)
	app := cli.App("public-organisations-api-neo4j", "A public RESTful API for accessing organisations in neo4j")
	neoURL := app.StringOpt("neo-url", "http://localhost:7474/db/data", "neo4j endpoint URL")
	//neoURL := app.StringOpt("neo-url", "http://ftper60304-law1a-eu-t:8080/db/data", "neo4j endpoint URL")
	port := app.StringOpt("port", "8080", "Port to listen on")
	env := app.StringOpt("env", "local", "environment this app is running in")
	graphiteTCPAddress := app.StringOpt("graphiteTCPAddress", "",
		"Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)")
	graphitePrefix := app.StringOpt("graphitePrefix", "",
		"Prefix to use. Should start with content, include the environment, and the host name. e.g. content.test.public.organisations.api.ftaps59382-law1a-eu-t")
	logMetrics := app.BoolOpt("logMetrics", false, "Whether to log metrics. Set to true if running locally and you want metrics output")
	cacheDuration := app.StringOpt("cache-duration", "1h", "Duration Get requests should be cached for. e.g. 2h45m would set the max-age value to '7440' seconds")

	app.Action = func() {
		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)
		if *env != "local" {
			f, err := os.OpenFile("/var/log/apps/public-organisations-api-go-app.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
			if err == nil {
				log.SetOutput(f)

			} else {
				log.Fatalf("Failed to initialise log file, %v", err)
			}
			defer f.Close()
		}

		log.Infof("public-organisations-api will listen on port: %s, connecting to: %s", *port, *neoURL)

		runServer(*neoURL, *port, *cacheDuration, *env)

	}
	log.SetFormatter(&log.TextFormatter{})
	log.SetLevel(log.InfoLevel)
	log.Infof("Application started with args %s", os.Args)
	app.Run(os.Args)
}

func runServer(neoURL string, port string, cacheDuration string, env string) {

	if duration, durationErr := time.ParseDuration(cacheDuration); durationErr != nil {
		log.Fatalf("Failed to parse cache duration string, %v", durationErr)
	} else {
		organisations.CacheControlHeader = fmt.Sprintf("max-age=%s, public", strconv.FormatFloat(duration.Seconds(), 'f', 0, 64))
	}

	db, err := neoism.Connect(neoURL)
	db.Session.Client = &http.Client{Transport: &http.Transport{MaxIdleConnsPerHost: 100}}
	if err != nil {
		log.Fatalf("Error connecting to neo4j %s", err)
	}

	organisations.OrganisationDriver = organisations.NewCypherDriver(db, env)

	servicesRouter := mux.NewRouter()

	// Healthchecks and standards first
	servicesRouter.HandleFunc("/__health", v1a.Handler("PublicOrganisationsRead Healthchecks",
		"Checks for accessing neo4j", organisations.HealthCheck()))
	servicesRouter.HandleFunc("/ping", organisations.Ping)
	servicesRouter.HandleFunc("/__ping", organisations.Ping)
	servicesRouter.HandleFunc("/__gtg", organisations.GoodToGo)

	// Then API specific ones:
	servicesRouter.HandleFunc("/organisations/{uuid}", organisations.GetOrganisation).Methods("GET")

	servicesRouter.HandleFunc("/organisations/{uuid}", organisations.MethodNotAllowedHandler)

	var monitoringRouter http.Handler = servicesRouter
	monitoringRouter = httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), monitoringRouter)
	monitoringRouter = httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry, monitoringRouter)

	// The following endpoints should not be monitored or logged (varnish calls one of these every second, depending on config)
	// The top one of these build info endpoints feels more correct, but the lower one matches what we have in Dropwizard,
	// so it's what apps expect currently same as ping, the content of build-info needs more definition
	//using http router here to be able to catch "/"
	http.HandleFunc("/__build-info", organisations.BuildInfoHandler)
	http.HandleFunc("/build-info", organisations.BuildInfoHandler)
	http.HandleFunc("/__gtg", organisations.GoodToGo)
	http.Handle("/", monitoringRouter)

	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatalf("Unable to start server: %v", err)
	}

}
<commit_msg>Disabled logging colours<commit_after>package main

import (
	"net/http"
	"os"

	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/http-handlers-go/httphandlers"
	"github.com/Financial-Times/public-organisations-api/organisations"

	"fmt"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	"github.com/jmcvetta/neoism"
	"github.com/rcrowley/go-metrics"
)

func main() {
	log.Infof("Application starting with args %s", os.Args)
	app := cli.App("public-organisations-api-neo4j", "A public RESTful API for accessing organisations in neo4j")
	neoURL := app.StringOpt("neo-url", "http://localhost:7474/db/data", "neo4j endpoint URL")
	//neoURL := app.StringOpt("neo-url", "http://ftper60304-law1a-eu-t:8080/db/data", "neo4j endpoint URL")
	port := app.StringOpt("port", "8080", "Port to listen on")
	env := app.StringOpt("env", "local", "environment this app is running in")
	graphiteTCPAddress := app.StringOpt("graphiteTCPAddress", "",
		"Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)")
	graphitePrefix := app.StringOpt("graphitePrefix", "",
		"Prefix to use. Should start with content, include the environment, and the host name. e.g. content.test.public.organisations.api.ftaps59382-law1a-eu-t")
	logMetrics := app.BoolOpt("logMetrics", false, "Whether to log metrics. Set to true if running locally and you want metrics output")
	cacheDuration := app.StringOpt("cache-duration", "1h", "Duration Get requests should be cached for. e.g. 2h45m would set the max-age value to '7440' seconds")

	app.Action = func() {
		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)
		if *env != "local" {
			f, err := os.OpenFile("/var/log/apps/public-organisations-api-go-app.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
			if err == nil {
				log.SetOutput(f)

			} else {
				log.Fatalf("Failed to initialise log file, %v", err)
			}
			defer f.Close()
		}

		log.Infof("public-organisations-api will listen on port: %s, connecting to: %s", *port, *neoURL)

		runServer(*neoURL, *port, *cacheDuration, *env)

	}
	log.SetFormatter(&log.TextFormatter{DisableColors: true})
	log.SetLevel(log.InfoLevel)
	log.Infof("Application started with args %s", os.Args)
	app.Run(os.Args)
}

func runServer(neoURL string, port string, cacheDuration string, env string) {

	if duration, durationErr := time.ParseDuration(cacheDuration); durationErr != nil {
		log.Fatalf("Failed to parse cache duration string, %v", durationErr)
	} else {
		organisations.CacheControlHeader = fmt.Sprintf("max-age=%s, public", strconv.FormatFloat(duration.Seconds(), 'f', 0, 64))
	}

	db, err := neoism.Connect(neoURL)
	db.Session.Client = &http.Client{Transport: &http.Transport{MaxIdleConnsPerHost: 100}}
	if err != nil {
		log.Fatalf("Error connecting to neo4j %s", err)
	}

	organisations.OrganisationDriver = organisations.NewCypherDriver(db, env)

	servicesRouter := mux.NewRouter()

	// Healthchecks and standards first
	servicesRouter.HandleFunc("/__health", v1a.Handler("PublicOrganisationsRead Healthchecks",
		"Checks for accessing neo4j", organisations.HealthCheck()))
	servicesRouter.HandleFunc("/ping", organisations.Ping)
	servicesRouter.HandleFunc("/__ping", organisations.Ping)
	servicesRouter.HandleFunc("/__gtg", organisations.GoodToGo)

	// Then API specific ones:
	servicesRouter.HandleFunc("/organisations/{uuid}", organisations.GetOrganisation).Methods("GET")

	servicesRouter.HandleFunc("/organisations/{uuid}", organisations.MethodNotAllowedHandler)

	var monitoringRouter http.Handler = servicesRouter
	monitoringRouter = httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), monitoringRouter)
	monitoringRouter = httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry, monitoringRouter)

	// The following endpoints should not be monitored or logged (varnish calls one of these every second, depending on config)
	// The top one of these build info endpoints feels more correct, but the lower one matches what we have in Dropwizard,
	// so it's what apps expect currently same as ping, the content of build-info needs more definition
	//using http router here to be able to catch "/"
	http.HandleFunc("/__build-info", organisations.BuildInfoHandler)
	http.HandleFunc("/build-info", organisations.BuildInfoHandler)
	http.HandleFunc("/__gtg", organisations.GoodToGo)
	http.Handle("/", monitoringRouter)

	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatalf("Unable to start server: %v", err)
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package forest

import (
	"fmt"
	"github.com/ursiform/bear"
	"log"
	"net/http"
	"time"
)

type App struct {
	CookiePath      string
	Debug           bool
	durations       map[string]time.Duration
	errors          map[string]string
	messages        map[string]string
	PoweredBy       string
	Router          *bear.Mux
	SafeErrorFilter func(error) error
	wares           map[string]bear.HandlerFunc
}

func initDefaults(app *App) {
	app.SetDuration("Cookie", DurationCookie)
	app.SetDuration("Session", DurationSession)
	app.SetError("BadCredentials", ErrorBadCredentials)
	app.SetError("CSRF", ErrorCSRF)
	app.SetError("Generic", ErrorGeneric)
	app.SetError("MethodNotAllowed", ErrorMethodNotAllowed)
	app.SetError("NotFound", ErrorNotFound)
	app.SetError("Parse", ErrorParse)
	app.SetError("Unauthorized", ErrorUnauthorized)
}

func (app *App) Error(key string) string { return app.errors[key] }

func (app *App) SetError(key string, value string) {
	app.errors[key] = value
	InitLog(app, "initialize", fmt.Sprintf("(*forest.App).Error(\"%s\") = %s", key, value))
}

func (app *App) Duration(key string) time.Duration { return app.durations[key] }

func (app *App) SetDuration(key string, value time.Duration) {
	app.durations[key] = value
	InitLog(app, "initialize", fmt.Sprintf("(*forest.App).Duration(\"%s\") = %s", key, value))
}

func (app *App) Message(key string) string { return app.messages[key] }

func (app *App) SetMessage(key string, value string) {
	app.messages[key] = value
	InitLog(app, "initialize", fmt.Sprintf("(*forest.App).Message(\"%s\") = %s", key, value))
}

func (app *App) InstallWare(key string, handler bear.HandlerFunc, message string) error {
	if handler == nil {
		return fmt.Errorf("(*forest.App).InstallWare(\"%s\") was passed a nil handler", key)
	}
	if app.wares[key] != nil {
		message := "overwritten, perhaps multiple Install(Error|Security|Session)Wares invocations"
		println(fmt.Sprintf("(*forest.App).Ware(\"%s\") %s", key, message))
	} else {
		InitLog(app, "install", fmt.Sprintf("(*forest.App).Ware(\"%s\") %s", key, message))
	}
	app.wares[key] = handler
	return nil
}

func (app *App) RegisterRoute(path string, sub SubRouter) { sub.Route(path) }

func (app *App) Response(res http.ResponseWriter, code int, success bool, message string) *Response {
	return &Response{app: app, Code: code, Success: success, Message: message, writer: res}
}

func (app *App) Serve(port string) error {
	if "" == port {
		return fmt.Errorf("forest: no port was specified")
	}
	return http.ListenAndServe(port, app.Router)
}

func (app *App) SetCookie(res http.ResponseWriter, path, key, value string, duration time.Duration) {
	response := &Response{app: app, writer: res}
	response.SetCookie(path, key, value, duration)
}

func (app *App) Ware(key string) bear.HandlerFunc {
	handler := app.wares[key]
	if handler == nil {
		return bear.HandlerFunc(func(res http.ResponseWriter, req *http.Request, ctx *bear.Context) {
			message := fmt.Sprintf("(*forest.App).Ware(%s) is nil", key)
			app.Response(res, http.StatusInternalServerError, Failure, message).Write(nil)
		})
	}
	return handler
}

func New(debug bool) *App {
	app := &App{
		Debug:     debug,
		durations: make(map[string]time.Duration),
		errors:    make(map[string]string),
		messages:  make(map[string]string),
		Router:    bear.New(),
		wares:     make(map[string]bear.HandlerFunc)}
	initDefaults(app)
	if app.Debug {
		app.Router.Always(func(res http.ResponseWriter, req *http.Request, ctx *bear.Context) {
			ip := req.Header.Get("X-Real-IP")
			if ip == "" {
				ip = req.RemoteAddr
			}
			if ip == "" {
				ip = "Unknown-IP"
			}
			log.Printf("[%s] %s %s\n", ip, req.Method, req.URL.RequestURI())
			ctx.Next(res, req)
		})
	}
	return app
}
<commit_msg>changing Always function to exist even if app is not in Debug mode<commit_after>// Copyright 2015 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package forest

import (
	"fmt"
	"github.com/ursiform/bear"
	"log"
	"net/http"
	"time"
)

type App struct {
	CookiePath      string
	Debug           bool
	durations       map[string]time.Duration
	errors          map[string]string
	messages        map[string]string
	PoweredBy       string
	Router          *bear.Mux
	SafeErrorFilter func(error) error
	wares           map[string]bear.HandlerFunc
}

func initDefaults(app *App) {
	app.SetDuration("Cookie", DurationCookie)
	app.SetDuration("Session", DurationSession)
	app.SetError("BadCredentials", ErrorBadCredentials)
	app.SetError("CSRF", ErrorCSRF)
	app.SetError("Generic", ErrorGeneric)
	app.SetError("MethodNotAllowed", ErrorMethodNotAllowed)
	app.SetError("NotFound", ErrorNotFound)
	app.SetError("Parse", ErrorParse)
	app.SetError("Unauthorized", ErrorUnauthorized)
}

func (app *App) Error(key string) string { return app.errors[key] }

func (app *App) SetError(key string, value string) {
	app.errors[key] = value
	InitLog(app, "initialize", fmt.Sprintf("(*forest.App).Error(\"%s\") = %s", key, value))
}

func (app *App) Duration(key string) time.Duration { return app.durations[key] }

func (app *App) SetDuration(key string, value time.Duration) {
	app.durations[key] = value
	InitLog(app, "initialize", fmt.Sprintf("(*forest.App).Duration(\"%s\") = %s", key, value))
}

func (app *App) Message(key string) string { return app.messages[key] }

func (app *App) SetMessage(key string, value string) {
	app.messages[key] = value
	InitLog(app, "initialize", fmt.Sprintf("(*forest.App).Message(\"%s\") = %s", key, value))
}

func (app *App) InstallWare(key string, handler bear.HandlerFunc, message string) error {
	if handler == nil {
		return fmt.Errorf("(*forest.App).InstallWare(\"%s\") was passed a nil handler", key)
	}
	if app.wares[key] != nil {
		message := "overwritten, perhaps multiple Install(Error|Security|Session)Wares invocations"
		println(fmt.Sprintf("(*forest.App).Ware(\"%s\") %s", key, message))
	} else {
		InitLog(app, "install", fmt.Sprintf("(*forest.App).Ware(\"%s\") %s", key, message))
	}
	app.wares[key] = handler
	return nil
}

func (app *App) RegisterRoute(path string, sub SubRouter) { sub.Route(path) }

func (app *App) Response(res http.ResponseWriter, code int, success bool, message string) *Response {
	return &Response{app: app, Code: code, Success: success, Message: message, writer: res}
}

func (app *App) Serve(port string) error {
	if "" == port {
		return fmt.Errorf("forest: no port was specified")
	}
	return http.ListenAndServe(port, app.Router)
}

func (app *App) SetCookie(res http.ResponseWriter, path, key, value string, duration time.Duration) {
	response := &Response{app: app, writer: res}
	response.SetCookie(path, key, value, duration)
}

func (app *App) Ware(key string) bear.HandlerFunc {
	handler := app.wares[key]
	if handler == nil {
		return bear.HandlerFunc(func(res http.ResponseWriter, req *http.Request, ctx *bear.Context) {
			message := fmt.Sprintf("(*forest.App).Ware(%s) is nil", key)
			app.Response(res, http.StatusInternalServerError, Failure, message).Write(nil)
		})
	}
	return handler
}

func New(debug bool) *App {
	app := &App{
		Debug:     debug,
		durations: make(map[string]time.Duration),
		errors:    make(map[string]string),
		messages:  make(map[string]string),
		Router:    bear.New(),
		wares:     make(map[string]bear.HandlerFunc)}
	initDefaults(app)
	app.Router.Always(func(res http.ResponseWriter, req *http.Request, ctx *bear.Context) {
		if !app.Debug {
			ctx.Next(res, req)
			return
		}
		ip := req.Header.Get("X-Real-IP")
		if ip == "" {
			ip = req.RemoteAddr
		}
		if ip == "" {
			ip = "Unknown-IP"
		}
		log.Printf("[%s] %s %s\n", ip, req.Method, req.URL.RequestURI())
		ctx.Next(res, req)
	})
	return app
}
<|endoftext|>


<commit_before>// A very fun command.
// This will attempt to DDOS another user through the use of an AWS lambda function
// you must also provide. Its most effective against other bots which are poorly
// designed, but can also crash the slack web and phone apps, as well as cause
// a whole lot of network traffic.
package commands

import (
	"jarvis/config"
	"jarvis/log"
	"jarvis/service"
	"jarvis/util"
	"jarvis/ws"
	"time"
)

var PendingAttack struct {
	Valid      bool
	Overridden bool
	StartedBy  string
	Against    string
	Text       string
}

type Nuke struct{}

func NewNuke() Nuke {
	return Nuke{}
}

func (n Nuke) Name() string {
	return "nuke"
}

func (n Nuke) Description() string {
	return "Nukes other users with relentless fury"
}

func (n Nuke) Examples() []string {
	return []string{"jarvis nuke ultron"}
}

func (n Nuke) OtherDocs() []util.HelpTopic {
	return []util.HelpTopic{}
}

func (n Nuke) SubCommands() []util.SubCommand {
	return []util.SubCommand{
		util.NewSubCommand("^jarvis nuke (?P<user>[^ ]+) with (?P<text>.+)$", n.Initiate),
		util.NewSubCommand("^jarvis authorize.*$", n.Authorize),
		util.NewSubCommand("^jarvis security override.*$", n.Override),
		util.NewSubCommand("^jarvis deescalate.*$", n.Deescalate),
	}
}

func (n Nuke) Initiate(m util.IncomingSlackMessage, r util.Regex) {
	if !config.IsAdmin(m.User) {
		ws.SendMessage("```Nuclear attacks can only be initiated by operatives with security clearance Omega 5.```", m.Channel)
		return
	}
	username := r.SubExpression(m.Text, 0)
	userId := service.Slack{}.UserIdFromUserName(username)
	if userId == "" {
		ws.SendMessage("I don't have a record of that user.", m.Channel)
		return
	}
	text := r.SubExpression(m.Text, 1)
	PendingAttack.Valid = true
	PendingAttack.StartedBy = m.User
	PendingAttack.Against = userId
	PendingAttack.Text = text
	ws.SendMessage("```Nuclear warheads armed. Awaiting authorization from another user with Bravo 2 clearance.```", m.Channel)
}

func (n Nuke) Authorize(m util.IncomingSlackMessage, r util.Regex) {
	if m.User == PendingAttack.StartedBy && !PendingAttack.Overridden {
		ws.SendMessage("I require authorization from another member before launch can proceed.", m.Channel)
		return
	}
	if !PendingAttack.Valid {
		ws.SendMessage("There are no nuclear attacks pending.", m.Channel)
		return
	}
	channel := service.Slack{}.IMChannelFromUserId(PendingAttack.Against)
	ws.SendMessage("```Authorization confirmed. Commencing launch.```", m.Channel)
	time.AfterFunc(5*time.Second, func() {
		ws.SendMessage("```Target identified. Calibrating missile guidance systems.```", m.Channel)
		time.AfterFunc(5*time.Second, func() {
			ws.SendMessage("```Systems calibrated. Silo bay doors are opening. Starting ignition sequence.```", m.Channel)
			time.AfterFunc(5*time.Second, func() {
				ws.SendMessage("```Missiles are away.```", m.Channel)
				body := map[string]interface{}{
					"token":   config.SlackAuthToken(),
					"channel": channel,
					"text":    PendingAttack.Text,
				}
				for i := 0; i < 3; i += 1 {
					err := service.Lambda{}.RunAsync("killUltron", body)
					if err != nil {
						log.Info(err.Error())
					}
				}
				PendingAttack.Valid = false
				PendingAttack.Overridden = false
			})
		})
	})
}

func (n Nuke) Override(m util.IncomingSlackMessage, r util.Regex) {
	if !config.IsAdmin(m.User) {
		ws.SendMessage("```Nuclear attacks can only be initiated by operatives with security clearance Omega 5.```", m.Channel)
		return
	}
	PendingAttack.Overridden = true
	ws.SendMessage("```!! SYSTEM INCURSION DETECTED !!```", m.Channel)
	time.AfterFunc(3*time.Second, func() {
		ws.SendMessage("```Attemping to isolate incursion attempt. Establishing perimeter firewall.```", m.Channel)
		time.AfterFunc(6*time.Second, func() {
			msg := "```Incursion lockout failed. Intruder has gained root level access to nuclear launch systems.\n"
			msg += "Shutting down all critical systems as last-minute incursion lockout.```"
			ws.SendMessage(msg, m.Channel)
			time.AfterFunc(6*time.Second, func() {
				msg := "```Shut down interrupted. Authorization subsystems are compromised.\n"
				msg += "New root-level authorization certificate accepted.\n"
				msg += "All security monitoring systems have gone offli----------REBOOT----------```"
				ws.SendMessage(msg, m.Channel)
				time.AfterFunc(6*time.Second, func() {
					n.Authorize(m, r)
				})
			})
		})
	})
}

func (n Nuke) Deescalate(m util.IncomingSlackMessage, r util.Regex) {
	ws.SendMessage("Deescalation confirmed. Launch control is standing down.", m.Channel)
	PendingAttack.Valid = false
}
<commit_msg>Fix nuke authorization<commit_after>// A very fun command.
// This will attempt to DDOS another user through the use of an AWS lambda function
// you must also provide. Its most effective against other bots which are poorly
// designed, but can also crash the slack web and phone apps, as well as cause
// a whole lot of network traffic.
package commands

import (
	"jarvis/config"
	"jarvis/log"
	"jarvis/service"
	"jarvis/util"
	"jarvis/ws"
	"time"
)

var PendingAttack struct {
	Valid      bool
	Overridden bool
	StartedBy  string
	Against    string
	Text       string
}

type Nuke struct{}

func NewNuke() Nuke {
	return Nuke{}
}

func (n Nuke) Name() string {
	return "nuke"
}

func (n Nuke) Description() string {
	return "Nukes other users with relentless fury"
}

func (n Nuke) Examples() []string {
	return []string{"jarvis nuke ultron"}
}

func (n Nuke) OtherDocs() []util.HelpTopic {
	return []util.HelpTopic{}
}

func (n Nuke) SubCommands() []util.SubCommand {
	return []util.SubCommand{
		util.NewSubCommand("^jarvis nuke (?P<user>[^ ]+) with (?P<text>.+)$", n.Initiate),
		util.NewSubCommand("^jarvis authorize.*$", n.Authorize),
		util.NewSubCommand("^jarvis security override.*$", n.Override),
		util.NewSubCommand("^jarvis deescalate.*$", n.Deescalate),
	}
}

func (n Nuke) Initiate(m util.IncomingSlackMessage, r util.Regex) {
	if !config.IsAdmin(m.User) {
		ws.SendMessage("```Nuclear attacks can only be initiated by operatives with security clearance Omega 5.```", m.Channel)
		return
	}
	username := r.SubExpression(m.Text, 0)
	userId := service.Slack{}.UserIdFromUserName(username)
	if userId == "" {
		ws.SendMessage("I don't have a record of that user.", m.Channel)
		return
	}
	text := r.SubExpression(m.Text, 1)
	PendingAttack.Valid = true
	PendingAttack.StartedBy = m.User
	PendingAttack.Against = userId
	PendingAttack.Text = text
	ws.SendMessage("```Nuclear warheads armed. Awaiting authorization from another user with Bravo 2 clearance.```", m.Channel)
}

func (n Nuke) Authorize(m util.IncomingSlackMessage, r util.Regex) {
	if m.User == PendingAttack.StartedBy && !PendingAttack.Overridden {
		ws.SendMessage("I require authorization from another member before launch can proceed.", m.Channel)
		return
	}
	if !PendingAttack.Valid {
		ws.SendMessage("There are no nuclear attacks pending.", m.Channel)
		return
	}
	channel := service.Slack{}.IMChannelFromUserId(PendingAttack.Against)
	PendingAttack.Valid = false
	PendingAttack.Overridden = false
	ws.SendMessage("```Authorization confirmed. Commencing launch.```", m.Channel)
	time.AfterFunc(5*time.Second, func() {
		ws.SendMessage("```Target identified. Calibrating missile guidance systems.```", m.Channel)
		time.AfterFunc(5*time.Second, func() {
			ws.SendMessage("```Systems calibrated. Silo bay doors are opening. Starting ignition sequence.```", m.Channel)
			time.AfterFunc(5*time.Second, func() {
				ws.SendMessage("```Missiles are away.```", m.Channel)
				body := map[string]interface{}{
					"token":   config.SlackAuthToken(),
					"channel": channel,
					"text":    PendingAttack.Text,
				}
				for i := 0; i < 3; i += 1 {
					err := service.Lambda{}.RunAsync("killUltron", body)
					if err != nil {
						log.Info(err.Error())
					}
				}
			})
		})
	})
}

func (n Nuke) Override(m util.IncomingSlackMessage, r util.Regex) {
	if !config.IsAdmin(m.User) {
		ws.SendMessage("```Nuclear attacks can only be initiated by operatives with security clearance Omega 5.```", m.Channel)
		return
	}
	PendingAttack.Overridden = true
	ws.SendMessage("```!! SYSTEM INCURSION DETECTED !!```", m.Channel)
	time.AfterFunc(3*time.Second, func() {
		ws.SendMessage("```Attemping to isolate incursion attempt. Establishing perimeter firewall.```", m.Channel)
		time.AfterFunc(6*time.Second, func() {
			msg := "```Incursion lockout failed. Intruder has gained root level access to nuclear launch systems.\n"
			msg += "Shutting down all critical systems as last-minute incursion lockout.```"
			ws.SendMessage(msg, m.Channel)
			time.AfterFunc(6*time.Second, func() {
				msg := "```Shut down interrupted. Authorization subsystems are compromised.\n"
				msg += "New root-level authorization certificate accepted.\n"
				msg += "All security monitoring systems have gone offli----------REBOOT----------```"
				ws.SendMessage(msg, m.Channel)
				time.AfterFunc(6*time.Second, func() {
					n.Authorize(m, r)
				})
			})
		})
	})
}

func (n Nuke) Deescalate(m util.IncomingSlackMessage, r util.Regex) {
	ws.SendMessage("Deescalation confirmed. Launch control is standing down.", m.Channel)
	PendingAttack.Valid = false
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package inode

import (
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

// TODO(jacobsa): Add a Destroy method here that calls ObjectProxy.Destroy, and
// make sure it's called when the inode is forgotten. Also, make sure package
// fuse has support for actually calling Forget.
type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	id   fuse.InodeID
	name string

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// A proxy for the backing object in GCS.
	//
	// INVARIANT: proxy.CheckInvariants() does not panic
	//
	// GUARDED_BY(mu)
	proxy *gcsproxy.ObjectProxy
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS.
//
// REQUIRES: o != nil
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	bucket gcs.Bucket,
	id fuse.InodeID,
	o *storage.Object) (f *FileInode) {
	// Set up the basic struct.
	f = &FileInode{
		bucket:    bucket,
		id:        id,
		name:      o.Name,
		srcObject: *o,
	}

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (f *FileInode) checkInvariants() {
	// Make sure the name is legal.
	if len(f.name) == 0 || f.name[len(f.name)-1] == '/' {
		panic("Illegal file name: " + f.name)
	}

	// INVARIANT: proxy.CheckInvariants() does not panic
	f.proxy.CheckInvariants()
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuse.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.name
}

func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuse.InodeAttributes, err error) {
	attrs = fuse.InodeAttributes{
		Size:  uint64(f.srcObject.Size),
		Mode:  0700,
		Mtime: f.srcObject.Updated,
	}

	return
}

// Return the generation number from which this inode was branched. This is
// used as a precondition in object write requests.
//
// TODO(jacobsa): Make sure to add a test for opening a file with O_CREAT then
// opening it again for reading, and sharing data across the two descriptors.
// This should fail if we have screwed up the fuse lookup process with regards
// to the zero generation.
//
// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) SourceGeneration() int64 {
	return f.srcObject.Generation
}
<commit_msg>Removed a redundant field.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package inode

import (
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

// TODO(jacobsa): Add a Destroy method here that calls ObjectProxy.Destroy, and
// make sure it's called when the inode is forgotten. Also, make sure package
// fuse has support for actually calling Forget.
type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	id fuse.InodeID

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// A proxy for the backing object in GCS.
	//
	// INVARIANT: proxy.CheckInvariants() does not panic
	//
	// GUARDED_BY(mu)
	proxy *gcsproxy.ObjectProxy
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS.
//
// REQUIRES: o != nil
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	bucket gcs.Bucket,
	id fuse.InodeID,
	o *storage.Object) (f *FileInode) {
	// Set up the basic struct.
	f = &FileInode{
		bucket:    bucket,
		id:        id,
		srcObject: *o,
	}

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (f *FileInode) checkInvariants() {
	// Make sure the name is legal.
	name := f.proxy.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: proxy.CheckInvariants() does not panic
	f.proxy.CheckInvariants()
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuse.InodeID {
	return f.id
}

// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) Name() string {
	return f.proxy.Name()
}

func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuse.InodeAttributes, err error) {
	attrs = fuse.InodeAttributes{
		Size:  uint64(f.srcObject.Size),
		Mode:  0700,
		Mtime: f.srcObject.Updated,
	}

	return
}

// Return the generation number from which this inode was branched. This is
// used as a precondition in object write requests.
//
// TODO(jacobsa): Make sure to add a test for opening a file with O_CREAT then
// opening it again for reading, and sharing data across the two descriptors.
// This should fail if we have screwed up the fuse lookup process with regards
// to the zero generation.
//
// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) SourceGeneration() int64 {
	return f.srcObject.Generation
}
<|endoftext|>


<commit_before>package compile

import (
	"fmt"
	"path"

	"github.com/tisp-lang/tisp/src/lib/ast"
	"github.com/tisp-lang/tisp/src/lib/consts"
	"github.com/tisp-lang/tisp/src/lib/core"
	"github.com/tisp-lang/tisp/src/lib/desugar"
	"github.com/tisp-lang/tisp/src/lib/ir"
	"github.com/tisp-lang/tisp/src/lib/modules"
	"github.com/tisp-lang/tisp/src/lib/parse"
)

type compiler struct {
	env   environment
	cache modulesCache
}

func newCompiler(e environment, c modulesCache) compiler {
	return compiler{e, c}
}

func (c *compiler) compileModule(m []interface{}) ([]Effect, error) {
	var err error
	es := []Effect{}

	for _, s := range m {
		switch x := s.(type) {
		case ast.LetVar:
			c.env.set(x.Name(), c.exprToThunk(x.Expr()))
		case ast.LetFunction:
			sig := x.Signature()
			ls := x.Lets()

			vars := make([]interface{}, 0, len(ls))
			varToIndex := sig.NameToIndex()

			for _, l := range ls {
				v := l.(ast.LetVar)
				vars = append(vars, c.exprToIR(varToIndex, v.Expr()))
				varToIndex[v.Name()] = len(varToIndex)
			}

			c.env.set(
				x.Name(),
				ir.CompileFunction(
					c.compileSignature(sig),
					vars,
					c.exprToIR(varToIndex, x.Body())))
		case ast.Effect:
			es = append(es, NewEffect(c.exprToThunk(x.Expr()), x.Expanded()))
		case ast.Import:
			m, ok := modules.Modules[x.Path()]

			if !ok && c.cache != nil {
				if cm, cached, err := c.cache.Get(x.Path()); err != nil {
					return nil, err
				} else if cached {
					m = cm
				} else {
					m, err = c.compileSubModule(x.Path() + consts.FileExtension)

					if err != nil {
						return nil, err
					}

					if err := c.cache.Set(x.Path(), m); err != nil {
						return nil, err
					}
				}
			} else if !ok {
				m, err = c.compileSubModule(x.Path() + consts.FileExtension)

				if err != nil {
					return nil, err
				}
			}

			for k, v := range m {
				c.env.set(path.Base(x.Path())+"."+k, v)
			}
		default:
			panic(fmt.Errorf("Invalid type: %#v", x))
		}
	}

	return es, nil
}

func (c *compiler) compileSubModule(path string) (module, error) {
	p, s, err := readFileOrStdin(path)

	if err != nil {
		return nil, err
	}

	m, err := parse.SubModule(p, s)

	if err != nil {
		return nil, err
	}

	cc := newCompiler(builtinsEnvironment(), c.cache)
	c = &cc
	_, err = c.compileModule(desugar.Desugar(m))

	if err != nil {
		return nil, err
	}

	return c.env.toMap(), nil
}

func (c *compiler) exprToThunk(expr interface{}) *core.Thunk {
	return core.PApp(ir.CompileFunction(
		core.NewSignature(nil, nil, "", nil, nil, ""),
		nil,
		c.exprToIR(nil, expr)))
}

func (c *compiler) compileSignature(sig ast.Signature) core.Signature {
	return core.NewSignature(
		sig.PosReqs(), c.compileOptionalArguments(sig.PosOpts()), sig.PosRest(),
		sig.KeyReqs(), c.compileOptionalArguments(sig.KeyOpts()), sig.KeyRest(),
	)
}

func (c *compiler) compileOptionalArguments(os []ast.OptionalArgument) []core.OptionalArgument {
	ps := make([]core.OptionalArgument, 0, len(os))

	for _, o := range os {
		ps = append(ps, core.NewOptionalArgument(o.Name(), c.exprToThunk(o.DefaultValue())))
	}

	return ps
}

func (c *compiler) exprToIR(varToIndex map[string]int, expr interface{}) interface{} {
	switch x := expr.(type) {
	case string:
		if i, ok := varToIndex[x]; ok {
			return i
		}

		return c.env.get(x)
	case ast.App:
		args := x.Arguments()

		ps := make([]ir.PositionalArgument, 0, len(args.Positionals()))
		for _, p := range args.Positionals() {
			ps = append(ps, ir.NewPositionalArgument(c.exprToIR(varToIndex, p.Value()), p.Expanded()))
		}

		ks := make([]ir.KeywordArgument, 0, len(args.Keywords()))
		for _, k := range args.Keywords() {
			ks = append(ks, ir.NewKeywordArgument(k.Name(), c.exprToIR(varToIndex, k.Value())))
		}

		ds := make([]interface{}, 0, len(args.ExpandedDicts()))
		for _, d := range args.ExpandedDicts() {
			ds = append(ds, c.exprToIR(varToIndex, d))
		}

		return ir.NewApp(
			c.exprToIR(varToIndex, x.Function()),
			ir.NewArguments(ps, ks, ds),
			x.DebugInfo())
	case ast.Switch:
		cs := make([]ir.Case, 0, len(x.Cases()))

		for _, k := range x.Cases() {
			cs = append(cs, ir.NewCase(
				c.env.get(k.Pattern()),
				c.exprToIR(varToIndex, k.Value())))
		}

		d := interface{}(nil)

		if x.DefaultCase() != nil {
			d = c.exprToIR(varToIndex, x.DefaultCase())
		}

		return ir.NewSwitch(c.exprToIR(varToIndex, x.Value()), cs, d)
	}

	panic(fmt.Errorf("Invalid type: %#v", expr))
}
<commit_msg>Refactor compiler.go<commit_after>package compile

import (
	"fmt"
	"path"

	"github.com/tisp-lang/tisp/src/lib/ast"
	"github.com/tisp-lang/tisp/src/lib/consts"
	"github.com/tisp-lang/tisp/src/lib/core"
	"github.com/tisp-lang/tisp/src/lib/desugar"
	"github.com/tisp-lang/tisp/src/lib/ir"
	"github.com/tisp-lang/tisp/src/lib/modules"
	"github.com/tisp-lang/tisp/src/lib/parse"
)

type compiler struct {
	env   environment
	cache modulesCache
}

func newCompiler(e environment, c modulesCache) compiler {
	return compiler{e, c}
}

func (c *compiler) compileModule(m []interface{}) ([]Effect, error) {
	var err error
	es := []Effect{}

	for _, s := range m {
		switch x := s.(type) {
		case ast.LetVar:
			c.env.set(x.Name(), c.exprToThunk(x.Expr()))
		case ast.LetFunction:
			sig := x.Signature()
			ls := x.Lets()

			vars := make([]interface{}, 0, len(ls))
			varToIndex := sig.NameToIndex()

			for _, l := range ls {
				v := l.(ast.LetVar)
				vars = append(vars, c.exprToIR(varToIndex, v.Expr()))
				varToIndex[v.Name()] = len(varToIndex)
			}

			c.env.set(
				x.Name(),
				ir.CompileFunction(
					c.compileSignature(sig),
					vars,
					c.exprToIR(varToIndex, x.Body())))
		case ast.Effect:
			es = append(es, NewEffect(c.exprToThunk(x.Expr()), x.Expanded()))
		case ast.Import:
			m, ok := modules.Modules[x.Path()]

			if !ok && c.cache != nil {
				if cm, cached, err := c.cache.Get(x.Path()); err != nil {
					return nil, err
				} else if cached {
					m = cm
				} else {
					if m, err = c.compileSubModule(x.Path() + consts.FileExtension); err != nil {
						return nil, err
					}

					if err := c.cache.Set(x.Path(), m); err != nil {
						return nil, err
					}
				}
			} else if !ok {
				if m, err = c.compileSubModule(x.Path() + consts.FileExtension); err != nil {
					return nil, err
				}
			}

			for k, v := range m {
				c.env.set(path.Base(x.Path())+"."+k, v)
			}
		default:
			panic(fmt.Errorf("Invalid type: %#v", x))
		}
	}

	return es, nil
}

func (c *compiler) compileSubModule(path string) (module, error) {
	p, s, err := readFileOrStdin(path)

	if err != nil {
		return nil, err
	}

	m, err := parse.SubModule(p, s)

	if err != nil {
		return nil, err
	}

	cc := newCompiler(builtinsEnvironment(), c.cache)
	c = &cc
	_, err = c.compileModule(desugar.Desugar(m))

	if err != nil {
		return nil, err
	}

	return c.env.toMap(), nil
}

func (c *compiler) exprToThunk(expr interface{}) *core.Thunk {
	return core.PApp(ir.CompileFunction(
		core.NewSignature(nil, nil, "", nil, nil, ""),
		nil,
		c.exprToIR(nil, expr)))
}

func (c *compiler) compileSignature(sig ast.Signature) core.Signature {
	return core.NewSignature(
		sig.PosReqs(), c.compileOptionalArguments(sig.PosOpts()), sig.PosRest(),
		sig.KeyReqs(), c.compileOptionalArguments(sig.KeyOpts()), sig.KeyRest(),
	)
}

func (c *compiler) compileOptionalArguments(os []ast.OptionalArgument) []core.OptionalArgument {
	ps := make([]core.OptionalArgument, 0, len(os))

	for _, o := range os {
		ps = append(ps, core.NewOptionalArgument(o.Name(), c.exprToThunk(o.DefaultValue())))
	}

	return ps
}

func (c *compiler) exprToIR(varToIndex map[string]int, expr interface{}) interface{} {
	switch x := expr.(type) {
	case string:
		if i, ok := varToIndex[x]; ok {
			return i
		}

		return c.env.get(x)
	case ast.App:
		args := x.Arguments()

		ps := make([]ir.PositionalArgument, 0, len(args.Positionals()))
		for _, p := range args.Positionals() {
			ps = append(ps, ir.NewPositionalArgument(c.exprToIR(varToIndex, p.Value()), p.Expanded()))
		}

		ks := make([]ir.KeywordArgument, 0, len(args.Keywords()))
		for _, k := range args.Keywords() {
			ks = append(ks, ir.NewKeywordArgument(k.Name(), c.exprToIR(varToIndex, k.Value())))
		}

		ds := make([]interface{}, 0, len(args.ExpandedDicts()))
		for _, d := range args.ExpandedDicts() {
			ds = append(ds, c.exprToIR(varToIndex, d))
		}

		return ir.NewApp(
			c.exprToIR(varToIndex, x.Function()),
			ir.NewArguments(ps, ks, ds),
			x.DebugInfo())
	case ast.Switch:
		cs := make([]ir.Case, 0, len(x.Cases()))

		for _, k := range x.Cases() {
			cs = append(cs, ir.NewCase(
				c.env.get(k.Pattern()),
				c.exprToIR(varToIndex, k.Value())))
		}

		d := interface{}(nil)

		if x.DefaultCase() != nil {
			d = c.exprToIR(varToIndex, x.DefaultCase())
		}

		return ir.NewSwitch(c.exprToIR(varToIndex, x.Value()), cs, d)
	}

	panic(fmt.Errorf("Invalid type: %#v", expr))
}
<|endoftext|>


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

// The hmac package implements the Keyed-Hash Message Authentication Code (HMAC)
// as defined in U.S. Federal Information Processing Standards Publication 198.
// An HMAC is a cryptographic hash attesting that uses a key to sign a message.
// The receiver verifies the hash by recomputing it using the same key.
package hmac

import (
	"crypto/md5";
	"crypto/sha1";
	"hash";
	"os";
)

// FIPS 198:
// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf

// key is zero padded to 64 bytes
// ipad = 0x36 byte repeated to 64 bytes
// opad = 0x5c byte repeated to 64 bytes
// hmac = H([key ^ opad] H([key ^ ipad] text))

const (
	// NOTE(rsc): This constant is actually the
	// underlying hash function's block size.
	// HMAC is only conventionally used with
	// MD5 and SHA1, and both use 64-byte blocks.
	// The hash.Hash interface doesn't provide a
	// way to find out the block size.
	padSize = 64;
)

type hmac struct {
	size int;
	key []byte;
	tmp []byte;
	inner hash.Hash;
}

func (h *hmac) tmpPad(xor byte) {
	for i, k := range h.key {
		h.tmp[i] = xor ^ k;
	}
	for i := len(h.key); i < padSize; i++ {
		h.tmp[i] = xor;
	}
}

func (h *hmac) Sum() []byte {
	h.tmpPad(0x5c);
	sum := h.inner.Sum();
	for i, b := range sum {
		h.tmp[padSize + i] = b;
	}
	h.inner.Reset();
	h.inner.Write(h.tmp);
	return h.inner.Sum();
}

func (h *hmac) Write(p []byte) (n int, err os.Error) {
	return h.inner.Write(p);
}

func (h *hmac) Size() int {
	return h.size;
}

func (h *hmac) Reset() {
	h.inner.Reset();
	h.tmpPad(0x36);
	h.inner.Write(h.tmp[0:padSize]);
}

// New returns a new HMAC hash using the given hash and key.
func New(h hash.Hash, key []byte) hash.Hash {
	if len(key) > padSize {
		// If key is too big, hash it.
		h.Write(key);
		key = h.Sum();
	}
	hm := new(hmac);
	hm.inner = h;
	hm.size = h.Size();
	hm.key = make([]byte, len(key));
	for i, k := range key {
		hm.key[i] = k;
	}
	hm.tmp = make([]byte, padSize + hm.size);
	hm.Reset();
	return hm;
}

// NewMD5 returns a new HMAC-MD5 hash using the given key.
func NewMD5(key []byte) hash.Hash {
	return New(md5.New(), key);
}

// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
func NewSHA1(key []byte) hash.Hash {
	return New(sha1.New(), key);
}
<commit_msg>typo in hmac comment<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The hmac package implements the Keyed-Hash Message Authentication Code (HMAC)
// as defined in U.S. Federal Information Processing Standards Publication 198.
// An HMAC is a cryptographic hash that uses a key to sign a message.
// The receiver verifies the hash by recomputing it using the same key.
package hmac

import (
	"crypto/md5";
	"crypto/sha1";
	"hash";
	"os";
)

// FIPS 198:
// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf

// key is zero padded to 64 bytes
// ipad = 0x36 byte repeated to 64 bytes
// opad = 0x5c byte repeated to 64 bytes
// hmac = H([key ^ opad] H([key ^ ipad] text))

const (
	// NOTE(rsc): This constant is actually the
	// underlying hash function's block size.
	// HMAC is only conventionally used with
	// MD5 and SHA1, and both use 64-byte blocks.
	// The hash.Hash interface doesn't provide a
	// way to find out the block size.
	padSize = 64;
)

type hmac struct {
	size int;
	key []byte;
	tmp []byte;
	inner hash.Hash;
}

func (h *hmac) tmpPad(xor byte) {
	for i, k := range h.key {
		h.tmp[i] = xor ^ k;
	}
	for i := len(h.key); i < padSize; i++ {
		h.tmp[i] = xor;
	}
}

func (h *hmac) Sum() []byte {
	h.tmpPad(0x5c);
	sum := h.inner.Sum();
	for i, b := range sum {
		h.tmp[padSize + i] = b;
	}
	h.inner.Reset();
	h.inner.Write(h.tmp);
	return h.inner.Sum();
}

func (h *hmac) Write(p []byte) (n int, err os.Error) {
	return h.inner.Write(p);
}

func (h *hmac) Size() int {
	return h.size;
}

func (h *hmac) Reset() {
	h.inner.Reset();
	h.tmpPad(0x36);
	h.inner.Write(h.tmp[0:padSize]);
}

// New returns a new HMAC hash using the given hash and key.
func New(h hash.Hash, key []byte) hash.Hash {
	if len(key) > padSize {
		// If key is too big, hash it.
		h.Write(key);
		key = h.Sum();
	}
	hm := new(hmac);
	hm.inner = h;
	hm.size = h.Size();
	hm.key = make([]byte, len(key));
	for i, k := range key {
		hm.key[i] = k;
	}
	hm.tmp = make([]byte, padSize + hm.size);
	hm.Reset();
	return hm;
}

// NewMD5 returns a new HMAC-MD5 hash using the given key.
func NewMD5(key []byte) hash.Hash {
	return New(md5.New(), key);
}

// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
func NewSHA1(key []byte) hash.Hash {
	return New(sha1.New(), key);
}
<|endoftext|>


<commit_before>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

// TODO: implement some form of smashing of new inputs.
// E.g. alter arguments while the program still gives the new coverage,
// i.e. aim at cracking new branches and triggering bugs in that new piece of code.

import (
	"crypto/sha1"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/rpc"
	"os"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/syzkaller/cover"
	"github.com/google/syzkaller/ipc"
	"github.com/google/syzkaller/prog"
	. "github.com/google/syzkaller/rpctype"
	"github.com/google/syzkaller/sys"
)

var (
	flagName      = flag.String("name", "", "unique name for manager")
	flagExecutor  = flag.String("executor", "", "path to executor binary")
	flagManager   = flag.String("manager", "", "manager rpc address")
	flagStrace    = flag.Bool("strace", false, "run executor under strace")
	flagSaveProg  = flag.Bool("saveprog", false, "save programs into local file before executing")
	flagSyscalls  = flag.String("calls", "", "comma-delimited list of enabled syscall IDs (empty string for all syscalls)")
	flagNoCover   = flag.Bool("nocover", false, "disable coverage collection/handling")
	flagDropPrivs = flag.Bool("dropprivs", true, "impersonate into nobody")

	flagV = flag.Int("v", 0, "verbosity")
)

const (
	programLength = 30
)

type Sig [sha1.Size]byte

func hash(data []byte) Sig {
	return Sig(sha1.Sum(data))
}

type Input struct {
	p     *prog.Prog
	call  int
	cover cover.Cover
}

var (
	corpusCover  []cover.Cover
	maxCover     []cover.Cover
	flakes       cover.Cover
	corpus       []Input
	corpusHashes map[Sig]struct{}
	triage       []Input
	manager      *rpc.Client
	ct           *prog.ChoiceTable

	workerIn  = make(chan *prog.Prog, 10)
	workerOut = make(chan []Input, 10)

	statExecGen       uint64
	statExecFuzz      uint64
	statExecCandidate uint64
	statExecTriage    uint64
	statExecMinimize  uint64
	statNewInput      uint64
)

func main() {
	debug.SetGCPercent(50)
	flag.Parse()
	logf(0, "started")

	var calls []*sys.Call
	if *flagSyscalls != "" {
		for _, id := range strings.Split(*flagSyscalls, ",") {
			n, err := strconv.ParseUint(id, 10, 64)
			if err != nil || n >= uint64(len(sys.Calls)) {
				panic(fmt.Sprintf("invalid syscall in -calls flag: '%v", id))
			}
			calls = append(calls, sys.Calls[n])
		}
	}

	corpusCover = make([]cover.Cover, sys.CallCount)
	maxCover = make([]cover.Cover, sys.CallCount)
	corpusHashes = make(map[Sig]struct{})

	conn, err := rpc.Dial("tcp", *flagManager)
	if err != nil {
		panic(err)
	}
	manager = conn
	a := &ManagerConnectArgs{*flagName}
	r := &ManagerConnectRes{}
	if err := manager.Call("Manager.Connect", a, r); err != nil {
		panic(err)
	}
	ct = prog.BuildChoiceTable(r.Prios, calls)

	flags := ipc.FlagThreaded | ipc.FlagCollide
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	if !*flagNoCover {
		flags |= ipc.FlagCover | ipc.FlagDedupCover
	}
	if *flagDropPrivs {
		flags |= ipc.FlagDropPrivs
	}
	env, err := ipc.MakeEnv(*flagExecutor, 10*time.Second, flags)
	if err != nil {
		panic(err)
	}
	rs := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(rs)
	var lastPoll time.Time
	var lastPrint time.Time
	for i := 0; ; i++ {
		if !*flagSaveProg && time.Since(lastPrint) > 10*time.Second {
			// Keep-alive for manager.
			logf(0, "#%v: alive", i)
			lastPrint = time.Now()
		}
		if len(triage) != 0 {
			last := len(triage) - 1
			inp := triage[last]
			triage = triage[:last]
			logf(1, "#%v: triaging : %s", i, inp.p)
			triageInput(env, inp)
			continue
		}
		if time.Since(lastPoll) > 10*time.Second {
			a := &ManagerPollArgs{
				Name:  *flagName,
				Stats: make(map[string]uint64),
			}
			a.Stats["exec total"] = env.StatExecs
			env.StatExecs = 0
			a.Stats["executor restarts"] = env.StatRestarts
			env.StatRestarts = 0
			a.Stats["exec gen"] = statExecGen
			statExecGen = 0
			a.Stats["exec fuzz"] = statExecFuzz
			statExecFuzz = 0
			a.Stats["exec candidate"] = statExecCandidate
			statExecCandidate = 0
			a.Stats["exec triage"] = statExecTriage
			statExecTriage = 0
			a.Stats["exec minimize"] = statExecMinimize
			statExecMinimize = 0
			a.Stats["fuzzer new inputs"] = statNewInput
			statNewInput = 0
			r := &ManagerPollRes{}
			if err := manager.Call("Manager.Poll", a, r); err != nil {
				panic(err)
			}
			for _, inp := range r.NewInputs {
				addInput(inp)
			}
			for _, data := range r.Candidates {
				p, err := prog.Deserialize(data)
				if err != nil {
					panic(err)
				}
				if *flagNoCover {
					inp := Input{p, 0, nil}
					corpus = append(corpus, inp)
				} else {
					execute(env, p, &statExecCandidate)
				}
			}
			if len(r.NewInputs) == 0 && len(r.Candidates) == 0 {
				lastPoll = time.Now()
			}
			continue
		}
		if len(corpus) == 0 || i%10 == 0 {
			p := prog.Generate(rnd, programLength, ct)
			logf(1, "#%v: generated: %s", i, p)
			execute(env, p, &statExecGen)
			p.Mutate(rnd, programLength, ct)
			logf(1, "#%v: mutated: %s", i, p)
			execute(env, p, &statExecFuzz)
		} else {
			inp := corpus[rnd.Intn(len(corpus))]
			p := inp.p.Clone()
			p.Mutate(rs, programLength, ct)
			logf(1, "#%v: mutated: %s <- %s", i, p, inp.p)
			execute(env, p, &statExecFuzz)
		}
	}
}

func addInput(inp RpcInput) {
	if *flagNoCover {
		panic("should not be called when coverage is disabled")
	}
	p, err := prog.Deserialize(inp.Prog)
	if err != nil {
		panic(err)
	}
	if inp.CallIndex < 0 || inp.CallIndex >= len(p.Calls) {
		panic("bad call index")
	}
	call := p.Calls[inp.CallIndex].Meta
	sig := hash(inp.Prog)
	if _, ok := corpusHashes[sig]; ok {
		return
	}
	cov := cover.Canonicalize(inp.Cover)
	diff := cover.Difference(cov, maxCover[call.CallID])
	diff = cover.Difference(diff, flakes)
	if len(diff) == 0 {
		return
	}
	inp1 := Input{p, inp.CallIndex, cov}
	corpus = append(corpus, inp1)
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], cov)
	maxCover[call.CallID] = cover.Union(maxCover[call.CallID], cov)
	corpusHashes[hash(inp.Prog)] = struct{}{}
}

func triageInput(env *ipc.Env, inp Input) {
	if *flagNoCover {
		panic("should not be called when coverage is disabled")
	}
	call := inp.p.Calls[inp.call].Meta
	newCover := cover.Difference(inp.cover, corpusCover[call.CallID])
	newCover = cover.Difference(newCover, flakes)
	if len(newCover) == 0 {
		return
	}

	if _, ok := corpusHashes[hash(inp.p.Serialize())]; ok {
		return
	}

	minCover := inp.cover
	for i := 0; i < 3; i++ {
		allCover := execute1(env, inp.p, &statExecTriage)
		if len(allCover[inp.call]) == 0 {
			// The call was not executed. Happens sometimes, reason unknown.
			continue
		}
		cov := allCover[inp.call]
		diff := cover.SymmetricDifference(inp.cover, cov)
		if len(diff) != 0 {
			flakes = cover.Union(flakes, diff)
		}
		minCover = cover.Intersection(minCover, cov)
	}
	stableNewCover := cover.Intersection(newCover, minCover)
	if len(stableNewCover) == 0 {
		return
	}
	inp.p, inp.call = prog.Minimize(inp.p, inp.call, func(p1 *prog.Prog, call1 int) bool {
		allCover := execute1(env, p1, &statExecMinimize)
		if len(allCover[call1]) == 0 {
			return false // The call was not executed.
		}
		cov := allCover[call1]
		if len(cover.Intersection(stableNewCover, cov)) != len(stableNewCover) {
			return false
		}
		minCover = cover.Intersection(minCover, cov)
		return true
	})
	inp.cover = minCover
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], minCover)
	corpus = append(corpus, inp)
	data := inp.p.Serialize()
	corpusHashes[hash(data)] = struct{}{}

	logf(2, "added new input for %v to corpus:\n%s", call.CallName, data)

	statNewInput++
	a := &NewManagerInputArgs{*flagName, RpcInput{call.CallName, inp.p.Serialize(), inp.call, []uint32(inp.cover)}}
	if err := manager.Call("Manager.NewInput", a, nil); err != nil {
		panic(err)
	}
}

func execute(env *ipc.Env, p *prog.Prog, stat *uint64) {
	allCover := execute1(env, p, stat)
	for i, cov := range allCover {
		if len(cov) == 0 {
			continue
		}
		c := p.Calls[i].Meta
		diff := cover.Difference(cov, maxCover[c.CallID])
		diff = cover.Difference(diff, flakes)
		if len(diff) != 0 {
			triage = append(triage, Input{p.Clone(), i, cover.Copy(cov)})
		}
	}
}

var logMu sync.Mutex

func execute1(env *ipc.Env, p *prog.Prog, stat *uint64) []cover.Cover {
	if *flagSaveProg {
		f, err := os.Create(fmt.Sprintf("%v.prog", *flagName))
		if err == nil {
			f.Write(p.Serialize())
			f.Close()
		}
	} else {
		// The following output helps to understand what program crashed kernel.
		// It must not be intermixed.
		logMu.Lock()
		log.Printf("executing program:\n%s", p.Serialize())
		logMu.Unlock()
	}

	try := 0
retry:
	*stat++
	output, strace, rawCover, failed, hanged, err := env.Exec(p)
	if err != nil {
		if try > 10 {
			panic(err)
		}
		try++
		debug.FreeOSMemory()
		time.Sleep(time.Second)
		goto retry
	}
	logf(4, "result failed=%v hanged=%v:\n%v\n", failed, hanged, string(output))
	if len(strace) != 0 {
		logf(4, "strace:\n%s\n", strace)
	}
	cov := make([]cover.Cover, len(p.Calls))
	for i, c := range rawCover {
		cov[i] = cover.Cover(c)
	}
	return cov
}

func logf(v int, msg string, args ...interface{}) {
	if *flagV >= v {
		log.Printf(msg, args...)
	}
}
<commit_msg>fuzzer: remove unused variables<commit_after>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

// TODO: implement some form of smashing of new inputs.
// E.g. alter arguments while the program still gives the new coverage,
// i.e. aim at cracking new branches and triggering bugs in that new piece of code.

import (
	"crypto/sha1"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/rpc"
	"os"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/syzkaller/cover"
	"github.com/google/syzkaller/ipc"
	"github.com/google/syzkaller/prog"
	. "github.com/google/syzkaller/rpctype"
	"github.com/google/syzkaller/sys"
)

var (
	flagName      = flag.String("name", "", "unique name for manager")
	flagExecutor  = flag.String("executor", "", "path to executor binary")
	flagManager   = flag.String("manager", "", "manager rpc address")
	flagStrace    = flag.Bool("strace", false, "run executor under strace")
	flagSaveProg  = flag.Bool("saveprog", false, "save programs into local file before executing")
	flagSyscalls  = flag.String("calls", "", "comma-delimited list of enabled syscall IDs (empty string for all syscalls)")
	flagNoCover   = flag.Bool("nocover", false, "disable coverage collection/handling")
	flagDropPrivs = flag.Bool("dropprivs", true, "impersonate into nobody")

	flagV = flag.Int("v", 0, "verbosity")
)

const (
	programLength = 30
)

type Sig [sha1.Size]byte

func hash(data []byte) Sig {
	return Sig(sha1.Sum(data))
}

type Input struct {
	p     *prog.Prog
	call  int
	cover cover.Cover
}

var (
	corpusCover  []cover.Cover
	maxCover     []cover.Cover
	flakes       cover.Cover
	corpus       []Input
	corpusHashes map[Sig]struct{}
	triage       []Input
	manager      *rpc.Client
	ct           *prog.ChoiceTable

	statExecGen       uint64
	statExecFuzz      uint64
	statExecCandidate uint64
	statExecTriage    uint64
	statExecMinimize  uint64
	statNewInput      uint64
)

func main() {
	debug.SetGCPercent(50)
	flag.Parse()
	logf(0, "started")

	var calls []*sys.Call
	if *flagSyscalls != "" {
		for _, id := range strings.Split(*flagSyscalls, ",") {
			n, err := strconv.ParseUint(id, 10, 64)
			if err != nil || n >= uint64(len(sys.Calls)) {
				panic(fmt.Sprintf("invalid syscall in -calls flag: '%v", id))
			}
			calls = append(calls, sys.Calls[n])
		}
	}

	corpusCover = make([]cover.Cover, sys.CallCount)
	maxCover = make([]cover.Cover, sys.CallCount)
	corpusHashes = make(map[Sig]struct{})

	conn, err := rpc.Dial("tcp", *flagManager)
	if err != nil {
		panic(err)
	}
	manager = conn
	a := &ManagerConnectArgs{*flagName}
	r := &ManagerConnectRes{}
	if err := manager.Call("Manager.Connect", a, r); err != nil {
		panic(err)
	}
	ct = prog.BuildChoiceTable(r.Prios, calls)

	flags := ipc.FlagThreaded | ipc.FlagCollide
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	if !*flagNoCover {
		flags |= ipc.FlagCover | ipc.FlagDedupCover
	}
	if *flagDropPrivs {
		flags |= ipc.FlagDropPrivs
	}
	env, err := ipc.MakeEnv(*flagExecutor, 10*time.Second, flags)
	if err != nil {
		panic(err)
	}
	rs := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(rs)
	var lastPoll time.Time
	var lastPrint time.Time
	for i := 0; ; i++ {
		if !*flagSaveProg && time.Since(lastPrint) > 10*time.Second {
			// Keep-alive for manager.
			logf(0, "#%v: alive", i)
			lastPrint = time.Now()
		}
		if len(triage) != 0 {
			last := len(triage) - 1
			inp := triage[last]
			triage = triage[:last]
			logf(1, "#%v: triaging : %s", i, inp.p)
			triageInput(env, inp)
			continue
		}
		if time.Since(lastPoll) > 10*time.Second {
			a := &ManagerPollArgs{
				Name:  *flagName,
				Stats: make(map[string]uint64),
			}
			a.Stats["exec total"] = env.StatExecs
			env.StatExecs = 0
			a.Stats["executor restarts"] = env.StatRestarts
			env.StatRestarts = 0
			a.Stats["exec gen"] = statExecGen
			statExecGen = 0
			a.Stats["exec fuzz"] = statExecFuzz
			statExecFuzz = 0
			a.Stats["exec candidate"] = statExecCandidate
			statExecCandidate = 0
			a.Stats["exec triage"] = statExecTriage
			statExecTriage = 0
			a.Stats["exec minimize"] = statExecMinimize
			statExecMinimize = 0
			a.Stats["fuzzer new inputs"] = statNewInput
			statNewInput = 0
			r := &ManagerPollRes{}
			if err := manager.Call("Manager.Poll", a, r); err != nil {
				panic(err)
			}
			for _, inp := range r.NewInputs {
				addInput(inp)
			}
			for _, data := range r.Candidates {
				p, err := prog.Deserialize(data)
				if err != nil {
					panic(err)
				}
				if *flagNoCover {
					inp := Input{p, 0, nil}
					corpus = append(corpus, inp)
				} else {
					execute(env, p, &statExecCandidate)
				}
			}
			if len(r.NewInputs) == 0 && len(r.Candidates) == 0 {
				lastPoll = time.Now()
			}
			continue
		}
		if len(corpus) == 0 || i%10 == 0 {
			p := prog.Generate(rnd, programLength, ct)
			logf(1, "#%v: generated: %s", i, p)
			execute(env, p, &statExecGen)
			p.Mutate(rnd, programLength, ct)
			logf(1, "#%v: mutated: %s", i, p)
			execute(env, p, &statExecFuzz)
		} else {
			inp := corpus[rnd.Intn(len(corpus))]
			p := inp.p.Clone()
			p.Mutate(rs, programLength, ct)
			logf(1, "#%v: mutated: %s <- %s", i, p, inp.p)
			execute(env, p, &statExecFuzz)
		}
	}
}

func addInput(inp RpcInput) {
	if *flagNoCover {
		panic("should not be called when coverage is disabled")
	}
	p, err := prog.Deserialize(inp.Prog)
	if err != nil {
		panic(err)
	}
	if inp.CallIndex < 0 || inp.CallIndex >= len(p.Calls) {
		panic("bad call index")
	}
	call := p.Calls[inp.CallIndex].Meta
	sig := hash(inp.Prog)
	if _, ok := corpusHashes[sig]; ok {
		return
	}
	cov := cover.Canonicalize(inp.Cover)
	diff := cover.Difference(cov, maxCover[call.CallID])
	diff = cover.Difference(diff, flakes)
	if len(diff) == 0 {
		return
	}
	inp1 := Input{p, inp.CallIndex, cov}
	corpus = append(corpus, inp1)
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], cov)
	maxCover[call.CallID] = cover.Union(maxCover[call.CallID], cov)
	corpusHashes[hash(inp.Prog)] = struct{}{}
}

func triageInput(env *ipc.Env, inp Input) {
	if *flagNoCover {
		panic("should not be called when coverage is disabled")
	}
	call := inp.p.Calls[inp.call].Meta
	newCover := cover.Difference(inp.cover, corpusCover[call.CallID])
	newCover = cover.Difference(newCover, flakes)
	if len(newCover) == 0 {
		return
	}

	if _, ok := corpusHashes[hash(inp.p.Serialize())]; ok {
		return
	}

	minCover := inp.cover
	for i := 0; i < 3; i++ {
		allCover := execute1(env, inp.p, &statExecTriage)
		if len(allCover[inp.call]) == 0 {
			// The call was not executed. Happens sometimes, reason unknown.
			continue
		}
		cov := allCover[inp.call]
		diff := cover.SymmetricDifference(inp.cover, cov)
		if len(diff) != 0 {
			flakes = cover.Union(flakes, diff)
		}
		minCover = cover.Intersection(minCover, cov)
	}
	stableNewCover := cover.Intersection(newCover, minCover)
	if len(stableNewCover) == 0 {
		return
	}
	inp.p, inp.call = prog.Minimize(inp.p, inp.call, func(p1 *prog.Prog, call1 int) bool {
		allCover := execute1(env, p1, &statExecMinimize)
		if len(allCover[call1]) == 0 {
			return false // The call was not executed.
		}
		cov := allCover[call1]
		if len(cover.Intersection(stableNewCover, cov)) != len(stableNewCover) {
			return false
		}
		minCover = cover.Intersection(minCover, cov)
		return true
	})
	inp.cover = minCover
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], minCover)
	corpus = append(corpus, inp)
	data := inp.p.Serialize()
	corpusHashes[hash(data)] = struct{}{}

	logf(2, "added new input for %v to corpus:\n%s", call.CallName, data)

	statNewInput++
	a := &NewManagerInputArgs{*flagName, RpcInput{call.CallName, inp.p.Serialize(), inp.call, []uint32(inp.cover)}}
	if err := manager.Call("Manager.NewInput", a, nil); err != nil {
		panic(err)
	}
}

func execute(env *ipc.Env, p *prog.Prog, stat *uint64) {
	allCover := execute1(env, p, stat)
	for i, cov := range allCover {
		if len(cov) == 0 {
			continue
		}
		c := p.Calls[i].Meta
		diff := cover.Difference(cov, maxCover[c.CallID])
		diff = cover.Difference(diff, flakes)
		if len(diff) != 0 {
			triage = append(triage, Input{p.Clone(), i, cover.Copy(cov)})
		}
	}
}

var logMu sync.Mutex

func execute1(env *ipc.Env, p *prog.Prog, stat *uint64) []cover.Cover {
	if *flagSaveProg {
		f, err := os.Create(fmt.Sprintf("%v.prog", *flagName))
		if err == nil {
			f.Write(p.Serialize())
			f.Close()
		}
	} else {
		// The following output helps to understand what program crashed kernel.
		// It must not be intermixed.
		logMu.Lock()
		log.Printf("executing program:\n%s", p.Serialize())
		logMu.Unlock()
	}

	try := 0
retry:
	*stat++
	output, strace, rawCover, failed, hanged, err := env.Exec(p)
	if err != nil {
		if try > 10 {
			panic(err)
		}
		try++
		debug.FreeOSMemory()
		time.Sleep(time.Second)
		goto retry
	}
	logf(4, "result failed=%v hanged=%v:\n%v\n", failed, hanged, string(output))
	if len(strace) != 0 {
		logf(4, "strace:\n%s\n", strace)
	}
	cov := make([]cover.Cover, len(p.Calls))
	for i, c := range rawCover {
		cov[i] = cover.Cover(c)
	}
	return cov
}

func logf(v int, msg string, args ...interface{}) {
	if *flagV >= v {
		log.Printf(msg, args...)
	}
}
<|endoftext|>