<commit_before>package main

import (
	"os"
	"io/ioutil"
	"path"
)

type FileWriter struct {
	filename string
	file     *os.File
	closeTag string
	isClosed bool
}

func NewFileWriter(filename string, openTag, closeTag string) (*FileWriter, error) {
	file, err := ioutil.TempFile(os.TempDir(), "proto2gql")

	if err != nil {
		return nil, err
	}

	file.Write([]byte(openTag))

	return &FileWriter{filename, file, closeTag, false}, nil
}

func (fw *FileWriter) IsClosed() bool {
	return fw.isClosed
}

func (fw *FileWriter) Write(p []byte) (n int, err error) {
	return fw.file.Write(p)
}

func (fw *FileWriter) Save() error {
	if fw.isClosed == true {
		return nil // return an error?
	}

	tmpName := fw.file.Name()

	fw.file.Write([]byte(fw.closeTag))

	if err := fw.Close(); err != nil {
		return err
	}

	if err := os.MkdirAll(path.Dir(fw.filename), os.ModePerm); err != nil {
		return err
	}

	return os.Rename(tmpName, fw.filename)
}

func (fw *FileWriter) Remove() error {
	if fw.isClosed == true {
		return nil // return an error?
	}

	tmpName := fw.file.Name()

	if err := fw.Close(); err != nil {
		return err
	}

	return os.Remove(tmpName)
}

func (fw *FileWriter) Close() error {
	if fw.isClosed == false {
		fw.isClosed = true

		return fw.file.Close()
	}

	return nil
}<commit_msg>Changed temp dir location<commit_after>package main

import (
	"os"
	"io/ioutil"
	"path/filepath"
)

type FileWriter struct {
	filename string
	file     *os.File
	closeTag string
	isClosed bool
}

func NewFileWriter(filename string, openTag, closeTag string) (*FileWriter, error) {
	file, err := ioutil.TempFile(filepath.Dir(filename), "proto2gql")

	if err != nil {
		return nil, err
	}

	file.Write([]byte(openTag))

	return &FileWriter{filename, file, closeTag, false}, nil
}

func (fw *FileWriter) IsClosed() bool {
	return fw.isClosed
}

func (fw *FileWriter) Write(p []byte) (n int, err error) {
	return fw.file.Write(p)
}

func (fw *FileWriter) Save() error {
	if fw.isClosed == true {
		return nil // return an error?
	}

	tmpName := fw.file.Name()

	fw.file.Write([]byte(fw.closeTag))

	if err := fw.Close(); err != nil {
		return err
	}

	if err := os.MkdirAll(filepath.Dir(fw.filename), os.ModePerm); err != nil {
		return err
	}

	return os.Rename(tmpName, fw.filename)
}

func (fw *FileWriter) Remove() error {
	if fw.isClosed == true {
		return nil // return an error?
	}

	tmpName := fw.file.Name()

	if err := fw.Close(); err != nil {
		return err
	}

	return os.Remove(tmpName)
}

func (fw *FileWriter) Close() error {
	if fw.isClosed == false {
		fw.isClosed = true

		return fw.file.Close()
	}

	return nil
}<|endoftext|>


<commit_before>/*
 * Minio Cloud Storage, (C) 2014-2016 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"fmt"
	"path"
	"time"

	"github.com/minio/minio-go/pkg/set"
)

type s3Peers struct {
	// A map of peer server address (in `host:port` format) to RPC
	// client connections
	rpcClient map[string]*AuthRPCClient

	// slice of all peer addresses (in `host:port` format)
	peers []string
}

func initGlobalS3Peers(disks []string) {
	// get list of de-duplicated peers
	peers := getAllPeers(disks)
	globalS3Peers = s3Peers{make(map[string]*AuthRPCClient), nil}
	for _, peer := range peers {
		globalS3Peers.InitS3PeerClient(peer)
	}

	// Additionally setup a local peer if one does not exist
	if globalS3Peers.GetPeerClient(globalMinioAddr) == nil {
		globalS3Peers.InitS3PeerClient(globalMinioAddr)
		peers = append(peers, globalMinioAddr)
	}

	globalS3Peers.peers = peers
}

func (s3p *s3Peers) GetPeers() []string {
	return s3p.peers
}

func (s3p *s3Peers) GetPeerClient(peer string) *AuthRPCClient {
	return s3p.rpcClient[peer]
}

// Initializes a new RPC connection (or closes and re-opens if it
// already exists) to a peer. Note that peer address is in `host:port`
// format.
func (s3p *s3Peers) InitS3PeerClient(peer string) {
	if s3p.rpcClient[peer] != nil {
		s3p.rpcClient[peer].Close()
		delete(s3p.rpcClient, peer)
	}
	authCfg := &authConfig{
		accessKey:   serverConfig.GetCredential().AccessKeyID,
		secretKey:   serverConfig.GetCredential().SecretAccessKey,
		address:     peer,
		path:        path.Join(reservedBucket, s3Path),
		loginMethod: "S3.LoginHandler",
	}
	s3p.rpcClient[peer] = newAuthClient(authCfg)
}

func (s3p *s3Peers) Close() error {
	for _, v := range s3p.rpcClient {
		if err := v.Close(); err != nil {
			return err
		}
	}
	s3p.rpcClient = nil
	s3p.peers = nil
	return nil
}

// returns the network addresses of all Minio servers in the cluster
// in `host:port` format.
func getAllPeers(disks []string) []string {
	res := []string{}
	// use set to de-duplicate
	sset := set.NewStringSet()
	for _, disk := range disks {
		netAddr, _, err := splitNetPath(disk)
		if err != nil || netAddr == "" {
			errorIf(err, "Unexpected error - most likely a bug.")
			continue
		}
		if !sset.Contains(netAddr) {
			res = append(
				res,
				fmt.Sprintf("%s:%d", netAddr, globalMinioPort),
			)
			sset.Add(netAddr)
		}
	}
	return res
}

// Make RPC calls with the given method and arguments to all the given
// peers (in parallel), and collects the results. Since the methods
// intended for use here, have only a success or failure response, we
// do not return/inspect the `reply` parameter in the RPC call. The
// function attempts to connect to a peer only once, and returns a map
// of peer address to error response. If the error is nil, it means
// the RPC succeeded.
func (s3p *s3Peers) SendRPC(peers []string, method string, args interface {
	SetToken(token string)
	SetTimestamp(tstamp time.Time)
}) map[string]error {
	// result type
	type callResult struct {
		target string
		err    error
	}
	// channel to collect results from goroutines
	resChan := make(chan callResult)
	// closure to make a single request.
	callTarget := func(target string) {
		reply := &GenericReply{}
		err := s3p.rpcClient[target].Call(method, args, reply)
		resChan <- callResult{target, err}
	}
	// map of errors
	errsMap := make(map[string]error)
	// make network calls in parallel
	for _, target := range peers {
		go callTarget(target)
	}
	// wait on channel and collect all results
	for range peers {
		res := <-resChan
		if res.err != nil {
			errsMap[res.target] = res.err
		}
	}
	// return errors map
	return errsMap
}

// S3PeersUpdateBucketNotification - Sends Update Bucket notification
// request to all peers. Currently we log an error and continue.
func S3PeersUpdateBucketNotification(bucket string, ncfg *notificationConfig) {
	setBNPArgs := &SetBNPArgs{Bucket: bucket, NCfg: ncfg}
	peers := globalS3Peers.GetPeers()
	errsMap := globalS3Peers.SendRPC(peers, "S3.SetBucketNotificationPeer",
		setBNPArgs)
	for peer, err := range errsMap {
		errorIf(err, "Error sending peer update bucket notification to %s - %v", peer, err)
	}
}

// S3PeersUpdateBucketListener - Sends Update Bucket listeners request
// to all peers. Currently we log an error and continue.
func S3PeersUpdateBucketListener(bucket string, lcfg []listenerConfig) {
	setBLPArgs := &SetBLPArgs{Bucket: bucket, LCfg: lcfg}
	peers := globalS3Peers.GetPeers()
	errsMap := globalS3Peers.SendRPC(peers, "S3.SetBucketListenerPeer",
		setBLPArgs)
	for peer, err := range errsMap {
		errorIf(err, "Error sending peer update bucket listener to %s - %v", peer, err)
	}
}
<commit_msg>Protect map from concurrent access (Fixes #2915) (#2916)<commit_after>/*
 * Minio Cloud Storage, (C) 2014-2016 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"fmt"
	"path"
	"sync"
	"time"

	"github.com/minio/minio-go/pkg/set"
)

type s3Peers struct {
	// A map of peer server address (in `host:port` format) to RPC
	// client connections.
	rpcClients map[string]*AuthRPCClient

	mutex *sync.RWMutex

	// Slice of all peer addresses (in `host:port` format).
	peers []string
}

func initGlobalS3Peers(disks []string) {
	// Get list of de-duplicated peers.
	peers := getAllPeers(disks)

	// Initialize global state.
	globalS3Peers = s3Peers{
		rpcClients: make(map[string]*AuthRPCClient),
		mutex:      &sync.RWMutex{},
	}
	// Initialize each peer connection.
	for _, peer := range peers {
		globalS3Peers.InitS3PeerClient(peer)
	}

	// Additionally setup a local peer if one does not exist.
	if globalS3Peers.GetPeerClient(globalMinioAddr) == nil {
		globalS3Peers.InitS3PeerClient(globalMinioAddr)
		peers = append(peers, globalMinioAddr)
	}

	globalS3Peers.peers = peers
}

func (s3p *s3Peers) GetPeers() []string {
	return s3p.peers
}

func (s3p *s3Peers) GetPeerClient(peer string) *AuthRPCClient {
	// Take a read lock
	s3p.mutex.RLock()
	defer s3p.mutex.RUnlock()
	return s3p.rpcClients[peer]
}

// Initializes a new RPC connection (or closes and re-opens if it
// already exists) to a peer. Note that peer address is in `host:port`
// format.
func (s3p *s3Peers) InitS3PeerClient(peer string) {
	// Take a write lock
	s3p.mutex.Lock()
	defer s3p.mutex.Unlock()

	if s3p.rpcClients[peer] != nil {
		_ = s3p.rpcClients[peer].Close()
		delete(s3p.rpcClients, peer)
	}
	authCfg := &authConfig{
		accessKey:   serverConfig.GetCredential().AccessKeyID,
		secretKey:   serverConfig.GetCredential().SecretAccessKey,
		address:     peer,
		path:        path.Join(reservedBucket, s3Path),
		loginMethod: "S3.LoginHandler",
	}
	s3p.rpcClients[peer] = newAuthClient(authCfg)
}

func (s3p *s3Peers) Close() error {
	// Take a write lock
	s3p.mutex.Lock()
	defer s3p.mutex.Unlock()

	for _, v := range s3p.rpcClients {
		if err := v.Close(); err != nil {
			return err
		}
	}
	s3p.rpcClients = nil
	s3p.peers = nil
	return nil
}

// returns the network addresses of all Minio servers in the cluster
// in `host:port` format.
func getAllPeers(disks []string) []string {
	res := []string{}
	// use set to de-duplicate
	sset := set.NewStringSet()
	for _, disk := range disks {
		netAddr, _, err := splitNetPath(disk)
		if err != nil || netAddr == "" {
			errorIf(err, "Unexpected error - most likely a bug.")
			continue
		}
		if !sset.Contains(netAddr) {
			res = append(
				res,
				fmt.Sprintf("%s:%d", netAddr, globalMinioPort),
			)
			sset.Add(netAddr)
		}
	}
	return res
}

// Make RPC calls with the given method and arguments to all the given
// peers (in parallel), and collects the results. Since the methods
// intended for use here, have only a success or failure response, we
// do not return/inspect the `reply` parameter in the RPC call. The
// function attempts to connect to a peer only once, and returns a map
// of peer address to error response. If the error is nil, it means
// the RPC succeeded.
func (s3p *s3Peers) SendRPC(peers []string, method string, args interface {
	SetToken(token string)
	SetTimestamp(tstamp time.Time)
}) map[string]error {
	// Take read lock for rpcClient map
	s3p.mutex.RLock()
	defer s3p.mutex.RUnlock()

	// Result type
	type callResult struct {
		target string
		err    error
	}

	// Channel to collect results from goroutines
	resChan := make(chan callResult)

	// Closure to make a single request.
	callTarget := func(target string) {
		reply := &GenericReply{}
		client, ok := s3p.rpcClients[target]
		var err error
		if !ok {
			err = fmt.Errorf("Requested client was not initialized - %v",
				target)
		} else {
			err = client.Call(method, args, reply)
		}
		resChan <- callResult{target, err}
	}

	// Map of errors
	errsMap := make(map[string]error)
	// make network calls in parallel
	for _, target := range peers {
		go callTarget(target)
	}
	// Wait on channel and collect all results
	for range peers {
		res := <-resChan
		if res.err != nil {
			errsMap[res.target] = res.err
		}
	}

	// Return errors map
	return errsMap
}

// S3PeersUpdateBucketNotification - Sends Update Bucket notification
// request to all peers. Currently we log an error and continue.
func S3PeersUpdateBucketNotification(bucket string, ncfg *notificationConfig) {
	setBNPArgs := &SetBNPArgs{Bucket: bucket, NCfg: ncfg}
	peers := globalS3Peers.GetPeers()
	errsMap := globalS3Peers.SendRPC(peers, "S3.SetBucketNotificationPeer",
		setBNPArgs)
	for peer, err := range errsMap {
		errorIf(err, "Error sending peer update bucket notification to %s - %v", peer, err)
	}
}

// S3PeersUpdateBucketListener - Sends Update Bucket listeners request
// to all peers. Currently we log an error and continue.
func S3PeersUpdateBucketListener(bucket string, lcfg []listenerConfig) {
	setBLPArgs := &SetBLPArgs{Bucket: bucket, LCfg: lcfg}
	peers := globalS3Peers.GetPeers()
	errsMap := globalS3Peers.SendRPC(peers, "S3.SetBucketListenerPeer",
		setBLPArgs)
	for peer, err := range errsMap {
		errorIf(err, "Error sending peer update bucket listener to %s - %v", peer, err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"errors"
	"flag"
	"net"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/cloudfoundry-incubator/bbs"
	"github.com/cloudfoundry-incubator/cf-debug-server"
	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/cf_http"
	"github.com/cloudfoundry-incubator/diego-ssh/authenticators"
	"github.com/cloudfoundry-incubator/diego-ssh/proxy"
	"github.com/cloudfoundry-incubator/diego-ssh/server"
	"github.com/cloudfoundry/dropsonde"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
	"golang.org/x/crypto/ssh"
)

var address = flag.String(
	"address",
	":2222",
	"listen address for ssh proxy",
)

var hostKey = flag.String(
	"hostKey",
	"",
	"PEM encoded RSA host key",
)

var bbsAddress = flag.String(
	"bbsAddress",
	"",
	"Address of the BBS API Server",
)

var ccAPIURL = flag.String(
	"ccAPIURL",
	"",
	"URL of Cloud Controller API",
)

var skipCertVerify = flag.Bool(
	"skipCertVerify",
	false,
	"skip SSL certificate verification",
)

var communicationTimeout = flag.Duration(
	"communicationTimeout",
	10*time.Second,
	"Timeout applied to all HTTP requests.",
)

var enableCFAuth = flag.Bool(
	"enableCFAuth",
	false,
	"Allow authentication with cf",
)

var enableDiegoAuth = flag.Bool(
	"enableDiegoAuth",
	false,
	"Allow authentication with diego",
)

var diegoCredentials = flag.String(
	"diegoCredentials",
	"",
	"Diego Credentials to be used with the Diego authentication method",
)

const (
	dropsondeDestination = "localhost:3457"
	dropsondeOrigin      = "ssh-proxy"
)

func main() {
	cf_debug_server.AddFlags(flag.CommandLine)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	logger, reconfigurableSink := cf_lager.New("ssh-proxy")

	initializeDropsonde(logger)

	proxyConfig, err := configure(logger)
	if err != nil {
		logger.Error("configure-failed", err)
		os.Exit(1)
	}

	sshProxy := proxy.New(logger, proxyConfig)
	server := server.NewServer(logger, *address, sshProxy)

	members := grouper.Members{
		{"ssh-proxy", server},
	}

	if dbgAddr := cf_debug_server.DebugAddress(flag.CommandLine); dbgAddr != "" {
		members = append(grouper.Members{{
			"debug-server", cf_debug_server.Runner(dbgAddr, reconfigurableSink),
		}}, members...)
	}

	group := grouper.NewOrdered(os.Interrupt, members)
	monitor := ifrit.Invoke(sigmon.New(group))

	logger.Info("started")

	err = <-monitor.Wait()
	if err != nil {
		logger.Error("exited-with-failure", err)
		os.Exit(1)
	}

	logger.Info("exited")
	os.Exit(0)
}

func initializeDropsonde(logger lager.Logger) {
	err := dropsonde.Initialize(dropsondeDestination, dropsondeOrigin)
	if err != nil {
		logger.Error("failed-to-initialize-dropsonde", err)
	}
}

func configure(logger lager.Logger) (*ssh.ServerConfig, error) {
	cf_http.Initialize(*communicationTimeout)

	if *bbsAddress == "" {
		err := errors.New("bbsAddress is required")
		logger.Fatal("bbs-address-required", err)
	}

	url, err := url.Parse(*bbsAddress)
	if err != nil {
		logger.Fatal("failed-to-parse-bbs-address", err)
	}

	_, err = url.Parse(*ccAPIURL)
	if *ccAPIURL != "" && err != nil {
		logger.Fatal("failed-to-parse-cc-api-url", err)
	}

	bbsClient := bbs.NewClient(*bbsAddress)
	permissionsBuilder := authenticators.NewPermissionsBuiler(bbsClient)

	authens := []authenticators.PasswordAuthenticator{}

	if *enableDiegoAuth {
		diegoAuthenticator := authenticators.NewDiegoProxyAuthenticator(logger, []byte(*diegoCredentials), permissionsBuilder)
		authens = append(authens, diegoAuthenticator)
	}

	if *ccAPIURL != "" && *enableCFAuth {
		client := NewHttpClient()
		cfAuthenticator := authenticators.NewCFAuthenticator(logger, client, *ccAPIURL, permissionsBuilder)
		authens = append(authens, cfAuthenticator)
	}

	authenticator := authenticators.NewCompositeAuthenticator(authens...)

	sshConfig := &ssh.ServerConfig{
		PasswordCallback: authenticator.Authenticate,
		AuthLogCallback: func(cmd ssh.ConnMetadata, method string, err error) {
			logger.Error("authentication-failed", err, lager.Data{"user": cmd.User()})
		},
	}

	if *hostKey == "" {
		err := errors.New("hostKey is required")
		logger.Fatal("host-key-required", err)
	}

	key, err := parsePrivateKey(logger, *hostKey)
	if err != nil {
		logger.Fatal("failed-to-parse-host-key", err)
	}

	sshConfig.AddHostKey(key)

	return sshConfig, err
}

func parsePrivateKey(logger lager.Logger, encodedKey string) (ssh.Signer, error) {
	key, err := ssh.ParsePrivateKey([]byte(encodedKey))
	if err != nil {
		logger.Error("failed-to-parse-private-key", err)
		return nil, err
	}
	return key, nil
}

func NewHttpClient() *http.Client {
	dialer := &net.Dialer{Timeout: 5 * time.Second}
	tlsConfig := &tls.Config{InsecureSkipVerify: *skipCertVerify}
	return &http.Client{
		Transport: &http.Transport{
			Dial:            dialer.Dial,
			TLSClientConfig: tlsConfig,
		},
		Timeout: *communicationTimeout,
	}
}
<commit_msg>support mutual-auth TLS to BBS<commit_after>package main

import (
	"crypto/tls"
	"errors"
	"flag"
	"net"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/cloudfoundry-incubator/bbs"
	"github.com/cloudfoundry-incubator/cf-debug-server"
	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/cf_http"
	"github.com/cloudfoundry-incubator/diego-ssh/authenticators"
	"github.com/cloudfoundry-incubator/diego-ssh/proxy"
	"github.com/cloudfoundry-incubator/diego-ssh/server"
	"github.com/cloudfoundry/dropsonde"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
	"golang.org/x/crypto/ssh"
)

var address = flag.String(
	"address",
	":2222",
	"listen address for ssh proxy",
)

var hostKey = flag.String(
	"hostKey",
	"",
	"PEM encoded RSA host key",
)

var bbsAddress = flag.String(
	"bbsAddress",
	"",
	"Address of the BBS API Server",
)

var ccAPIURL = flag.String(
	"ccAPIURL",
	"",
	"URL of Cloud Controller API",
)

var skipCertVerify = flag.Bool(
	"skipCertVerify",
	false,
	"skip SSL certificate verification",
)

var communicationTimeout = flag.Duration(
	"communicationTimeout",
	10*time.Second,
	"Timeout applied to all HTTP requests.",
)

var enableCFAuth = flag.Bool(
	"enableCFAuth",
	false,
	"Allow authentication with cf",
)

var enableDiegoAuth = flag.Bool(
	"enableDiegoAuth",
	false,
	"Allow authentication with diego",
)

var diegoCredentials = flag.String(
	"diegoCredentials",
	"",
	"Diego Credentials to be used with the Diego authentication method",
)

var bbsCACert = flag.String(
	"bbsCACert",
	"",
	"path to certificate authority cert used for mutually authenticated TLS BBS communication",
)

var bbsClientCert = flag.String(
	"bbsClientCert",
	"",
	"path to client cert used for mutually authenticated TLS BBS communication",
)

var bbsClientKey = flag.String(
	"bbsClientKey",
	"",
	"path to client key used for mutually authenticated TLS BBS communication",
)

const (
	dropsondeDestination = "localhost:3457"
	dropsondeOrigin      = "ssh-proxy"
)

func main() {
	cf_debug_server.AddFlags(flag.CommandLine)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	logger, reconfigurableSink := cf_lager.New("ssh-proxy")

	initializeDropsonde(logger)

	proxyConfig, err := configure(logger)
	if err != nil {
		logger.Error("configure-failed", err)
		os.Exit(1)
	}

	sshProxy := proxy.New(logger, proxyConfig)
	server := server.NewServer(logger, *address, sshProxy)

	members := grouper.Members{
		{"ssh-proxy", server},
	}

	if dbgAddr := cf_debug_server.DebugAddress(flag.CommandLine); dbgAddr != "" {
		members = append(grouper.Members{{
			"debug-server", cf_debug_server.Runner(dbgAddr, reconfigurableSink),
		}}, members...)
	}

	group := grouper.NewOrdered(os.Interrupt, members)
	monitor := ifrit.Invoke(sigmon.New(group))

	logger.Info("started")

	err = <-monitor.Wait()
	if err != nil {
		logger.Error("exited-with-failure", err)
		os.Exit(1)
	}

	logger.Info("exited")
	os.Exit(0)
}

func initializeDropsonde(logger lager.Logger) {
	err := dropsonde.Initialize(dropsondeDestination, dropsondeOrigin)
	if err != nil {
		logger.Error("failed-to-initialize-dropsonde", err)
	}
}

func configure(logger lager.Logger) (*ssh.ServerConfig, error) {
	cf_http.Initialize(*communicationTimeout)

	if *bbsAddress == "" {
		err := errors.New("bbsAddress is required")
		logger.Fatal("bbs-address-required", err)
	}

	url, err := url.Parse(*bbsAddress)
	if err != nil {
		logger.Fatal("failed-to-parse-bbs-address", err)
	}

	_, err = url.Parse(*ccAPIURL)
	if *ccAPIURL != "" && err != nil {
		logger.Fatal("failed-to-parse-cc-api-url", err)
	}

	permissionsBuilder := authenticators.NewPermissionsBuiler(initializeBBSClient(logger))

	authens := []authenticators.PasswordAuthenticator{}

	if *enableDiegoAuth {
		diegoAuthenticator := authenticators.NewDiegoProxyAuthenticator(logger, []byte(*diegoCredentials), permissionsBuilder)
		authens = append(authens, diegoAuthenticator)
	}

	if *ccAPIURL != "" && *enableCFAuth {
		client := NewHttpClient()
		cfAuthenticator := authenticators.NewCFAuthenticator(logger, client, *ccAPIURL, permissionsBuilder)
		authens = append(authens, cfAuthenticator)
	}

	authenticator := authenticators.NewCompositeAuthenticator(authens...)

	sshConfig := &ssh.ServerConfig{
		PasswordCallback: authenticator.Authenticate,
		AuthLogCallback: func(cmd ssh.ConnMetadata, method string, err error) {
			logger.Error("authentication-failed", err, lager.Data{"user": cmd.User()})
		},
	}

	if *hostKey == "" {
		err := errors.New("hostKey is required")
		logger.Fatal("host-key-required", err)
	}

	key, err := parsePrivateKey(logger, *hostKey)
	if err != nil {
		logger.Fatal("failed-to-parse-host-key", err)
	}

	sshConfig.AddHostKey(key)

	return sshConfig, err
}

func parsePrivateKey(logger lager.Logger, encodedKey string) (ssh.Signer, error) {
	key, err := ssh.ParsePrivateKey([]byte(encodedKey))
	if err != nil {
		logger.Error("failed-to-parse-private-key", err)
		return nil, err
	}
	return key, nil
}

func NewHttpClient() *http.Client {
	dialer := &net.Dialer{Timeout: 5 * time.Second}
	tlsConfig := &tls.Config{InsecureSkipVerify: *skipCertVerify}
	return &http.Client{
		Transport: &http.Transport{
			Dial:            dialer.Dial,
			TLSClientConfig: tlsConfig,
		},
		Timeout: *communicationTimeout,
	}
}

func initializeBBSClient(logger lager.Logger) bbs.Client {
	bbsURL, err := url.Parse(*bbsAddress)
	if err != nil {
		logger.Fatal("Invalid BBS URL", err)
	}

	if bbsURL.Scheme != "https" {
		return bbs.NewClient(*bbsAddress)
	}

	bbsClient, err := bbs.NewSecureClient(*bbsAddress, *bbsCACert, *bbsClientCert, *bbsClientKey)
	if err != nil {
		logger.Fatal("Failed to configure secure BBS client", err)
	}
	return bbsClient
}
<|endoftext|>


<commit_before>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	"github.com/spf13/cast"
)

type sanitizedEnviron []string

var sanitizeEnvmap = map[string]bool{
	"VAULT_TOKEN":           true,
	"VAULT_ADDR":            true,
	"VAULT_CACERT":          true,
	"VAULT_CAPATH":          true,
	"VAULT_CLIENT_CERT":     true,
	"VAULT_CLIENT_KEY":      true,
	"VAULT_CLIENT_TIMEOUT":  true,
	"VAULT_CLUSTER_ADDR":    true,
	"VAULT_MAX_RETRIES":     true,
	"VAULT_REDIRECT_ADDR":   true,
	"VAULT_SKIP_VERIFY":     true,
	"VAULT_TLS_SERVER_NAME": true,
	"VAULT_CLI_NO_COLOR":    true,
	"VAULT_RATE_LIMIT":      true,
	"VAULT_NAMESPACE":       true,
	"VAULT_MFA":             true,
	"VAULT_ROLE":            true,
	"VAULT_PATH":            true,
}

// Appends variable an entry (name=value) into the environ list.
// VAULT_* variables are not populated into this list.
func (environ *sanitizedEnviron) append(iname interface{}, ivalue interface{}) {
	name, value := iname.(string), ivalue.(string)
	if _, ok := sanitizeEnvmap[name]; !ok {
		*environ = append(*environ, fmt.Sprintf("%s=%s", name, value))
	}
}

func main() {

	role := os.Getenv("VAULT_ROLE")
	if role == "" {
		role = "default"
	}
	path := os.Getenv("VAULT_PATH")
	if path == "" {
		path = "kubernetes"
	}

	client, err := vault.NewClientWithConfig(vaultapi.DefaultConfig(), role, path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create vault client: %s\n", err.Error())
		os.Exit(1)
	}

	// initial and sanitized environs
	environ := syscall.Environ()
	sanitized := make(sanitizedEnviron, 0, len(environ))

	for _, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		var update bool
		if strings.HasPrefix(value, ">>") {
			value = strings.TrimPrefix(value, ">>")
			update = true
		} else {
			update = false
		}
		if strings.HasPrefix(value, "vault:") {
			path := strings.TrimPrefix(value, "vault:")
			split := strings.SplitN(path, "#", 2)
			path = split[0]

			var key string
			if len(split) > 1 {
				key = split[1]
			}

			var secret *vaultapi.Secret
			var err error

			if update {
				var empty map[string]interface{}
				secret, err = client.Vault().Logical().Write(path, empty)
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to write secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			} else {
				secret, err = client.Vault().Logical().Read(path)
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to read secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			}

			if secret == nil {
				fmt.Fprintf(os.Stderr, "path not found: %s\n", path)
				os.Exit(1)
			} else {
				var data map[string]interface{}
				v2Data, ok := secret.Data["data"]
				if ok {
					data = cast.ToStringMap(v2Data)
				} else {
					data = cast.ToStringMap(secret.Data)
				}
				if value, ok := data[key]; ok {
					sanitized.append(name, value)
				} else {
					fmt.Fprintf(os.Stderr, "key not found: %s\n", key)
					os.Exit(1)
				}
			}
		} else {
			sanitized.append(name, value)
		}
	}

	if len(os.Args) == 1 {
		fmt.Fprintf(os.Stderr, "no command is given, currently vault-env can't determine the entrypoint (command), please specify it explicitly")
		os.Exit(1)
	} else {
		binary, err := exec.LookPath(os.Args[1])
		if err != nil {
			fmt.Fprintf(os.Stderr, "binary not found: %s\n", os.Args[1])
			os.Exit(1)
		}
		err = syscall.Exec(binary, os.Args[1:], sanitized)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to exec process '%s': %s\n", binary, err.Error())
			os.Exit(1)
		}
	}
}
<commit_msg>Add support for versioning<commit_after>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	"github.com/spf13/cast"
)

type sanitizedEnviron []string

var sanitizeEnvmap = map[string]bool{
	"VAULT_TOKEN":           true,
	"VAULT_ADDR":            true,
	"VAULT_CACERT":          true,
	"VAULT_CAPATH":          true,
	"VAULT_CLIENT_CERT":     true,
	"VAULT_CLIENT_KEY":      true,
	"VAULT_CLIENT_TIMEOUT":  true,
	"VAULT_CLUSTER_ADDR":    true,
	"VAULT_MAX_RETRIES":     true,
	"VAULT_REDIRECT_ADDR":   true,
	"VAULT_SKIP_VERIFY":     true,
	"VAULT_TLS_SERVER_NAME": true,
	"VAULT_CLI_NO_COLOR":    true,
	"VAULT_RATE_LIMIT":      true,
	"VAULT_NAMESPACE":       true,
	"VAULT_MFA":             true,
	"VAULT_ROLE":            true,
	"VAULT_PATH":            true,
}

// Appends variable an entry (name=value) into the environ list.
// VAULT_* variables are not populated into this list.
func (environ *sanitizedEnviron) append(iname interface{}, ivalue interface{}) {
	name, value := iname.(string), ivalue.(string)
	if _, ok := sanitizeEnvmap[name]; !ok {
		*environ = append(*environ, fmt.Sprintf("%s=%s", name, value))
	}
}

func main() {

	role := os.Getenv("VAULT_ROLE")
	if role == "" {
		role = "default"
	}
	path := os.Getenv("VAULT_PATH")
	if path == "" {
		path = "kubernetes"
	}

	client, err := vault.NewClientWithConfig(vaultapi.DefaultConfig(), role, path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create vault client: %s\n", err.Error())
		os.Exit(1)
	}

	// initial and sanitized environs
	environ := syscall.Environ()
	sanitized := make(sanitizedEnviron, 0, len(environ))

	for _, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		var update bool
		if strings.HasPrefix(value, ">>") {
			value = strings.TrimPrefix(value, ">>")
			update = true
		} else {
			update = false
		}
		if strings.HasPrefix(value, "vault:") {
			path := strings.TrimPrefix(value, "vault:")
			split := strings.SplitN(path, "#", 3)
			path = split[0]

			var key string
			if len(split) > 1 {
				key = split[1]
			}

			version := "-1"
			if len(split) == 3 {
				version = split[2]
			}

			var secret *vaultapi.Secret
			var err error

			if update {
				var empty map[string]interface{}
				secret, err = client.Vault().Logical().Write(path, empty)
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to write secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			} else {
				secret, err = client.Vault().Logical().ReadWithData(path, map[string][]string{"version": {version}})
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to read secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			}

			if secret == nil {
				fmt.Fprintf(os.Stderr, "path not found: %s\n", path)
				os.Exit(1)
			} else {
				var data map[string]interface{}
				v2Data, ok := secret.Data["data"]

				if ok {
					data = cast.ToStringMap(v2Data)

					// Check if a given version of a path is destroyed
					metadata := secret.Data["metadata"].(map[string]interface{})
					if metadata["destroyed"].(bool) {
						fmt.Fprintf(os.Stderr, "Version %s of %s secret has been permanently destroyed\n", version, path)
					}

					// Check if a given version of a path still exists
					if metadata["deletion_time"].(string) != "" {
						fmt.Fprintf(os.Stderr, "Cannot find data for path: %s, given version (%s) has been deleted at %s\n", path, version, metadata["deletion_time"])
					}
				} else {
					data = cast.ToStringMap(secret.Data)
				}
				if value, ok := data[key]; ok {
					sanitized.append(name, value)
				} else {
					fmt.Fprintf(os.Stderr, "key not found: %s\n", key)
					os.Exit(1)
				}
			}
		} else {
			sanitized.append(name, value)
		}
	}

	if len(os.Args) == 1 {
		fmt.Fprintf(os.Stderr, "no command is given, currently vault-env can't determine the entrypoint (command), please specify it explicitly")
		os.Exit(1)
	} else {
		binary, err := exec.LookPath(os.Args[1])
		if err != nil {
			fmt.Fprintf(os.Stderr, "binary not found: %s\n", os.Args[1])
			os.Exit(1)
		}
		err = syscall.Exec(binary, os.Args[1:], sanitized)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to exec process '%s': %s\n", binary, err.Error())
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>// Package signin implements the signin command.
package signin

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/pkg/browser"
	"github.com/spf13/cobra"
	"github.com/taskcluster/taskcluster-cli/cmds/root"
	"github.com/taskcluster/taskcluster-cli/config"
	graceful "gopkg.in/tylerb/graceful.v1"
)

func init() {
	cmd := &cobra.Command{
		Use:   "signin",
		Short: "Obtain temporary credentials from login.taskcluster.net.",
		Long: `The command 'taskcluster signin' will open your web-browser to
login.taskcluster.net where you can sign-in and obtain temporary
credentials.

Once signed in, you can click the 'Grant Access' button which
will redirect you to localhost where this command will be listening
and save the temporary credentials to local configuration file.`,
		RunE: cmdSignin,
	}
	cmd.Flags().IntP("port", "p", 0, "Port to use; defaults to random ephemeral port.")

	root.Command.AddCommand(cmd)

	config.RegisterOptions("signin", map[string]config.OptionDefinition{
		"loginUrl": config.OptionDefinition{
			Description: "URL for the login service.",
			Default:     "https://login.taskcluster.net",
			Validate: func(value interface{}) error {
				if _, ok := value.(string); !ok {
					return errors.New("Must be a string")
				}
				return nil
			},
		},
	})
}

func cmdSignin(cmd *cobra.Command, _ []string) error {
	// Load configuration
	fmt.Fprintln(cmd.OutOrStdout(), "Starting")

	// Find port, choose 0 meaning random port, if none
	port, _ := cmd.Flags().GetInt("port")

	// Setup server that we can shutdown gracefully
	s := graceful.Server{
		Timeout: 5 * time.Second,
		Server:  &http.Server{},
	}

	// Handle callback
	var serr error
	s.Server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		qs := r.URL.Query()
		config.Configuration["config"]["clientId"] = qs.Get("clientId")
		config.Configuration["config"]["accessToken"] = qs.Get("accessToken")
		config.Configuration["config"]["certificate"] = qs.Get("certificate")

		serr = config.Save(config.Configuration)
		if serr == nil {
			fmt.Fprintln(cmd.OutOrStdout(), "Credentials saved in configuration file.")
		}

		title := "Successful"
		result := "You have successfully signed in."
		if serr != nil {
			title = "Failed"
			result = "Failed to save credentials!"
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`
			<!doctype html>

					<title>Sign-In ` + title + `</title>

` + result + `.

		`))
		s.Stop(50 * time.Millisecond)
	})

	// Start listening on localhost
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: port,
	})
	if err != nil {
		return fmt.Errorf("failed to listen on localhost, error: %s", err)
	}

	// Construct URL for login service and open it
	target := "http://" + strings.Replace(listener.Addr().String(), "127.0.0.1", "localhost", 1)
	description := url.QueryEscape(
		`Login and click the "Grant Access" button to transfer
		temporary credentials to the taskcluster CLI client`,
	)
	loginURL := config.Configuration["signin"]["loginUrl"].(string)
	loginURL += "/?target=" + url.QueryEscape(target) + "&description=" + description

	// Open browser
	fmt.Fprintln(cmd.OutOrStdout(), "Listening for a callback on: "+target)
	fmt.Fprintln(cmd.OutOrStdout(), "Opening URL: "+loginURL)
	browser.OpenURL(loginURL)

	// Start serving
	s.Serve(listener)

	if serr != nil {
		return fmt.Errorf("failed to save configuration, error: %s", serr)
	}

	return nil
}
<commit_msg>Bug 1395349 - refactor signin to use new client creator, don't store (#174)<commit_after>// Package signin implements the signin command.
package signin

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/pkg/browser"
	"github.com/spf13/cobra"
	"github.com/taskcluster/taskcluster-cli/cmds/root"
	"github.com/taskcluster/taskcluster-cli/config"
	graceful "gopkg.in/tylerb/graceful.v1"
)

func init() {
	cmd := &cobra.Command{
		Use:   "signin",
		Short: "Get Taskcluster credentials and export to the shell",
		Long: `The command 'taskcluster signin', run on a desktop system, will use
your browser to get Taskcluster credentials for use with other commands.

Use it like this:

$ eval ` + "`taskcluster signin`" + `

You might make this easy to use with an alias in ~/.bashrc:

alias tc-signin="eval ` + "`taskcluster signin`" + `"

This will set environment variables in your shell session containing the credentials.
Note that the JS and Python client recognize the same environment variables, so any
tools using those libraries can also benefit from this signin method.`,

		RunE: cmdSignin,
	}
	cmd.Flags().Bool("csh", false, "Output csh-style environment variables (default is Bourne shell)")
	cmd.Flags().StringP("name", "n", "cli", "Name of the credential to create/reset.")
	cmd.Flags().String("expires", "1d", "Lifetime for this client (keep it short to avoid risk from accidental disclosure).")
	cmd.Flags().StringArrayP("scope", "s", []string{"*"}, "(can be repeated) Scopes for this client (limit this to avoid risk from accidental disclosure).")
	cmd.Flags().IntP("port", "p", 0, "Port to use; defaults to random ephemeral port.")

	root.Command.AddCommand(cmd)

	config.RegisterOptions("signin", map[string]config.OptionDefinition{
		"toolsUrl": config.OptionDefinition{
			Description: "URL for the tools service.",
			Default:     "https://tools.taskcluster.net",
			Validate: func(value interface{}) error {
				if _, ok := value.(string); !ok {
					return errors.New("Must be a string")
				}
				return nil
			},
		},
	})
}

func cmdSignin(cmd *cobra.Command, _ []string) error {
	// Load configuration
	fmt.Fprintln(cmd.OutOrStderr(), "Starting")

	// Find port, choose 0 meaning random port, if none
	port, _ := cmd.Flags().GetInt("port")

	// Setup server that we can shutdown gracefully
	s := graceful.Server{
		Timeout: 5 * time.Second,
		Server:  &http.Server{},
	}

	// Handle callback
	var serr error
	s.Server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		qs := r.URL.Query()
		csh, _ := cmd.Flags().GetBool("csh")
		if csh {
			fmt.Fprintln(cmd.OutOrStdout(), "setenv TASKCLUSTER_CLIENT_ID '" + qs.Get("clientId") + "'")
			fmt.Fprintln(cmd.OutOrStdout(), "setenv TASKCLUSTER_ACCESS_TOKEN '" + qs.Get("accessToken") + "'")
		} else {
			fmt.Fprintln(cmd.OutOrStdout(), "export TASKCLUSTER_CLIENT_ID='" + qs.Get("clientId") + "'")
			fmt.Fprintln(cmd.OutOrStdout(), "export TASKCLUSTER_ACCESS_TOKEN='" + qs.Get("accessToken") + "'")
		}
		fmt.Fprintln(cmd.OutOrStderr(), "Credentials output as environment variables")

		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`
			<!doctype html>

					<title>Sign-In Successful</title>

You have successfully signed in

You may now close this window.

		`))
		s.Stop(50 * time.Millisecond)
	})

	// Start listening on localhost
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: port,
	})
	if err != nil {
		return fmt.Errorf("failed to listen on localhost, error: %s", err)
	}

	// Construct URL for login service and open it
	callbackURL := "http://" + strings.Replace(listener.Addr().String(), "127.0.0.1", "localhost", 1)
	description := url.QueryEscape("Temporary client for use on the command line")
	loginURL := config.Configuration["signin"]["toolsUrl"].(string) + "/auth/clients/new";
	name, _ := cmd.Flags().GetString("name")
	loginURL += "?name=" + url.QueryEscape(name)
	loginURL += "&description=" + description
	scopes, _ := cmd.Flags().GetStringArray("scope")
	for i := range scopes {
		loginURL += "&scope=" + scopes[i]
	}
	expires, _ := cmd.Flags().GetString("expires")
	loginURL += "&expires=" + url.QueryEscape(expires)
	loginURL += "&callback_url=" + url.QueryEscape(callbackURL)

	// Open browser
	fmt.Fprintln(cmd.OutOrStderr(), "Listening for a callback on: "+callbackURL)
	fmt.Fprintln(cmd.OutOrStderr(), "Opening URL: "+loginURL)
	browser.OpenURL(loginURL)

	// Start serving
	s.Serve(listener)

	if serr != nil {
		return fmt.Errorf("failed to save configuration, error: %s", serr)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codeclimate/cc-engine-go/engine"
	"github.com/golang/lint"
	"io/ioutil"
	"os"
	"sort"
	"strconv"
	"strings"
)

const defaultMinConfidence = 0.8

func main() {
	rootPath := "/code/"
	analysisFiles, err := engine.GoFileWalk(rootPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error initializing: %s", err)
		os.Exit(1)
	}

	config, err := engine.LoadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error loading config: %s", err)
		os.Exit(1)
	}

	excludedFiles := getExcludedFiles(config)
	minConfidence := getMinConfidence(config)

	for _, path := range analysisFiles {
		relativePath := strings.SplitAfter(path, rootPath)[1]
		if isFileExcluded(relativePath, excludedFiles) {
			continue
		}

		lintFile(path, relativePath, minConfidence)
	}
}

func getExcludedFiles(config engine.Config) []string {
	excludedFiles := []string{}
	if config["exclude_paths"] != nil {
		for _, file := range config["exclude_paths"].([]interface{}) {
			excludedFiles = append(excludedFiles, file.(string))
		}
		sort.Strings(excludedFiles)
	}
	return excludedFiles
}

func isFileExcluded(filePath string, excludedFiles []string) bool {
	i := sort.SearchStrings(excludedFiles, filePath)
	return i < len(excludedFiles) && excludedFiles[i] == filePath
}

func lintFile(fullPath string, relativePath string, minConfidence float64) {
	linter := new(lint.Linter)

	code, err := ioutil.ReadFile(fullPath)
	if err != nil {
		warning := &engine.Warning{
			Description: "Could not read file",
			Location: &engine.Location{
				Path: fullPath,
				Lines: &engine.LinesOnlyPosition{
					Begin: 1,
					End:   1,
				},
			},
		}
		engine.PrintWarning(warning)
	}

	problems, err := linter.Lint("", code)
	if err != nil {
		warningDesc := fmt.Sprintf("Could not lint file (%s)", err)
		warning := &engine.Warning{
			Description: warningDesc,
			Location: &engine.Location{
				Path: fullPath,
			},
		}
		engine.PrintWarning(warning)
	}

	for _, problem := range problems {
		if problem.Confidence < minConfidence {
			continue
		}

		issue := &engine.Issue{
			Type:              "issue",
			Check:             codeClimateCheckName(&problem),
			Description:       (&problem).Text,
			RemediationPoints: 50000,
			Categories:        []string{"Style"},
			Location:          codeClimateLocation(&problem, relativePath),
		}
		engine.PrintIssue(issue)
	}
}

func codeClimateCheckName(l *lint.Problem) string {
	return "GoLint/" + strings.Title(l.Category) + "/" + codeClimateIssueName(l)
}

func codeClimateIssueName(l *lint.Problem) string {
	splitURL := strings.Split(l.Link, "#")
	kebabLink := splitURL[len(splitURL)-1]
	splitLink := strings.Split(kebabLink, "-")
	for i, link := range splitLink {
		splitLink[i] = strings.Title(link)
	}
	camelLink := strings.Join(splitLink, "")
	return camelLink
}

func codeClimateLocation(l *lint.Problem, relativePath string) *engine.Location {
	position := l.Position

	return &engine.Location{
		Path: relativePath,
		Lines: &engine.LinesOnlyPosition{
			Begin: position.Line,
			End:   position.Line,
		},
	}
}

func getMinConfidence(config engine.Config) float64 {
	if subConfig, ok := config["config"].(map[string]interface{}); ok {
		if minConfidence, ok := subConfig["min_confidence"].(string); ok {
			val, err := strconv.ParseFloat(minConfidence, 64)
			if err == nil {
				return val
			}
		}
	}
	return defaultMinConfidence
}
<commit_msg>use config include paths<commit_after>package main

import (
	"fmt"
	"github.com/codeclimate/cc-engine-go/engine"
	"github.com/golang/lint"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

const defaultMinConfidence = 0.8

func main() {
	rootPath := "/code/"

	config, err := engine.LoadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error loading config: %s", err)
		os.Exit(1)
	}

	analysisFiles, err := engine.GoFileWalk(rootPath, engine.IncludePaths(rootPath, config))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error initializing: %s", err)
		os.Exit(1)
	}

	minConfidence := getMinConfidence(config)

	for _, path := range analysisFiles {
		relativePath := strings.SplitAfter(path, rootPath)[1]

		lintFile(path, relativePath, minConfidence)
	}
}

func lintFile(fullPath string, relativePath string, minConfidence float64) {
	linter := new(lint.Linter)

	code, err := ioutil.ReadFile(fullPath)
	if err != nil {
		warning := &engine.Warning{
			Description: "Could not read file",
			Location: &engine.Location{
				Path: fullPath,
				Lines: &engine.LinesOnlyPosition{
					Begin: 1,
					End:   1,
				},
			},
		}
		engine.PrintWarning(warning)
	}

	problems, err := linter.Lint("", code)
	if err != nil {
		warningDesc := fmt.Sprintf("Could not lint file (%s)", err)
		warning := &engine.Warning{
			Description: warningDesc,
			Location: &engine.Location{
				Path: fullPath,
			},
		}
		engine.PrintWarning(warning)
	}

	for _, problem := range problems {
		if problem.Confidence < minConfidence {
			continue
		}

		issue := &engine.Issue{
			Type:              "issue",
			Check:             codeClimateCheckName(&problem),
			Description:       (&problem).Text,
			RemediationPoints: 50000,
			Categories:        []string{"Style"},
			Location:          codeClimateLocation(&problem, relativePath),
		}
		engine.PrintIssue(issue)
	}
}

func codeClimateCheckName(l *lint.Problem) string {
	return "GoLint/" + strings.Title(l.Category) + "/" + codeClimateIssueName(l)
}

func codeClimateIssueName(l *lint.Problem) string {
	splitURL := strings.Split(l.Link, "#")
	kebabLink := splitURL[len(splitURL)-1]
	splitLink := strings.Split(kebabLink, "-")
	for i, link := range splitLink {
		splitLink[i] = strings.Title(link)
	}
	camelLink := strings.Join(splitLink, "")
	return camelLink
}

func codeClimateLocation(l *lint.Problem, relativePath string) *engine.Location {
	position := l.Position

	return &engine.Location{
		Path: relativePath,
		Lines: &engine.LinesOnlyPosition{
			Begin: position.Line,
			End:   position.Line,
		},
	}
}

func getMinConfidence(config engine.Config) float64 {
	if subConfig, ok := config["config"].(map[string]interface{}); ok {
		if minConfidence, ok := subConfig["min_confidence"].(string); ok {
			val, err := strconv.ParseFloat(minConfidence, 64)
			if err == nil {
				return val
			}
		}
	}
	return defaultMinConfidence
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Jetstack Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package certificate

import (
	"flag"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	cmutil "github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/test/e2e/framework"
	"github.com/jetstack/cert-manager/test/util"
)

const invalidACMEURL = "http://not-a-real-acme-url.com"
const testingACMEEmail = "test@example.com"
const testingACMEPrivateKey = "test-acme-private-key"
const foreverTestTimeout = time.Second * 60

var acmeIngressClass string

func init() {
	flag.StringVar(&acmeIngressClass, "acme-nginx-ingress-class", "nginx", ""+
		"The ingress class for the nginx ingress controller")
}

var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
	f := framework.NewDefaultFramework("create-acme-certificate-http01")

	issuerName := "test-acme-issuer"
	certificateName := "test-acme-certificate"
	certificateSecretName := "test-acme-certificate"

	BeforeEach(func() {
		By("Verifying there is no existing ACME private key")
		_, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(testingACMEPrivateKey, metav1.GetOptions{})
		Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), testingACMEPrivateKey)))
		By("Verifying there is no existing TLS certificate secret")
		_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
		Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), certificateSecretName)))
		By("Creating an Issuer")
		_, err = f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerACMEIssuer(issuerName, framework.TestContext.ACMEURL, testingACMEEmail, testingACMEPrivateKey))
		Expect(err).NotTo(HaveOccurred())
		By("Waiting for Issuer to become Ready")
		err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
			issuerName,
			v1alpha1.IssuerCondition{
				Type:   v1alpha1.IssuerConditionReady,
				Status: v1alpha1.ConditionTrue,
			})
		Expect(err).NotTo(HaveOccurred())
		By("Verifying the ACME account URI is set")
		err = util.WaitForIssuerStatusFunc(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
			issuerName,
			func(i *v1alpha1.Issuer) (bool, error) {
				if i.GetStatus().ACMEStatus().URI == "" {
					return false, nil
				}
				return true, nil
			})
		Expect(err).NotTo(HaveOccurred())
		By("Verifying ACME account private key exists")
		secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(testingACMEPrivateKey, metav1.GetOptions{})
		Expect(err).NotTo(HaveOccurred())
		if len(secret.Data) != 1 {
			Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data))
		}
	})

	AfterEach(func() {
		By("Cleaning up")
		f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Delete(issuerName, nil)
		f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(testingACMEPrivateKey, nil)
	})

	It("should obtain a signed certificate with a single CN from the ACME server", func() {
		By("Creating a Certificate")
		cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain))
		Expect(err).NotTo(HaveOccurred())
		f.WaitCertificateIssuedValid(cert)
	})

	It("should obtain a signed certificate for a long (more than 100 chars) domain using http01 validation", func() {
		By("Creating a Certificate")
		cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(100), util.ACMECertificateDomain)))
		Expect(err).NotTo(HaveOccurred())
		f.WaitCertificateIssuedValid(cert)
	})

	It("should obtain a signed certificate with a CN and single subdomain as dns name from the ACME server", func() {
		By("Creating a Certificate")
		cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), util.ACMECertificateDomain)))
		Expect(err).NotTo(HaveOccurred())
		f.WaitCertificateIssuedValid(cert)
	})

	It("should fail to obtain a certificate for an invalid ACME dns name", func() {
		By("Creating a Certificate")
		_, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, "google.com"))
		Expect(err).NotTo(HaveOccurred())
		By("Waiting for the Certificate to not have a ready condition")
		err = util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name),
			certificateName,
			v1alpha1.CertificateCondition{
				Type:   v1alpha1.CertificateConditionReady,
				Status: v1alpha1.ConditionTrue,
			}, foreverTestTimeout)
		Expect(err).To(HaveOccurred())
		By("Verifying TLS certificate secret does not exist")
		_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
		Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), certificateSecretName)))
	})
})
<commit_msg>Adjust max segment length to 63 chars<commit_after>/*
Copyright 2017 Jetstack Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package certificate

import (
	"flag"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	cmutil "github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/test/e2e/framework"
	"github.com/jetstack/cert-manager/test/util"
)

const invalidACMEURL = "http://not-a-real-acme-url.com"
const testingACMEEmail = "test@example.com"
const testingACMEPrivateKey = "test-acme-private-key"
const foreverTestTimeout = time.Second * 60

var acmeIngressClass string

func init() {
	flag.StringVar(&acmeIngressClass, "acme-nginx-ingress-class", "nginx", ""+
		"The ingress class for the nginx ingress controller")
}

var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
	f := framework.NewDefaultFramework("create-acme-certificate-http01")

	issuerName := "test-acme-issuer"
	certificateName := "test-acme-certificate"
	certificateSecretName := "test-acme-certificate"

	BeforeEach(func() {
		By("Verifying there is no existing ACME private key")
		_, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(testingACMEPrivateKey, metav1.GetOptions{})
		Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), testingACMEPrivateKey)))
		By("Verifying there is no existing TLS certificate secret")
		_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
		Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), certificateSecretName)))
		By("Creating an Issuer")
		_, err = f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerACMEIssuer(issuerName, framework.TestContext.ACMEURL, testingACMEEmail, testingACMEPrivateKey))
		Expect(err).NotTo(HaveOccurred())
		By("Waiting for Issuer to become Ready")
		err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
			issuerName,
			v1alpha1.IssuerCondition{
				Type:   v1alpha1.IssuerConditionReady,
				Status: v1alpha1.ConditionTrue,
			})
		Expect(err).NotTo(HaveOccurred())
		By("Verifying the ACME account URI is set")
		err = util.WaitForIssuerStatusFunc(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
			issuerName,
			func(i *v1alpha1.Issuer) (bool, error) {
				if i.GetStatus().ACMEStatus().URI == "" {
					return false, nil
				}
				return true, nil
			})
		Expect(err).NotTo(HaveOccurred())
		By("Verifying ACME account private key exists")
		secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(testingACMEPrivateKey, metav1.GetOptions{})
		Expect(err).NotTo(HaveOccurred())
		if len(secret.Data) != 1 {
			Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data))
		}
	})

	AfterEach(func() {
		By("Cleaning up")
		f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Delete(issuerName, nil)
		f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(testingACMEPrivateKey, nil)
	})

	It("should obtain a signed certificate with a single CN from the ACME server", func() {
		By("Creating a Certificate")
		cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain))
		Expect(err).NotTo(HaveOccurred())
		f.WaitCertificateIssuedValid(cert)
	})

	It("should obtain a signed certificate for a long domain using http01 validation", func() {
		// the maximum length of a single segment of the domain being requested
		const maxLengthOfDomainSegment = 63
		By("Creating a Certificate")
		cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), util.ACMECertificateDomain)))
		Expect(err).NotTo(HaveOccurred())
		f.WaitCertificateIssuedValid(cert)
	})

	It("should obtain a signed certificate with a CN and single subdomain as dns name from the ACME server", func() {
		By("Creating a Certificate")
		cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), util.ACMECertificateDomain)))
		Expect(err).NotTo(HaveOccurred())
		f.WaitCertificateIssuedValid(cert)
	})

	It("should fail to obtain a certificate for an invalid ACME dns name", func() {
		By("Creating a Certificate")
		_, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, "google.com"))
		Expect(err).NotTo(HaveOccurred())
		By("Waiting for the Certificate to not have a ready condition")
		err = util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name),
			certificateName,
			v1alpha1.CertificateCondition{
				Type:   v1alpha1.CertificateConditionReady,
				Status: v1alpha1.ConditionTrue,
			}, foreverTestTimeout)
		Expect(err).To(HaveOccurred())
		By("Verifying TLS certificate secret does not exist")
		_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
		Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), certificateSecretName)))
	})
})
<|endoftext|>


<commit_before>package secondly

import (
	"testing"
)

func TestExtractFields(t *testing.T) {
	c := testConf{
		AppName: "Secondly",
		Version: 1.1,
		Database: testDatabaseConf{
			Adapter: "mysql",
			Host:    "localhost",
			Port:    3306,
		},
	}

	fields := indexFields(extractFields(c, ""))
	testField := func(fname, kind string, val interface{}) {
		if f, ok := fields[fname]; ok {
			if f.Kind != kind {
				t.Errorf("%s expected to be of kind %q, got %q", fname, kind, f.Kind)
			}
			if f.Value != val {
				t.Errorf("%s expected to have value %q, got %q", fname, val, f.Value)
			}
		} else {
			t.Errorf("Missing %s field", fname)
		}
	}

	testField("AppName", "string", c.AppName)
	testField("Version", "float32", c.Version)
	testField("Database.Adapter", "string", c.Database.Adapter)
	testField("Database.Host", "string", c.Database.Host)
	testField("Database.Port", "int", c.Database.Port)
}

func TestDiff(t *testing.T) {
	c1 := testConf{
		AppName: "Secondly",
		Version: 1.3,
		Database: testDatabaseConf{
			Adapter: "mysql",
			Host:    "localhost",
			Port:    3306,
		},
	}
	c2 := testConf{
		AppName: "Secondly",
		Version: 2,
		Database: testDatabaseConf{
			Adapter:  "postgresql",
			Host:     "localhost",
			Port:     5432,
			Username: "root",
		},
	}

	d := diff(c1, c2)
	testField := func(fname string, oldVal, newVal interface{}) {
		if f, ok := d[fname]; ok {
			if f[0] != oldVal {
				t.Errorf("%s field old value was %q, not %q", oldVal, f[0])
			}
			if f[1] != newVal {
				t.Errorf("%s field new value was %q, not %q", newVal, f[1])
			}
		} else {
			t.Errorf("Expected %s field to have different values", fname)
		}
	}

	unchangedFields := []string{"AppName", "Database.Host", "Database.Password"}
	for _, f := range unchangedFields {
		if _, ok := d[f]; ok {
			t.Errorf("Expected %q field to be unchanged", f)
		}
	}

	testField("Version", c1.Version, c2.Version)
	testField("Database.Adapter", c1.Database.Adapter, c2.Database.Adapter)
	testField("Database.Port", c1.Database.Port, c2.Database.Port)
	testField("Database.Username", c1.Database.Username, c2.Database.Username)
}
<commit_msg>Fix tests<commit_after>package secondly

import (
	"testing"
)

func TestExtractFields(t *testing.T) {
	c := testConf{
		AppName: "Secondly",
		Version: 1.1,
		Database: testDatabaseConf{
			Adapter: "mysql",
			Host:    "localhost",
			Port:    3306,
		},
	}

	fields := indexFields(extractFields(c, ""))
	testField := func(fname, kind string, val interface{}) {
		if f, ok := fields[fname]; ok {
			if f.Kind != kind {
				t.Errorf("%s expected to be of kind %q, got %q", fname, kind, f.Kind)
			}
			if f.Value != val {
				t.Errorf("%s expected to have value %q, got %q", fname, val, f.Value)
			}
		} else {
			t.Errorf("Missing %s field", fname)
		}
	}

	testField("app_name", "string", c.AppName)
	testField("version", "float32", c.Version)
	testField("database.adapter", "string", c.Database.Adapter)
	testField("database.host", "string", c.Database.Host)
	testField("database.port", "int", c.Database.Port)
}

func TestDiff(t *testing.T) {
	c1 := testConf{
		AppName: "Secondly",
		Version: 1.3,
		Database: testDatabaseConf{
			Adapter: "mysql",
			Host:    "localhost",
			Port:    3306,
		},
	}
	c2 := testConf{
		AppName: "Secondly",
		Version: 2,
		Database: testDatabaseConf{
			Adapter:  "postgresql",
			Host:     "localhost",
			Port:     5432,
			Username: "root",
		},
	}

	d := diff(c1, c2)
	testField := func(fname string, oldVal, newVal interface{}) {
		if f, ok := d[fname]; ok {
			if f[0] != oldVal {
				t.Errorf("%s field old value was %q, not %q", oldVal, f[0])
			}
			if f[1] != newVal {
				t.Errorf("%s field new value was %q, not %q", newVal, f[1])
			}
		} else {
			t.Errorf("Expected %s field to have different values", fname)
		}
	}

	unchangedFields := []string{"app_name", "database.host", "database.password"}
	for _, f := range unchangedFields {
		if _, ok := d[f]; ok {
			t.Errorf("Expected %q field to be unchanged", f)
		}
	}

	testField("version", c1.Version, c2.Version)
	testField("database.adapter", c1.Database.Adapter, c2.Database.Adapter)
	testField("database.port", c1.Database.Port, c2.Database.Port)
	testField("database.username", c1.Database.Username, c2.Database.Username)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"math/rand"
	"net"
	"net/http"
)

var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"

// generates a random string of fixed size
func srand(size int) string {
	buf := make([]byte, size)
	for i := 0; i < size; i++ {
		buf[i] = alpha[rand.Intn(len(alpha))]
	}
	return string(buf)
}

// GetNewId returns random 5 character string.
// Random characters are [a-zA-Z0-9] excluding those with visible similarity = l,1,O,0.
// This gives 550 731 776 unique id's.
func GetNewId() string {
	return srand(5)
}

func getRemoteAddrs(req *http.Request) string {
	addr := "-"
	addr, _, err := net.SplitHostPort(req.RemoteAddr)
	if err != nil {
		addr = req.RemoteAddr
	}
	return addr
}

func getRemoteUser(req *http.Request) string {
	user := "-"
	if req.URL.User != nil && req.URL.User.Username() != "" {
		user = req.URL.User.Username()
	} else if len(req.Header["Remote-User"]) > 0 {
		user = req.Header["Remote-User"][0]
	}
	return user
}

func info(template string, values ...interface{}) {
	log.Printf("[inkblot] "+template+"\n", values...)
}
<commit_msg>moved to github.com/niilo/golib/http/handlers/common.go<commit_after>package main

import (
	"log"
	"math/rand"
)

var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"

// generates a random string of fixed size
func srand(size int) string {
	buf := make([]byte, size)
	for i := 0; i < size; i++ {
		buf[i] = alpha[rand.Intn(len(alpha))]
	}
	return string(buf)
}

// GetNewId returns random 5 character string.
// Random characters are [a-zA-Z0-9] excluding those with visible similarity = l,1,O,0.
// This gives 550 731 776 unique id's.
func GetNewId() string {
	return srand(5)
}

func info(template string, values ...interface{}) {
	log.Printf("[inkblot] "+template+"\n", values...)
}
<|endoftext|>


<commit_before>// Dataflow kit - extract
//
//Copyright for portions of Dataflow kit are held by Andrew Dunham, 2016 as part of goscrape.
//All other copyright for Dataflow kit are held by Slotix s.r.o., 2017-2018
//
// All rights reserved. Use of this source code is governed
// by the BSD 3-Clause License license.

// Package extract of the Dataflow kit describes available extractors to retrieve a structured data from html web pages. The following extractor types are available: Text, HTML, OuterHTML, Attr, Link, Image, Regex.
//
package extract

// EOF
<commit_msg>added some info to extract doc.go<commit_after>// Dataflow kit - extract
//
//Copyright for portions of Dataflow kit are held by Andrew Dunham, 2016 as part of goscrape.
//All other copyright for Dataflow kit are held by Slotix s.r.o., 2017-2018
//
// All rights reserved. Use of this source code is governed
// by the BSD 3-Clause License license.

// Package extract of the Dataflow kit describes available extractors to retrieve a structured data from html web pages. The following extractor types are available: Text, HTML, OuterHTML, Attr, Link, Image, Regex.
//
//Filters are used to manipulate text data when extracting.
//Currently the following filters are available:
	//upperCase returns a copy of the Attr with all Unicode letters mapped to their upper case.
	//lowerCase returns a copy of the Attr with all Unicode letters mapped to their lower case.
	//trim returns a copy of the Attr, with all leading and trailing white space removed
//Filters are available for Text, Link and Image extractor types.
//Image alt attribute, Link Text and Text are influenced by specified filters.
package extract

// EOF
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libcompose/project"
	"github.com/rancher/go-rancher/client"
	"github.com/rancher/rancher-compose/lookup"
	"github.com/rancher/rancher-compose/rancher"
)

func constructProjectUpgrade(logger *logrus.Entry, env *client.Environment, upgradeOpts client.EnvironmentUpgrade, url, accessKey, secretKey string) (*project.Project, map[string]interface{}, error) {
	variables := map[string]interface{}{}
	for k, v := range env.Environment {
		variables[k] = v
	}

	for k, v := range upgradeOpts.Environment {
		variables[k] = v
	}

	context := rancher.Context{
		Context: project.Context{
			ProjectName: env.Name,
			ComposeBytes: [][]byte{
				[]byte(upgradeOpts.DockerCompose),
			},
			ResourceLookup: &lookup.FileConfigLookup{},
			EnvironmentLookup: &lookup.MapEnvLookup{
				Env: variables,
			},
		},
		Url:                 fmt.Sprintf("%s/projects/%s/schemas", url, env.AccountId),
		AccessKey:           accessKey,
		SecretKey:           secretKey,
		RancherComposeBytes: []byte(upgradeOpts.RancherCompose),
		Upgrade:             true,
	}

	p, err := rancher.NewProject(&context)
	if err != nil {
		return nil, nil, err
	}

	p.AddListener(NewListenLogger(logger, p))
	return p, variables, p.Parse()
}

func constructProject(logger *logrus.Entry, env *client.Environment, url, accessKey, secretKey string) (*rancher.Context, *project.Project, error) {
	context := rancher.Context{
		Context: project.Context{
			ProjectName: env.Name,
			ComposeBytes: [][]byte{
				[]byte(env.DockerCompose),
			},
			ResourceLookup: &lookup.FileConfigLookup{},
			EnvironmentLookup: &lookup.MapEnvLookup{
				Env: env.Environment,
			},
		},
		Url:                 fmt.Sprintf("%s/projects/%s/schemas", url, env.AccountId),
		AccessKey:           accessKey,
		SecretKey:           secretKey,
		RancherComposeBytes: []byte(env.RancherCompose),
	}

	p, err := rancher.NewProject(&context)
	if err != nil {
		return nil, nil, err
	}

	p.AddListener(NewListenLogger(logger, p))
	return &context, p, nil
}
<commit_msg>Only parse project once during executor upgrade<commit_after>package handlers

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libcompose/project"
	"github.com/rancher/go-rancher/client"
	"github.com/rancher/rancher-compose/lookup"
	"github.com/rancher/rancher-compose/rancher"
)

func constructProjectUpgrade(logger *logrus.Entry, env *client.Environment, upgradeOpts client.EnvironmentUpgrade, url, accessKey, secretKey string) (*project.Project, map[string]interface{}, error) {
	variables := map[string]interface{}{}
	for k, v := range env.Environment {
		variables[k] = v
	}

	for k, v := range upgradeOpts.Environment {
		variables[k] = v
	}

	context := rancher.Context{
		Context: project.Context{
			ProjectName: env.Name,
			ComposeBytes: [][]byte{
				[]byte(upgradeOpts.DockerCompose),
			},
			ResourceLookup: &lookup.FileConfigLookup{},
			EnvironmentLookup: &lookup.MapEnvLookup{
				Env: variables,
			},
		},
		Url:                 fmt.Sprintf("%s/projects/%s/schemas", url, env.AccountId),
		AccessKey:           accessKey,
		SecretKey:           secretKey,
		RancherComposeBytes: []byte(upgradeOpts.RancherCompose),
		Upgrade:             true,
	}

	p, err := rancher.NewProject(&context)
	if err != nil {
		return nil, nil, err
	}

	p.AddListener(NewListenLogger(logger, p))
	return p, variables, nil
}

func constructProject(logger *logrus.Entry, env *client.Environment, url, accessKey, secretKey string) (*rancher.Context, *project.Project, error) {
	context := rancher.Context{
		Context: project.Context{
			ProjectName: env.Name,
			ComposeBytes: [][]byte{
				[]byte(env.DockerCompose),
			},
			ResourceLookup: &lookup.FileConfigLookup{},
			EnvironmentLookup: &lookup.MapEnvLookup{
				Env: env.Environment,
			},
		},
		Url:                 fmt.Sprintf("%s/projects/%s/schemas", url, env.AccountId),
		AccessKey:           accessKey,
		SecretKey:           secretKey,
		RancherComposeBytes: []byte(env.RancherCompose),
	}

	p, err := rancher.NewProject(&context)
	if err != nil {
		return nil, nil, err
	}

	p.AddListener(NewListenLogger(logger, p))
	return &context, p, nil
}
<|endoftext|>


<commit_before>package exercise2

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"
	"time"

	"github.com/jzipfler/htw-ava/protobuf"
	"github.com/jzipfler/htw-ava/server"
	"github.com/jzipfler/htw-ava/utils"
)

const (
	// The number of nodes from which the rumor must be heared before the node belives in it.
	BELIVE_IN_RUMOR_THRESHOLD = 2
)

var (
	localNode                 server.NetworkServer
	allNodes                  map[int]server.NetworkServer
	neighbors                 map[int]server.NetworkServer
	messageToAllNeighborsSent bool
)

// With this function an node that interacts independently gets started.
// He can be controlled with a controller.
func StartIndependentNode(localNodeId int, allAvailableNodes, neighborNodes map[int]server.NetworkServer, businessNode bool) {
	if allAvailableNodes == nil {
		utils.PrintMessage(fmt.Sprintf("To start the controller, there must be a node map which is currently nil.\n%s\n", utils.ERROR_FOOTER))
		os.Exit(1)
	}
	if _, ok := allAvailableNodes[localNodeId]; !ok {
		utils.PrintMessage(fmt.Sprintf("The given id exists not in the node map.\n%s\n", utils.ERROR_FOOTER))
		os.Exit(1)
	}
	if neighborNodes == nil {
		utils.PrintMessage(fmt.Sprintf("No neighbors given. Use the ChooseThreeNeighbors function to get some.\n%s\n", utils.ERROR_FOOTER))
		neighborNodes = ChooseThreeNeighbors(localNodeId, allAvailableNodes)
	}
	utils.PrintMessage("Start current instance as independent node.")
	allNodes = allAvailableNodes
	neighbors = neighborNodes
	localNode = allAvailableNodes[localNodeId]
	messageToAllNeighborsSent = false
	utils.PrintMessage("This node has the folowing settings: ")
	utils.PrintMessage(localNode)

	protobufChannel := make(chan *protobuf.Nachricht)
	//A goroutine that receives the protobuf message and reacts to it.
	go handleReceivedProtobufMessageWithChannel(localNode, protobufChannel)
	if err := server.StartServer(localNode, nil); err != nil {
		log.Fatal("Error happened: " + err.Error())
	}
	defer server.StopServer()

	for {
		//ReceiveMessage blocks until a message comes in
		if conn, err := server.ReceiveMessage(); err == nil {
			//If err is nil then that means that data is available for us so we take up this data and pass it to a new goroutine
			go ReceiveAndParseIncomingProtobufMessageToChannel(conn, protobufChannel)
			//ReceiveAndParseIncomingProtobufMessageToChannel(conn, protobufChannel)
			//protodata := ReceiveAndParseInfomingProtoufMessage(conn)
			//utils.PrintMessage(fmt.Sprintf("Message on %s received:\n\n%s\n\n", localNode.String(), protodata.String()))
			//handleReceivedProtobufMessage(protodata)
		}
	}
}

// The chooseThreeNeighbors function uses the allAvailableNodes map to return
// another map that contains 3 nodes at the most.
// It calls os.Exit(1) if only one node is available in the allAvailableNodes map.
func ChooseThreeNeighbors(localNodeId int, allAvailableNodes map[int]server.NetworkServer) (neighbors map[int]server.NetworkServer) {
	neighbors = make(map[int]server.NetworkServer, 3)
	// If there are only 1, 2 or 3 possible neighbors...take them.
	switch len(allAvailableNodes) {
	case 1:
		utils.PrintMessage(fmt.Sprintf("There is only one node in the nodeList. Ther must be at least 2.\n%s\n", utils.ERROR_FOOTER))
		os.Exit(1)
	case 2, 3, 4:
		for key, value := range allAvailableNodes {
			if key != localNodeId {
				neighbors[key] = value
			}
		}
		return
	}
	// Because of
	var highestId int
	for key := range allAvailableNodes {
		if highestId < key {
			highestId = key
		}
	}
	randomObject := rand.New(rand.NewSource(time.Now().UnixNano()))
	for len(neighbors) != 3 {
		var randomNumber int
		randomNumber = randomObject.Intn(highestId + 1)
		if randomNumber == localNodeId {
			continue
		}
		// Add only the nodes with the id which exists.
		if value, ok := allAvailableNodes[randomNumber]; ok {
			// And check here if the node already exists in the neighbors map.
			if _, ok := neighbors[randomNumber]; !ok {
				neighbors[randomNumber] = value
				// Now remove the added node from the map.
				delete(allAvailableNodes, randomNumber)
			}
		}
	}
	return
}

// This function waits for a message that is sent to the channel and
// splits the handling of the message depending on the NachrichtenTyp (message type)
func handleReceivedProtobufMessageWithChannel(localNode server.NetworkServer, receivingChannel chan *protobuf.Nachricht) {
	for {
		// This call blocks until a new message is available.
		message := <-receivingChannel
		handleReceivedProtobufMessage(localNode, message)
	}
}

// This method gets a protobuf message and decides if it is a control or a
// application message and gives it to the related function.
func handleReceivedProtobufMessage(localNode server.NetworkServer, protoMessage *protobuf.Nachricht) {
	utils.PrintMessage(fmt.Sprintf("Message on %s received:\n\n%s\n\n", localNode.String(), protoMessage.String()))
	switch protoMessage.GetNachrichtenTyp() {
	case protobuf.Nachricht_KONTROLLNACHRICHT:
		utils.PrintMessage("Message is of type KONTROLLNACHRICHT.")
		handleReceivedControlMessage(protoMessage)
	case protobuf.Nachricht_ANWENDUNGSNACHRICHT:
		utils.PrintMessage("Message is of type ANWENDUNGSNACHRICHT.")
		handleReceivedApplicationMessage(protoMessage)
	default:
		log.Fatalln("Read a unknown \"NachrichtenTyp\"")
	}
}

func handleReceivedControlMessage(message *protobuf.Nachricht) {
	switch message.GetKontrollTyp() {
	case protobuf.Nachricht_INITIALISIEREN:
		if !messageToAllNeighborsSent {
			for key, value := range neighbors {
				SendProtobufApplicationMessage(localNode, value, key, message.GetNachrichtenInhalt())
			}
			messageToAllNeighborsSent = true
		}
	case protobuf.Nachricht_BEENDEN:
		for id, destinationNode := range neighbors {
			SendProtobufControlMessage(localNode, destinationNode, id, utils.CONTROL_TYPE_EXIT, message.GetNachrichtenInhalt())
		}
		utils.PrintMessage("Received a EXIT message, so program will be exited.")
		os.Exit(0)
	default:
		log.Fatalln("Read a unknown \"KontrollTyp\"")
	}
}

func handleReceivedApplicationMessage(message *protobuf.Nachricht) {
	if !messageToAllNeighborsSent {
		for key, value := range neighbors {
			SendProtobufApplicationMessage(localNode, value, key, message.GetNachrichtenInhalt())
		}
		messageToAllNeighborsSent = true
	}
	// Because the SourceID is of type int32, I have to cast it here.
	sourceId := int(message.GetSourceID())
	// Check if the node that sends the message is in the neighbors map.
	// If not, add him.
	// Optional: Send him a response that he is added as neighbor.
	if _, ok := neighbors[sourceId]; !ok {
		networkServerObject := server.New()
		networkServerObject.SetClientName(strconv.Itoa(sourceId))
		networkServerObject.SetIpAddressAsString(message.GetSourceIP())
		networkServerObject.SetPort(sourceId)
		networkServerObject.SetUsedProtocol("tcp") //TODO: Maybe a different approach...
		neighbors[int(message.GetSourceID())] = networkServerObject
		//sendProtobufApplicationMessage(sourceId)
	}
}
<commit_msg>Changed the name of boolean to customerNode (like in my diagrams)<commit_after>package exercise2

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"
	"time"

	"github.com/jzipfler/htw-ava/protobuf"
	"github.com/jzipfler/htw-ava/server"
	"github.com/jzipfler/htw-ava/utils"
)

var (
	localNode                 server.NetworkServer
	allNodes                  map[int]server.NetworkServer
	neighbors                 map[int]server.NetworkServer
	messageToAllNeighborsSent bool
)

// With this function an node that interacts independently gets started.
// He can be controlled with a controller.
func StartIndependentNode(localNodeId int, allAvailableNodes, neighborNodes map[int]server.NetworkServer, customerNode bool) {
	if allAvailableNodes == nil {
		utils.PrintMessage(fmt.Sprintf("To start the node, there must be a node map which is currently nil.\n%s\n", utils.ERROR_FOOTER))
		os.Exit(1)
	}
	if _, ok := allAvailableNodes[localNodeId]; !ok {
		utils.PrintMessage(fmt.Sprintf("The given id exists not in the node map.\n%s\n", utils.ERROR_FOOTER))
		os.Exit(1)
	}
	if neighborNodes == nil {
		utils.PrintMessage(fmt.Sprintf("No neighbors given. Use the ChooseThreeNeighbors function to get some.\n%s\n", utils.ERROR_FOOTER))
		neighborNodes = ChooseThreeNeighbors(localNodeId, allAvailableNodes)
	}
	utils.PrintMessage("Start current instance as independent node.")
	allNodes = allAvailableNodes
	neighbors = neighborNodes
	localNode = allAvailableNodes[localNodeId]
	messageToAllNeighborsSent = false
	utils.PrintMessage("This node has the folowing settings: ")
	utils.PrintMessage(localNode)

	protobufChannel := make(chan *protobuf.Nachricht)
	//A goroutine that receives the protobuf message and reacts to it.
	go handleReceivedProtobufMessageWithChannel(localNode, protobufChannel)
	if err := server.StartServer(localNode, nil); err != nil {
		log.Fatal("Error happened: " + err.Error())
	}
	defer server.StopServer()

	for {
		//ReceiveMessage blocks until a message comes in
		if conn, err := server.ReceiveMessage(); err == nil {
			//If err is nil then that means that data is available for us so we take up this data and pass it to a new goroutine
			go ReceiveAndParseIncomingProtobufMessageToChannel(conn, protobufChannel)
			//ReceiveAndParseIncomingProtobufMessageToChannel(conn, protobufChannel)
			//protodata := ReceiveAndParseInfomingProtoufMessage(conn)
			//utils.PrintMessage(fmt.Sprintf("Message on %s received:\n\n%s\n\n", localNode.String(), protodata.String()))
			//handleReceivedProtobufMessage(protodata)
		}
	}
}

// The chooseThreeNeighbors function uses the allAvailableNodes map to return
// another map that contains 3 nodes at the most.
// It calls os.Exit(1) if only one node is available in the allAvailableNodes map.
func ChooseThreeNeighbors(localNodeId int, allAvailableNodes map[int]server.NetworkServer) (neighbors map[int]server.NetworkServer) {
	neighbors = make(map[int]server.NetworkServer, 3)
	// If there are only 1, 2 or 3 possible neighbors...take them.
	switch len(allAvailableNodes) {
	case 1:
		utils.PrintMessage(fmt.Sprintf("There is only one node in the nodeList. Ther must be at least 2.\n%s\n", utils.ERROR_FOOTER))
		os.Exit(1)
	case 2, 3, 4:
		for key, value := range allAvailableNodes {
			if key != localNodeId {
				neighbors[key] = value
			}
		}
		return
	}
	// Because of
	var highestId int
	for key := range allAvailableNodes {
		if highestId < key {
			highestId = key
		}
	}
	randomObject := rand.New(rand.NewSource(time.Now().UnixNano()))
	for len(neighbors) != 3 {
		var randomNumber int
		randomNumber = randomObject.Intn(highestId + 1)
		if randomNumber == localNodeId {
			continue
		}
		// Add only the nodes with the id which exists.
		if value, ok := allAvailableNodes[randomNumber]; ok {
			// And check here if the node already exists in the neighbors map.
			if _, ok := neighbors[randomNumber]; !ok {
				neighbors[randomNumber] = value
				// Now remove the added node from the map.
				delete(allAvailableNodes, randomNumber)
			}
		}
	}
	return
}

// This function waits for a message that is sent to the channel and
// splits the handling of the message depending on the NachrichtenTyp (message type)
func handleReceivedProtobufMessageWithChannel(localNode server.NetworkServer, receivingChannel chan *protobuf.Nachricht) {
	for {
		// This call blocks until a new message is available.
		message := <-receivingChannel
		handleReceivedProtobufMessage(localNode, message)
	}
}

// This method gets a protobuf message and decides if it is a control or a
// application message and gives it to the related function.
func handleReceivedProtobufMessage(localNode server.NetworkServer, protoMessage *protobuf.Nachricht) {
	utils.PrintMessage(fmt.Sprintf("Message on %s received:\n\n%s\n\n", localNode.String(), protoMessage.String()))
	switch protoMessage.GetNachrichtenTyp() {
	case protobuf.Nachricht_KONTROLLNACHRICHT:
		utils.PrintMessage("Message is of type KONTROLLNACHRICHT.")
		handleReceivedControlMessage(protoMessage)
	case protobuf.Nachricht_ANWENDUNGSNACHRICHT:
		utils.PrintMessage("Message is of type ANWENDUNGSNACHRICHT.")
		handleReceivedApplicationMessage(protoMessage)
	default:
		log.Fatalln("Read a unknown \"NachrichtenTyp\"")
	}
}

func handleReceivedControlMessage(message *protobuf.Nachricht) {
	switch message.GetKontrollTyp() {
	case protobuf.Nachricht_INITIALISIEREN:
		if !messageToAllNeighborsSent {
			for key, value := range neighbors {
				SendProtobufApplicationMessage(localNode, value, key, message.GetNachrichtenInhalt())
			}
			messageToAllNeighborsSent = true
		}
	case protobuf.Nachricht_BEENDEN:
		for id, destinationNode := range neighbors {
			SendProtobufControlMessage(localNode, destinationNode, id, utils.CONTROL_TYPE_EXIT, message.GetNachrichtenInhalt())
		}
		utils.PrintMessage("Received a EXIT message, so program will be exited.")
		os.Exit(0)
	default:
		log.Fatalln("Read a unknown \"KontrollTyp\"")
	}
}

func handleReceivedApplicationMessage(message *protobuf.Nachricht) {
	if !messageToAllNeighborsSent {
		for key, value := range neighbors {
			SendProtobufApplicationMessage(localNode, value, key, message.GetNachrichtenInhalt())
		}
		messageToAllNeighborsSent = true
	}
	// Because the SourceID is of type int32, I have to cast it here.
	sourceId := int(message.GetSourceID())
	// Check if the node that sends the message is in the neighbors map.
	// If not, add him.
	// Optional: Send him a response that he is added as neighbor.
	if _, ok := neighbors[sourceId]; !ok {
		networkServerObject := server.New()
		networkServerObject.SetClientName(strconv.Itoa(sourceId))
		networkServerObject.SetIpAddressAsString(message.GetSourceIP())
		networkServerObject.SetPort(sourceId)
		networkServerObject.SetUsedProtocol("tcp") //TODO: Maybe a different approach...
		neighbors[int(message.GetSourceID())] = networkServerObject
		//sendProtobufApplicationMessage(sourceId)
	}
}
<|endoftext|>


<commit_before>// Package sendgrid provides a simple interface to interact with the SendGrid API
package sendgrid

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const Version = "2.0.0"

// SGClient will contain the credentials and default values
type SGClient struct {
	apiUser string
	apiPwd  string
	APIMail string
	Client  *http.Client
}

// NewSendGridClient will return a new SGClient. Used for username and password
func NewSendGridClient(apiUser, apiKey string) *SGClient {
	apiMail := "https://api.sendgrid.com/api/mail.send.json?"

	Client := &SGClient{
		apiUser: apiUser,
		apiPwd:  apiKey,
		APIMail: apiMail,
	}

	return Client
}

// NewSendGridClient will return a new SGClient. Used for api key
func NewSendGridClientWithApiKey(apiKey string) *SGClient {
	apiMail := "https://api.sendgrid.com/api/mail.send.json?"

	Client := &SGClient{
		apiPwd:  apiKey,
		APIMail: apiMail,
	}

	return Client
}

func (sg *SGClient) buildURL(m *SGMail) (url.Values, error) {
	values := url.Values{}
	if sg.apiUser != "" {
		values.Set("api_user", sg.apiUser)
		values.Set("api_key", sg.apiPwd)
	}
	values.Set("subject", m.Subject)
	values.Set("html", m.HTML)
	values.Set("text", m.Text)
	values.Set("from", m.From)
	values.Set("replyto", m.ReplyTo)
	apiHeaders, err := m.SMTPAPIHeader.JSONString()
	if err != nil {
		return nil, fmt.Errorf("sendgrid.go: error:%v", err)
	}
	values.Set("x-smtpapi", apiHeaders)
	headers, err := m.HeadersString()
	if err != nil {
		return nil, fmt.Errorf("sendgrid.go: error: %v", err)
	}
	values.Set("headers", headers)
	if len(m.FromName) != 0 {
		values.Set("fromname", m.FromName)
	}
	for i := 0; i < len(m.To); i++ {
		values.Add("to[]", m.To[i])
	}
	for i := 0; i < len(m.Cc); i++ {
		values.Add("cc[]", m.Cc[i])
	}
	for i := 0; i < len(m.Bcc); i++ {
		values.Add("bcc[]", m.Bcc[i])
	}
	for i := 0; i < len(m.ToName); i++ {
		values.Add("toname[]", m.ToName[i])
	}
	for k, v := range m.Files {
		values.Set("files["+k+"]", v)
	}
	for k, v := range m.Content {
		values.Set("content["+k+"]", v)
	}
	return values, nil
}

// Send will send mail using SG web API
func (sg *SGClient) Send(m *SGMail) error {
	if sg.Client == nil {
		sg.Client = &http.Client{
			Transport: http.DefaultTransport,
			Timeout:   5 * time.Second,
		}
	}
	var e error
	values, e := sg.buildURL(m)
	if e != nil {
		return e
	}
	req, e := http.NewRequest("POST", sg.APIMail, strings.NewReader(values.Encode()))
	if e != nil {
		return e
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("User-Agent", "sendgrid/"+Version+";go")

	// Using API key
	if sg.apiUser == "" {
		req.Header.Set("Authorization", "Bearer "+sg.apiPwd)
	}

	res, e := sg.Client.Do(req)
	if e != nil {
		return fmt.Errorf("sendgrid.go: error:%v; response:%v", e, res)
	}

	defer res.Body.Close()

	if res.StatusCode == http.StatusOK {
		return nil
	}

	body, _ := ioutil.ReadAll(res.Body)

	return fmt.Errorf("sendgrid.go: code:%d error:%v body:%s", res.StatusCode, e, body)
}
<commit_msg>Pass api url in for testing<commit_after>// Package sendgrid provides a simple interface to interact with the SendGrid API
package sendgrid

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const Version = "2.0.0"

// SGClient will contain the credentials and default values
type SGClient struct {
	apiUser string
	apiPwd  string
	APIMail string
	Client  *http.Client
}

// NewSendGridClient will return a new SGClient. Used for username and password
func NewSendGridClient(apiUser, apiKey string) *SGClient {
	apiMail := "https://api.sendgrid.com/api/mail.send.json?"

	Client := &SGClient{
		apiUser: apiUser,
		apiPwd:  apiKey,
		APIMail: apiMail,
	}

	return Client
}

// NewSendGridClient will return a new SGClient. Used for api key
func NewSendGridClientWithApiKey(apiKey string) *SGClient {
	apiMail := "https://api.sendgrid.com/api/mail.send.json?"

	Client := &SGClient{
		apiPwd:  apiKey,
		APIMail: apiMail,
	}

	return Client
}

// NewSendGridClient will return a new SGClient. Used for api key
func NewSendGridClientWithApiKeyAndMailUrl(apiKey, apiMail string) *SGClient {

	Client := &SGClient{
		apiPwd:  apiKey,
		APIMail: apiMail,
	}

	return Client
}

func (sg *SGClient) buildURL(m *SGMail) (url.Values, error) {
	values := url.Values{}
	if sg.apiUser != "" {
		values.Set("api_user", sg.apiUser)
		values.Set("api_key", sg.apiPwd)
	}
	values.Set("subject", m.Subject)
	values.Set("html", m.HTML)
	values.Set("text", m.Text)
	values.Set("from", m.From)
	values.Set("replyto", m.ReplyTo)
	apiHeaders, err := m.SMTPAPIHeader.JSONString()
	if err != nil {
		return nil, fmt.Errorf("sendgrid.go: error:%v", err)
	}
	values.Set("x-smtpapi", apiHeaders)
	headers, err := m.HeadersString()
	if err != nil {
		return nil, fmt.Errorf("sendgrid.go: error: %v", err)
	}
	values.Set("headers", headers)
	if len(m.FromName) != 0 {
		values.Set("fromname", m.FromName)
	}
	for i := 0; i < len(m.To); i++ {
		values.Add("to[]", m.To[i])
	}
	for i := 0; i < len(m.Cc); i++ {
		values.Add("cc[]", m.Cc[i])
	}
	for i := 0; i < len(m.Bcc); i++ {
		values.Add("bcc[]", m.Bcc[i])
	}
	for i := 0; i < len(m.ToName); i++ {
		values.Add("toname[]", m.ToName[i])
	}
	for k, v := range m.Files {
		values.Set("files["+k+"]", v)
	}
	for k, v := range m.Content {
		values.Set("content["+k+"]", v)
	}
	return values, nil
}

// Send will send mail using SG web API
func (sg *SGClient) Send(m *SGMail) error {
	if sg.Client == nil {
		sg.Client = &http.Client{
			Transport: http.DefaultTransport,
			Timeout:   5 * time.Second,
		}
	}
	var e error
	values, e := sg.buildURL(m)
	if e != nil {
		return e
	}
	req, e := http.NewRequest("POST", sg.APIMail, strings.NewReader(values.Encode()))
	if e != nil {
		return e
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("User-Agent", "sendgrid/"+Version+";go")

	// Using API key
	if sg.apiUser == "" {
		req.Header.Set("Authorization", "Bearer "+sg.apiPwd)
	}

	res, e := sg.Client.Do(req)
	if e != nil {
		return fmt.Errorf("sendgrid.go: error:%v; response:%v", e, res)
	}

	defer res.Body.Close()

	if res.StatusCode == http.StatusOK {
		return nil
	}

	body, _ := ioutil.ReadAll(res.Body)

	return fmt.Errorf("sendgrid.go: code:%d error:%v body:%s", res.StatusCode, e, body)
}
<|endoftext|>