<commit_before>// Package nosurf implements an HTTP handler that
// mitigates Cross-Site Request Forgery Attacks.
package nosurf

import (
	"errors"
	"net/http"
	"net/url"
	"regexp"
)

const (
	// the name of CSRF cookie
	CookieName = "csrf_token"
	// the name of the form field
	FormFieldName = "csrf_token"
	// the name of CSRF header
	HeaderName = "X-CSRF-Token"
	// the HTTP status code for the default failure handler
	FailureCode = 400

	// Max-Age in seconds for the default base cookie. 365 days.
	MaxAge = 365 * 24 * 60 * 60
)

var safeMethods = []string{"GET", "HEAD", "OPTIONS", "TRACE"}

// reasons for CSRF check failures
var (
	ErrNoReferer  = errors.New("A secure request contained no Referer or its value was malformed")
	ErrBadReferer = errors.New("A secure request's Referer comes from a different Origin" +
		" from the request's URL")
	ErrBadToken = errors.New("The CSRF token in the cookie doesn't match the one" +
		" received in a form/header.")
)

type CSRFHandler struct {
	// Handlers that CSRFHandler wraps.
	successHandler http.Handler
	failureHandler http.Handler

	// The base cookie that CSRF cookies will be built upon.
	// This should be a better solution of customizing the options
	// than a bunch of methods SetCookieExpiration(), etc.
	baseCookie http.Cookie

	// Slices of paths that are exempt from CSRF checks.
	// They can be specified by...
	// ...an exact path,
	exemptPaths []string
	// ...a regexp,
	exemptRegexps []*regexp.Regexp
	// ...or a glob (as used by path.Match()).
	exemptGlobs []string

	// All of those will be matched against Request.URL.Path,
	// So they should take the leading slash into account
}

func defaultFailureHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(FailureCode)
}

// Constructs a new CSRFHandler that calls
// the specified handler if the CSRF check succeeds.
func New(handler http.Handler) *CSRFHandler {
	baseCookie := http.Cookie{}
	baseCookie.MaxAge = MaxAge

	csrf := &CSRFHandler{successHandler: handler,
		failureHandler: http.HandlerFunc(defaultFailureHandler),
		baseCookie:     baseCookie,
	}

	return csrf
}

func (h *CSRFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Vary", "Cookie")

	var realToken []byte

	token_cookie, err := r.Cookie(CookieName)
	if err == http.ErrNoCookie {
		h.RegenerateToken(w, r)
	} else {
		realToken = b64decode(token_cookie.Value)
	}

	// If the length of the real token isn't what it should be,
	// it has either been tampered with,
	// or we're migrating onto a new algorithm for generating tokens,
	// or it hasn't ever been set so far.
	// In any case of those, we should regenerate it.
	//
	// As a consequence, CSRF check will fail when comparing the tokens later on,
	// so we don't have to fail it just yet.
	if len(realToken) != tokenLength {
		h.RegenerateToken(w, r)
	} else {
		ctxSetToken(r, realToken)
	}

	if sContains(safeMethods, r.Method) {
		// short-circuit with a success for safe methods
		h.handleSuccess(w, r)
		return
	}

	if h.IsExempt(r.URL.Path) {
		h.handleSuccess(w, r)
		return
	}

	// if the request is secure, we enforce origin check
	// for referer to prevent MITM of http->https requests
	if r.URL.Scheme == "https" {
		referer, err := url.Parse(r.Header.Get("Referer"))

		// if we can't parse the referer or it's empty,
		// we assume it's not specified
		if err != nil || referer.String() == "" {
			ctxSetReason(r, ErrNoReferer)
			h.handleFailure(w, r)
			return
		}

		// if the referer doesn't share origin with the request URL,
		// we have another error for that
		if !sameOrigin(referer, r.URL) {
			ctxSetReason(r, ErrBadReferer)
			h.handleFailure(w, r)
			return
		}
	}

	// Finally, we check the token itself.

	// Prefer the header over form value
	var sentToken []byte
	sentToken = b64decode(r.Header.Get(HeaderName))
	if len(sentToken) == 0 {
		sentToken = b64decode(r.PostFormValue(FormFieldName))
	}

	equals := verifyToken(realToken, sentToken)
	if !equals {
		ctxSetReason(r, ErrBadToken)
		h.handleFailure(w, r)
		return
	}

	// Everything else passed, handle the success.
	h.handleSuccess(w, r)
}

// handleSuccess simply calls the successHandler.
// Everything else, like setting a token in the context
// is taken care of by h.ServeHTTP()
func (h *CSRFHandler) handleSuccess(w http.ResponseWriter, r *http.Request) {
	h.successHandler.ServeHTTP(w, r)
}

// Same applies here: h.ServeHTTP() sets the failure reason, the token,
// and only then calls handleFailure()
func (h *CSRFHandler) handleFailure(w http.ResponseWriter, r *http.Request) {
	h.failureHandler.ServeHTTP(w, r)
}

// Generates a new token, sets it on the given request and returns it
func (h *CSRFHandler) RegenerateToken(w http.ResponseWriter, r *http.Request) string {
	token := generateToken()
	h.setTokenCookie(w, r, token)

	return Token(r)
}

func (h *CSRFHandler) setTokenCookie(w http.ResponseWriter, r *http.Request, token []byte) {
	// ctxSetToken() does the encryption for us
	ctxSetToken(r, token)

	cookie := h.baseCookie
	cookie.Name = CookieName
	cookie.Value = b64encode(token)

	http.SetCookie(w, &cookie)

}

// Sets the handler to call in case the CSRF check
// fails. By default it's defaultFailureHandler.
func (h *CSRFHandler) SetFailureHandler(handler http.Handler) {
	h.failureHandler = handler
}

// Sets the base cookie to use when building a CSRF token cookie
// This way you can specify the Domain, Path, HttpOnly, Secure, etc.
func (h *CSRFHandler) SetBaseCookie(cookie http.Cookie) {
	h.baseCookie = cookie
}
<commit_msg>Remove unnecessary double token generation. Fixes #6<commit_after>// Package nosurf implements an HTTP handler that
// mitigates Cross-Site Request Forgery Attacks.
package nosurf

import (
	"errors"
	"net/http"
	"net/url"
	"regexp"
)

const (
	// the name of CSRF cookie
	CookieName = "csrf_token"
	// the name of the form field
	FormFieldName = "csrf_token"
	// the name of CSRF header
	HeaderName = "X-CSRF-Token"
	// the HTTP status code for the default failure handler
	FailureCode = 400

	// Max-Age in seconds for the default base cookie. 365 days.
	MaxAge = 365 * 24 * 60 * 60
)

var safeMethods = []string{"GET", "HEAD", "OPTIONS", "TRACE"}

// reasons for CSRF check failures
var (
	ErrNoReferer  = errors.New("A secure request contained no Referer or its value was malformed")
	ErrBadReferer = errors.New("A secure request's Referer comes from a different Origin" +
		" from the request's URL")
	ErrBadToken = errors.New("The CSRF token in the cookie doesn't match the one" +
		" received in a form/header.")
)

type CSRFHandler struct {
	// Handlers that CSRFHandler wraps.
	successHandler http.Handler
	failureHandler http.Handler

	// The base cookie that CSRF cookies will be built upon.
	// This should be a better solution of customizing the options
	// than a bunch of methods SetCookieExpiration(), etc.
	baseCookie http.Cookie

	// Slices of paths that are exempt from CSRF checks.
	// They can be specified by...
	// ...an exact path,
	exemptPaths []string
	// ...a regexp,
	exemptRegexps []*regexp.Regexp
	// ...or a glob (as used by path.Match()).
	exemptGlobs []string

	// All of those will be matched against Request.URL.Path,
	// So they should take the leading slash into account
}

func defaultFailureHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(FailureCode)
}

// Constructs a new CSRFHandler that calls
// the specified handler if the CSRF check succeeds.
func New(handler http.Handler) *CSRFHandler {
	baseCookie := http.Cookie{}
	baseCookie.MaxAge = MaxAge

	csrf := &CSRFHandler{successHandler: handler,
		failureHandler: http.HandlerFunc(defaultFailureHandler),
		baseCookie:     baseCookie,
	}

	return csrf
}

func (h *CSRFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Vary", "Cookie")

	var realToken []byte

	token_cookie, err := r.Cookie(CookieName)
	if err == nil {
		realToken = b64decode(token_cookie.Value)
	}

	// If the length of the real token isn't what it should be,
	// it has either been tampered with,
	// or we're migrating onto a new algorithm for generating tokens,
	// or it hasn't ever been set so far.
	// In any case of those, we should regenerate it.
	//
	// As a consequence, CSRF check will fail when comparing the tokens later on,
	// so we don't have to fail it just yet.
	if len(realToken) != tokenLength {
		h.RegenerateToken(w, r)
	} else {
		ctxSetToken(r, realToken)
	}

	if sContains(safeMethods, r.Method) {
		// short-circuit with a success for safe methods
		h.handleSuccess(w, r)
		return
	}

	if h.IsExempt(r.URL.Path) {
		h.handleSuccess(w, r)
		return
	}

	// if the request is secure, we enforce origin check
	// for referer to prevent MITM of http->https requests
	if r.URL.Scheme == "https" {
		referer, err := url.Parse(r.Header.Get("Referer"))

		// if we can't parse the referer or it's empty,
		// we assume it's not specified
		if err != nil || referer.String() == "" {
			ctxSetReason(r, ErrNoReferer)
			h.handleFailure(w, r)
			return
		}

		// if the referer doesn't share origin with the request URL,
		// we have another error for that
		if !sameOrigin(referer, r.URL) {
			ctxSetReason(r, ErrBadReferer)
			h.handleFailure(w, r)
			return
		}
	}

	// Finally, we check the token itself.

	// Prefer the header over form value
	var sentToken []byte
	sentToken = b64decode(r.Header.Get(HeaderName))
	if len(sentToken) == 0 {
		sentToken = b64decode(r.PostFormValue(FormFieldName))
	}

	equals := verifyToken(realToken, sentToken)
	if !equals {
		ctxSetReason(r, ErrBadToken)
		h.handleFailure(w, r)
		return
	}

	// Everything else passed, handle the success.
	h.handleSuccess(w, r)
}

// handleSuccess simply calls the successHandler.
// Everything else, like setting a token in the context
// is taken care of by h.ServeHTTP()
func (h *CSRFHandler) handleSuccess(w http.ResponseWriter, r *http.Request) {
	h.successHandler.ServeHTTP(w, r)
}

// Same applies here: h.ServeHTTP() sets the failure reason, the token,
// and only then calls handleFailure()
func (h *CSRFHandler) handleFailure(w http.ResponseWriter, r *http.Request) {
	h.failureHandler.ServeHTTP(w, r)
}

// Generates a new token, sets it on the given request and returns it
func (h *CSRFHandler) RegenerateToken(w http.ResponseWriter, r *http.Request) string {
	token := generateToken()
	h.setTokenCookie(w, r, token)

	return Token(r)
}

func (h *CSRFHandler) setTokenCookie(w http.ResponseWriter, r *http.Request, token []byte) {
	// ctxSetToken() does the encryption for us
	ctxSetToken(r, token)

	cookie := h.baseCookie
	cookie.Name = CookieName
	cookie.Value = b64encode(token)

	http.SetCookie(w, &cookie)

}

// Sets the handler to call in case the CSRF check
// fails. By default it's defaultFailureHandler.
func (h *CSRFHandler) SetFailureHandler(handler http.Handler) {
	h.failureHandler = handler
}

// Sets the base cookie to use when building a CSRF token cookie
// This way you can specify the Domain, Path, HttpOnly, Secure, etc.
func (h *CSRFHandler) SetBaseCookie(cookie http.Cookie) {
	h.baseCookie = cookie
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 VMware, 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 methods

import (
	"bytes"
	"reflect"
	"testing"

	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"
	"github.com/vmware/govmomi/vim25/xml"
)

var invalidLoginFault = `
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<soapenv:Fault><faultcode>ServerFaultCode</faultcode><faultstring>Cannot complete login due to an incorrect user name or password.</faultstring><detail><InvalidLoginFault xmlns="urn:vim25" xsi:type="InvalidLogin"></InvalidLoginFault></detail></soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>`

type TestBody struct {
	Fault *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}

func TestFaultDetail(t *testing.T) {
	body := TestBody{}
	env := soap.Envelope{Body: &body}

	dec := xml.NewDecoder(bytes.NewReader([]byte(invalidLoginFault)))
	dec.AddType(reflect.TypeOf(types.InvalidLogin{}))

	err := dec.Decode(&env)
	if err != nil {
		t.Fatalf("Decode: %s", err)
	}

	if body.Fault == nil {
		t.Fatal("Expected fault")
	}

	if _, ok := body.Fault.Detail.Fault.(types.InvalidLogin); !ok {
		t.Fatal("Expected InvalidLogin, got: %#v", body.Fault.Detail.Fault)
	}
}
<commit_msg>Change xml.Decoder.AddType to TypeFunc<commit_after>/*
Copyright (c) 2014 VMware, 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 methods

import (
	"bytes"
	"testing"

	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"
	"github.com/vmware/govmomi/vim25/xml"
)

var invalidLoginFault = `
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<soapenv:Fault><faultcode>ServerFaultCode</faultcode><faultstring>Cannot complete login due to an incorrect user name or password.</faultstring><detail><InvalidLoginFault xmlns="urn:vim25" xsi:type="InvalidLogin"></InvalidLoginFault></detail></soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>`

type TestBody struct {
	Fault *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
}

func TestFaultDetail(t *testing.T) {
	body := TestBody{}
	env := soap.Envelope{Body: &body}

	dec := xml.NewDecoder(bytes.NewReader([]byte(invalidLoginFault)))
	dec.TypeFunc = types.TypeFunc()

	err := dec.Decode(&env)
	if err != nil {
		t.Fatalf("Decode: %s", err)
	}

	if body.Fault == nil {
		t.Fatal("Expected fault")
	}

	if _, ok := body.Fault.Detail.Fault.(types.InvalidLogin); !ok {
		t.Fatal("Expected InvalidLogin, got: %#v", body.Fault.Detail.Fault)
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2018 Cisco and/or its affiliates.
//
//  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 agent

import (
	"os"
	"os/signal"
	"syscall"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/logging/logrus"
	"github.com/ligato/cn-infra/utils/once"
	"github.com/namsral/flag"
)

// Agent implements startup & shutdown procedures.
type Agent interface {
	Run() error
	Start() error
	Wait() error
	Stop() error
	Options() Options
}

// NewAgent creates a new Agent
func NewAgent(opts ...Option) Agent {
	options := newOptions(opts...)

	flag.Parse()

	return &agent{
		opts: options,
	}
}

type agent struct {
	opts      Options
	closeCh   chan struct{}
	startOnce once.ReturnError
	stopOnce  once.ReturnError
}

// Options returns the Options the agent was created with
func (a *agent) Options() Options {
	return a.opts
}

// Start starts the agent.  Start will return as soon as the Agent is ready.  The Agent continues
// running after Start returns.
func (a *agent) Start() error {
	return a.startOnce.Do(a.start)
}

func (a *agent) start() error {
	// Init plugins
	for _, p := range a.opts.Plugins {
		if err := p.Init(); err != nil {
			return err
		}
	}
	// AfterInit plugins
	for _, p := range a.opts.Plugins {
		var plug core.Plugin = p
		if np, ok := p.(*core.NamedPlugin); ok {
			plug = np.Plugin
		}
		if postPlugin, ok := plug.(core.PostInit); ok {
			if err := postPlugin.AfterInit(); err != nil {
				return err
			}
		} else {
			logrus.DefaultLogger().Debugf("plugin %v has no AfterInit", p)
		}
	}
	return nil
}

// Stop the Agent.  Calls close on all Plugins
func (a *agent) Stop() error {
	return a.stopOnce.Do(a.stop)
}

func (a *agent) stop() error {
	// Close plugins
	for _, p := range a.opts.Plugins {
		if err := p.Close(); err != nil {
			return err
		}
	}
	close(a.closeCh)
	logrus.DefaultLogger().Info("Agent Stopped.")
	return nil
}

// Wait will not return until a SIGINT, SIGTERM, or SIGKILL is received
// Or the Agent is Stopped
// All Plugins are Closed() before Wait returns
func (a *agent) Wait() error {
	// Wait for signal
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-sig:
		logrus.DefaultLogger().Info("Signal received, stopping.")
	case <-a.closeCh:
	}

	return a.Stop()
}

// Run runs the agent.  Run will not return until a SIGINT, SIGTERM, or SIGKILL is received
func (a *agent) Run() error {
	if err := a.Start(); err != nil {
		return err
	}
	return a.Wait()
}
<commit_msg>Fixed Wait(), and Stop() to correctly handle Agent's that weren't Started<commit_after>//  Copyright (c) 2018 Cisco and/or its affiliates.
//
//  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 agent

import (
	"os"
	"os/signal"
	"syscall"

	"errors"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/logging/logrus"
	"github.com/ligato/cn-infra/utils/once"
	"github.com/namsral/flag"
)

// Agent implements startup & shutdown procedures.
type Agent interface {
	Run() error
	Start() error
	Wait() error
	Stop() error
	Options() Options
}

// NewAgent creates a new Agent
func NewAgent(opts ...Option) Agent {
	options := newOptions(opts...)

	flag.Parse()

	return &agent{
		opts: options,
	}
}

type agent struct {
	opts      Options
	stopCh    chan struct{}
	startOnce once.ReturnError
	stopOnce  once.ReturnError
}

// Options returns the Options the agent was created with
func (a *agent) Options() Options {
	return a.opts
}

// Start starts the agent.  Start will return as soon as the Agent is ready.  The Agent continues
// running after Start returns.
func (a *agent) Start() error {
	return a.startOnce.Do(a.start)
}

func (a *agent) start() error {
	// Init plugins
	for _, p := range a.opts.Plugins {
		if err := p.Init(); err != nil {
			return err
		}
	}
	// AfterInit plugins
	for _, p := range a.opts.Plugins {
		var plug core.Plugin = p
		if np, ok := p.(*core.NamedPlugin); ok {
			plug = np.Plugin
		}
		if postPlugin, ok := plug.(core.PostInit); ok {
			if err := postPlugin.AfterInit(); err != nil {
				return err
			}
		} else {
			logrus.DefaultLogger().Debugf("plugin %v has no AfterInit", p)
		}
	}
	a.stopCh = make(chan struct{}, 1) // If we are started, we have a stopTime to signal stopping
	return nil
}

// Stop the Agent.  Calls close on all Plugins
func (a *agent) Stop() error {
	return a.stopOnce.Do(a.stop)
}

func (a *agent) stop() error {
	if a.stopCh != nil { // Don't stop if we didn't start
		defer close(a.stopCh)
		// Close plugins
		for _, p := range a.opts.Plugins {
			if err := p.Close(); err != nil {
				return err
			}
		}
		logrus.DefaultLogger().Info("Agent Stopped.")
		return nil
	}
	err := errors.New("attempted to stop an agent that wasn't Started")
	logrus.DefaultLogger().Error(err)
	return err

}

// Wait will not return until a SIGINT, SIGTERM, or SIGKILL is received
// Or the Agent is Stopped
// All Plugins are Closed() before Wait returns
func (a *agent) Wait() error {
	if a.stopCh != nil { // Don't wait if we didn't start
		// Wait for signal
		sig := make(chan os.Signal, 1)
		signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
		select {
		case <-sig:
			logrus.DefaultLogger().Info("Signal received, stopping.")
			return a.Stop()
		case <-a.stopCh:
		}
		return nil
	}
	err := errors.New("attempted to wait on an agent that wasn't Started")
	logrus.DefaultLogger().Error(err)
	return err
}

// Run runs the agent.  Run will not return until a SIGINT, SIGTERM, or SIGKILL is received
func (a *agent) Run() error {
	if err := a.Start(); err != nil {
		return err
	}
	return a.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"bytes"

	"github.com/gin-gonic/gin"
	"zxq.co/ripple/hanayo/modules/bbcode"
	tp "zxq.co/ripple/hanayo/modules/top-passwords"
	"zxq.co/ripple/rippleapi/common"
)

//go:generate go run scripts/generate_mappings.go -g
//go:generate go run scripts/top_passwords.go

func cmd5(s string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
}

func validatePassword(p string) string {
	if len(p) < 8 {
		return "Your password is too short! It must be at least 8 characters long."
	}

	for _, k := range tp.TopPasswords {
		if k == p {
			return "Your password is one of the most common passwords on the entire internet. No way we're letting you use that!"
		}
	}

	return ""
}

func recaptchaCheck(c *gin.Context) bool {
	f := make(url.Values)
	f.Add("secret", config.RecaptchaPrivate)
	f.Add("response", c.PostForm("g-recaptcha-response"))
	f.Add("remoteip", clientIP(c))

	req, err := http.Post("https://www.google.com/recaptcha/api/siteverify",
		"application/x-www-form-urlencoded", strings.NewReader(f.Encode()))
	if err != nil {
		c.Error(err)
		return false
	}

	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		c.Error(err)
		return false
	}

	var e struct {
		Success bool `json:"success"`
	}
	err = json.Unmarshal(data, &e)
	if err != nil {
		c.Error(err)
		return false
	}

	return e.Success
}

func parseBBCode(c *gin.Context) {
	body, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		c.Error(err)
		c.String(200, "Error")
		return
	}
	d := bbcode.Compile(string(body))
	c.String(200, d)
}

func discordFinish(c *gin.Context) {
	sess := getSession(c)
	defer func() {
		sess.Save()
		c.Redirect(302, "/settings/discord")
	}()

	ctx := getContext(c)
	if ok, _ := CSRF.Validate(ctx.User.ID, c.PostForm("csrf")); !ok {
		addMessage(c, errorMessage{"CSRF token is invalid. Please retry linking your account."})
		return
	}

	if ctx.User.Privileges&common.UserPrivilegeDonor == 0 {
		addMessage(c, errorMessage{"You're not a donor!"})
		return
	}

	tok, err := getDiscord().Exchange(nil, c.Query("code"))
	if err != nil {
		c.Error(err)
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	// Yoloest error handling ever
	// Here we're getting the user ID of our user on discord
	req, _ := http.NewRequest("GET", "https://discordapp.com/api/users/@me", nil)
	req.Header.Set("Authorization", "Bearer "+tok.AccessToken)
	resp, _ := http.DefaultClient.Do(req)
	rawData, _ := ioutil.ReadAll(resp.Body)
	var x struct {
		ID string `json:"id"`
	}
	err = json.Unmarshal(rawData, &x)
	if err != nil {
		c.Error(err)
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	// Here, instead, we're telling donorbot about the user.
	// setup post data
	vals := make(url.Values, 2)
	vals.Set("discord_id", x.ID)
	vals.Set("secret", config.DonorBotSecret)
	// send request
	resp, err = http.Post(config.DonorBotURL+"/api/v1/give_donor", "application/x-www-form-urlencoded", bytes.NewReader([]byte(vals.Encode())))
	if err != nil {
		c.Error(err)
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	var o struct {
		Status int `json:"status"`
	}
	json.NewDecoder(resp.Body).Decode(&o)

	switch o.Status {
	case 200:
		// move on
	case 404:
		addMessage(c, errorMessage{"You've not joined the discord server! Links to it are below on the page. Please join the server before attempting to connect your account to Discord."})
	default:
		c.Error(fmt.Errorf("donorbot: %d", resp.StatusCode))
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	db.Exec("INSERT INTO discord_roles (id, userid, discordid, roleid) VALUES (NULL, ?, ?, 0)", ctx.User.ID, x.ID)

	addMessage(c, successMessage{"Your account has been linked successfully!"})
}

func mustCSRFGenerate(u int) string {
	v, err := CSRF.Generate(u)
	if err != nil {
		panic(err)
	}
	return v
}
<commit_msg>fix discord donor linking not working<commit_after>package main

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"bytes"

	"github.com/gin-gonic/gin"
	"zxq.co/ripple/hanayo/modules/bbcode"
	tp "zxq.co/ripple/hanayo/modules/top-passwords"
	"zxq.co/ripple/rippleapi/common"
)

//go:generate go run scripts/generate_mappings.go -g
//go:generate go run scripts/top_passwords.go

func cmd5(s string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
}

func validatePassword(p string) string {
	if len(p) < 8 {
		return "Your password is too short! It must be at least 8 characters long."
	}

	for _, k := range tp.TopPasswords {
		if k == p {
			return "Your password is one of the most common passwords on the entire internet. No way we're letting you use that!"
		}
	}

	return ""
}

func recaptchaCheck(c *gin.Context) bool {
	f := make(url.Values)
	f.Add("secret", config.RecaptchaPrivate)
	f.Add("response", c.PostForm("g-recaptcha-response"))
	f.Add("remoteip", clientIP(c))

	req, err := http.Post("https://www.google.com/recaptcha/api/siteverify",
		"application/x-www-form-urlencoded", strings.NewReader(f.Encode()))
	if err != nil {
		c.Error(err)
		return false
	}

	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		c.Error(err)
		return false
	}

	var e struct {
		Success bool `json:"success"`
	}
	err = json.Unmarshal(data, &e)
	if err != nil {
		c.Error(err)
		return false
	}

	return e.Success
}

func parseBBCode(c *gin.Context) {
	body, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		c.Error(err)
		c.String(200, "Error")
		return
	}
	d := bbcode.Compile(string(body))
	c.String(200, d)
}

func discordFinish(c *gin.Context) {
	sess := getSession(c)
	defer func() {
		sess.Save()
		c.Redirect(302, "/settings/discord")
	}()

	ctx := getContext(c)
	if ok, _ := CSRF.Validate(ctx.User.ID, c.Query("state")); !ok {
		addMessage(c, errorMessage{"CSRF token is invalid. Please retry linking your account."})
		return
	}

	if ctx.User.Privileges&common.UserPrivilegeDonor == 0 {
		addMessage(c, errorMessage{"You're not a donor!"})
		return
	}

	tok, err := getDiscord().Exchange(nil, c.Query("code"))
	if err != nil {
		c.Error(err)
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	// Yoloest error handling ever
	// Here we're getting the user ID of our user on discord
	req, _ := http.NewRequest("GET", "https://discordapp.com/api/users/@me", nil)
	req.Header.Set("Authorization", "Bearer "+tok.AccessToken)
	resp, _ := http.DefaultClient.Do(req)
	rawData, _ := ioutil.ReadAll(resp.Body)
	var x struct {
		ID string `json:"id"`
	}
	err = json.Unmarshal(rawData, &x)
	if err != nil {
		c.Error(err)
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	// Here, instead, we're telling donorbot about the user.
	// setup post data
	vals := make(url.Values, 2)
	vals.Set("discord_id", x.ID)
	vals.Set("secret", config.DonorBotSecret)
	// send request
	resp, err = http.Post(config.DonorBotURL+"/api/v1/give_donor", "application/x-www-form-urlencoded", bytes.NewReader([]byte(vals.Encode())))
	if err != nil {
		c.Error(err)
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	var o struct {
		Status int `json:"status"`
	}
	json.NewDecoder(resp.Body).Decode(&o)

	switch o.Status {
	case 200:
		// move on
	case 404:
		addMessage(c, errorMessage{"You've not joined the discord server! Links to it are below on the page. Please join the server before attempting to connect your account to Discord."})
	default:
		c.Error(fmt.Errorf("donorbot: %d", resp.StatusCode))
		addMessage(c, errorMessage{"An error occurred."})
		return
	}

	db.Exec("INSERT INTO discord_roles (id, userid, discordid, roleid) VALUES (NULL, ?, ?, 0)", ctx.User.ID, x.ID)

	addMessage(c, successMessage{"Your account has been linked successfully!"})
}

func mustCSRFGenerate(u int) string {
	v, err := CSRF.Generate(u)
	if err != nil {
		panic(err)
	}
	return v
}
<|endoftext|>


<commit_before>// Resources Agent

package agent

import (
	"encoding/json"
	"github.com/golang/glog"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/tsinghua-io/api-server/webapp"
	"net/http"
	"reflect"
)

type handlerSpec struct {
	methodName string
	httpMethod string
	getArgs    func(http.ResponseWriter, *http.Request) []interface{}
}

type userAgent struct {
	UrlMap map[string]handlerSpec
}

var UserAgent = userAgent{
	UrlMap: map[string]handlerSpec{
		"/users/me":                         handlerSpec{"Profile", "GET", getArgsMe},
		"/users/me/attended":                handlerSpec{"Attended", "GET", getArgsMe},
		"/courses/{courseId}/announcements": handlerSpec{"CourseAnnouncements", "GET", getArgsCourse},
		"/courses/{courseId}/files":         handlerSpec{"CourseFiles", "GET", getArgsCourse},
		"/courses/{courseId}/homeworks":     handlerSpec{"CourseHomework", "GET", getArgsCourse},
	},
}

func argsFromUrl(argNames ...string) func(http.ResponseWriter, *http.Request) []interface{} {
	return func(w http.ResponseWriter, r *http.Request) (args []interface{}) {
		vars := mux.Vars(r)
		for _, argName := range argNames {
			args = append(args, vars[argName])
		}
		return
	}
}

var getArgsCourse = argsFromUrl("courseId")
var getArgsMe = argsFromUrl("userId")

func (useragent *userAgent) BindRoute(app *webapp.WebApp) {
	for path, handlerSpec := range useragent.UrlMap {
		app.HandleFunc(path, useragent.GenerateHandler(handlerSpec.methodName,
			handlerSpec.getArgs)).Methods(handlerSpec.httpMethod)
	}
}

func (useragent *userAgent) GenerateHandler(methodName string,
	getArgs func(http.ResponseWriter, *http.Request) []interface{}) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ada, ok := context.GetOk(r, "adapter")
		if !ok {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		// get the arguments
		args := getArgs(w, r)
		values := make([]reflect.Value, len(args)+1)
		for i, arg := range args {
			values[i] = reflect.ValueOf(arg)
		}
		values[len(values)-1] = reflect.ValueOf(make(map[string]string))

		// call the actual handler in the adapter
		methodVal := reflect.ValueOf(ada).MethodByName(methodName)
		if !methodVal.IsValid() {
			glog.Errorf("The current in-use adapter is not a receiver of method named '%s': Please check the url mapping.", methodName)
			status := http.StatusInternalServerError
			w.WriteHeader(status)
			return
		}

		returnVals := methodVal.Call(values)
		res := returnVals[0].Interface()
		status := returnVals[1].Interface().(int)

		w.WriteHeader(status)
		if res != nil {
			j, _ := json.Marshal(res)
			w.Write(j)
		}

	})
}
<commit_msg>Pass url queries to adapter functions<commit_after>// Resources Agent

package agent

import (
	"encoding/json"
	"github.com/golang/glog"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/tsinghua-io/api-server/webapp"
	"net/http"
	"reflect"
	"strings"
)

type handlerSpec struct {
	methodName string
	httpMethod string
	getArgs    func(http.ResponseWriter, *http.Request) []interface{}
}

type userAgent struct {
	UrlMap map[string]handlerSpec
}

var UserAgent = userAgent{
	UrlMap: map[string]handlerSpec{
		"/users/me":                         handlerSpec{"Profile", "GET", getArgsMe},
		"/users/me/attended":                handlerSpec{"Attended", "GET", getArgsMe},
		"/courses/{courseId}/announcements": handlerSpec{"CourseAnnouncements", "GET", getArgsCourse},
		"/courses/{courseId}/files":         handlerSpec{"CourseFiles", "GET", getArgsCourse},
		"/courses/{courseId}/homeworks":     handlerSpec{"CourseHomework", "GET", getArgsCourse},
	},
}

func argsFromUrl(argNames ...string) func(http.ResponseWriter, *http.Request) []interface{} {
	return func(w http.ResponseWriter, r *http.Request) (args []interface{}) {
		vars := mux.Vars(r)
		for _, argName := range argNames {
			args = append(args, vars[argName])
		}
		return
	}
}

var getArgsCourse = argsFromUrl("courseId")
var getArgsMe = argsFromUrl("userId")

func (useragent *userAgent) BindRoute(app *webapp.WebApp) {
	for path, handlerSpec := range useragent.UrlMap {
		app.HandleFunc(path, useragent.GenerateHandler(handlerSpec.methodName,
			handlerSpec.getArgs)).Methods(handlerSpec.httpMethod)
	}
}

func (useragent *userAgent) GenerateHandler(methodName string,
	getArgs func(http.ResponseWriter, *http.Request) []interface{}) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ada, ok := context.GetOk(r, "adapter")
		if !ok {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		// get the arguments
		args := getArgs(w, r)
		values := make([]reflect.Value, len(args)+1)
		for i, arg := range args {
			values[i] = reflect.ValueOf(arg)
		}

		// Pass url query as the final parameter
		var params = make(map[string]string)
		for k, v := range r.URL.Query() {
			params[k] = strings.Join(v, ", ")
		}
		values[len(values)-1] = reflect.ValueOf(params)

		// call the actual handler in the adapter
		methodVal := reflect.ValueOf(ada).MethodByName(methodName)
		if !methodVal.IsValid() {
			glog.Errorf("The current in-use adapter is not a receiver of method named '%s': Please check the url mapping.", methodName)
			status := http.StatusInternalServerError
			w.WriteHeader(status)
			return
		}

		returnVals := methodVal.Call(values)
		res := returnVals[0].Interface()
		status := returnVals[1].Interface().(int)

		w.WriteHeader(status)
		if res != nil {
			j, _ := json.Marshal(res)
			w.Write(j)
		}

	})
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"
	"time"
)

// Get the scores for a game.
func (g CAHGame) Scores() string {
	var str string = ""
	for key, value := range g.Players {
		str += value.Player.String() + " - " + string(value.Points)
	}
	return str
}

// Get the settings for a game.
func (gs GameSettings) String() string {
	var onOff string
	if gs.MysteryPlayer {
		onOff = "on"
	} else {
		onOff = "off"
	}
	tmp := "Mystery Player - " + onOff + "\n"
	if gs.TradeInTwoCardsEveryRound {
		onOff = "on"
	} else {
		onOff = "off"
	}
	tmp += "Trade in 2 cards every round " + onOff + "\n"
	if gs.PickWorstToo {
		onOff = "on"
	} else {
		onOff = "off"
	}
	tmp += "Pick the worst answer also " + onOff + "\n"
	tmp += "Each player has " + string(gs.NumCardsInHand) + "in their hand."
	return tmp
}

// Shuffle an array of ints.
func shuffle(arr []int) {
	t := time.Now()
	rand.Seed(int64(t.Nanosecond()))

	for i := len(arr) - 1; i > 0; i-- {
		j := rand.Intn(i)
		arr[i], arr[j] = arr[j], arr[i]
	}
}
<commit_msg>Added by identifier to please Go<commit_after>package main

import (
	"math/rand"
	"time"
)

// Get the scores for a game.
func (g CAHGame) Scores() string {
	var str string = ""
	for _, value := range g.Players {
		str += value.Player.String() + " - " + string(value.Points)
	}
	return str
}

// Get the settings for a game.
func (gs GameSettings) String() string {
	var onOff string
	if gs.MysteryPlayer {
		onOff = "on"
	} else {
		onOff = "off"
	}
	tmp := "Mystery Player - " + onOff + "\n"
	if gs.TradeInTwoCardsEveryRound {
		onOff = "on"
	} else {
		onOff = "off"
	}
	tmp += "Trade in 2 cards every round " + onOff + "\n"
	if gs.PickWorstToo {
		onOff = "on"
	} else {
		onOff = "off"
	}
	tmp += "Pick the worst answer also " + onOff + "\n"
	tmp += "Each player has " + string(gs.NumCardsInHand) + "in their hand."
	return tmp
}

// Shuffle an array of ints.
func shuffle(arr []int) {
	t := time.Now()
	rand.Seed(int64(t.Nanosecond()))

	for i := len(arr) - 1; i > 0; i-- {
		j := rand.Intn(i)
		arr[i], arr[j] = arr[j], arr[i]
	}
}
<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// vespa cert command
// Author: mpolden
package cmd

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
	"github.com/vespa-engine/vespa/util"
	"github.com/vespa-engine/vespa/vespa"
)

var overwriteCertificate bool

func init() {
	certCmd.Flags().BoolVarP(&overwriteCertificate, "force", "f", false, "Force overwrite of existing certificate and private key")
	rootCmd.AddCommand(certCmd)
}

var certCmd = &cobra.Command{
	Use:   "cert",
	Short: "Creates a new private key and self-signed certificate",
	Long: `Applications in Vespa Cloud are required to secure their data plane with mutual TLS. ` +
		`This command creates a self-signed certificate suitable for development purposes. ` +
		`See https://cloud.vespa.ai/en/security-model for more information on the Vespa Cloud security model.`,
	Run: func(cmd *cobra.Command, args []string) {
		var path string
		if len(args) > 0 {
			path = args[0]
		} else {
			var err error
			path, err = os.Getwd()
			util.FatalIfErr(err)
		}

		pkg, err := vespa.FindApplicationPackage(path)
		util.FatalIfErr(err)
		if pkg.HasCertificate() {
			util.Print("Certificate already exists")
			return
		}

		// TODO: Consider writing key pair inside ~/.vespa/<app-name>/ instead so that vespa document commands can easily
		// locate key pair
		securityDir := filepath.Join(pkg.Path, "security")
		privateKeyFile := filepath.Join(path, "data-plane-private-key.pem")
		certificateFile := filepath.Join(path, "data-plane-public-cert.pem")
		pkgCertificateFile := filepath.Join(securityDir, "clients.pem")

		keyPair, err := vespa.CreateKeyPair()
		util.FatalIfErr(err)

		err = os.MkdirAll(securityDir, 0755)
		util.FatalIfErr(err)
		err = keyPair.WriteCertificateFile(pkgCertificateFile, overwriteCertificate)
		util.FatalIfErr(err)
		err = keyPair.WriteCertificateFile(certificateFile, overwriteCertificate)
		util.FatalIfErr(err)
		err = keyPair.WritePrivateKeyFile(privateKeyFile, overwriteCertificate)
		util.FatalIfErr(err)

		// TODO: Just use log package, which has Printf
		util.Print(fmt.Sprintf("Certificate written to %s", pkgCertificateFile))
		util.Print(fmt.Sprintf("Certificate written to %s", certificateFile))
		util.Print(fmt.Sprintf("Private key written to %s", privateKeyFile))
	},
}
<commit_msg>Check overwrite flag<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// vespa cert command
// Author: mpolden
package cmd

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
	"github.com/vespa-engine/vespa/util"
	"github.com/vespa-engine/vespa/vespa"
)

var overwriteCertificate bool

func init() {
	certCmd.Flags().BoolVarP(&overwriteCertificate, "force", "f", false, "Force overwrite of existing certificate and private key")
	rootCmd.AddCommand(certCmd)
}

var certCmd = &cobra.Command{
	Use:   "cert",
	Short: "Creates a new private key and self-signed certificate",
	Long: `Applications in Vespa Cloud are required to secure their data plane with mutual TLS. ` +
		`This command creates a self-signed certificate suitable for development purposes. ` +
		`See https://cloud.vespa.ai/en/security-model for more information on the Vespa Cloud security model.`,
	Run: func(cmd *cobra.Command, args []string) {
		var path string
		if len(args) > 0 {
			path = args[0]
		} else {
			var err error
			path, err = os.Getwd()
			util.FatalIfErr(err)
		}

		pkg, err := vespa.FindApplicationPackage(path)
		util.FatalIfErr(err)
		if pkg.HasCertificate() && !overwriteCertificate {
			util.Print("Certificate already exists")
			return
		}

		// TODO: Consider writing key pair inside ~/.vespa/<app-name>/ instead so that vespa document commands can easily
		// locate key pair
		securityDir := filepath.Join(pkg.Path, "security")
		privateKeyFile := filepath.Join(path, "data-plane-private-key.pem")
		certificateFile := filepath.Join(path, "data-plane-public-cert.pem")
		pkgCertificateFile := filepath.Join(securityDir, "clients.pem")

		keyPair, err := vespa.CreateKeyPair()
		util.FatalIfErr(err)

		err = os.MkdirAll(securityDir, 0755)
		util.FatalIfErr(err)
		err = keyPair.WriteCertificateFile(pkgCertificateFile, overwriteCertificate)
		util.FatalIfErr(err)
		err = keyPair.WriteCertificateFile(certificateFile, overwriteCertificate)
		util.FatalIfErr(err)
		err = keyPair.WritePrivateKeyFile(privateKeyFile, overwriteCertificate)
		util.FatalIfErr(err)

		// TODO: Just use log package, which has Printf
		util.Print(fmt.Sprintf("Certificate written to %s", pkgCertificateFile))
		util.Print(fmt.Sprintf("Certificate written to %s", certificateFile))
		util.Print(fmt.Sprintf("Private key written to %s", privateKeyFile))
	},
}
<|endoftext|>


<commit_before>package client

import (
	"irken/test"
	"testing"
)

func TestLexValid(t *testing.T) {
	message := ":prefix COMMAND param1 param2 :param 3 :-) yeah!?"
	l, err := lexMsg(message)
	if err != nil {
		t.Error(err)
	}
	prefix := l.Src
	command := l.Cmd
	params := l.Args

	test.Check(t, prefix, "prefix")
	test.Check(t, command, "COMMAND")
	test.Check(t, params[0], "param1")
	test.Check(t, params[1], "param2")
	test.Check(t, params[2], "param 3 :-) yeah!?")
}

func TestLexInValid(t *testing.T) {
	message := ":prefix"
	message2 := ":prefix "
	_, err := lexMsg(message)
	if err == nil {
		t.Errorf("Illegal message is not error reported")
	}
	_, err = lexMsg(message2)
	if err == nil {
		t.Errorf("Illegal message is not error reported")
	}

}

func TestLexNoParams(t *testing.T) {
	message := "COMMAND"
	_, err := lexMsg(message)
	if err == nil {
		t.Errorf("No prefix - should not parse")
	}
}

func TestJoin(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com JOIN #chan"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx has joined #chan"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestMode(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com MODE #chan +i -l"
	msg, cont, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	expMsg := "_mrx changed mode +i -l for #chan"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestQuit(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com QUIT :Later suckerz"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx has quit (Later suckerz)"
	expCont := ""
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestPart(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com PART #chan"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx has left #chan"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestPrivMsg(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com PRIVMSG #chan :Octotastic! I like pie btw :)"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	if err != nil {
		t.Errorf("Should parse!")
	}
	expMsg := "_mrx: Octotastic! I like pie btw :)"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestResolveValidPrefix(t *testing.T) {
	input := "_mrx!blabla@haxxor.com"
	nick, ident, host, src, err := resolvePrefix(input)
	expNick := "_mrx"
	expIdent := "blabla"
	expHost := "haxxor.com"
	expSrc := "_mrx!blabla@haxxor.com"
	if err != nil {
		t.Errorf("Should parse")
	}

	test.Check(t, nick, expNick)
	test.Check(t, ident, expIdent)
	test.Check(t, host, expHost)
	test.Check(t, src, expSrc)
}

func TestResolveInvalidPrefix(t *testing.T) {
	input := ""
	_, _, _, _, err := resolvePrefix(input)
	if err == nil {
		t.Errorf("Should not parse")
	}
}

func TestResolveServer(t *testing.T) {
	input := "blabla.haxxor.com"
	nick, ident, host, src, err := resolvePrefix(input)
	expNick := "blabla.haxxor.com"
	expIdent := ""
	expHost := ""
	expSrc := "blabla.haxxor.com"
	if err != nil {
		t.Errorf("Should parse")
	}

	test.Check(t, nick, expNick)
	test.Check(t, ident, expIdent)
	test.Check(t, host, expHost)
	test.Check(t, src, expSrc)
}
<commit_msg>MODE test code now compatible with parser<commit_after>package client

import (
	"irken/test"
	"testing"
)

func TestLexValid(t *testing.T) {
	message := ":prefix COMMAND param1 param2 :param 3 :-) yeah!?"
	l, err := lexMsg(message)
	if err != nil {
		t.Error(err)
	}
	prefix := l.Src
	command := l.Cmd
	params := l.Args

	test.Check(t, prefix, "prefix")
	test.Check(t, command, "COMMAND")
	test.Check(t, params[0], "param1")
	test.Check(t, params[1], "param2")
	test.Check(t, params[2], "param 3 :-) yeah!?")
}

func TestLexInValid(t *testing.T) {
	message := ":prefix"
	message2 := ":prefix "
	_, err := lexMsg(message)
	if err == nil {
		t.Errorf("Illegal message is not error reported")
	}
	_, err = lexMsg(message2)
	if err == nil {
		t.Errorf("Illegal message is not error reported")
	}

}

func TestLexNoParams(t *testing.T) {
	message := "COMMAND"
	_, err := lexMsg(message)
	if err == nil {
		t.Errorf("No prefix - should not parse")
	}
}

func TestJoin(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com JOIN #chan"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx has joined #chan"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestMode(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com MODE #chan +i -l"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx changed mode +i -l for #chan"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestQuit(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com QUIT :Later suckerz"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx has quit (Later suckerz)"
	expCont := ""
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestPart(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com PART #chan"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	expMsg := "_mrx has left #chan"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestPrivMsg(t *testing.T) {
	input := ":_mrx!blabla@haxxor.com PRIVMSG #chan :Octotastic! I like pie btw :)"
	l, err := ParseServerMsg(input)
	if err != nil {
		t.Errorf("Should parse!")
	}
	msg := l.output
	cont := l.Context
	if err != nil {
		t.Errorf("Should parse!")
	}
	expMsg := "_mrx: Octotastic! I like pie btw :)"
	expCont := "#chan"
	test.Check(t, msg, expMsg)
	test.Check(t, cont, expCont)
}

func TestResolveValidPrefix(t *testing.T) {
	input := "_mrx!blabla@haxxor.com"
	nick, ident, host, src, err := resolvePrefix(input)
	expNick := "_mrx"
	expIdent := "blabla"
	expHost := "haxxor.com"
	expSrc := "_mrx!blabla@haxxor.com"
	if err != nil {
		t.Errorf("Should parse")
	}

	test.Check(t, nick, expNick)
	test.Check(t, ident, expIdent)
	test.Check(t, host, expHost)
	test.Check(t, src, expSrc)
}

func TestResolveInvalidPrefix(t *testing.T) {
	input := ""
	_, _, _, _, err := resolvePrefix(input)
	if err == nil {
		t.Errorf("Should not parse")
	}
}

func TestResolveServer(t *testing.T) {
	input := "blabla.haxxor.com"
	nick, ident, host, src, err := resolvePrefix(input)
	expNick := "blabla.haxxor.com"
	expIdent := ""
	expHost := ""
	expSrc := "blabla.haxxor.com"
	if err != nil {
		t.Errorf("Should parse")
	}

	test.Check(t, nick, expNick)
	test.Check(t, ident, expIdent)
	test.Check(t, host, expHost)
	test.Check(t, src, expSrc)
}
<|endoftext|>


<commit_before>package dump

import (
	"flag"
	"fmt"
	"github.com/siddontang/go-mysql/client"
	. "gopkg.in/check.v1"
	"io/ioutil"
	//"os"
	"bytes"
	"testing"
)

// use docker mysql for test
var host = flag.String("host", "127.0.0.1", "MySQL host")
var port = flag.Int("port", 3306, "MySQL host")

var execution = flag.String("exec", "mysqldump", "mysqldump execution path")

func Test(t *testing.T) {
	TestingT(t)
}

type schemaTestSuite struct {
	conn *client.Conn
	d    *Dumper
}

var _ = Suite(&schemaTestSuite{})

func (s *schemaTestSuite) SetUpSuite(c *C) {
	var err error
	s.conn, err = client.Connect(fmt.Sprintf("%s:%d", *host, *port), "root", "", "")
	c.Assert(err, IsNil)

	s.d, err = NewDumper(*execution, fmt.Sprintf("%s:%d", *host, *port), "root", "")
	c.Assert(err, IsNil)

	s.d.SetErrOut(ioutil.Discard)

	_, err = s.conn.Execute("CREATE DATABASE IF NOT EXISTS test1")
	c.Assert(err, IsNil)

	_, err = s.conn.Execute("CREATE DATABASE IF NOT EXISTS test2")
	c.Assert(err, IsNil)

	str := `CREATE TABLE IF NOT EXISTS test%d.t%d (
			id int AUTO_INCREMENT,
			name varchar(256),
			PRIMARY KEY(id)
			) ENGINE=INNODB`
	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 2))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 2))
	c.Assert(err, IsNil)

	str = `INSERT INTO test%d.t%d (name) VALUES ("a"), ("b"), ("\\"), ("''")`

	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 2))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 2))
	c.Assert(err, IsNil)
}

func (s *schemaTestSuite) TearDownSuite(c *C) {
	if s.conn != nil {
		_, err := s.conn.Execute("DROP DATABASE IF EXISTS test1")
		c.Assert(err, IsNil)

		_, err = s.conn.Execute("DROP DATABASE IF EXISTS test2")
		c.Assert(err, IsNil)

		s.conn.Close()
	}
}

func (s *schemaTestSuite) TestDump(c *C) {
	err := s.d.Dump(ioutil.Discard)
	c.Assert(err, IsNil)

	s.d.AddDatabases("test1", "test2")

	s.d.AddIgnoreTables("test1", "t2")

	err = s.d.Dump(ioutil.Discard)
	c.Assert(err, IsNil)

	s.d.AddTables("test1", "t1")

	err = s.d.Dump(ioutil.Discard)
	c.Assert(err, IsNil)
}

type testParseHandler struct {
}

func (h *testParseHandler) BinLog(name string, pos uint64) error {
	return nil
}

func (h *testParseHandler) Data(schema string, table string, values []string) error {
	return nil
}

func (s *schemaTestSuite) TestParse(c *C) {
	var buf bytes.Buffer

	s.d.Reset()

	s.d.AddDatabases("test1", "test2")

	err := s.d.Dump(&buf)
	c.Assert(err, IsNil)

	err = Parse(&buf, new(testParseHandler))
	c.Assert(err, IsNil)
}

func (s *schemaTestSuite) TestParseValue(c *C) {
	str := `'abc\\',''`
	values, err := parseValues(str)
	c.Assert(err, IsNil)
	c.Assert(values, DeepEquals, []string{`'abc\\'`, `''`})

	str = `123,'\Z#÷QÎx£. Æ‘ÇoPâÅ_\r—\\','','qn'`
	values, err = parseValues(str)
	c.Assert(err, IsNil)
	c.Assert(values, HasLen, 4)

	str = `123,'\Z#÷QÎx£. Æ‘ÇoPâÅ_\r—\\','','qn\'`
	values, err = parseValues(str)
	c.Assert(err, NotNil)

}
<commit_msg>import pretty<commit_after>package dump

import (
	"flag"
	"fmt"
	"io/ioutil"
	//"os"
	"bytes"
	"testing"

	"github.com/siddontang/go-mysql/client"
	. "gopkg.in/check.v1"
)

// use docker mysql for test
var host = flag.String("host", "127.0.0.1", "MySQL host")
var port = flag.Int("port", 3306, "MySQL host")

var execution = flag.String("exec", "mysqldump", "mysqldump execution path")

func Test(t *testing.T) {
	TestingT(t)
}

type schemaTestSuite struct {
	conn *client.Conn
	d    *Dumper
}

var _ = Suite(&schemaTestSuite{})

func (s *schemaTestSuite) SetUpSuite(c *C) {
	var err error
	s.conn, err = client.Connect(fmt.Sprintf("%s:%d", *host, *port), "root", "", "")
	c.Assert(err, IsNil)

	s.d, err = NewDumper(*execution, fmt.Sprintf("%s:%d", *host, *port), "root", "")
	c.Assert(err, IsNil)

	s.d.SetErrOut(ioutil.Discard)

	_, err = s.conn.Execute("CREATE DATABASE IF NOT EXISTS test1")
	c.Assert(err, IsNil)

	_, err = s.conn.Execute("CREATE DATABASE IF NOT EXISTS test2")
	c.Assert(err, IsNil)

	str := `CREATE TABLE IF NOT EXISTS test%d.t%d (
			id int AUTO_INCREMENT,
			name varchar(256),
			PRIMARY KEY(id)
			) ENGINE=INNODB`
	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 2))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 2))
	c.Assert(err, IsNil)

	str = `INSERT INTO test%d.t%d (name) VALUES ("a"), ("b"), ("\\"), ("''")`

	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 1))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 1, 2))
	c.Assert(err, IsNil)

	_, err = s.conn.Execute(fmt.Sprintf(str, 2, 2))
	c.Assert(err, IsNil)
}

func (s *schemaTestSuite) TearDownSuite(c *C) {
	if s.conn != nil {
		_, err := s.conn.Execute("DROP DATABASE IF EXISTS test1")
		c.Assert(err, IsNil)

		_, err = s.conn.Execute("DROP DATABASE IF EXISTS test2")
		c.Assert(err, IsNil)

		s.conn.Close()
	}
}

func (s *schemaTestSuite) TestDump(c *C) {
	err := s.d.Dump(ioutil.Discard)
	c.Assert(err, IsNil)

	s.d.AddDatabases("test1", "test2")

	s.d.AddIgnoreTables("test1", "t2")

	err = s.d.Dump(ioutil.Discard)
	c.Assert(err, IsNil)

	s.d.AddTables("test1", "t1")

	err = s.d.Dump(ioutil.Discard)
	c.Assert(err, IsNil)
}

type testParseHandler struct {
}

func (h *testParseHandler) BinLog(name string, pos uint64) error {
	return nil
}

func (h *testParseHandler) Data(schema string, table string, values []string) error {
	return nil
}

func (s *schemaTestSuite) TestParse(c *C) {
	var buf bytes.Buffer

	s.d.Reset()

	s.d.AddDatabases("test1", "test2")

	err := s.d.Dump(&buf)
	c.Assert(err, IsNil)

	err = Parse(&buf, new(testParseHandler))
	c.Assert(err, IsNil)
}

func (s *schemaTestSuite) TestParseValue(c *C) {
	str := `'abc\\',''`
	values, err := parseValues(str)
	c.Assert(err, IsNil)
	c.Assert(values, DeepEquals, []string{`'abc\\'`, `''`})

	str = `123,'\Z#÷QÎx£. Æ‘ÇoPâÅ_\r—\\','','qn'`
	values, err = parseValues(str)
	c.Assert(err, IsNil)
	c.Assert(values, HasLen, 4)

	str = `123,'\Z#÷QÎx£. Æ‘ÇoPâÅ_\r—\\','','qn\'`
	values, err = parseValues(str)
	c.Assert(err, NotNil)

}
<|endoftext|>


<commit_before>package algoliasearch

import (
	"sync"
	"testing"
	"time"
)

func deleteClientKey(t *testing.T, c Client, key string) {
	_, err := c.DeleteUserKey(key)
	if err != nil {
		t.Fatalf("deleteClientKey: Cannot delete key: %s", err)
	}
}

func waitClientKey(t *testing.T, c Client, keyID string, f func(k Key) bool) {
	retries := 10

	for r := 0; r < retries; r++ {
		key, err := c.GetUserKey(keyID)

		if err == nil && (f == nil || f(key)) {
			return
		}
		time.Sleep(1 * time.Second)
	}

	t.Fatalf("waitClientKey: Key not found or function call failed")
}

func waitClientKeysAsync(t *testing.T, c Client, keyIDs []string, f func(k Key) bool) {
	var wg sync.WaitGroup

	for _, keyID := range keyIDs {
		wg.Add(1)

		go func(keyID string) {
			defer wg.Done()
			waitClientKey(t, c, keyID, f)
		}(keyID)
	}

	wg.Wait()
}

func TestClientKeys(t *testing.T) {
	c := initClient(t)

	// Check that no key was previously existing
	{
		keys, err := c.ListKeys()

		if err != nil {
			t.Fatalf("TestClientKeys: Cannot list the keys: %s", err)
		}

		if len(keys) != 1 || keys[0].Description != "Search-only API Key" {
			t.Fatalf("TestClientKeys: Should return the Search-only API Key instead of %d key(s)", len(keys))
		}
	}

	var searchKey, allRightsKey string

	// Add a search key with parameters
	{
		params := Map{
			"description":            "",
			"maxQueriesPerIPPerHour": 1000,
			"referers":               []string{},
			"queryParameters":        "typoTolerance=strict",
			"validity":               600,
			"maxHitsPerQuery":        1,
		}

		res, err := c.AddUserKey([]string{"search"}, params)
		if err != nil {
			t.Fatalf("TestClientKeys: Cannot create the search key: %s", err)
		}

		searchKey = res.Key
	}
	defer deleteClientKey(t, c, searchKey)

	// Add an all-permissions key
	{
		acl := []string{
			"search",
			"browse",
			"addObject",
			"deleteObject",
			"deleteIndex",
			"settings",
			"editSettings",
			"analytics",
			"listIndexes",
		}

		res, err := c.AddUserKey(acl, nil)
		if err != nil {
			t.Fatalf("TestClientKeys: Cannot create the all-rights key: %s", err)
		}

		allRightsKey = res.Key
	}
	defer deleteClientKey(t, c, allRightsKey)

	waitClientKeysAsync(t, c, []string{searchKey, allRightsKey}, nil)

	// Check that the 2 previous keys were added
	{
		keys, err := c.ListKeys()

		if err != nil {
			t.Fatalf("TestClientKeys: Cannot list the added keys: %s", err)
		}

		if len(keys) != 3 {
			t.Fatalf("TestClientKeys: Should return 3 keys instead of %d", len(keys))
		}
	}

	// Update search key description
	{
		params := Map{"description": "Search-Only Key"}

		_, err := c.UpdateUserKey(searchKey, params)
		if err != nil {
			t.Fatalf("TestClientKeys: Cannot update search only key's description: %s", err)
		}

		waitClientKey(t, c, searchKey, func(k Key) bool { return k.Description == "Search-Only Key" })
	}
}
<commit_msg>Add Client test cases for index operations<commit_after>package algoliasearch

import (
	"sync"
	"testing"
	"time"
)

func TestClientOperations(t *testing.T) {
	c, i := initClientAndIndex(t, "TestClientOperations")

	objectID := addOneObject(t, c, i)

	// Test CopyIndex
	{
		res, err := c.CopyIndex("TestClientOperations", "TestClientOperations_copy")
		if err != nil {
			t.Fatalf("TestClientOperations: Cannot copy the index: %s", err)
		}

		waitTask(t, i, res.TaskID)
	}

	// Test MoveIndex
	i = c.InitIndex("TestClientOperations_copy")
	{
		res, err := c.MoveIndex("TestClientOperations_copy", "TestClientOperations_move")
		if err != nil {
			t.Fatalf("TestClientOperations: Cannot move the index: %s", err)
		}

		waitTask(t, i, res.TaskID)
	}

	// Test ClearIndex
	i = c.InitIndex("TestClientOperations_move")
	{
		res, err := c.ClearIndex("TestClientOperations_move")
		if err != nil {
			t.Fatalf("TestClear: Cannot clear the index: %s, err")
		}

		waitTask(t, i, res.TaskID)

		_, err = i.GetObject(objectID, nil)
		if err == nil || err.Error() != "{\"message\":\"ObjectID does not exist\",\"status\":404}\n" {
			t.Fatalf("TestClientOperations: Object %s should be deleted after clear: %s", objectID, err)
		}
	}

	// Test DeleteIndex
	{
		_, err := c.DeleteIndex("TestClientOperations_move")
		if err != nil {
			t.Fatalf("TestClientOperations: Cannot delete the moved index: %s", err)
		}
	}
}

func deleteClientKey(t *testing.T, c Client, key string) {
	_, err := c.DeleteUserKey(key)
	if err != nil {
		t.Fatalf("deleteClientKey: Cannot delete key: %s", err)
	}
}

func waitClientKey(t *testing.T, c Client, keyID string, f func(k Key) bool) {
	retries := 10

	for r := 0; r < retries; r++ {
		key, err := c.GetUserKey(keyID)

		if err == nil && (f == nil || f(key)) {
			return
		}
		time.Sleep(1 * time.Second)
	}

	t.Fatalf("waitClientKey: Key not found or function call failed")
}

func waitClientKeysAsync(t *testing.T, c Client, keyIDs []string, f func(k Key) bool) {
	var wg sync.WaitGroup

	for _, keyID := range keyIDs {
		wg.Add(1)

		go func(keyID string) {
			defer wg.Done()
			waitClientKey(t, c, keyID, f)
		}(keyID)
	}

	wg.Wait()
}

func TestClientKeys(t *testing.T) {
	c := initClient(t)

	// Check that no key was previously existing
	{
		keys, err := c.ListKeys()

		if err != nil {
			t.Fatalf("TestClientKeys: Cannot list the keys: %s", err)
		}

		if len(keys) != 1 || keys[0].Description != "Search-only API Key" {
			t.Fatalf("TestClientKeys: Should return the Search-only API Key instead of %d key(s)", len(keys))
		}
	}

	var searchKey, allRightsKey string

	// Add a search key with parameters
	{
		params := Map{
			"description":            "",
			"maxQueriesPerIPPerHour": 1000,
			"referers":               []string{},
			"queryParameters":        "typoTolerance=strict",
			"validity":               600,
			"maxHitsPerQuery":        1,
		}

		res, err := c.AddUserKey([]string{"search"}, params)
		if err != nil {
			t.Fatalf("TestClientKeys: Cannot create the search key: %s", err)
		}

		searchKey = res.Key
	}
	defer deleteClientKey(t, c, searchKey)

	// Add an all-permissions key
	{
		acl := []string{
			"search",
			"browse",
			"addObject",
			"deleteObject",
			"deleteIndex",
			"settings",
			"editSettings",
			"analytics",
			"listIndexes",
		}

		res, err := c.AddUserKey(acl, nil)
		if err != nil {
			t.Fatalf("TestClientKeys: Cannot create the all-rights key: %s", err)
		}

		allRightsKey = res.Key
	}
	defer deleteClientKey(t, c, allRightsKey)

	waitClientKeysAsync(t, c, []string{searchKey, allRightsKey}, nil)

	// Check that the 2 previous keys were added
	{
		keys, err := c.ListKeys()

		if err != nil {
			t.Fatalf("TestClientKeys: Cannot list the added keys: %s", err)
		}

		if len(keys) != 3 {
			t.Fatalf("TestClientKeys: Should return 3 keys instead of %d", len(keys))
		}
	}

	// Update search key description
	{
		params := Map{"description": "Search-Only Key"}

		_, err := c.UpdateUserKey(searchKey, params)
		if err != nil {
			t.Fatalf("TestClientKeys: Cannot update search only key's description: %s", err)
		}

		waitClientKey(t, c, searchKey, func(k Key) bool { return k.Description == "Search-Only Key" })
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/url"
	"strconv"
	"strings"
	"time"

	amazon "github.com/dominicphillips/amazing"
	"github.com/kennygrant/sanitize"
)

const (
	productsFile = "amazonstore.json"
)

// AmazonStore provides products from amazon.com. It uses the Product Advertising
// API to fetch the products.
//
// The products are stored in the amazonstore.json file. It tries to rebuild
// the file every 4 hours.
type AmazonStore struct {
	Products             map[string]Product  `json:"products"`
	ProductIDs           []string            `json:"productIDs"`
	ProductIDsByCategory map[string][]string `json:"productIDsByCategory"`
}

// NewAmazonStore creates a new AmazonStore.
//
// It reads the products from the amazonstore.json file. If the file is missing
// it tries to create it by fetching products from the Product Advertising API.
func NewAmazonStore() AmazonStore {
	store := AmazonStore{
		Products:             make(map[string]Product),
		ProductIDsByCategory: make(map[string][]string),
	}
	store.loadFromProductsFile()

	return store
}

// GetRandomProduct returns a random product from the store. If the category
// doesn't equal "" it limits the lookup to the category.
func (s AmazonStore) GetRandomProduct(category string) (Product, error) {
	if category == "" {
		id := s.ProductIDs[rand.Intn(len(s.ProductIDs))]
		return s.Products[id], nil
	}

	products := s.ProductIDsByCategory[category]
	if len(products) == 0 {
		return Product{}, fmt.Errorf("No products found [category: %s]", category)
	}
	return s.Products[products[rand.Intn(len(products))]], nil
}

// GetProduct returns the product with the provided ID from the store.
func (s AmazonStore) GetProduct(id string) (Product, error) {
	if product, found := s.Products[id]; found {
		return product, nil
	}

	return Product{}, fmt.Errorf("Product not found [ID: %s]", id)
}

// GetSimilarProducts returns up to 10 products from the same category as
// the product with the provided ID.
func (s AmazonStore) GetSimilarProducts(id string) ([]Product, error) {
	if product, found := s.Products[id]; found {
		var similar []Product

		similarProductIDs := make(map[string]string)
		productIDs := s.ProductIDsByCategory[product.Category]
		for range productIDs {
			productID := productIDs[rand.Intn(len(productIDs))]
			if productID != id && similarProductIDs[productID] == "" {
				similarProductIDs[productID] = productID
				similar = append(similar, s.Products[productID])
				if len(similar) == 10 {
					break
				}
			}
		}

		return similar, nil
	}

	return []Product{}, fmt.Errorf("Product not found [ID: %s]", id)
}

func (s *AmazonStore) loadFromProductsFile() {
	bytes, err := ioutil.ReadFile(productsFile)
	if err != nil {
		log.Printf("ERROR %s", err.Error())
		return
	}

	json.Unmarshal(bytes, s)
}

const (
	locale      = "US"
	associateID = ""
	apiKey      = ""
	apiSecret   = ""
)

func (s AmazonStore) build() error {
	categories := map[string]string{
		"babies":         "Baby",
		"beauty":         "Beauty",
		"books":          "Books",
		"fashion-babies": "FashionBaby",
		"fashion-boys":   "FashionBoys",
		"fashion-girls":  "FashionGirls",
		"fashion-men":    "FashionMen",
		"fashion-women":  "FashionWomen",
		"jewelry":        "Jewelry",
		"pets":           "PetSupplies",
		"toys-and-games": "Toys",
		"watches":        "Watches",
	}

	log.Printf("INFO  Building products started")
	client, _ := amazon.NewAmazing(locale, associateID, apiKey, apiSecret)

	for key, value := range categories {
		for i := 1; i <= 10; i++ {
			err := s.buildCategory(client, key, value, i)
			if err != nil {
				log.Printf("ERROR Building products finished [error: %s]", err.Error())
				return err
			}
		}
	}

	json, _ := json.Marshal(s)
	ioutil.WriteFile(productsFile, json, 0600)

	log.Printf("INFO  Building products finished [products: %d]", len(s.ProductIDs))
	return nil
}

func (s *AmazonStore) buildCategory(client *amazon.Amazing, category,
	amazonCategory string, page int) error {
	products, err := fetchProducts(client, category, amazonCategory, page)
	if err != nil {
		return err
	}

	for _, product := range products {
		s.Products[product.ID] = product
		s.ProductIDs = append(s.ProductIDs, product.ID)
		s.ProductIDsByCategory[category] = append(s.ProductIDsByCategory[category], product.ID)
	}
	return nil
}

func fetchProducts(client *amazon.Amazing, category, amazonCategory string,
	page int) ([]Product, error) {
	sort := "salesrank"
	if strings.Contains(amazonCategory, "Fashion") {
		sort = "reviewrank"
	}

	params := url.Values{
		"Operation":     []string{"ItemSearch"},
		"SearchIndex":   []string{amazonCategory},
		"Keywords":      []string{"%20"},
		"Condition":     []string{"New"},
		"Availability":  []string{"Available"},
		"MerchantId":    []string{"Amazon"},
		"Sort":          []string{sort},
		"ItemPage":      []string{strconv.Itoa(page)},
		"ResponseGroup": []string{"ItemAttributes,EditorialReview,Images"},
	}

	res, err := client.ItemSearch(params)
	if err != nil {
		return []Product{}, err
	}

	var products []Product
	for _, item := range res.AmazonItems.Items {
		product, err := toProduct(item)
		if err != nil {
			continue
		}

		product.Category = category
		products = append(products, product)
	}
	return products, nil
}

func toProduct(item amazon.AmazonItem) (Product, error) {
	if len(item.EditorialReviews) == 0 {
		return Product{}, fmt.Errorf("Invalid product")
	}

	product := Product{
		ID:           item.ASIN,
		Title:        strings.TrimSpace(item.ItemAttributes.Title),
		Description:  strings.TrimSpace(sanitize.HTML(item.EditorialReviews[0].Content)),
		ThumbnailURL: item.MediumImage.URL,
		ImageURL:     item.LargeImage.URL,
		Price:        item.ItemAttributes.ListPrice.FormattedPrice,
		URL:          item.DetailPageURL,
		AddedOn:      time.Now(),
	}

	if product.Title == "" || product.Description == "" ||
		product.ThumbnailURL == "" || product.ImageURL == "" ||
		product.Price == "" {
		return Product{}, fmt.Errorf("Invalid product")
	}
	return product, nil
}
<commit_msg>Updated comments<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/url"
	"strconv"
	"strings"
	"time"

	amazon "github.com/dominicphillips/amazing"
	"github.com/kennygrant/sanitize"
)

const (
	productsFile = "amazonstore.json"
)

// AmazonStore provides products from amazon.com.
//
// It uses the Product Advertising API to fetch the products. The products are
// stored in the amazonstore.json file.
type AmazonStore struct {
	Products             map[string]Product  `json:"products"`
	ProductIDs           []string            `json:"productIDs"`
	ProductIDsByCategory map[string][]string `json:"productIDsByCategory"`
}

// NewAmazonStore creates a new AmazonStore. It reads the products from
// the amazonstore.json file.
func NewAmazonStore() AmazonStore {
	store := AmazonStore{
		Products:             make(map[string]Product),
		ProductIDsByCategory: make(map[string][]string),
	}
	store.loadFromProductsFile()

	return store
}

// GetRandomProduct returns a random product from the store. If the category
// doesn't equal "" it limits the lookup to the category.
func (s AmazonStore) GetRandomProduct(category string) (Product, error) {
	if category == "" {
		id := s.ProductIDs[rand.Intn(len(s.ProductIDs))]
		return s.Products[id], nil
	}

	products := s.ProductIDsByCategory[category]
	if len(products) == 0 {
		return Product{}, fmt.Errorf("No products found [category: %s]", category)
	}
	return s.Products[products[rand.Intn(len(products))]], nil
}

// GetProduct returns the product with the provided ID from the store.
func (s AmazonStore) GetProduct(id string) (Product, error) {
	if product, found := s.Products[id]; found {
		return product, nil
	}

	return Product{}, fmt.Errorf("Product not found [ID: %s]", id)
}

// GetSimilarProducts returns up to 10 products from the same category as
// the product with the provided ID.
func (s AmazonStore) GetSimilarProducts(id string) ([]Product, error) {
	if product, found := s.Products[id]; found {
		var similar []Product

		similarProductIDs := make(map[string]string)
		productIDs := s.ProductIDsByCategory[product.Category]
		for range productIDs {
			productID := productIDs[rand.Intn(len(productIDs))]
			if productID != id && similarProductIDs[productID] == "" {
				similarProductIDs[productID] = productID
				similar = append(similar, s.Products[productID])
				if len(similar) == 10 {
					break
				}
			}
		}

		return similar, nil
	}

	return []Product{}, fmt.Errorf("Product not found [ID: %s]", id)
}

func (s *AmazonStore) loadFromProductsFile() {
	bytes, err := ioutil.ReadFile(productsFile)
	if err != nil {
		log.Printf("ERROR %s", err.Error())
		return
	}

	json.Unmarshal(bytes, s)
}

const (
	locale      = "US"
	associateID = ""
	apiKey      = ""
	apiSecret   = ""
)

func (s AmazonStore) build() error {
	categories := map[string]string{
		"babies":         "Baby",
		"beauty":         "Beauty",
		"books":          "Books",
		"fashion-babies": "FashionBaby",
		"fashion-boys":   "FashionBoys",
		"fashion-girls":  "FashionGirls",
		"fashion-men":    "FashionMen",
		"fashion-women":  "FashionWomen",
		"jewelry":        "Jewelry",
		"pets":           "PetSupplies",
		"toys-and-games": "Toys",
		"watches":        "Watches",
	}

	log.Printf("INFO  Building products started")
	client, _ := amazon.NewAmazing(locale, associateID, apiKey, apiSecret)

	for key, value := range categories {
		for i := 1; i <= 10; i++ {
			err := s.buildCategory(client, key, value, i)
			if err != nil {
				log.Printf("ERROR Building products finished [error: %s]", err.Error())
				return err
			}
		}
	}

	json, _ := json.Marshal(s)
	ioutil.WriteFile(productsFile, json, 0600)

	log.Printf("INFO  Building products finished [products: %d]", len(s.ProductIDs))
	return nil
}

func (s *AmazonStore) buildCategory(client *amazon.Amazing, category,
	amazonCategory string, page int) error {
	products, err := fetchProducts(client, category, amazonCategory, page)
	if err != nil {
		return err
	}

	for _, product := range products {
		s.Products[product.ID] = product
		s.ProductIDs = append(s.ProductIDs, product.ID)
		s.ProductIDsByCategory[category] = append(s.ProductIDsByCategory[category], product.ID)
	}
	return nil
}

func fetchProducts(client *amazon.Amazing, category, amazonCategory string,
	page int) ([]Product, error) {
	sort := "salesrank"
	if strings.Contains(amazonCategory, "Fashion") {
		sort = "reviewrank"
	}

	params := url.Values{
		"Operation":     []string{"ItemSearch"},
		"SearchIndex":   []string{amazonCategory},
		"Keywords":      []string{"%20"},
		"Condition":     []string{"New"},
		"Availability":  []string{"Available"},
		"MerchantId":    []string{"Amazon"},
		"Sort":          []string{sort},
		"ItemPage":      []string{strconv.Itoa(page)},
		"ResponseGroup": []string{"ItemAttributes,EditorialReview,Images"},
	}

	res, err := client.ItemSearch(params)
	if err != nil {
		return []Product{}, err
	}

	var products []Product
	for _, item := range res.AmazonItems.Items {
		product, err := toProduct(item)
		if err != nil {
			continue
		}

		product.Category = category
		products = append(products, product)
	}
	return products, nil
}

func toProduct(item amazon.AmazonItem) (Product, error) {
	if len(item.EditorialReviews) == 0 {
		return Product{}, fmt.Errorf("Invalid product")
	}

	product := Product{
		ID:           item.ASIN,
		Title:        strings.TrimSpace(item.ItemAttributes.Title),
		Description:  strings.TrimSpace(sanitize.HTML(item.EditorialReviews[0].Content)),
		ThumbnailURL: item.MediumImage.URL,
		ImageURL:     item.LargeImage.URL,
		Price:        item.ItemAttributes.ListPrice.FormattedPrice,
		URL:          item.DetailPageURL,
		AddedOn:      time.Now(),
	}

	if product.Title == "" || product.Description == "" ||
		product.ThumbnailURL == "" || product.ImageURL == "" ||
		product.Price == "" {
		return Product{}, fmt.Errorf("Invalid product")
	}
	return product, nil
}
<|endoftext|>


<commit_before>package horenso

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/jessevdk/go-flags"
	"github.com/kballard/go-shellquote"
)

const version = "0.0.2"

type opts struct {
	Reporter  []string `short:"r" long:"reporter" required:"true" value-name:"/path/to/reporter.pl" description:"handler for reporting the result of the job"`
	Noticer   []string `short:"n" long:"noticer" value-name:"/path/to/noticer.rb" description:"handler for noticing the start of the job"`
	TimeStamp bool     `short:"T" long:"timestamp" description:"add timestamp to merged output"`
	Tag       string   `short:"t" long:"tag" value-name:"job-name" description:"tag of the job"`
}

// Report is represents the result of the command
type Report struct {
	Command     string     `json:"command"`
	CommandArgs []string   `json:"commandArgs"`
	Tag         string     `json:"tag,omitempty"`
	Output      string     `json:"output"`
	Stdout      string     `json:"stdout"`
	Stderr      string     `json:"stderr"`
	ExitCode    *int       `json:"exitCode,omitempty"`
	Result      string     `json:"result"`
	Hostname    string     `json:"hostname"`
	Pid         *int       `json:"pid,omitempty"`
	StartAt     *time.Time `json:"startAt,omitempty"`
	EndAt       *time.Time `json:"endAt,omitempty"`
	SystemTime  *float64   `json:"systemTime,omitempty"`
	UserTime    *float64   `json:"userTime,omitempty"`
}

func (o *opts) run(args []string) (Report, error) {
	hostname, _ := os.Hostname()
	r := Report{
		Command:     shellquote.Join(args...),
		CommandArgs: args,
		Tag:         o.Tag,
		Hostname:    hostname,
	}
	cmd := exec.Command(args[0], args[1:]...)

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return o.failReport(r, err.Error()), err
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		stdoutPipe.Close()
		return o.failReport(r, err.Error()), err
	}

	var bufStdout bytes.Buffer
	var bufStderr bytes.Buffer
	var bufMerged bytes.Buffer

	var wtr io.Writer = &bufMerged
	if o.TimeStamp {
		wtr = newTimestampWriter(&bufMerged)
	}
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(&bufStdout, wtr))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(&bufStderr, wtr))

	r.StartAt = now()
	err = cmd.Start()
	if err != nil {
		stderrPipe.Close()
		stdoutPipe.Close()
		return o.failReport(r, err.Error()), err
	}
	if cmd.Process != nil {
		r.Pid = &cmd.Process.Pid
	}
	done := make(chan struct{})
	go func() {
		o.runNoticer(r)
		done <- struct{}{}
	}()

	outDone := make(chan struct{})
	go func() {
		defer func() {
			stdoutPipe.Close()
			outDone <- struct{}{}
		}()
		io.Copy(os.Stdout, stdoutPipe2)
	}()

	errDone := make(chan struct{})
	go func() {
		defer func() {
			stderrPipe.Close()
			errDone <- struct{}{}
		}()
		io.Copy(os.Stderr, stderrPipe2)
	}()

	<-outDone
	<-errDone
	err = cmd.Wait()
	r.EndAt = now()
	ex := wrapcommander.ResolveExitCode(err)
	r.ExitCode = &ex
	r.Result = fmt.Sprintf("command exited with code: %d", *r.ExitCode)
	if *r.ExitCode > 128 {
		r.Result = fmt.Sprintf("command died with signal: %d", *r.ExitCode&127)
	}
	r.Stdout = bufStdout.String()
	r.Stderr = bufStderr.String()
	r.Output = bufMerged.String()
	if p := cmd.ProcessState; p != nil {
		durPtr := func(t time.Duration) *float64 {
			f := float64(t) / float64(time.Second)
			return &f
		}
		r.UserTime = durPtr(p.UserTime())
		r.SystemTime = durPtr(p.SystemTime())
	}
	o.runReporter(r)
	<-done

	return r, nil
}

func now() *time.Time {
	now := time.Now()
	return &now
}

func parseArgs(args []string) (*flags.Parser, *opts, []string, error) {
	o := &opts{}
	p := flags.NewParser(o, flags.Default)
	p.Usage = "--reporter /path/to/reporter.pl -- /path/to/job [...]\n\nVersion: " + version
	rest, err := p.ParseArgs(args)
	return p, o, rest, err
}

// Run the horenso
func Run(args []string) int {
	p, o, cmdArgs, err := parseArgs(args)
	if err != nil || len(cmdArgs) < 1 {
		if ferr, ok := err.(*flags.Error); !ok || ferr.Type != flags.ErrHelp {
			p.WriteHelp(os.Stderr)
		}
		return 2
	}
	r, err := o.run(cmdArgs)
	if err != nil {
		return wrapcommander.ResolveExitCode(err)
	}
	return *r.ExitCode
}

func (o *opts) failReport(r Report, errStr string) Report {
	fail := -1
	r.ExitCode = &fail
	r.Result = fmt.Sprintf("failed to execute command: %s", errStr)
	done := make(chan struct{})
	go func() {
		o.runNoticer(r)
		done <- struct{}{}
	}()
	o.runReporter(r)
	<-done
	return r
}

func runHandler(cmdStr string, json []byte) ([]byte, error) {
	args, err := shellquote.Split(cmdStr)
	if err != nil || len(args) < 1 {
		return nil, fmt.Errorf("invalid handler: %q", cmdStr)
	}
	cmd := exec.Command(args[0], args[1:]...)
	stdinPipe, _ := cmd.StdinPipe()
	var b bytes.Buffer
	cmd.Stdout = &b
	cmd.Stderr = &b
	if err := cmd.Start(); err != nil {
		stdinPipe.Close()
		return b.Bytes(), err
	}
	stdinPipe.Write(json)
	stdinPipe.Close()
	err = cmd.Wait()
	return b.Bytes(), err
}

func runHandlers(handlers []string, json []byte) {
	wg := &sync.WaitGroup{}
	for _, handler := range handlers {
		wg.Add(1)
		go func(h string) {
			runHandler(h, json)
			wg.Done()
		}(handler)
	}
	wg.Wait()
}

func (o *opts) runNoticer(r Report) {
	if len(o.Noticer) < 1 {
		return
	}
	json, _ := json.Marshal(r)
	runHandlers(o.Noticer, json)
}

func (o *opts) runReporter(r Report) {
	json, _ := json.Marshal(r)
	runHandlers(o.Reporter, json)
}
<commit_msg>add override command status option<commit_after>package horenso

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/jessevdk/go-flags"
	"github.com/kballard/go-shellquote"
)

const version = "0.0.2"

type opts struct {
	Reporter       []string `short:"r" long:"reporter" required:"true" value-name:"/path/to/reporter.pl" description:"handler for reporting the result of the job"`
	Noticer        []string `short:"n" long:"noticer" value-name:"/path/to/noticer.rb" description:"handler for noticing the start of the job"`
	TimeStamp      bool     `short:"T" long:"timestamp" description:"add timestamp to merged output"`
	Tag            string   `short:"t" long:"tag" value-name:"job-name" description:"tag of the job"`
	OverrideStatus bool     `short:"o" long:"override-status" description:"override command exit status, always exit 0"`
}

// Report is represents the result of the command
type Report struct {
	Command     string     `json:"command"`
	CommandArgs []string   `json:"commandArgs"`
	Tag         string     `json:"tag,omitempty"`
	Output      string     `json:"output"`
	Stdout      string     `json:"stdout"`
	Stderr      string     `json:"stderr"`
	ExitCode    *int       `json:"exitCode,omitempty"`
	Result      string     `json:"result"`
	Hostname    string     `json:"hostname"`
	Pid         *int       `json:"pid,omitempty"`
	StartAt     *time.Time `json:"startAt,omitempty"`
	EndAt       *time.Time `json:"endAt,omitempty"`
	SystemTime  *float64   `json:"systemTime,omitempty"`
	UserTime    *float64   `json:"userTime,omitempty"`
}

func (o *opts) run(args []string) (Report, error) {
	hostname, _ := os.Hostname()
	r := Report{
		Command:     shellquote.Join(args...),
		CommandArgs: args,
		Tag:         o.Tag,
		Hostname:    hostname,
	}
	cmd := exec.Command(args[0], args[1:]...)

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return o.failReport(r, err.Error()), err
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		stdoutPipe.Close()
		return o.failReport(r, err.Error()), err
	}

	var bufStdout bytes.Buffer
	var bufStderr bytes.Buffer
	var bufMerged bytes.Buffer

	var wtr io.Writer = &bufMerged
	if o.TimeStamp {
		wtr = newTimestampWriter(&bufMerged)
	}
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(&bufStdout, wtr))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(&bufStderr, wtr))

	r.StartAt = now()
	err = cmd.Start()
	if err != nil {
		stderrPipe.Close()
		stdoutPipe.Close()
		return o.failReport(r, err.Error()), err
	}
	if cmd.Process != nil {
		r.Pid = &cmd.Process.Pid
	}
	done := make(chan struct{})
	go func() {
		o.runNoticer(r)
		done <- struct{}{}
	}()

	outDone := make(chan struct{})
	go func() {
		defer func() {
			stdoutPipe.Close()
			outDone <- struct{}{}
		}()
		io.Copy(os.Stdout, stdoutPipe2)
	}()

	errDone := make(chan struct{})
	go func() {
		defer func() {
			stderrPipe.Close()
			errDone <- struct{}{}
		}()
		io.Copy(os.Stderr, stderrPipe2)
	}()

	<-outDone
	<-errDone
	err = cmd.Wait()
	r.EndAt = now()
	ex := wrapcommander.ResolveExitCode(err)
	r.ExitCode = &ex
	r.Result = fmt.Sprintf("command exited with code: %d", *r.ExitCode)
	if *r.ExitCode > 128 {
		r.Result = fmt.Sprintf("command died with signal: %d", *r.ExitCode&127)
	}
	r.Stdout = bufStdout.String()
	r.Stderr = bufStderr.String()
	r.Output = bufMerged.String()
	if p := cmd.ProcessState; p != nil {
		durPtr := func(t time.Duration) *float64 {
			f := float64(t) / float64(time.Second)
			return &f
		}
		r.UserTime = durPtr(p.UserTime())
		r.SystemTime = durPtr(p.SystemTime())
	}
	o.runReporter(r)
	<-done

	return r, nil
}

func now() *time.Time {
	now := time.Now()
	return &now
}

func parseArgs(args []string) (*flags.Parser, *opts, []string, error) {
	o := &opts{}
	p := flags.NewParser(o, flags.Default)
	p.Usage = "--reporter /path/to/reporter.pl -- /path/to/job [...]\n\nVersion: " + version
	rest, err := p.ParseArgs(args)
	return p, o, rest, err
}

// Run the horenso
func Run(args []string) int {
	p, o, cmdArgs, err := parseArgs(args)
	if err != nil || len(cmdArgs) < 1 {
		if ferr, ok := err.(*flags.Error); !ok || ferr.Type != flags.ErrHelp {
			p.WriteHelp(os.Stderr)
		}
		return 2
	}
	r, err := o.run(cmdArgs)
	if err != nil {
		return wrapcommander.ResolveExitCode(err)
	}
	if o.OverrideStatus {
		return 0
	}
	return *r.ExitCode
}

func (o *opts) failReport(r Report, errStr string) Report {
	fail := -1
	r.ExitCode = &fail
	r.Result = fmt.Sprintf("failed to execute command: %s", errStr)
	done := make(chan struct{})
	go func() {
		o.runNoticer(r)
		done <- struct{}{}
	}()
	o.runReporter(r)
	<-done
	return r
}

func runHandler(cmdStr string, json []byte) ([]byte, error) {
	args, err := shellquote.Split(cmdStr)
	if err != nil || len(args) < 1 {
		return nil, fmt.Errorf("invalid handler: %q", cmdStr)
	}
	cmd := exec.Command(args[0], args[1:]...)
	stdinPipe, _ := cmd.StdinPipe()
	var b bytes.Buffer
	cmd.Stdout = &b
	cmd.Stderr = &b
	if err := cmd.Start(); err != nil {
		stdinPipe.Close()
		return b.Bytes(), err
	}
	stdinPipe.Write(json)
	stdinPipe.Close()
	err = cmd.Wait()
	return b.Bytes(), err
}

func runHandlers(handlers []string, json []byte) {
	wg := &sync.WaitGroup{}
	for _, handler := range handlers {
		wg.Add(1)
		go func(h string) {
			runHandler(h, json)
			wg.Done()
		}(handler)
	}
	wg.Wait()
}

func (o *opts) runNoticer(r Report) {
	if len(o.Noticer) < 1 {
		return
	}
	json, _ := json.Marshal(r)
	runHandlers(o.Noticer, json)
}

func (o *opts) runReporter(r Report) {
	json, _ := json.Marshal(r)
	runHandlers(o.Reporter, json)
}
<|endoftext|>


<commit_before>// This binary is the canonical way to use autoroute. It supports most use cases and should
// be able to provide most needs. Ideally the binary should merely be a wrapper around the core library
// and should be the canonical example of how to use it. There should be nothing which this binary can
// do which isn't possible in the core library.
package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"

	"github.com/AutoRoute/node"
	"github.com/AutoRoute/node/types"
	"github.com/AutoRoute/tuntap"
)

var listen = flag.String("listen", "[::]:34321",
	"The address to listen to incoming connections on")
var connect = flag.String("connect", "",
	"Comma separated list of addresses to connect to")
var autodiscover = flag.Bool("auto", false,
	"Whether we should try and find neighboring routers")
var dev_names = flag.String("devs", "",
	"Comma separated list of interfaces to discover on")
var keyfile = flag.String("keyfile", "",
	"The keyfile we should check for a key and write our current key to")
var btc_host = flag.String("btc_host", "localhost:8333",
	"The bitcoin daemon we should connect to")
var btc_user = flag.String("btc_user", "user",
	"The bitcoin daemon username")
var btc_pass = flag.String("btc_pass", "password",
	"The bitcoin daemon password")
var fake_money = flag.Bool("fake_money", false, "Enables a money system which is purely fake")
var status = flag.String("status", "[::1]:12345", "The port to expose status information on")
var unix = flag.String("unix", "", "The path to accept / receive packets as unix packets from")
var tcptun = flag.String("tcptun", "", "Address to try and tcp tunnel to")

func main() {
	log.Print(os.Args)
	flag.Parse()

	// Capture all signals to the quit channel
	quit := make(chan os.Signal)
	signal.Notify(quit)

	// Figure out and load what key we are using for our identity
	var key node.Key
	var err error
	if len(*keyfile) > 0 {
		key, err = node.LoadKey(*keyfile)
		if err != nil {
			log.Fatalf("Error loading key: %v", err)
		}
	} else {
		log.Print("Generating key")
		key, err = node.NewKey()
		if err != nil {
			log.Fatalf("Error Generating Key: %v", err)
		}
	}
	log.Printf("Key is %x", key)

	// Connect to our money server
	money := node.FakeMoney()
	if !*fake_money {
		log.Print("Connecting to bitcoin daemon")
		rpc, err := node.NewRPCMoney(*btc_host, *btc_user, *btc_pass)
		if err != nil {
			log.Fatalf("Error connection to bitcoin daemon: %v", err)
		}
		money = rpc
	}
	log.Printf("Connected")
	n := node.NewServer(key, money)

	log.Printf("Starting to listen on %s", *listen)
	err = n.Listen(*listen)
	if err != nil {
		log.Printf("Error listening: %v", err)
	}

	if *autodiscover {
		devs := make([]net.Interface, 0)

		if *dev_names == "" {
			devs, err = net.Interfaces()
			if err != nil {
				log.Fatal(err)
			}
		} else {
			for _, dev_name := range strings.Split(*dev_names, ",") {
				dev, err := net.InterfaceByName(dev_name)
				if err != nil {
					log.Fatal(err)
				}
				devs = append(devs, *dev)
			}
		}

		for _, dev := range devs {
			go func() {
				err := n.Probe(dev)
				if err != nil {
					log.Fatal(err)
				}
			}()
		}
	}

	for _, ip := range strings.Split(*connect, ",") {
		if len(ip) == 0 {
			continue
		}
		err := n.Connect(ip)
		if err != nil {
			log.Printf("Error connecting to %s: %v", ip, err)
		}
	}

	go func() {
		log.Fatal(http.ListenAndServe(*status, nil))
	}()

	if len(*tcptun) > 0 {
		log.Printf("Establishing tcp tunnel to %v", *tcptun)
		i, err := tuntap.Open("tun%d", tuntap.DevTun)
		if err != nil {
			log.Fatal(err)
		}
		dest := ""
		_, err = fmt.Sscanf(*tcptun, "%x", &dest)
		if err != nil {
			log.Fatal(err)
		}
		t := node.NewTCPTunnel(i, n.Node(), types.NodeAddress(dest), 10000)
		defer t.Close()
		<-quit
		return
	}

	if len(*unix) > 0 {
		log.Printf("Establishing unix interface %s", *unix)
		c, err := node.NewUnixSocket(*unix, n.Node())
		if err != nil {
			log.Fatal(err)
		}
		defer os.Remove(*unix)
		defer c.Close()
		<-quit
		return
	}

	<-quit
}
<commit_msg>Fix race condition in passing device argument to Probe call.<commit_after>// This binary is the canonical way to use autoroute. It supports most use cases and should
// be able to provide most needs. Ideally the binary should merely be a wrapper around the core library
// and should be the canonical example of how to use it. There should be nothing which this binary can
// do which isn't possible in the core library.
package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"

	"github.com/AutoRoute/node"
	"github.com/AutoRoute/node/types"
	"github.com/AutoRoute/tuntap"
)

var listen = flag.String("listen", "[::]:34321",
	"The address to listen to incoming connections on")
var connect = flag.String("connect", "",
	"Comma separated list of addresses to connect to")
var autodiscover = flag.Bool("auto", false,
	"Whether we should try and find neighboring routers")
var dev_names = flag.String("devs", "",
	"Comma separated list of interfaces to discover on")
var keyfile = flag.String("keyfile", "",
	"The keyfile we should check for a key and write our current key to")
var btc_host = flag.String("btc_host", "localhost:8333",
	"The bitcoin daemon we should connect to")
var btc_user = flag.String("btc_user", "user",
	"The bitcoin daemon username")
var btc_pass = flag.String("btc_pass", "password",
	"The bitcoin daemon password")
var fake_money = flag.Bool("fake_money", false, "Enables a money system which is purely fake")
var status = flag.String("status", "[::1]:12345", "The port to expose status information on")
var unix = flag.String("unix", "", "The path to accept / receive packets as unix packets from")
var tcptun = flag.String("tcptun", "", "Address to try and tcp tunnel to")

func main() {
	log.Print(os.Args)
	flag.Parse()

	// Capture all signals to the quit channel
	quit := make(chan os.Signal)
	signal.Notify(quit)

	// Figure out and load what key we are using for our identity
	var key node.Key
	var err error
	if len(*keyfile) > 0 {
		key, err = node.LoadKey(*keyfile)
		if err != nil {
			log.Fatalf("Error loading key: %v", err)
		}
	} else {
		log.Print("Generating key")
		key, err = node.NewKey()
		if err != nil {
			log.Fatalf("Error Generating Key: %v", err)
		}
	}
	log.Printf("Key is %x", key)

	// Connect to our money server
	money := node.FakeMoney()
	if !*fake_money {
		log.Print("Connecting to bitcoin daemon")
		rpc, err := node.NewRPCMoney(*btc_host, *btc_user, *btc_pass)
		if err != nil {
			log.Fatalf("Error connection to bitcoin daemon: %v", err)
		}
		money = rpc
	}
	log.Printf("Connected")
	n := node.NewServer(key, money)

	log.Printf("Starting to listen on %s", *listen)
	err = n.Listen(*listen)
	if err != nil {
		log.Printf("Error listening: %v", err)
	}

	if *autodiscover {
		devs := make([]net.Interface, 0)

		if *dev_names == "" {
			devs, err = net.Interfaces()
			if err != nil {
				log.Fatal(err)
			}
		} else {
			for _, dev_name := range strings.Split(*dev_names, ",") {
				dev, err := net.InterfaceByName(dev_name)
				if err != nil {
					log.Fatal(err)
				}
				devs = append(devs, *dev)
			}
		}

		for _, dev := range devs {
			go func(dev net.Interface) {
				err := n.Probe(dev)
				if err != nil {
					log.Fatal(err)
				}
			}(dev)
		}
	}

	for _, ip := range strings.Split(*connect, ",") {
		if len(ip) == 0 {
			continue
		}
		err := n.Connect(ip)
		if err != nil {
			log.Printf("Error connecting to %s: %v", ip, err)
		}
	}

	go func() {
		log.Fatal(http.ListenAndServe(*status, nil))
	}()

	if len(*tcptun) > 0 {
		log.Printf("Establishing tcp tunnel to %v", *tcptun)
		i, err := tuntap.Open("tun%d", tuntap.DevTun)
		if err != nil {
			log.Fatal(err)
		}
		dest := ""
		_, err = fmt.Sscanf(*tcptun, "%x", &dest)
		if err != nil {
			log.Fatal(err)
		}
		t := node.NewTCPTunnel(i, n.Node(), types.NodeAddress(dest), 10000)
		defer t.Close()
		<-quit
		return
	}

	if len(*unix) > 0 {
		log.Printf("Establishing unix interface %s", *unix)
		c, err := node.NewUnixSocket(*unix, n.Node())
		if err != nil {
			log.Fatal(err)
		}
		defer os.Remove(*unix)
		defer c.Close()
		<-quit
		return
	}

	<-quit
}
<|endoftext|>