<commit_before>package provider

import (
	log "github.com/Sirupsen/logrus"
	"github.com/cenkalti/backoff"
	"github.com/containous/traefik/provider/k8s"
	"github.com/containous/traefik/safe"
	"github.com/containous/traefik/types"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"text/template"
	"time"
)

const (
	serviceAccountToken  = "/var/run/secrets/kubernetes.io/serviceaccount/token"
	serviceAccountCACert = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)

// Kubernetes holds configurations of the Kubernetes provider.
type Kubernetes struct {
	BaseProvider           `mapstructure:",squash"`
	Endpoint               string
	disablePassHostHeaders bool
	Namespaces             []string
}

func (provider *Kubernetes) createClient() (k8s.Client, error) {
	var token string
	tokenBytes, err := ioutil.ReadFile(serviceAccountToken)
	if err == nil {
		token = string(tokenBytes)
		log.Debugf("Kubernetes token: %s", token)
	} else {
		log.Errorf("Kubernetes load token error: %s", err)
	}
	caCert, err := ioutil.ReadFile(serviceAccountCACert)
	if err == nil {
		log.Debugf("Kubernetes CA cert: %s", serviceAccountCACert)
	} else {
		log.Errorf("Kubernetes load token error: %s", err)
	}
	kubernetesHost := os.Getenv("KUBERNETES_SERVICE_HOST")
	kubernetesPort := os.Getenv("KUBERNETES_SERVICE_PORT_HTTPS")
	if len(kubernetesPort) > 0 && len(kubernetesHost) > 0 {
		provider.Endpoint = "https://" + kubernetesHost + ":" + kubernetesPort
	}
	log.Debugf("Kubernetes endpoint: %s", provider.Endpoint)
	return k8s.NewClient(provider.Endpoint, caCert, token)
}

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
	k8sClient, err := provider.createClient()
	if err != nil {
		return err
	}
	backOff := backoff.NewExponentialBackOff()

	pool.Go(func(stop chan bool) {
		stopWatch := make(chan bool)
		defer close(stopWatch)
		operation := func() error {
			select {
			case <-stop:
				return nil
			default:
			}
			for {
				eventsChan, errEventsChan, err := k8sClient.WatchAll(stopWatch)
				if err != nil {
					log.Errorf("Error watching kubernetes events: %v", err)
					return err
				}
			Watch:
				for {
					select {
					case <-stop:
						stopWatch <- true
						return nil
					case err := <-errEventsChan:
						if strings.Contains(err.Error(), io.EOF.Error()) {
							// edge case, kubernetes long-polling disconnection
							break Watch
						}
						return err
					case event := <-eventsChan:
						log.Debugf("Received event from kubenetes %+v", event)
						templateObjects, err := provider.loadIngresses(k8sClient)
						if err != nil {
							return err
						}
						configurationChan <- types.ConfigMessage{
							ProviderName:  "kubernetes",
							Configuration: provider.loadConfig(*templateObjects),
						}
					}
				}
			}
		}

		notify := func(err error, time time.Duration) {
			log.Errorf("Kubernetes connection error %+v, retrying in %s", err, time)
		}
		err := backoff.RetryNotify(operation, backOff, notify)
		if err != nil {
			log.Fatalf("Cannot connect to Kubernetes server %+v", err)
		}
	})

	templateObjects, err := provider.loadIngresses(k8sClient)
	if err != nil {
		return err
	}
	configurationChan <- types.ConfigMessage{
		ProviderName:  "kubernetes",
		Configuration: provider.loadConfig(*templateObjects),
	}

	return nil
}

func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configuration, error) {
	ingresses, err := k8sClient.GetIngresses(func(ingress k8s.Ingress) bool {
		if len(provider.Namespaces) == 0 {
			return true
		}
		for _, n := range provider.Namespaces {
			if ingress.ObjectMeta.Namespace == n {
				return true
			}
		}
		return false
	})
	if err != nil {
		log.Errorf("Error retrieving ingresses: %+v", err)
		return nil, err
	}
	templateObjects := types.Configuration{
		map[string]*types.Backend{},
		map[string]*types.Frontend{},
	}
	PassHostHeader := provider.getPassHostHeader()
	for _, i := range ingresses {
		for _, r := range i.Spec.Rules {
			for _, pa := range r.HTTP.Paths {
				if _, exists := templateObjects.Backends[r.Host+pa.Path]; !exists {
					templateObjects.Backends[r.Host+pa.Path] = &types.Backend{
						Servers: make(map[string]types.Server),
					}
				}
				if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
					templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
						Backend:        r.Host + pa.Path,
						PassHostHeader: PassHostHeader,
						Routes:         make(map[string]types.Route),
					}
				}
				if _, exists := templateObjects.Frontends[r.Host+pa.Path].Routes[r.Host]; !exists {
					templateObjects.Frontends[r.Host+pa.Path].Routes[r.Host] = types.Route{
						Rule: "Host:" + r.Host,
					}
				}
				if len(pa.Path) > 0 {
					ruleType := i.Annotations["traefik.frontend.rule.type"]

					switch strings.ToLower(ruleType) {
					case "pathprefixstrip":
						ruleType = "PathPrefixStrip"
					case "pathstrip":
						ruleType = "PathStrip"
					case "path":
						ruleType = "Path"
					case "pathprefix":
						ruleType = "PathPrefix"
					default:
						log.Debugf("Unknown RuleType `%s`, falling back to `PathPrefix", ruleType)
						ruleType = "PathPrefix"
					}

					templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{
						Rule: ruleType + ":" + pa.Path,
					}
				}
				services, err := k8sClient.GetServices(func(service k8s.Service) bool {
					return service.Name == pa.Backend.ServiceName
				})
				if err != nil {
					log.Errorf("Error retrieving services: %v", err)
					continue
				}
				if len(services) == 0 {
					// no backends found, delete frontend...
					delete(templateObjects.Frontends, r.Host+pa.Path)
					log.Errorf("Error retrieving services %s", pa.Backend.ServiceName)
				}
				for _, service := range services {
					protocol := "http"
					for _, port := range service.Spec.Ports {
						if port.Port == pa.Backend.ServicePort.IntValue() {
							if port.Port == 443 {
								protocol = "https"
							}
							templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{
								URL:    protocol + "://" + service.Spec.ClusterIP + ":" + pa.Backend.ServicePort.String(),
								Weight: 1,
							}
							break
						}
					}
				}
			}
		}
	}
	return &templateObjects, nil
}

func (provider *Kubernetes) getPassHostHeader() bool {
	if provider.disablePassHostHeaders {
		return false
	}
	return true
}

func (provider *Kubernetes) loadConfig(templateObjects types.Configuration) *types.Configuration {
	var FuncMap = template.FuncMap{}
	configuration, err := provider.getConfiguration("templates/kubernetes.tmpl", FuncMap, templateObjects)
	if err != nil {
		log.Error(err)
	}
	return configuration
}
<commit_msg>change log error of "ruleType" to warning<commit_after>package provider

import (
	log "github.com/Sirupsen/logrus"
	"github.com/cenkalti/backoff"
	"github.com/containous/traefik/provider/k8s"
	"github.com/containous/traefik/safe"
	"github.com/containous/traefik/types"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"text/template"
	"time"
)

const (
	serviceAccountToken  = "/var/run/secrets/kubernetes.io/serviceaccount/token"
	serviceAccountCACert = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)

// Kubernetes holds configurations of the Kubernetes provider.
type Kubernetes struct {
	BaseProvider           `mapstructure:",squash"`
	Endpoint               string
	disablePassHostHeaders bool
	Namespaces             []string
}

func (provider *Kubernetes) createClient() (k8s.Client, error) {
	var token string
	tokenBytes, err := ioutil.ReadFile(serviceAccountToken)
	if err == nil {
		token = string(tokenBytes)
		log.Debugf("Kubernetes token: %s", token)
	} else {
		log.Errorf("Kubernetes load token error: %s", err)
	}
	caCert, err := ioutil.ReadFile(serviceAccountCACert)
	if err == nil {
		log.Debugf("Kubernetes CA cert: %s", serviceAccountCACert)
	} else {
		log.Errorf("Kubernetes load token error: %s", err)
	}
	kubernetesHost := os.Getenv("KUBERNETES_SERVICE_HOST")
	kubernetesPort := os.Getenv("KUBERNETES_SERVICE_PORT_HTTPS")
	if len(kubernetesPort) > 0 && len(kubernetesHost) > 0 {
		provider.Endpoint = "https://" + kubernetesHost + ":" + kubernetesPort
	}
	log.Debugf("Kubernetes endpoint: %s", provider.Endpoint)
	return k8s.NewClient(provider.Endpoint, caCert, token)
}

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
	k8sClient, err := provider.createClient()
	if err != nil {
		return err
	}
	backOff := backoff.NewExponentialBackOff()

	pool.Go(func(stop chan bool) {
		stopWatch := make(chan bool)
		defer close(stopWatch)
		operation := func() error {
			select {
			case <-stop:
				return nil
			default:
			}
			for {
				eventsChan, errEventsChan, err := k8sClient.WatchAll(stopWatch)
				if err != nil {
					log.Errorf("Error watching kubernetes events: %v", err)
					return err
				}
			Watch:
				for {
					select {
					case <-stop:
						stopWatch <- true
						return nil
					case err := <-errEventsChan:
						if strings.Contains(err.Error(), io.EOF.Error()) {
							// edge case, kubernetes long-polling disconnection
							break Watch
						}
						return err
					case event := <-eventsChan:
						log.Debugf("Received event from kubenetes %+v", event)
						templateObjects, err := provider.loadIngresses(k8sClient)
						if err != nil {
							return err
						}
						configurationChan <- types.ConfigMessage{
							ProviderName:  "kubernetes",
							Configuration: provider.loadConfig(*templateObjects),
						}
					}
				}
			}
		}

		notify := func(err error, time time.Duration) {
			log.Errorf("Kubernetes connection error %+v, retrying in %s", err, time)
		}
		err := backoff.RetryNotify(operation, backOff, notify)
		if err != nil {
			log.Fatalf("Cannot connect to Kubernetes server %+v", err)
		}
	})

	templateObjects, err := provider.loadIngresses(k8sClient)
	if err != nil {
		return err
	}
	configurationChan <- types.ConfigMessage{
		ProviderName:  "kubernetes",
		Configuration: provider.loadConfig(*templateObjects),
	}

	return nil
}

func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configuration, error) {
	ingresses, err := k8sClient.GetIngresses(func(ingress k8s.Ingress) bool {
		if len(provider.Namespaces) == 0 {
			return true
		}
		for _, n := range provider.Namespaces {
			if ingress.ObjectMeta.Namespace == n {
				return true
			}
		}
		return false
	})
	if err != nil {
		log.Errorf("Error retrieving ingresses: %+v", err)
		return nil, err
	}
	templateObjects := types.Configuration{
		map[string]*types.Backend{},
		map[string]*types.Frontend{},
	}
	PassHostHeader := provider.getPassHostHeader()
	for _, i := range ingresses {
		for _, r := range i.Spec.Rules {
			for _, pa := range r.HTTP.Paths {
				if _, exists := templateObjects.Backends[r.Host+pa.Path]; !exists {
					templateObjects.Backends[r.Host+pa.Path] = &types.Backend{
						Servers: make(map[string]types.Server),
					}
				}
				if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
					templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
						Backend:        r.Host + pa.Path,
						PassHostHeader: PassHostHeader,
						Routes:         make(map[string]types.Route),
					}
				}
				if _, exists := templateObjects.Frontends[r.Host+pa.Path].Routes[r.Host]; !exists {
					templateObjects.Frontends[r.Host+pa.Path].Routes[r.Host] = types.Route{
						Rule: "Host:" + r.Host,
					}
				}
				if len(pa.Path) > 0 {
					ruleType := i.Annotations["traefik.frontend.rule.type"]

					switch strings.ToLower(ruleType) {
					case "pathprefixstrip":
						ruleType = "PathPrefixStrip"
					case "pathstrip":
						ruleType = "PathStrip"
					case "path":
						ruleType = "Path"
					case "pathprefix":
						ruleType = "PathPrefix"
					default:
						log.Warnf("Unknown RuleType `%s`, falling back to `PathPrefix", ruleType)
						ruleType = "PathPrefix"
					}

					templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{
						Rule: ruleType + ":" + pa.Path,
					}
				}
				services, err := k8sClient.GetServices(func(service k8s.Service) bool {
					return service.Name == pa.Backend.ServiceName
				})
				if err != nil {
					log.Errorf("Error retrieving services: %v", err)
					continue
				}
				if len(services) == 0 {
					// no backends found, delete frontend...
					delete(templateObjects.Frontends, r.Host+pa.Path)
					log.Errorf("Error retrieving services %s", pa.Backend.ServiceName)
				}
				for _, service := range services {
					protocol := "http"
					for _, port := range service.Spec.Ports {
						if port.Port == pa.Backend.ServicePort.IntValue() {
							if port.Port == 443 {
								protocol = "https"
							}
							templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{
								URL:    protocol + "://" + service.Spec.ClusterIP + ":" + pa.Backend.ServicePort.String(),
								Weight: 1,
							}
							break
						}
					}
				}
			}
		}
	}
	return &templateObjects, nil
}

func (provider *Kubernetes) getPassHostHeader() bool {
	if provider.disablePassHostHeaders {
		return false
	}
	return true
}

func (provider *Kubernetes) loadConfig(templateObjects types.Configuration) *types.Configuration {
	var FuncMap = template.FuncMap{}
	configuration, err := provider.getConfiguration("templates/kubernetes.tmpl", FuncMap, templateObjects)
	if err != nil {
		log.Error(err)
	}
	return configuration
}
<|endoftext|>


<commit_before>// Package line implements the OAuth2 protocol for authenticating users through line.
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
package line

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"fmt"

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

const (
	authURL      string = "https://access.line.me/oauth2/v2.1/authorize"
	tokenURL     string = "https://api.line.me/oauth2/v2.1/token"
	endpointUser string = "https://api.line.me/v2/profile"
)

// Provider is the implementation of `goth.Provider` for accessing Battle.net.
type Provider struct {
	ClientKey    string
	Secret       string
	CallbackURL  string
	HTTPClient   *http.Client
	config       *oauth2.Config
	providerName string
}

// New creates a new Line provider and sets up important connection details.
// You should always call `line.New` to get a new provider.  Never try to
// create one manually.
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:    clientKey,
		Secret:       secret,
		CallbackURL:  callbackURL,
		providerName: "line",
	}
	p.config = newConfig(p, scopes)
	return p
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return p.providerName
}

// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
	p.providerName = name
}

// Client returns a pointer to http.Client setting some client fallback.
func (p *Provider) Client() *http.Client {
	return goth.HTTPClientWithFallBack(p.HTTPClient)
}

// Debug is a no-op for the line package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks line.me for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	return &Session{
		AuthURL: p.config.AuthCodeURL(state),
	}, nil
}

// FetchUser will go to line.me and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	sess := session.(*Session)
	user := goth.User{
		AccessToken:  sess.AccessToken,
		Provider:     p.Name(),
		RefreshToken: sess.RefreshToken,
		ExpiresAt:    sess.ExpiresAt,
	}

	if user.AccessToken == "" {
		// data is not yet retrieved since accessToken is still empty
		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
	}

	// Get the userID, line needs userID in order to get user profile info
	c := p.Client()
	req, err := http.NewRequest("GET", endpointUser, nil)
	if err != nil {
		return user, err
	}

	req.Header.Add("Authorization", "Bearer "+sess.AccessToken)

	response, err := c.Do(req)
	if err != nil {
		if response != nil {
			response.Body.Close()
		}
		return user, err
	}

	if response.StatusCode != http.StatusOK {
		return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode)
	}

	bits, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return user, err
	}

	u := struct {
		UserID        string `json:"userId"`
		DisplayName   string `json:"displayName"`
		PictureURL    string `json:"pictureUrl"`
		StatusMessage string `json:"statusMessage"`
	}{}

	if err = json.NewDecoder(bytes.NewReader(bits)).Decode(&u); err != nil {
		return user, err
	}

	user.NickName = u.DisplayName
	user.UserID = u.UserID
	return user, err
}

func newConfig(provider *Provider, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     provider.ClientKey,
		ClientSecret: provider.Secret,
		RedirectURL:  provider.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{},
	}

	if len(scopes) > 0 {
		for _, scope := range scopes {
			c.Scopes = append(c.Scopes, scope)
		}
	}
	return c
}

//RefreshTokenAvailable refresh token is provided by auth provider or not
func (p *Provider) RefreshTokenAvailable() bool {
	return false
}

//RefreshToken get new access token based on the refresh token
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	return nil, nil
}
<commit_msg>Added line as a provider<commit_after>// Package line implements the OAuth2 protocol for authenticating users through line.
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
package line

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"fmt"

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

const (
	authURL      string = "https://access.line.me/oauth2/v2.1/authorize"
	tokenURL     string = "https://api.line.me/oauth2/v2.1/token"
	endpointUser string = "https://api.line.me/v2/profile"
)

// Provider is the implementation of `goth.Provider` for accessing Line.me.
type Provider struct {
	ClientKey    string
	Secret       string
	CallbackURL  string
	HTTPClient   *http.Client
	config       *oauth2.Config
	providerName string
}

// New creates a new Line provider and sets up important connection details.
// You should always call `line.New` to get a new provider.  Never try to
// create one manually.
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:    clientKey,
		Secret:       secret,
		CallbackURL:  callbackURL,
		providerName: "line",
	}
	p.config = newConfig(p, scopes)
	return p
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return p.providerName
}

// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
	p.providerName = name
}

// Client returns a pointer to http.Client setting some client fallback.
func (p *Provider) Client() *http.Client {
	return goth.HTTPClientWithFallBack(p.HTTPClient)
}

// Debug is a no-op for the line package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks line.me for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	return &Session{
		AuthURL: p.config.AuthCodeURL(state),
	}, nil
}

// FetchUser will go to line.me and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	sess := session.(*Session)
	user := goth.User{
		AccessToken:  sess.AccessToken,
		Provider:     p.Name(),
		RefreshToken: sess.RefreshToken,
		ExpiresAt:    sess.ExpiresAt,
	}

	if user.AccessToken == "" {
		// data is not yet retrieved since accessToken is still empty
		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
	}

	// Get the userID, line needs userID in order to get user profile info
	c := p.Client()
	req, err := http.NewRequest("GET", endpointUser, nil)
	if err != nil {
		return user, err
	}

	req.Header.Add("Authorization", "Bearer "+sess.AccessToken)

	response, err := c.Do(req)
	if err != nil {
		if response != nil {
			response.Body.Close()
		}
		return user, err
	}

	if response.StatusCode != http.StatusOK {
		return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode)
	}

	bits, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return user, err
	}

	u := struct {
		UserID        string `json:"userId"`
		DisplayName   string `json:"displayName"`
		PictureURL    string `json:"pictureUrl"`
		StatusMessage string `json:"statusMessage"`
	}{}

	if err = json.NewDecoder(bytes.NewReader(bits)).Decode(&u); err != nil {
		return user, err
	}

	user.NickName = u.DisplayName
	user.UserID = u.UserID
	return user, err
}

func newConfig(provider *Provider, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     provider.ClientKey,
		ClientSecret: provider.Secret,
		RedirectURL:  provider.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{},
	}

	if len(scopes) > 0 {
		for _, scope := range scopes {
			c.Scopes = append(c.Scopes, scope)
		}
	}
	return c
}

//RefreshTokenAvailable refresh token is provided by auth provider or not
func (p *Provider) RefreshTokenAvailable() bool {
	return false
}

//RefreshToken get new access token based on the refresh token
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/docopt/docopt-go"
	. "github.com/fholiveira/smartprompt/parsers"
)

func getParsers() []Parser {
	return []Parser{
		PluginParser{},
		ColorParser{},
		WhiteSpacesParser{},
	}
}

func print(errors []error) {
	for _, err := range errors {
		fmt.Println(err)
	}
}

func parsePrompt(pattern string, debug bool) string {
	var errors []error
	prompt := PromptLine{pattern}

	for _, parser := range getParsers() {
		prompt, errors = parser.Parse(prompt)
		if debug && nil != errors {
			print(errors)
		}
	}

	return prompt.Text
}

func main() {
	arguments, _ := docopt.Parse(usage(), nil, true, "0.1", false)

	debug, _ := arguments["--debug"].(bool)
	pattern, _ := arguments["--pattern"].(string)

	fmt.Println(parsePrompt(pattern, debug))
}

func usage() string {
	return `Smart Prompt
A customizable prompt generator for your terminal emulator.

Usage:
  smartprompt [--pattern=<pattern>] [-d | --debug]
  smartprompt -h | --help
  smartprompt --version

Options:
  --pattern=<pattern>    Prompt pattern [default: {GREEN:bold}{user}@{host} {BLUE:bold}{location:vimstyle} {sourcecontrol} {PURPLE:bold}{symbol} {TEXT:reset}].
  -d, --debug            Debug mode (print all errors in stdout).
  -h, --help             Show this screen.
  --version              Show version.`
}
<commit_msg>Rename docopt<commit_after>package main

import (
	"fmt"

	"github.com/docopt/docopt.go"
	. "github.com/fholiveira/smartprompt/parsers"
)

func getParsers() []Parser {
	return []Parser{
		PluginParser{},
		ColorParser{},
		WhiteSpacesParser{},
	}
}

func print(errors []error) {
	for _, err := range errors {
		fmt.Println(err)
	}
}

func parsePrompt(pattern string, debug bool) string {
	var errors []error
	prompt := PromptLine{pattern}

	for _, parser := range getParsers() {
		prompt, errors = parser.Parse(prompt)
		if debug && nil != errors {
			print(errors)
		}
	}

	return prompt.Text
}

func main() {
	arguments, _ := docopt.Parse(usage(), nil, true, "0.1", false)

	debug, _ := arguments["--debug"].(bool)
	pattern, _ := arguments["--pattern"].(string)

	fmt.Println(parsePrompt(pattern, debug))
}

func usage() string {
	return `Smart Prompt
A customizable prompt generator for your terminal emulator.

Usage:
  smartprompt [--pattern=<pattern>] [-d | --debug]
  smartprompt -h | --help
  smartprompt --version

Options:
  --pattern=<pattern>    Prompt pattern [default: {GREEN:bold}{user}@{host} {BLUE:bold}{location:vimstyle} {sourcecontrol} {PURPLE:bold}{symbol} {TEXT:reset}].
  -d, --debug            Debug mode (print all errors in stdout).
  -h, --help             Show this screen.
  --version              Show version.`
}
<|endoftext|>


<commit_before>package main

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

	"github.com/DataDog/datadog-go/statsd"
	"github.com/icub3d/graceful"
	"github.com/stripe/go-einhorn/einhorn"
	"gopkg.in/elazarl/goproxy.v1"
)

var privateNetworks []net.IPNet

var connectTimeout time.Duration

var track *statsd.Client

func init() {
	var err error
	privateNetworkStrings := []string{
		"10.0.0.0/8",
		"172.16.0.0/12",
		"192.168.0.0/16",
		"fc00::/7",
	}

	privateNetworks = make([]net.IPNet, len(privateNetworkStrings))
	for i, netstring := range privateNetworkStrings {
		_, net, err := net.ParseCIDR(netstring)
		if err != nil {
			log.Fatal(err)
		}
		privateNetworks[i] = *net
	}

	track, err = statsd.New("127.0.0.1:8200")
	if err != nil {
		log.Fatal(err)
	}
	track.Namespace = "smokescreen."
}

func isPrivateNetwork(ip net.IP) bool {
	if !ip.IsGlobalUnicast() {
		return true
	}

	for _, net := range privateNetworks {
		if net.Contains(ip) {
			return true
		}
	}
	return false
}

func safeResolve(network, addr string) (string, error) {
	track.Count("resolver.attempts_total", 1, []string{}, 0.3)
	resolved, err := net.ResolveTCPAddr(network, addr)
	if err != nil {
		track.Count("resolver.errors_total", 1, []string{}, 0.3)
		return "", err
	}

	if isPrivateNetwork(resolved.IP) {
		track.Count("resolver.illegal_total", 1, []string{}, 0.3)
		return "", fmt.Errorf("host %s resolves to illegal IP %s",
			addr, resolved.IP)
	}

	return resolved.String(), nil
}

func dial(network, addr string) (net.Conn, error) {
	resolved, err := safeResolve(network, addr)
	if err != nil {
		return nil, err
	}

	return net.DialTimeout(network, resolved, connectTimeout)
}

func errorResponse(req *http.Request, err error) *http.Response {
	resp := goproxy.NewResponse(req,
		goproxy.ContentTypeText,
		http.StatusServiceUnavailable,
		err.Error()+"\n")
	resp.ProtoMajor = req.ProtoMajor
	resp.ProtoMinor = req.ProtoMinor
	resp.Header.Add("X-Smokescreen-Error", err.Error())
	return resp
}

func buildProxy() *goproxy.ProxyHttpServer {
	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = false
	proxy.Tr.Dial = dial
	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		ctx.Logf("Received HTTP proxy request: "+
			"remote=%#v host=%#v url=%#v",
			ctx.Req.RemoteAddr,
			ctx.Req.Host,
			ctx.Req.RequestURI)
		ctx.UserData = time.Now().Unix()
		return req, nil
	})
	proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
		ctx.Logf("Received CONNECT proxy request: "+
			"remote=%#v host=%#v",
			ctx.Req.RemoteAddr,
			host)

		resolved, err := safeResolve("tcp", host)
		if err != nil {
			ctx.Resp = errorResponse(ctx.Req, err)
			return goproxy.RejectConnect, ""
		}
		ctx.UserData = time.Now().Unix()
		logHttpsRequest(ctx, resolved)
		return goproxy.OkConnect, resolved
	})

	proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		logResponse(ctx)
		if resp == nil && ctx.Error != nil {
			resp = errorResponse(ctx.Req, ctx.Error)
		}
		return resp
	})

	return proxy
}

func logHttpsRequest(ctx *goproxy.ProxyCtx, resolved string) {
	var contentLength int64
	if ctx.Resp != nil {
		contentLength = ctx.Resp.ContentLength
	}
	from_host, from_port, _ := net.SplitHostPort(ctx.Req.RemoteAddr)
	to_host, to_port, _ := net.SplitHostPort(resolved)
	log.Printf("Received CONNECT request: "+
		"proxy_type=connect src_host=%#v src_port=%s host=%#v dest_ip=%#v dest_port=%s start_time=%#v end_time=%d content_length=%#v\n",
		from_host,
		from_port,
		ctx.Req.Host,
		to_host,
		to_port,
		ctx.UserData,
		time.Now().Unix(),
		// The content length is often -1 because of HTTP chunked encoding. this is normal.
		contentLength,
	)
}

func logResponse(ctx *goproxy.ProxyCtx) {
	var contentLength int64
	if ctx.RoundTrip == nil || ctx.RoundTrip.TCPAddr == nil {
		// Reasons this might happen:
		// 1) private ip destination (eg. 192.168.0.0/16, 10.0.0.0/8, etc)
		// 2) Destination that doesn't respond (eg. i/o timeout)
		// 3) destination domain that doesn't resolve
		// 4) bogus IP address (eg. 1154.218.100.183)
		log.Println("Could not log response: missing IP address")
		return
	}
	if ctx.Resp != nil {
		contentLength = ctx.Resp.ContentLength
	}
	from_host, from_port, _ := net.SplitHostPort(ctx.Req.RemoteAddr)
	log.Printf("Completed response: "+
		"proxy_type=http src_host=%#v src_port=%s host=%#v dest_ip=%#v dest_port=%d start_time=%#v end_time=%d content_length=%#v\n",
		from_host,
		from_port,
		ctx.Req.Host,
		ctx.RoundTrip.TCPAddr.IP.String(),
		ctx.RoundTrip.TCPAddr.Port,
		ctx.UserData,
		time.Now().Unix(),
		// The content length is often -1 because of HTTP chunked encoding. this is normal.
		contentLength,
	)
}

func findListener(defaultPort int) (net.Listener, error) {
	if einhorn.IsWorker() {
		listener, err := einhorn.GetListener(0)
		if err != nil {
			return nil, err
		}

		err = einhorn.Ack()

		return listener, err
	} else {
		return net.Listen("tcp", fmt.Sprintf(":%d", defaultPort))
	}
}

func main() {
	var port int
	var maintenanceFile string

	flag.IntVar(&port, "port", 4750, "Port to bind on")
	flag.DurationVar(&connectTimeout, "timeout",
		time.Duration(10)*time.Second, "Time to wait while connecting")
	flag.StringVar(&maintenanceFile, "maintenance", "",
		"Flag file for maintenance. chmod to 000 to put into maintenance mode")
	flag.Parse()

	proxy := buildProxy()

	listener, err := findListener(port)
	if err != nil {
		log.Fatal(err)
	}

	kill := make(chan os.Signal, 1)

	var handler http.Handler = proxy
	if maintenanceFile != "" {
		handler = &HealthcheckMiddleware{
			App:             handler,
			MaintenanceFile: maintenanceFile,
		}
	}

	server := graceful.NewServer(&http.Server{
		Handler: handler,
	})
	go func() {
		<-kill
		server.Close()
	}()
	signal.Notify(kill, syscall.SIGUSR2, syscall.SIGTERM)

	err = server.Serve(listener)
	if !strings.HasSuffix(err.Error(), "use of closed network connection") {
		log.Fatal(err)
	}
}
<commit_msg>Normalize destination host (remove port number)<commit_after>package main

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

	"github.com/DataDog/datadog-go/statsd"
	"github.com/icub3d/graceful"
	"github.com/stripe/go-einhorn/einhorn"
	"gopkg.in/elazarl/goproxy.v1"
)

var privateNetworks []net.IPNet

var connectTimeout time.Duration

var track *statsd.Client

func init() {
	var err error
	privateNetworkStrings := []string{
		"10.0.0.0/8",
		"172.16.0.0/12",
		"192.168.0.0/16",
		"fc00::/7",
	}

	privateNetworks = make([]net.IPNet, len(privateNetworkStrings))
	for i, netstring := range privateNetworkStrings {
		_, net, err := net.ParseCIDR(netstring)
		if err != nil {
			log.Fatal(err)
		}
		privateNetworks[i] = *net
	}

	track, err = statsd.New("127.0.0.1:8200")
	if err != nil {
		log.Fatal(err)
	}
	track.Namespace = "smokescreen."
}

func isPrivateNetwork(ip net.IP) bool {
	if !ip.IsGlobalUnicast() {
		return true
	}

	for _, net := range privateNetworks {
		if net.Contains(ip) {
			return true
		}
	}
	return false
}

func safeResolve(network, addr string) (string, error) {
	track.Count("resolver.attempts_total", 1, []string{}, 0.3)
	resolved, err := net.ResolveTCPAddr(network, addr)
	if err != nil {
		track.Count("resolver.errors_total", 1, []string{}, 0.3)
		return "", err
	}

	if isPrivateNetwork(resolved.IP) {
		track.Count("resolver.illegal_total", 1, []string{}, 0.3)
		return "", fmt.Errorf("host %s resolves to illegal IP %s",
			addr, resolved.IP)
	}

	return resolved.String(), nil
}

func dial(network, addr string) (net.Conn, error) {
	resolved, err := safeResolve(network, addr)
	if err != nil {
		return nil, err
	}

	return net.DialTimeout(network, resolved, connectTimeout)
}

func errorResponse(req *http.Request, err error) *http.Response {
	resp := goproxy.NewResponse(req,
		goproxy.ContentTypeText,
		http.StatusServiceUnavailable,
		err.Error()+"\n")
	resp.ProtoMajor = req.ProtoMajor
	resp.ProtoMinor = req.ProtoMinor
	resp.Header.Add("X-Smokescreen-Error", err.Error())
	return resp
}

func buildProxy() *goproxy.ProxyHttpServer {
	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = false
	proxy.Tr.Dial = dial
	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		ctx.Logf("Received HTTP proxy request: "+
			"remote=%#v host=%#v url=%#v",
			ctx.Req.RemoteAddr,
			ctx.Req.Host,
			ctx.Req.RequestURI)
		ctx.UserData = time.Now().Unix()
		return req, nil
	})
	proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
		ctx.Logf("Received CONNECT proxy request: "+
			"remote=%#v host=%#v",
			ctx.Req.RemoteAddr,
			host)

		resolved, err := safeResolve("tcp", host)
		if err != nil {
			ctx.Resp = errorResponse(ctx.Req, err)
			return goproxy.RejectConnect, ""
		}
		ctx.UserData = time.Now().Unix()
		logHttpsRequest(ctx, resolved)
		return goproxy.OkConnect, resolved
	})

	proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		logResponse(ctx)
		if resp == nil && ctx.Error != nil {
			resp = errorResponse(ctx.Req, ctx.Error)
		}
		return resp
	})

	return proxy
}

func extractHostname(ctx *goproxy.ProxyCtx) string {
	var hostname string
	if (ctx.Req != nil) {
		hostname, _, _ = net.SplitHostPort(ctx.Req.Host);
	}
	return hostname
}

func logHttpsRequest(ctx *goproxy.ProxyCtx, resolved string) {
	var contentLength int64
	if ctx.Resp != nil {
		contentLength = ctx.Resp.ContentLength
	}
	hostname := extractHostname(ctx)
	from_host, from_port, _ := net.SplitHostPort(ctx.Req.RemoteAddr)
	to_host, to_port, _ := net.SplitHostPort(resolved)
	log.Printf("Received CONNECT request: "+
		"proxy_type=connect src_host=%#v src_port=%s host=%#v dest_ip=%#v dest_port=%s start_time=%#v end_time=%d content_length=%#v\n",
		from_host,
		from_port,
		hostname,
		to_host,
		to_port,
		ctx.UserData,
		time.Now().Unix(),
		// The content length is often -1 because of HTTP chunked encoding. this is normal.
		contentLength,
	)
}

func logResponse(ctx *goproxy.ProxyCtx) {
	var contentLength int64
	if ctx.RoundTrip == nil || ctx.RoundTrip.TCPAddr == nil {
		// Reasons this might happen:
		// 1) private ip destination (eg. 192.168.0.0/16, 10.0.0.0/8, etc)
		// 2) Destination that doesn't respond (eg. i/o timeout)
		// 3) destination domain that doesn't resolve
		// 4) bogus IP address (eg. 1154.218.100.183)
		log.Println("Could not log response: missing IP address")
		return
	}
	if ctx.Resp != nil {
		contentLength = ctx.Resp.ContentLength
	}
	from_host, from_port, _ := net.SplitHostPort(ctx.Req.RemoteAddr)
	hostname := extractHostname(ctx)
	log.Printf("Completed response: "+
		"proxy_type=http src_host=%#v src_port=%s host=%#v dest_ip=%#v dest_port=%d start_time=%#v end_time=%d content_length=%#v\n",
		from_host,
		from_port,
		hostname,
		ctx.RoundTrip.TCPAddr.IP.String(),
		ctx.RoundTrip.TCPAddr.Port,
		ctx.UserData,
		time.Now().Unix(),
		// The content length is often -1 because of HTTP chunked encoding. this is normal.
		contentLength,
	)
}

func findListener(defaultPort int) (net.Listener, error) {
	if einhorn.IsWorker() {
		listener, err := einhorn.GetListener(0)
		if err != nil {
			return nil, err
		}

		err = einhorn.Ack()

		return listener, err
	} else {
		return net.Listen("tcp", fmt.Sprintf(":%d", defaultPort))
	}
}

func main() {
	var port int
	var maintenanceFile string

	flag.IntVar(&port, "port", 4750, "Port to bind on")
	flag.DurationVar(&connectTimeout, "timeout",
		time.Duration(10)*time.Second, "Time to wait while connecting")
	flag.StringVar(&maintenanceFile, "maintenance", "",
		"Flag file for maintenance. chmod to 000 to put into maintenance mode")
	flag.Parse()

	proxy := buildProxy()

	listener, err := findListener(port)
	if err != nil {
		log.Fatal(err)
	}

	kill := make(chan os.Signal, 1)

	var handler http.Handler = proxy
	if maintenanceFile != "" {
		handler = &HealthcheckMiddleware{
			App:             handler,
			MaintenanceFile: maintenanceFile,
		}
	}

	server := graceful.NewServer(&http.Server{
		Handler: handler,
	})
	go func() {
		<-kill
		server.Close()
	}()
	signal.Notify(kill, syscall.SIGUSR2, syscall.SIGTERM)

	err = server.Serve(listener)
	if !strings.HasSuffix(err.Error(), "use of closed network connection") {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/eferro/go-snmpqueries/pkg/snmpquery"
)

const (
	CONTENTION = 4
)

func readQueriesFromStdin(input chan snmpquery.Query) {
	reader := bufio.NewReader(os.Stdin)
	queryId := 0
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			break
		}

		fields := strings.Fields(line)
		if len(fields) != 4 {
			log.Println("InvalidLine", line)
		} else {
			var cmd snmpquery.OpSnmp
			switch fields[0] {
			case "walk":
				cmd = snmpquery.WALK
			case "get":
				cmd = snmpquery.GET
			default:
				log.Println("InvalidLine", line)
				continue
			}

			timeout := time.Duration(2 * time.Second)
			retries := 2

			query := snmpquery.Query{
				Id:          queryId,
				Cmd:         cmd,
				Community:   fields[2],
				Oid:         fields[3],
				Destination: fields[1],
				Timeout:     timeout,
				Retries:     retries,
			}
			input <- query
			queryId += 1
		}
	}
}

func printResults(processed chan snmpquery.Query) {
	for query := range processed {
		fmt.Println("Result", query)
	}
}

func main() {
	input := make(chan snmpquery.Query, 10)
	processed := make(chan snmpquery.Query, 10)

	go readQueriesFromStdin(input)
	go snmpquery.Process(input, processed, CONTENTION)

	printResults(processed)
}
<commit_msg>Process input line with json format<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/eferro/go-snmpqueries/pkg/snmpquery"
)

const (
	CONTENTION = 4
)

type QueryMessage struct {
	Command        string
	Destination    string
	Community      string
	Oid            string
	Timeout        int
	Retries        int
	AdditionalInfo interface{}
}

func readLinesFromStdin(inputLines chan string) {
	reader := bufio.NewReader(os.Stdin)
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			close(inputLines)
			return
		}
		inputLines <- line
	}
}

func readQueriesFromStdin(input chan snmpquery.Query) {

	inputLines := make(chan string, 10)
	go readLinesFromStdin(inputLines)

	queryId := 0
	for line := range inputLines {

		var m QueryMessage
		m.Timeout = 2
		m.Retries = 1

		b := []byte(line)
		err := json.Unmarshal(b, &m)
		if err != nil {
			fmt.Println("Invalid line format", err, line)
		}

		cmd, err := convertCommand(m.Command)
		query := snmpquery.Query{
			Id:          queryId,
			Cmd:         cmd,
			Community:   m.Community,
			Oid:         m.Oid,
			Destination: m.Destination,
			Timeout:     time.Duration(m.Timeout) * time.Second,
			Retries:     m.Retries,
		}
		fmt.Println("AÑADIMOS QUERY", query.Id)
		input <- query
		queryId += 1
	}
}

func convertCommand(command string) (snmpquery.OpSnmp, error) {
	switch command {
	case "walk":
		return snmpquery.WALK, nil
	case "get":
		return snmpquery.GET, nil
	default:
		return 0, fmt.Errorf("Unsupported command %s ", command)
	}
}

func printResults(processed chan snmpquery.Query) {
	for query := range processed {
		fmt.Println("Result", query)
	}
}

func main() {
	input := make(chan snmpquery.Query, 10)
	processed := make(chan snmpquery.Query, 10)

	go readQueriesFromStdin(input)
	go snmpquery.Process(input, processed, CONTENTION)

	printResults(processed)
}
<|endoftext|>


<commit_before>// +build js

package sync

import "github.com/gopherjs/gopherjs/js"

var semWaiters = make(map[*uint32][]chan bool)

// semAwoken tracks the number of waiters awoken by runtime_Semrelease (`ch <- true`)
// that have not yet acquired the semaphore (`<-ch` in runtime_SemacquireMutex).
//
// This prevents a new call to runtime_SemacquireMutex to wrongly acquire the semaphore
// in between (because runtime_Semrelease has already incremented the semaphore while
// all the pending calls to runtime_SemacquireMutex have not yet received from the channel
// and thus decremented the semaphore).
//
// See https://github.com/gopherjs/gopherjs/issues/736.
var semAwoken = make(map[*uint32]uint32)

func runtime_Semacquire(s *uint32) {
	runtime_SemacquireMutex(s, false)
}

// SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
// Mutex profiling is not supported, so just use the same implementation as runtime_Semacquire.
// TODO: Investigate this. If it's possible to implement, consider doing so, otherwise remove this comment.
func runtime_SemacquireMutex(s *uint32, lifo bool) {
	if (*s - semAwoken[s]) == 0 {
		ch := make(chan bool)
		if lifo {
			semWaiters[s] = append([]chan bool{ch}, semWaiters[s]...)
		} else {
			semWaiters[s] = append(semWaiters[s], ch)
		}
		<-ch
		semAwoken[s] -= 1
		if semAwoken[s] == 0 {
			delete(semAwoken, s)
		}
	}
	*s--
}

func runtime_Semrelease(s *uint32, handoff bool) {
	// TODO: Use handoff if needed/possible.
	*s++

	w := semWaiters[s]
	if len(w) == 0 {
		return
	}

	ch := w[0]
	w = w[1:]
	semWaiters[s] = w
	if len(w) == 0 {
		delete(semWaiters, s)
	}

	semAwoken[s] += 1

	ch <- true
}

func runtime_notifyListCheck(size uintptr) {}

func runtime_canSpin(i int) bool {
	return false
}

// Copy of time.runtimeNano.
func runtime_nanotime() int64 {
	const millisecond = 1000000
	return js.Global.Get("Date").New().Call("getTime").Int64() * millisecond
}
<commit_msg>compiler/natives/src/reflect: Implement throw.<commit_after>// +build js

package sync

import "github.com/gopherjs/gopherjs/js"

var semWaiters = make(map[*uint32][]chan bool)

// semAwoken tracks the number of waiters awoken by runtime_Semrelease (`ch <- true`)
// that have not yet acquired the semaphore (`<-ch` in runtime_SemacquireMutex).
//
// This prevents a new call to runtime_SemacquireMutex to wrongly acquire the semaphore
// in between (because runtime_Semrelease has already incremented the semaphore while
// all the pending calls to runtime_SemacquireMutex have not yet received from the channel
// and thus decremented the semaphore).
//
// See https://github.com/gopherjs/gopherjs/issues/736.
var semAwoken = make(map[*uint32]uint32)

func runtime_Semacquire(s *uint32) {
	runtime_SemacquireMutex(s, false)
}

// SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
// Mutex profiling is not supported, so just use the same implementation as runtime_Semacquire.
// TODO: Investigate this. If it's possible to implement, consider doing so, otherwise remove this comment.
func runtime_SemacquireMutex(s *uint32, lifo bool) {
	if (*s - semAwoken[s]) == 0 {
		ch := make(chan bool)
		if lifo {
			semWaiters[s] = append([]chan bool{ch}, semWaiters[s]...)
		} else {
			semWaiters[s] = append(semWaiters[s], ch)
		}
		<-ch
		semAwoken[s] -= 1
		if semAwoken[s] == 0 {
			delete(semAwoken, s)
		}
	}
	*s--
}

func runtime_Semrelease(s *uint32, handoff bool) {
	// TODO: Use handoff if needed/possible.
	*s++

	w := semWaiters[s]
	if len(w) == 0 {
		return
	}

	ch := w[0]
	w = w[1:]
	semWaiters[s] = w
	if len(w) == 0 {
		delete(semWaiters, s)
	}

	semAwoken[s] += 1

	ch <- true
}

func runtime_notifyListCheck(size uintptr) {}

func runtime_canSpin(i int) bool {
	return false
}

// Copy of time.runtimeNano.
func runtime_nanotime() int64 {
	const millisecond = 1000000
	return js.Global.Get("Date").New().Call("getTime").Int64() * millisecond
}

// Implemented in runtime.
func throw(s string) {
	js.Global.Call("$throwRuntimeError", s)
}
<|endoftext|>


<commit_before>package seabird

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

	"bitbucket.org/belak/irc"
)

var diceRe = regexp.MustCompile(`(?:^|\b)(\d*)d(\d+)\b`)

func DiceHandler(c *irc.Client, e *irc.Event) {
	var rolls []string
	totalCount := 0

	matches := diceRe.FindAllStringSubmatch(e.Trailing(), -1)
	for _, match := range matches {
		if len(match) != 3 {
			continue
		}

		// Grab the count, otherwise 1
		count, _ := strconv.Atoi(match[1])

		// Clamp count
		if count < 0 {
			c.MentionReply(e, "You cannot request a negative number of rolls")
			return
		}

		totalCount += count
		if totalCount > 100 {
			c.MentionReply(e, "You cannot request more than 100 dice")
			return
		}

		// How big is the die?
		size, _ := strconv.Atoi(match[2])

		if size > 100 {
			c.MentionReply(e, "You cannot request dice larger than 100")
			return
		}

		// Clamp size
		if size < 1 {
			c.MentionReply(e, "You cannot request a non-positive die size")
			return
		}

		var dice []string
		for i := 0; i < count; i++ {
			dice = append(dice, fmt.Sprintf("%d", rand.Intn(size)+1))
		}

		rolls = append(rolls, fmt.Sprintf("%dd%d: %s", count, size, strings.Join(dice, ", ")))
	}

	if len(rolls) > 0 {
		c.MentionReply(e, "%s", strings.Join(rolls, " "))
	}
}
<commit_msg>Clamp dice roll count to 1<commit_after>package seabird

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

	"bitbucket.org/belak/irc"
)

var diceRe = regexp.MustCompile(`(?:^|\b)(\d*)d(\d+)\b`)

func DiceHandler(c *irc.Client, e *irc.Event) {
	var rolls []string
	totalCount := 0

	matches := diceRe.FindAllStringSubmatch(e.Trailing(), -1)
	for _, match := range matches {
		if len(match) != 3 {
			continue
		}

		// Grab the count, otherwise 1
		count, _ := strconv.Atoi(match[1])
		if count == 0 {
			count = 1
		}

		// Clamp count
		if count < 0 {
			c.MentionReply(e, "You cannot request a negative number of rolls")
			return
		}

		totalCount += count
		if totalCount > 100 {
			c.MentionReply(e, "You cannot request more than 100 dice")
			return
		}

		// How big is the die?
		size, _ := strconv.Atoi(match[2])

		if size > 100 {
			c.MentionReply(e, "You cannot request dice larger than 100")
			return
		}

		// Clamp size
		if size < 1 {
			c.MentionReply(e, "You cannot request a non-positive die size")
			return
		}

		var dice []string
		for i := 0; i < count; i++ {
			dice = append(dice, fmt.Sprintf("%d", rand.Intn(size)+1))
		}

		rolls = append(rolls, fmt.Sprintf("%dd%d: %s", count, size, strings.Join(dice, ", ")))
	}

	if len(rolls) > 0 {
		c.MentionReply(e, "%s", strings.Join(rolls, " "))
	}
}
<|endoftext|>


<commit_before>package root

import (
	"fmt"
	"net/http"
	"time"

	"github.com/bitrise-io/bitrise-webhooks/config"
	"github.com/bitrise-io/bitrise-webhooks/service"
	"github.com/bitrise-io/bitrise-webhooks/version"
)

// RespModel ...
type RespModel struct {
	Message         string `json:"message"`
	Version         string `json:"version"`
	Time            string `json:"time"`
	EnvironmentMode string `json:"environment_mode"`
}

// HTTPHandler ...
func HTTPHandler(w http.ResponseWriter, r *http.Request) {
	resp := RespModel{
		Message:         "Welcome to bitrise-webhooks!",
		Version:         version.VERSION,
		Time:            fmt.Sprintf("%s", time.Now()),
		EnvironmentMode: config.GetServerEnvMode(),
	}

	service.RespondWithSuccessOK(w, resp)
}
<commit_msg>root URL: include link to the official GitHub repo<commit_after>package root

import (
	"fmt"
	"net/http"
	"time"

	"github.com/bitrise-io/bitrise-webhooks/config"
	"github.com/bitrise-io/bitrise-webhooks/service"
	"github.com/bitrise-io/bitrise-webhooks/version"
)

// RespModel ...
type RespModel struct {
	Message         string `json:"message"`
	Version         string `json:"version"`
	Time            string `json:"time"`
	EnvironmentMode string `json:"environment_mode"`
}

// HTTPHandler ...
func HTTPHandler(w http.ResponseWriter, r *http.Request) {
	resp := RespModel{
		Message:         "Welcome to bitrise-webhooks! You can find more information and setup guides at: https://github.com/bitrise-io/bitrise-webhooks",
		Version:         version.VERSION,
		Time:            fmt.Sprintf("%s", time.Now()),
		EnvironmentMode: config.GetServerEnvMode(),
	}

	service.RespondWithSuccessOK(w, resp)
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestCLI(t *testing.T) {
	Convey("Invalid flags should cause an error", t, func() {
		err := app.Run(strings.Split("envetcd -bacon delicious", " "))
		So(err, ShouldNotBeNil)
		So(err.Error(), ShouldEqual, "flag provided but not defined: -bacon")
	})
}

/*
func TestRun__versionFlag(t *testing.T) {
	outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
	cli := &CLI{outStream: outStream, errStream: errStream}
	args := strings.Split("envetcd -version", " ")

	status := cli.Run(args)
	if status != ExitCodeOK {
		t.Errorf("expected %s to eq %s", status, ExitCodeOK)
	}

	expected := fmt.Sprintf("envetcd v%s", Version)
	if !strings.Contains(errStream.String(), expected) {
		t.Errorf("expected %q to eq %q", errStream.String(), expected)
	}
}

func TestRun_parseError(t *testing.T) {
	outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
	cli := &CLI{outStream: outStream, errStream: errStream}
	args := strings.Split("envetcd -bacon delicious", " ")

	status := cli.Run(args)
	if status != ExitCodeParseFlagsError {
		t.Errorf("expected %s to eq %s", status, ExitCodeParseFlagsError)
	}

	expected := "flag provided but not defined: -bacon"
	if !strings.Contains(errStream.String(), expected) {
		t.Fatalf("expected %q to contain %q", errStream.String(), expected)
	}
}

func TestRun_waitFlagError(t *testing.T) {
	outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
	cli := &CLI{outStream: outStream, errStream: errStream}
	args := strings.Split("envetcd -wait=watermelon:bacon", " ")

	status := cli.Run(args)
	if status != ExitCodeParseWaitError {
		t.Errorf("expected %s to eq %s", status, ExitCodeParseWaitError)
	}

	expected := "time: invalid duration watermelon"
	if !strings.Contains(errStream.String(), expected) {
		t.Fatalf("expected %q to contain %q", errStream.String(), expected)
	}
}

func TestRun_onceFlag(t *testing.T) {
	outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
	cli := &CLI{outStream: outStream, errStream: errStream}

	command := "envetcd -etcd demo.consul.io -once global/time sh -c ':'"
	args := strings.Split(command, " ")

	ch := make(chan int, 1)

	go func() {
		ch <- cli.Run(args)
	}()

	select {
	case status := <-ch:
		if status != ExitCodeOK {
			t.Errorf("expected %d to eq %d", status, ExitCodeOK)
			t.Errorf("stderr: %s", errStream.String())
		}
	case <-time.After(5 * time.Second):
		t.Errorf("expected data, but nothing was returned")
	}
}
*/
<commit_msg>start adding some tests<commit_after>package main

import (
	"io/ioutil"
	"os"
	"strings"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func capture(args string) (string, error) {
	stdout := os.Stdout

	r, w, err := os.Pipe()
	if err != nil {
		return "", err
	}

	defer func() {
		w.Close()
		os.Stdout = stdout
	}()

	os.Stdout = w
	err = app.Run(strings.Split(args, " "))
	if err != nil {
		return "", err
	}

	w.Close()
	output, err := ioutil.ReadAll(r)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(output)), nil
}

func TestCLI(t *testing.T) {
	Convey("Command should execute as expected", t, func() {

		Convey("Invalid flags should cause an error", func() {
			_, err := capture("envetcd -shmaltz delicious")
			So(err, ShouldNotBeNil)
			So(err.Error(), ShouldEqual, "flag provided but not defined: -shmaltz")
		})

		Convey("Version should be printed", func() {
			output, err := capture("envetcd --version")
			So(err, ShouldBeNil)
			So(output, ShouldEqual, "envetcd version "+app.Version)
		})
	})
}
<|endoftext|>


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

package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"golang.org/x/crypto/ssh/terminal"
)

type loginScheme struct {
	Name string
	Data map[string]string
}

type login struct {
	scheme *loginScheme
}

func nativeLogin(context *Context, client *Client) error {
	var email string
	if len(context.Args) > 0 {
		email = context.Args[0]
	} else {
		fmt.Fprint(context.Stdout, "Email: ")
		fmt.Fscanf(context.Stdin, "%s\n", &email)
	}
	fmt.Fprint(context.Stdout, "Password: ")
	password, err := passwordFromReader(context.Stdin)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout)
	url, err := GetURL("/users/" + email + "/tokens")
	if err != nil {
		return err
	}
	b := bytes.NewBufferString(`{"password":"` + password + `"}`)
	request, err := http.NewRequest("POST", url, b)
	if err != nil {
		return err
	}
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	result, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	out := make(map[string]interface{})
	err = json.Unmarshal(result, &out)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Successfully logged in!")
	return writeToken(out["token"].(string))
}

func (c *login) getScheme() *loginScheme {
	if c.scheme == nil {
		info, err := schemeInfo()
		if err != nil {
			c.scheme = &loginScheme{Name: "native", Data: make(map[string]string)}
		} else {
			c.scheme = info
		}
	}
	return c.scheme
}

func (c *login) Run(context *Context, client *Client) error {
	if c.getScheme().Name == "oauth" {
		return c.oauthLogin(context, client)
	}
	return nativeLogin(context, client)
}

func (c *login) Info() *Info {
	usage := "login [email]"
	return &Info{
		Name:  "login",
		Usage: usage,
		Desc: `Initiates a new tsuru session for a user. If using tsuru native authentication
scheme, it will ask for the email and the password and check if the user is
successfully authenticated. If using OAuth, it will open a web browser for the
user to complete the login.

After that, the token generated by the tsuru server will be stored in
[[${HOME}/.tsuru_token]].

All tsuru actions require the user to be authenticated (except [[tsuru login]]
and [[tsuru version]]).`,
		MinArgs: 0,
	}
}

type logout struct{}

func (c *logout) Info() *Info {
	return &Info{
		Name:  "logout",
		Usage: "logout",
		Desc: `Logout will delete the token file and terminate the session within tsuru
server.`,
	}
}

func (c *logout) Run(context *Context, client *Client) error {
	if url, err := GetURL("/users/tokens"); err == nil {
		request, _ := http.NewRequest("DELETE", url, nil)
		client.Do(request)
	}
	err := filesystem().Remove(JoinWithUserDir(".tsuru_token"))
	if err != nil && os.IsNotExist(err) {
		return errors.New("You're not logged in!")
	}
	fmt.Fprintln(context.Stdout, "Successfully logged out!")
	return nil
}

func passwordFromReader(reader io.Reader) (string, error) {
	var (
		password []byte
		err      error
	)
	if file, ok := reader.(*os.File); ok && terminal.IsTerminal(int(file.Fd())) {
		password, err = terminal.ReadPassword(int(file.Fd()))
		if err != nil {
			return "", err
		}
	} else {
		fmt.Fscanf(reader, "%s\n", &password)
	}
	if len(password) == 0 {
		msg := "You must provide the password!"
		return "", errors.New(msg)
	}
	return string(password), err
}

func schemeInfo() (*loginScheme, error) {
	url, err := GetURL("/auth/scheme")
	if err != nil {
		return nil, err
	}
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	info := loginScheme{}
	err = json.NewDecoder(resp.Body).Decode(&info)
	if err != nil {
		return nil, err
	}
	return &info, nil
}
<commit_msg>cmd/auth: set output to raw mode in login<commit_after>// Copyright 2015 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"golang.org/x/crypto/ssh/terminal"
)

type loginScheme struct {
	Name string
	Data map[string]string
}

type login struct {
	scheme *loginScheme
}

func nativeLogin(context *Context, client *Client) error {
	var email string
	if len(context.Args) > 0 {
		email = context.Args[0]
	} else {
		fmt.Fprint(context.Stdout, "Email: ")
		fmt.Fscanf(context.Stdin, "%s\n", &email)
	}
	fmt.Fprint(context.Stdout, "Password: ")
	password, err := passwordFromReader(context.Stdin)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout)
	url, err := GetURL("/users/" + email + "/tokens")
	if err != nil {
		return err
	}
	b := bytes.NewBufferString(`{"password":"` + password + `"}`)
	request, err := http.NewRequest("POST", url, b)
	if err != nil {
		return err
	}
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	result, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	out := make(map[string]interface{})
	err = json.Unmarshal(result, &out)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Successfully logged in!")
	return writeToken(out["token"].(string))
}

func (c *login) getScheme() *loginScheme {
	if c.scheme == nil {
		info, err := schemeInfo()
		if err != nil {
			c.scheme = &loginScheme{Name: "native", Data: make(map[string]string)}
		} else {
			c.scheme = info
		}
	}
	return c.scheme
}

func (c *login) Run(context *Context, client *Client) error {
	context.RawOutput()
	if c.getScheme().Name == "oauth" {
		return c.oauthLogin(context, client)
	}
	return nativeLogin(context, client)
}

func (c *login) Info() *Info {
	usage := "login [email]"
	return &Info{
		Name:  "login",
		Usage: usage,
		Desc: `Initiates a new tsuru session for a user. If using tsuru native authentication
scheme, it will ask for the email and the password and check if the user is
successfully authenticated. If using OAuth, it will open a web browser for the
user to complete the login.

After that, the token generated by the tsuru server will be stored in
[[${HOME}/.tsuru_token]].

All tsuru actions require the user to be authenticated (except [[tsuru login]]
and [[tsuru version]]).`,
		MinArgs: 0,
	}
}

type logout struct{}

func (c *logout) Info() *Info {
	return &Info{
		Name:  "logout",
		Usage: "logout",
		Desc: `Logout will delete the token file and terminate the session within tsuru
server.`,
	}
}

func (c *logout) Run(context *Context, client *Client) error {
	if url, err := GetURL("/users/tokens"); err == nil {
		request, _ := http.NewRequest("DELETE", url, nil)
		client.Do(request)
	}
	err := filesystem().Remove(JoinWithUserDir(".tsuru_token"))
	if err != nil && os.IsNotExist(err) {
		return errors.New("You're not logged in!")
	}
	fmt.Fprintln(context.Stdout, "Successfully logged out!")
	return nil
}

func passwordFromReader(reader io.Reader) (string, error) {
	var (
		password []byte
		err      error
	)
	if file, ok := reader.(*os.File); ok && terminal.IsTerminal(int(file.Fd())) {
		password, err = terminal.ReadPassword(int(file.Fd()))
		if err != nil {
			return "", err
		}
	} else {
		fmt.Fscanf(reader, "%s\n", &password)
	}
	if len(password) == 0 {
		msg := "You must provide the password!"
		return "", errors.New(msg)
	}
	return string(password), err
}

func schemeInfo() (*loginScheme, error) {
	url, err := GetURL("/auth/scheme")
	if err != nil {
		return nil, err
	}
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	info := loginScheme{}
	err = json.NewDecoder(resp.Body).Decode(&info)
	if err != nil {
		return nil, err
	}
	return &info, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"github.com/adamdecaf/cert-manage/certs"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
)

// `Find` finds certs for the given platform or application
func Find(app *string, format string) {
	var certificates []*x509.Certificate

	// Find certs for an app
	if app != nil && *app != "" {
		c, err := certs.FindCertsForApplication(*app)
		if err != nil {
			fmt.Printf("error finding certs for application %s\n", err)
			os.Exit(1)
		}
		certificates = c
	} else {
		// Find certs for a platform
		c, err := certs.FindCerts()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		certificates = c
	}

	if format == "table" {
		printCertsInTable(certificates)
	} else {
		// -format raw
		printCertsToStdout(certificates)
	}
}

// IStringSlice is a case-insensitive string sorting implementation
type IStringSlice []string
func (p IStringSlice) Len() int           { return len(p) }
func (p IStringSlice) Less(i, j int) bool { return strings.ToLower(p[i]) < strings.ToLower(p[j]) }
func (p IStringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// printCertsInTable outputs a nicely formatted table of the certs found. This uses golang's
// native text/tabwriter package to align based on the rows given to it.
func printCertsInTable(certs []*x509.Certificate) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	fmt.Fprintln(w, "Subject\tIssuer\tPublic Key Algorithm\tFingerprint\tNot Before\tNot After")
	defer w.Flush()

	rows := make([]string, len(certs))
	for i := range certs {
		ss := sha256.New()
		ss.Write(certs[i].RawSubjectPublicKeyInfo)
		fingerprint := hex.EncodeToString(ss.Sum(nil))

		c1 := certs[i].Subject.CommonName
		c2 := certs[i].Issuer.CommonName
		c3 := stringifyPublicKeyAlgo(certs[i].PublicKeyAlgorithm)
		c4 := fingerprint[:16]

		c5 := certs[i].NotBefore.Format("2006-01-02")
		c6 := certs[i].NotAfter.Format("2006-01-02")

		rows[i] = fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", c1, c2, c3, c4, c5, c6)
	}

	sort.Sort(IStringSlice(rows))
	for i := range rows {
		fmt.Fprintln(w, rows[i])
	}
}

// printCertsToStdout very verbosly prints out the ecah certificate's information
// to stdout. This isn't very useful for machine parsing or small screen displays.
func printCertsToStdout(certs []*x509.Certificate) {
	for i := range certs[:10] {
		ss := sha256.New()
		ss.Write(certs[i].RawSubjectPublicKeyInfo)
		fingerprint := hex.EncodeToString(ss.Sum(nil))

		fmt.Printf("Certificate\n")
		fmt.Printf("  SHA256 Fingerprint - %s\n", fingerprint)
		fmt.Printf("  Signature Algorithm: %s\n", certs[i].SignatureAlgorithm.String())
		fmt.Printf("  Public Key Algorithm - %v\n", stringifyPublicKeyAlgo(certs[i].PublicKeyAlgorithm))
		fmt.Printf("  Issuer CommonName - %s, SerialNumber - %s\n", certs[i].Issuer.CommonName, certs[i].Issuer.SerialNumber)
		fmt.Printf("  Subject CommonName - %s, SerialNumber - %s\n", certs[i].Subject.CommonName, certs[i].Subject.SerialNumber)
		fmt.Printf("  NotBefore - %s, NotAfter - %s\n", certs[i].NotBefore, certs[i].NotAfter)
		fmt.Printf("  IsCA - %t\n", certs[i].IsCA)
		fmt.Printf("  MaxPathLen - %d\n", certs[i].MaxPathLen)

		fmt.Printf("  DNSNames\n")
		for j := range certs[i].DNSNames {
			fmt.Printf("    %s\n", certs[i].DNSNames[j])
		}

		fmt.Printf("  EmailAddresses\n")
		for j := range certs[i].EmailAddresses {
			fmt.Printf("    %s\n", certs[i].EmailAddresses[j])
		}

		fmt.Printf("  IPAddresses\n")
		for j := range certs[i].IPAddresses {
			fmt.Printf("    %s\n", certs[i].IPAddresses[j])
		}

		fmt.Printf("  PermittedDNSDomains\n")
		for j := range certs[i].PermittedDNSDomains {
			fmt.Printf("    %s\n", certs[i].PermittedDNSDomains[j])
		}

		fmt.Printf("  CRLDistributionPoints\n")
		for j := range certs[i].CRLDistributionPoints {
			fmt.Printf("    %s\n", certs[i].CRLDistributionPoints[j])
		}
	}
}

func stringifyPublicKeyAlgo(p x509.PublicKeyAlgorithm) string {
	res := "Unknown"
	switch p {
	case x509.RSA:
		res = "RSA"
	case x509.DSA:
		res = "DSA"
	case x509.ECDSA:
		res = "ECDSA"
	}
	return res
}
<commit_msg>cmd/find: Output all certs in raw format<commit_after>package cmd

import (
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"github.com/adamdecaf/cert-manage/certs"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
)

// `Find` finds certs for the given platform or application
func Find(app *string, format string) {
	var certificates []*x509.Certificate

	// Find certs for an app
	if app != nil && *app != "" {
		c, err := certs.FindCertsForApplication(*app)
		if err != nil {
			fmt.Printf("error finding certs for application %s\n", err)
			os.Exit(1)
		}
		certificates = c
	} else {
		// Find certs for a platform
		c, err := certs.FindCerts()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		certificates = c
	}

	if format == "table" {
		printCertsInTable(certificates)
	} else {
		// -format raw
		printCertsToStdout(certificates)
	}
}

// IStringSlice is a case-insensitive string sorting implementation
type IStringSlice []string
func (p IStringSlice) Len() int           { return len(p) }
func (p IStringSlice) Less(i, j int) bool { return strings.ToLower(p[i]) < strings.ToLower(p[j]) }
func (p IStringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// printCertsInTable outputs a nicely formatted table of the certs found. This uses golang's
// native text/tabwriter package to align based on the rows given to it.
func printCertsInTable(certs []*x509.Certificate) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	fmt.Fprintln(w, "Subject\tIssuer\tPublic Key Algorithm\tFingerprint\tNot Before\tNot After")
	defer w.Flush()

	rows := make([]string, len(certs))
	for i := range certs {
		ss := sha256.New()
		ss.Write(certs[i].RawSubjectPublicKeyInfo)
		fingerprint := hex.EncodeToString(ss.Sum(nil))

		c1 := certs[i].Subject.CommonName
		c2 := certs[i].Issuer.CommonName
		c3 := stringifyPublicKeyAlgo(certs[i].PublicKeyAlgorithm)
		c4 := fingerprint[:16]

		c5 := certs[i].NotBefore.Format("2006-01-02")
		c6 := certs[i].NotAfter.Format("2006-01-02")

		rows[i] = fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", c1, c2, c3, c4, c5, c6)
	}

	sort.Sort(IStringSlice(rows))
	for i := range rows {
		fmt.Fprintln(w, rows[i])
	}
}

// printCertsToStdout very verbosly prints out the ecah certificate's information
// to stdout. This isn't very useful for machine parsing or small screen displays.
func printCertsToStdout(certs []*x509.Certificate) {
	for i := range certs {
		ss := sha256.New()
		ss.Write(certs[i].RawSubjectPublicKeyInfo)
		fingerprint := hex.EncodeToString(ss.Sum(nil))

		fmt.Printf("Certificate\n")
		fmt.Printf("  SHA256 Fingerprint - %s\n", fingerprint)
		fmt.Printf("  Signature Algorithm: %s\n", certs[i].SignatureAlgorithm.String())
		fmt.Printf("  Public Key Algorithm - %v\n", stringifyPublicKeyAlgo(certs[i].PublicKeyAlgorithm))
		fmt.Printf("  Issuer CommonName - %s, SerialNumber - %s\n", certs[i].Issuer.CommonName, certs[i].Issuer.SerialNumber)
		fmt.Printf("  Subject CommonName - %s, SerialNumber - %s\n", certs[i].Subject.CommonName, certs[i].Subject.SerialNumber)
		fmt.Printf("  NotBefore - %s, NotAfter - %s\n", certs[i].NotBefore, certs[i].NotAfter)
		fmt.Printf("  IsCA - %t\n", certs[i].IsCA)
		fmt.Printf("  MaxPathLen - %d\n", certs[i].MaxPathLen)

		fmt.Printf("  DNSNames\n")
		for j := range certs[i].DNSNames {
			fmt.Printf("    %s\n", certs[i].DNSNames[j])
		}

		fmt.Printf("  EmailAddresses\n")
		for j := range certs[i].EmailAddresses {
			fmt.Printf("    %s\n", certs[i].EmailAddresses[j])
		}

		fmt.Printf("  IPAddresses\n")
		for j := range certs[i].IPAddresses {
			fmt.Printf("    %s\n", certs[i].IPAddresses[j])
		}

		fmt.Printf("  PermittedDNSDomains\n")
		for j := range certs[i].PermittedDNSDomains {
			fmt.Printf("    %s\n", certs[i].PermittedDNSDomains[j])
		}

		fmt.Printf("  CRLDistributionPoints\n")
		for j := range certs[i].CRLDistributionPoints {
			fmt.Printf("    %s\n", certs[i].CRLDistributionPoints[j])
		}
	}
}

func stringifyPublicKeyAlgo(p x509.PublicKeyAlgorithm) string {
	res := "Unknown"
	switch p {
	case x509.RSA:
		res = "RSA"
	case x509.DSA:
		res = "DSA"
	case x509.ECDSA:
		res = "ECDSA"
	}
	return res
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net/http"

	"github.com/gilcrest/env"
	"github.com/gilcrest/go-api-basic/server"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

func main() {

	// loglvl flag allows for setting logging level, e.g. to run the server
	// with level set to debug, it'd be: ./server loglvl=debug
	loglvlFlag := flag.String("loglvl", "error", "sets log level")

	// env flag allows for setting environment, e.g. Production, QA, etc.
	// example: env=dev, env=qa, env=stg, env=prod
	envFlag := flag.String("env", "dev", "sets log level")

	flag.Parse()

	// get appropriate zerolog.Level based on flag
	loglevel := logLevel(loglvlFlag)
	log.Log().Msgf("Logging Level set to %s", loglevel)

	// get appropriate env.Name based on flag
	eName := envName(envFlag)
	log.Log().Msgf("Environment set to %s", eName)

	// call constructor for Server struct
	server, err := server.NewServer(eName, loglevel)
	if err != nil {
		log.Fatal().Err(err).Msg("")
	}

	// handle all requests with the Gorilla router
	http.Handle("/", server.Router)

	// ListenAndServe on port 8080, not specifying a particular IP address
	// for this particular implementation
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal().Err(err).Msg("")
	}
}

func logLevel(s *string) zerolog.Level {

	var lvl zerolog.Level

	// dereference the string pointer to get flag value
	ds := *s

	switch ds {
	case "debug":
		lvl = zerolog.DebugLevel
	case "info":
		lvl = zerolog.InfoLevel
	case "warn":
		lvl = zerolog.WarnLevel
	case "fatal":
		lvl = zerolog.FatalLevel
	case "panic":
		lvl = zerolog.PanicLevel
	case "disabled":
		lvl = zerolog.Disabled
	default:
		lvl = zerolog.ErrorLevel
	}
	return lvl
}

func envName(s *string) env.Name {

	var name env.Name

	// dereference the string pointer to get flag value
	ds := *s

	switch ds {
	case "dev":
		name = env.Dev
	case "qa":
		name = env.QA
	case "stg":
		name = env.Staging
	case "prod":
		name = env.Production
	default:
		name = env.Dev
	}
	return name
}
<commit_msg>naming conv update for clarity<commit_after>package main

import (
	"flag"
	"net/http"

	"github.com/gilcrest/env"
	"github.com/gilcrest/go-api-basic/server"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

func main() {

	// loglvl flag allows for setting logging level, e.g. to run the server
	// with level set to debug, it'd be: ./server loglvl=debug
	loglvlFlag := flag.String("loglvl", "error", "sets log level")

	// env flag allows for setting environment, e.g. Production, QA, etc.
	// example: env=dev, env=qa, env=stg, env=prod
	envFlag := flag.String("env", "dev", "sets log level")

	flag.Parse()

	// get appropriate zerolog.Level based on flag
	lvl := logLevel(loglvlFlag)
	log.Log().Msgf("Logging Level set to %s", lvl)

	// get appropriate env.Name based on flag
	eName := envName(envFlag)
	log.Log().Msgf("Environment set to %s", eName)

	// call constructor for Server struct
	server, err := server.NewServer(eName, lvl)
	if err != nil {
		log.Fatal().Err(err).Msg("")
	}

	// handle all requests with the Gorilla router
	http.Handle("/", server.Router)

	// ListenAndServe on port 8080, not specifying a particular IP address
	// for this particular implementation
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal().Err(err).Msg("")
	}
}

func logLevel(s *string) zerolog.Level {

	var lvl zerolog.Level

	// dereference the string pointer to get flag value
	ds := *s

	switch ds {
	case "debug":
		lvl = zerolog.DebugLevel
	case "info":
		lvl = zerolog.InfoLevel
	case "warn":
		lvl = zerolog.WarnLevel
	case "fatal":
		lvl = zerolog.FatalLevel
	case "panic":
		lvl = zerolog.PanicLevel
	case "disabled":
		lvl = zerolog.Disabled
	default:
		lvl = zerolog.ErrorLevel
	}
	return lvl
}

func envName(s *string) env.Name {

	var name env.Name

	// dereference the string pointer to get flag value
	ds := *s

	switch ds {
	case "dev":
		name = env.Dev
	case "qa":
		name = env.QA
	case "stg":
		name = env.Staging
	case "prod":
		name = env.Production
	default:
		name = env.Dev
	}
	return name
}
<|endoftext|>


<commit_before>// Copyright © 2016 Tobias Wellnitz, DH1TW <Tobias.Wellnitz@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"fmt"
	"os"

	"github.com/dh1tw/goSoundbench/mqtt"
	"github.com/dh1tw/goSoundbench/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// mqttCmd represents the mqtt command
var mqttCmd = &cobra.Command{
	Use:   "mqtt",
	Short: "MQTT Server which can execute sound test cases",
	Long:  `MQTT Server which can execute sound test cases`,
	Run: func(cmd *cobra.Command, args []string) {
		MqttServer()
	},
}

func init() {
	serverCmd.AddCommand(mqttCmd)
	mqttCmd.Flags().StringP("url", "u", "localhost", "URL of the MQTT broker")
	mqttCmd.Flags().IntP("port", "p", 1883, "Port of the MQTT broker")
	mqttCmd.Flags().Float64P("samplerate", "s", 48000, "Sampling rate")
	mqttCmd.Flags().IntP("frame-length-input", "i", 24000, "Buffer frame length for recording audio devices")
	mqttCmd.Flags().IntP("frame-length-output", "o", 1024, "Buffer frame length for playing audio devices")
	viper.BindPFlag("mqtt.broker_url", mqttCmd.Flags().Lookup("url"))
	viper.BindPFlag("mqtt.broker_port", mqttCmd.Flags().Lookup("port"))
	viper.BindPFlag("audio.samplingrate", mqttCmd.Flags().Lookup("samplingrate"))
	viper.BindPFlag("audio.frame-length-input", mqttCmd.Flags().Lookup("frame-length-input"))
	viper.BindPFlag("audio.frame-length-output", mqttCmd.Flags().Lookup("frame-length-output"))
}

func MqttServer() {

	mapping := viper.GetStringMapString("topic-device-mapping")
	if len(mapping) == 0 {
		fmt.Println("topic - device map is empty; Check config file")
		os.Exit(-1)
	}

	topics := make([]string, 0, len(mapping))

	for k := range mapping {
		topics = append(topics, k)
	}

	ms := mqttserver.MqttSettings{
		Transport:  "tcp",
		BrokerURL:  viper.GetString("mqtt.broker_url"),
		BrokerPort: viper.GetInt("mqtt.broker_port"),
		ClientID:   utils.RandSeq(10),
		Topics:     topics,
	}

	mqttserver.MqttServer(ms)
}
<commit_msg>fixed viper binding<commit_after>// Copyright © 2016 Tobias Wellnitz, DH1TW <Tobias.Wellnitz@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"fmt"
	"os"

	"github.com/dh1tw/goSoundbench/mqtt"
	"github.com/dh1tw/goSoundbench/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// mqttCmd represents the mqtt command
var mqttCmd = &cobra.Command{
	Use:   "mqtt",
	Short: "MQTT Server which can execute sound test cases",
	Long:  `MQTT Server which can execute sound test cases`,
	Run: func(cmd *cobra.Command, args []string) {
		MqttServer()
	},
}

func init() {
	serverCmd.AddCommand(mqttCmd)
	mqttCmd.Flags().StringP("url", "u", "localhost", "URL of the MQTT broker")
	mqttCmd.Flags().IntP("port", "p", 1883, "Port of the MQTT broker")
	mqttCmd.Flags().Float64P("samplerate", "s", 48000, "Sampling rate")
	mqttCmd.Flags().IntP("frame-length-input", "i", 24000, "Buffer frame length for recording audio devices")
	mqttCmd.Flags().IntP("frame-length-output", "o", 1024, "Buffer frame length for playing audio devices")
	viper.BindPFlag("mqtt.broker-url", mqttCmd.Flags().Lookup("url"))
	viper.BindPFlag("mqtt.broker-port", mqttCmd.Flags().Lookup("port"))
	viper.BindPFlag("audio.samplingrate", mqttCmd.Flags().Lookup("samplingrate"))
	viper.BindPFlag("audio.frame-length-input", mqttCmd.Flags().Lookup("frame-length-input"))
	viper.BindPFlag("audio.frame-length-output", mqttCmd.Flags().Lookup("frame-length-output"))
}

func MqttServer() {

	mapping := viper.GetStringMapString("topic-device-mapping")
	if len(mapping) == 0 {
		fmt.Println("topic - device map is empty; Check config file")
		os.Exit(-1)
	}

	topics := make([]string, 0, len(mapping))

	for k := range mapping {
		topics = append(topics, k)
	}

	ms := mqttserver.MqttSettings{
		Transport:  "tcp",
		BrokerURL:  viper.GetString("mqtt.broker_url"),
		BrokerPort: viper.GetInt("mqtt.broker_port"),
		ClientID:   utils.RandSeq(10),
		Topics:     topics,
	}

	mqttserver.MqttServer(ms)
}
<|endoftext|>


<commit_before>package spnego

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"

	"gopkg.in/jcmturner/goidentity.v3"
	"gopkg.in/jcmturner/gokrb5.v7/client"
	"gopkg.in/jcmturner/gokrb5.v7/gssapi"
	"gopkg.in/jcmturner/gokrb5.v7/keytab"
	"gopkg.in/jcmturner/gokrb5.v7/krberror"
	"gopkg.in/jcmturner/gokrb5.v7/service"
	"gopkg.in/jcmturner/gokrb5.v7/types"
)

// Client side functionality //

// Client will negotiate authentication with a server using SPNEGO.
type Client struct {
	*http.Client
	krb5Client *client.Client
	spn        string
	reqs       []*http.Request
}

type redirectErr struct {
	reqTarget *http.Request
}

func (e redirectErr) Error() string {
	return fmt.Sprintf("redirect to %v", e.reqTarget.URL)
}

// NewClient returns an SPNEGO enabled HTTP client.
func NewClient(krb5Cl *client.Client, httpCl *http.Client, spn string) *Client {
	if httpCl == nil {
		httpCl = http.DefaultClient
	}
	// Add a cookie jar if there isn't one
	if httpCl.Jar == nil {
		httpCl.Jar, _ = cookiejar.New(nil)
	}
	// Add a CheckRedirect function that will execute any functional already defined and then remove
	f := httpCl.CheckRedirect
	httpCl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if f != nil {
			err := f(req, via)
			if err != nil {
				return err
			}
		}
		return redirectErr{reqTarget: req}
	}
	return &Client{
		Client:     httpCl,
		krb5Client: krb5Cl,
		spn:        spn,
	}
}

// Do is the SPNEGO enabled HTTP client's equivalent of the http.Client's Do method.
func (c *Client) Do(req *http.Request) (resp *http.Response, err error) {
	resp, err = c.Client.Do(req)
	if err != nil {
		if ue, ok := err.(*url.Error); ok {
			if e, ok := ue.Err.(redirectErr); ok {
				e.reqTarget.Header.Del(HTTPHeaderAuthRequest)
				c.reqs = append(c.reqs, e.reqTarget)
				if len(c.reqs) >= 10 {
					return resp, errors.New("stopped after 10 redirects")
				}
				return c.Do(e.reqTarget)
			}
			return resp, err
		}
	}
	if respUnauthorizedNegotiate(resp) {
		err := SetSPNEGOHeader(c.krb5Client, req, c.spn)
		if err != nil {
			return resp, err
		}
		return c.Do(req)
	}
	return resp, err
}

// Get is the SPNEGO enabled HTTP client's equivalent of the http.Client's Get method.
func (c *Client) Get(url string) (resp *http.Response, err error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

// Post is the SPNEGO enabled HTTP client's equivalent of the http.Client's Post method.
func (c *Client) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) {
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", contentType)
	return c.Do(req)
}

// PostForm is the SPNEGO enabled HTTP client's equivalent of the http.Client's PostForm method.
func (c *Client) PostForm(url string, data url.Values) (resp *http.Response, err error) {
	return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

// Head is the SPNEGO enabled HTTP client's equivalent of the http.Client's Head method.
func (c *Client) Head(url string) (resp *http.Response, err error) {
	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

func respUnauthorizedNegotiate(resp *http.Response) bool {
	if resp.StatusCode == http.StatusUnauthorized {
		if resp.Header.Get(HTTPHeaderAuthResponse) == HTTPHeaderAuthResponseValueKey {
			return true
		}
	}
	return false
}

// SetSPNEGOHeader gets the service ticket and sets it as the SPNEGO authorization header on HTTP request object.
// To auto generate the SPN from the request object pass a null string "".
func SetSPNEGOHeader(cl *client.Client, r *http.Request, spn string) error {
	if spn == "" {
		spn = "HTTP/" + strings.SplitN(r.Host, ":", 2)[0]
	}
	s := SPNEGOClient(cl, spn)
	err := s.AcquireCred()
	if err != nil {
		return fmt.Errorf("could not acquire client credenital: %v", err)
	}
	st, err := s.InitSecContext()
	if err != nil {
		return fmt.Errorf("could not initialize context: %v", err)
	}
	nb, err := st.Marshal()
	if err != nil {
		return krberror.Errorf(err, krberror.EncodingError, "could not marshal SPNEGO")
	}
	hs := "Negotiate " + base64.StdEncoding.EncodeToString(nb)
	r.Header.Set(HTTPHeaderAuthRequest, hs)
	return nil
}

// Service side functionality //

type ctxKey string

const (
	// spnegoNegTokenRespKRBAcceptCompleted - The response on successful authentication always has this header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespKRBAcceptCompleted = "Negotiate oRQwEqADCgEAoQsGCSqGSIb3EgECAg=="
	// spnegoNegTokenRespReject - The response on a failed authentication always has this rejection header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespReject = "Negotiate oQcwBaADCgEC"
	// spnegoNegTokenRespIncompleteKRB5 - Response token specifying incomplete context and KRB5 as the supported mechtype.
	spnegoNegTokenRespIncompleteKRB5 = "Negotiate oRQwEqADCgEBoQsGCSqGSIb3EgECAg=="
	// CTXKeyAuthenticated is the request context key holding a boolean indicating if the request has been authenticated.
	CTXKeyAuthenticated ctxKey = "github.com/jcmturner/gokrb5/CTXKeyAuthenticated"
	// CTXKeyCredentials is the request context key holding the credentials gopkg.in/jcmturner/goidentity.v2/Identity object.
	CTXKeyCredentials ctxKey = "github.com/jcmturner/gokrb5/CTXKeyCredentials"
	// HTTPHeaderAuthRequest is the header that will hold authn/z information.
	HTTPHeaderAuthRequest = "Authorization"
	// HTTPHeaderAuthResponse is the header that will hold SPNEGO data from the server.
	HTTPHeaderAuthResponse = "WWW-Authenticate"
	// HTTPHeaderAuthResponseValueKey is the key in the auth header for SPNEGO.
	HTTPHeaderAuthResponseValueKey = "Negotiate"
	// UnauthorizedMsg is the message returned in the body when authentication fails.
	UnauthorizedMsg = "Unauthorised.\n"
)

// SPNEGOKRB5Authenticate is a Kerberos SPNEGO authentication HTTP handler wrapper.
func SPNEGOKRB5Authenticate(inner http.Handler, kt *keytab.Keytab, settings ...func(*service.Settings)) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Get the auth header
		s := strings.SplitN(r.Header.Get(HTTPHeaderAuthRequest), " ", 2)
		if len(s) != 2 || s[0] != HTTPHeaderAuthResponseValueKey {
			// No Authorization header set so return 401 with WWW-Authenticate Negotiate header
			w.Header().Set(HTTPHeaderAuthResponse, HTTPHeaderAuthResponseValueKey)
			http.Error(w, UnauthorizedMsg, http.StatusUnauthorized)
			return
		}

		// Set up the SPNEGO GSS-API mechanism
		var spnego *SPNEGO
		h, err := types.GetHostAddress(r.RemoteAddr)
		if err == nil {
			// put in this order so that if the user provides a ClientAddress it will override the one here.
			o := append([]func(*service.Settings){service.ClientAddress(h)}, settings...)
			spnego = SPNEGOService(kt, o...)
		} else {
			spnego = SPNEGOService(kt, settings...)
			spnego.Log("%s - SPNEGO could not parse client address: %v", r.RemoteAddr, err)
		}

		// Decode the header into an SPNEGO context token
		b, err := base64.StdEncoding.DecodeString(s[1])
		if err != nil {
			spnegoNegotiateKRB5MechType(spnego, w, "%s - SPNEGO error in base64 decoding negotiation header: %v", r.RemoteAddr, err)
		}
		var st SPNEGOToken
		err = st.Unmarshal(b)
		if err != nil {
			spnegoNegotiateKRB5MechType(spnego, w, "%s - SPNEGO error in unmarshaling SPNEGO token: %v", r.RemoteAddr, err)
		}

		// Validate the context token
		authed, ctx, status := spnego.AcceptSecContext(&st)
		if status.Code != gssapi.StatusComplete && status.Code != gssapi.StatusContinueNeeded {
			spnegoResponseReject(spnego, w, "%s - SPNEGO validation error: %v", r.RemoteAddr, status)
		}
		if status.Code == gssapi.StatusContinueNeeded {
			spnegoNegotiateKRB5MechType(spnego, w, "%s - SPNEGO GSS-API continue needed", r.RemoteAddr)
		}
		if authed {
			id := ctx.Value(CTXKeyCredentials).(goidentity.Identity)
			context.WithValue(r.Context(), CTXKeyCredentials, id)
			context.WithValue(r.Context(), CTXKeyAuthenticated, ctx.Value(CTXKeyAuthenticated))
			spnegoResponseAcceptCompleted(spnego, w, "%s %s@%s - SPNEGO authentication succeeded", r.RemoteAddr, id.UserName(), id.Domain())
			inner.ServeHTTP(w, r.WithContext(ctx))
		} else {
			spnegoResponseReject(spnego, w, "%s - SPNEGO Kerberos authentication failed", r.RemoteAddr)
		}
		return
	})
}

func spnegoNegotiateKRB5MechType(s *SPNEGO, w http.ResponseWriter, format string, v ...interface{}) {
	s.Log(format, v...)
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespIncompleteKRB5)
	http.Error(w, UnauthorizedMsg, http.StatusUnauthorized)
}

func spnegoResponseReject(s *SPNEGO, w http.ResponseWriter, format string, v ...interface{}) {
	s.Log(format, v...)
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespReject)
	http.Error(w, UnauthorizedMsg, http.StatusUnauthorized)
}

func spnegoResponseAcceptCompleted(s *SPNEGO, w http.ResponseWriter, format string, v ...interface{}) {
	s.Log(format, v...)
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespKRBAcceptCompleted)
}
<commit_msg>missed err handle<commit_after>package spnego

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"

	"gopkg.in/jcmturner/goidentity.v3"
	"gopkg.in/jcmturner/gokrb5.v7/client"
	"gopkg.in/jcmturner/gokrb5.v7/gssapi"
	"gopkg.in/jcmturner/gokrb5.v7/keytab"
	"gopkg.in/jcmturner/gokrb5.v7/krberror"
	"gopkg.in/jcmturner/gokrb5.v7/service"
	"gopkg.in/jcmturner/gokrb5.v7/types"
)

// Client side functionality //

// Client will negotiate authentication with a server using SPNEGO.
type Client struct {
	*http.Client
	krb5Client *client.Client
	spn        string
	reqs       []*http.Request
}

type redirectErr struct {
	reqTarget *http.Request
}

func (e redirectErr) Error() string {
	return fmt.Sprintf("redirect to %v", e.reqTarget.URL)
}

// NewClient returns an SPNEGO enabled HTTP client.
func NewClient(krb5Cl *client.Client, httpCl *http.Client, spn string) *Client {
	if httpCl == nil {
		httpCl = http.DefaultClient
	}
	// Add a cookie jar if there isn't one
	if httpCl.Jar == nil {
		httpCl.Jar, _ = cookiejar.New(nil)
	}
	// Add a CheckRedirect function that will execute any functional already defined and then error with a redirectErr
	f := httpCl.CheckRedirect
	httpCl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if f != nil {
			err := f(req, via)
			if err != nil {
				return err
			}
		}
		return redirectErr{reqTarget: req}
	}
	return &Client{
		Client:     httpCl,
		krb5Client: krb5Cl,
		spn:        spn,
	}
}

// Do is the SPNEGO enabled HTTP client's equivalent of the http.Client's Do method.
func (c *Client) Do(req *http.Request) (resp *http.Response, err error) {
	resp, err = c.Client.Do(req)
	if err != nil {
		if ue, ok := err.(*url.Error); ok {
			if e, ok := ue.Err.(redirectErr); ok {
				// Picked up a redirect
				e.reqTarget.Header.Del(HTTPHeaderAuthRequest)
				c.reqs = append(c.reqs, e.reqTarget)
				if len(c.reqs) >= 10 {
					return resp, errors.New("stopped after 10 redirects")
				}
				return c.Do(e.reqTarget)
			}
		}
		return resp, err
	}
	if respUnauthorizedNegotiate(resp) {
		err := SetSPNEGOHeader(c.krb5Client, req, c.spn)
		if err != nil {
			return resp, err
		}
		return c.Do(req)
	}
	return resp, err
}

// Get is the SPNEGO enabled HTTP client's equivalent of the http.Client's Get method.
func (c *Client) Get(url string) (resp *http.Response, err error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

// Post is the SPNEGO enabled HTTP client's equivalent of the http.Client's Post method.
func (c *Client) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) {
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", contentType)
	return c.Do(req)
}

// PostForm is the SPNEGO enabled HTTP client's equivalent of the http.Client's PostForm method.
func (c *Client) PostForm(url string, data url.Values) (resp *http.Response, err error) {
	return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

// Head is the SPNEGO enabled HTTP client's equivalent of the http.Client's Head method.
func (c *Client) Head(url string) (resp *http.Response, err error) {
	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

func respUnauthorizedNegotiate(resp *http.Response) bool {
	if resp.StatusCode == http.StatusUnauthorized {
		if resp.Header.Get(HTTPHeaderAuthResponse) == HTTPHeaderAuthResponseValueKey {
			return true
		}
	}
	return false
}

// SetSPNEGOHeader gets the service ticket and sets it as the SPNEGO authorization header on HTTP request object.
// To auto generate the SPN from the request object pass a null string "".
func SetSPNEGOHeader(cl *client.Client, r *http.Request, spn string) error {
	if spn == "" {
		spn = "HTTP/" + strings.SplitN(r.Host, ":", 2)[0]
	}
	s := SPNEGOClient(cl, spn)
	err := s.AcquireCred()
	if err != nil {
		return fmt.Errorf("could not acquire client credenital: %v", err)
	}
	st, err := s.InitSecContext()
	if err != nil {
		return fmt.Errorf("could not initialize context: %v", err)
	}
	nb, err := st.Marshal()
	if err != nil {
		return krberror.Errorf(err, krberror.EncodingError, "could not marshal SPNEGO")
	}
	hs := "Negotiate " + base64.StdEncoding.EncodeToString(nb)
	r.Header.Set(HTTPHeaderAuthRequest, hs)
	return nil
}

// Service side functionality //

type ctxKey string

const (
	// spnegoNegTokenRespKRBAcceptCompleted - The response on successful authentication always has this header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespKRBAcceptCompleted = "Negotiate oRQwEqADCgEAoQsGCSqGSIb3EgECAg=="
	// spnegoNegTokenRespReject - The response on a failed authentication always has this rejection header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespReject = "Negotiate oQcwBaADCgEC"
	// spnegoNegTokenRespIncompleteKRB5 - Response token specifying incomplete context and KRB5 as the supported mechtype.
	spnegoNegTokenRespIncompleteKRB5 = "Negotiate oRQwEqADCgEBoQsGCSqGSIb3EgECAg=="
	// CTXKeyAuthenticated is the request context key holding a boolean indicating if the request has been authenticated.
	CTXKeyAuthenticated ctxKey = "github.com/jcmturner/gokrb5/CTXKeyAuthenticated"
	// CTXKeyCredentials is the request context key holding the credentials gopkg.in/jcmturner/goidentity.v2/Identity object.
	CTXKeyCredentials ctxKey = "github.com/jcmturner/gokrb5/CTXKeyCredentials"
	// HTTPHeaderAuthRequest is the header that will hold authn/z information.
	HTTPHeaderAuthRequest = "Authorization"
	// HTTPHeaderAuthResponse is the header that will hold SPNEGO data from the server.
	HTTPHeaderAuthResponse = "WWW-Authenticate"
	// HTTPHeaderAuthResponseValueKey is the key in the auth header for SPNEGO.
	HTTPHeaderAuthResponseValueKey = "Negotiate"
	// UnauthorizedMsg is the message returned in the body when authentication fails.
	UnauthorizedMsg = "Unauthorised.\n"
)

// SPNEGOKRB5Authenticate is a Kerberos SPNEGO authentication HTTP handler wrapper.
func SPNEGOKRB5Authenticate(inner http.Handler, kt *keytab.Keytab, settings ...func(*service.Settings)) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Get the auth header
		s := strings.SplitN(r.Header.Get(HTTPHeaderAuthRequest), " ", 2)
		if len(s) != 2 || s[0] != HTTPHeaderAuthResponseValueKey {
			// No Authorization header set so return 401 with WWW-Authenticate Negotiate header
			w.Header().Set(HTTPHeaderAuthResponse, HTTPHeaderAuthResponseValueKey)
			http.Error(w, UnauthorizedMsg, http.StatusUnauthorized)
			return
		}

		// Set up the SPNEGO GSS-API mechanism
		var spnego *SPNEGO
		h, err := types.GetHostAddress(r.RemoteAddr)
		if err == nil {
			// put in this order so that if the user provides a ClientAddress it will override the one here.
			o := append([]func(*service.Settings){service.ClientAddress(h)}, settings...)
			spnego = SPNEGOService(kt, o...)
		} else {
			spnego = SPNEGOService(kt, settings...)
			spnego.Log("%s - SPNEGO could not parse client address: %v", r.RemoteAddr, err)
		}

		// Decode the header into an SPNEGO context token
		b, err := base64.StdEncoding.DecodeString(s[1])
		if err != nil {
			spnegoNegotiateKRB5MechType(spnego, w, "%s - SPNEGO error in base64 decoding negotiation header: %v", r.RemoteAddr, err)
		}
		var st SPNEGOToken
		err = st.Unmarshal(b)
		if err != nil {
			spnegoNegotiateKRB5MechType(spnego, w, "%s - SPNEGO error in unmarshaling SPNEGO token: %v", r.RemoteAddr, err)
		}

		// Validate the context token
		authed, ctx, status := spnego.AcceptSecContext(&st)
		if status.Code != gssapi.StatusComplete && status.Code != gssapi.StatusContinueNeeded {
			spnegoResponseReject(spnego, w, "%s - SPNEGO validation error: %v", r.RemoteAddr, status)
		}
		if status.Code == gssapi.StatusContinueNeeded {
			spnegoNegotiateKRB5MechType(spnego, w, "%s - SPNEGO GSS-API continue needed", r.RemoteAddr)
		}
		if authed {
			id := ctx.Value(CTXKeyCredentials).(goidentity.Identity)
			context.WithValue(r.Context(), CTXKeyCredentials, id)
			context.WithValue(r.Context(), CTXKeyAuthenticated, ctx.Value(CTXKeyAuthenticated))
			spnegoResponseAcceptCompleted(spnego, w, "%s %s@%s - SPNEGO authentication succeeded", r.RemoteAddr, id.UserName(), id.Domain())
			inner.ServeHTTP(w, r.WithContext(ctx))
		} else {
			spnegoResponseReject(spnego, w, "%s - SPNEGO Kerberos authentication failed", r.RemoteAddr)
		}
		return
	})
}

func spnegoNegotiateKRB5MechType(s *SPNEGO, w http.ResponseWriter, format string, v ...interface{}) {
	s.Log(format, v...)
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespIncompleteKRB5)
	http.Error(w, UnauthorizedMsg, http.StatusUnauthorized)
}

func spnegoResponseReject(s *SPNEGO, w http.ResponseWriter, format string, v ...interface{}) {
	s.Log(format, v...)
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespReject)
	http.Error(w, UnauthorizedMsg, http.StatusUnauthorized)
}

func spnegoResponseAcceptCompleted(s *SPNEGO, w http.ResponseWriter, format string, v ...interface{}) {
	s.Log(format, v...)
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespKRBAcceptCompleted)
}
<|endoftext|>