<commit_before>package vagrant

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/url"
	"time"

	"koding/kites/kloud/api/vagrantapi"
	puser "koding/kites/kloud/scripts/provisionklient/userdata"
	"koding/kites/kloud/stack"
	"koding/kites/kloud/stack/provider"
	"koding/kites/kloud/utils"
	"koding/klient/tunnel"

	"github.com/koding/kite"
	"github.com/satori/go.uuid"
)

// VagrantResource represents vagrant_instance Terraform resource.
type VagrantResource struct {
	Build map[string]map[string]interface{} `hcl:"vagrant_instance"`
}

type Tunnel struct {
	Name    string
	KiteURL string
}

// Stack provides an implementation for the kloud.Stacker interface.
type Stack struct {
	*provider.BaseStack

	// TunnelURL for klient connection inside vagrant boxes.
	TunnelURL *url.URL

	api *vagrantapi.Klient
}

var (
	_ provider.Stack = (*Stack)(nil)
	_ stack.Stacker  = (*Stack)(nil)
)

func (s *Stack) VerifyCredential(c *stack.Credential) error {
	version, err := s.api.Version(c.Credential.(*Cred).QueryString)
	if err != nil {
		return err
	}

	if version == "" {
		return errors.New("invalid version empty response")
	}

	return nil
}

func (s *Stack) BootstrapTemplates(*stack.Credential) ([]*stack.Template, error) {
	return make([]*stack.Template, 0), nil
}

// InjectVagrantData sets default properties for vagrant_instance Terraform template.
func (s *Stack) ApplyTemplate(c *stack.Credential) (*stack.Template, error) {
	t := s.Builder.Template
	cred := c.Credential.(*Cred)

	var res VagrantResource

	if err := t.DecodeResource(&res); err != nil {
		return nil, err
	}

	if len(res.Build) == 0 {
		return nil, errors.New("no vagrant instances specified")
	}

	uids := s.Builder.MachineUIDs()

	s.Log.Debug("machine uids (%d): %v", len(uids), uids)

	klientURL, err := s.Session.Userdata.LookupKlientURL()
	if err != nil {
		return nil, err
	}

	// queryString is taken from jCredentialData.meta.queryString,
	// for debugging purposes it can be overwritten in the template,
	// however if template has multiple machines, all of them
	// are required to overwrite the queryString to the same value
	// to match current implementation of terraformplugins/vagrant
	// provider.
	//
	// Otherwise we fail early to show problem with the template.
	var queryString string
	for resourceName, box := range res.Build {
		kiteID := uuid.NewV4().String()

		kiteKey, err := s.Session.Userdata.Keycreator.Create(s.Req.Username, kiteID)
		if err != nil {
			return nil, err
		}

		// set kontrolURL if not provided via template
		kontrolURL := s.Session.Userdata.Keycreator.KontrolURL
		if k, ok := box["kontrolURL"].(string); ok {
			kontrolURL = k
		} else {
			box["kontrolURL"] = kontrolURL
		}

		if q, ok := box["queryString"].(string); ok {
			q = utils.QueryString(q)
			if queryString != "" && queryString != q {
				return nil, fmt.Errorf("mismatched queryString provided for multiple instances; want %q, got %q", queryString, q)
			}
			queryString = q
		} else {
			box["queryString"] = "${var.vagrant_queryString}"
			queryString = cred.QueryString
		}

		// set default filePath to relative <stackdir>/<boxname>; for
		// default configured klient it resolves to ~/.vagrant.d/<stackdir>/<boxname>
		if _, ok := box["filePath"]; !ok {
			uid, ok := uids[resourceName]
			if !ok {
				// For Plan call we return random uid as it won't be returned
				// as a part of meta; the filePath is inserted into meta by
				// the apply method.
				uid = resourceName + "-" + utils.RandString(6)
			}
			box["filePath"] = "koding/${var.koding_group_slug}/" + uid
		}

		// set default CPU number
		if _, ok := box["cpus"]; !ok {
			box["cpus"] = "${var.vagrant_cpus}"
		}

		// set default RAM in MiB
		if _, ok := box["memory"]; !ok {
			box["memory"] = "${var.vagrant_memory}"
		}

		// set default box type
		if _, ok := box["box"]; !ok {
			box["box"] = "${var.vagrant_box}"
		}

		var ports []interface{}

		switch p := box["forwarded_ports"].(type) {
		case []interface{}:
			ports = p
		case []map[string]interface{}:
			ports = make([]interface{}, len(p))

			for i := range p {
				ports[i] = p[i]
			}
		}

		// klient kite port
		kitePort := &vagrantapi.ForwardedPort{
			HostPort:  2200,
			GuestPort: 56789,
		}

		// tlsproxy port
		kitesPort := &vagrantapi.ForwardedPort{
			HostPort:  2201,
			GuestPort: 56790,
		}

		ports = append(ports, kitePort, kitesPort)

		box["forwarded_ports"] = ports
		box["username"] = s.Req.Username

		tunnel := s.newTunnel(resourceName)

		s.Builder.InterpolateField(box, resourceName, "user_data")

		if b, ok := box["debug"].(bool); ok && b {
			s.Debug = true
		}

		data := puser.Value{
			Username:        s.Req.Username,
			Groups:          []string{"sudo"},
			Hostname:        s.Req.Username, // no typo here. hostname = username
			KiteKey:         kiteKey,
			LatestKlientURL: klientURL,
			TunnelName:      tunnel.Name,
			TunnelKiteURL:   tunnel.KiteURL,
			KontrolURL:      kontrolURL,
		}

		// pass the values as a JSON encoded as base64. Our script will decode
		// and unmarshall and use it inside the Vagrant box
		val, err := json.Marshal(&data)
		if err != nil {
			return nil, err
		}

		// Compressing the provision data isn't doing any serious optimizations,
		// it's just here so the debug output does not take half a screen.
		//
		// The provisionclient handles both compressed and uncompressed JSONs.
		var buf bytes.Buffer
		if cw, err := gzip.NewWriterLevel(&buf, 9); err == nil {
			if _, err = io.Copy(cw, bytes.NewReader(val)); err == nil && cw.Close() == nil {
				s.Log.Debug("using compressed provision data: %d vs %d", len(val), len(buf.Bytes()))

				val = buf.Bytes()
			}
		}

		box["provisionData"] = base64.StdEncoding.EncodeToString(val)
		res.Build[resourceName] = box
	}

	t.Resource["vagrant_instance"] = res.Build

	if err := t.Flush(); err != nil {
		return nil, err
	}

	content, err := t.JsonOutput()
	if err != nil {
		return nil, err
	}

	return &stack.Template{
		Content: content,
	}, nil
}

func (s *Stack) machinesFromTemplate(t *provider.Template) (stack.Machines, error) {
	var res VagrantResource
	if err := t.DecodeResource(&res); err != nil {
		return nil, err
	}

	machines := make(stack.Machines, len(res.Build))

	for label, box := range res.Build {
		m := &stack.Machine{
			Provider:   "vagrant",
			Label:      label,
			Attributes: make(map[string]string),
		}

		if cpus, ok := box["cpus"].(string); ok && !provider.IsVariable(cpus) {
			m.Attributes["cpus"] = cpus
		}
		if mem, ok := box["memory"].(string); ok && !provider.IsVariable(mem) {
			m.Attributes["memory"] = mem
		}
		if typ, ok := box["box"].(string); ok && !provider.IsVariable(typ) {
			m.Attributes["box"] = typ
		}

		if _, ok := machines[label]; ok {
			return nil, errors.New("duplicate instance labels: " + label)
		}

		machines[label] = m
	}

	return machines, nil
}

func (s *Stack) checkTunnel(c *kite.Client) error {
	resp, err := c.TellWithTimeout("tunnel.info", 2*time.Minute)
	if err != nil {
		return err
	}

	var info tunnel.InfoResponse
	if err := resp.Unmarshal(&info); err != nil {
		return err
	}

	s.Log.Debug("received tunnel.info response: %+v", &info)

	if info.State != tunnel.StateConnected {
		// We do not fail here, as the tunnel can be recovering
		// and we might hit the window when it's not yet done.
		// However we log, to show kloud observed problems with
		// connection.
		s.Log.Warning("%s: want tunnel to be %q, was %q instead", c.ID, tunnel.StateConnected, info.State)

		return nil
	}

	if _, ok := info.Ports["kite"]; !ok {
		// Every klient has its connection to kontrol tunneled, thus
		// tunnel.info should report ports for kite. Warn if there're
		// none to show kloud observed unexpected behavior.
		// However it is not critical though, as we were able to
		// kite.ping the klient, it means the klient may have some
		// other problems (connection with host kite etc.).
		s.Log.Warning("%s: no ports for kite", c.ID)
	}

	return nil
}

func (s *Stack) newTunnel(resourceName string) *Tunnel {
	t := &Tunnel{
		Name:    utils.RandString(12),
		KiteURL: s.TunnelURL.String(),
	}

	if m, ok := s.Builder.Machines[resourceName]; ok {
		t.Name = m.Uid
	}

	return t
}
<commit_msg>provider/vagrant: use BuildKiteKey<commit_after>package vagrant

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/url"
	"time"

	"koding/kites/kloud/api/vagrantapi"
	puser "koding/kites/kloud/scripts/provisionklient/userdata"
	"koding/kites/kloud/stack"
	"koding/kites/kloud/stack/provider"
	"koding/kites/kloud/utils"
	"koding/klient/tunnel"

	"github.com/koding/kite"
)

// VagrantResource represents vagrant_instance Terraform resource.
type VagrantResource struct {
	Build map[string]map[string]interface{} `hcl:"vagrant_instance"`
}

type Tunnel struct {
	Name    string
	KiteURL string
}

// Stack provides an implementation for the kloud.Stacker interface.
type Stack struct {
	*provider.BaseStack

	// TunnelURL for klient connection inside vagrant boxes.
	TunnelURL *url.URL

	api *vagrantapi.Klient
}

var (
	_ provider.Stack = (*Stack)(nil)
	_ stack.Stacker  = (*Stack)(nil)
)

func (s *Stack) VerifyCredential(c *stack.Credential) error {
	version, err := s.api.Version(c.Credential.(*Cred).QueryString)
	if err != nil {
		return err
	}

	if version == "" {
		return errors.New("invalid version empty response")
	}

	return nil
}

func (s *Stack) BootstrapTemplates(*stack.Credential) ([]*stack.Template, error) {
	return make([]*stack.Template, 0), nil
}

// InjectVagrantData sets default properties for vagrant_instance Terraform template.
func (s *Stack) ApplyTemplate(c *stack.Credential) (*stack.Template, error) {
	t := s.Builder.Template
	cred := c.Credential.(*Cred)

	var res VagrantResource

	if err := t.DecodeResource(&res); err != nil {
		return nil, err
	}

	if len(res.Build) == 0 {
		return nil, errors.New("no vagrant instances specified")
	}

	uids := s.Builder.MachineUIDs()

	s.Log.Debug("machine uids (%d): %v", len(uids), uids)

	klientURL, err := s.Session.Userdata.LookupKlientURL()
	if err != nil {
		return nil, err
	}

	// queryString is taken from jCredentialData.meta.queryString,
	// for debugging purposes it can be overwritten in the template,
	// however if template has multiple machines, all of them
	// are required to overwrite the queryString to the same value
	// to match current implementation of terraformplugins/vagrant
	// provider.
	//
	// Otherwise we fail early to show problem with the template.
	var queryString string
	for resourceName, box := range res.Build {
		kiteKey, err := s.BuildKiteKey(resourceName, s.Req.Username)
		if err != nil {
			return nil, err
		}

		// set kontrolURL if not provided via template
		kontrolURL := s.Session.Userdata.Keycreator.KontrolURL
		if k, ok := box["kontrolURL"].(string); ok {
			kontrolURL = k
		} else {
			box["kontrolURL"] = kontrolURL
		}

		if q, ok := box["queryString"].(string); ok {
			q = utils.QueryString(q)
			if queryString != "" && queryString != q {
				return nil, fmt.Errorf("mismatched queryString provided for multiple instances; want %q, got %q", queryString, q)
			}
			queryString = q
		} else {
			box["queryString"] = "${var.vagrant_queryString}"
			queryString = cred.QueryString
		}

		// set default filePath to relative <stackdir>/<boxname>; for
		// default configured klient it resolves to ~/.vagrant.d/<stackdir>/<boxname>
		if _, ok := box["filePath"]; !ok {
			uid, ok := uids[resourceName]
			if !ok {
				// For Plan call we return random uid as it won't be returned
				// as a part of meta; the filePath is inserted into meta by
				// the apply method.
				uid = resourceName + "-" + utils.RandString(6)
			}
			box["filePath"] = "koding/${var.koding_group_slug}/" + uid
		}

		// set default CPU number
		if _, ok := box["cpus"]; !ok {
			box["cpus"] = "${var.vagrant_cpus}"
		}

		// set default RAM in MiB
		if _, ok := box["memory"]; !ok {
			box["memory"] = "${var.vagrant_memory}"
		}

		// set default box type
		if _, ok := box["box"]; !ok {
			box["box"] = "${var.vagrant_box}"
		}

		var ports []interface{}

		switch p := box["forwarded_ports"].(type) {
		case []interface{}:
			ports = p
		case []map[string]interface{}:
			ports = make([]interface{}, len(p))

			for i := range p {
				ports[i] = p[i]
			}
		}

		// klient kite port
		kitePort := &vagrantapi.ForwardedPort{
			HostPort:  2200,
			GuestPort: 56789,
		}

		// tlsproxy port
		kitesPort := &vagrantapi.ForwardedPort{
			HostPort:  2201,
			GuestPort: 56790,
		}

		ports = append(ports, kitePort, kitesPort)

		box["forwarded_ports"] = ports
		box["username"] = s.Req.Username

		tunnel := s.newTunnel(resourceName)

		s.Builder.InterpolateField(box, resourceName, "user_data")

		if b, ok := box["debug"].(bool); ok && b {
			s.Debug = true
		}

		data := puser.Value{
			Username:        s.Req.Username,
			Groups:          []string{"sudo"},
			Hostname:        s.Req.Username, // no typo here. hostname = username
			KiteKey:         kiteKey,
			LatestKlientURL: klientURL,
			TunnelName:      tunnel.Name,
			TunnelKiteURL:   tunnel.KiteURL,
			KontrolURL:      kontrolURL,
		}

		// pass the values as a JSON encoded as base64. Our script will decode
		// and unmarshall and use it inside the Vagrant box
		val, err := json.Marshal(&data)
		if err != nil {
			return nil, err
		}

		// Compressing the provision data isn't doing any serious optimizations,
		// it's just here so the debug output does not take half a screen.
		//
		// The provisionclient handles both compressed and uncompressed JSONs.
		var buf bytes.Buffer
		if cw, err := gzip.NewWriterLevel(&buf, 9); err == nil {
			if _, err = io.Copy(cw, bytes.NewReader(val)); err == nil && cw.Close() == nil {
				s.Log.Debug("using compressed provision data: %d vs %d", len(val), len(buf.Bytes()))

				val = buf.Bytes()
			}
		}

		box["provisionData"] = base64.StdEncoding.EncodeToString(val)
		res.Build[resourceName] = box
	}

	t.Resource["vagrant_instance"] = res.Build

	if err := t.Flush(); err != nil {
		return nil, err
	}

	content, err := t.JsonOutput()
	if err != nil {
		return nil, err
	}

	return &stack.Template{
		Content: content,
	}, nil
}

func (s *Stack) machinesFromTemplate(t *provider.Template) (stack.Machines, error) {
	var res VagrantResource
	if err := t.DecodeResource(&res); err != nil {
		return nil, err
	}

	machines := make(stack.Machines, len(res.Build))

	for label, box := range res.Build {
		m := &stack.Machine{
			Provider:   "vagrant",
			Label:      label,
			Attributes: make(map[string]string),
		}

		if cpus, ok := box["cpus"].(string); ok && !provider.IsVariable(cpus) {
			m.Attributes["cpus"] = cpus
		}
		if mem, ok := box["memory"].(string); ok && !provider.IsVariable(mem) {
			m.Attributes["memory"] = mem
		}
		if typ, ok := box["box"].(string); ok && !provider.IsVariable(typ) {
			m.Attributes["box"] = typ
		}

		if _, ok := machines[label]; ok {
			return nil, errors.New("duplicate instance labels: " + label)
		}

		machines[label] = m
	}

	return machines, nil
}

func (s *Stack) checkTunnel(c *kite.Client) error {
	resp, err := c.TellWithTimeout("tunnel.info", 2*time.Minute)
	if err != nil {
		return err
	}

	var info tunnel.InfoResponse
	if err := resp.Unmarshal(&info); err != nil {
		return err
	}

	s.Log.Debug("received tunnel.info response: %+v", &info)

	if info.State != tunnel.StateConnected {
		// We do not fail here, as the tunnel can be recovering
		// and we might hit the window when it's not yet done.
		// However we log, to show kloud observed problems with
		// connection.
		s.Log.Warning("%s: want tunnel to be %q, was %q instead", c.ID, tunnel.StateConnected, info.State)

		return nil
	}

	if _, ok := info.Ports["kite"]; !ok {
		// Every klient has its connection to kontrol tunneled, thus
		// tunnel.info should report ports for kite. Warn if there're
		// none to show kloud observed unexpected behavior.
		// However it is not critical though, as we were able to
		// kite.ping the klient, it means the klient may have some
		// other problems (connection with host kite etc.).
		s.Log.Warning("%s: no ports for kite", c.ID)
	}

	return nil
}

func (s *Stack) newTunnel(resourceName string) *Tunnel {
	t := &Tunnel{
		Name:    utils.RandString(12),
		KiteURL: s.TunnelURL.String(),
	}

	if m, ok := s.Builder.Machines[resourceName]; ok {
		t.Name = m.Uid
	}

	return t
}
<|endoftext|>


<commit_before>package reply

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/api/modules/helpers"
	"socialapi/workers/common/response"
	"time"
)

func Create(u *url.URL, h http.Header, reply *models.ChannelMessage) (int, http.Header, interface{}, error) {
	parentId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	// first create reply as a message
	reply.TypeConstant = models.ChannelMessage_TYPE_REPLY

	if err := reply.Create(); err != nil {
		// todo this should be internal server error
		return response.NewBadRequest(err)
	}

	// fetch parent
	parent := models.NewChannelMessage()
	if err := parent.ById(parentId); err != nil {
		return response.NewBadRequest(err)
	}

	// set reply message's inital channel id from parent's
	reply.InitialChannelId = parent.InitialChannelId

	// then add this message as a reply to a parent message
	mr := models.NewMessageReply()
	mr.MessageId = parentId
	mr.ReplyId = reply.Id
	mr.CreatedAt = reply.CreatedAt
	if err := mr.Create(); err != nil {
		// todo this should be internal server error
		return response.NewBadRequest(err)
	}

	// update all channels that contains this message
	// todo move this to a worker
	updateAllContainingChannels(parent.Id)

	return response.HandleResultAndError(
		reply.BuildEmptyMessageContainer(),
	)
}

// fetch all channels that parent is in
// update all channels
func updateAllContainingChannels(parentId int64) error {
	cml := models.NewChannelMessageList()
	channels, err := cml.FetchMessageChannels(parentId)
	if err != nil {
		return err
	}

	if len(channels) == 0 {
		return nil
	}

	for _, channel := range channels {
		// if channel type is group, we dont need to update group's updatedAt
		if channel.TypeConstant == models.Channel_TYPE_GROUP {
			continue
		}

		// pinned activity channel holds messages one by one
		if channel.TypeConstant != models.Channel_TYPE_PINNED_ACTIVITY {
			channel.UpdatedAt = time.Now().UTC()
			if err := channel.Update(); err != nil {
				// err
			}
			continue
		}

		// if channel.TypeConstant == models.Channel_TYPE_PINNED_ACTIVITY {
		err := models.NewChannelMessageList().UpdateAddedAt(channel.Id, parentId)
		if err != nil {
			// return err
		}
	}

	return nil

}

func Delete(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	parentId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if parentId == 0 {
		// todo add proper logging
		return response.NewBadRequest(err)
	}

	replyId, err := request.GetURIInt64(u, "replyId")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if replyId == 0 {
		// todo add proper logging
		return response.NewBadRequest(err)
	}

	// first delete the connection between message and the reply
	mr := models.NewMessageReply()
	mr.MessageId = parentId
	mr.ReplyId = replyId
	if err := mr.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	// then delete the message itself
	reply := models.NewChannelMessage()
	reply.Id = replyId
	if err := reply.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	// yes it is deleted but not removed completely from our system
	return response.NewDeleted()
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	messageId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	reply := models.NewMessageReply()
	reply.MessageId = messageId

	return response.HandleResultAndError(
		helpers.ConvertMessagesToMessageContainers(
			reply.List(
				request.GetQuery(u),
			),
		),
	)
}
<commit_msg>Social: Get accountId parameter for message reply fetcher<commit_after>package reply

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/api/modules/helpers"
	"socialapi/workers/common/response"
	"time"
)

func Create(u *url.URL, h http.Header, reply *models.ChannelMessage) (int, http.Header, interface{}, error) {
	parentId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	// first create reply as a message
	reply.TypeConstant = models.ChannelMessage_TYPE_REPLY

	if err := reply.Create(); err != nil {
		// todo this should be internal server error
		return response.NewBadRequest(err)
	}

	// fetch parent
	parent := models.NewChannelMessage()
	if err := parent.ById(parentId); err != nil {
		return response.NewBadRequest(err)
	}

	// set reply message's inital channel id from parent's
	reply.InitialChannelId = parent.InitialChannelId

	// then add this message as a reply to a parent message
	mr := models.NewMessageReply()
	mr.MessageId = parentId
	mr.ReplyId = reply.Id
	mr.CreatedAt = reply.CreatedAt
	if err := mr.Create(); err != nil {
		// todo this should be internal server error
		return response.NewBadRequest(err)
	}

	// update all channels that contains this message
	// todo move this to a worker
	updateAllContainingChannels(parent.Id)

	return response.HandleResultAndError(
		reply.BuildEmptyMessageContainer(),
	)
}

// fetch all channels that parent is in
// update all channels
func updateAllContainingChannels(parentId int64) error {
	cml := models.NewChannelMessageList()
	channels, err := cml.FetchMessageChannels(parentId)
	if err != nil {
		return err
	}

	if len(channels) == 0 {
		return nil
	}

	for _, channel := range channels {
		// if channel type is group, we dont need to update group's updatedAt
		if channel.TypeConstant == models.Channel_TYPE_GROUP {
			continue
		}

		// pinned activity channel holds messages one by one
		if channel.TypeConstant != models.Channel_TYPE_PINNED_ACTIVITY {
			channel.UpdatedAt = time.Now().UTC()
			if err := channel.Update(); err != nil {
				// err
			}
			continue
		}

		// if channel.TypeConstant == models.Channel_TYPE_PINNED_ACTIVITY {
		err := models.NewChannelMessageList().UpdateAddedAt(channel.Id, parentId)
		if err != nil {
			// return err
		}
	}

	return nil

}

func Delete(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	parentId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if parentId == 0 {
		// todo add proper logging
		return response.NewBadRequest(err)
	}

	replyId, err := request.GetURIInt64(u, "replyId")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if replyId == 0 {
		// todo add proper logging
		return response.NewBadRequest(err)
	}

	// first delete the connection between message and the reply
	mr := models.NewMessageReply()
	mr.MessageId = parentId
	mr.ReplyId = replyId
	if err := mr.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	// then delete the message itself
	reply := models.NewChannelMessage()
	reply.Id = replyId
	if err := reply.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	// yes it is deleted but not removed completely from our system
	return response.NewDeleted()
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	messageId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}
	accountId, err := request.GetURIInt64(u, "accountId")
	if err != nil {
		return response.NewBadRequest(err)
	}

	reply := models.NewMessageReply()
	reply.MessageId = messageId

	return response.HandleResultAndError(
		helpers.ConvertMessagesToMessageContainers(
			reply.List(
				request.GetQuery(u),
			),
		),
	)
}
<|endoftext|>


<commit_before>// Timebox is a thin wrapper around nacl/secretbox for time-based secrets.
package timebox

import (
	"crypto/rand"
	"time"

	"golang.org/x/crypto/nacl/secretbox"
)

// SealWith encrypts data the time-sensitive using nacl/secretbox.
func SealWith(data []byte, expires time.Time, nonce *[24]byte, key *[32]byte) ([]byte, error) {
	tb, err := expires.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// The data is encoded as follows.
	//
	// [0, 1):      Length of the following binary encoded time.Time value. (N)
	// [1, N]:      Through the prefixed length (byte 0) is the binary encoded
	// 		        time.Time value.
	// (N, N+24]:   Nonce
	// (N+24, ...]: Sealed data

	outlen := 1 + len(tb) + len(nonce)

	out := make([]byte, outlen, outlen+len(data)+secretbox.Overhead)

	// Encode the length of the marshaled time.Time value in the first byte
	// since time.Time.UnmarshalBinary panics if its argument isn't the correct
	// length.
	out[0] = byte(len(tb))
	copy(out[1:], tb)
	copy(out[1+len(tb):], nonce[:])

	return secretbox.Seal(out, data, nonce, key), nil
}

// Seal is shorthand for calling SealWith with a nonce read via rand.Read.
func Seal(data []byte, expires time.Time, key *[32]byte) ([]byte, error) {
	var nonce [24]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		return nil, err
	}
	return SealWith(data, expires, &nonce, key)
}

// Open is shorthand for calling OpenAt with time.Now as its first argument.
func Open(data []byte, key *[32]byte) ([]byte, bool) {
	return OpenAt(time.Now(), data, key)
}

// OpenAt attempts to unseal the sealed data, returning false if the data has
// expired.
func OpenAt(when time.Time, data []byte, key *[32]byte) (out []byte, ok bool) {
	end := int(data[0]) + 1

	var t time.Time
	err := t.UnmarshalBinary(data[1:end])
	if err != nil || !when.Before(t) {
		return nil, false
	}
	data = data[end:]

	var nonce [24]byte
	n := copy(nonce[:], data)
	return secretbox.Open(out, data[n:], &nonce, key)
}
<commit_msg>timebox: move time inside body, of course...<commit_after>// Timebox is a thin wrapper around nacl/secretbox for time-based secrets.
package timebox

import (
	"crypto/rand"
	"time"

	"golang.org/x/crypto/nacl/secretbox"
)

// SealWith encrypts data the time-sensitive using nacl/secretbox.
func SealWith(data []byte, expires time.Time, nonce *[24]byte, key *[32]byte) ([]byte, error) {
	tb, err := expires.MarshalBinary()
	if err != nil {
		return nil, err
	}

	data1 := make([]byte, len(data)+len(tb)+1)
	data1[0] = byte(len(tb))
	n := copy(data1[1:], tb)
	copy(data1[n+1:], data)

	out := make([]byte, len(nonce), len(nonce)+len(data)+secretbox.Overhead)
	copy(out, nonce[:])
	return secretbox.Seal(out, data1, nonce, key), nil
}

// Seal is shorthand for calling SealWith with a nonce read via rand.Read.
func Seal(data []byte, expires time.Time, key *[32]byte) ([]byte, error) {
	var nonce [24]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		return nil, err
	}
	return SealWith(data, expires, &nonce, key)
}

// Open is shorthand for calling OpenAt with time.Now as its first argument.
func Open(data []byte, key *[32]byte) ([]byte, bool) {
	return OpenAt(time.Now(), data, key)
}

// OpenAt attempts to unseal the sealed data, returning false if the data has
// expired.
func OpenAt(when time.Time, data []byte, key *[32]byte) (out []byte, ok bool) {
	var nonce [24]byte
	copy(nonce[:], data)

	data, ok = secretbox.Open(out, data[len(nonce):], &nonce, key)
	if !ok {
		return nil, false
	}

	len := int(data[0]) + 1

	var t time.Time
	err := t.UnmarshalBinary(data[1:len])
	if err != nil || !when.Before(t) {
		return nil, false
	}
	return data[len:], true
}
<|endoftext|>


<commit_before>package random

import (
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/go-uuid"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceUuid() *schema.Resource {
	return &schema.Resource{
		Create: CreateUuid,
		Read:   RepopulateUuid,
		Delete: schema.RemoveFromState,
		Importer: &schema.ResourceImporter{
			State: ImportUuid,
		},

		Schema: map[string]*schema.Schema{
			"keepers": {
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},

			"result": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func CreateUuid(d *schema.ResourceData, meta interface{}) error {
	result, err := uuid.GenerateUUID()
	if err != nil {
		return errwrap.Wrapf("error generating uuid: {{err}}", err)
	}
	d.Set("result", result)
	d.SetId(result)
	return nil
}

func RepopulateUuid(d *schema.ResourceData, _ interface{}) error {
	return nil
}

func ImportUuid(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	id := d.Id()
	bytes, err := uuid.ParseUUID(id)
	if err != nil {
		return nil, errwrap.Wrapf("error parsing uuid bytes: {{err}}", err)
	}
	result, err2 := uuid.FormatUUID(bytes)
	if err2 != nil {
		return nil, errwrap.Wrapf("error formatting uuid bytes: {{err2}}", err2)
	}

	d.Set("result", result)
	d.SetId(result)

	return []*schema.ResourceData{d}, nil
}
<commit_msg>Delete redundant noop function in resource_uuid<commit_after>package random

import (
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/go-uuid"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceUuid() *schema.Resource {
	return &schema.Resource{
		Create: CreateUuid,
		Read:   schema.Noop,
		Delete: schema.RemoveFromState,
		Importer: &schema.ResourceImporter{
			State: ImportUuid,
		},

		Schema: map[string]*schema.Schema{
			"keepers": {
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},

			"result": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func CreateUuid(d *schema.ResourceData, meta interface{}) error {
	result, err := uuid.GenerateUUID()
	if err != nil {
		return errwrap.Wrapf("error generating uuid: {{err}}", err)
	}
	d.Set("result", result)
	d.SetId(result)
	return nil
}

func ImportUuid(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	id := d.Id()
	bytes, err := uuid.ParseUUID(id)
	if err != nil {
		return nil, errwrap.Wrapf("error parsing uuid bytes: {{err}}", err)
	}
	result, err2 := uuid.FormatUUID(bytes)
	if err2 != nil {
		return nil, errwrap.Wrapf("error formatting uuid bytes: {{err2}}", err2)
	}

	d.Set("result", result)
	d.SetId(result)

	return []*schema.ResourceData{d}, nil
}
<|endoftext|>


<commit_before>// Package raw_file_server provides a http.Handler that serves the given virtual file system without special handling of index.html.
package raw_file_server

import (
	"fmt"
	"html"
	"net/http"
	"net/url"
	"path"
	"strings"

	"golang.org/x/tools/godoc/vfs"
	"golang.org/x/tools/godoc/vfs/httpfs"
)

type rawFileServer struct {
	// TODO: Use vfs.FileSystem.
	root http.FileSystem
}

// New returns a raw file server, that serves the given virtual file system without special handling of index.html.
func New(root vfs.FileSystem) http.Handler {
	// TODO: Use vfs.FileSystem.
	return &rawFileServer{httpfs.New(root)}
}

// NewUsingHttpFs returns a raw file server.
//
// TODO: Remove when this is no longer neccessary.
func NewUsingHttpFs(root http.FileSystem) http.Handler {
	return &rawFileServer{root}
}

func (f *rawFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !strings.HasPrefix(r.URL.Path, "/") {
		r.URL.Path = "/" + r.URL.Path
	}
	serveFile(w, r, f.root, path.Clean(r.URL.Path))
}

func dirList(w http.ResponseWriter, f http.File, name string) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, "
\n")
	fmt.Fprintf(w, "%s\n", path.Clean(name+"/.."), "..")
	for {
		dirs, err := f.Readdir(100)
		if err != nil || len(dirs) == 0 {
			break
		}
		for _, d := range dirs {
			name := d.Name()
			if d.IsDir() {
				name += "/"
			}
			// name may contain '?' or '#', which must be escaped to remain
			// part of the URL path, and not indicate the start of a query
			// string or fragment.
			url := url.URL{Path: name}
			fmt.Fprintf(w, "%s\n", url.String(), html.EscapeString(name))
		}
	}
	fmt.Fprintf(w, "
\n")
}

// name is '/'-separated, not filepath.Separator.
func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string) {
	f, err := fs.Open(name)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer f.Close()

	d, err := f.Stat()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// redirect to canonical path: / at end of directory url
	// r.URL.Path always begins with /
	url := r.URL.Path
	if d.IsDir() {
		if url[len(url)-1] != '/' {
			localRedirect(w, r, path.Base(url)+"/")
			return
		}
	} else {
		if url[len(url)-1] == '/' {
			localRedirect(w, r, "../"+path.Base(url))
			return
		}
	}

	// A directory?
	if d.IsDir() {
		// TODO: Consider using checkLastModified?
		/*if checkLastModified(w, r, d.ModTime()) {
			return
		}*/
		dirList(w, f, name)
		return
	}

	if _, plain := r.URL.Query()["plain"]; plain {
		w.Header().Set("Content-Type", "text/plain")
	}
	http.ServeContent(w, r, d.Name(), d.ModTime(), f)
}

// localRedirect gives a Moved Permanently response.
// It does not convert relative paths to absolute paths like Redirect does.
func localRedirect(w http.ResponseWriter, r *http.Request, newPath string) {
	if q := r.URL.RawQuery; q != "" {
		newPath += "?" + q
	}
	w.Header().Set("Location", newPath)
	w.WriteHeader(http.StatusMovedPermanently)
}
<commit_msg>raw_file_server: Sort directory entries.<commit_after>// Package raw_file_server provides a http.Handler that serves the given virtual file system without special handling of index.html.
package raw_file_server

import (
	"fmt"
	"html"
	"net/http"
	"net/url"
	"os"
	"path"
	"sort"
	"strings"

	"golang.org/x/tools/godoc/vfs"
	"golang.org/x/tools/godoc/vfs/httpfs"
)

type rawFileServer struct {
	// TODO: Use vfs.FileSystem.
	root http.FileSystem
}

// New returns a raw file server, that serves the given virtual file system without special handling of index.html.
func New(root vfs.FileSystem) http.Handler {
	// TODO: Use vfs.FileSystem.
	return &rawFileServer{httpfs.New(root)}
}

// NewUsingHttpFs returns a raw file server.
//
// TODO: Remove when this is no longer neccessary.
func NewUsingHttpFs(root http.FileSystem) http.Handler {
	return &rawFileServer{root}
}

func (f *rawFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !strings.HasPrefix(r.URL.Path, "/") {
		r.URL.Path = "/" + r.URL.Path
	}
	serveFile(w, r, f.root, path.Clean(r.URL.Path))
}

func dirList(w http.ResponseWriter, f http.File, name string) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, "
\n")
	fmt.Fprintf(w, "%s\n", path.Clean(name+"/.."), "..")
	for {
		dirs, err := f.Readdir(100)
		if err != nil || len(dirs) == 0 {
			break
		}
		sort.Sort(byName(dirs))
		for _, d := range dirs {
			name := d.Name()
			if d.IsDir() {
				name += "/"
			}
			// name may contain '?' or '#', which must be escaped to remain
			// part of the URL path, and not indicate the start of a query
			// string or fragment.
			url := url.URL{Path: name}
			fmt.Fprintf(w, "%s\n", url.String(), html.EscapeString(name))
		}
	}
	fmt.Fprintf(w, "
\n")
}

// name is '/'-separated, not filepath.Separator.
func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string) {
	f, err := fs.Open(name)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer f.Close()

	d, err := f.Stat()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// redirect to canonical path: / at end of directory url
	// r.URL.Path always begins with /
	url := r.URL.Path
	if d.IsDir() {
		if url[len(url)-1] != '/' {
			localRedirect(w, r, path.Base(url)+"/")
			return
		}
	} else {
		if url[len(url)-1] == '/' {
			localRedirect(w, r, "../"+path.Base(url))
			return
		}
	}

	// A directory?
	if d.IsDir() {
		// TODO: Consider using checkLastModified?
		/*if checkLastModified(w, r, d.ModTime()) {
			return
		}*/
		dirList(w, f, name)
		return
	}

	if _, plain := r.URL.Query()["plain"]; plain {
		w.Header().Set("Content-Type", "text/plain")
	}
	http.ServeContent(w, r, d.Name(), d.ModTime(), f)
}

// localRedirect gives a Moved Permanently response.
// It does not convert relative paths to absolute paths like Redirect does.
func localRedirect(w http.ResponseWriter, r *http.Request, newPath string) {
	if q := r.URL.RawQuery; q != "" {
		newPath += "?" + q
	}
	w.Header().Set("Location", newPath)
	w.WriteHeader(http.StatusMovedPermanently)
}

// byName implements sort.Interface.
type byName []os.FileInfo

func (f byName) Len() int           { return len(f) }
func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
<|endoftext|>


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

/*
Goinstall is an experiment in automatic package installation.
It installs packages, possibly downloading them from the internet.
It maintains a list of public Go packages at http://godashboard.appspot.com/package.

Usage:
	goinstall [flags] importpath...
	goinstall [flags] -a

Flags and default settings:
        -a=false          install all previously installed packages
	-clean=false      clean the package directory before installing
	-dashboard=true   tally public packages on godashboard.appspot.com
	-install=true     build and install the package and its dependencies
	-log=true         log installed packages to $GOROOT/goinstall.log for use by -a
	-nuke=false       remove the target object and clean before installing
	-u=false          update already-downloaded packages
	-v=false          verbose operation

Goinstall installs each of the packages identified on the command line.  It
installs a package's prerequisites before trying to install the package
itself. Unless -log=false is specified, goinstall logs the import path of each
installed package to $GOROOT/goinstall.log for use by goinstall -a.

If the -a flag is given, goinstall reinstalls all previously installed
packages, reading the list from $GOROOT/goinstall.log.  After updating to a
new Go release, which deletes all package binaries, running

	goinstall -a

will recompile and reinstall goinstalled packages.

Another common idiom is to use

	goinstall -a -u

to update, recompile, and reinstall all goinstalled packages.

The source code for a package with import path foo/bar is expected
to be in the directory $GOROOT/src/pkg/foo/bar/.  If the import
path refers to a code hosting site, goinstall will download the code
if necessary.  The recognized code hosting sites are:

	BitBucket (Mercurial)

		import "bitbucket.org/user/project"
		import "bitbucket.org/user/project/sub/directory"

	GitHub (Git)

		import "github.com/user/project"
		import "github.com/user/project/sub/directory"

	Google Code Project Hosting (Mercurial, Subversion)

		import "project.googlecode.com/hg"
		import "project.googlecode.com/hg/sub/directory"

		import "project.googlecode.com/svn/trunk"
		import "project.googlecode.com/svn/trunk/sub/directory"

	Launchpad

		import "launchpad.net/project"
		import "launchpad.net/project/series"
		import "launchpad.net/project/series/sub/directory"

		import "launchpad.net/~user/project/branch"
		import "launchpad.net/~user/project/branch/sub/directory"

If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
already exists and contains an appropriate checkout, goinstall will not
attempt to fetch updates.  The -u flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.

When downloading or updating, goinstall first looks for a tag or branch
named "release".  If there is one, it uses that version of the code.
Otherwise it uses the default version selected by the version control
system, typically HEAD for git, tip for Mercurial.

After a successful download and installation of a publicly accessible
remote package, goinstall reports the installation to godashboard.appspot.com,
which increments a count associated with the package and the time
of its most recent installation.  This mechanism powers the package list
at http://godashboard.appspot.com/package, allowing Go programmers
to learn about popular packages that might be worth looking at.
The -dashboard=false flag disables this reporting.

By default, goinstall prints output only when it encounters an error.
The -v flag causes goinstall to print information about packages
being considered and installed.

Goinstall does not attempt to be a replacement for make.
Instead, it invokes "make install" after locating the package sources.
For local packages without a Makefile and all remote packages,
goinstall creates and uses a temporary Makefile constructed from
the import path and the list of Go files in the package.

The GOPATH Environment Variable

GOPATH may be set to a colon-separated list of paths inside which Go code,
package objects, and executables may be found.

Set a GOPATH to use goinstall to build and install your own code and
external libraries outside of the Go tree (and to avoid writing Makefiles).

The top-level directory structure of a GOPATH is prescribed:

The 'src' directory is for source code. The directory naming inside 'src'
determines the package import path or executable name.

The 'pkg' directory is for package objects. Like the Go tree, package objects
are stored inside a directory named after the target operating system and
processor architecture ('pkg/$GOOS_$GOARCH').
A package whose source is located at '$GOPATH/src/foo/bar' would be imported
as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'.

The 'bin' directory is for executable files.
Goinstall installs program binaries using the name of the source folder.
A binary whose source is at 'src/foo/qux' would be built and installed to
'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that
you can put the bin directory in your PATH.)

Here's an example directory layout:

	GOPATH=/home/user/gocode

	/home/user/gocode/
		src/foo/
			bar/               (go code in package bar)
			qux/               (go code in package main)
		bin/qux                    (executable file)
		pkg/linux_amd64/foo/bar.a  (object file)

Run 'goinstall foo/bar' to build and install the package 'foo/bar'
(and its dependencies).
Goinstall will search each GOPATH (in order) for 'src/foo/bar'.
If the directory cannot be found, goinstall will attempt to fetch the
source from a remote repository and write it to the 'src' directory of the
first GOPATH (or $GOROOT/src/pkg if GOPATH is not set).

Goinstall recognizes relative and absolute paths (paths beginning with / or .).
The following commands would build our example packages:

	goinstall /home/user/gocode/src/foo/bar  # build and install foo/bar
	cd /home/user/gocode/src/foo
	goinstall ./bar  # build and install foo/bar (again)
	cd qux
	goinstall .      # build and install foo/qux

*/
package documentation
<commit_msg>goinstall: update doc.go<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Goinstall is an experiment in automatic package installation.
It installs packages, possibly downloading them from the internet.
It maintains a list of public Go packages at http://godashboard.appspot.com/package.

Usage:
	goinstall [flags] importpath...
	goinstall [flags] -a

Flags and default settings:
        -a=false          install all previously installed packages
	-clean=false      clean the package directory before installing
	-dashboard=true   tally public packages on godashboard.appspot.com
	-install=true     build and install the package and its dependencies
	-log=true         log installed packages to $GOROOT/goinstall.log for use by -a
	-nuke=false       remove the target object and clean before installing
	-u=false          update already-downloaded packages
	-v=false          verbose operation

Goinstall installs each of the packages identified on the command line.  It
installs a package's prerequisites before trying to install the package
itself. Unless -log=false is specified, goinstall logs the import path of each
installed package to $GOROOT/goinstall.log for use by goinstall -a.

If the -a flag is given, goinstall reinstalls all previously installed
packages, reading the list from $GOROOT/goinstall.log.  After updating to a
new Go release, which deletes all package binaries, running

	goinstall -a

will recompile and reinstall goinstalled packages.

Another common idiom is to use

	goinstall -a -u

to update, recompile, and reinstall all goinstalled packages.

The source code for a package with import path foo/bar is expected
to be in the directory $GOPATH/src/foo/bar/ or $GOROOT/src/pkg/foo/bar/.
(See the discussion of GOPATH below for more detail.)

If the package source is not found locally and the import path begins
with a domain name, goinstall attempts to detect a remote source repository
(Bazaar, Git, Mercurial, or Subversion). If a supported repository is found,
goinstall uses the appropriate tool to download the source code.

If the import path refers to a known code hosting site, goinstall skips the
repository detection and downloads the code directly.
The recognized code hosting sites are:

	BitBucket (Mercurial)

		import "bitbucket.org/user/project"
		import "bitbucket.org/user/project/sub/directory"

	GitHub (Git)

		import "github.com/user/project"
		import "github.com/user/project/sub/directory"

	Google Code Project Hosting (Mercurial, Subversion)

		import "project.googlecode.com/hg"
		import "project.googlecode.com/hg/sub/directory"

		import "project.googlecode.com/svn/trunk"
		import "project.googlecode.com/svn/trunk/sub/directory"

	Launchpad (Bazaar)

		import "launchpad.net/project"
		import "launchpad.net/project/series"
		import "launchpad.net/project/series/sub/directory"

		import "launchpad.net/~user/project/branch"
		import "launchpad.net/~user/project/branch/sub/directory"

If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
already exists and contains an appropriate checkout, goinstall will not
attempt to fetch updates.  The -u flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.

When downloading or updating, goinstall first looks for a tag or branch
named "release".  If there is one, it uses that version of the code.
Otherwise it uses the default version selected by the version control
system, typically HEAD for git, tip for Mercurial.

After a successful download and installation of a publicly accessible
remote package, goinstall reports the installation to godashboard.appspot.com,
which increments a count associated with the package and the time
of its most recent installation. This mechanism powers the package list
at http://godashboard.appspot.com/package, allowing Go programmers
to learn about popular packages that might be worth looking at.
The -dashboard=false flag disables this reporting.

By default, goinstall prints output only when it encounters an error.
The -v flag causes goinstall to print information about packages
being considered and installed.

Goinstall does not use make. Makefiles are ignored by goinstall.

The GOPATH Environment Variable

GOPATH may be set to a colon-separated list of paths inside which Go code,
package objects, and executables may be found.

Set a GOPATH to use goinstall to build and install your own code and
external libraries outside of the Go tree (and to avoid writing Makefiles).

The top-level directory structure of a GOPATH is prescribed:

The 'src' directory is for source code. The directory naming inside 'src'
determines the package import path or executable name.

The 'pkg' directory is for package objects. Like the Go tree, package objects
are stored inside a directory named after the target operating system and
processor architecture ('pkg/$GOOS_$GOARCH').
A package whose source is located at '$GOPATH/src/foo/bar' would be imported
as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'.

The 'bin' directory is for executable files.
Goinstall installs program binaries using the name of the source folder.
A binary whose source is at 'src/foo/qux' would be built and installed to
'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that
you can put the bin directory in your PATH.)

Here's an example directory layout:

	GOPATH=/home/user/gocode

	/home/user/gocode/
		src/foo/
			bar/               (go code in package bar)
			qux/               (go code in package main)
		bin/qux                    (executable file)
		pkg/linux_amd64/foo/bar.a  (object file)

Run 'goinstall foo/bar' to build and install the package 'foo/bar'
(and its dependencies).
Goinstall will search each GOPATH (in order) for 'src/foo/bar'.
If the directory cannot be found, goinstall will attempt to fetch the
source from a remote repository and write it to the 'src' directory of the
first GOPATH (or $GOROOT/src/pkg if GOPATH is not set).

Goinstall recognizes relative and absolute paths (paths beginning with / or .).
The following commands would build our example packages:

	goinstall /home/user/gocode/src/foo/bar  # build and install foo/bar
	cd /home/user/gocode/src/foo
	goinstall ./bar  # build and install foo/bar (again)
	cd qux
	goinstall .      # build and install foo/qux

*/
package documentation
<|endoftext|>


<commit_before>package todolist

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

const (
	VERSION = "0.5.2"
	S3URL   = "https://s3.amazonaws.com/todolist-local/" + VERSION
)

type Webapp struct {
	Router *httprouter.Router
}

func NewWebapp() *Webapp {
	return &Webapp{Router: setupRoutes()}
}

func (w *Webapp) Run() {
	log.Fatal(http.ListenAndServe(":7890", w.Router))
}

func setupRoutes() *httprouter.Router {
	router := httprouter.New()
	router.GET("/", IndexScaffold)
	router.OPTIONS("/todos", TodoOptions)
	router.GET("/todos", GetTodos)
	router.POST("/todos", SaveTodos)
	router.NotFound = http.HandlerFunc(RedirectScaffold)
	return router
}

func IndexScaffold(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	template := `
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet" href="https://bootswatch.com/flatly/bootstrap.min.css">
    <title>Todolist</title>
    <link href="` + urlFor("main.css") + `" rel="stylesheet">

	`
	fmt.Fprintf(w, template)
}

func RedirectScaffold(w http.ResponseWriter, r *http.Request) {
	template := `
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet" href="https://bootswatch.com/flatly/bootstrap.min.css">
    <title>Todolist</title>
    <link href="` + urlFor("main.css") + `" rel="stylesheet">

	`
	fmt.Fprintf(w, template)
}

func urlFor(file string) string {
	return S3URL + "/" + file
}

func RedirectToIndex(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, S3URL+r.URL.Path, 301)
}

func GetTodos(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	app := NewApp()
	app.Load()
	json, _ := json.Marshal(app.TodoList.Data)
	fmt.Fprintf(w, string(json))
}
func TodoOptions(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	fmt.Fprintf(w, "")
}

func SaveTodos(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	decoder := json.NewDecoder(r.Body)
	var todos []*Todo
	err := decoder.Decode(&todos)
	if err != nil {
		log.Fatal("encountered an error parsing json, ", err)
	}
	app := NewApp()
	app.TodoStore.Save(todos)
}
<commit_msg>Fix issue with web view<commit_after>package todolist

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

const (
	VERSION = "0.5.2"
	S3URL   = "https://s3.amazonaws.com/todolist-local/" + VERSION
)

type Webapp struct {
	Router *httprouter.Router
}

func NewWebapp() *Webapp {
	return &Webapp{Router: setupRoutes()}
}

func (w *Webapp) Run() {
	log.Fatal(http.ListenAndServe(":7890", w.Router))
}

func setupRoutes() *httprouter.Router {
	router := httprouter.New()
	router.GET("/", IndexScaffold)
	router.OPTIONS("/todos", TodoOptions)
	router.GET("/todos", GetTodos)
	router.POST("/todos", SaveTodos)
	router.NotFound = http.HandlerFunc(RedirectScaffold)
	return router
}

func IndexScaffold(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	template := `
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet" href="https://bootswatch.com/flatly/bootstrap.min.css">
    <title>Todolist</title>
    <link href="` + urlFor("main.css") + `" rel="stylesheet">

	`
	fmt.Fprintf(w, template)
}

func RedirectScaffold(w http.ResponseWriter, r *http.Request) {
	template := `
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet" href="https://bootswatch.com/flatly/bootstrap.min.css">
    <title>Todolist</title>
    <link href="` + urlFor("main.css") + `" rel="stylesheet">

	`
	fmt.Fprintf(w, template)
}

func urlFor(file string) string {
	return S3URL + "/" + file
}

func RedirectToIndex(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, S3URL+r.URL.Path, 301)
}

func GetTodos(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	app := NewApp()
	app.Load()
	json, _ := json.Marshal(app.TodoList.Data)
	fmt.Fprintf(w, string(json))
}
func TodoOptions(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	fmt.Fprintf(w, "")
}

func SaveTodos(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	decoder := json.NewDecoder(r.Body)
	var todos []*Todo
	err := decoder.Decode(&todos)
	if err != nil {
		log.Fatal("encountered an error parsing json, ", err)
	}
	app := NewApp()
	app.TodoStore.Load()
	app.TodoStore.Save(todos)
}
<|endoftext|>


<commit_before>package toolkits

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	"github.com/bitrise-io/bitrise/configs"
	"github.com/bitrise-io/bitrise/models"
	"github.com/bitrise-io/bitrise/tools"
	"github.com/bitrise-io/bitrise/utils"
	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/go-utils/progress"
	"github.com/bitrise-io/go-utils/retry"
	"github.com/bitrise-io/go-utils/versions"
	stepmanModels "github.com/bitrise-io/stepman/models"
	"github.com/bitrise-tools/gows/gows"
)

const (
	minGoVersionForToolkit = "1.9.1"
)

// === Base Toolkit struct ===

// GoToolkit ...
type GoToolkit struct {
}

// ToolkitName ...
func (toolkit GoToolkit) ToolkitName() string {
	return "go"
}

// === Toolkit: Check ===

// GoConfigurationModel ...
type GoConfigurationModel struct {
	// full path of the go binary to use
	GoBinaryPath string
	// GOROOT env var value to set (unless empty)
	GOROOT string
}

func checkGoConfiguration(goConfig GoConfigurationModel) (bool, ToolkitCheckResult, error) {
	cmdEnvs := os.Environ()
	if len(goConfig.GOROOT) > 0 {
		cmdEnvs = append(cmdEnvs, "GOROOT="+goConfig.GOROOT)
	}
	verOut, err := command.New(goConfig.GoBinaryPath, "version").SetEnvs(cmdEnvs...).RunAndReturnTrimmedOutput()
	if err != nil {
		return false, ToolkitCheckResult{}, fmt.Errorf("Failed to check go version, error: %s", err)
	}

	verStr, err := parseGoVersionFromGoVersionOutput(verOut)
	if err != nil {
		return false, ToolkitCheckResult{}, fmt.Errorf("Failed to parse go version, error: %s", err)
	}

	checkRes := ToolkitCheckResult{
		Path:    goConfig.GoBinaryPath,
		Version: verStr,
	}

	// version check
	isVersionOk, err := versions.IsVersionGreaterOrEqual(verStr, minGoVersionForToolkit)
	if err != nil {
		return false, checkRes, fmt.Errorf("Failed to validate installed go version, error: %s", err)
	}
	if !isVersionOk {
		return true, checkRes, nil
	}

	return false, checkRes, nil
}

func selectGoConfiguration() (bool, ToolkitCheckResult, GoConfigurationModel, error) {
	potentialGoConfigurations := []GoConfigurationModel{}
	// from PATH
	{
		binPath, err := utils.CheckProgramInstalledPath("go")
		if err == nil {
			potentialGoConfigurations = append(potentialGoConfigurations, GoConfigurationModel{GoBinaryPath: binPath})
		}
	}
	// from Bitrise Toolkits
	{
		binPath := goBinaryInToolkitFullPath()
		if isExist, err := pathutil.IsPathExists(binPath); err != nil {
			log.Warnf("Failed to check the status of the 'go' binary inside the Bitrise Toolkit dir, error: %s", err)
		} else if isExist {
			potentialGoConfigurations = append(potentialGoConfigurations, GoConfigurationModel{
				GoBinaryPath: binPath,
				GOROOT:       goToolkitInstallRootPath(),
			})
		}
	}

	isRequireInstall := true
	checkResult := ToolkitCheckResult{}
	goConfig := GoConfigurationModel{}
	var checkError error
	for _, aPotentialGoInfoToUse := range potentialGoConfigurations {
		isInstReq, chkRes, err := checkGoConfiguration(aPotentialGoInfoToUse)
		checkResult = chkRes
		checkError = err
		if !isInstReq {
			// select this one
			goConfig = aPotentialGoInfoToUse
			isRequireInstall = false
			break
		}
	}

	if len(potentialGoConfigurations) > 0 && isRequireInstall {
		log.Warnf("Installed go found (path: %s), but not a supported version: %s", checkResult.Path, checkResult.Version)
	}

	return isRequireInstall, checkResult, goConfig, checkError
}

// Check ...
func (toolkit GoToolkit) Check() (bool, ToolkitCheckResult, error) {
	isInstallRequired, checkResult, _, err := selectGoConfiguration()
	return isInstallRequired, checkResult, err
}

func parseGoVersionFromGoVersionOutput(goVersionCallOutput string) (string, error) {
	origGoVersionCallOutput := goVersionCallOutput
	goVersionCallOutput = strings.TrimSpace(goVersionCallOutput)
	if goVersionCallOutput == "" {
		return "", errors.New("Failed to parse Go version, error: version call output was empty")
	}

	// example goVersionCallOutput: go version go1.7 darwin/amd64
	goVerExp := regexp.MustCompile(`go version go(?P<goVersionNumber>[0-9.]+) (?P<platform>[a-zA-Z0-9]+/[a-zA-Z0-9]+)`)
	expRes := goVerExp.FindStringSubmatch(goVersionCallOutput)
	if expRes == nil {
		return "", fmt.Errorf("Failed to parse Go version, error: failed to find version in input: %s", origGoVersionCallOutput)
	}
	verStr := expRes[1]

	return verStr, nil
}

// IsToolAvailableInPATH ...
func (toolkit GoToolkit) IsToolAvailableInPATH() bool {
	if configs.IsDebugUseSystemTools() {
		log.Warnf("[BitriseDebug] Using system tools (system installed Go), instead of the ones in BITRISE_HOME")
		return true
	}

	if _, err := utils.CheckProgramInstalledPath("go"); err != nil {
		return false
	}

	if _, err := command.RunCommandAndReturnStdout("go", "version"); err != nil {
		return false
	}

	return true
}

// === Toolkit: Bootstrap ===

// Bootstrap ...
func (toolkit GoToolkit) Bootstrap() error {
	if toolkit.IsToolAvailableInPATH() {
		return nil
	}

	pthWithGoBins := configs.GeneratePATHEnvString(os.Getenv("PATH"), goToolkitBinsPath())
	if err := os.Setenv("PATH", pthWithGoBins); err != nil {
		return fmt.Errorf("Failed to set PATH to include the Go toolkit bins, error: %s", err)
	}

	if err := os.Setenv("GOROOT", goToolkitInstallRootPath()); err != nil {
		return fmt.Errorf("Failed to set GOROOT to Go toolkit root, error: %s", err)
	}

	return nil
}

// === Toolkit: Install ===

func installGoTar(goTarGzPath string) error {
	installToPath := goToolkitInstallToPath()

	if err := os.RemoveAll(installToPath); err != nil {
		return fmt.Errorf("Failed to remove previous Go toolkit install (path: %s), error: %s", installToPath, err)
	}
	if err := pathutil.EnsureDirExist(installToPath); err != nil {
		return fmt.Errorf("Failed create Go toolkit directory (path: %s), error: %s", installToPath, err)
	}

	cmd := command.New("tar", "-C", installToPath, "-xzf", goTarGzPath)
	if combinedOut, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil {
		log.Errorf(" [!] Failed to uncompress Go toolkit, output:")
		log.Errorf(combinedOut)
		return fmt.Errorf("Failed to uncompress Go toolkit, error: %s", err)
	}
	return nil
}

// Install ...
func (toolkit GoToolkit) Install() error {
	versionStr := minGoVersionForToolkit
	osStr := runtime.GOOS
	archStr := runtime.GOARCH
	extentionStr := "tar.gz"
	if osStr == "windows" {
		extentionStr = "zip"
	}
	downloadURL := fmt.Sprintf("https://storage.googleapis.com/golang/go%s.%s-%s.%s", versionStr, osStr, archStr, extentionStr)

	goTmpDirPath := goToolkitTmpDirPath()
	if err := pathutil.EnsureDirExist(goTmpDirPath); err != nil {
		return fmt.Errorf("Failed to create Toolkits TMP directory, error: %s", err)
	}

	localFileName := "go." + extentionStr
	goArchiveDownloadPath := filepath.Join(goTmpDirPath, localFileName)

	var downloadErr error
	progress.NewDefaultWrapper("Downloading").WrapAction(func() {
		downloadErr = retry.Times(2).Wait(5 * time.Second).Try(func(attempt uint) error {
			if attempt > 0 {
				log.Warnf("==> Download failed, retrying ...")
			}
			return tools.DownloadFile(downloadURL, goArchiveDownloadPath)
		})
	})
	if downloadErr != nil {
		return fmt.Errorf("Failed to download toolkit (%s), error: %s", downloadURL, downloadErr)
	}

	fmt.Println("=> Installing ...")
	if err := installGoTar(goArchiveDownloadPath); err != nil {
		return fmt.Errorf("Failed to install Go toolkit, error: %s", err)
	}
	if err := os.Remove(goArchiveDownloadPath); err != nil {
		return fmt.Errorf("Failed to remove the downloaded Go archive (path: %s), error: %s", goArchiveDownloadPath, err)
	}
	fmt.Println("=> Installing [DONE]")

	return nil
}

// === Toolkit: Prepare for Step Run ===

func goBuildInIsolation(packageName, srcPath, outputBinPath string) error {
	workspaceRootPath, err := pathutil.NormalizedOSTempDirPath("bitrise-go-toolkit")
	if err != nil {
		return fmt.Errorf("Failed to create root directory of isolated workspace, error: %s", err)
	}

	// origGOPATH := os.Getenv("GOPATH")
	// if origGOPATH == "" {
	// 	return fmt.Errorf("You don't have a GOPATH environment - please set it; GOPATH/bin will be symlinked")
	// }

	// if err := gows.CreateGopathBinSymlink(origGOPATH, workspaceRootPath); err != nil {
	// 	return fmt.Errorf("Failed to create GOPATH/bin symlink, error: %s", err)
	// }

	fullPackageWorkspacePath := filepath.Join(workspaceRootPath, "src", packageName)
	if err := gows.CreateOrUpdateSymlink(srcPath, fullPackageWorkspacePath); err != nil {
		return fmt.Errorf("Failed to create Project->Workspace symlink, error: %s", err)
	}

	{
		isInstallRequired, _, goConfig, err := selectGoConfiguration()
		if err != nil {
			return fmt.Errorf("Failed to select an appropriate Go installation for compiling the step, error: %s", err)
		}
		if isInstallRequired {
			return fmt.Errorf("Failed to select an appropriate Go installation for compiling the step, error: %s",
				"Found Go version is older than required. Please run 'bitrise setup' to check and install the required version")
		}

		cmd := gows.CreateCommand(workspaceRootPath, workspaceRootPath,
			goConfig.GoBinaryPath, "build", "-o", outputBinPath, packageName)
		cmd.Env = append(cmd.Env, "GOROOT="+goConfig.GOROOT)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("Failed to install package, error: %s", err)
		}
	}

	{
		if err := os.RemoveAll(workspaceRootPath); err != nil {
			return fmt.Errorf("Failed to delete temporary isolated workspace, error: %s", err)
		}
	}

	return nil
}

// stepIDorURI : doesn't work for "path::./" yet!!
func stepBinaryFilename(sIDData models.StepIDData) string {
	//
	replaceRexp, err := regexp.Compile("[^A-Za-z0-9.-]")
	if err != nil {
		log.Warnf("Invalid regex, error: %s", err)
		return ""
	}

	compositeStepID := fmt.Sprintf("%s-%s-%s",
		sIDData.SteplibSource, sIDData.IDorURI, sIDData.Version)

	safeStepID := replaceRexp.ReplaceAllString(compositeStepID, "_")
	//
	return safeStepID
}

func stepBinaryCacheFullPath(sIDData models.StepIDData) string {
	return filepath.Join(goToolkitCacheRootPath(), stepBinaryFilename(sIDData))
}

// PrepareForStepRun ...
func (toolkit GoToolkit) PrepareForStepRun(step stepmanModels.StepModel, sIDData models.StepIDData, stepAbsDirPath string) error {
	fullStepBinPath := stepBinaryCacheFullPath(sIDData)

	// try to use cached binary, if possible
	if sIDData.IsUniqueResourceID() {
		if exists, err := pathutil.IsPathExists(fullStepBinPath); err != nil {
			log.Warnf("Failed to check cached binary for step, error: %s", err)
		} else if exists {
			return nil
		}
	}

	// it's not cached, so compile it

	if step.Toolkit == nil {
		return errors.New("No Toolkit information specified in step")
	}
	if step.Toolkit.Go == nil {
		return errors.New("No Toolkit.Go information specified in step")
	}
	packageName := step.Toolkit.Go.PackageName

	return goBuildInIsolation(packageName, stepAbsDirPath, fullStepBinPath)
}

// === Toolkit: Step Run ===

// StepRunCommandArguments ...
func (toolkit GoToolkit) StepRunCommandArguments(step stepmanModels.StepModel, sIDData models.StepIDData, stepAbsDirPath string) ([]string, error) {
	fullStepBinPath := stepBinaryCacheFullPath(sIDData)
	return []string{fullStepBinPath}, nil
}

// === Toolkit path utility function ===

func goToolkitRootPath() string {
	return filepath.Join(configs.GetBitriseToolkitsDirPath(), "go")
}

func goToolkitTmpDirPath() string {
	return filepath.Join(goToolkitRootPath(), "tmp")
}

func goToolkitInstallToPath() string {
	return filepath.Join(goToolkitRootPath(), "inst")
}
func goToolkitCacheRootPath() string {
	return filepath.Join(goToolkitRootPath(), "cache")
}

func goToolkitInstallRootPath() string {
	return filepath.Join(goToolkitInstallToPath(), "go")
}

func goToolkitBinsPath() string {
	return filepath.Join(goToolkitInstallRootPath(), "bin")
}

func goBinaryInToolkitFullPath() string {
	return filepath.Join(goToolkitBinsPath(), "go")
}
<commit_msg>Go toolkit: version bump: go 1.9.1 -> 1.9.2 (#545)<commit_after>package toolkits

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	"github.com/bitrise-io/bitrise/configs"
	"github.com/bitrise-io/bitrise/models"
	"github.com/bitrise-io/bitrise/tools"
	"github.com/bitrise-io/bitrise/utils"
	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/go-utils/progress"
	"github.com/bitrise-io/go-utils/retry"
	"github.com/bitrise-io/go-utils/versions"
	stepmanModels "github.com/bitrise-io/stepman/models"
	"github.com/bitrise-tools/gows/gows"
)

const (
	minGoVersionForToolkit = "1.9.2"
)

// === Base Toolkit struct ===

// GoToolkit ...
type GoToolkit struct {
}

// ToolkitName ...
func (toolkit GoToolkit) ToolkitName() string {
	return "go"
}

// === Toolkit: Check ===

// GoConfigurationModel ...
type GoConfigurationModel struct {
	// full path of the go binary to use
	GoBinaryPath string
	// GOROOT env var value to set (unless empty)
	GOROOT string
}

func checkGoConfiguration(goConfig GoConfigurationModel) (bool, ToolkitCheckResult, error) {
	cmdEnvs := os.Environ()
	if len(goConfig.GOROOT) > 0 {
		cmdEnvs = append(cmdEnvs, "GOROOT="+goConfig.GOROOT)
	}
	verOut, err := command.New(goConfig.GoBinaryPath, "version").SetEnvs(cmdEnvs...).RunAndReturnTrimmedOutput()
	if err != nil {
		return false, ToolkitCheckResult{}, fmt.Errorf("Failed to check go version, error: %s", err)
	}

	verStr, err := parseGoVersionFromGoVersionOutput(verOut)
	if err != nil {
		return false, ToolkitCheckResult{}, fmt.Errorf("Failed to parse go version, error: %s", err)
	}

	checkRes := ToolkitCheckResult{
		Path:    goConfig.GoBinaryPath,
		Version: verStr,
	}

	// version check
	isVersionOk, err := versions.IsVersionGreaterOrEqual(verStr, minGoVersionForToolkit)
	if err != nil {
		return false, checkRes, fmt.Errorf("Failed to validate installed go version, error: %s", err)
	}
	if !isVersionOk {
		return true, checkRes, nil
	}

	return false, checkRes, nil
}

func selectGoConfiguration() (bool, ToolkitCheckResult, GoConfigurationModel, error) {
	potentialGoConfigurations := []GoConfigurationModel{}
	// from PATH
	{
		binPath, err := utils.CheckProgramInstalledPath("go")
		if err == nil {
			potentialGoConfigurations = append(potentialGoConfigurations, GoConfigurationModel{GoBinaryPath: binPath})
		}
	}
	// from Bitrise Toolkits
	{
		binPath := goBinaryInToolkitFullPath()
		if isExist, err := pathutil.IsPathExists(binPath); err != nil {
			log.Warnf("Failed to check the status of the 'go' binary inside the Bitrise Toolkit dir, error: %s", err)
		} else if isExist {
			potentialGoConfigurations = append(potentialGoConfigurations, GoConfigurationModel{
				GoBinaryPath: binPath,
				GOROOT:       goToolkitInstallRootPath(),
			})
		}
	}

	isRequireInstall := true
	checkResult := ToolkitCheckResult{}
	goConfig := GoConfigurationModel{}
	var checkError error
	for _, aPotentialGoInfoToUse := range potentialGoConfigurations {
		isInstReq, chkRes, err := checkGoConfiguration(aPotentialGoInfoToUse)
		checkResult = chkRes
		checkError = err
		if !isInstReq {
			// select this one
			goConfig = aPotentialGoInfoToUse
			isRequireInstall = false
			break
		}
	}

	if len(potentialGoConfigurations) > 0 && isRequireInstall {
		log.Warnf("Installed go found (path: %s), but not a supported version: %s", checkResult.Path, checkResult.Version)
	}

	return isRequireInstall, checkResult, goConfig, checkError
}

// Check ...
func (toolkit GoToolkit) Check() (bool, ToolkitCheckResult, error) {
	isInstallRequired, checkResult, _, err := selectGoConfiguration()
	return isInstallRequired, checkResult, err
}

func parseGoVersionFromGoVersionOutput(goVersionCallOutput string) (string, error) {
	origGoVersionCallOutput := goVersionCallOutput
	goVersionCallOutput = strings.TrimSpace(goVersionCallOutput)
	if goVersionCallOutput == "" {
		return "", errors.New("Failed to parse Go version, error: version call output was empty")
	}

	// example goVersionCallOutput: go version go1.7 darwin/amd64
	goVerExp := regexp.MustCompile(`go version go(?P<goVersionNumber>[0-9.]+) (?P<platform>[a-zA-Z0-9]+/[a-zA-Z0-9]+)`)
	expRes := goVerExp.FindStringSubmatch(goVersionCallOutput)
	if expRes == nil {
		return "", fmt.Errorf("Failed to parse Go version, error: failed to find version in input: %s", origGoVersionCallOutput)
	}
	verStr := expRes[1]

	return verStr, nil
}

// IsToolAvailableInPATH ...
func (toolkit GoToolkit) IsToolAvailableInPATH() bool {
	if configs.IsDebugUseSystemTools() {
		log.Warnf("[BitriseDebug] Using system tools (system installed Go), instead of the ones in BITRISE_HOME")
		return true
	}

	if _, err := utils.CheckProgramInstalledPath("go"); err != nil {
		return false
	}

	if _, err := command.RunCommandAndReturnStdout("go", "version"); err != nil {
		return false
	}

	return true
}

// === Toolkit: Bootstrap ===

// Bootstrap ...
func (toolkit GoToolkit) Bootstrap() error {
	if toolkit.IsToolAvailableInPATH() {
		return nil
	}

	pthWithGoBins := configs.GeneratePATHEnvString(os.Getenv("PATH"), goToolkitBinsPath())
	if err := os.Setenv("PATH", pthWithGoBins); err != nil {
		return fmt.Errorf("Failed to set PATH to include the Go toolkit bins, error: %s", err)
	}

	if err := os.Setenv("GOROOT", goToolkitInstallRootPath()); err != nil {
		return fmt.Errorf("Failed to set GOROOT to Go toolkit root, error: %s", err)
	}

	return nil
}

// === Toolkit: Install ===

func installGoTar(goTarGzPath string) error {
	installToPath := goToolkitInstallToPath()

	if err := os.RemoveAll(installToPath); err != nil {
		return fmt.Errorf("Failed to remove previous Go toolkit install (path: %s), error: %s", installToPath, err)
	}
	if err := pathutil.EnsureDirExist(installToPath); err != nil {
		return fmt.Errorf("Failed create Go toolkit directory (path: %s), error: %s", installToPath, err)
	}

	cmd := command.New("tar", "-C", installToPath, "-xzf", goTarGzPath)
	if combinedOut, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil {
		log.Errorf(" [!] Failed to uncompress Go toolkit, output:")
		log.Errorf(combinedOut)
		return fmt.Errorf("Failed to uncompress Go toolkit, error: %s", err)
	}
	return nil
}

// Install ...
func (toolkit GoToolkit) Install() error {
	versionStr := minGoVersionForToolkit
	osStr := runtime.GOOS
	archStr := runtime.GOARCH
	extentionStr := "tar.gz"
	if osStr == "windows" {
		extentionStr = "zip"
	}
	downloadURL := fmt.Sprintf("https://storage.googleapis.com/golang/go%s.%s-%s.%s", versionStr, osStr, archStr, extentionStr)

	goTmpDirPath := goToolkitTmpDirPath()
	if err := pathutil.EnsureDirExist(goTmpDirPath); err != nil {
		return fmt.Errorf("Failed to create Toolkits TMP directory, error: %s", err)
	}

	localFileName := "go." + extentionStr
	goArchiveDownloadPath := filepath.Join(goTmpDirPath, localFileName)

	var downloadErr error
	progress.NewDefaultWrapper("Downloading").WrapAction(func() {
		downloadErr = retry.Times(2).Wait(5 * time.Second).Try(func(attempt uint) error {
			if attempt > 0 {
				log.Warnf("==> Download failed, retrying ...")
			}
			return tools.DownloadFile(downloadURL, goArchiveDownloadPath)
		})
	})
	if downloadErr != nil {
		return fmt.Errorf("Failed to download toolkit (%s), error: %s", downloadURL, downloadErr)
	}

	fmt.Println("=> Installing ...")
	if err := installGoTar(goArchiveDownloadPath); err != nil {
		return fmt.Errorf("Failed to install Go toolkit, error: %s", err)
	}
	if err := os.Remove(goArchiveDownloadPath); err != nil {
		return fmt.Errorf("Failed to remove the downloaded Go archive (path: %s), error: %s", goArchiveDownloadPath, err)
	}
	fmt.Println("=> Installing [DONE]")

	return nil
}

// === Toolkit: Prepare for Step Run ===

func goBuildInIsolation(packageName, srcPath, outputBinPath string) error {
	workspaceRootPath, err := pathutil.NormalizedOSTempDirPath("bitrise-go-toolkit")
	if err != nil {
		return fmt.Errorf("Failed to create root directory of isolated workspace, error: %s", err)
	}

	// origGOPATH := os.Getenv("GOPATH")
	// if origGOPATH == "" {
	// 	return fmt.Errorf("You don't have a GOPATH environment - please set it; GOPATH/bin will be symlinked")
	// }

	// if err := gows.CreateGopathBinSymlink(origGOPATH, workspaceRootPath); err != nil {
	// 	return fmt.Errorf("Failed to create GOPATH/bin symlink, error: %s", err)
	// }

	fullPackageWorkspacePath := filepath.Join(workspaceRootPath, "src", packageName)
	if err := gows.CreateOrUpdateSymlink(srcPath, fullPackageWorkspacePath); err != nil {
		return fmt.Errorf("Failed to create Project->Workspace symlink, error: %s", err)
	}

	{
		isInstallRequired, _, goConfig, err := selectGoConfiguration()
		if err != nil {
			return fmt.Errorf("Failed to select an appropriate Go installation for compiling the step, error: %s", err)
		}
		if isInstallRequired {
			return fmt.Errorf("Failed to select an appropriate Go installation for compiling the step, error: %s",
				"Found Go version is older than required. Please run 'bitrise setup' to check and install the required version")
		}

		cmd := gows.CreateCommand(workspaceRootPath, workspaceRootPath,
			goConfig.GoBinaryPath, "build", "-o", outputBinPath, packageName)
		cmd.Env = append(cmd.Env, "GOROOT="+goConfig.GOROOT)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("Failed to install package, error: %s", err)
		}
	}

	{
		if err := os.RemoveAll(workspaceRootPath); err != nil {
			return fmt.Errorf("Failed to delete temporary isolated workspace, error: %s", err)
		}
	}

	return nil
}

// stepIDorURI : doesn't work for "path::./" yet!!
func stepBinaryFilename(sIDData models.StepIDData) string {
	//
	replaceRexp, err := regexp.Compile("[^A-Za-z0-9.-]")
	if err != nil {
		log.Warnf("Invalid regex, error: %s", err)
		return ""
	}

	compositeStepID := fmt.Sprintf("%s-%s-%s",
		sIDData.SteplibSource, sIDData.IDorURI, sIDData.Version)

	safeStepID := replaceRexp.ReplaceAllString(compositeStepID, "_")
	//
	return safeStepID
}

func stepBinaryCacheFullPath(sIDData models.StepIDData) string {
	return filepath.Join(goToolkitCacheRootPath(), stepBinaryFilename(sIDData))
}

// PrepareForStepRun ...
func (toolkit GoToolkit) PrepareForStepRun(step stepmanModels.StepModel, sIDData models.StepIDData, stepAbsDirPath string) error {
	fullStepBinPath := stepBinaryCacheFullPath(sIDData)

	// try to use cached binary, if possible
	if sIDData.IsUniqueResourceID() {
		if exists, err := pathutil.IsPathExists(fullStepBinPath); err != nil {
			log.Warnf("Failed to check cached binary for step, error: %s", err)
		} else if exists {
			return nil
		}
	}

	// it's not cached, so compile it

	if step.Toolkit == nil {
		return errors.New("No Toolkit information specified in step")
	}
	if step.Toolkit.Go == nil {
		return errors.New("No Toolkit.Go information specified in step")
	}
	packageName := step.Toolkit.Go.PackageName

	return goBuildInIsolation(packageName, stepAbsDirPath, fullStepBinPath)
}

// === Toolkit: Step Run ===

// StepRunCommandArguments ...
func (toolkit GoToolkit) StepRunCommandArguments(step stepmanModels.StepModel, sIDData models.StepIDData, stepAbsDirPath string) ([]string, error) {
	fullStepBinPath := stepBinaryCacheFullPath(sIDData)
	return []string{fullStepBinPath}, nil
}

// === Toolkit path utility function ===

func goToolkitRootPath() string {
	return filepath.Join(configs.GetBitriseToolkitsDirPath(), "go")
}

func goToolkitTmpDirPath() string {
	return filepath.Join(goToolkitRootPath(), "tmp")
}

func goToolkitInstallToPath() string {
	return filepath.Join(goToolkitRootPath(), "inst")
}
func goToolkitCacheRootPath() string {
	return filepath.Join(goToolkitRootPath(), "cache")
}

func goToolkitInstallRootPath() string {
	return filepath.Join(goToolkitInstallToPath(), "go")
}

func goToolkitBinsPath() string {
	return filepath.Join(goToolkitInstallRootPath(), "bin")
}

func goBinaryInToolkitFullPath() string {
	return filepath.Join(goToolkitBinsPath(), "go")
}
<|endoftext|>


<commit_before>package render

import (
	"image/color"
	"testing"
)

func TestColorBox(t *testing.T) {
	c := color.RGBA{255, 200, 255, 255}
	sp := NewColorBox(5, 5, c)
	rgba := sp.GetRGBA()
	for x := 0; x < 5; x++ {
		for y := 0; y < 5; y++ {
			if rgba.At(x, y) != c {
				t.Fatalf("rgba not set at %v,%v", x, y)
			}
		}
	}
	if rgba.At(6, 6) != (color.RGBA{0, 0, 0, 0}) {
		t.Fatalf("rgba exceeded w/h")
	}
}
<commit_msg>render: add property based testing for color box R<commit_after>package render

import (
	"image"
	"image/color"
	"testing"
	"testing/quick"
)

func TestColorBox(t *testing.T) {
	c := color.RGBA{255, 200, 255, 255}
	sp := NewColorBox(5, 5, c)
	rgba := sp.GetRGBA()
	for x := 0; x < 5; x++ {
		for y := 0; y < 5; y++ {
			if rgba.At(x, y) != c {
				t.Fatalf("rgba not set at %v,%v", x, y)
			}
		}
	}
	if rgba.At(6, 6) != (color.RGBA{0, 0, 0, 0}) {
		t.Fatalf("rgba exceeded w/h")
	}
}

func TestColorBoxR(t *testing.T) {
	if err := quick.Check(testColorBoxRProperties, nil); err != nil {
		t.Error(err)
	}
}

// w and h are int8 because int16 can make us check 65536*65536 = 4 billion pixels which can time out
func testColorBoxRProperties(r, g, b, a uint8, w8, h8 int8) bool {
	c := color.RGBA{r, g, b, a}
	w := int(w8)
	h := int(h8)
	sp := NewColorBoxR(w, h, c)
	w2, h2 := sp.GetDims()
	if w2 != w {
		return false
	}
	if h2 != h {
		return false
	}
	img := image.NewRGBA(image.Rect(0, 0, w, h))
	sp.Draw(img, 0, 0)
	for x := 0; x < w; x++ {
		for y := 0; y < h; y++ {
			cAt := img.RGBAAt(x, y)
			if c != cAt {
				return false
			}
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package uid

import (
	"bytes"
	"io"
	"testing"
	"time"

	"github.com/agl/ed25519"
	"github.com/mutecomm/mute/cipher"
	"github.com/mutecomm/mute/encode/base64"
	"github.com/mutecomm/mute/keyserver/hashchain"
	"github.com/mutecomm/mute/util/times"
)

func TestKeyInitSuccess(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if err := ki.Check(); err != nil {
		t.Error(err)
	}
	// getter methods
	if ki.MsgCount() != ki.CONTENTS.MSGCOUNT {
		t.Error("msgCount mismatch")
	}
	if ki.SigKeyHash() != ki.CONTENTS.SIGKEYHASH {
		t.Error("sigKeyHash mismatch")
	}
	// JSON conversion
	jsn := ki.JSON()
	jsnKI, err := NewJSONKeyInit(jsn)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(jsn, jsnKI.JSON()) {
		t.Errorf("KeyInits differ")
	}
	// verify
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != nil {
		t.Error(err)
	}
	// sign
	sigKey, err := cipher.Ed25519Generate(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	sig := ki.Sign(sigKey)
	// verify signature
	pubKey := base64.Encode(sigKey.PublicKey()[:])
	if err := ki.VerifySrvSig(sig, pubKey); err != nil {
		t.Error(err)
	}
}

func TestExpired(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.Now()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// wait until key init expires
	time.Sleep(time.Second)
	// verify
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != ErrExpired {
		t.Error("should fail")
	}
}

func TestKeyInitFailure(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// invalid times
	_, _, _, err = msg.KeyInit(0, 0, 0, false, "mute.berlin", "", "",
		cipher.RandReader)
	if err != ErrInvalidTimes {
		t.Error("should fail")
	}
	_, _, _, err = msg.KeyInit(0, 1, 0, false, "mute.berlin", "", "",
		cipher.RandReader)
	if err != ErrExpired {
		t.Error("should fail")
	}
	_, _, _, err = msg.KeyInit(0, uint64(times.OneYearLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != ErrFuture {
		t.Fatal(err)
	}
	// rand fail
	_, _, _, err = msg.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandFail)
	if err == nil {
		t.Error("should fail")
	}
	// decode failure
	msg.UIDContent.SIGKEY.HASH = "!"
	_, _, _, err = msg.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err == nil {
		t.Error("should fail")
	}
}

func TestVerifyFailure(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	other, err := Create("other@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	ki2, _, _, err := other.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// repo URI
	if err := ki.Verify(nil, msg.UIDContent.SIGKEY.PUBKEY); err != ErrRepoURI {
		t.Error("should fail")
	}
	// sighash
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, other.UIDContent.SIGKEY.PUBKEY); err != ErrWrongSigKeyHash {
		t.Error("should fail")
	}
	// bad signature
	sig := ki.SIGNATURE
	ki.SIGNATURE = "!"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err == nil {
		t.Error("should fail")
	}
	ki.SIGNATURE = sig
	pubKey := msg.UIDContent.SIGKEY.PUBKEY
	msg.UIDContent.SIGKEY.PUBKEY = "!"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err == nil {
		t.Error("should fail")
	}
	// wrong signature
	msg.UIDContent.SIGKEY.PUBKEY = pubKey
	ki.SIGNATURE = ki2.SIGNATURE
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != ErrInvalidKeyInitSig {
		t.Error("should fail")
	}
	// invalid times
	ki2.CONTENTS.MSGCOUNT = 1
	ki2.CONTENTS.NOTAFTER = 0
	if err := ki2.Verify(uris, other.UIDContent.SIGKEY.PUBKEY); err != ErrInvalidTimes {
		t.Error("should fail")
	}
}

func TestVerifySrvSigfailure(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// sign
	sigKey, err := cipher.Ed25519Generate(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	sig := ki.Sign(sigKey)
	pubKey := base64.Encode(sigKey.PublicKey()[:])
	// invalid signature
	if err := ki.VerifySrvSig("!", pubKey); err == nil {
		t.Error("should fail")
	}
	// invalid public key
	if err := ki.VerifySrvSig(sig, "!"); err == nil {
		t.Error("should fail")
	}
	// invalid signature
	var signature [ed25519.PrivateKeySize]byte
	if _, err := io.ReadFull(cipher.RandReader, signature[:]); err != nil {
		t.Fatal(err)
	}
	sig = base64.Encode(signature[:])
	if err := ki.VerifySrvSig(sig, pubKey); err == nil {
		t.Error("should fail")
	}
}

func TestSessionAnchor(t *testing.T) {
	// create UID message
	msg, err := Create("alice@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}

	// KeyInit
	now := uint64(times.Now())
	ki, _, privKey, err := msg.KeyInit(1, now+times.Day, now-times.Day,
		false, "mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}

	// SesionAnchor
	sa, err := ki.SessionAnchor(msg.SigPubKey())
	if err != nil {
		t.Fatal(err)
	}

	// check private key methods
	if err := sa.SetPrivateKey(privKey); err != nil {
		t.Fatal(err)
	}
	if privKey != sa.PrivateKey() {
		t.Fatal("private keys differ")
	}
}
<commit_msg>uid: fix unit tests<commit_after>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package uid

import (
	"bytes"
	"io"
	"testing"
	"time"

	"github.com/agl/ed25519"
	"github.com/mutecomm/mute/cipher"
	"github.com/mutecomm/mute/encode/base64"
	"github.com/mutecomm/mute/keyserver/hashchain"
	"github.com/mutecomm/mute/util/times"
)

func TestKeyInitSuccess(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if err := ki.Check(); err != nil {
		t.Error(err)
	}
	// getter methods
	if ki.MsgCount() != ki.Contents.MSGCOUNT {
		t.Error("msgCount mismatch")
	}
	if ki.SigKeyHash() != ki.Contents.SIGKEYHASH {
		t.Error("sigKeyHash mismatch")
	}
	// JSON conversion
	jsn := ki.JSON()
	jsnKI, err := NewJSONKeyInit(jsn)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(jsn, jsnKI.JSON()) {
		t.Errorf("KeyInits differ")
	}
	// verify
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != nil {
		t.Error(err)
	}
	// sign
	sigKey, err := cipher.Ed25519Generate(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	sig := ki.Sign(sigKey)
	// verify signature
	pubKey := base64.Encode(sigKey.PublicKey()[:])
	if err := ki.VerifySrvSig(sig, pubKey); err != nil {
		t.Error(err)
	}
}

func TestExpired(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.Now()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// wait until key init expires
	time.Sleep(time.Second)
	// verify
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != ErrExpired {
		t.Error("should fail")
	}
}

func TestKeyInitFailure(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// invalid times
	_, _, _, err = msg.KeyInit(0, 0, 0, false, "mute.berlin", "", "",
		cipher.RandReader)
	if err != ErrInvalidTimes {
		t.Error("should fail")
	}
	_, _, _, err = msg.KeyInit(0, 1, 0, false, "mute.berlin", "", "",
		cipher.RandReader)
	if err != ErrExpired {
		t.Error("should fail")
	}
	_, _, _, err = msg.KeyInit(0, uint64(times.OneYearLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != ErrFuture {
		t.Fatal(err)
	}
	// rand fail
	_, _, _, err = msg.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandFail)
	if err == nil {
		t.Error("should fail")
	}
	// decode failure
	msg.UIDContent.SIGKEY.HASH = "!"
	_, _, _, err = msg.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err == nil {
		t.Error("should fail")
	}
}

func TestVerifyFailure(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	other, err := Create("other@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	ki2, _, _, err := other.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// repo URI
	if err := ki.Verify(nil, msg.UIDContent.SIGKEY.PUBKEY); err != ErrRepoURI {
		t.Error("should fail")
	}
	// sighash
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, other.UIDContent.SIGKEY.PUBKEY); err != ErrWrongSigKeyHash {
		t.Error("should fail")
	}
	// bad signature
	sig := ki.SIGNATURE
	ki.SIGNATURE = "!"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err == nil {
		t.Error("should fail")
	}
	ki.SIGNATURE = sig
	pubKey := msg.UIDContent.SIGKEY.PUBKEY
	msg.UIDContent.SIGKEY.PUBKEY = "!"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err == nil {
		t.Error("should fail")
	}
	// wrong signature
	msg.UIDContent.SIGKEY.PUBKEY = pubKey
	ki.SIGNATURE = ki2.SIGNATURE
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != ErrInvalidKeyInitSig {
		t.Error("should fail")
	}
	// invalid times
	ki2.Contents.MSGCOUNT = 1
	ki2.Contents.NOTAFTER = 0
	if err := ki2.Verify(uris, other.UIDContent.SIGKEY.PUBKEY); err != ErrInvalidTimes {
		t.Error("should fail")
	}
}

func TestVerifySrvSigfailure(t *testing.T) {
	msg, err := Create("test@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// sign
	sigKey, err := cipher.Ed25519Generate(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	sig := ki.Sign(sigKey)
	pubKey := base64.Encode(sigKey.PublicKey()[:])
	// invalid signature
	if err := ki.VerifySrvSig("!", pubKey); err == nil {
		t.Error("should fail")
	}
	// invalid public key
	if err := ki.VerifySrvSig(sig, "!"); err == nil {
		t.Error("should fail")
	}
	// invalid signature
	var signature [ed25519.PrivateKeySize]byte
	if _, err := io.ReadFull(cipher.RandReader, signature[:]); err != nil {
		t.Fatal(err)
	}
	sig = base64.Encode(signature[:])
	if err := ki.VerifySrvSig(sig, pubKey); err == nil {
		t.Error("should fail")
	}
}

func TestSessionAnchor(t *testing.T) {
	// create UID message
	msg, err := Create("alice@mute.berlin", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}

	// KeyInit
	now := uint64(times.Now())
	ki, _, privKey, err := msg.KeyInit(1, now+times.Day, now-times.Day,
		false, "mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}

	// SesionAnchor
	sa, err := ki.SessionAnchor(msg.SigPubKey())
	if err != nil {
		t.Fatal(err)
	}

	// check private key methods
	if err := sa.SetPrivateKey(privKey); err != nil {
		t.Fatal(err)
	}
	if privKey != sa.PrivateKey() {
		t.Fatal("private keys differ")
	}
}
<|endoftext|>


<commit_before>package tile

import (
	"bytes"

	"github.com/thomersch/grandine/lib/geojson"
	"github.com/thomersch/grandine/lib/spatial"
)

type Codec interface {
	EncodeTile(features map[string][]spatial.Feature, tid ID) ([]byte, error)
	Extension() string
}

// GeoJSONCodec for debugging purposes. Probably not suitable for any real-world use.
type GeoJSONCodec struct{}

func (g *GeoJSONCodec) EncodeTile(features map[string][]spatial.Feature, tid ID) ([]byte, error) {
	var buf bytes.Buffer
	var fts []spatial.Feature
	for _, ly := range features {
		for _, ft := range ly {
			fts = append(fts, ft)
		}
	}
	gjc := &geojson.Codec{}
	err := gjc.Encode(&buf, &spatial.FeatureCollection{Features: fts})
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (g *GeoJSONCodec) Extension() string {
	return "geojson"
}
<commit_msg>lib/tile: remove statement, since it's used in production<commit_after>package tile

import (
	"bytes"

	"github.com/thomersch/grandine/lib/geojson"
	"github.com/thomersch/grandine/lib/spatial"
)

type Codec interface {
	EncodeTile(features map[string][]spatial.Feature, tid ID) ([]byte, error)
	Extension() string
}

type GeoJSONCodec struct{}

func (g *GeoJSONCodec) EncodeTile(features map[string][]spatial.Feature, tid ID) ([]byte, error) {
	var buf bytes.Buffer
	var fts []spatial.Feature
	for _, ly := range features {
		for _, ft := range ly {
			fts = append(fts, ft)
		}
	}
	gjc := &geojson.Codec{}
	err := gjc.Encode(&buf, &spatial.FeatureCollection{Features: fts})
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (g *GeoJSONCodec) Extension() string {
	return "geojson"
}
<|endoftext|>