<commit_before>// Copyright © 2017 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package statsd

import (
	"bytes"
	"strconv"
	"strings"

	"github.com/circonus-labs/circonus-agent/internal/config"
	"github.com/circonus-labs/circonus-agent/internal/tags"
	cgm "github.com/circonus-labs/circonus-gometrics/v3"
	"github.com/maier/go-appstats"
	"github.com/pkg/errors"
)

// processPacket parses a packet for metrics
func (s *Server) processPacket(pkt []byte) error {
	if len(pkt) == 0 {
		return nil
	}

	s.logger.Debug().Str("packet", string(pkt)).Msg("received")
	metrics := bytes.Split(pkt, []byte("\n"))
	for _, metric := range metrics {
		if err := s.parseMetric(string(metric)); err != nil {
			appstats.IncrementInt("statsd_metrics_bad")
			s.logger.Warn().Err(err).Str("metric", string(metric)).Msg("parsing")
		}
	}

	return nil
}

// getMetricDestination determines "where" a metric should be sent (host or group)
// and cleans up the metric name if it matches a host|group prefix
func (s *Server) getMetricDestination(metricName string) (string, string) {
	if s.hostPrefix == "" && s.groupPrefix == "" { // no host/group prefixes - send all metrics to host
		return destHost, metricName
	}

	if s.hostPrefix != "" && s.groupPrefix != "" { // explicit host and group, otherwise ignore
		if strings.HasPrefix(metricName, s.hostPrefix) {
			return destHost, strings.Replace(metricName, s.hostPrefix, "", 1)
		}
		if strings.HasPrefix(metricName, s.groupPrefix) {
			return destGroup, strings.Replace(metricName, s.groupPrefix, "", 1)
		}
		s.logger.Debug().Str("metric_name", metricName).Msg("does not match host|group prefix, ignoring")
		return destIgnore, metricName
	}

	if s.groupPrefix != "" && s.hostPrefix == "" { // default to host
		if strings.HasPrefix(metricName, s.groupPrefix) {
			return destGroup, strings.Replace(metricName, s.groupPrefix, "", 1)
		}
		return destHost, metricName
	}

	if s.groupPrefix == "" && s.hostPrefix != "" { // default to group
		if strings.HasPrefix(metricName, s.hostPrefix) {
			return destHost, strings.Replace(metricName, s.hostPrefix, "", 1)
		}
		return destGroup, metricName
	}

	s.logger.Debug().Str("metric_name", metricName).Msg("does not match host|group criteria, ignoring")
	return destIgnore, metricName
}

func (s *Server) parseMetric(metric string) error {
	// ignore 'blank' lines/empty strings
	if len(metric) == 0 {
		return nil
	}

	metricName := ""
	metricType := ""
	metricValue := ""
	metricRate := ""
	sampleRate := 0.0
	metricTagSpec := ""

	if !s.metricRegex.MatchString(metric) {
		return errors.Errorf("invalid metric format '%s', ignoring", metric)
	}

	for _, match := range s.metricRegex.FindAllStringSubmatch(metric, -1) {
		for gIdx, matchVal := range match {
			switch s.metricRegexGroupNames[gIdx] {
			case "name":
				metricName = matchVal
			case "type":
				metricType = matchVal
			case "value":
				metricValue = matchVal
			case "sample":
				metricRate = matchVal
			case "tags":
				metricTagSpec = matchVal
			default:
				// ignore any other groups
			}
		}
	}

	if metricName == "" || metricValue == "" {
		return errors.Errorf("empty metric name (%s) or metric value (%s) - metricRegex failed, check", metricName, metricValue)
	}

	if metricRate != "" {
		r, err := strconv.ParseFloat(metricRate, 32)
		if err != nil {
			return errors.Errorf("invalid metric sampling rate (%s), ignoring", err)
		}
		sampleRate = r
	}

	var (
		dest       *cgm.CirconusMetrics
		metricDest string
	)
	metricDest, metricName = s.getMetricDestination(metricName)

	if metricDest == destGroup {
		dest = s.groupMetrics
	} else if metricDest == destHost {
		dest = s.hostMetrics
		metricName = s.hostCategory + config.MetricNameSeparator + metricName
	}

	if dest == nil {
		return errors.Errorf("invalid metric destination (%s)->(%s)", metric, metricDest)
	}

	// add stream tags to metric name
	metricTagList := []string{}
	if metricTagSpec != "" {
		metricTagList = strings.Split(metricTagSpec, tags.Separator)
	}
	tagList := make([]string, 0, len(s.baseTags)+len(metricTagList))
	tagList = append(tagList, s.baseTags...)
	tagList = append(tagList, metricTagList...)
	metricTags := tags.FromList(metricTagList)

	switch metricType {
	case "c": // counter
		v, err := strconv.ParseUint(metricValue, 10, 64)
		if err != nil {
			return errors.Wrap(err, "invalid counter value")
		}
		if v == 0 {
			v = 1
		}
		if sampleRate > 0 {
			v = uint64(float64(v) * (1 / sampleRate))
		}
		dest.IncrementByValueWithTags(metricName, metricTags, v)
	case "g": // gauge
		if strings.Contains(metricValue, ".") {
			v, err := strconv.ParseFloat(metricValue, 64)
			if err != nil {
				return errors.Wrap(err, "invalid gauge value")
			}
			dest.GaugeWithTags(metricName, metricTags, v)
		} else if strings.Contains(metricValue, "-") {
			v, err := strconv.ParseInt(metricValue, 10, 64)
			if err != nil {
				return errors.Wrap(err, "invalid gauge value")
			}
			dest.GaugeWithTags(metricName, metricTags, v)
		} else {
			v, err := strconv.ParseUint(metricValue, 10, 64)
			if err != nil {
				return errors.Wrap(err, "invalid gauge value")
			}
			dest.GaugeWithTags(metricName, metricTags, v)
		}
	case "h": // histogram (circonus)
		fallthrough
	case "ms": // measurement
		v, err := strconv.ParseFloat(metricValue, 64)
		if err != nil {
			return errors.Wrap(err, "invalid histogram value")
		}
		if sampleRate > 0 {
			v /= sampleRate
		}
		dest.RecordValueWithTags(metricName, metricTags, v)
	case "s": // set
		// in the case of sets, the value is the unique "thing" to be tracked
		// counters are used to track individual "things"
		dest.IncrementWithTags(strings.Join([]string{metricName, metricValue}, config.MetricNameSeparator), metricTags)
	case "t": // text (circonus)
		dest.SetTextWithTags(metricName, metricTags, metricValue)
	default:
		return errors.Errorf("invalid metric type (%s)", metricType)
	}

	s.logger.Debug().
		Str("destination", metricDest).
		Str("metric", metric).
		Str("name", metricName).
		Str("type", metricType).
		Str("value", metricValue).
		Msg("parsing")

	return nil
}
<commit_msg>fix: statsd counter incorrectly setting 0 values to 1<commit_after>// Copyright © 2017 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package statsd

import (
	"bytes"
	"strconv"
	"strings"

	"github.com/circonus-labs/circonus-agent/internal/config"
	"github.com/circonus-labs/circonus-agent/internal/tags"
	cgm "github.com/circonus-labs/circonus-gometrics/v3"
	"github.com/maier/go-appstats"
	"github.com/pkg/errors"
)

// processPacket parses a packet for metrics
func (s *Server) processPacket(pkt []byte) error {
	if len(pkt) == 0 {
		return nil
	}

	s.logger.Debug().Str("packet", string(pkt)).Msg("received")
	metrics := bytes.Split(pkt, []byte("\n"))
	for _, metric := range metrics {
		if err := s.parseMetric(string(metric)); err != nil {
			appstats.IncrementInt("statsd_metrics_bad")
			s.logger.Warn().Err(err).Str("metric", string(metric)).Msg("parsing")
		}
	}

	return nil
}

// getMetricDestination determines "where" a metric should be sent (host or group)
// and cleans up the metric name if it matches a host|group prefix
func (s *Server) getMetricDestination(metricName string) (string, string) {
	if s.hostPrefix == "" && s.groupPrefix == "" { // no host/group prefixes - send all metrics to host
		return destHost, metricName
	}

	if s.hostPrefix != "" && s.groupPrefix != "" { // explicit host and group, otherwise ignore
		if strings.HasPrefix(metricName, s.hostPrefix) {
			return destHost, strings.Replace(metricName, s.hostPrefix, "", 1)
		}
		if strings.HasPrefix(metricName, s.groupPrefix) {
			return destGroup, strings.Replace(metricName, s.groupPrefix, "", 1)
		}
		s.logger.Debug().Str("metric_name", metricName).Msg("does not match host|group prefix, ignoring")
		return destIgnore, metricName
	}

	if s.groupPrefix != "" && s.hostPrefix == "" { // default to host
		if strings.HasPrefix(metricName, s.groupPrefix) {
			return destGroup, strings.Replace(metricName, s.groupPrefix, "", 1)
		}
		return destHost, metricName
	}

	if s.groupPrefix == "" && s.hostPrefix != "" { // default to group
		if strings.HasPrefix(metricName, s.hostPrefix) {
			return destHost, strings.Replace(metricName, s.hostPrefix, "", 1)
		}
		return destGroup, metricName
	}

	s.logger.Debug().Str("metric_name", metricName).Msg("does not match host|group criteria, ignoring")
	return destIgnore, metricName
}

func (s *Server) parseMetric(metric string) error {
	// ignore 'blank' lines/empty strings
	if len(metric) == 0 {
		return nil
	}

	metricName := ""
	metricType := ""
	metricValue := ""
	metricRate := ""
	sampleRate := 0.0
	metricTagSpec := ""

	if !s.metricRegex.MatchString(metric) {
		return errors.Errorf("invalid metric format '%s', ignoring", metric)
	}

	for _, match := range s.metricRegex.FindAllStringSubmatch(metric, -1) {
		for gIdx, matchVal := range match {
			switch s.metricRegexGroupNames[gIdx] {
			case "name":
				metricName = matchVal
			case "type":
				metricType = matchVal
			case "value":
				metricValue = matchVal
			case "sample":
				metricRate = matchVal
			case "tags":
				metricTagSpec = matchVal
			default:
				// ignore any other groups
			}
		}
	}

	if metricName == "" || metricValue == "" {
		return errors.Errorf("empty metric name (%s) or metric value (%s) - metricRegex failed, check", metricName, metricValue)
	}

	if metricRate != "" {
		r, err := strconv.ParseFloat(metricRate, 32)
		if err != nil {
			return errors.Errorf("invalid metric sampling rate (%s), ignoring", err)
		}
		sampleRate = r
	}

	var (
		dest       *cgm.CirconusMetrics
		metricDest string
	)
	metricDest, metricName = s.getMetricDestination(metricName)

	if metricDest == destGroup {
		dest = s.groupMetrics
	} else if metricDest == destHost {
		dest = s.hostMetrics
		metricName = s.hostCategory + config.MetricNameSeparator + metricName
	}

	if dest == nil {
		return errors.Errorf("invalid metric destination (%s)->(%s)", metric, metricDest)
	}

	// add stream tags to metric name
	metricTagList := []string{}
	if metricTagSpec != "" {
		metricTagList = strings.Split(metricTagSpec, tags.Separator)
	}
	tagList := make([]string, 0, len(s.baseTags)+len(metricTagList))
	tagList = append(tagList, s.baseTags...)
	tagList = append(tagList, metricTagList...)
	metricTags := tags.FromList(metricTagList)

	switch metricType {
	case "c": // counter
		v, err := strconv.ParseUint(metricValue, 10, 64)
		if err != nil {
			return errors.Wrap(err, "invalid counter value")
		}
		if sampleRate > 0 {
			v = uint64(float64(v) * (1 / sampleRate))
		}
		dest.IncrementByValueWithTags(metricName, metricTags, v)
	case "g": // gauge
		if strings.Contains(metricValue, ".") {
			v, err := strconv.ParseFloat(metricValue, 64)
			if err != nil {
				return errors.Wrap(err, "invalid gauge value")
			}
			dest.GaugeWithTags(metricName, metricTags, v)
		} else if strings.Contains(metricValue, "-") {
			v, err := strconv.ParseInt(metricValue, 10, 64)
			if err != nil {
				return errors.Wrap(err, "invalid gauge value")
			}
			dest.GaugeWithTags(metricName, metricTags, v)
		} else {
			v, err := strconv.ParseUint(metricValue, 10, 64)
			if err != nil {
				return errors.Wrap(err, "invalid gauge value")
			}
			dest.GaugeWithTags(metricName, metricTags, v)
		}
	case "h": // histogram (circonus)
		fallthrough
	case "ms": // measurement
		v, err := strconv.ParseFloat(metricValue, 64)
		if err != nil {
			return errors.Wrap(err, "invalid histogram value")
		}
		if sampleRate > 0 {
			v /= sampleRate
		}
		dest.RecordValueWithTags(metricName, metricTags, v)
	case "s": // set
		// in the case of sets, the value is the unique "thing" to be tracked
		// counters are used to track individual "things"
		dest.IncrementWithTags(strings.Join([]string{metricName, metricValue}, config.MetricNameSeparator), metricTags)
	case "t": // text (circonus)
		dest.SetTextWithTags(metricName, metricTags, metricValue)
	default:
		return errors.Errorf("invalid metric type (%s)", metricType)
	}

	s.logger.Debug().
		Str("destination", metricDest).
		Str("metric", metric).
		Str("name", metricName).
		Str("type", metricType).
		Str("value", metricValue).
		Msg("parsing")

	return nil
}
<|endoftext|>


<commit_before>package constant

import (
	"regexp"
)

var (
	Host           = "localhost"
	Region         = "dev"
	Zone           = "dev1"
	AvailableZones = []string{"dev1"}
	AppRegexp      = regexp.MustCompile("[A-Za-z0-9-]+") // apps can contain letters, numbers, and -
)

const (
	ManagerRPCVersion               = "1.0.0"
	ManagerAPIVersion               = "1.0.0"
	DefaultManagerHost              = "localhost"
	DefaultManagerRPCPort           = uint16(1338)
	DefaultManagerAPIPort           = uint16(443)
	DefaultManagerKeyPath           = "~/.manager"
	DefaultResultDuration           = "30m"
	DefaultMaintenanceFile          = "/etc/atlantis/manager/maint"
	DefaultMaintenanceCheckInterval = "5s"
	DefaultMinProxyPort             = uint16(40000)
	DefaultMaxProxyPort             = uint16(65535)
	DefaultProxyIP                  = "172.31.254.254"
)
<commit_msg>move proxy defaults to common<commit_after>package constant

import (
	"regexp"
)

var (
	Host           = "localhost"
	Region         = "dev"
	Zone           = "dev1"
	AvailableZones = []string{"dev1"}
	AppRegexp      = regexp.MustCompile("[A-Za-z0-9-]+") // apps can contain letters, numbers, and -
)

const (
	ManagerRPCVersion               = "1.0.0"
	ManagerAPIVersion               = "1.0.0"
	DefaultManagerHost              = "localhost"
	DefaultManagerRPCPort           = uint16(1338)
	DefaultManagerAPIPort           = uint16(443)
	DefaultManagerKeyPath           = "~/.manager"
	DefaultResultDuration           = "30m"
	DefaultMaintenanceFile          = "/etc/atlantis/manager/maint"
	DefaultMaintenanceCheckInterval = "5s"
)
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package x509

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"net/http"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"

	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apiserver/pkg/authentication/authenticator"
	"k8s.io/apiserver/pkg/authentication/user"
)

var clientCertificateExpirationHistogram = prometheus.NewHistogram(
	prometheus.HistogramOpts{
		Namespace: "apiserver",
		Subsystem: "client",
		Name:      "certificate_expiration_seconds",
		Help:      "Distribution of the remaining lifetime on the certificate used to authenticate a request.",
		Buckets: []float64{
			0,
			(6 * time.Hour).Seconds(),
			(12 * time.Hour).Seconds(),
			(24 * time.Hour).Seconds(),
			(2 * 24 * time.Hour).Seconds(),
			(4 * 24 * time.Hour).Seconds(),
			(7 * 24 * time.Hour).Seconds(),
		},
	},
)

func init() {
	prometheus.MustRegister(clientCertificateExpirationHistogram)
}

// UserConversion defines an interface for extracting user info from a client certificate chain
type UserConversion interface {
	User(chain []*x509.Certificate) (user.Info, bool, error)
}

// UserConversionFunc is a function that implements the UserConversion interface.
type UserConversionFunc func(chain []*x509.Certificate) (user.Info, bool, error)

// User implements x509.UserConversion
func (f UserConversionFunc) User(chain []*x509.Certificate) (user.Info, bool, error) {
	return f(chain)
}

// Authenticator implements request.Authenticator by extracting user info from verified client certificates
type Authenticator struct {
	opts x509.VerifyOptions
	user UserConversion
}

// New returns a request.Authenticator that verifies client certificates using the provided
// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
	return &Authenticator{opts, user}
}

// AuthenticateRequest authenticates the request using presented client certificates
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	remaining := req.TLS.PeerCertificates[0].NotAfter.Sub(time.Now())
	clientCertificateExpirationHistogram.Observe(remaining.Seconds())
	chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy)
	if err != nil {
		return nil, false, err
	}

	var errlist []error
	for _, chain := range chains {
		user, ok, err := a.user.User(chain)
		if err != nil {
			errlist = append(errlist, err)
			continue
		}

		if ok {
			return user, ok, err
		}
	}
	return nil, false, utilerrors.NewAggregate(errlist)
}

// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
type Verifier struct {
	opts x509.VerifyOptions
	auth authenticator.Request

	// allowedCommonNames contains the common names which a verified certificate is allowed to have.
	// If empty, all verified certificates are allowed.
	allowedCommonNames sets.String
}

// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
	return &Verifier{opts, auth, allowedCommonNames}
}

// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
func (a *Verifier) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	if _, err := req.TLS.PeerCertificates[0].Verify(optsCopy); err != nil {
		return nil, false, err
	}
	if err := a.verifySubject(req.TLS.PeerCertificates[0].Subject); err != nil {
		return nil, false, err
	}
	return a.auth.AuthenticateRequest(req)
}

func (a *Verifier) verifySubject(subject pkix.Name) error {
	// No CN restrictions
	if len(a.allowedCommonNames) == 0 {
		return nil
	}
	// Enforce CN restrictions
	if a.allowedCommonNames.Has(subject.CommonName) {
		return nil
	}
	glog.Warningf("x509: subject with cn=%s is not in the allowed list: %v", subject.CommonName, a.allowedCommonNames.List())
	return fmt.Errorf("x509: subject with cn=%s is not allowed", subject.CommonName)
}

// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
func DefaultVerifyOptions() x509.VerifyOptions {
	return x509.VerifyOptions{
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}
}

// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
	if len(chain[0].Subject.CommonName) == 0 {
		return nil, false, nil
	}
	return &user.DefaultInfo{
		Name:   chain[0].Subject.CommonName,
		Groups: chain[0].Subject.Organization,
	}, true, nil
})

// DNSNameUserConversion builds user info from a certificate chain using the first DNSName on the certificate
var DNSNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
	if len(chain[0].DNSNames) == 0 {
		return nil, false, nil
	}
	return &user.DefaultInfo{Name: chain[0].DNSNames[0]}, true, nil
})

// EmailAddressUserConversion builds user info from a certificate chain using the first EmailAddress on the certificate
var EmailAddressUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
	var emailAddressOID asn1.ObjectIdentifier = []int{1, 2, 840, 113549, 1, 9, 1}
	if len(chain[0].EmailAddresses) == 0 {
		for _, name := range chain[0].Subject.Names {
			if name.Type.Equal(emailAddressOID) {
				return &user.DefaultInfo{Name: name.Value.(string)}, true, nil
			}
		}
		return nil, false, nil
	}
	return &user.DefaultInfo{Name: chain[0].EmailAddresses[0]}, true, nil
})
<commit_msg>certs: add month buckets<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package x509

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"net/http"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"

	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apiserver/pkg/authentication/authenticator"
	"k8s.io/apiserver/pkg/authentication/user"
)

var clientCertificateExpirationHistogram = prometheus.NewHistogram(
	prometheus.HistogramOpts{
		Namespace: "apiserver",
		Subsystem: "client",
		Name:      "certificate_expiration_seconds",
		Help:      "Distribution of the remaining lifetime on the certificate used to authenticate a request.",
		Buckets: []float64{
			0,
			(6 * time.Hour).Seconds(),
			(12 * time.Hour).Seconds(),
			(24 * time.Hour).Seconds(),
			(2 * 24 * time.Hour).Seconds(),
			(4 * 24 * time.Hour).Seconds(),
			(7 * 24 * time.Hour).Seconds(),
			(30 * 24 * time.Hour).Seconds(),
			(3 * 30 * 24 * time.Hour).Seconds(),
			(6 * 30 * 24 * time.Hour).Seconds(),
			(12 * 30 * 24 * time.Hour).Seconds(),
		},
	},
)

func init() {
	prometheus.MustRegister(clientCertificateExpirationHistogram)
}

// UserConversion defines an interface for extracting user info from a client certificate chain
type UserConversion interface {
	User(chain []*x509.Certificate) (user.Info, bool, error)
}

// UserConversionFunc is a function that implements the UserConversion interface.
type UserConversionFunc func(chain []*x509.Certificate) (user.Info, bool, error)

// User implements x509.UserConversion
func (f UserConversionFunc) User(chain []*x509.Certificate) (user.Info, bool, error) {
	return f(chain)
}

// Authenticator implements request.Authenticator by extracting user info from verified client certificates
type Authenticator struct {
	opts x509.VerifyOptions
	user UserConversion
}

// New returns a request.Authenticator that verifies client certificates using the provided
// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
	return &Authenticator{opts, user}
}

// AuthenticateRequest authenticates the request using presented client certificates
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	remaining := req.TLS.PeerCertificates[0].NotAfter.Sub(time.Now())
	clientCertificateExpirationHistogram.Observe(remaining.Seconds())
	chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy)
	if err != nil {
		return nil, false, err
	}

	var errlist []error
	for _, chain := range chains {
		user, ok, err := a.user.User(chain)
		if err != nil {
			errlist = append(errlist, err)
			continue
		}

		if ok {
			return user, ok, err
		}
	}
	return nil, false, utilerrors.NewAggregate(errlist)
}

// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
type Verifier struct {
	opts x509.VerifyOptions
	auth authenticator.Request

	// allowedCommonNames contains the common names which a verified certificate is allowed to have.
	// If empty, all verified certificates are allowed.
	allowedCommonNames sets.String
}

// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
	return &Verifier{opts, auth, allowedCommonNames}
}

// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
func (a *Verifier) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	if _, err := req.TLS.PeerCertificates[0].Verify(optsCopy); err != nil {
		return nil, false, err
	}
	if err := a.verifySubject(req.TLS.PeerCertificates[0].Subject); err != nil {
		return nil, false, err
	}
	return a.auth.AuthenticateRequest(req)
}

func (a *Verifier) verifySubject(subject pkix.Name) error {
	// No CN restrictions
	if len(a.allowedCommonNames) == 0 {
		return nil
	}
	// Enforce CN restrictions
	if a.allowedCommonNames.Has(subject.CommonName) {
		return nil
	}
	glog.Warningf("x509: subject with cn=%s is not in the allowed list: %v", subject.CommonName, a.allowedCommonNames.List())
	return fmt.Errorf("x509: subject with cn=%s is not allowed", subject.CommonName)
}

// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
func DefaultVerifyOptions() x509.VerifyOptions {
	return x509.VerifyOptions{
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}
}

// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
	if len(chain[0].Subject.CommonName) == 0 {
		return nil, false, nil
	}
	return &user.DefaultInfo{
		Name:   chain[0].Subject.CommonName,
		Groups: chain[0].Subject.Organization,
	}, true, nil
})

// DNSNameUserConversion builds user info from a certificate chain using the first DNSName on the certificate
var DNSNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
	if len(chain[0].DNSNames) == 0 {
		return nil, false, nil
	}
	return &user.DefaultInfo{Name: chain[0].DNSNames[0]}, true, nil
})

// EmailAddressUserConversion builds user info from a certificate chain using the first EmailAddress on the certificate
var EmailAddressUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
	var emailAddressOID asn1.ObjectIdentifier = []int{1, 2, 840, 113549, 1, 9, 1}
	if len(chain[0].EmailAddresses) == 0 {
		for _, name := range chain[0].Subject.Names {
			if name.Type.Equal(emailAddressOID) {
				return &user.DefaultInfo{Name: name.Value.(string)}, true, nil
			}
		}
		return nil, false, nil
	}
	return &user.DefaultInfo{Name: chain[0].EmailAddresses[0]}, true, nil
})
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func tail(li []int) int {
	return li[len(li)-1]
}

func head(li []int) int {
	return li[0]
}

func search(piece int, in []int) int {
	if len(in) == 1 {
		if in[0] == piece {
			return 0
		}
		return - 1
	}

	if len(in) == 0 {
		return -1
	}

	if head(in) == piece {
		return 0
	}

	if tail(in) == piece {
		return len(in) -1
	}

	return binsearch(piece, in, 0, len(in)-1)
}

func binsearch(piece int, in []int, ubound, lbound int) int {
	mid := (ubound + lbound) / 2

	if in[ubound] == piece {
		return ubound
	}

	if in[lbound] == piece {
		return lbound
	}

	if in[mid] == piece {
		return mid
	}

	if lbound > ubound { return -1 }

	if in[mid] > piece {
		return binsearch(piece, in, mid, lbound)
	}

	if in[mid] < piece {
		return binsearch(piece, in, lbound, mid)
	}

	panic("Unreachable")
}

func main() {
	do_tests()
}

func do_tests() {
    assert_equal(-1, search(3, []int{}))
    fmt.Printf("Test %d passed\n",1)
    assert_equal(-1, search(3, []int{1}))
    fmt.Printf("Test %d passed\n",2)
    assert_equal(0,  search(1, []int{1}))
    fmt.Printf("Test %d passed\n",3)
    assert_equal(0,  search(1, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",4)
    assert_equal(1,  search(3, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",5)
    assert_equal(2,  search(5, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",6)
    assert_equal(-1, search(0, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",7)
    assert_equal(-1, search(2, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",8)
    assert_equal(-1, search(4, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",9)
    assert_equal(-1, search(6, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",10)
    assert_equal(0,  search(1, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",11)
    assert_equal(1,  search(3, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",12)
    assert_equal(2,  search(5, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",13)
    assert_equal(3,  search(7, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",14)
    assert_equal(-1, search(0, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n", 15)
    assert_equal(-1, search(2, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",16)
    assert_equal(-1, search(4, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",17)
    assert_equal(-1, search(6, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",18)
    assert_equal(-1, search(8, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",19)
}

func assert_equal(a, b int) {
	if a != b {
		panic(fmt.Sprintf("Fail test! Got %d when the answer was %d", b, a))
	}
}<commit_msg>Fixed binarysearch for Go.<commit_after>package main

import (
	"fmt"
)

func tail(li []int) int {
	return li[len(li)-1]
}

func head(li []int) int {
	return li[0]
}

func search(piece int, in []int) int {
	if len(in) == 3 {
		for idx, item := range in {
			if item == piece {
				return idx
			}
		}
		return -1
	}
	if len(in) == 1 {
		if in[0] == piece {
			return 0
		}
		return - 1
	}
	if len(in) == 0 {
		return -1
	}
	if head(in) == piece {
		return 0
	}
	if tail(in) == piece {
		return len(in) - 1
	}
	return binsearch(piece, in, 0, len(in)-1)
}

func binsearch(piece int, in []int, ubound, lbound int) int {

	if in[ubound] == piece { return ubound }
	if in[lbound] == piece { return lbound }
	if ubound >= lbound { return -1 }

	mid := ubound + lbound / 2
	if in[mid] == piece {
		return mid
	}
	if in[mid] > piece {
		return binsearch(piece, in, lbound, mid-1)
	}
	return binsearch(piece, in, mid+1, ubound)

}

func main() {
	do_tests()
}

func do_tests() {
    assert_equal(-1, search(3, []int{}))
    fmt.Printf("Test %d passed\n",1)
    assert_equal(-1, search(3, []int{1}))
    fmt.Printf("Test %d passed\n",2)
    assert_equal(0,  search(1, []int{1}))
    fmt.Printf("Test %d passed\n",3)
    assert_equal(0,  search(1, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",4)
    assert_equal(1,  search(3, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",5)
    assert_equal(2,  search(5, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",6)
    assert_equal(-1, search(0, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",7)
    assert_equal(-1, search(2, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",8)
    assert_equal(-1, search(4, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",9)
    assert_equal(-1, search(6, []int{1,3,5}))
    fmt.Printf("Test %d passed\n",10)
    assert_equal(0,  search(1, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",11)
    assert_equal(1,  search(3, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",12)
    assert_equal(2,  search(5, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",13)
    assert_equal(3,  search(7, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",14)
    assert_equal(-1, search(0, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n", 15)
    assert_equal(-1, search(2, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",16)
    assert_equal(-1, search(4, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",17)
    assert_equal(-1, search(6, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",18)
    assert_equal(-1, search(8, []int{1,3,5,7}))
    fmt.Printf("Test %d passed\n",19)
}

func assert_equal(a, b int) {
	if a != b {
		panic(fmt.Sprintf("Fail test! Got %d when the answer was %d", b, a))
	}
}<|endoftext|>


<commit_before>// Copyright 2016 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 kubernetes

import (
	"errors"
	"io"

	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/provision"
)

const (
	provisionerName = "kubernetes"
)

var errNotImplemented = errors.New("not implemented")

type kubernetesProvisioner struct{}

func init() {
	provision.Register(provisionerName, func() (provision.Provisioner, error) {
		return &kubernetesProvisioner{}, nil
	})
}

func (p *kubernetesProvisioner) GetName() string {
	return provisionerName
}

func (p *kubernetesProvisioner) Provision(provision.App) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Destroy(provision.App) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) AddUnits(provision.App, uint, string, io.Writer) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RemoveUnits(provision.App, uint, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) SetUnitStatus(provision.Unit, provision.Status) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Restart(provision.App, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Start(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Stop(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Units(app provision.App) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RoutableUnits(app provision.App) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RegisterUnit(unit provision.Unit, customData map[string]interface{}) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) SetNodeStatus(provision.NodeStatusData) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ListNodes(addressFilter []string) ([]provision.Node, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) GetNode(address string) (provision.Node, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) AddNode(opts provision.AddNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) RemoveNode(opts provision.RemoveNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) UpdateNode(provision.UpdateNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ArchiveDeploy(app provision.App, archiveURL string, evt *event.Event) (imgID string, err error) {
	return "", errNotImplemented
}

func (p *kubernetesProvisioner) ImageDeploy(a provision.App, imgID string, evt *event.Event) (string, error) {
	return "", errNotImplemented
}
<commit_msg>kubernetes: implement AddNode<commit_after>// Copyright 2016 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 kubernetes

import (
	"io"

	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/mgo.v2/bson"
)

const (
	provisionerName = "kubernetes"
)

var errNotImplemented = errors.New("not implemented")

type kubernetesProvisioner struct{}

func init() {
	provision.Register(provisionerName, func() (provision.Provisioner, error) {
		return &kubernetesProvisioner{}, nil
	})
}

func (p *kubernetesProvisioner) GetName() string {
	return provisionerName
}

func (p *kubernetesProvisioner) Provision(provision.App) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Destroy(provision.App) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) AddUnits(provision.App, uint, string, io.Writer) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RemoveUnits(provision.App, uint, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) SetUnitStatus(provision.Unit, provision.Status) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Restart(provision.App, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Start(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Stop(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Units(app provision.App) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RoutableUnits(app provision.App) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RegisterUnit(unit provision.Unit, customData map[string]interface{}) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) SetNodeStatus(provision.NodeStatusData) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ListNodes(addressFilter []string) ([]provision.Node, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) GetNode(address string) (provision.Node, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) AddNode(opts provision.AddNodeOptions) error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	addrs := []string{opts.Address}
	_, err = coll.UpsertId(uniqueDocumentID, bson.M{"$set": bson.M{"addresses": addrs}})
	if err != nil {
		return errors.Wrap(err, "")
	}
	return nil
}

func (p *kubernetesProvisioner) RemoveNode(opts provision.RemoveNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) UpdateNode(provision.UpdateNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ArchiveDeploy(app provision.App, archiveURL string, evt *event.Event) (imgID string, err error) {
	return "", errNotImplemented
}

func (p *kubernetesProvisioner) ImageDeploy(a provision.App, imgID string, evt *event.Event) (string, error) {
	return "", errNotImplemented
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"net"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/miekg/dns"
)

type Service struct {
	Name    string
	Image   string
	Ip      net.IP
	Ttl     int
	Aliases []string
}

func NewService() (s *Service) {
	s = &Service{Ttl: -1}
	return
}

type ServiceListProvider interface {
	AddService(string, Service)
	RemoveService(string) error
	GetService(string) (Service, error)
	GetAllServices() map[string]Service
}

type DNSServer struct {
	config   *Config
	server   *dns.Server
	mux      *dns.ServeMux
	services map[string]*Service
	lock     *sync.RWMutex
}

func NewDNSServer(c *Config) *DNSServer {
	s := &DNSServer{
		config:   c,
		services: make(map[string]*Service),
		lock:     &sync.RWMutex{},
	}

	s.mux = dns.NewServeMux()
	s.mux.HandleFunc(c.domain.String()+".", s.handleRequest)
	s.mux.HandleFunc("in-addr.arpa.", s.handleReverseRequest)
	s.mux.HandleFunc(".", s.handleForward)

	s.server = &dns.Server{Addr: c.dnsAddr, Net: "udp", Handler: s.mux}

	return s
}

func (s *DNSServer) Start() error {
	return s.server.ListenAndServe()
}

func (s *DNSServer) Stop() {
	s.server.Shutdown()
}

func (s *DNSServer) AddService(id string, service Service) {
	defer s.lock.Unlock()
	s.lock.Lock()

	id = s.getExpandedID(id)
	s.services[id] = &service

	for _, alias := range service.Aliases {
		s.mux.HandleFunc(alias+".", s.handleRequest)
	}

	if s.config.verbose {
		log.Println("Added service:", id, service)
	}
}

func (s *DNSServer) RemoveService(id string) error {
	defer s.lock.Unlock()
	s.lock.Lock()

	id = s.getExpandedID(id)
	if _, ok := s.services[id]; !ok {
		return errors.New("No such service: " + id)
	}

	for _, alias := range s.services[id].Aliases {
		s.mux.HandleRemove(alias + ".")
	}

	delete(s.services, id)

	if s.config.verbose {
		log.Println("Stopped service:", id)
	}

	return nil
}

func (s *DNSServer) GetService(id string) (Service, error) {
	defer s.lock.RUnlock()
	s.lock.RLock()

	id = s.getExpandedID(id)
	if s, ok := s.services[id]; ok {
		return *s, nil
	}
	// Check for a pa
	return *new(Service), errors.New("No such service: " + id)
}

func (s *DNSServer) GetAllServices() map[string]Service {
	defer s.lock.RUnlock()
	s.lock.RLock()

	list := make(map[string]Service, len(s.services))
	for id, service := range s.services {
		list[id] = *service
	}

	return list
}

func (s *DNSServer) listDomains(service *Service) chan string {
	c := make(chan string)

	go func() {

		if service.Image == "" {
			c <- service.Name + "." + s.config.domain.String() + "."
		} else {
			domain := service.Image + "." + s.config.domain.String() + "."

			c <- domain
			c <- service.Name + "." + domain
		}

		for _, alias := range service.Aliases {
			c <- alias + "."
		}

		close(c)
	}()

	return c
}

func (s *DNSServer) handleForward(w dns.ResponseWriter, r *dns.Msg) {
	// Otherwise just forward the request to another server
	c := new(dns.Client)
	if in, _, err := c.Exchange(r, s.config.nameserver); err != nil {
		log.Print(err)

		m := new(dns.Msg)
		m.SetReply(r)
		m.Ns = s.createSOA()
		m.SetRcode(r, dns.RcodeRefused) // REFUSED

		w.WriteMsg(m)
	} else {
		w.WriteMsg(in)
	}
}

func (s *DNSServer) makeServiceA(n string, service *Service) dns.RR {
	rr := new(dns.A)

	var ttl int
	if service.Ttl != -1 {
		ttl = service.Ttl
	} else {
		ttl = s.config.ttl
	}

	rr.Hdr = dns.RR_Header{
		Name:   n,
		Rrtype: dns.TypeA,
		Class:  dns.ClassINET,
		Ttl:    uint32(ttl),
	}

	rr.A = service.Ip

	return rr
}

func (s *DNSServer) makeServiceMX(n string, service *Service) dns.RR {
	rr := new(dns.MX)

	var ttl int
	if service.Ttl != -1 {
		ttl = service.Ttl
	} else {
		ttl = s.config.ttl
	}

	rr.Hdr = dns.RR_Header{
		Name:   n,
		Rrtype: dns.TypeMX,
		Class:  dns.ClassINET,
		Ttl:    uint32(ttl),
	}

	rr.Mx = n

	return rr
}

func (s *DNSServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
	m := new(dns.Msg)
	m.SetReply(r)

	// Send empty response for empty requests
	if len(r.Question) == 0 {
		m.Ns = s.createSOA()
		w.WriteMsg(m)
		return
	}

	// respond to SOA requests
	if r.Question[0].Qtype == dns.TypeSOA {
		m.Answer = s.createSOA()
		w.WriteMsg(m)
		return
	}

	m.Answer = make([]dns.RR, 0, 2)
	query := r.Question[0].Name

	// trim off any trailing dot
	if query[len(query)-1] == '.' {
		query = query[:len(query)-1]
	}

	for service := range s.queryServices(query) {
		var rr dns.RR
		switch r.Question[0].Qtype {
		case dns.TypeA:
			rr = s.makeServiceA(r.Question[0].Name, service)
		case dns.TypeMX:
			rr = s.makeServiceMX(r.Question[0].Name, service)
		default:
			// this query type isn't supported, but we do have
			// a record with this name. Per RFC 4074 sec. 3, we
			// immediately return an empty NOERROR reply.
			m.Ns = s.createSOA()
			m.MsgHdr.Authoritative = true
			w.WriteMsg(m)
			return
		}

		m.Answer = append(m.Answer, rr)
	}

	// We didn't find a record corresponding to the query
	if len(m.Answer) == 0 {
		m.Ns = s.createSOA()
		m.SetRcode(r, dns.RcodeNameError) // NXDOMAIN
	}

	w.WriteMsg(m)
}

func (s *DNSServer) handleReverseRequest(w dns.ResponseWriter, r *dns.Msg) {
	m := new(dns.Msg)
	m.SetReply(r)

	// Send empty response for empty requests
	if len(r.Question) == 0 {
		m.Ns = s.createSOA()
		w.WriteMsg(m)
		return
	}

	m.Answer = make([]dns.RR, 0, 2)
	query := r.Question[0].Name

	// trim off any trailing dot
	if query[len(query)-1] == '.' {
		query = query[:len(query)-1]
	}

	for service := range s.queryIp(query) {
		if r.Question[0].Qtype != dns.TypePTR {
			m.Ns = s.createSOA()
			w.WriteMsg(m)
			return
		}

		var ttl int
		if service.Ttl != -1 {
			ttl = service.Ttl
		} else {
			ttl = s.config.ttl
		}

		for domain := range s.listDomains(service) {
			rr := new(dns.PTR)
			rr.Hdr = dns.RR_Header{
				Name:   r.Question[0].Name,
				Rrtype: dns.TypePTR,
				Class:  dns.ClassINET,
				Ttl:    uint32(ttl),
			}
			rr.Ptr = domain

			m.Answer = append(m.Answer, rr)
		}
	}

	if len(m.Answer) != 0 {
		w.WriteMsg(m)
	} else {
		// We didn't find a record corresponding to the query,
		// try forwarding
		s.handleForward(w, r)
	}
}

func (s *DNSServer) queryIp(query string) chan *Service {
	c := make(chan *Service, 3)
	reversedIp := strings.TrimSuffix(query, ".in-addr.arpa")
	ip := strings.Join(reverse(strings.Split(reversedIp, ".")), ".")

	go func() {
		defer s.lock.RUnlock()
		s.lock.RLock()

		for _, service := range s.services {
			if service.Ip.String() == ip {
				c <- service
			}
		}

		close(c)
	}()

	return c
}

func (s *DNSServer) queryServices(query string) chan *Service {
	c := make(chan *Service, 3)

	go func() {
		query := strings.Split(strings.ToLower(query), ".")

		defer s.lock.RUnlock()
		s.lock.RLock()

		for _, service := range s.services {
			// create the name for this service, skip empty strings
			test := []string{}
			// todo: add some cache to avoid calculating this every time
			if len(service.Name) > 0 {
				test = append(test, strings.Split(service.Name, ".")...)
			}

			if len(service.Image) > 0 {
				test = append(test, strings.Split(service.Image, ".")...)
			}

			test = append(test, s.config.domain...)

			if isPrefixQuery(query, test) {
				c <- service
			}

			// check aliases
			for _, alias := range service.Aliases {
				if isPrefixQuery(query, strings.Split(alias, ".")) {
					c <- service
				}
			}
		}

		close(c)

	}()

	return c

}

// Checks for a partial match for container SHA and outputs it if found.
func (s *DNSServer) getExpandedID(in string) (out string) {
	out = in

	// Hard to make a judgement on small image names.
	if len(in) < 4 {
		return
	}

	if isHex, _ := regexp.MatchString("^[0-9a-f]+$", in); !isHex {
		return
	}

	for id := range s.services {
		if len(id) == 64 {
			if isHex, _ := regexp.MatchString("^[0-9a-f]+$", id); isHex {
				if strings.HasPrefix(id, in) {
					out = id
					return
				}
			}
		}
	}
	return
}

// Ttl is used from config so that not-found result responses are not cached
// for a long time. The other defaults left as is(skydns source) because they
// do not have an use case in this situation.
func (s *DNSServer) createSOA() []dns.RR {
	dom := dns.Fqdn(s.config.domain.String() + ".")
	soa := &dns.SOA{
		Hdr: dns.RR_Header{
			Name:   dom,
			Rrtype: dns.TypeSOA,
			Class:  dns.ClassINET,
			Ttl:    uint32(s.config.ttl)},
		Ns:      "dnsdock." + dom,
		Mbox:    "dnsdock.dnsdock." + dom,
		Serial:  uint32(time.Now().Truncate(time.Hour).Unix()),
		Refresh: 28800,
		Retry:   7200,
		Expire:  604800,
		Minttl:  uint32(s.config.ttl),
	}
	return []dns.RR{soa}
}

// isPrefixQuery is used to determine whether "query" is a potential prefix
// query for "name". It allows for wildcards (*) in the query. However is makes
// one exception to accomodate the desired behavior we wish from dnsdock,
// namely, the query may be longer than "name" and still be a valid prefix
// query for "name".
// Examples:
//   foo.bar.baz.qux is a valid query for bar.baz.qux (longer prefix is okay)
//   foo.*.baz.qux   is a valid query for bar.baz.qux (wildcards okay)
//   *.baz.qux       is a valid query for baz.baz.qux (wildcard prefix okay)
func isPrefixQuery(query, name []string) bool {
	for i, j := len(query)-1, len(name)-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
		if query[i] != name[j] && query[i] != "*" {
			return false
		}
	}
	return true
}

func reverse(input []string) []string {
	if len(input) == 0 {
		return input
	}

	return append(reverse(input[1:]), input[0])
}
<commit_msg>Return service before domain during reverse resolution<commit_after>package main

import (
	"errors"
	"log"
	"net"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/miekg/dns"
)

type Service struct {
	Name    string
	Image   string
	Ip      net.IP
	Ttl     int
	Aliases []string
}

func NewService() (s *Service) {
	s = &Service{Ttl: -1}
	return
}

type ServiceListProvider interface {
	AddService(string, Service)
	RemoveService(string) error
	GetService(string) (Service, error)
	GetAllServices() map[string]Service
}

type DNSServer struct {
	config   *Config
	server   *dns.Server
	mux      *dns.ServeMux
	services map[string]*Service
	lock     *sync.RWMutex
}

func NewDNSServer(c *Config) *DNSServer {
	s := &DNSServer{
		config:   c,
		services: make(map[string]*Service),
		lock:     &sync.RWMutex{},
	}

	s.mux = dns.NewServeMux()
	s.mux.HandleFunc(c.domain.String()+".", s.handleRequest)
	s.mux.HandleFunc("in-addr.arpa.", s.handleReverseRequest)
	s.mux.HandleFunc(".", s.handleForward)

	s.server = &dns.Server{Addr: c.dnsAddr, Net: "udp", Handler: s.mux}

	return s
}

func (s *DNSServer) Start() error {
	return s.server.ListenAndServe()
}

func (s *DNSServer) Stop() {
	s.server.Shutdown()
}

func (s *DNSServer) AddService(id string, service Service) {
	defer s.lock.Unlock()
	s.lock.Lock()

	id = s.getExpandedID(id)
	s.services[id] = &service

	for _, alias := range service.Aliases {
		s.mux.HandleFunc(alias+".", s.handleRequest)
	}

	if s.config.verbose {
		log.Println("Added service:", id, service)
	}
}

func (s *DNSServer) RemoveService(id string) error {
	defer s.lock.Unlock()
	s.lock.Lock()

	id = s.getExpandedID(id)
	if _, ok := s.services[id]; !ok {
		return errors.New("No such service: " + id)
	}

	for _, alias := range s.services[id].Aliases {
		s.mux.HandleRemove(alias + ".")
	}

	delete(s.services, id)

	if s.config.verbose {
		log.Println("Stopped service:", id)
	}

	return nil
}

func (s *DNSServer) GetService(id string) (Service, error) {
	defer s.lock.RUnlock()
	s.lock.RLock()

	id = s.getExpandedID(id)
	if s, ok := s.services[id]; ok {
		return *s, nil
	}
	// Check for a pa
	return *new(Service), errors.New("No such service: " + id)
}

func (s *DNSServer) GetAllServices() map[string]Service {
	defer s.lock.RUnlock()
	s.lock.RLock()

	list := make(map[string]Service, len(s.services))
	for id, service := range s.services {
		list[id] = *service
	}

	return list
}

func (s *DNSServer) listDomains(service *Service) chan string {
	c := make(chan string)

	go func() {

		if service.Image == "" {
			c <- service.Name + "." + s.config.domain.String() + "."
		} else {
			domain := service.Image + "." + s.config.domain.String() + "."

			c <- service.Name + "." + domain
			c <- domain
		}

		for _, alias := range service.Aliases {
			c <- alias + "."
		}

		close(c)
	}()

	return c
}

func (s *DNSServer) handleForward(w dns.ResponseWriter, r *dns.Msg) {
	// Otherwise just forward the request to another server
	c := new(dns.Client)
	if in, _, err := c.Exchange(r, s.config.nameserver); err != nil {
		log.Print(err)

		m := new(dns.Msg)
		m.SetReply(r)
		m.Ns = s.createSOA()
		m.SetRcode(r, dns.RcodeRefused) // REFUSED

		w.WriteMsg(m)
	} else {
		w.WriteMsg(in)
	}
}

func (s *DNSServer) makeServiceA(n string, service *Service) dns.RR {
	rr := new(dns.A)

	var ttl int
	if service.Ttl != -1 {
		ttl = service.Ttl
	} else {
		ttl = s.config.ttl
	}

	rr.Hdr = dns.RR_Header{
		Name:   n,
		Rrtype: dns.TypeA,
		Class:  dns.ClassINET,
		Ttl:    uint32(ttl),
	}

	rr.A = service.Ip

	return rr
}

func (s *DNSServer) makeServiceMX(n string, service *Service) dns.RR {
	rr := new(dns.MX)

	var ttl int
	if service.Ttl != -1 {
		ttl = service.Ttl
	} else {
		ttl = s.config.ttl
	}

	rr.Hdr = dns.RR_Header{
		Name:   n,
		Rrtype: dns.TypeMX,
		Class:  dns.ClassINET,
		Ttl:    uint32(ttl),
	}

	rr.Mx = n

	return rr
}

func (s *DNSServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
	m := new(dns.Msg)
	m.SetReply(r)

	// Send empty response for empty requests
	if len(r.Question) == 0 {
		m.Ns = s.createSOA()
		w.WriteMsg(m)
		return
	}

	// respond to SOA requests
	if r.Question[0].Qtype == dns.TypeSOA {
		m.Answer = s.createSOA()
		w.WriteMsg(m)
		return
	}

	m.Answer = make([]dns.RR, 0, 2)
	query := r.Question[0].Name

	// trim off any trailing dot
	if query[len(query)-1] == '.' {
		query = query[:len(query)-1]
	}

	for service := range s.queryServices(query) {
		var rr dns.RR
		switch r.Question[0].Qtype {
		case dns.TypeA:
			rr = s.makeServiceA(r.Question[0].Name, service)
		case dns.TypeMX:
			rr = s.makeServiceMX(r.Question[0].Name, service)
		default:
			// this query type isn't supported, but we do have
			// a record with this name. Per RFC 4074 sec. 3, we
			// immediately return an empty NOERROR reply.
			m.Ns = s.createSOA()
			m.MsgHdr.Authoritative = true
			w.WriteMsg(m)
			return
		}

		m.Answer = append(m.Answer, rr)
	}

	// We didn't find a record corresponding to the query
	if len(m.Answer) == 0 {
		m.Ns = s.createSOA()
		m.SetRcode(r, dns.RcodeNameError) // NXDOMAIN
	}

	w.WriteMsg(m)
}

func (s *DNSServer) handleReverseRequest(w dns.ResponseWriter, r *dns.Msg) {
	m := new(dns.Msg)
	m.SetReply(r)

	// Send empty response for empty requests
	if len(r.Question) == 0 {
		m.Ns = s.createSOA()
		w.WriteMsg(m)
		return
	}

	m.Answer = make([]dns.RR, 0, 2)
	query := r.Question[0].Name

	// trim off any trailing dot
	if query[len(query)-1] == '.' {
		query = query[:len(query)-1]
	}

	for service := range s.queryIp(query) {
		if r.Question[0].Qtype != dns.TypePTR {
			m.Ns = s.createSOA()
			w.WriteMsg(m)
			return
		}

		var ttl int
		if service.Ttl != -1 {
			ttl = service.Ttl
		} else {
			ttl = s.config.ttl
		}

		for domain := range s.listDomains(service) {
			rr := new(dns.PTR)
			rr.Hdr = dns.RR_Header{
				Name:   r.Question[0].Name,
				Rrtype: dns.TypePTR,
				Class:  dns.ClassINET,
				Ttl:    uint32(ttl),
			}
			rr.Ptr = domain

			m.Answer = append(m.Answer, rr)
		}
	}

	if len(m.Answer) != 0 {
		w.WriteMsg(m)
	} else {
		// We didn't find a record corresponding to the query,
		// try forwarding
		s.handleForward(w, r)
	}
}

func (s *DNSServer) queryIp(query string) chan *Service {
	c := make(chan *Service, 3)
	reversedIp := strings.TrimSuffix(query, ".in-addr.arpa")
	ip := strings.Join(reverse(strings.Split(reversedIp, ".")), ".")

	go func() {
		defer s.lock.RUnlock()
		s.lock.RLock()

		for _, service := range s.services {
			if service.Ip.String() == ip {
				c <- service
			}
		}

		close(c)
	}()

	return c
}

func (s *DNSServer) queryServices(query string) chan *Service {
	c := make(chan *Service, 3)

	go func() {
		query := strings.Split(strings.ToLower(query), ".")

		defer s.lock.RUnlock()
		s.lock.RLock()

		for _, service := range s.services {
			// create the name for this service, skip empty strings
			test := []string{}
			// todo: add some cache to avoid calculating this every time
			if len(service.Name) > 0 {
				test = append(test, strings.Split(service.Name, ".")...)
			}

			if len(service.Image) > 0 {
				test = append(test, strings.Split(service.Image, ".")...)
			}

			test = append(test, s.config.domain...)

			if isPrefixQuery(query, test) {
				c <- service
			}

			// check aliases
			for _, alias := range service.Aliases {
				if isPrefixQuery(query, strings.Split(alias, ".")) {
					c <- service
				}
			}
		}

		close(c)

	}()

	return c

}

// Checks for a partial match for container SHA and outputs it if found.
func (s *DNSServer) getExpandedID(in string) (out string) {
	out = in

	// Hard to make a judgement on small image names.
	if len(in) < 4 {
		return
	}

	if isHex, _ := regexp.MatchString("^[0-9a-f]+$", in); !isHex {
		return
	}

	for id := range s.services {
		if len(id) == 64 {
			if isHex, _ := regexp.MatchString("^[0-9a-f]+$", id); isHex {
				if strings.HasPrefix(id, in) {
					out = id
					return
				}
			}
		}
	}
	return
}

// Ttl is used from config so that not-found result responses are not cached
// for a long time. The other defaults left as is(skydns source) because they
// do not have an use case in this situation.
func (s *DNSServer) createSOA() []dns.RR {
	dom := dns.Fqdn(s.config.domain.String() + ".")
	soa := &dns.SOA{
		Hdr: dns.RR_Header{
			Name:   dom,
			Rrtype: dns.TypeSOA,
			Class:  dns.ClassINET,
			Ttl:    uint32(s.config.ttl)},
		Ns:      "dnsdock." + dom,
		Mbox:    "dnsdock.dnsdock." + dom,
		Serial:  uint32(time.Now().Truncate(time.Hour).Unix()),
		Refresh: 28800,
		Retry:   7200,
		Expire:  604800,
		Minttl:  uint32(s.config.ttl),
	}
	return []dns.RR{soa}
}

// isPrefixQuery is used to determine whether "query" is a potential prefix
// query for "name". It allows for wildcards (*) in the query. However is makes
// one exception to accomodate the desired behavior we wish from dnsdock,
// namely, the query may be longer than "name" and still be a valid prefix
// query for "name".
// Examples:
//   foo.bar.baz.qux is a valid query for bar.baz.qux (longer prefix is okay)
//   foo.*.baz.qux   is a valid query for bar.baz.qux (wildcards okay)
//   *.baz.qux       is a valid query for baz.baz.qux (wildcard prefix okay)
func isPrefixQuery(query, name []string) bool {
	for i, j := len(query)-1, len(name)-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
		if query[i] != name[j] && query[i] != "*" {
			return false
		}
	}
	return true
}

func reverse(input []string) []string {
	if len(input) == 0 {
		return input
	}

	return append(reverse(input[1:]), input[0])
}
<|endoftext|>


<commit_before>package sendgrid

import (
	"errors"
	"net/http"
	"strconv"
	"time"

	"github.com/sendgrid/rest"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
)

// Version is this client library's current version
const (
	Version        = "3.7.0"
	rateLimitRetry = 5
	rateLimitSleep = 1100
)

type options struct {
	Auth     string
	Endpoint string
	Host     string
	Subuser  string
}

// Client is the Twilio SendGrid Go client
type Client struct {
	rest.Request
}

func (o *options) baseURL() string {
	return o.Host + o.Endpoint
}

// requestNew create Request
// @return [Request] a default request object
func requestNew(options options) rest.Request {
	requestHeaders := map[string]string{
		"Authorization": options.Auth,
		"User-Agent":    "sendgrid/" + Version + ";go",
		"Accept":        "application/json",
	}

	if len(options.Subuser) != 0 {
		requestHeaders["On-Behalf-Of"] = options.Subuser
	}

	return rest.Request{
		BaseURL: options.baseURL(),
		Headers: requestHeaders,
	}
}

// Send sends an email through Twilio SendGrid
func (cl *Client) Send(email *mail.SGMailV3) (*rest.Response, error) {
	cl.Body = mail.GetRequestBody(email)
	return MakeRequest(cl.Request)
}

// DefaultClient is used if no custom HTTP client is defined
var DefaultClient = rest.DefaultClient

// API sets up the request to the Twilio SendGrid API, this is main interface.
// Please use the MakeRequest or MakeRequestAsync functions instead.
// (deprecated)
func API(request rest.Request) (*rest.Response, error) {
	return MakeRequest(request)
}

// MakeRequest attempts a Twilio SendGrid request synchronously.
func MakeRequest(request rest.Request) (*rest.Response, error) {
	return DefaultClient.Send(request)
}

// MakeRequestRetry a synchronous request, but retry in the event of a rate
// limited response.
func MakeRequestRetry(request rest.Request) (*rest.Response, error) {
	retry := 0
	var response *rest.Response
	var err error

	for {
		response, err = MakeRequest(request)
		if err != nil {
			return nil, err
		}

		if response.StatusCode != http.StatusTooManyRequests {
			return response, nil
		}

		if retry > rateLimitRetry {
			return nil, errors.New("rate limit retry exceeded")
		}
		retry++

		resetTime := time.Now().Add(rateLimitSleep * time.Millisecond)

		reset, ok := response.Headers["X-RateLimit-Reset"]
		if ok && len(reset) > 0 {
			t, err := strconv.Atoi(reset[0])
			if err == nil {
				resetTime = time.Unix(int64(t), 0)
			}
		}
		time.Sleep(resetTime.Sub(time.Now()))
	}
}

// MakeRequestAsync attempts a request asynchronously in a new go
// routine. This function returns two channels: responses
// and errors. This function will retry in the case of a
// rate limit.
func MakeRequestAsync(request rest.Request) (chan *rest.Response, chan error) {
	r := make(chan *rest.Response)
	e := make(chan error)

	go func() {
		response, err := MakeRequestRetry(request)
		if err != nil {
			e <- err
		}
		if response != nil {
			r <- response
		}
	}()

	return r, e
}
<commit_msg>Release v3.7.1<commit_after>package sendgrid

import (
	"errors"
	"net/http"
	"strconv"
	"time"

	"github.com/sendgrid/rest"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
)

// Version is this client library's current version
const (
	Version        = "3.7.1"
	rateLimitRetry = 5
	rateLimitSleep = 1100
)

type options struct {
	Auth     string
	Endpoint string
	Host     string
	Subuser  string
}

// Client is the Twilio SendGrid Go client
type Client struct {
	rest.Request
}

func (o *options) baseURL() string {
	return o.Host + o.Endpoint
}

// requestNew create Request
// @return [Request] a default request object
func requestNew(options options) rest.Request {
	requestHeaders := map[string]string{
		"Authorization": options.Auth,
		"User-Agent":    "sendgrid/" + Version + ";go",
		"Accept":        "application/json",
	}

	if len(options.Subuser) != 0 {
		requestHeaders["On-Behalf-Of"] = options.Subuser
	}

	return rest.Request{
		BaseURL: options.baseURL(),
		Headers: requestHeaders,
	}
}

// Send sends an email through Twilio SendGrid
func (cl *Client) Send(email *mail.SGMailV3) (*rest.Response, error) {
	cl.Body = mail.GetRequestBody(email)
	return MakeRequest(cl.Request)
}

// DefaultClient is used if no custom HTTP client is defined
var DefaultClient = rest.DefaultClient

// API sets up the request to the Twilio SendGrid API, this is main interface.
// Please use the MakeRequest or MakeRequestAsync functions instead.
// (deprecated)
func API(request rest.Request) (*rest.Response, error) {
	return MakeRequest(request)
}

// MakeRequest attempts a Twilio SendGrid request synchronously.
func MakeRequest(request rest.Request) (*rest.Response, error) {
	return DefaultClient.Send(request)
}

// MakeRequestRetry a synchronous request, but retry in the event of a rate
// limited response.
func MakeRequestRetry(request rest.Request) (*rest.Response, error) {
	retry := 0
	var response *rest.Response
	var err error

	for {
		response, err = MakeRequest(request)
		if err != nil {
			return nil, err
		}

		if response.StatusCode != http.StatusTooManyRequests {
			return response, nil
		}

		if retry > rateLimitRetry {
			return nil, errors.New("rate limit retry exceeded")
		}
		retry++

		resetTime := time.Now().Add(rateLimitSleep * time.Millisecond)

		reset, ok := response.Headers["X-RateLimit-Reset"]
		if ok && len(reset) > 0 {
			t, err := strconv.Atoi(reset[0])
			if err == nil {
				resetTime = time.Unix(int64(t), 0)
			}
		}
		time.Sleep(resetTime.Sub(time.Now()))
	}
}

// MakeRequestAsync attempts a request asynchronously in a new go
// routine. This function returns two channels: responses
// and errors. This function will retry in the case of a
// rate limit.
func MakeRequestAsync(request rest.Request) (chan *rest.Response, chan error) {
	r := make(chan *rest.Response)
	e := make(chan error)

	go func() {
		response, err := MakeRequestRetry(request)
		if err != nil {
			e <- err
		}
		if response != nil {
			r <- response
		}
	}()

	return r, e
}
<|endoftext|>


<commit_before><commit_msg>crypto/tls: deflake TestConnReadNonzeroAndEOF<commit_after><|endoftext|>


<commit_before><commit_msg>exp/ssh: allow for msgUserAuthBanner during authentication<commit_after><|endoftext|>


<commit_before>package getter

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	urlhelper "github.com/hashicorp/go-getter/helper/url"
)

// fileChecksum helps verifying the checksum for a file.
type fileChecksum struct {
	Type     string
	Hash     hash.Hash
	Value    []byte
	Filename string
}

// extractChecksum will return a fileChecksum based on the 'checksum'
// parameter of u.
// ex:
//  http://hashicorp.com/terraform?checksum=<checksumValue>
//  http://hashicorp.com/terraform?checksum=<checksumType>:<checksumValue>
//  http://hashicorp.com/terraform?checksum=file:<checksum_url>
// when checksumming from a file, extractChecksum will go get checksum_url
// in a temporary directory, parse the content of the file then delete it.
// Content of files are expected to be BSD style or GNU style.
//
// BSD-style checksum:
//  MD5 (file1) = <checksum>
//  MD5 (file2) = <checksum>
//
// GNU-style:
//  <checksum>  file1
//  <checksum> *file2
//
// see parseChecksumLine for more detail on checksum file parsing
func (c *Client) extractChecksum(u *url.URL) (*fileChecksum, error) {
	q := u.Query()
	v := q.Get("checksum")

	if v == "" {
		return nil, nil
	}

	vs := strings.SplitN(v, ":", 2)
	switch len(vs) {
	case 2:
		break // good
	default:
		// here, we try to guess the checksum from it's length
		// if the type was not passed
		return newChecksumFromValue(v, filepath.Base(u.EscapedPath()))
	}

	checksumType, checksumValue := vs[0], vs[1]

	switch checksumType {
	case "file":
		return c.checksumFromFile(checksumValue, u)
	default:
		return newChecksumFromType(checksumType, checksumValue, filepath.Base(u.EscapedPath()))
	}
}

func newChecksum(checksumValue, filename string) (*fileChecksum, error) {
	c := &fileChecksum{
		Filename: filename,
	}
	var err error
	c.Value, err = hex.DecodeString(checksumValue)
	if err != nil {
		return nil, fmt.Errorf("invalid checksum: %s", err)
	}
	return c, nil
}

func newChecksumFromType(checksumType, checksumValue, filename string) (*fileChecksum, error) {
	c, err := newChecksum(checksumValue, filename)
	if err != nil {
		return nil, err
	}

	c.Type = strings.ToLower(checksumType)
	switch c.Type {
	case "md5":
		c.Hash = md5.New()
	case "sha1":
		c.Hash = sha1.New()
	case "sha256":
		c.Hash = sha256.New()
	case "sha512":
		c.Hash = sha512.New()
	default:
		return nil, fmt.Errorf(
			"unsupported checksum type: %s", checksumType)
	}

	return c, nil
}

func newChecksumFromValue(checksumValue, filename string) (*fileChecksum, error) {
	c, err := newChecksum(checksumValue, filename)
	if err != nil {
		return nil, err
	}

	switch len(c.Value) {
	case md5.Size:
		c.Hash = md5.New()
		c.Type = "md5"
	case sha1.Size:
		c.Hash = sha1.New()
		c.Type = "sha1"
	case sha256.Size:
		c.Hash = sha256.New()
		c.Type = "sha256"
	case sha512.Size:
		c.Hash = sha512.New()
		c.Type = "sha512"
	default:
		return nil, fmt.Errorf("Unknown type for checksum %s", checksumValue)
	}

	return c, nil
}

// checksumsFromFile will return all the fileChecksums found in file
//
// checksumsFromFile will try to guess the hashing algorithm based on content
// of checksum file
//
// checksumsFromFile will only return checksums for files that match file
// behind src
func (c *Client) checksumFromFile(checksumFile string, src *url.URL) (*fileChecksum, error) {
	checksumFileURL, err := urlhelper.Parse(checksumFile)
	if err != nil {
		return nil, err
	}

	tempfile, err := tmpFile("", filepath.Base(checksumFileURL.Path))
	if err != nil {
		return nil, err
	}
	defer func() {
		os.Remove(tempfile)
	}()

	c2 := &Client{
		Getters:       c.Getters,
		Decompressors: c.Decompressors,
		Detectors:     c.Detectors,
		Pwd:           c.Pwd,
		Dir:           false,
		Src:           checksumFile,
		Dst:           tempfile,
	}
	if err = c2.Get(); err != nil {
		return nil, fmt.Errorf(
			"Error downloading checksum file: %s", err)
	}

	filename := filepath.Base(src.Path)
	absPath, _ := filepath.Abs(src.Path)
	relpath, _ := filepath.Rel(filepath.Dir(checksumFileURL.Path), absPath)

	// possible file identifiers:
	options := []string{
		filename,       // ubuntu-14.04.1-server-amd64.iso
		"*" + filename, // *ubuntu-14.04.1-server-amd64.iso  Standard checksum
		"?" + filename, // ?ubuntu-14.04.1-server-amd64.iso  shasum -p
		relpath,        // dir/ubuntu-14.04.1-server-amd64.iso
		"./" + relpath, // ./dir/ubuntu-14.04.1-server-amd64.iso
		absPath,        // fullpath; set if local
	}

	f, err := os.Open(tempfile)
	if err != nil {
		return nil, fmt.Errorf(
			"Error opening downloaded file: %s", err)
	}
	defer f.Close()
	rd := bufio.NewReader(f)
	for {
		line, err := rd.ReadString('\n')
		if err != nil {
			if err != io.EOF {
				return nil, fmt.Errorf(
					"Error reading checksum file: %s", err)
			}
			break
		}
		checksum, err := parseChecksumLine(line)
		if err != nil || checksum == nil {
			continue
		}
		if checksum.Filename == "" {
			// filename not sure, let's try
			return checksum, nil
		}
		// make sure the checksum is for the right file
		for _, option := range options {
			if checksum.Filename == option {
				// any checksum will work so we return the first one
				return checksum, nil
			}
		}
	}
	return nil, fmt.Errorf("no checksum found in: %s", checksumFile)
}

// parseChecksumLine takes a line from a checksum file and returns
// checksumType, checksumValue and filename parseChecksumLine guesses the style
// of the checksum BSD vs GNU by splitting the line and by counting the parts.
// of a line.
// for BSD type sums parseChecksumLine guesses the hashing algorithm
// by checking the length of the checksum.
func parseChecksumLine(line string) (*fileChecksum, error) {
	parts := strings.Fields(line)

	switch len(parts) {
	case 4:
		// BSD-style checksum:
		//  MD5 (file1) = <checksum>
		//  MD5 (file2) = <checksum>
		if len(parts[1]) <= 2 ||
			parts[1][0] != '(' || parts[1][len(parts[1])-1] != ')' {
			return nil, fmt.Errorf(
				"Unexpected BSD-style-checksum filename format: %s", line)
		}
		filename := parts[1][1 : len(parts[1])-1]
		return newChecksumFromType(parts[0], parts[3], filename)
	case 2:
		// GNU-style:
		//  <checksum>  file1
		//  <checksum> *file2
		return newChecksumFromValue(parts[0], parts[1])
	case 0:
		return nil, nil // empty line
	default:
		return newChecksumFromValue(parts[0], "")
	}
}
<commit_msg>don't ignore path errors<commit_after>package getter

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	urlhelper "github.com/hashicorp/go-getter/helper/url"
)

// fileChecksum helps verifying the checksum for a file.
type fileChecksum struct {
	Type     string
	Hash     hash.Hash
	Value    []byte
	Filename string
}

// extractChecksum will return a fileChecksum based on the 'checksum'
// parameter of u.
// ex:
//  http://hashicorp.com/terraform?checksum=<checksumValue>
//  http://hashicorp.com/terraform?checksum=<checksumType>:<checksumValue>
//  http://hashicorp.com/terraform?checksum=file:<checksum_url>
// when checksumming from a file, extractChecksum will go get checksum_url
// in a temporary directory, parse the content of the file then delete it.
// Content of files are expected to be BSD style or GNU style.
//
// BSD-style checksum:
//  MD5 (file1) = <checksum>
//  MD5 (file2) = <checksum>
//
// GNU-style:
//  <checksum>  file1
//  <checksum> *file2
//
// see parseChecksumLine for more detail on checksum file parsing
func (c *Client) extractChecksum(u *url.URL) (*fileChecksum, error) {
	q := u.Query()
	v := q.Get("checksum")

	if v == "" {
		return nil, nil
	}

	vs := strings.SplitN(v, ":", 2)
	switch len(vs) {
	case 2:
		break // good
	default:
		// here, we try to guess the checksum from it's length
		// if the type was not passed
		return newChecksumFromValue(v, filepath.Base(u.EscapedPath()))
	}

	checksumType, checksumValue := vs[0], vs[1]

	switch checksumType {
	case "file":
		return c.checksumFromFile(checksumValue, u)
	default:
		return newChecksumFromType(checksumType, checksumValue, filepath.Base(u.EscapedPath()))
	}
}

func newChecksum(checksumValue, filename string) (*fileChecksum, error) {
	c := &fileChecksum{
		Filename: filename,
	}
	var err error
	c.Value, err = hex.DecodeString(checksumValue)
	if err != nil {
		return nil, fmt.Errorf("invalid checksum: %s", err)
	}
	return c, nil
}

func newChecksumFromType(checksumType, checksumValue, filename string) (*fileChecksum, error) {
	c, err := newChecksum(checksumValue, filename)
	if err != nil {
		return nil, err
	}

	c.Type = strings.ToLower(checksumType)
	switch c.Type {
	case "md5":
		c.Hash = md5.New()
	case "sha1":
		c.Hash = sha1.New()
	case "sha256":
		c.Hash = sha256.New()
	case "sha512":
		c.Hash = sha512.New()
	default:
		return nil, fmt.Errorf(
			"unsupported checksum type: %s", checksumType)
	}

	return c, nil
}

func newChecksumFromValue(checksumValue, filename string) (*fileChecksum, error) {
	c, err := newChecksum(checksumValue, filename)
	if err != nil {
		return nil, err
	}

	switch len(c.Value) {
	case md5.Size:
		c.Hash = md5.New()
		c.Type = "md5"
	case sha1.Size:
		c.Hash = sha1.New()
		c.Type = "sha1"
	case sha256.Size:
		c.Hash = sha256.New()
		c.Type = "sha256"
	case sha512.Size:
		c.Hash = sha512.New()
		c.Type = "sha512"
	default:
		return nil, fmt.Errorf("Unknown type for checksum %s", checksumValue)
	}

	return c, nil
}

// checksumsFromFile will return all the fileChecksums found in file
//
// checksumsFromFile will try to guess the hashing algorithm based on content
// of checksum file
//
// checksumsFromFile will only return checksums for files that match file
// behind src
func (c *Client) checksumFromFile(checksumFile string, src *url.URL) (*fileChecksum, error) {
	checksumFileURL, err := urlhelper.Parse(checksumFile)
	if err != nil {
		return nil, err
	}

	tempfile, err := tmpFile("", filepath.Base(checksumFileURL.Path))
	if err != nil {
		return nil, err
	}
	defer func() {
		os.Remove(tempfile)
	}()

	c2 := &Client{
		Getters:       c.Getters,
		Decompressors: c.Decompressors,
		Detectors:     c.Detectors,
		Pwd:           c.Pwd,
		Dir:           false,
		Src:           checksumFile,
		Dst:           tempfile,
	}
	if err = c2.Get(); err != nil {
		return nil, fmt.Errorf(
			"Error downloading checksum file: %s", err)
	}

	filename := filepath.Base(src.Path)
	absPath, err := filepath.Abs(src.Path)
	if err != nil {
		return nil, err
	}
	relpath, err := filepath.Rel(filepath.Dir(checksumFileURL.Path), absPath)
	if err != nil {
		return nil, err
	}

	// possible file identifiers:
	options := []string{
		filename,       // ubuntu-14.04.1-server-amd64.iso
		"*" + filename, // *ubuntu-14.04.1-server-amd64.iso  Standard checksum
		"?" + filename, // ?ubuntu-14.04.1-server-amd64.iso  shasum -p
		relpath,        // dir/ubuntu-14.04.1-server-amd64.iso
		"./" + relpath, // ./dir/ubuntu-14.04.1-server-amd64.iso
		absPath,        // fullpath; set if local
	}

	f, err := os.Open(tempfile)
	if err != nil {
		return nil, fmt.Errorf(
			"Error opening downloaded file: %s", err)
	}
	defer f.Close()
	rd := bufio.NewReader(f)
	for {
		line, err := rd.ReadString('\n')
		if err != nil {
			if err != io.EOF {
				return nil, fmt.Errorf(
					"Error reading checksum file: %s", err)
			}
			break
		}
		checksum, err := parseChecksumLine(line)
		if err != nil || checksum == nil {
			continue
		}
		if checksum.Filename == "" {
			// filename not sure, let's try
			return checksum, nil
		}
		// make sure the checksum is for the right file
		for _, option := range options {
			if checksum.Filename == option {
				// any checksum will work so we return the first one
				return checksum, nil
			}
		}
	}
	return nil, fmt.Errorf("no checksum found in: %s", checksumFile)
}

// parseChecksumLine takes a line from a checksum file and returns
// checksumType, checksumValue and filename parseChecksumLine guesses the style
// of the checksum BSD vs GNU by splitting the line and by counting the parts.
// of a line.
// for BSD type sums parseChecksumLine guesses the hashing algorithm
// by checking the length of the checksum.
func parseChecksumLine(line string) (*fileChecksum, error) {
	parts := strings.Fields(line)

	switch len(parts) {
	case 4:
		// BSD-style checksum:
		//  MD5 (file1) = <checksum>
		//  MD5 (file2) = <checksum>
		if len(parts[1]) <= 2 ||
			parts[1][0] != '(' || parts[1][len(parts[1])-1] != ')' {
			return nil, fmt.Errorf(
				"Unexpected BSD-style-checksum filename format: %s", line)
		}
		filename := parts[1][1 : len(parts[1])-1]
		return newChecksumFromType(parts[0], parts[3], filename)
	case 2:
		// GNU-style:
		//  <checksum>  file1
		//  <checksum> *file2
		return newChecksumFromValue(parts[0], parts[1])
	case 0:
		return nil, nil // empty line
	default:
		return newChecksumFromValue(parts[0], "")
	}
}
<|endoftext|>


<commit_before>package hitGox

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
)

// User contains information about user.
type User struct {
	Followers         string `json:"followers,omitempty"`
	Videos            string `json:"videos,omitempty"`
	Recordings        string `json:"recordings,omitempty"`
	Teams             string `json:"teams,omitempty"`
	UserID            string `json:"user_id,omitempty"`
	UserName          string `json:"user_name,omitempty"`
	UserStatus        string `json:"user_status,omitempty"`
	UserLogo          string `json:"user_logo,omitempty"`
	UserCover         string `json:"user_cover,omitempty"`
	UserLogoSmall     string `json:"user_logo_small,omitempty"`
	UserIsBroadcaster bool   `json:"user_is_broadcaster"`
	UserEmail         string `json:"user_email,omitempty"`
	UserPartner       string `json:"user_partner,omitempty"`
	PartnerType       string `json:"partner_type,omitempty"`
	UserBetaProfile   string `json:"user_beta_profile,omitempty"`
	MediaIsLive       string `json:"media_is_live,omitempty"`
	MediaLiveSince    string `json:"media_live_since,omitempty"`
	UserMediaID       string `json:"user_media_id,omitempty"`
	TwitterAccount    string `json:"twitter_account,omitempty"`
	TwitterEnabled    string `json:"twitter_enabled,omitempty"`
	LivestreamCount   string `json:"livestream_count,omitempty"`
	TFAActive         string `json:"tfa_active,omitempty"`
	IsLive            string `json:"is_live,omitempty"`
	LiveSince         string `json:"live_since,omitempty"`
}

// GetUserObject return information about user.
//
// When a user isn’t found, this API returns a regular response but with all values containing null.
func GetUserObject(userName UserName, authToken AuthToken) (User, error) {
	var args fasthttp.Args

	// Returns private user details.
	args.Add("authToken", authToken.AuthToken)

	requestURL := fmt.Sprintf("%s/user/%s?%s", API, userName.UserName, args.String())
	_, body, err := fasthttp.Get(nil, requestURL)
	if err != nil {
		return User{}, err
	}
	var obj User
	if err = json.NewDecoder(bytes.NewReader(body)).Decode(&obj); err != nil {
		return User{}, err
	}
	return obj, nil
}
<commit_msg>✅ Approved getUserObject<commit_after>package hitGox

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
)

// User is about basic information about user.
//
// When a user isn’t found, this API returns a regular response but with all values containing null.
type User struct {
	Followers       string `json:"followers"`
	LivestreamCount string `json:"livestream_count"`
	MediaIsLive     string `json:"media_is_live"`
	MediaLiveSince  string `json:"media_live_since"`
	PartnerType     string `json:"partner_type"`
	Recordings      string `json:"recordings"`
	Teams           string `json:"teams"`
	TFAActive       string `json:"tfa_active"`
	TwitterAccount  string `json:"twitter_account"`
	TwitterEnabled  string `json:"twitter_enabled"`
	UserBetaProfile string `json:"user_beta_profile"`
	UserCover       string `json:"user_cover"`
	UserEmail       string `json:"user_email"`
	UserID          string `json:"user_id"`
	UserLogo        string `json:"user_logo"`
	UserLogoSmall   string `json:"user_logo_small"`
	UserMediaID     string `json:"user_media_id"`
	UserName        string `json:"user_name"`
	UserPartner     string `json:"user_partner"`
	UserStatus      string `json:"user_status"`
	Videos          string `json:"videos"`
}

// GetUserObject returns a regular response about user.
func GetUserObject(userName string, authToken string) (*User, error) {
	var args fasthttp.Args
	args.Add("authToken", authToken)

	url := fmt.Sprintf("%s/user/%s?%s", APIEndpoint, userName, args.String())
	_, body, err := fasthttp.Get(nil, url)
	if err != nil {
		return nil, err
	}

	var obj User
	if err = json.NewDecoder(bytes.NewReader(body)).Decode(&obj); err != nil {
		return nil, err
	}

	return &obj, nil
}
<|endoftext|>


<commit_before>package otaru

import (
	"compress/zlib"
	"io"
	"log"
)

const (
	INodeDBSnapshotBlobpath = "INODEDB_SNAPSHOT"
)

func (idb *INodeDB) SaveToBlobStore(bs RandomAccessBlobStore, c Cipher) error {
	raw, err := bs.Open(INodeDBSnapshotBlobpath, O_RDWR|O_CREATE)
	if err != nil {
		return err
	}
	if err := raw.Truncate(0); err != nil {
		return err
	}

	cio := NewChunkIOWithMetadata(raw, c, ChunkPrologue{
		OrigFilename: "*INODEDB_SNAPSHOT*",
		OrigOffset:   0,
	})
	zw := zlib.NewWriter(&OffsetWriter{cio, 0})
	if err := idb.SerializeSnapshot(zw); err != nil {
		return err
	}
	if err := zw.Close(); err != nil {
		return err
	}
	if err := cio.Close(); err != nil {
		return err
	}
	if err := raw.Close(); err != nil {
		return err
	}

	return nil
}

func LoadINodeDBFromBlobStore(bs RandomAccessBlobStore, c Cipher) (*INodeDB, error) {
	raw, err := bs.Open(INodeDBSnapshotBlobpath, O_RDONLY)
	if err != nil {
		return nil, err
	}

	cio := NewChunkIO(raw, c)
	log.Printf("serialized blob size: %d", cio.Size())
	zr, err := zlib.NewReader(&io.LimitedReader{&OffsetReader{cio, 0}, cio.Size()})
	if err != nil {
		return nil, err
	}
	log.Printf("LoadINodeDBFromBlobStore: zlib init success!")
	idb, err := DeserializeINodeDBSnapshot(zr)
	if err != nil {
		return nil, err
	}
	if err := zr.Close(); err != nil {
		return nil, err
	}
	if err := cio.Close(); err != nil {
		return nil, err
	}
	if err := raw.Close(); err != nil {
		return nil, err
	}

	return idb, nil
}
<commit_msg>buffer writes<commit_after>package otaru

import (
	"bufio"
	"compress/zlib"
	"io"
	"log"
)

const (
	INodeDBSnapshotBlobpath = "INODEDB_SNAPSHOT"
)

func (idb *INodeDB) SaveToBlobStore(bs RandomAccessBlobStore, c Cipher) error {
	raw, err := bs.Open(INodeDBSnapshotBlobpath, O_RDWR|O_CREATE)
	if err != nil {
		return err
	}
	if err := raw.Truncate(0); err != nil {
		return err
	}

	cio := NewChunkIOWithMetadata(raw, c, ChunkPrologue{
		OrigFilename: "*INODEDB_SNAPSHOT*",
		OrigOffset:   0,
	})
	bufio := bufio.NewWriter(&OffsetWriter{cio, 0})
	zw := zlib.NewWriter(bufio)
	if err := idb.SerializeSnapshot(zw); err != nil {
		return err
	}
	if err := zw.Close(); err != nil {
		return err
	}
	if err := bufio.Flush(); err != nil {
		return err
	}
	if err := cio.Close(); err != nil {
		return err
	}
	if err := raw.Close(); err != nil {
		return err
	}

	return nil
}

func LoadINodeDBFromBlobStore(bs RandomAccessBlobStore, c Cipher) (*INodeDB, error) {
	raw, err := bs.Open(INodeDBSnapshotBlobpath, O_RDONLY)
	if err != nil {
		return nil, err
	}

	cio := NewChunkIO(raw, c)
	log.Printf("serialized blob size: %d", cio.Size())
	zr, err := zlib.NewReader(&io.LimitedReader{&OffsetReader{cio, 0}, cio.Size()})
	if err != nil {
		return nil, err
	}
	log.Printf("LoadINodeDBFromBlobStore: zlib init success!")
	idb, err := DeserializeINodeDBSnapshot(zr)
	if err != nil {
		return nil, err
	}
	if err := zr.Close(); err != nil {
		return nil, err
	}
	if err := cio.Close(); err != nil {
		return nil, err
	}
	if err := raw.Close(); err != nil {
		return nil, err
	}

	return idb, nil
}
<|endoftext|>