<commit_before>// Copyright 2016 The Prometheus 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 prober

import (
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	pconfig "github.com/prometheus/common/config"

	"github.com/prometheus/blackbox_exporter/config"
)

func matchRegularExpressions(reader io.Reader, httpConfig config.HTTPProbe, logger log.Logger) bool {
	body, err := ioutil.ReadAll(reader)
	if err != nil {
		level.Error(logger).Log("msg", "Error reading HTTP body", "err", err)
		return false
	}
	for _, expression := range httpConfig.FailIfMatchesRegexp {
		re, err := regexp.Compile(expression)
		if err != nil {
			level.Error(logger).Log("msg", "Could not compile regular expression", "regexp", expression, "err", err)
			return false
		}
		if re.Match(body) {
			level.Error(logger).Log("msg", "Body matched regular expression", "regexp", expression)
			return false
		}
	}
	for _, expression := range httpConfig.FailIfNotMatchesRegexp {
		re, err := regexp.Compile(expression)
		if err != nil {
			level.Error(logger).Log("msg", "Could not compile regular expression", "regexp", expression, "err", err)
			return false
		}
		if !re.Match(body) {
			level.Error(logger).Log("msg", "Body did not match regular expression", "regexp", expression)
			return false
		}
	}
	return true
}

func ProbeHTTP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) {
	var redirects int
	var (
		contentLengthGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "content_length",
			Help: "Length of http content response",
		})

		redirectsGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_redirects",
			Help: "The number of redirects",
		})

		isSSLGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_ssl",
			Help: "Indicates if SSL was used for the final redirect",
		})

		statusCodeGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_status_code",
			Help: "Response HTTP status code",
		})

		probeSSLEarliestCertExpiryGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_ssl_earliest_cert_expiry",
			Help: "Returns earliest SSL cert expiry in unixtime",
		})

		probeHTTPVersionGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_version",
			Help: "Returns the version of HTTP of the probe response",
		})

		probeFailedDueToRegex = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_failed_due_to_regex",
			Help: "Indicates if probe failed due to regex",
		})
	)

	registry.MustRegister(contentLengthGauge)
	registry.MustRegister(redirectsGauge)
	registry.MustRegister(isSSLGauge)
	registry.MustRegister(statusCodeGauge)
	registry.MustRegister(probeHTTPVersionGauge)
	registry.MustRegister(probeFailedDueToRegex)

	httpConfig := module.HTTP

	if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") {
		target = "http://" + target
	}

	targetURL, err := url.Parse(target)
	if err != nil {
		level.Error(logger).Log("msg", "Could not parse target URL", "err", err)
		return false
	}
	targetHost, targetPort, err := net.SplitHostPort(targetURL.Host)
	// If split fails, assuming it's a hostname without port part.
	if err != nil {
		targetHost = targetURL.Host
	}

	ip, err := chooseProtocol(module.HTTP.PreferredIPProtocol, targetHost, registry, logger)
	if err != nil {
		level.Error(logger).Log("msg", "Error resolving address", "err", err)
		return false
	}

	httpClientConfig := &module.HTTP.HTTPClientConfig

	client, err := pconfig.NewHTTPClientFromConfig(httpClientConfig)
	if err != nil {
		level.Error(logger).Log("msg", "Error generating HTTP client", "err", err)
		return false
	}

	client.CheckRedirect = func(r *http.Request, via []*http.Request) error {
		level.Info(logger).Log("msg", "Received redirect", "url", r.URL.String())
		redirects = len(via)
		if redirects > 10 || httpConfig.NoFollowRedirects {
			level.Info(logger).Log("msg", "Not following redirect")
			return errors.New("Don't follow redirects")
		}
		return nil
	}

	if httpConfig.Method == "" {
		httpConfig.Method = "GET"
	}

	request, err := http.NewRequest(httpConfig.Method, target, nil)
	request.Host = targetURL.Host
	request = request.WithContext(ctx)
	if targetPort == "" {
		targetURL.Host = ip.String()
	} else {
		targetURL.Host = net.JoinHostPort(ip.String(), targetPort)
	}

	if err != nil {
		level.Error(logger).Log("msg", "Error creating request", "err", err)
		return
	}

	for key, value := range httpConfig.Headers {
		if strings.Title(key) == "Host" {
			request.Host = value
			continue
		}
		request.Header.Set(key, value)
	}

	// If a body is configured, add it to the request.
	if httpConfig.Body != "" {
		request.Body = ioutil.NopCloser(strings.NewReader(httpConfig.Body))
	}
	level.Info(logger).Log("msg", "Making HTTP request", "url", request.URL.String())
	resp, err := client.Do(request)
	// Err won't be nil if redirects were turned off. See https://github.com/golang/go/issues/3795
	if err != nil && resp == nil {
		level.Error(logger).Log("msg", "Error for HTTP request", "err", err)
	} else {
		defer resp.Body.Close()
		level.Info(logger).Log("msg", "Received HTTP response", "status_code", resp.StatusCode)
		if len(httpConfig.ValidStatusCodes) != 0 {
			for _, code := range httpConfig.ValidStatusCodes {
				if resp.StatusCode == code {
					success = true
					break
				}
			}
			if !success {
				level.Info(logger).Log("msg", "Invalid HTTP response status code", "status_code", resp.StatusCode,
					"valid_status_codes", fmt.Sprintf("%v", httpConfig.ValidStatusCodes))
			}
		} else if 200 <= resp.StatusCode && resp.StatusCode < 300 {
			success = true
		} else {
			level.Info(logger).Log("msg", "Invalid HTTP response status code, wanted 2xx", "status_code", resp.StatusCode)
		}

		if success && (len(httpConfig.FailIfMatchesRegexp) > 0 || len(httpConfig.FailIfNotMatchesRegexp) > 0) {
			success = matchRegularExpressions(resp.Body, httpConfig, logger)
			if success {
				probeFailedDueToRegex.Set(0)
			} else {
				probeFailedDueToRegex.Set(1)
			}
		}

		var httpVersionNumber float64
		httpVersionNumber, err = strconv.ParseFloat(strings.TrimPrefix(resp.Proto, "HTTP/"), 64)
		if err != nil {
			level.Error(logger).Log("msg", "Error parsing version number from HTTP version", "err", err)
		}
		probeHTTPVersionGauge.Set(httpVersionNumber)

		if len(httpConfig.ValidHTTPVersions) != 0 {
			found := false
			for _, version := range httpConfig.ValidHTTPVersions {
				if version == resp.Proto {
					found = true
					break
				}
			}
			if !found {
				level.Error(logger).Log("msg", "Invalid HTTP version number", "version", httpVersionNumber)
				success = false
			}
		}

	}

	if resp == nil {
		resp = &http.Response{}
	}

	if resp.TLS != nil {
		isSSLGauge.Set(float64(1))
		registry.MustRegister(probeSSLEarliestCertExpiryGauge)
		probeSSLEarliestCertExpiryGauge.Set(float64(getEarliestCertExpiry(resp.TLS).UnixNano() / 1e9))
		if httpConfig.FailIfSSL {
			level.Error(logger).Log("msg", "Final request was over SSL")
			success = false
		}
	} else if httpConfig.FailIfNotSSL {
		level.Error(logger).Log("msg", "Final request was not over SSL")
		success = false
	}

	statusCodeGauge.Set(float64(resp.StatusCode))
	contentLengthGauge.Set(float64(resp.ContentLength))
	redirectsGauge.Set(float64(redirects))
	return
}
<commit_msg>Fix http requests to actually use the resolved ip<commit_after>// Copyright 2016 The Prometheus 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 prober

import (
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	pconfig "github.com/prometheus/common/config"

	"github.com/prometheus/blackbox_exporter/config"
)

func matchRegularExpressions(reader io.Reader, httpConfig config.HTTPProbe, logger log.Logger) bool {
	body, err := ioutil.ReadAll(reader)
	if err != nil {
		level.Error(logger).Log("msg", "Error reading HTTP body", "err", err)
		return false
	}
	for _, expression := range httpConfig.FailIfMatchesRegexp {
		re, err := regexp.Compile(expression)
		if err != nil {
			level.Error(logger).Log("msg", "Could not compile regular expression", "regexp", expression, "err", err)
			return false
		}
		if re.Match(body) {
			level.Error(logger).Log("msg", "Body matched regular expression", "regexp", expression)
			return false
		}
	}
	for _, expression := range httpConfig.FailIfNotMatchesRegexp {
		re, err := regexp.Compile(expression)
		if err != nil {
			level.Error(logger).Log("msg", "Could not compile regular expression", "regexp", expression, "err", err)
			return false
		}
		if !re.Match(body) {
			level.Error(logger).Log("msg", "Body did not match regular expression", "regexp", expression)
			return false
		}
	}
	return true
}

func ProbeHTTP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) {
	var redirects int
	var (
		contentLengthGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "content_length",
			Help: "Length of http content response",
		})

		redirectsGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_redirects",
			Help: "The number of redirects",
		})

		isSSLGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_ssl",
			Help: "Indicates if SSL was used for the final redirect",
		})

		statusCodeGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_status_code",
			Help: "Response HTTP status code",
		})

		probeSSLEarliestCertExpiryGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_ssl_earliest_cert_expiry",
			Help: "Returns earliest SSL cert expiry in unixtime",
		})

		probeHTTPVersionGauge = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_http_version",
			Help: "Returns the version of HTTP of the probe response",
		})

		probeFailedDueToRegex = prometheus.NewGauge(prometheus.GaugeOpts{
			Name: "probe_failed_due_to_regex",
			Help: "Indicates if probe failed due to regex",
		})
	)

	registry.MustRegister(contentLengthGauge)
	registry.MustRegister(redirectsGauge)
	registry.MustRegister(isSSLGauge)
	registry.MustRegister(statusCodeGauge)
	registry.MustRegister(probeHTTPVersionGauge)
	registry.MustRegister(probeFailedDueToRegex)

	httpConfig := module.HTTP

	if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") {
		target = "http://" + target
	}

	targetURL, err := url.Parse(target)
	if err != nil {
		level.Error(logger).Log("msg", "Could not parse target URL", "err", err)
		return false
	}
	targetHost, targetPort, err := net.SplitHostPort(targetURL.Host)
	// If split fails, assuming it's a hostname without port part.
	if err != nil {
		targetHost = targetURL.Host
	}

	ip, err := chooseProtocol(module.HTTP.PreferredIPProtocol, targetHost, registry, logger)
	if err != nil {
		level.Error(logger).Log("msg", "Error resolving address", "err", err)
		return false
	}

	httpClientConfig := &module.HTTP.HTTPClientConfig

	client, err := pconfig.NewHTTPClientFromConfig(httpClientConfig)
	if err != nil {
		level.Error(logger).Log("msg", "Error generating HTTP client", "err", err)
		return false
	}

	client.CheckRedirect = func(r *http.Request, via []*http.Request) error {
		level.Info(logger).Log("msg", "Received redirect", "url", r.URL.String())
		redirects = len(via)
		if redirects > 10 || httpConfig.NoFollowRedirects {
			level.Info(logger).Log("msg", "Not following redirect")
			return errors.New("Don't follow redirects")
		}
		return nil
	}

	if httpConfig.Method == "" {
		httpConfig.Method = "GET"
	}

	// Replace the host field in the URL with the IP we resolved.
	origHost := targetURL.Host
	if targetPort == "" {
		targetURL.Host = "[" + ip.String() + "]"
	} else {
		targetURL.Host = net.JoinHostPort(ip.String(), targetPort)
	}
	request, err := http.NewRequest(httpConfig.Method, targetURL.String(), nil)
	request.Host = origHost
	request = request.WithContext(ctx)
	if err != nil {
		level.Error(logger).Log("msg", "Error creating request", "err", err)
		return
	}

	for key, value := range httpConfig.Headers {
		if strings.Title(key) == "Host" {
			request.Host = value
			continue
		}
		request.Header.Set(key, value)
	}

	// If a body is configured, add it to the request.
	if httpConfig.Body != "" {
		request.Body = ioutil.NopCloser(strings.NewReader(httpConfig.Body))
	}
	level.Info(logger).Log("msg", "Making HTTP request", "url", request.URL.String(), "host", request.Host)
	resp, err := client.Do(request)
	// Err won't be nil if redirects were turned off. See https://github.com/golang/go/issues/3795
	if err != nil && resp == nil {
		level.Error(logger).Log("msg", "Error for HTTP request", "err", err)
	} else {
		defer resp.Body.Close()
		level.Info(logger).Log("msg", "Received HTTP response", "status_code", resp.StatusCode)
		if len(httpConfig.ValidStatusCodes) != 0 {
			for _, code := range httpConfig.ValidStatusCodes {
				if resp.StatusCode == code {
					success = true
					break
				}
			}
			if !success {
				level.Info(logger).Log("msg", "Invalid HTTP response status code", "status_code", resp.StatusCode,
					"valid_status_codes", fmt.Sprintf("%v", httpConfig.ValidStatusCodes))
			}
		} else if 200 <= resp.StatusCode && resp.StatusCode < 300 {
			success = true
		} else {
			level.Info(logger).Log("msg", "Invalid HTTP response status code, wanted 2xx", "status_code", resp.StatusCode)
		}

		if success && (len(httpConfig.FailIfMatchesRegexp) > 0 || len(httpConfig.FailIfNotMatchesRegexp) > 0) {
			success = matchRegularExpressions(resp.Body, httpConfig, logger)
			if success {
				probeFailedDueToRegex.Set(0)
			} else {
				probeFailedDueToRegex.Set(1)
			}
		}

		var httpVersionNumber float64
		httpVersionNumber, err = strconv.ParseFloat(strings.TrimPrefix(resp.Proto, "HTTP/"), 64)
		if err != nil {
			level.Error(logger).Log("msg", "Error parsing version number from HTTP version", "err", err)
		}
		probeHTTPVersionGauge.Set(httpVersionNumber)

		if len(httpConfig.ValidHTTPVersions) != 0 {
			found := false
			for _, version := range httpConfig.ValidHTTPVersions {
				if version == resp.Proto {
					found = true
					break
				}
			}
			if !found {
				level.Error(logger).Log("msg", "Invalid HTTP version number", "version", httpVersionNumber)
				success = false
			}
		}

	}

	if resp == nil {
		resp = &http.Response{}
	}

	if resp.TLS != nil {
		isSSLGauge.Set(float64(1))
		registry.MustRegister(probeSSLEarliestCertExpiryGauge)
		probeSSLEarliestCertExpiryGauge.Set(float64(getEarliestCertExpiry(resp.TLS).UnixNano() / 1e9))
		if httpConfig.FailIfSSL {
			level.Error(logger).Log("msg", "Final request was over SSL")
			success = false
		}
	} else if httpConfig.FailIfNotSSL {
		level.Error(logger).Log("msg", "Final request was not over SSL")
		success = false
	}

	statusCodeGauge.Set(float64(resp.StatusCode))
	contentLengthGauge.Set(float64(resp.ContentLength))
	redirectsGauge.Set(float64(redirects))
	return
}
<|endoftext|>


<commit_before>// Copyright 2016 The Prometheus 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 prober

import (
	"bytes"
	"context"
	"math/rand"
	"net"
	"os"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"

	"github.com/prometheus/blackbox_exporter/config"
)

var (
	icmpID            int
	icmpSequence      uint16
	icmpSequenceMutex sync.Mutex
)

func init() {
	// PID is typically 1 when running in a container; in that case, set
	// the ICMP echo ID to a random value to avoid potential clashes with
	// other blackbox_exporter instances. See #411.
	if pid := os.Getpid(); pid == 1 {
		icmpID = rand.Intn(1 << 16)
	} else {
		icmpID = pid & 0xffff
	}

	// Start the ICMP echo sequence at a random offset to prevent them from
	// being in sync when several blackbox_exporter instances are restarted
	// at the same time. See #411.
	icmpSequence = uint16(rand.Intn(1 << 16))
}

func getICMPSequence() uint16 {
	icmpSequenceMutex.Lock()
	defer icmpSequenceMutex.Unlock()
	icmpSequence++
	return icmpSequence
}

func ProbeICMP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) {
	var (
		socket      net.PacketConn
		requestType icmp.Type
		replyType   icmp.Type

		durationGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Name: "probe_icmp_duration_seconds",
			Help: "Duration of icmp request by phase",
		}, []string{"phase"})
	)

	for _, lv := range []string{"resolve", "setup", "rtt"} {
		durationGaugeVec.WithLabelValues(lv)
	}

	registry.MustRegister(durationGaugeVec)

	ip, lookupTime, err := chooseProtocol(ctx, module.ICMP.IPProtocol, module.ICMP.IPProtocolFallback, target, registry, logger)
	if err != nil {
		level.Warn(logger).Log("msg", "Error resolving address", "err", err)
		return false
	}
	durationGaugeVec.WithLabelValues("resolve").Add(lookupTime)

	var srcIP net.IP
	if len(module.ICMP.SourceIPAddress) > 0 {
		if srcIP = net.ParseIP(module.ICMP.SourceIPAddress); srcIP == nil {
			level.Error(logger).Log("msg", "Error parsing source ip address", "srcIP", module.ICMP.SourceIPAddress)
			return false
		}
		level.Info(logger).Log("msg", "Using source address", "srcIP", srcIP)
	}

	setupStart := time.Now()
	level.Info(logger).Log("msg", "Creating socket")
	if ip.IP.To4() == nil {
		requestType = ipv6.ICMPTypeEchoRequest
		replyType = ipv6.ICMPTypeEchoReply

		if srcIP == nil {
			srcIP = net.ParseIP("::")
		}
		icmpConn, err := icmp.ListenPacket("ip6:ipv6-icmp", srcIP.String())
		if err != nil {
			level.Error(logger).Log("msg", "Error listening to socket", "err", err)
			return
		}

		socket = icmpConn
	} else {
		requestType = ipv4.ICMPTypeEcho
		replyType = ipv4.ICMPTypeEchoReply

		if srcIP == nil {
			srcIP = net.ParseIP("0.0.0.0")
		}
		icmpConn, err := net.ListenPacket("ip4:icmp", srcIP.String())
		if err != nil {
			level.Error(logger).Log("msg", "Error listening to socket", "err", err)
			return
		}

		if module.ICMP.DontFragment {
			rc, err := ipv4.NewRawConn(icmpConn)
			if err != nil {
				level.Error(logger).Log("msg", "Error creating raw connection", "err", err)
				return
			}
			socket = &v4Conn{c: rc, df: true}
		} else {
			socket = icmpConn
		}
	}

	defer socket.Close()

	var data []byte
	if module.ICMP.PayloadSize != 0 {
		data = make([]byte, module.ICMP.PayloadSize)
		copy(data, "Prometheus Blackbox Exporter")
	} else {
		data = []byte("Prometheus Blackbox Exporter")
	}

	body := &icmp.Echo{
		ID:   icmpID,
		Seq:  int(getICMPSequence()),
		Data: data,
	}
	level.Info(logger).Log("msg", "Creating ICMP packet", "seq", body.Seq, "id", body.ID)
	wm := icmp.Message{
		Type: requestType,
		Code: 0,
		Body: body,
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		level.Error(logger).Log("msg", "Error marshalling packet", "err", err)
		return
	}
	durationGaugeVec.WithLabelValues("setup").Add(time.Since(setupStart).Seconds())
	level.Info(logger).Log("msg", "Writing out packet")
	rttStart := time.Now()
	if _, err = socket.WriteTo(wb, ip); err != nil {
		level.Warn(logger).Log("msg", "Error writing to socket", "err", err)
		return
	}

	// Reply should be the same except for the message type.
	wm.Type = replyType
	wb, err = wm.Marshal(nil)
	if err != nil {
		level.Error(logger).Log("msg", "Error marshalling packet", "err", err)
		return
	}

	rb := make([]byte, 65536)
	deadline, _ := ctx.Deadline()
	if err := socket.SetReadDeadline(deadline); err != nil {
		level.Error(logger).Log("msg", "Error setting socket deadline", "err", err)
		return
	}
	level.Info(logger).Log("msg", "Waiting for reply packets")
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				level.Warn(logger).Log("msg", "Timeout reading from socket", "err", err)
				return
			}
			level.Error(logger).Log("msg", "Error reading from socket", "err", err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		if replyType == ipv6.ICMPTypeEchoReply {
			// Clear checksum to make comparison succeed.
			rb[2] = 0
			rb[3] = 0
		}
		if bytes.Equal(rb[:n], wb) {
			durationGaugeVec.WithLabelValues("rtt").Add(time.Since(rttStart).Seconds())
			level.Info(logger).Log("msg", "Found matching reply packet")
			return true
		}
	}
}

type v4Conn struct {
	c *ipv4.RawConn

	df  bool
	src net.IP
}

func (c *v4Conn) ReadFrom(b []byte) (int, net.Addr, error) {
	h, p, _, err := c.c.ReadFrom(b)
	if err != nil {
		return 0, nil, err
	}

	copy(b, p)
	n := len(b)
	if len(p) < len(b) {
		n = len(p)
	}
	return n, &net.IPAddr{IP: h.Src}, nil
}

func (d *v4Conn) WriteTo(b []byte, addr net.Addr) (int, error) {
	ipAddr, err := net.ResolveIPAddr(addr.Network(), addr.String())
	if err != nil {
		return 0, err
	}

	header := &ipv4.Header{
		Version:  ipv4.Version,
		Len:      ipv4.HeaderLen,
		Protocol: 1,
		TotalLen: ipv4.HeaderLen + len(b),
		TTL:      64,
		Dst:      ipAddr.IP,
		Src:      d.src,
	}

	if d.df {
		header.Flags |= ipv4.DontFragment
	}

	return len(b), d.c.WriteTo(header, b, nil)
}

func (d *v4Conn) Close() error {
	return d.c.Close()
}

func (d *v4Conn) LocalAddr() net.Addr {
	return nil
}

func (d *v4Conn) SetDeadline(t time.Time) error {
	return d.c.SetDeadline(t)
}

func (d *v4Conn) SetReadDeadline(t time.Time) error {
	return d.c.SetReadDeadline(t)
}

func (d *v4Conn) SetWriteDeadline(t time.Time) error {
	return d.c.SetWriteDeadline(t)
}
<commit_msg>Seed RNG to ensure different ICMP ids. (#638)<commit_after>// Copyright 2016 The Prometheus 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 prober

import (
	"bytes"
	"context"
	"math/rand"
	"net"
	"os"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"

	"github.com/prometheus/blackbox_exporter/config"
)

var (
	icmpID            int
	icmpSequence      uint16
	icmpSequenceMutex sync.Mutex
)

func init() {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	// PID is typically 1 when running in a container; in that case, set
	// the ICMP echo ID to a random value to avoid potential clashes with
	// other blackbox_exporter instances. See #411.
	if pid := os.Getpid(); pid == 1 {
		icmpID = r.Intn(1 << 16)
	} else {
		icmpID = pid & 0xffff
	}

	// Start the ICMP echo sequence at a random offset to prevent them from
	// being in sync when several blackbox_exporter instances are restarted
	// at the same time. See #411.
	icmpSequence = uint16(r.Intn(1 << 16))
}

func getICMPSequence() uint16 {
	icmpSequenceMutex.Lock()
	defer icmpSequenceMutex.Unlock()
	icmpSequence++
	return icmpSequence
}

func ProbeICMP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger log.Logger) (success bool) {
	var (
		socket      net.PacketConn
		requestType icmp.Type
		replyType   icmp.Type

		durationGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Name: "probe_icmp_duration_seconds",
			Help: "Duration of icmp request by phase",
		}, []string{"phase"})
	)

	for _, lv := range []string{"resolve", "setup", "rtt"} {
		durationGaugeVec.WithLabelValues(lv)
	}

	registry.MustRegister(durationGaugeVec)

	ip, lookupTime, err := chooseProtocol(ctx, module.ICMP.IPProtocol, module.ICMP.IPProtocolFallback, target, registry, logger)
	if err != nil {
		level.Warn(logger).Log("msg", "Error resolving address", "err", err)
		return false
	}
	durationGaugeVec.WithLabelValues("resolve").Add(lookupTime)

	var srcIP net.IP
	if len(module.ICMP.SourceIPAddress) > 0 {
		if srcIP = net.ParseIP(module.ICMP.SourceIPAddress); srcIP == nil {
			level.Error(logger).Log("msg", "Error parsing source ip address", "srcIP", module.ICMP.SourceIPAddress)
			return false
		}
		level.Info(logger).Log("msg", "Using source address", "srcIP", srcIP)
	}

	setupStart := time.Now()
	level.Info(logger).Log("msg", "Creating socket")
	if ip.IP.To4() == nil {
		requestType = ipv6.ICMPTypeEchoRequest
		replyType = ipv6.ICMPTypeEchoReply

		if srcIP == nil {
			srcIP = net.ParseIP("::")
		}
		icmpConn, err := icmp.ListenPacket("ip6:ipv6-icmp", srcIP.String())
		if err != nil {
			level.Error(logger).Log("msg", "Error listening to socket", "err", err)
			return
		}

		socket = icmpConn
	} else {
		requestType = ipv4.ICMPTypeEcho
		replyType = ipv4.ICMPTypeEchoReply

		if srcIP == nil {
			srcIP = net.ParseIP("0.0.0.0")
		}
		icmpConn, err := net.ListenPacket("ip4:icmp", srcIP.String())
		if err != nil {
			level.Error(logger).Log("msg", "Error listening to socket", "err", err)
			return
		}

		if module.ICMP.DontFragment {
			rc, err := ipv4.NewRawConn(icmpConn)
			if err != nil {
				level.Error(logger).Log("msg", "Error creating raw connection", "err", err)
				return
			}
			socket = &v4Conn{c: rc, df: true}
		} else {
			socket = icmpConn
		}
	}

	defer socket.Close()

	var data []byte
	if module.ICMP.PayloadSize != 0 {
		data = make([]byte, module.ICMP.PayloadSize)
		copy(data, "Prometheus Blackbox Exporter")
	} else {
		data = []byte("Prometheus Blackbox Exporter")
	}

	body := &icmp.Echo{
		ID:   icmpID,
		Seq:  int(getICMPSequence()),
		Data: data,
	}
	level.Info(logger).Log("msg", "Creating ICMP packet", "seq", body.Seq, "id", body.ID)
	wm := icmp.Message{
		Type: requestType,
		Code: 0,
		Body: body,
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		level.Error(logger).Log("msg", "Error marshalling packet", "err", err)
		return
	}
	durationGaugeVec.WithLabelValues("setup").Add(time.Since(setupStart).Seconds())
	level.Info(logger).Log("msg", "Writing out packet")
	rttStart := time.Now()
	if _, err = socket.WriteTo(wb, ip); err != nil {
		level.Warn(logger).Log("msg", "Error writing to socket", "err", err)
		return
	}

	// Reply should be the same except for the message type.
	wm.Type = replyType
	wb, err = wm.Marshal(nil)
	if err != nil {
		level.Error(logger).Log("msg", "Error marshalling packet", "err", err)
		return
	}

	rb := make([]byte, 65536)
	deadline, _ := ctx.Deadline()
	if err := socket.SetReadDeadline(deadline); err != nil {
		level.Error(logger).Log("msg", "Error setting socket deadline", "err", err)
		return
	}
	level.Info(logger).Log("msg", "Waiting for reply packets")
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				level.Warn(logger).Log("msg", "Timeout reading from socket", "err", err)
				return
			}
			level.Error(logger).Log("msg", "Error reading from socket", "err", err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		if replyType == ipv6.ICMPTypeEchoReply {
			// Clear checksum to make comparison succeed.
			rb[2] = 0
			rb[3] = 0
		}
		if bytes.Equal(rb[:n], wb) {
			durationGaugeVec.WithLabelValues("rtt").Add(time.Since(rttStart).Seconds())
			level.Info(logger).Log("msg", "Found matching reply packet")
			return true
		}
	}
}

type v4Conn struct {
	c *ipv4.RawConn

	df  bool
	src net.IP
}

func (c *v4Conn) ReadFrom(b []byte) (int, net.Addr, error) {
	h, p, _, err := c.c.ReadFrom(b)
	if err != nil {
		return 0, nil, err
	}

	copy(b, p)
	n := len(b)
	if len(p) < len(b) {
		n = len(p)
	}
	return n, &net.IPAddr{IP: h.Src}, nil
}

func (d *v4Conn) WriteTo(b []byte, addr net.Addr) (int, error) {
	ipAddr, err := net.ResolveIPAddr(addr.Network(), addr.String())
	if err != nil {
		return 0, err
	}

	header := &ipv4.Header{
		Version:  ipv4.Version,
		Len:      ipv4.HeaderLen,
		Protocol: 1,
		TotalLen: ipv4.HeaderLen + len(b),
		TTL:      64,
		Dst:      ipAddr.IP,
		Src:      d.src,
	}

	if d.df {
		header.Flags |= ipv4.DontFragment
	}

	return len(b), d.c.WriteTo(header, b, nil)
}

func (d *v4Conn) Close() error {
	return d.c.Close()
}

func (d *v4Conn) LocalAddr() net.Addr {
	return nil
}

func (d *v4Conn) SetDeadline(t time.Time) error {
	return d.c.SetDeadline(t)
}

func (d *v4Conn) SetReadDeadline(t time.Time) error {
	return d.c.SetReadDeadline(t)
}

func (d *v4Conn) SetWriteDeadline(t time.Time) error {
	return d.c.SetWriteDeadline(t)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"math"
	"math/big"
)

const targetBits = 24

// ProofOfWork represents a proof-of-work
type ProofOfWork struct {
	block  *Block
	target *big.Int
}

func NewProofOfWork(b *Block) *ProofOfWork {
	target := big.NewInt(1)
	target.Lsh(target, uint(256-targetBits))

	pow := &ProofOfWork{b, target}

	return pow
}

func (pow *ProofOfWork) prepareData(nonce int) []byte {
	data := bytes.Join(
		[][]byte{
			pow.block.PrevBlockHash,
			pow.block.Data,
			IntToHex(pow.block.TimeStamp),
			IntToHex(int64(targetBits)),
			IntToHex(int64(nonce)),
		},
		[]byte{},
	)

	return data
}

// Run performs a proof-of-work
func (pow *ProofOfWork) Run() (int, []byte) {
	var hashInt big.Int
	var hash [32]byte
	nonce := 0

	fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data)
	for nonce < math.MaxInt32 {
		data := pow.prepareData(nonce)

		hash = sha256.Sum256(data)
		fmt.Printf("\r%x", hash)
		hashInt.SetBytes(hash[:])

		if hashInt.Cmp(pow.target) == -1 {
			break
		} else {
			nonce++
		}
	}
	fmt.Print("\n\n")

	return nonce, hash[:]
}
<commit_msg>change the maxInt64 constant<commit_after>package main

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"math/big"
)

const targetBits = 24

// ProofOfWork represents a proof-of-work
type ProofOfWork struct {
	block  *Block
	target *big.Int
}

func NewProofOfWork(b *Block) *ProofOfWork {
	target := big.NewInt(1)
	target.Lsh(target, uint(256-targetBits))

	pow := &ProofOfWork{b, target}

	return pow
}

func (pow *ProofOfWork) prepareData(nonce int) []byte {
	data := bytes.Join(
		[][]byte{
			pow.block.PrevBlockHash,
			pow.block.Data,
			IntToHex(pow.block.TimeStamp),
			IntToHex(int64(targetBits)),
			IntToHex(int64(nonce)),
		},
		[]byte{},
	)

	return data
}

// Run performs a proof-of-work
func (pow *ProofOfWork) Run() (int, []byte) {
	var hashInt big.Int
	var hash [32]byte
	nonce := 0

	maxInt := 2 ^ 63 - 1

	fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data)
	for nonce < maxInt {
		data := pow.prepareData(nonce)

		hash = sha256.Sum256(data)
		fmt.Printf("\r%x", hash)
		hashInt.SetBytes(hash[:])

		if hashInt.Cmp(pow.target) == -1 {
			break
		} else {
			nonce++
		}
	}
	fmt.Print("\n\n")

	return nonce, hash[:]
}
<|endoftext|>


<commit_before>package Common

import (
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"time"
)

// zero size, empty struct
type Empty struct{}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

// parse flag and print usage/value to writer
func Init(writer io.Writer) {
	flag.Parse()

	if writer == nil {
		return
	}

	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(writer, "#%s : %s\n", f.Name, f.Usage)
	})

	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(writer, "-%s=%v \\\n", f.Name, f.Value)
	})
}

// check panic when exit
func CheckPanic() {
	if err := recover(); err != nil {
		fmt.Fprintf(os.Stderr, "\n%v\n", err)

		for skip := 1; ; skip++ {
			if pc, file, line, ok := runtime.Caller(skip); ok {
				fn := runtime.FuncForPC(pc).Name()
				fmt.Fprintf(os.Stderr, "%v %v %v:%v\n",
					FormatNow(), fn, path.Base(file), line)
			} else {
				break
			}
		}
	}
}

// hash : []byte to uint64
func Hash(mem []byte) uint64 {
	var hash uint64 = 5381

	for _, b := range mem {
		hash = (hash << 5) + hash + uint64(b)
	}

	return hash
}

// format a time.Time to string as 2006-01-02 15:04:05.999
func FormatTime(t time.Time) string {
	return t.Format("2006-01-02 15:04:05.999")
}

// format time.Now() use FormatTime
func FormatNow() string {
	return FormatTime(time.Now())
}

// parse a string as "2006-01-02 15:04:05.999" to time.Time
func ParseTime(s string) (time.Time, error) {
	return time.ParseInLocation("2006-01-02 15:04:05.999", s, time.Local)
}

// format a time.Time to number as 20060102150405999
func NumberTime(t time.Time) uint64 {
	return uint64(t.UnixNano()/1000000)%1000 +
		uint64(t.Second())*1000 +
		uint64(t.Minute())*100000 +
		uint64(t.Hour())*10000000 +
		uint64(t.Day())*1000000000 +
		uint64(t.Month())*100000000000 +
		uint64(t.Year())*10000000000000
}

// create a uuid string
func NewUUID() string {
	u := [16]byte{}
	rand.Read(u[:])
	u[8] = (u[8] | 0x40) & 0x7F
	u[6] = (u[6] & 0xF) | (4 << 4)
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
}
<commit_msg>add time print<commit_after>package Common

import (
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"time"
)

// zero size, empty struct
type Empty struct{}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

// parse flag and print usage/value to writer
func Init(writer io.Writer) {
	flag.Parse()

	if writer == nil {
		return
	}

	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(writer, "#%s : %s\n", f.Name, f.Usage)
	})

	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(writer, "-%s=%v \\\n", f.Name, f.Value)
	})
}

// check panic when exit
func CheckPanic() {
	if err := recover(); err != nil {
		fmt.Fprintf(os.Stderr, "\n%v %v\n", FormatNow(), err)

		for skip := 1; ; skip++ {
			if pc, file, line, ok := runtime.Caller(skip); ok {
				fn := runtime.FuncForPC(pc).Name()
				fmt.Fprintf(os.Stderr, "%v %v %v:%v\n",
					FormatNow(), fn, path.Base(file), line)
			} else {
				break
			}
		}
	}
}

// hash : []byte to uint64
func Hash(mem []byte) uint64 {
	var hash uint64 = 5381

	for _, b := range mem {
		hash = (hash << 5) + hash + uint64(b)
	}

	return hash
}

// format a time.Time to string as 2006-01-02 15:04:05.999
func FormatTime(t time.Time) string {
	return t.Format("2006-01-02 15:04:05.999")
}

// format time.Now() use FormatTime
func FormatNow() string {
	return FormatTime(time.Now())
}

// parse a string as "2006-01-02 15:04:05.999" to time.Time
func ParseTime(s string) (time.Time, error) {
	return time.ParseInLocation("2006-01-02 15:04:05.999", s, time.Local)
}

// format a time.Time to number as 20060102150405999
func NumberTime(t time.Time) uint64 {
	return uint64(t.UnixNano()/1000000)%1000 +
		uint64(t.Second())*1000 +
		uint64(t.Minute())*100000 +
		uint64(t.Hour())*10000000 +
		uint64(t.Day())*1000000000 +
		uint64(t.Month())*100000000000 +
		uint64(t.Year())*10000000000000
}

// create a uuid string
func NewUUID() string {
	u := [16]byte{}
	rand.Read(u[:])
	u[8] = (u[8] | 0x40) & 0x7F
	u[6] = (u[6] & 0xF) | (4 << 4)
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
}
<|endoftext|>


<commit_before>// Copyright 2020 DSR Corporation
//
// 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"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"

	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

type Certificate struct {
	Issuer         string
	SerialNumber   string
	Subject        string
	SubjectKeyID   string
	AuthorityKeyID string
	Certificate    *x509.Certificate
}

func DecodeX509Certificate(pemCertificate string) (*Certificate, error) {
	block, _ := pem.Decode([]byte(pemCertificate))
	if block == nil {
		return nil, types.NewErrInvalidCertificate("Could not decode pem certificate")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, types.NewErrInvalidCertificate(fmt.Sprintf("Could not parse certificate: %v", err.Error()))
	}

	certificate := Certificate{
		Issuer:         cert.Issuer.String(),
		SerialNumber:   cert.SerialNumber.String(),
		Subject:        cert.Subject.String(),
		SubjectKeyID:   BytesToHex(cert.SubjectKeyId),
		AuthorityKeyID: BytesToHex(cert.AuthorityKeyId),
		Certificate:    cert,
	}

	certificate = PatchCertificate(certificate)

	return &certificate, nil
}

// This function is needed to patch the Issuer/Subject(vid/pid) field of certificate to hex format.
// https://github.com/zigbee-alliance/distributed-compliance-ledger/issues/270
func PatchCertificate(certificate Certificate) Certificate {
	oldVIDKey := "1.3.6.1.4.1.37244.2.1"
	oldPIDKey := "1.3.6.1.4.1.37244.2.2"

	newVIDKey := "vid"
	newPIDKey := "pid"

	issuer := certificate.Issuer
	issuer = FormatOID(issuer, oldVIDKey, newVIDKey)
	issuer = FormatOID(issuer, oldPIDKey, newPIDKey)

	subject := certificate.Subject
	subject = FormatOID(subject, oldVIDKey, newVIDKey)
	subject = FormatOID(subject, oldPIDKey, newPIDKey)

	certificate.Issuer = issuer
	certificate.Subject = subject

	return certificate
}

func FormatOID(header, oldKey, newKey string) string {
	subjectValues := strings.Split(header, ",")

	// When translating a string number into a hexadecimal number,
	// we must take 8 numbers of this string number from the end so that it needs to fit into an integer number.
	hexStringIntegerLength := 8
	for index, value := range subjectValues {
		if strings.HasPrefix(value, oldKey) {
			// get value from header
			value = value[len(value)-hexStringIntegerLength:]

			decoded, _ := hex.DecodeString(value)

			subjectValues[index] = fmt.Sprintf("%s=0x%s", newKey, decoded)
		}
	}

	return strings.Join(subjectValues, ",")
}

func BytesToHex(bytes []byte) string {
	if bytes == nil {
		return ""
	}

	bytesHex := make([]string, len(bytes))
	for i, b := range bytes {
		bytesHex[i] = fmt.Sprintf("%02X", b)
	}

	return strings.Join(bytesHex, ":")
}

func (c Certificate) Verify(parent *Certificate) error {
	roots := x509.NewCertPool()
	roots.AddCert(parent.Certificate)

	opts := x509.VerifyOptions{Roots: roots}

	if _, err := c.Certificate.Verify(opts); err != nil {
		return types.NewErrInvalidCertificate(fmt.Sprintf("Certificate verification failed. Error: %v", err))
	}

	return nil
}

func (c Certificate) IsSelfSigned() bool {
	if len(c.AuthorityKeyID) > 0 {
		return c.Issuer == c.Subject && c.AuthorityKeyID == c.SubjectKeyID
	}

	return c.Issuer == c.Subject
}
<commit_msg>Convert original Subject (string) to type base64<commit_after>// Copyright 2020 DSR Corporation
//
// 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"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"

	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

type Certificate struct {
	Issuer         string
	SerialNumber   string
	Subject        string
	SubjectAsText  string
	SubjectKeyID   string
	AuthorityKeyID string
	Certificate    *x509.Certificate
}

func DecodeX509Certificate(pemCertificate string) (*Certificate, error) {
	block, _ := pem.Decode([]byte(pemCertificate))
	if block == nil {
		return nil, types.NewErrInvalidCertificate("Could not decode pem certificate")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, types.NewErrInvalidCertificate(fmt.Sprintf("Could not parse certificate: %v", err.Error()))
	}

	certificate := Certificate{
		Issuer:         cert.Issuer.String(),
		SerialNumber:   cert.SerialNumber.String(),
		Subject:        cert.Subject.String(),
		SubjectAsText:  cert.Subject.String(),
		SubjectKeyID:   BytesToHex(cert.SubjectKeyId),
		AuthorityKeyID: BytesToHex(cert.AuthorityKeyId),
		Certificate:    cert,
	}

	certificate = PatchCertificate(certificate)

	return &certificate, nil
}

// This function is needed to patch the Issuer/Subject(vid/pid) field of certificate to hex format.
// https://github.com/zigbee-alliance/distributed-compliance-ledger/issues/270
func PatchCertificate(certificate Certificate) Certificate {
	oldVIDKey := "1.3.6.1.4.1.37244.2.1"
	oldPIDKey := "1.3.6.1.4.1.37244.2.2"

	newVIDKey := "vid"
	newPIDKey := "pid"

	issuer := certificate.Issuer
	issuer = FormatOID(issuer, oldVIDKey, newVIDKey)
	issuer = FormatOID(issuer, oldPIDKey, newPIDKey)

	subject := certificate.Subject
	subject = FormatOID(subject, oldVIDKey, newVIDKey)
	subject = FormatOID(subject, oldPIDKey, newPIDKey)

	certificate.Issuer = issuer
	certificate.SubjectAsText = subject

	certificate.Subject = StringtoBase64(certificate.Subject)

	return certificate
}

func FormatOID(header, oldKey, newKey string) string {
	subjectValues := strings.Split(header, ",")

	// When translating a string number into a hexadecimal number,
	// we must take 8 numbers of this string number from the end so that it needs to fit into an integer number.
	hexStringIntegerLength := 8
	for index, value := range subjectValues {
		if strings.HasPrefix(value, oldKey) {
			// get value from header
			value = value[len(value)-hexStringIntegerLength:]

			decoded, _ := hex.DecodeString(value)

			subjectValues[index] = fmt.Sprintf("%s=0x%s", newKey, decoded)
		}
	}

	return strings.Join(subjectValues, ",")
}

func StringtoBase64(subject string) string {
	return base64.StdEncoding.EncodeToString([]byte(subject))
}

func BytesToHex(bytes []byte) string {
	if bytes == nil {
		return ""
	}

	bytesHex := make([]string, len(bytes))
	for i, b := range bytes {
		bytesHex[i] = fmt.Sprintf("%02X", b)
	}

	return strings.Join(bytesHex, ":")
}

func (c Certificate) Verify(parent *Certificate) error {
	roots := x509.NewCertPool()
	roots.AddCert(parent.Certificate)

	opts := x509.VerifyOptions{Roots: roots}

	if _, err := c.Certificate.Verify(opts); err != nil {
		return types.NewErrInvalidCertificate(fmt.Sprintf("Certificate verification failed. Error: %v", err))
	}

	return nil
}

func (c Certificate) IsSelfSigned() bool {
	if len(c.AuthorityKeyID) > 0 {
		return c.Issuer == c.Subject && c.AuthorityKeyID == c.SubjectKeyID
	}

	return c.Issuer == c.Subject
}
<|endoftext|>


<commit_before>package proxy

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"

	"github.com/DimShadoWWW/power-pg/common"
)

var (
	connid = uint64(0)
)

// Start function
func Start(localHost, remoteHost *string, powerCallback common.Callback) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost)
	listener := getListener(localAddr)

	for {
		conn, err := listener.Accept()
		// .AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  &Conn{conn: conn},
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
		}
		go p.start(powerCallback)
	}
}

func getResolvedAddresses(localHost, remoteHost *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", *remoteHost)
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  *Conn
	erred         bool
	errsig        chan bool
	prefix        string
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(powerCallback common.Callback) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn.conn = rconn
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, powerCallback)
	go p.pipe(p.rconn, p.lconn, nil)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst *Conn, powerCallback common.Callback) {
	//data direction
	islocal := src.conn == p.lconn.conn
	//directional copy (64k buffer)
	buff := make([]byte, 0xffff)
	var softErr error
	if islocal {
		for {

			fmt.Println("a")
			c := src
			c.reader = bufio.NewReader(src.conn)
			c.mr.reader = c.reader

			fmt.Println("b")
			var t byte
			var r *msgReader
			t, r, err := c.rxMsg()
			if err != nil {
				fmt.Println("c")
				return
			}

			fmt.Printf("t: %#v\n", t)
			switch t {
			case readyForQuery:
				c.rxReadyForQuery(r)
				return
			// case rowDescription:
			// case dataRow:
			// case bindComplete:
			// case commandComplete:
			// 	commandTag = CommandTag(r.readCString())
			default:
				if e := c.processContextFreeMsg(t, r); e != nil && softErr == nil {
					softErr = e
				}
			}

			// n, err := src.Read(buff)
			// if err != nil {
			// 	p.err("Read failed '%s'\n", err)
			// 	return
			// }
			// b := buff[:n]
			// //show output
			//
			//
			// b = getModifiedBuffer(b, powerCallback)
			// n, err = dst.Write(b)
			//
			// //write out result
			// n, err = dst.Write(b)
			// if err != nil {
			// 	p.err("Write failed '%s'\n", err)
			// 	return
			// }
		}
	} else {
		for {
			n, err := src.conn.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.conn.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}
<commit_msg>Update<commit_after>package proxy

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"

	"github.com/DimShadoWWW/power-pg/common"
)

var (
	connid = uint64(0)
)

// Start function
func Start(localHost, remoteHost *string, powerCallback common.Callback) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost)
	listener := getListener(localAddr)

	for {
		conn, err := listener.Accept()
		// .AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  Conn{conn: conn},
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
		}
		go p.start(powerCallback)
	}
}

func getResolvedAddresses(localHost, remoteHost *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", *remoteHost)
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  Conn
	erred         bool
	errsig        chan bool
	prefix        string
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(powerCallback common.Callback) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn.conn = rconn
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(&p.lconn, &p.rconn, powerCallback)
	go p.pipe(&p.rconn, &p.lconn, nil)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst *Conn, powerCallback common.Callback) {
	//data direction
	islocal := src.conn == p.lconn.conn
	//directional copy (64k buffer)
	buff := make([]byte, 0xffff)
	var softErr error
	if islocal {
		for {

			fmt.Println("a")
			c := src
			c.reader = bufio.NewReader(src.conn)
			c.mr.reader = c.reader

			fmt.Println("b")
			var t byte
			var r *msgReader
			t, r, err := c.rxMsg()
			if err != nil {
				fmt.Println("c")
				return
			}

			fmt.Printf("t: %#v\n", t)
			switch t {
			case readyForQuery:
				c.rxReadyForQuery(r)
				return
			// case rowDescription:
			// case dataRow:
			// case bindComplete:
			// case commandComplete:
			// 	commandTag = CommandTag(r.readCString())
			default:
				if e := c.processContextFreeMsg(t, r); e != nil && softErr == nil {
					softErr = e
				}
			}

			// n, err := src.Read(buff)
			// if err != nil {
			// 	p.err("Read failed '%s'\n", err)
			// 	return
			// }
			// b := buff[:n]
			// //show output
			//
			//
			// b = getModifiedBuffer(b, powerCallback)
			// n, err = dst.Write(b)
			//
			// //write out result
			// n, err = dst.Write(b)
			// if err != nil {
			// 	p.err("Write failed '%s'\n", err)
			// 	return
			// }
		}
	} else {
		for {
			n, err := src.conn.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.conn.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}
<|endoftext|>


<commit_before>package proxy

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"

	"github.com/DimShadoWWW/power-pg/common"
)

var (
	connid = uint64(0)
)

// Start function
func Start(localHost, remoteHost *string, powerCallback common.Callback) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost)
	listener := getListener(localAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  *conn,
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
		}
		go p.start(powerCallback)
	}
}

func getResolvedAddresses(localHost, remoteHost *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", *remoteHost)
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  net.TCPConn
	erred         bool
	errsig        chan bool
	prefix        string
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(powerCallback common.Callback) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = *rconn
	// p.rconn.alive = true
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, powerCallback)
	go p.pipe(p.rconn, p.lconn, nil)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst net.TCPConn, powerCallback common.Callback) {
	//data direction
	islocal := src == p.lconn
	//directional copy (64k buffer)
	buff := make(readBuf, 0xffff)
	newPacket := true
	var msg string
	remainingBytes := 0
	var r readBuf
	if islocal {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			r = append(readBuf{}, buff[:n]...)
			fmt.Printf("Remaining bytes: %d\n", remainingBytes)
			if remainingBytes > 0 && remainingBytes <= 0xffff {
				newPacket = true
				msg = msg + string(r.next(remainingBytes))
				remainingBytes = 0xffff - remainingBytes
				fmt.Println(msg)
			} else {
				if remainingBytes > 0 {
					newPacket = false
					msg = msg + string(r.next(remainingBytes))
					remainingBytes = remainingBytes - 0xffff
				}
			}
		NewP:
			if newPacket {
				remainingBytes = 0
				newPacket = false
				msg = ""
				t := r.byte()
				switch t {
				case query:
					// c.rxReadyForQuery(r)
					remainingBytes = r.int32()
					if remainingBytes <= 0xffff {
						newPacket = true
						msg = msg + string(r.next(remainingBytes))
						remainingBytes = 0xffff - remainingBytes
						fmt.Println(msg)
						goto NewP
					} else {
						newPacket = false
						msg = msg + string(r.next(remainingBytes))
						remainingBytes = remainingBytes - 0xffff
					}
				// case rowDescription:
				// case dataRow:
				// case bindComplete:
				// case commandComplete:
				// 	commandTag = CommandTag(r.readCString())
				default:
					// if e := c.processContextFreeMsg(t, r); e != nil && softErr == nil {
					// 	softErr = e
					// }
				}
			}
			r = append(r, buff[:]...)

			// fmt.Println("a")
			// c := src
			// c.reader = bufio.NewReader(src.conn)
			// c.mr.reader = c.reader
			//
			// var t byte
			// var r *msgReader
			// fmt.Println("b")
			// t, r, err := c.rxMsg()
			// fmt.Println("c")
			// if err != nil {
			// 	fmt.Println(err)
			// 	return
			// }
			// fmt.Println("d")
			//
			// fmt.Printf("t: %#v\n", t)

			// n, err := src.Read(buff)
			// if err != nil {
			// 	p.err("Read failed '%s'\n", err)
			// 	return
			// }
			// b := buff[:n]
			// //show output
			//
			//
			// b = getModifiedBuffer(b, powerCallback)
			// n, err = dst.Write(b)
			//
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	} else {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}
<commit_msg>Update<commit_after>package proxy

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"

	"github.com/DimShadoWWW/power-pg/common"
)

var (
	connid = uint64(0)
)

// Start function
func Start(localHost, remoteHost *string, powerCallback common.Callback) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost)
	listener := getListener(localAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  *conn,
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
		}
		go p.start(powerCallback)
	}
}

func getResolvedAddresses(localHost, remoteHost *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", *remoteHost)
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  net.TCPConn
	erred         bool
	errsig        chan bool
	prefix        string
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(powerCallback common.Callback) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = *rconn
	// p.rconn.alive = true
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, powerCallback)
	go p.pipe(p.rconn, p.lconn, nil)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst net.TCPConn, powerCallback common.Callback) {
	//data direction
	islocal := src == p.lconn
	//directional copy (64k buffer)
	buff := make(readBuf, 0xffff)
	newPacket := true
	var msg string
	remainingBytes := 0
	var r readBuf
	if islocal {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			r = append(readBuf{}, buff[:n]...)
			if remainingBytes > 0 && remainingBytes <= 0xffff {
				newPacket = true
				msg = msg + string(r.next(remainingBytes))
				remainingBytes = 0xffff - remainingBytes
				fmt.Println(msg)
			} else {
				if remainingBytes > 0 {
					newPacket = false
					msg = msg + string(r.next(remainingBytes))
					remainingBytes = remainingBytes - 0xffff
				}
			}
			fmt.Printf("Remaining bytes: %d\n", remainingBytes)
		NewP:
			if newPacket {
				remainingBytes = 0
				newPacket = false
				msg = ""
				t := r.byte()
				switch t {
				case query:
					// c.rxReadyForQuery(r)
					remainingBytes = r.int32()
					fmt.Printf("Remaining bytes: %d\n", remainingBytes)
					if remainingBytes <= 0xffff {
						newPacket = true
						msg = msg + string(r.next(remainingBytes))
						remainingBytes = 0xffff - remainingBytes
						fmt.Println(msg)
						goto NewP
					} else {
						newPacket = false
						msg = msg + string(r.next(remainingBytes))
						remainingBytes = remainingBytes - 0xffff
					}
					fmt.Printf("Remaining bytes: %d\n", remainingBytes)
				// case rowDescription:
				// case dataRow:
				// case bindComplete:
				// case commandComplete:
				// 	commandTag = CommandTag(r.readCString())
				default:
					// if e := c.processContextFreeMsg(t, r); e != nil && softErr == nil {
					// 	softErr = e
					// }
				}
			}
			r = append(r, buff[:]...)

			// fmt.Println("a")
			// c := src
			// c.reader = bufio.NewReader(src.conn)
			// c.mr.reader = c.reader
			//
			// var t byte
			// var r *msgReader
			// fmt.Println("b")
			// t, r, err := c.rxMsg()
			// fmt.Println("c")
			// if err != nil {
			// 	fmt.Println(err)
			// 	return
			// }
			// fmt.Println("d")
			//
			// fmt.Printf("t: %#v\n", t)

			// n, err := src.Read(buff)
			// if err != nil {
			// 	p.err("Read failed '%s'\n", err)
			// 	return
			// }
			// b := buff[:n]
			// //show output
			//
			//
			// b = getModifiedBuffer(b, powerCallback)
			// n, err = dst.Write(b)
			//
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	} else {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}
<|endoftext|>


<commit_before>package telemetry

import (
	"fmt"
	"io"
	"io/ioutil"
)

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func Read(f io.Reader) (*TELEM, error) {
	labels := []string{
		"ACCL",
		"DEVC",
		"DVID",
		"DVNM",
		"EMPT",
		"GPRO",
		"GPS5",
		"GPSF",
		"GPSP",
		"GPSU",
		"GYRO",
		"HD5.",
		"ISOG",
		"SCAL",
		"SHUT",
		"SIUN",
		"STNM",
		"STRM",
		"TICK",
		"TMPC",
		"TSMP",
		"UNIT",
		"TYPE",
		"FACE",
		"FCNM",
		"ISOE",
		"WBAL",
		"WRGB",
		"MAGN",
		"ALLD",
		"MTRX",
		"ORIN",
		"ORIO",
		"YAVG",
		"UNIF",
		"SCEN",
		"HUES",
		"SROT",
		"TIMO",
	}

	label := make([]byte, 4, 4) // 4 byte ascii label of data
	desc := make([]byte, 4, 4)  // 4 byte description of length of data

	// keep a copy of the scale to apply to subsequent sentences
	s := SCAL{}

	// the full telemetry for this period
	t := &TELEM{}

	for {
		// pick out the label
		read, err := f.Read(label)
		if err == io.EOF || read == 0 {
			return nil, err
		}

		label_string := string(label)

		if !stringInSlice(label_string, labels) {
			err := fmt.Errorf("Could not find label in list: %s (%x)\n", label, label)
			return nil, err
		}

		// pick out the label description
		read, err = f.Read(desc)
		if err == io.EOF || read == 0 {
			break
		}

		// first byte is zero, there is no length
		if 0x0 == desc[0] {
			continue
		}

		// skip empty packets
		if "EMPT" == label_string {
			io.CopyN(ioutil.Discard, f, 4)
			continue
		}

		// extract the size and length
		val_size := int64(desc[1])
		num_values := (int64(desc[2]) << 8) | int64(desc[3])
		length := val_size * num_values

		// uncomment to see label, type, size and length
		//fmt.Printf("%s (%c) of size %v and len %v\n", label, desc[0], val_size, length)

		if "SCAL" == label_string {
			value := make([]byte, val_size*num_values, val_size*num_values)
			read, err = f.Read(value)
			if err == io.EOF || read == 0 {
				return nil, err
			}

			// clear the scales
			s.Values = s.Values[:0]

			err := s.Parse(value, val_size)
			if err != nil {
				return nil, err
			}
		} else {
			value := make([]byte, val_size)

			for i := int64(0); i < num_values; i++ {
				read, err := f.Read(value)
				if err == io.EOF || read == 0 {
					return nil, err
				}

				// I think DVID is the payload boundary; this might be a bad assumption
				if "DVID" == label_string {

					// XXX: I think this might skip the first sentence
					return t, nil
				} else if "GPS5" == label_string {
					g := GPS5{}
					g.Parse(value, &s)
					t.Gps = append(t.Gps, g)
				} else if "GPSU" == label_string {
					g := GPSU{}
					err := g.Parse(value)
					if err != nil {
						return nil, err
					}
					t.Time = g
				} else if "ACCL" == label_string {
					a := ACCL{}
					err := a.Parse(value, &s)
					if err != nil {
						return nil, err
					}
					t.Accl = append(t.Accl, a)
				} else if "TMPC" == label_string {
					tmp := TMPC{}
					tmp.Parse(value)
					t.Temp = tmp
				} else if "TSMP" == label_string {
					tsmp := TSMP{}
					tsmp.Parse(value, &s)
				} else if "GYRO" == label_string {
					g := GYRO{}
					err := g.Parse(value, &s)
					if err != nil {
						return nil, err
					}
					t.Gyro = append(t.Gyro, g)
				} else if "GPSP" == label_string {
					g := GPSP{}
					err := g.Parse(value)
					if err != nil {
						return nil, err
					}
					t.GpsAccuracy = g
				} else if "GPSF" == label_string {
					g := GPSF{}
					err := g.Parse(value)
					if err != nil {
						return nil, err
					}
					t.GpsFix = g
				} else if "UNIT" == label_string {
					// this is a string of units like "rad/s", not sure if it changes
					//fmt.Printf("\tvals: %s\n", value)
				} else if "SIUN" == label_string {
					// this is the SI unit - also not sure if it changes
					//fmt.Printf("\tvals: %s\n", value)
				} else if "DVNM" == label_string {
					// device name, "Camera"
					//fmt.Printf("\tvals: %s\n", value)
				} else {
					//fmt.Printf("\tvalue is %v\n", value)
				}
			}
		}

		// pack into 4 bytes
		mod := length % 4
		if mod != 0 {
			seek := 4 - mod
			io.CopyN(ioutil.Discard, f, seek)
		}
	}

	return nil, nil
}
<commit_msg>Changes<commit_after>package telemetry

import (
	"fmt"
	"io"
	"io/ioutil"
)

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func Read(f io.Reader) (*TELEM, error) {
	labels := []string{
		"ACCL",
		"DEVC",
		"DVID",
		"DVNM",
		"EMPT",
		"GPRO",
		"GPS5",
		"GPSF",
		"GPSP",
		"GPSU",
		"GYRO",
		"HD5.",
		"ISOG",
		"SCAL",
		"SHUT",
		"SIUN",
		"STNM",
		"STRM",
		"TICK",
		"TMPC",
		"TSMP",
		"UNIT",
		"TYPE",
		"FACE",
		"FCNM",
		"ISOE",
		"WBAL",
		"WRGB",
		"MAGN",
		"ALLD",
		"MTRX",
		"ORIN",
		"ORIO",
		"YAVG",
		"UNIF",
		"SCEN",
		"HUES",
		"SROT",
		"TIMO",
	}

	label := make([]byte, 4, 4) // 4 byte ascii label of data
	desc := make([]byte, 4, 4)  // 4 byte description of length of data

	// keep a copy of the scale to apply to subsequent sentences
	s := SCAL{}

	// the full telemetry for this period
	t := &TELEM{}

	for {
		// pick out the label
		read, err := f.Read(label)
		if err == io.EOF || read == 0 {
			return nil, err
		}

		label_string := string(label)

		if !stringInSlice(label_string, labels) {
			err := fmt.Errorf("Could not find label in list: %s (%x)\n", label, label)
			return nil, err
		}

		// pick out the label description
		read, err = f.Read(desc)
		if err == io.EOF || read == 0 {
			break
		}

		// first byte is zero, there is no length
		if 0x0 == desc[0] {
			continue
		}

		// skip empty packets
		if "EMPT" == label_string {
			io.CopyN(ioutil.Discard, f, 4)
			continue
		}

		// extract the size and length
		val_size := int64(desc[1])
		num_values := (int64(desc[2]) << 8) | int64(desc[3])
		length := val_size * num_values

		// uncomment to see label, type, size and length
		//fmt.Printf("%s (%c) of size %v and len %v\n", label, desc[0], val_size, length)

		if "SCAL" == label_string {
			value := make([]byte, val_size*num_values, val_size*num_values)
			read, err = f.Read(value)
			if err == io.EOF || read == 0 {
				return nil, err
			}

			// clear the scales
			s.Values = s.Values[:0]

			err := s.Parse(value, val_size)
			if err != nil {
				return nil, err
			}
		} else {
			value := make([]byte, val_size)

			for i := int64(0); i < num_values; i++ {
				read, err := f.Read(value)
				if err == io.EOF || read == 0 {
					return nil, err
				}

				// I think DVID is the payload boundary; this might be a bad assumption
				if "DVID" == label_string {

					// XXX: I think this might skip the first sentence
					return t, nil
				} else if "GPS5" == label_string {
					g := GPS5{}
					g.Parse(value, &s)
					t.Gps = append(t.Gps, g)
				} else if "GPSU" == label_string {
					g := GPSU{}
					err := g.Parse(value)
					if err != nil {
						return nil, err
					}
					t.Time = g
				} else if "ACCL" == label_string {
					a := ACCL{}
					err := a.Parse(value, &s)
					if err != nil {
						return nil, err
					}
					t.Accl = append(t.Accl, a)
				} else if "TMPC" == label_string {
					tmp := TMPC{}
					tmp.Parse(value)
					t.Temp = tmp
				} else if "TSMP" == label_string {
					tsmp := TSMP{}
					tsmp.Parse(value, &s)
				} else if "GYRO" == label_string {
					g := GYRO{}
					err := g.Parse(value, &s)
					if err != nil {
						return nil, err
					}
					t.Gyro = append(t.Gyro, g)
				} else if "GPSP" == label_string {
					g := GPSP{}
					err := g.Parse(value)
					if err != nil {
						return nil, err
					}
					t.GpsAccuracy = g
				} else if "GPSF" == label_string {
					g := GPSF{}
					err := g.Parse(value)
					if err != nil {
						return nil, err
					}
					t.GpsFix = g
				} else if "UNIT" == label_string {
					// this is a string of units like "rad/s", not sure if it changes
					//fmt.Printf("\tvals: %s\n", value)
				} else if "SIUN" == label_string {
					// this is the SI unit - also not sure if it changes
					//fmt.Printf("\tvals: %s\n", value)
				} else if "DVNM" == label_string {
					// device name, "Camera"
					//fmt.Printf("\tvals: %s\n", value)
				} else if "FACE" == label_string {
					// device name, "Camera"
					fmt.Printf("\tvals: %d\n", value)
				} else {
					//fmt.Printf("\tvalue is %v\n", value)
				}
			}
		}

		// pack into 4 bytes
		mod := length % 4
		if mod != 0 {
			seek := 4 - mod
			io.CopyN(ioutil.Discard, f, seek)
		}
	}

	return nil, nil
}
<|endoftext|>


<commit_before>package ash

import (
	"go.mongodb.org/mongo-driver/bson"

	"github.com/256dpi/fire"
	"github.com/256dpi/fire/stick"
)

// E is a short-hand function to create an enforcer.
func E(name string, m fire.Matcher, h fire.Handler) *Enforcer {
	return fire.C(name, m, h)
}

// An Enforcer is returned by an Authorizer to enforce the previously inspected
// Authorization.
//
// Enforcers should only return errors if the operation is clearly not allowed for
// the presented candidate and that this information is general knowledge (e.g.
// API documentation). In order to prevent the leakage of implementation details
// the enforcer should mutate the context's Query field to hide existing data
// from the candidate.
type Enforcer = fire.Callback

// GrantAccess will enforce the authorization without any changes to the
// context. It should be used stand-alone if the presented candidate has full
// access to the data (.e.g a superuser) or in an authorizer chain to delegate
// authorization to the next authorizer.
func GrantAccess() *Enforcer {
	return E("ash/GrantAccess", fire.All(), func(_ *fire.Context) error {
		return nil
	})
}

// DenyAccess will enforce the authorization by directly returning an access
// denied error. It should be used if the operation should not be authorized in
// any case (.e.g a candidate accessing a resource he has clearly no access to).
//
// Note: Usually access is denied by returning no enforcers. This enforcer should
// only be returned to immediately stop the authorization process and prevent
// other enforcers from authorizing the operation.
func DenyAccess() *Enforcer {
	return E("ash/DenyAccess", fire.All(), func(_ *fire.Context) error {
		return fire.ErrAccessDenied.Wrap()
	})
}

// AddFilter will enforce the authorization by adding the passed filter to the
// Filter query of the context. It should be used if the candidate is allowed to
// access the resource in general, but some documents should be filtered out.
//
// Note: This enforcer cannot be used to authorize Create and CollectionAction
// operations.
func AddFilter(filter bson.M) *Enforcer {
	return E("ash/AddFilter", fire.Except(fire.Create, fire.CollectionAction), func(ctx *fire.Context) error {
		// assign specified filter
		ctx.Filters = append(ctx.Filters, filter)

		return nil
	})
}

// WhitelistReadableFields will enforce the authorization by making sure only the
// specified fields are returned for the client.
//
// Note: This enforcer cannot be used to authorize Delete, ResourceAction and
// CollectionAction operations.
func WhitelistReadableFields(fields ...string) *Enforcer {
	return E("ash/WhitelistReadableFields", fire.Except(fire.Delete, fire.ResourceAction, fire.CollectionAction), func(ctx *fire.Context) error {
		// set new list
		ctx.ReadableFields = stick.Intersect(ctx.ReadableFields, fields)

		return nil
	})
}

// WhitelistWritableFields will enforce the authorization by making sure only the
// specified fields can be changed by the client.
//
// Note: This enforcer can only be used to authorize Create and Update operations.
func WhitelistWritableFields(fields ...string) *Enforcer {
	return E("ash/WhitelistWritableFields", fire.Only(fire.Create, fire.Update), func(ctx *fire.Context) error {
		// set new list
		ctx.WritableFields = stick.Intersect(ctx.WritableFields, fields)

		return nil
	})
}

// WhitelistReadableProperties will enforce the authorization by making sure only
// the specified properties are returned for the client.
//
// Note: This enforcer cannot be used to authorize Delete, ResourceAction and
// CollectionAction operations.
func WhitelistReadableProperties(fields ...string) *Enforcer {
	return E("ash/WhitelistReadableProperties", fire.Only(fire.Create, fire.Update), func(ctx *fire.Context) error {
		// set new list
		ctx.ReadableProperties = stick.Intersect(ctx.ReadableProperties, fields)

		return nil
	})
}

// AddRelationshipFilter will enforce the authorization by adding the passed
// relationship filter to the RelationshipFilter field of the context. It should
// be used if the candidate is allowed to access the relationship in general, but
// some documents should be filtered out.
//
// Note: This enforcer cannot be used to authorize Create and CollectionAction
// operations.
func AddRelationshipFilter(rel string, filter bson.M) *Enforcer {
	return E("ash/AddRelationshipFilter", fire.Except(fire.Create, fire.CollectionAction), func(ctx *fire.Context) error {
		// append filter
		ctx.RelationshipFilters[rel] = append(ctx.RelationshipFilters[rel], filter)

		return nil
	})
}
<commit_msg>ash: fix enforcer matcher<commit_after>package ash

import (
	"go.mongodb.org/mongo-driver/bson"

	"github.com/256dpi/fire"
	"github.com/256dpi/fire/stick"
)

// E is a short-hand function to create an enforcer.
func E(name string, m fire.Matcher, h fire.Handler) *Enforcer {
	return fire.C(name, m, h)
}

// An Enforcer is returned by an Authorizer to enforce the previously inspected
// Authorization.
//
// Enforcers should only return errors if the operation is clearly not allowed for
// the presented candidate and that this information is general knowledge (e.g.
// API documentation). In order to prevent the leakage of implementation details
// the enforcer should mutate the context's Query field to hide existing data
// from the candidate.
type Enforcer = fire.Callback

// GrantAccess will enforce the authorization without any changes to the
// context. It should be used stand-alone if the presented candidate has full
// access to the data (.e.g a superuser) or in an authorizer chain to delegate
// authorization to the next authorizer.
func GrantAccess() *Enforcer {
	return E("ash/GrantAccess", fire.All(), func(_ *fire.Context) error {
		return nil
	})
}

// DenyAccess will enforce the authorization by directly returning an access
// denied error. It should be used if the operation should not be authorized in
// any case (.e.g a candidate accessing a resource he has clearly no access to).
//
// Note: Usually access is denied by returning no enforcers. This enforcer should
// only be returned to immediately stop the authorization process and prevent
// other enforcers from authorizing the operation.
func DenyAccess() *Enforcer {
	return E("ash/DenyAccess", fire.All(), func(_ *fire.Context) error {
		return fire.ErrAccessDenied.Wrap()
	})
}

// AddFilter will enforce the authorization by adding the passed filter to the
// Filter query of the context. It should be used if the candidate is allowed to
// access the resource in general, but some documents should be filtered out.
//
// Note: This enforcer cannot be used to authorize Create and CollectionAction
// operations.
func AddFilter(filter bson.M) *Enforcer {
	return E("ash/AddFilter", fire.Except(fire.Create, fire.CollectionAction), func(ctx *fire.Context) error {
		// assign specified filter
		ctx.Filters = append(ctx.Filters, filter)

		return nil
	})
}

// WhitelistReadableFields will enforce the authorization by making sure only the
// specified fields are returned for the client.
//
// Note: This enforcer cannot be used to authorize Delete, ResourceAction and
// CollectionAction operations.
func WhitelistReadableFields(fields ...string) *Enforcer {
	return E("ash/WhitelistReadableFields", fire.Except(fire.Delete, fire.ResourceAction, fire.CollectionAction), func(ctx *fire.Context) error {
		// set new list
		ctx.ReadableFields = stick.Intersect(ctx.ReadableFields, fields)

		return nil
	})
}

// WhitelistWritableFields will enforce the authorization by making sure only the
// specified fields can be changed by the client.
//
// Note: This enforcer can only be used to authorize Create and Update operations.
func WhitelistWritableFields(fields ...string) *Enforcer {
	return E("ash/WhitelistWritableFields", fire.Only(fire.Create, fire.Update), func(ctx *fire.Context) error {
		// set new list
		ctx.WritableFields = stick.Intersect(ctx.WritableFields, fields)

		return nil
	})
}

// WhitelistReadableProperties will enforce the authorization by making sure only
// the specified properties are returned for the client.
//
// Note: This enforcer cannot be used to authorize Delete, ResourceAction and
// CollectionAction operations.
func WhitelistReadableProperties(fields ...string) *Enforcer {
	return E("ash/WhitelistReadableProperties", fire.Except(fire.Delete, fire.ResourceAction, fire.CollectionAction), func(ctx *fire.Context) error {
		// set new list
		ctx.ReadableProperties = stick.Intersect(ctx.ReadableProperties, fields)

		return nil
	})
}

// AddRelationshipFilter will enforce the authorization by adding the passed
// relationship filter to the RelationshipFilter field of the context. It should
// be used if the candidate is allowed to access the relationship in general, but
// some documents should be filtered out.
//
// Note: This enforcer cannot be used to authorize Create and CollectionAction
// operations.
func AddRelationshipFilter(rel string, filter bson.M) *Enforcer {
	return E("ash/AddRelationshipFilter", fire.Except(fire.Create, fire.CollectionAction), func(ctx *fire.Context) error {
		// append filter
		ctx.RelationshipFilters[rel] = append(ctx.RelationshipFilters[rel], filter)

		return nil
	})
}
<|endoftext|>


<commit_before>// Internal interface for use from Go
//
// See arithmetic.go for the auto generated stuff

package py

// AttributeName converts an Object to a string, raising a TypeError
// if it wasn't a String
func AttributeName(keyObj Object) string {
	if key, ok := keyObj.(String); ok {
		return string(key)
	}
	panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", keyObj.Type().Name))
}

// Bool is called to implement truth value testing and the built-in
// operation bool(); should return False or True. When this method is
// not defined, __len__() is called, if it is defined, and the object
// is considered true if its result is nonzero. If a class defines
// neither __len__() nor __bool__(), all its instances are considered
// true.
func MakeBool(a Object) Object {
	if _, ok := a.(Bool); ok {
		return a
	}

	if A, ok := a.(I__bool__); ok {
		res := A.M__bool__()
		if res != NotImplemented {
			return res
		}
	}

	if B, ok := a.(I__len__); ok {
		res := B.M__len__()
		if res != NotImplemented {
			return MakeBool(res)
		}
	}

	return True
}

// Index the python Object returning an Int
//
// Will raise TypeError if Index can't be run on this object
func Index(a Object) Int {
	A, ok := a.(I__index__)
	if ok {
		return A.M__index__()
	}

	panic(ExceptionNewf(TypeError, "unsupported operand type(s) for index: '%s'", a.Type().Name))
}

// Index the python Object returning an int
//
// Will raise TypeError if Index can't be run on this object
//
// or IndexError if the Int won't fit!
func IndexInt(a Object) int {
	i := Index(a)
	intI := int(i)

	// Int might not fit in an int
	if Int(intI) != i {
		panic(ExceptionNewf(IndexError, "cannot fit %d into an index-sized integer", i))
	}

	return intI
}

// As IndexInt but if index is -ve addresses it from the end
//
// If index is out of range throws IndexError
func IndexIntCheck(a Object, max int) int {
	i := IndexInt(a)
	if i < 0 {
		i += max
	}
	if i < 0 || i >= max {
		panic(ExceptionNewf(IndexError, "list index out of range"))
	}
	return i
}

// Returns the number of items of a sequence or mapping
func Len(self Object) Object {
	if I, ok := self.(I__len__); ok {
		return I.M__len__()
	} else if res, ok := TypeCall0(self, "__len__"); ok {
		return res
	}
	panic(ExceptionNewf(TypeError, "object of type '%s' has no len()", self.Type().Name))
}

// Return the result of not a
func Not(a Object) Object {
	switch MakeBool(a) {
	case False:
		return True
	case True:
		return False
	}
	panic("bool() didn't return True or False")
}

// Calls function fnObj with args and kwargs in a new vm (or directly
// if Go code)
//
// kwargs should be nil if not required
//
// fnObj must be a callable type such as *py.Method or *py.Function
//
// The result is returned
func Call(fn Object, args Tuple, kwargs StringDict) Object {
	if I, ok := fn.(I__call__); ok {
		return I.M__call__(args, kwargs)
	}
	panic(ExceptionNewf(TypeError, "'%s' object is not callable", fn.Type().Name))
}

// GetItem
func GetItem(self Object, key Object) Object {
	if I, ok := self.(I__getitem__); ok {
		return I.M__getitem__(key)
	} else if res, ok := TypeCall1(self, "__getitem__", key); ok {
		return res
	}
	panic(ExceptionNewf(TypeError, "'%s' object is not subscriptable", self.Type().Name))
}

// SetItem
func SetItem(self Object, key Object, value Object) Object {
	if I, ok := self.(I__setitem__); ok {
		return I.M__setitem__(key, value)
	} else if res, ok := TypeCall2(self, "__setitem__", key, value); ok {
		return res
	}

	panic(ExceptionNewf(TypeError, "'%s' object does not support item assignment", self.Type().Name))
}

// Delitem
func DelItem(self Object, key Object) Object {
	if I, ok := self.(I__delitem__); ok {
		return I.M__delitem__(key)
	} else if res, ok := TypeCall1(self, "__delitem__", key); ok {
		return res
	}
	panic(ExceptionNewf(TypeError, "'%s' object does not support item deletion", self.Type().Name))
}

// GetAttrStringErr - returns the result or an err to be raised if not found
//
// Only AttributeErrors will be returned in err, everything else will be raised
func GetAttrStringErr(self Object, key string) (res Object, err error) {
	defer func() {
		if r := recover(); r != nil {
			if IsException(AttributeError, r) {
				// AttributeError caught - return nil and error
				res = nil
				err = r.(error)
			} else {
				// Propagate the exception
				panic(r)
			}
		}
	}()

	// Call __getattribute__ unconditionally if it exists
	if I, ok := self.(I__getattribute__); ok {
		res = I.M__getattribute__(key)
		return
	} else if res, ok = TypeCall1(self, "__getattribute__", Object(String(key))); ok {
		return
	}

	// Look in the instance dictionary if it exists
	if I, ok := self.(IGetDict); ok {
		dict := I.GetDict()
		res, ok = dict[key]
		if ok {
			return
		}
	}

	// Now look in type's dictionary etc
	t := self.Type()
	res = t.NativeGetAttrOrNil(key)
	if res != nil {
		// Call __get__ which creates bound methods, reads properties etc
		if I, ok := res.(I__get__); ok {
			res = I.M__get__(self, t)
		}
		return
	}

	// And now only if not found call __getattr__
	if I, ok := self.(I__getattr__); ok {
		res = I.M__getattr__(key)
		return
	} else if res, ok = TypeCall1(self, "__getattr__", Object(String(key))); ok {
		return
	}

	// Not found - return nil
	res = nil
	err = ExceptionNewf(AttributeError, "'%s' has no attribute '%s'", self.Type().Name, key)
	return
}

// GetAttrErr - returns the result or an err to be raised if not found
//
// Only AttributeErrors will be returned in err, everything else will be raised
func GetAttrErr(self Object, keyObj Object) (res Object, err error) {
	return GetAttrStringErr(self, AttributeName(keyObj))
}

// GetAttrString gets the attribute, raising an error if not found
func GetAttrString(self Object, key string) Object {
	res, err := GetAttrStringErr(self, key)
	if err != nil {
		panic(err)
	}
	return res
}

// GetAttr gets the attribute rasing an error if key isn't a string or
// attribute not found
func GetAttr(self Object, keyObj Object) Object {
	return GetAttrString(self, AttributeName(keyObj))
}

// SetAttrString
func SetAttrString(self Object, key string, value Object) Object {
	// First look in type's dictionary etc for a property that could
	// be set - do this before looking in the instance dictionary
	setter := self.Type().NativeGetAttrOrNil(key)
	if setter != nil {
		// Call __set__ which writes properties etc
		if I, ok := setter.(I__set__); ok {
			return I.M__set__(self, value)
		}
	}

	// If we have __setattr__ then use that
	if I, ok := self.(I__setattr__); ok {
		return I.M__setattr__(key, value)
	} else if res, ok := TypeCall2(self, "__setattr__", String(key), value); ok {
		return res
	}

	// Otherwise set the attribute in the instance dictionary if
	// possible
	if I, ok := self.(IGetDict); ok {
		dict := I.GetDict()
		if dict == nil {
			panic(ExceptionNewf(SystemError, "nil Dict in %s", self.Type().Name))
		}
		dict[key] = value
		return None
	}

	// If not blow up
	panic(ExceptionNewf(AttributeError, "'%s' object has no attribute '%s'", self.Type().Name, key))
}

// SetAttr
func SetAttr(self Object, keyObj Object, value Object) Object {
	return GetAttrString(self, AttributeName(keyObj))
}

// DeleteAttrString
func DeleteAttrString(self Object, key string) {
	// First look in type's dictionary etc for a property that could
	// be set - do this before looking in the instance dictionary
	deleter := self.Type().NativeGetAttrOrNil(key)
	if deleter != nil {
		// Call __set__ which writes properties etc
		if I, ok := deleter.(I__delete__); ok {
			I.M__delete__(self)
			return
		}
	}

	// If we have __delattr__ then use that
	if I, ok := self.(I__delattr__); ok {
		I.M__delattr__(key)
		return
	} else if _, ok := TypeCall1(self, "__delattr__", String(key)); ok {
		return
	}

	// Otherwise delete the attribute from the instance dictionary
	// if possible
	if I, ok := self.(IGetDict); ok {
		dict := I.GetDict()
		if dict == nil {
			panic(ExceptionNewf(SystemError, "nil Dict in %s", self.Type().Name))
		}
		if _, ok := dict[key]; ok {
			delete(dict, key)
			return
		}
	}

	// If not blow up
	panic(ExceptionNewf(AttributeError, "'%s' object has no attribute '%s'", self.Type().Name, key))
}

// DeleteAttr
func DeleteAttr(self Object, keyObj Object) {
	DeleteAttrString(self, AttributeName(keyObj))
}
<commit_msg>py: Fix SetAttr<commit_after>// Internal interface for use from Go
//
// See arithmetic.go for the auto generated stuff

package py

// AttributeName converts an Object to a string, raising a TypeError
// if it wasn't a String
func AttributeName(keyObj Object) string {
	if key, ok := keyObj.(String); ok {
		return string(key)
	}
	panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", keyObj.Type().Name))
}

// Bool is called to implement truth value testing and the built-in
// operation bool(); should return False or True. When this method is
// not defined, __len__() is called, if it is defined, and the object
// is considered true if its result is nonzero. If a class defines
// neither __len__() nor __bool__(), all its instances are considered
// true.
func MakeBool(a Object) Object {
	if _, ok := a.(Bool); ok {
		return a
	}

	if A, ok := a.(I__bool__); ok {
		res := A.M__bool__()
		if res != NotImplemented {
			return res
		}
	}

	if B, ok := a.(I__len__); ok {
		res := B.M__len__()
		if res != NotImplemented {
			return MakeBool(res)
		}
	}

	return True
}

// Index the python Object returning an Int
//
// Will raise TypeError if Index can't be run on this object
func Index(a Object) Int {
	A, ok := a.(I__index__)
	if ok {
		return A.M__index__()
	}

	panic(ExceptionNewf(TypeError, "unsupported operand type(s) for index: '%s'", a.Type().Name))
}

// Index the python Object returning an int
//
// Will raise TypeError if Index can't be run on this object
//
// or IndexError if the Int won't fit!
func IndexInt(a Object) int {
	i := Index(a)
	intI := int(i)

	// Int might not fit in an int
	if Int(intI) != i {
		panic(ExceptionNewf(IndexError, "cannot fit %d into an index-sized integer", i))
	}

	return intI
}

// As IndexInt but if index is -ve addresses it from the end
//
// If index is out of range throws IndexError
func IndexIntCheck(a Object, max int) int {
	i := IndexInt(a)
	if i < 0 {
		i += max
	}
	if i < 0 || i >= max {
		panic(ExceptionNewf(IndexError, "list index out of range"))
	}
	return i
}

// Returns the number of items of a sequence or mapping
func Len(self Object) Object {
	if I, ok := self.(I__len__); ok {
		return I.M__len__()
	} else if res, ok := TypeCall0(self, "__len__"); ok {
		return res
	}
	panic(ExceptionNewf(TypeError, "object of type '%s' has no len()", self.Type().Name))
}

// Return the result of not a
func Not(a Object) Object {
	switch MakeBool(a) {
	case False:
		return True
	case True:
		return False
	}
	panic("bool() didn't return True or False")
}

// Calls function fnObj with args and kwargs in a new vm (or directly
// if Go code)
//
// kwargs should be nil if not required
//
// fnObj must be a callable type such as *py.Method or *py.Function
//
// The result is returned
func Call(fn Object, args Tuple, kwargs StringDict) Object {
	if I, ok := fn.(I__call__); ok {
		return I.M__call__(args, kwargs)
	}
	panic(ExceptionNewf(TypeError, "'%s' object is not callable", fn.Type().Name))
}

// GetItem
func GetItem(self Object, key Object) Object {
	if I, ok := self.(I__getitem__); ok {
		return I.M__getitem__(key)
	} else if res, ok := TypeCall1(self, "__getitem__", key); ok {
		return res
	}
	panic(ExceptionNewf(TypeError, "'%s' object is not subscriptable", self.Type().Name))
}

// SetItem
func SetItem(self Object, key Object, value Object) Object {
	if I, ok := self.(I__setitem__); ok {
		return I.M__setitem__(key, value)
	} else if res, ok := TypeCall2(self, "__setitem__", key, value); ok {
		return res
	}

	panic(ExceptionNewf(TypeError, "'%s' object does not support item assignment", self.Type().Name))
}

// Delitem
func DelItem(self Object, key Object) Object {
	if I, ok := self.(I__delitem__); ok {
		return I.M__delitem__(key)
	} else if res, ok := TypeCall1(self, "__delitem__", key); ok {
		return res
	}
	panic(ExceptionNewf(TypeError, "'%s' object does not support item deletion", self.Type().Name))
}

// GetAttrStringErr - returns the result or an err to be raised if not found
//
// Only AttributeErrors will be returned in err, everything else will be raised
func GetAttrStringErr(self Object, key string) (res Object, err error) {
	defer func() {
		if r := recover(); r != nil {
			if IsException(AttributeError, r) {
				// AttributeError caught - return nil and error
				res = nil
				err = r.(error)
			} else {
				// Propagate the exception
				panic(r)
			}
		}
	}()

	// Call __getattribute__ unconditionally if it exists
	if I, ok := self.(I__getattribute__); ok {
		res = I.M__getattribute__(key)
		return
	} else if res, ok = TypeCall1(self, "__getattribute__", Object(String(key))); ok {
		return
	}

	// Look in the instance dictionary if it exists
	if I, ok := self.(IGetDict); ok {
		dict := I.GetDict()
		res, ok = dict[key]
		if ok {
			return
		}
	}

	// Now look in type's dictionary etc
	t := self.Type()
	res = t.NativeGetAttrOrNil(key)
	if res != nil {
		// Call __get__ which creates bound methods, reads properties etc
		if I, ok := res.(I__get__); ok {
			res = I.M__get__(self, t)
		}
		return
	}

	// And now only if not found call __getattr__
	if I, ok := self.(I__getattr__); ok {
		res = I.M__getattr__(key)
		return
	} else if res, ok = TypeCall1(self, "__getattr__", Object(String(key))); ok {
		return
	}

	// Not found - return nil
	res = nil
	err = ExceptionNewf(AttributeError, "'%s' has no attribute '%s'", self.Type().Name, key)
	return
}

// GetAttrErr - returns the result or an err to be raised if not found
//
// Only AttributeErrors will be returned in err, everything else will be raised
func GetAttrErr(self Object, keyObj Object) (res Object, err error) {
	return GetAttrStringErr(self, AttributeName(keyObj))
}

// GetAttrString gets the attribute, raising an error if not found
func GetAttrString(self Object, key string) Object {
	res, err := GetAttrStringErr(self, key)
	if err != nil {
		panic(err)
	}
	return res
}

// GetAttr gets the attribute rasing an error if key isn't a string or
// attribute not found
func GetAttr(self Object, keyObj Object) Object {
	return GetAttrString(self, AttributeName(keyObj))
}

// SetAttrString
func SetAttrString(self Object, key string, value Object) Object {
	// First look in type's dictionary etc for a property that could
	// be set - do this before looking in the instance dictionary
	setter := self.Type().NativeGetAttrOrNil(key)
	if setter != nil {
		// Call __set__ which writes properties etc
		if I, ok := setter.(I__set__); ok {
			return I.M__set__(self, value)
		}
	}

	// If we have __setattr__ then use that
	if I, ok := self.(I__setattr__); ok {
		return I.M__setattr__(key, value)
	} else if res, ok := TypeCall2(self, "__setattr__", String(key), value); ok {
		return res
	}

	// Otherwise set the attribute in the instance dictionary if
	// possible
	if I, ok := self.(IGetDict); ok {
		dict := I.GetDict()
		if dict == nil {
			panic(ExceptionNewf(SystemError, "nil Dict in %s", self.Type().Name))
		}
		dict[key] = value
		return None
	}

	// If not blow up
	panic(ExceptionNewf(AttributeError, "'%s' object has no attribute '%s'", self.Type().Name, key))
}

// SetAttr
func SetAttr(self Object, keyObj Object, value Object) Object {
	return SetAttrString(self, AttributeName(keyObj), value)
}

// DeleteAttrString
func DeleteAttrString(self Object, key string) {
	// First look in type's dictionary etc for a property that could
	// be set - do this before looking in the instance dictionary
	deleter := self.Type().NativeGetAttrOrNil(key)
	if deleter != nil {
		// Call __set__ which writes properties etc
		if I, ok := deleter.(I__delete__); ok {
			I.M__delete__(self)
			return
		}
	}

	// If we have __delattr__ then use that
	if I, ok := self.(I__delattr__); ok {
		I.M__delattr__(key)
		return
	} else if _, ok := TypeCall1(self, "__delattr__", String(key)); ok {
		return
	}

	// Otherwise delete the attribute from the instance dictionary
	// if possible
	if I, ok := self.(IGetDict); ok {
		dict := I.GetDict()
		if dict == nil {
			panic(ExceptionNewf(SystemError, "nil Dict in %s", self.Type().Name))
		}
		if _, ok := dict[key]; ok {
			delete(dict, key)
			return
		}
	}

	// If not blow up
	panic(ExceptionNewf(AttributeError, "'%s' object has no attribute '%s'", self.Type().Name, key))
}

// DeleteAttr
func DeleteAttr(self Object, keyObj Object) {
	DeleteAttrString(self, AttributeName(keyObj))
}
<|endoftext|>