<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"github.com/gorilla/mux"
	. "gopkg.in/check.v1"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"vip/test"
)

var (
	_ = Suite(&UploadSuite{})
)

type UploadSuite struct{}

func (s *UploadSuite) SetUpSuite(c *C) {
	setUpSuite(c)
}

func (s *UploadSuite) SetUpTest(c *C) {
	setUpTest(c)

	storage = test.NewStore()
}

func (s *UploadSuite) TestUpload(c *C) {
	authToken = "lalalatokenlalala"
	os.Setenv("DOMAIN_DATA", "")

	recorder := httptest.NewRecorder()

	// Mock up a router so that mux.Vars are passed
	// correctly
	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))
	f, err := os.Open("./test/awesome.jpeg")
	c.Assert(err, IsNil)

	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)
	c.Assert(err, IsNil)
	fstat, err := os.Stat("./test/awesome.jpeg")
	c.Assert(err, IsNil)
	req.ContentLength = fstat.Size()
	req.Header.Set("Content-Type", "image/jpeg")
	req.Header.Set("X-Vip-Token", authToken)

	m.ServeHTTP(recorder, req)

	var u UploadResponse
	err = json.NewDecoder(recorder.Body).Decode(&u)
	c.Assert(err, IsNil)
	c.Assert(len(u.Url), Not(Equals), 0)

	uri, err := url.Parse(u.Url)
	c.Assert(err, IsNil)

	c.Assert(uri.Scheme, Equals, "http")
	c.Assert(uri.Host, Equals, "localhost:8080")
	c.Assert(uri.Path[1:13], Equals, "samplebucket")
	c.Assert(strings.HasSuffix(ui.Path, "-1024x786"), Equals, true)
	c.Assert(recorder.HeaderMap["Content-Type"][0], Equals, "application/json")
}

func (s *UploadSuite) TestEmptyUpload(c *C) {
	authToken = "lalalatokenlalala"
	os.Setenv("ALLOWED_ORIGIN", "")

	recorder := httptest.NewRecorder()

	// Mock up a router so that mux.Vars are passed
	// correctly
	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))
	f := &bytes.Reader{}
	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)
	c.Assert(err, IsNil)

	req.Header.Set("Content-Type", "image/jpeg")
	req.Header.Set("X-Vip-Token", authToken)

	m.ServeHTTP(recorder, req)
	c.Assert(recorder.Code, Equals, http.StatusBadRequest)

	var u ErrorResponse
	err = json.NewDecoder(recorder.Body).Decode(&u)
	c.Assert(err, IsNil)
	c.Assert(u.Msg, Equals, "File must have size greater than 0")
}

func (s *UploadSuite) TestUnauthorizedUpload(c *C) {
	authToken = "lalalatokenlalala"
	os.Setenv("ALLOWED_ORIGIN", "")

	recorder := httptest.NewRecorder()

	// Mock up a router so that mux.Vars are passed
	// correctly
	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))

	f, err := os.Open("./test/awesome.jpeg")
	c.Assert(err, IsNil)

	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)

	c.Assert(err, IsNil)

	req.Header.Set("Content-Type", "image/jpeg")

	m.ServeHTTP(recorder, req)

	c.Assert(recorder.Code, Equals, http.StatusUnauthorized)
}

func (s *UploadSuite) TestSetOriginData(c *C) {
	authToken = "heyheyheyimatoken"
	os.Setenv("ALLOWED_ORIGIN", "WHATEVER, MAN")

	recorder := httptest.NewRecorder()

	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))

	f, err := os.Open("./test/awesome.jpeg")
	c.Assert(err, IsNil)

	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)
	c.Assert(err, IsNil)
	fstat, err := os.Stat("./test/awesome.jpeg")
	c.Assert(err, IsNil)
	req.ContentLength = fstat.Size()
	req.Header.Set("Origin", "WHATEVER, MAN")
	c.Assert(err, IsNil)
	req.Header.Set("Content-Type", "image/jpeg")

	m.ServeHTTP(recorder, req)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
}
<commit_msg>Fix image size in key again<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"github.com/gorilla/mux"
	. "gopkg.in/check.v1"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strings"
	"vip/test"
)

var (
	_ = Suite(&UploadSuite{})
)

type UploadSuite struct{}

func (s *UploadSuite) SetUpSuite(c *C) {
	setUpSuite(c)
}

func (s *UploadSuite) SetUpTest(c *C) {
	setUpTest(c)

	storage = test.NewStore()
}

func (s *UploadSuite) TestUpload(c *C) {
	authToken = "lalalatokenlalala"
	os.Setenv("DOMAIN_DATA", "")

	recorder := httptest.NewRecorder()

	// Mock up a router so that mux.Vars are passed
	// correctly
	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))
	f, err := os.Open("./test/awesome.jpeg")
	c.Assert(err, IsNil)

	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)
	c.Assert(err, IsNil)
	fstat, err := os.Stat("./test/awesome.jpeg")
	c.Assert(err, IsNil)
	req.ContentLength = fstat.Size()
	req.Header.Set("Content-Type", "image/jpeg")
	req.Header.Set("X-Vip-Token", authToken)

	m.ServeHTTP(recorder, req)

	var u UploadResponse
	err = json.NewDecoder(recorder.Body).Decode(&u)
	c.Assert(err, IsNil)
	c.Assert(len(u.Url), Not(Equals), 0)

	uri, err := url.Parse(u.Url)
	c.Assert(err, IsNil)

	c.Assert(uri.Scheme, Equals, "http")
	c.Assert(uri.Host, Equals, "localhost:8080")
	c.Assert(uri.Path[1:13], Equals, "samplebucket")
	c.Assert(strings.HasSuffix(uri.Path, "-1024x768"), Equals, true)
	c.Assert(recorder.HeaderMap["Content-Type"][0], Equals, "application/json")
}

func (s *UploadSuite) TestEmptyUpload(c *C) {
	authToken = "lalalatokenlalala"
	os.Setenv("ALLOWED_ORIGIN", "")

	recorder := httptest.NewRecorder()

	// Mock up a router so that mux.Vars are passed
	// correctly
	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))
	f := &bytes.Reader{}
	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)
	c.Assert(err, IsNil)

	req.Header.Set("Content-Type", "image/jpeg")
	req.Header.Set("X-Vip-Token", authToken)

	m.ServeHTTP(recorder, req)
	c.Assert(recorder.Code, Equals, http.StatusBadRequest)

	var u ErrorResponse
	err = json.NewDecoder(recorder.Body).Decode(&u)
	c.Assert(err, IsNil)
	c.Assert(u.Msg, Equals, "File must have size greater than 0")
}

func (s *UploadSuite) TestUnauthorizedUpload(c *C) {
	authToken = "lalalatokenlalala"
	os.Setenv("ALLOWED_ORIGIN", "")

	recorder := httptest.NewRecorder()

	// Mock up a router so that mux.Vars are passed
	// correctly
	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))

	f, err := os.Open("./test/awesome.jpeg")
	c.Assert(err, IsNil)

	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)

	c.Assert(err, IsNil)

	req.Header.Set("Content-Type", "image/jpeg")

	m.ServeHTTP(recorder, req)

	c.Assert(recorder.Code, Equals, http.StatusUnauthorized)
}

func (s *UploadSuite) TestSetOriginData(c *C) {
	authToken = "heyheyheyimatoken"
	os.Setenv("ALLOWED_ORIGIN", "WHATEVER, MAN")

	recorder := httptest.NewRecorder()

	m := mux.NewRouter()
	m.Handle("/upload/{bucket_id}", verifyAuth(handleUpload))

	f, err := os.Open("./test/awesome.jpeg")
	c.Assert(err, IsNil)

	req, err := http.NewRequest("POST", "http://localhost:8080/upload/samplebucket", f)
	c.Assert(err, IsNil)
	fstat, err := os.Stat("./test/awesome.jpeg")
	c.Assert(err, IsNil)
	req.ContentLength = fstat.Size()
	req.Header.Set("Origin", "WHATEVER, MAN")
	c.Assert(err, IsNil)
	req.Header.Set("Content-Type", "image/jpeg")

	m.ServeHTTP(recorder, req)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
}
<|endoftext|>


<commit_before><commit_msg>Remove "shouldn't happen" condition<commit_after><|endoftext|>


<commit_before>package job

import (
	"fmt"
	"os"
	"os/exec"
	//"os/user"
	"os/signal"
	"strconv"
	"strings"
	//"syscall"
	"time"

	"../utils/iso8601"

	"github.com/222Labs/common/go/logging"
	"github.com/nu7hatch/gouuid"
)

var (
	log = logging.GetLogger("kala")
)

func init() {
	// Prep cache
	allJobs, err := GetAllJobs()
	if err != nil {
		log.Fatal(err)
	}
	for _, v := range allJobs {
		AllJobs.Set(v)
	}
	// Occasionally, save items in cache to db.
	go AllJobs.PersistEvery(SaveAllJobsWaitTime)

	// Process-level defer for shutting down the db.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	go func() {
		s := <-c
		log.Info("Process got signal: %s", s)
		log.Info("Shutting down....")

		// Persist all jobs to database
		AllJobs.Persist()

		// Close the database
		db.Close()
	}()

}

type JobStat struct {
	JobId             string
	RanAt             time.Time
	NumberOfRetries   uint
	Success           bool
	ExecutionDuration time.Duration
}

type Job struct {
	Name string `json:"name"`
	Id   string `json:"id"`

	// Command to run
	// e.g. "bash /path/to/my/script.sh"
	Command string `json:"command"`
	// Run command as a different user?
	//TODO
	//RunAsUser string `json:""`
	//user *user.User

	// Email of the owner of this job
	// e.g. "admin@example.com"
	Owner string `json:"owner"`

	// Is this job disabled?
	Disabled bool `json:"disabled"`

	// Jobs that are dependent upon this one.
	// Will be run after this job runs.
	DependentJobs []string `json:"dependent_jobs"`
	ParentJobs    []string `json:"parent_jobs"`

	// ISO 8601 String
	// e.g. "R/2014-03-08T20:00:00.000Z/PT2H"
	Schedule     string `json:"schedule"`
	scheduleTime time.Time
	// ISO 8601 Duration struct, used for scheduling
	// job after each run.
	delayDuration *iso8601.Duration

	// Number of times to schedule this job after the
	// first run.
	timesToRepeat int64

	// Number of times to retry on failed attempt for each run.
	Retries         uint `json:"retries"`
	currentRetries  uint
	Epsilon         string `json:"epsilon"`
	epsilonDuration *iso8601.Duration

	// Meta data about successful and failed runs.
	SuccessCount     uint      `json:"success_count"`
	LastSuccess      time.Time `json:"last_success"`
	ErrorCount       uint      `json:"error_count"`
	LastError        time.Time `json:"last_error"`
	LastAttemptedRun time.Time `json:"last_attempted_run"`

	jobTimer  *time.Timer
	NextRunAt time.Time `json:"next_run_at"`

	// TODO
	// EnvironmentVariables map[string]string `json:""`
}

// Init() fills in the protected fields and parses the iso8601 notation.
func (j *Job) Init() error {
	u4, err := uuid.NewV4()
	if err != nil {
		log.Error("Error occured when generating uuid: %s", err)
		return err
	}
	j.Id = u4.String()

	if len(j.ParentJobs) != 0 {
		// Add new job to parent jobs
		for _, p := range j.ParentJobs {
			AllJobs.Get(p).DependentJobs = append(AllJobs.Get(p).DependentJobs, j.Id)
		}
		return nil
	}

	if j.Schedule == "" {
		// If schedule is empty, its a one-off job.
		go j.Run()
		return nil
	}

	splitTime := strings.Split(j.Schedule, "/")
	if len(splitTime) != 3 {
		return fmt.Errorf("Schedule not formatted correctly. Should look like: R/2014-03-08T20:00:00Z/PT2H")
	}

	// Handle Repeat Amount
	if splitTime[0] == "R" {
		// Repeat forever
		j.timesToRepeat = -1
	} else {
		j.timesToRepeat, err = strconv.ParseInt(strings.Split(splitTime[0], "R")[1], 10, 0)
		if err != nil {
			log.Error("Error converting timesToRepeat to an int: %s", err)
			return err
		}
	}
	log.Debug("timesToRepeat: %d", j.timesToRepeat)

	j.scheduleTime, err = time.Parse(time.RFC3339, splitTime[1])
	if err != nil {
		log.Error("Error converting scheduleTime to a time.Time: %s", err)
		return err
	}
	if (time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())) < 0 {
		return fmt.Errorf("Schedule time has passed.")
	}
	log.Debug("Schedule Time: %s", j.scheduleTime)

	j.delayDuration, err = iso8601.FromString(splitTime[2])
	if err != nil {
		log.Error("Error converting delayDuration to a iso8601.Duration: %s", err)
		return err
	}
	log.Debug("Delay Duration: %s", j.delayDuration.ToDuration())

	if j.Epsilon != "" {
		j.epsilonDuration, err = iso8601.FromString(j.Epsilon)
		if err != nil {
			log.Error("Error converting j.Epsilon to iso8601.Duration: %s", err)
			return err
		}
	}

	//TODO
	/*
		if j.RunAsUser != "" {
			j.user, err = user.Lookup(j.RunAsUser)
			if err != nil {
				log.Error("Error looking up user %s", j.RunAsUser)
				return err
			}
		}
	*/

	j.StartWaiting()

	return nil
}

// StartWaiting begins a timer for when it should execute the Jobs .Run() method.
func (j *Job) StartWaiting() {
	waitDuration := time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())
	log.Debug("Wait Duration initial: %s", waitDuration)
	if waitDuration < 0 {
		// Needs to be recalculated each time because of Months.
		waitDuration = j.delayDuration.ToDuration()
	}
	log.Info("Job Scheduled to run in: %s", waitDuration)
	j.NextRunAt = time.Now().Add(waitDuration)
	j.jobTimer = time.AfterFunc(waitDuration, j.Run)
}

func (j *Job) Disable() {
	// TODO - revisit error handling
	//hasBeenStopped := j.jobTimer.Stop()
	_ = j.jobTimer.Stop()
	j.Disabled = true
}

// Run() executes the Job's command, collects metadata around the success
// or failure of the Job's execution, and schedules the next run.
func (j *Job) Run() {
	log.Info("Job %s running", j.Name)

	// Schedule next run
	if j.timesToRepeat != 0 {
		j.timesToRepeat -= 1
		go j.StartWaiting()
	}

	j.LastAttemptedRun = time.Now()

	// TODO - Make thread safe
	// Init retries
	if j.currentRetries == 0 && j.Retries != 0 {
		j.currentRetries = j.Retries
	}

	// Execute command
	args := strings.Split(j.Command, " ")
	cmd := exec.Command(args[0], args[1:]...)

	//TODO
	/*
		if j.RunAsUser != "" {
			uid, err := strconv.Atoi(j.user.Uid)
			if err != nil {
				//TODO
				//return err
				return
			}
			gid, err := strconv.Atoi(j.user.Gid)
			if err != nil {
				//TODO
				//return err
				return
			}
			cmd.SysProcAttr = &syscall.SysProcAttr{}
			cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
		}
	*/
	err := cmd.Run()
	if err != nil {
		// TODO - Error Reporting, email error
		log.Error("Run Command got an Error: %s", err)
		j.ErrorCount += 1
		j.LastError = time.Now()
		// Handle retrying
		if j.currentRetries != 0 {
			if j.Epsilon != "" {
				if j.epsilonDuration.ToDuration() == 0 {
					timeLeftToRetry := time.Duration(j.epsilonDuration.ToDuration()) - time.Duration(time.Now().UnixNano()-j.NextRunAt.UnixNano())
					if timeLeftToRetry < 0 {
						// TODO - Make thread safe
						// Reset retries and exit.
						j.currentRetries = 0
						return
					}
				}
			}
			j.currentRetries -= 0
			j.Run()
		}
		// TODO - Error Reporting, email error
		return
	}

	log.Info("%s was successful!", j.Name)
	j.SuccessCount += 1
	j.LastSuccess = time.Now()

	// Run Dependent Jobs
	if len(j.DependentJobs) != 0 {
		for _, id := range j.DependentJobs {
			go AllJobs.Get(id).Run()
		}
	}
}
<commit_msg>Fixed typo with reducing currentRetries.<commit_after>package job

import (
	"fmt"
	"os"
	"os/exec"
	//"os/user"
	"os/signal"
	"strconv"
	"strings"
	//"syscall"
	"time"

	"../utils/iso8601"

	"github.com/222Labs/common/go/logging"
	"github.com/nu7hatch/gouuid"
)

var (
	log = logging.GetLogger("kala")
)

func init() {
	// Prep cache
	allJobs, err := GetAllJobs()
	if err != nil {
		log.Fatal(err)
	}
	for _, v := range allJobs {
		AllJobs.Set(v)
	}
	// Occasionally, save items in cache to db.
	go AllJobs.PersistEvery(SaveAllJobsWaitTime)

	// Process-level defer for shutting down the db.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	go func() {
		s := <-c
		log.Info("Process got signal: %s", s)
		log.Info("Shutting down....")

		// Persist all jobs to database
		AllJobs.Persist()

		// Close the database
		db.Close()
	}()

}

type JobStat struct {
	JobId             string
	RanAt             time.Time
	NumberOfRetries   uint
	Success           bool
	ExecutionDuration time.Duration
}

type Job struct {
	Name string `json:"name"`
	Id   string `json:"id"`

	// Command to run
	// e.g. "bash /path/to/my/script.sh"
	Command string `json:"command"`
	// Run command as a different user?
	//TODO
	//RunAsUser string `json:""`
	//user *user.User

	// Email of the owner of this job
	// e.g. "admin@example.com"
	Owner string `json:"owner"`

	// Is this job disabled?
	Disabled bool `json:"disabled"`

	// Jobs that are dependent upon this one.
	// Will be run after this job runs.
	DependentJobs []string `json:"dependent_jobs"`
	ParentJobs    []string `json:"parent_jobs"`

	// ISO 8601 String
	// e.g. "R/2014-03-08T20:00:00.000Z/PT2H"
	Schedule     string `json:"schedule"`
	scheduleTime time.Time
	// ISO 8601 Duration struct, used for scheduling
	// job after each run.
	delayDuration *iso8601.Duration

	// Number of times to schedule this job after the
	// first run.
	timesToRepeat int64

	// Number of times to retry on failed attempt for each run.
	Retries         uint `json:"retries"`
	currentRetries  uint
	Epsilon         string `json:"epsilon"`
	epsilonDuration *iso8601.Duration

	// Meta data about successful and failed runs.
	SuccessCount     uint      `json:"success_count"`
	LastSuccess      time.Time `json:"last_success"`
	ErrorCount       uint      `json:"error_count"`
	LastError        time.Time `json:"last_error"`
	LastAttemptedRun time.Time `json:"last_attempted_run"`

	jobTimer  *time.Timer
	NextRunAt time.Time `json:"next_run_at"`

	// TODO
	// EnvironmentVariables map[string]string `json:""`
}

// Init() fills in the protected fields and parses the iso8601 notation.
func (j *Job) Init() error {
	u4, err := uuid.NewV4()
	if err != nil {
		log.Error("Error occured when generating uuid: %s", err)
		return err
	}
	j.Id = u4.String()

	if len(j.ParentJobs) != 0 {
		// Add new job to parent jobs
		for _, p := range j.ParentJobs {
			AllJobs.Get(p).DependentJobs = append(AllJobs.Get(p).DependentJobs, j.Id)
		}
		return nil
	}

	if j.Schedule == "" {
		// If schedule is empty, its a one-off job.
		go j.Run()
		return nil
	}

	splitTime := strings.Split(j.Schedule, "/")
	if len(splitTime) != 3 {
		return fmt.Errorf("Schedule not formatted correctly. Should look like: R/2014-03-08T20:00:00Z/PT2H")
	}

	// Handle Repeat Amount
	if splitTime[0] == "R" {
		// Repeat forever
		j.timesToRepeat = -1
	} else {
		j.timesToRepeat, err = strconv.ParseInt(strings.Split(splitTime[0], "R")[1], 10, 0)
		if err != nil {
			log.Error("Error converting timesToRepeat to an int: %s", err)
			return err
		}
	}
	log.Debug("timesToRepeat: %d", j.timesToRepeat)

	j.scheduleTime, err = time.Parse(time.RFC3339, splitTime[1])
	if err != nil {
		log.Error("Error converting scheduleTime to a time.Time: %s", err)
		return err
	}
	if (time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())) < 0 {
		return fmt.Errorf("Schedule time has passed.")
	}
	log.Debug("Schedule Time: %s", j.scheduleTime)

	j.delayDuration, err = iso8601.FromString(splitTime[2])
	if err != nil {
		log.Error("Error converting delayDuration to a iso8601.Duration: %s", err)
		return err
	}
	log.Debug("Delay Duration: %s", j.delayDuration.ToDuration())

	if j.Epsilon != "" {
		j.epsilonDuration, err = iso8601.FromString(j.Epsilon)
		if err != nil {
			log.Error("Error converting j.Epsilon to iso8601.Duration: %s", err)
			return err
		}
	}

	//TODO
	/*
		if j.RunAsUser != "" {
			j.user, err = user.Lookup(j.RunAsUser)
			if err != nil {
				log.Error("Error looking up user %s", j.RunAsUser)
				return err
			}
		}
	*/

	j.StartWaiting()

	return nil
}

// StartWaiting begins a timer for when it should execute the Jobs .Run() method.
func (j *Job) StartWaiting() {
	waitDuration := time.Duration(j.scheduleTime.UnixNano() - time.Now().UnixNano())
	log.Debug("Wait Duration initial: %s", waitDuration)
	if waitDuration < 0 {
		// Needs to be recalculated each time because of Months.
		waitDuration = j.delayDuration.ToDuration()
	}
	log.Info("Job Scheduled to run in: %s", waitDuration)
	j.NextRunAt = time.Now().Add(waitDuration)
	j.jobTimer = time.AfterFunc(waitDuration, j.Run)
}

func (j *Job) Disable() {
	// TODO - revisit error handling
	//hasBeenStopped := j.jobTimer.Stop()
	_ = j.jobTimer.Stop()
	j.Disabled = true
}

// Run() executes the Job's command, collects metadata around the success
// or failure of the Job's execution, and schedules the next run.
func (j *Job) Run() {
	log.Info("Job %s running", j.Name)

	// Schedule next run
	if j.timesToRepeat != 0 {
		j.timesToRepeat -= 1
		go j.StartWaiting()
	}

	j.LastAttemptedRun = time.Now()

	// TODO - Make thread safe
	// Init retries
	if j.currentRetries == 0 && j.Retries != 0 {
		j.currentRetries = j.Retries
	}

	// Execute command
	args := strings.Split(j.Command, " ")
	cmd := exec.Command(args[0], args[1:]...)

	//TODO
	/*
		if j.RunAsUser != "" {
			uid, err := strconv.Atoi(j.user.Uid)
			if err != nil {
				//TODO
				//return err
				return
			}
			gid, err := strconv.Atoi(j.user.Gid)
			if err != nil {
				//TODO
				//return err
				return
			}
			cmd.SysProcAttr = &syscall.SysProcAttr{}
			cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
		}
	*/
	err := cmd.Run()
	if err != nil {
		// TODO - Error Reporting, email error
		log.Error("Run Command got an Error: %s", err)
		j.ErrorCount += 1
		j.LastError = time.Now()
		// Handle retrying
		if j.currentRetries != 0 {
			if j.Epsilon != "" {
				if j.epsilonDuration.ToDuration() == 0 {
					timeLeftToRetry := time.Duration(j.epsilonDuration.ToDuration()) - time.Duration(time.Now().UnixNano()-j.NextRunAt.UnixNano())
					if timeLeftToRetry < 0 {
						// TODO - Make thread safe
						// Reset retries and exit.
						j.currentRetries = 0
						return
					}
				}
			}
			j.currentRetries -= 1
			j.Run()
		}
		// TODO - Error Reporting, email error
		return
	}

	log.Info("%s was successful!", j.Name)
	j.SuccessCount += 1
	j.LastSuccess = time.Now()

	// Run Dependent Jobs
	if len(j.DependentJobs) != 0 {
		for _, id := range j.DependentJobs {
			go AllJobs.Get(id).Run()
		}
	}
}
<|endoftext|>


<commit_before>package util

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
)

type Reader struct {
	buf *bufio.Reader
}

func NewReader(rd io.Reader) *Reader {
	return &Reader{buf: bufio.NewReader(rd)}
}

// Read reads data into p.
// It returns the number of bytes read into p.
// The bytes are taken from at most one Read on the underlying Reader,
// hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF.
func (r *Reader) Read(p []byte) (n int, err error) {
	return r.buf.Read(p)
}

// ReadAll reads from Reader until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from Reader until EOF, it does not treat an EOF from Read
// as an error to be reported.
func (r *Reader) ReadAll() ([]byte, error) {
	return ioutil.ReadAll(r.buf)
}

// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (r *Reader) ReadByte() (byte, error) {
	return r.buf.ReadByte()
}

// ReadSeveralBytes reads n bytes.
func (r *Reader) ReadSeveralBytes(n int) ([]byte, error) {
	if n == 0 {
		return nil, nil
	}

	peeked, err := r.buf.Peek(n)
	if err != nil {
		return nil, err
	}

	if _, err := r.buf.Discard(n); err != nil {
		return nil, err
	}

	return peeked, nil
}

// ReadTillDelim reads until the first occurrence of delim in the input,
// returning a slice containing the data up to the delimiter.
// ReadTillDelim advances buffer up to and including delimiter
// but returns only a slice containing the data without the delimiter though.
// If ReadTillDelim encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillDelim returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelim(delim byte) ([]byte, error) {
	read, err := r.buf.ReadBytes(delim)
	if read == nil || len(read) == 0 {
		return read, err
	}
	return read[:len(read)-1], err
}

// ReadTillDelims reads until the first occurrence of delims in the input,
// returning a slice containing the data up to the delimiters.
// ReadTillDelims advances buffer up to and including delimiters
// but returns only a slice containing the data without the delimiters though.
// If ReadTillDelims encounters an error before finding a delimiters,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillAndWithDelims returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelims(delims []byte) ([]byte, error) {
	if len(delims) == 0 {
		return r.ReadAll()
	}
	if len(delims) == 1 {
		return r.ReadTillDelim(delims[0])
	}

	buf := make([]byte, 0)

	for {
		b, err := r.buf.ReadByte()
		if err != nil {
			return buf, err
		}

		if b == delims[0] {
			peeked, err := r.buf.Peek(len(delims) - 1)
			if err != nil {
				return buf, err
			}
			if bytes.Equal(peeked, delims[1:]) {
				r.buf.Discard(len(peeked) - 1)
				break
			}
		}
		buf = append(buf, b)
	}

	return buf, nil
}

// Reset discards any buffered data, resets all state,
// and switches the buffered reader to read from r.
func (r *Reader) Reset(rd io.Reader) {
	r.buf.Reset(rd)
}
<commit_msg>Improve performance of reader.ReadTillDelims func<commit_after>package util

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
)

type Reader struct {
	buf *bufio.Reader
}

func NewReader(rd io.Reader) *Reader {
	return &Reader{buf: bufio.NewReader(rd)}
}

// Read reads data into p.
// It returns the number of bytes read into p.
// The bytes are taken from at most one Read on the underlying Reader,
// hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF.
func (r *Reader) Read(p []byte) (n int, err error) {
	return r.buf.Read(p)
}

// ReadAll reads from Reader until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from Reader until EOF, it does not treat an EOF from Read
// as an error to be reported.
func (r *Reader) ReadAll() ([]byte, error) {
	return ioutil.ReadAll(r.buf)
}

// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (r *Reader) ReadByte() (byte, error) {
	return r.buf.ReadByte()
}

// ReadSeveralBytes reads n bytes.
func (r *Reader) ReadSeveralBytes(n int) ([]byte, error) {
	if n == 0 {
		return nil, nil
	}

	peeked, err := r.buf.Peek(n)
	if err != nil {
		return nil, err
	}

	if _, err := r.buf.Discard(n); err != nil {
		return nil, err
	}

	return peeked, nil
}

// ReadTillDelim reads until the first occurrence of delim in the input,
// returning a slice containing the data up to the delimiter.
// ReadTillDelim advances buffer up to and including delimiter
// but returns only a slice containing the data without the delimiter though.
// If ReadTillDelim encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillDelim returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelim(delim byte) ([]byte, error) {
	read, err := r.buf.ReadBytes(delim)
	if read == nil || len(read) == 0 {
		return read, err
	}
	return read[:len(read)-1], err
}

// ReadTillDelims reads until the first occurrence of delims in the input,
// returning a slice containing the data up to the delimiters.
// ReadTillDelims advances buffer up to and including delimiters
// but returns only a slice containing the data without the delimiters though.
// If ReadTillDelims encounters an error before finding a delimiters,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillAndWithDelims returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelims(delims []byte) ([]byte, error) {
	if len(delims) == 0 {
		return r.ReadAll()
	}
	if len(delims) == 1 {
		return r.ReadTillDelim(delims[0])
	}

	buf := make([]byte, 0)

	for {
		read, err := r.ReadTillDelim(delims[0])
		if err != nil {
			return buf, err
		}
		buf = append(buf, read...)
		err = r.buf.UnreadByte()
		if err != nil {
			return buf, err
		}

		b, err := r.buf.ReadByte()
		if err != nil {
			return buf, err
		}

		if b == delims[0] {
			peeked, err := r.buf.Peek(len(delims) - 1)
			if err != nil {
				return buf, err
			}
			if bytes.Equal(peeked, delims[1:]) {
				r.buf.Discard(len(peeked) - 1)
				break
			}
		}
		buf = append(buf, b)
	}

	return buf, nil
}

// Reset discards any buffered data, resets all state,
// and switches the buffered reader to read from r.
func (r *Reader) Reset(rd io.Reader) {
	r.buf.Reset(rd)
}
<|endoftext|>


<commit_before>package gcss

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// selector represents a selector of CSS.
type selector struct {
	elementBase
	name string
	sels []*selector
	decs []*declaration
}

// WriteTo writes the selector to the writer.
func (sel *selector) WriteTo(w io.Writer) (int64, error) {
	bf := new(bytes.Buffer)

	// Write the declarations.
	if len(sel.decs) > 0 {
		bf.WriteString(sel.names())
		bf.WriteString(openBrace)

		for _, dec := range sel.decs {
			bf.WriteString(dec.property)
			bf.WriteString(colon)
			bf.WriteString(dec.value)
			bf.WriteString(semicolon)
		}

		bf.WriteString(closeBrace)
	}

	// Write the child selectors.
	for _, childSel := range sel.sels {
		if _, err := childSel.WriteTo(bf); err != nil {
			return 0, err
		}
	}

	n, err := w.Write(bf.Bytes())

	return int64(n), err
}

// AppendChild appends a selector or declaration to the selector.
func (sel *selector) AppendChild(child element) error {
	switch child.(type) {
	case *selector:
		sel.sels = append(sel.sels, child.(*selector))
	case *declaration:
		sel.decs = append(sel.decs, child.(*declaration))
	default:
		return fmt.Errorf("invalid child's type [line: %d]", sel.ln.no)
	}

	return nil
}

// names returns the selector names.
func (sel *selector) names() string {
	bf := new(bytes.Buffer)

	switch sel.parent.(type) {
	case nil:
		for _, name := range strings.Split(sel.name, comma) {
			if bf.Len() > 0 {
				bf.WriteString(comma)
			}

			bf.WriteString(strings.TrimSpace(name))
		}
	case *selector:
		for _, parentS := range strings.Split(sel.parent.(*selector).names(), comma) {
			for _, s := range strings.Split(sel.name, comma) {
				if bf.Len() > 0 {
					bf.WriteString(comma)
				}

				bf.WriteString(parentS)

				s = strings.TrimSpace(s)

				if strings.HasPrefix(s, ampersand) {
					bf.WriteString(strings.TrimPrefix(s, ampersand))
				} else {
					bf.WriteString(space)
					bf.WriteString(s)
				}
			}
		}
	}

	return bf.String()
}

// newSelector creates and returns a selector.
func newSelector(ln *line, parent element) *selector {
	return &selector{
		elementBase: newElementBase(ln, parent),
		name:        strings.TrimSpace(ln.s),
	}
}
<commit_msg>Update selector.go<commit_after>package gcss

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// selector represents a selector of CSS.
type selector struct {
	elementBase
	name string
	sels []*selector
	decs []*declaration
}

// WriteTo writes the selector to the writer.
func (sel *selector) WriteTo(w io.Writer) (int64, error) {
	bf := new(bytes.Buffer)

	// Write the declarations.
	if len(sel.decs) > 0 {
		bf.WriteString(sel.names())
		bf.WriteString(openBrace)

		for _, dec := range sel.decs {
			bf.WriteString(dec.property)
			bf.WriteString(colon)
			bf.WriteString(dec.value)
			bf.WriteString(semicolon)
		}

		bf.WriteString(closeBrace)
	}

	// Write the child selectors.
	for _, childSel := range sel.sels {
		childSel.WriteTo(bf)
	}

	n, err := w.Write(bf.Bytes())

	return int64(n), err
}

// AppendChild appends a selector or declaration to the selector.
func (sel *selector) AppendChild(child element) error {
	switch child.(type) {
	case *selector:
		sel.sels = append(sel.sels, child.(*selector))
	case *declaration:
		sel.decs = append(sel.decs, child.(*declaration))
	default:
		return fmt.Errorf("invalid child's type [line: %d]", sel.ln.no)
	}

	return nil
}

// names returns the selector names.
func (sel *selector) names() string {
	bf := new(bytes.Buffer)

	switch sel.parent.(type) {
	case nil:
		for _, name := range strings.Split(sel.name, comma) {
			if bf.Len() > 0 {
				bf.WriteString(comma)
			}

			bf.WriteString(strings.TrimSpace(name))
		}
	case *selector:
		for _, parentS := range strings.Split(sel.parent.(*selector).names(), comma) {
			for _, s := range strings.Split(sel.name, comma) {
				if bf.Len() > 0 {
					bf.WriteString(comma)
				}

				bf.WriteString(parentS)

				s = strings.TrimSpace(s)

				if strings.HasPrefix(s, ampersand) {
					bf.WriteString(strings.TrimPrefix(s, ampersand))
				} else {
					bf.WriteString(space)
					bf.WriteString(s)
				}
			}
		}
	}

	return bf.String()
}

// newSelector creates and returns a selector.
func newSelector(ln *line, parent element) *selector {
	return &selector{
		elementBase: newElementBase(ln, parent),
		name:        strings.TrimSpace(ln.s),
	}
}
<|endoftext|>


<commit_before>package base

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/scrapli/scrapligo/logging"
	"github.com/sirikothe/gotextfsm"
)

// ErrFailedOpeningTemplate error for failure to open a textfsm template.
var ErrFailedOpeningTemplate = errors.New("failed opening provided path to textfsm template")

// ErrFailedParsingTemplate error for failure of parsing a textfsm template.
var ErrFailedParsingTemplate = errors.New("failed opening provided path to textfsm template")

// Response response object that gets returned from scrapli send operations.
type Response struct {
	Host               string
	Port               int
	ChannelInput       string
	RawResult          []byte
	Result             string
	StartTime          time.Time
	EndTime            time.Time
	ElapsedTime        float64
	FailedWhenContains []string
	Failed             bool
}

// NewResponse create a new response object.
func NewResponse(
	host string,
	port int,
	channelInput string,
	failedWhenContains []string,
) *Response {
	r := &Response{
		Host:               host,
		Port:               port,
		ChannelInput:       channelInput,
		RawResult:          nil,
		Result:             "",
		StartTime:          time.Now(),
		EndTime:            time.Time{},
		ElapsedTime:        0,
		Failed:             true,
		FailedWhenContains: failedWhenContains,
	}

	return r
}

// Record records a response from an operation.
func (r *Response) Record(rawResult []byte, result string) {
	r.EndTime = time.Now()
	r.ElapsedTime = r.EndTime.Sub(r.StartTime).Seconds()

	r.RawResult = rawResult
	r.Result = result

	// at this point the command has completed, so only thing that can "fail" it is there being
	// some bad output in the string matching a FailedWhenContains substr
	r.Failed = false

	for _, failedStr := range r.FailedWhenContains {
		if strings.Contains(r.Result, failedStr) {
			r.Failed = true
			break
		}
	}
}

// TextFsmParse parses recorded output w/ a provided textfsm template.
func (r *Response) TextFsmParse(template string) ([]map[string]interface{}, error) {
	t, err := os.ReadFile(template)
	if err != nil {
		logging.LogError(
			r.FormatLogMessage(
				"error",
				fmt.Sprintf("Failed opening provided template, error: %s\n", err.Error()),
			),
		)

		return []map[string]interface{}{}, ErrFailedOpeningTemplate
	}

	fsm := gotextfsm.TextFSM{}

	err = fsm.ParseString(string(t))
	if err != nil {
		logging.LogError(
			r.FormatLogMessage(
				"error",
				fmt.Sprintf("Failed parsing provided template, gotextfsm error: %s\n", err.Error()),
			),
		)

		return []map[string]interface{}{}, ErrFailedParsingTemplate
	}

	parser := gotextfsm.ParserOutput{}

	err = parser.ParseTextString(r.Result, fsm, true)
	if err != nil {
		logging.LogError(
			r.FormatLogMessage(
				"error",
				fmt.Sprintf(
					"Error while parsing device output, gotextfsm error: %s\n",
					err.Error(),
				),
			),
		)

		return []map[string]interface{}{}, err
	}

	return parser.Dict, nil
}

// FormatLogMessage formats log message payload, adding contextual info about the host.
func (r *Response) FormatLogMessage(level, msg string) string {
	return logging.FormatLogMessage(level, r.Host, r.Port, msg)
}
<commit_msg>fix error text<commit_after>package base

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/scrapli/scrapligo/logging"
	"github.com/sirikothe/gotextfsm"
)

// ErrFailedOpeningTemplate error for failure to open a textfsm template.
var ErrFailedOpeningTemplate = errors.New("failed opening provided path to textfsm template")

// ErrFailedParsingTemplate error for failure of parsing a textfsm template.
var ErrFailedParsingTemplate = errors.New("failed parsing textfsm template")

// Response response object that gets returned from scrapli send operations.
type Response struct {
	Host               string
	Port               int
	ChannelInput       string
	RawResult          []byte
	Result             string
	StartTime          time.Time
	EndTime            time.Time
	ElapsedTime        float64
	FailedWhenContains []string
	Failed             bool
}

// NewResponse create a new response object.
func NewResponse(
	host string,
	port int,
	channelInput string,
	failedWhenContains []string,
) *Response {
	r := &Response{
		Host:               host,
		Port:               port,
		ChannelInput:       channelInput,
		RawResult:          nil,
		Result:             "",
		StartTime:          time.Now(),
		EndTime:            time.Time{},
		ElapsedTime:        0,
		Failed:             true,
		FailedWhenContains: failedWhenContains,
	}

	return r
}

// Record records a response from an operation.
func (r *Response) Record(rawResult []byte, result string) {
	r.EndTime = time.Now()
	r.ElapsedTime = r.EndTime.Sub(r.StartTime).Seconds()

	r.RawResult = rawResult
	r.Result = result

	// at this point the command has completed, so only thing that can "fail" it is there being
	// some bad output in the string matching a FailedWhenContains substr
	r.Failed = false

	for _, failedStr := range r.FailedWhenContains {
		if strings.Contains(r.Result, failedStr) {
			r.Failed = true
			break
		}
	}
}

// TextFsmParse parses recorded output w/ a provided textfsm template.
func (r *Response) TextFsmParse(template string) ([]map[string]interface{}, error) {
	t, err := os.ReadFile(template)
	if err != nil {
		logging.LogError(
			r.FormatLogMessage(
				"error",
				fmt.Sprintf("Failed opening provided template, error: %s\n", err.Error()),
			),
		)

		return []map[string]interface{}{}, ErrFailedOpeningTemplate
	}

	fsm := gotextfsm.TextFSM{}

	err = fsm.ParseString(string(t))
	if err != nil {
		logging.LogError(
			r.FormatLogMessage(
				"error",
				fmt.Sprintf("Failed parsing provided template, gotextfsm error: %s\n", err.Error()),
			),
		)

		return []map[string]interface{}{}, ErrFailedParsingTemplate
	}

	parser := gotextfsm.ParserOutput{}

	err = parser.ParseTextString(r.Result, fsm, true)
	if err != nil {
		logging.LogError(
			r.FormatLogMessage(
				"error",
				fmt.Sprintf(
					"Error while parsing device output, gotextfsm error: %s\n",
					err.Error(),
				),
			),
		)

		return []map[string]interface{}{}, err
	}

	return parser.Dict, nil
}

// FormatLogMessage formats log message payload, adding contextual info about the host.
func (r *Response) FormatLogMessage(level, msg string) string {
	return logging.FormatLogMessage(level, r.Host, r.Port, msg)
}
<|endoftext|>


<commit_before>package trust

import (
	"bytes"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/trust"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/theupdateframework/notary"
	"github.com/theupdateframework/notary/storage"
	"github.com/theupdateframework/notary/trustmanager"
	tufutils "github.com/theupdateframework/notary/tuf/utils"
)

const (
	nonOwnerReadWriteMask = 0077
)

type keyLoadOptions struct {
	keyName string
}

func newKeyLoadCommand(dockerCli command.Streams) *cobra.Command {
	var options keyLoadOptions
	cmd := &cobra.Command{
		Use:   "load [OPTIONS] KEYFILE",
		Short: "Load a private key file for signing",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return loadPrivKey(dockerCli, args[0], options)
		},
	}
	flags := cmd.Flags()
	flags.StringVar(&options.keyName, "name", "signer", "Name for the loaded key")
	return cmd
}

func loadPrivKey(streams command.Streams, keyPath string, options keyLoadOptions) error {
	// validate the key name if provided
	if options.keyName != "" && !validKeyName(options.keyName) {
		return fmt.Errorf("key name \"%s\" must start with lowercase alphanumeric characters and can include \"-\" or \"_\" after the first character", options.keyName)
	}
	trustDir := trust.GetTrustDirectory()
	keyFileStore, err := storage.NewPrivateKeyFileStorage(trustDir, notary.KeyExtension)
	if err != nil {
		return err
	}
	privKeyImporters := []trustmanager.Importer{keyFileStore}

	fmt.Fprintf(streams.Out(), "Loading key from \"%s\"...\n", keyPath)

	// Always use a fresh passphrase retriever for each import
	passRet := trust.GetPassphraseRetriever(streams.In(), streams.Out())
	keyBytes, err := getPrivKeyBytesFromPath(keyPath)
	if err != nil {
		return errors.Wrapf(err, "refusing to load key from %s", keyPath)
	}
	if err := loadPrivKeyBytesToStore(keyBytes, privKeyImporters, keyPath, options.keyName, passRet); err != nil {
		return errors.Wrapf(err, "error importing key from %s", keyPath)
	}
	fmt.Fprintf(streams.Out(), "Successfully imported key from %s\n", keyPath)
	return nil
}

func getPrivKeyBytesFromPath(keyPath string) ([]byte, error) {
	fileInfo, err := os.Stat(keyPath)
	if err != nil {
		return nil, err
	}
	if fileInfo.Mode()&nonOwnerReadWriteMask != 0 {
		return nil, fmt.Errorf("private key file %s must not be readable or writable by others", keyPath)
	}

	from, err := os.OpenFile(keyPath, os.O_RDONLY, notary.PrivExecPerms)
	if err != nil {
		return nil, err
	}
	defer from.Close()

	return ioutil.ReadAll(from)
}

func loadPrivKeyBytesToStore(privKeyBytes []byte, privKeyImporters []trustmanager.Importer, keyPath, keyName string, passRet notary.PassRetriever) error {
	var err error
	if _, _, err = tufutils.ExtractPrivateKeyAttributes(privKeyBytes); err != nil {
		return fmt.Errorf("provided file %s is not a supported private key - to add a signer's public key use docker trust signer add", keyPath)
	}
	if privKeyBytes, err = decodePrivKeyIfNecessary(privKeyBytes, passRet); err != nil {
		return errors.Wrapf(err, "cannot load key from provided file %s", keyPath)
	}
	// Make a reader, rewind the file pointer
	return trustmanager.ImportKeys(bytes.NewReader(privKeyBytes), privKeyImporters, keyName, "", passRet)
}

func decodePrivKeyIfNecessary(privPemBytes []byte, passRet notary.PassRetriever) ([]byte, error) {
	pemBlock, _ := pem.Decode(privPemBytes)
	_, containsDEKInfo := pemBlock.Headers["DEK-Info"]
	if containsDEKInfo || pemBlock.Type == "ENCRYPTED PRIVATE KEY" {
		// if we do not have enough information to properly import, try to decrypt the key
		if _, ok := pemBlock.Headers["path"]; !ok {
			privKey, _, err := trustmanager.GetPasswdDecryptBytes(passRet, privPemBytes, "", "encrypted")
			if err != nil {
				return []byte{}, fmt.Errorf("could not decrypt key")
			}
			privPemBytes = privKey.Private()
		}
	}
	return privPemBytes, nil
}
<commit_msg>Windows: skip permissions check on key<commit_after>package trust

import (
	"bytes"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/trust"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/theupdateframework/notary"
	"github.com/theupdateframework/notary/storage"
	"github.com/theupdateframework/notary/trustmanager"
	tufutils "github.com/theupdateframework/notary/tuf/utils"
)

const (
	nonOwnerReadWriteMask = 0077
)

type keyLoadOptions struct {
	keyName string
}

func newKeyLoadCommand(dockerCli command.Streams) *cobra.Command {
	var options keyLoadOptions
	cmd := &cobra.Command{
		Use:   "load [OPTIONS] KEYFILE",
		Short: "Load a private key file for signing",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return loadPrivKey(dockerCli, args[0], options)
		},
	}
	flags := cmd.Flags()
	flags.StringVar(&options.keyName, "name", "signer", "Name for the loaded key")
	return cmd
}

func loadPrivKey(streams command.Streams, keyPath string, options keyLoadOptions) error {
	// validate the key name if provided
	if options.keyName != "" && !validKeyName(options.keyName) {
		return fmt.Errorf("key name \"%s\" must start with lowercase alphanumeric characters and can include \"-\" or \"_\" after the first character", options.keyName)
	}
	trustDir := trust.GetTrustDirectory()
	keyFileStore, err := storage.NewPrivateKeyFileStorage(trustDir, notary.KeyExtension)
	if err != nil {
		return err
	}
	privKeyImporters := []trustmanager.Importer{keyFileStore}

	fmt.Fprintf(streams.Out(), "Loading key from \"%s\"...\n", keyPath)

	// Always use a fresh passphrase retriever for each import
	passRet := trust.GetPassphraseRetriever(streams.In(), streams.Out())
	keyBytes, err := getPrivKeyBytesFromPath(keyPath)
	if err != nil {
		return errors.Wrapf(err, "refusing to load key from %s", keyPath)
	}
	if err := loadPrivKeyBytesToStore(keyBytes, privKeyImporters, keyPath, options.keyName, passRet); err != nil {
		return errors.Wrapf(err, "error importing key from %s", keyPath)
	}
	fmt.Fprintf(streams.Out(), "Successfully imported key from %s\n", keyPath)
	return nil
}

func getPrivKeyBytesFromPath(keyPath string) ([]byte, error) {
	if runtime.GOOS != "windows" {
		fileInfo, err := os.Stat(keyPath)
		if err != nil {
			return nil, err
		}
		if fileInfo.Mode()&nonOwnerReadWriteMask != 0 {
			return nil, fmt.Errorf("private key file %s must not be readable or writable by others", keyPath)
		}
	}

	from, err := os.OpenFile(keyPath, os.O_RDONLY, notary.PrivExecPerms)
	if err != nil {
		return nil, err
	}
	defer from.Close()

	return ioutil.ReadAll(from)
}

func loadPrivKeyBytesToStore(privKeyBytes []byte, privKeyImporters []trustmanager.Importer, keyPath, keyName string, passRet notary.PassRetriever) error {
	var err error
	if _, _, err = tufutils.ExtractPrivateKeyAttributes(privKeyBytes); err != nil {
		return fmt.Errorf("provided file %s is not a supported private key - to add a signer's public key use docker trust signer add", keyPath)
	}
	if privKeyBytes, err = decodePrivKeyIfNecessary(privKeyBytes, passRet); err != nil {
		return errors.Wrapf(err, "cannot load key from provided file %s", keyPath)
	}
	// Make a reader, rewind the file pointer
	return trustmanager.ImportKeys(bytes.NewReader(privKeyBytes), privKeyImporters, keyName, "", passRet)
}

func decodePrivKeyIfNecessary(privPemBytes []byte, passRet notary.PassRetriever) ([]byte, error) {
	pemBlock, _ := pem.Decode(privPemBytes)
	_, containsDEKInfo := pemBlock.Headers["DEK-Info"]
	if containsDEKInfo || pemBlock.Type == "ENCRYPTED PRIVATE KEY" {
		// if we do not have enough information to properly import, try to decrypt the key
		if _, ok := pemBlock.Headers["path"]; !ok {
			privKey, _, err := trustmanager.GetPasswdDecryptBytes(passRet, privPemBytes, "", "encrypted")
			if err != nil {
				return []byte{}, fmt.Errorf("could not decrypt key")
			}
			privPemBytes = privKey.Private()
		}
	}
	return privPemBytes, nil
}
<|endoftext|>


<commit_before>package client

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	manifesttypes "github.com/docker/cli/cli/manifest/types"
	"github.com/docker/cli/cli/trust"
	"github.com/docker/distribution"
	"github.com/docker/distribution/reference"
	distributionclient "github.com/docker/distribution/registry/client"
	"github.com/docker/docker/api/types"
	registrytypes "github.com/docker/docker/api/types/registry"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// RegistryClient is a client used to communicate with a Docker distribution
// registry
type RegistryClient interface {
	GetManifest(ctx context.Context, ref reference.Named) (manifesttypes.ImageManifest, error)
	GetManifestList(ctx context.Context, ref reference.Named) ([]manifesttypes.ImageManifest, error)
	MountBlob(ctx context.Context, source reference.Canonical, target reference.Named) error
	PutManifest(ctx context.Context, ref reference.Named, manifest distribution.Manifest) (digest.Digest, error)
	GetTags(ctx context.Context, ref reference.Named) ([]string, error)
}

// NewRegistryClient returns a new RegistryClient with a resolver
func NewRegistryClient(resolver AuthConfigResolver, userAgent string, insecure bool) RegistryClient {
	return &client{
		authConfigResolver: resolver,
		insecureRegistry:   insecure,
		userAgent:          userAgent,
	}
}

// AuthConfigResolver returns Auth Configuration for an index
type AuthConfigResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig

// PutManifestOptions is the data sent to push a manifest
type PutManifestOptions struct {
	MediaType string
	Payload   []byte
}

type client struct {
	authConfigResolver AuthConfigResolver
	insecureRegistry   bool
	userAgent          string
}

// ErrBlobCreated returned when a blob mount request was created
type ErrBlobCreated struct {
	From   reference.Named
	Target reference.Named
}

func (err ErrBlobCreated) Error() string {
	return fmt.Sprintf("blob mounted from: %v to: %v",
		err.From, err.Target)
}

// ErrHTTPProto returned if attempting to use TLS with a non-TLS registry
type ErrHTTPProto struct {
	OrigErr string
}

func (err ErrHTTPProto) Error() string {
	return err.OrigErr
}

var _ RegistryClient = &client{}

// MountBlob into the registry, so it can be referenced by a manifest
func (c *client) MountBlob(ctx context.Context, sourceRef reference.Canonical, targetRef reference.Named) error {
	repoEndpoint, err := newDefaultRepositoryEndpoint(targetRef, c.insecureRegistry)
	if err != nil {
		return err
	}
	repo, err := c.getRepositoryForReference(ctx, targetRef, repoEndpoint)
	if err != nil {
		return err
	}
	lu, err := repo.Blobs(ctx).Create(ctx, distributionclient.WithMountFrom(sourceRef))
	switch err.(type) {
	case distribution.ErrBlobMounted:
		logrus.Debugf("mount of blob %s succeeded", sourceRef)
		return nil
	case nil:
	default:
		return errors.Wrapf(err, "failed to mount blob %s to %s", sourceRef, targetRef)
	}
	lu.Cancel(ctx)
	logrus.Debugf("mount of blob %s created", sourceRef)
	return ErrBlobCreated{From: sourceRef, Target: targetRef}
}

// PutManifest sends the manifest to a registry and returns the new digest
func (c *client) PutManifest(ctx context.Context, ref reference.Named, manifest distribution.Manifest) (digest.Digest, error) {
	repoEndpoint, err := newDefaultRepositoryEndpoint(ref, c.insecureRegistry)
	if err != nil {
		return digest.Digest(""), err
	}

	repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
	if err != nil {
		return digest.Digest(""), err
	}

	manifestService, err := repo.Manifests(ctx)
	if err != nil {
		return digest.Digest(""), err
	}

	_, opts, err := getManifestOptionsFromReference(ref)
	if err != nil {
		return digest.Digest(""), err
	}

	dgst, err := manifestService.Put(ctx, manifest, opts...)
	return dgst, errors.Wrapf(err, "failed to put manifest %s", ref)
}

func (c *client) GetTags(ctx context.Context, ref reference.Named) ([]string, error) {
	repoEndpoint, err := newDefaultRepositoryEndpoint(ref, c.insecureRegistry)
	if err != nil {
		return nil, err
	}

	repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
	if err != nil {
		return nil, err
	}
	return repo.Tags(ctx).All(ctx)
}

func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Named, repoEndpoint repositoryEndpoint) (distribution.Repository, error) {
	repoName, err := reference.WithName(repoEndpoint.Name())
	if err != nil {
		return nil, errors.Wrapf(err, "failed to parse repo name from %s", ref)
	}
	httpTransport, err := c.getHTTPTransportForRepoEndpoint(ctx, repoEndpoint)
	if err != nil {
		if !strings.Contains(err.Error(), "server gave HTTP response to HTTPS client") {
			return nil, err
		}
		if !repoEndpoint.endpoint.TLSConfig.InsecureSkipVerify {
			return nil, ErrHTTPProto{OrigErr: err.Error()}
		}
		// --insecure was set; fall back to plain HTTP
		if url := repoEndpoint.endpoint.URL; url != nil && url.Scheme == "https" {
			url.Scheme = "http"
			httpTransport, err = c.getHTTPTransportForRepoEndpoint(ctx, repoEndpoint)
			if err != nil {
				return nil, err
			}
		}
	}
	return distributionclient.NewRepository(repoName, repoEndpoint.BaseURL(), httpTransport)
}

func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoint repositoryEndpoint) (http.RoundTripper, error) {
	httpTransport, err := getHTTPTransport(
		c.authConfigResolver(ctx, repoEndpoint.info.Index),
		repoEndpoint.endpoint,
		repoEndpoint.Name(),
		c.userAgent)
	return httpTransport, errors.Wrap(err, "failed to configure transport")
}

// GetManifest returns an ImageManifest for the reference
func (c *client) GetManifest(ctx context.Context, ref reference.Named) (manifesttypes.ImageManifest, error) {
	var result manifesttypes.ImageManifest
	fetch := func(ctx context.Context, repo distribution.Repository, ref reference.Named) (bool, error) {
		var err error
		result, err = fetchManifest(ctx, repo, ref)
		return result.Ref != nil, err
	}

	err := c.iterateEndpoints(ctx, ref, fetch)
	return result, err
}

// GetManifestList returns a list of ImageManifest for the reference
func (c *client) GetManifestList(ctx context.Context, ref reference.Named) ([]manifesttypes.ImageManifest, error) {
	result := []manifesttypes.ImageManifest{}
	fetch := func(ctx context.Context, repo distribution.Repository, ref reference.Named) (bool, error) {
		var err error
		result, err = fetchList(ctx, repo, ref)
		return len(result) > 0, err
	}

	err := c.iterateEndpoints(ctx, ref, fetch)
	return result, err
}

func getManifestOptionsFromReference(ref reference.Named) (digest.Digest, []distribution.ManifestServiceOption, error) {
	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
		tag := tagged.Tag()
		return "", []distribution.ManifestServiceOption{distribution.WithTag(tag)}, nil
	}
	if digested, isDigested := ref.(reference.Canonical); isDigested {
		return digested.Digest(), []distribution.ManifestServiceOption{}, nil
	}
	return "", nil, errors.Errorf("%s no tag or digest", ref)
}

// GetRegistryAuth returns the auth config given an input image
func GetRegistryAuth(ctx context.Context, resolver AuthConfigResolver, imageName string) (*types.AuthConfig, error) {
	distributionRef, err := reference.ParseNormalizedNamed(imageName)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse image name: %s: %s", imageName, err)
	}
	imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, resolver, distributionRef.String())
	if err != nil {
		return nil, fmt.Errorf("Failed to get imgRefAndAuth: %s", err)
	}
	return imgRefAndAuth.AuthConfig(), nil
}
<commit_msg>cli/registry/client: remove unused GetRegistryAuth()<commit_after>package client

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	manifesttypes "github.com/docker/cli/cli/manifest/types"
	"github.com/docker/distribution"
	"github.com/docker/distribution/reference"
	distributionclient "github.com/docker/distribution/registry/client"
	"github.com/docker/docker/api/types"
	registrytypes "github.com/docker/docker/api/types/registry"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// RegistryClient is a client used to communicate with a Docker distribution
// registry
type RegistryClient interface {
	GetManifest(ctx context.Context, ref reference.Named) (manifesttypes.ImageManifest, error)
	GetManifestList(ctx context.Context, ref reference.Named) ([]manifesttypes.ImageManifest, error)
	MountBlob(ctx context.Context, source reference.Canonical, target reference.Named) error
	PutManifest(ctx context.Context, ref reference.Named, manifest distribution.Manifest) (digest.Digest, error)
	GetTags(ctx context.Context, ref reference.Named) ([]string, error)
}

// NewRegistryClient returns a new RegistryClient with a resolver
func NewRegistryClient(resolver AuthConfigResolver, userAgent string, insecure bool) RegistryClient {
	return &client{
		authConfigResolver: resolver,
		insecureRegistry:   insecure,
		userAgent:          userAgent,
	}
}

// AuthConfigResolver returns Auth Configuration for an index
type AuthConfigResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig

// PutManifestOptions is the data sent to push a manifest
type PutManifestOptions struct {
	MediaType string
	Payload   []byte
}

type client struct {
	authConfigResolver AuthConfigResolver
	insecureRegistry   bool
	userAgent          string
}

// ErrBlobCreated returned when a blob mount request was created
type ErrBlobCreated struct {
	From   reference.Named
	Target reference.Named
}

func (err ErrBlobCreated) Error() string {
	return fmt.Sprintf("blob mounted from: %v to: %v",
		err.From, err.Target)
}

// ErrHTTPProto returned if attempting to use TLS with a non-TLS registry
type ErrHTTPProto struct {
	OrigErr string
}

func (err ErrHTTPProto) Error() string {
	return err.OrigErr
}

var _ RegistryClient = &client{}

// MountBlob into the registry, so it can be referenced by a manifest
func (c *client) MountBlob(ctx context.Context, sourceRef reference.Canonical, targetRef reference.Named) error {
	repoEndpoint, err := newDefaultRepositoryEndpoint(targetRef, c.insecureRegistry)
	if err != nil {
		return err
	}
	repo, err := c.getRepositoryForReference(ctx, targetRef, repoEndpoint)
	if err != nil {
		return err
	}
	lu, err := repo.Blobs(ctx).Create(ctx, distributionclient.WithMountFrom(sourceRef))
	switch err.(type) {
	case distribution.ErrBlobMounted:
		logrus.Debugf("mount of blob %s succeeded", sourceRef)
		return nil
	case nil:
	default:
		return errors.Wrapf(err, "failed to mount blob %s to %s", sourceRef, targetRef)
	}
	lu.Cancel(ctx)
	logrus.Debugf("mount of blob %s created", sourceRef)
	return ErrBlobCreated{From: sourceRef, Target: targetRef}
}

// PutManifest sends the manifest to a registry and returns the new digest
func (c *client) PutManifest(ctx context.Context, ref reference.Named, manifest distribution.Manifest) (digest.Digest, error) {
	repoEndpoint, err := newDefaultRepositoryEndpoint(ref, c.insecureRegistry)
	if err != nil {
		return digest.Digest(""), err
	}

	repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
	if err != nil {
		return digest.Digest(""), err
	}

	manifestService, err := repo.Manifests(ctx)
	if err != nil {
		return digest.Digest(""), err
	}

	_, opts, err := getManifestOptionsFromReference(ref)
	if err != nil {
		return digest.Digest(""), err
	}

	dgst, err := manifestService.Put(ctx, manifest, opts...)
	return dgst, errors.Wrapf(err, "failed to put manifest %s", ref)
}

func (c *client) GetTags(ctx context.Context, ref reference.Named) ([]string, error) {
	repoEndpoint, err := newDefaultRepositoryEndpoint(ref, c.insecureRegistry)
	if err != nil {
		return nil, err
	}

	repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
	if err != nil {
		return nil, err
	}
	return repo.Tags(ctx).All(ctx)
}

func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Named, repoEndpoint repositoryEndpoint) (distribution.Repository, error) {
	repoName, err := reference.WithName(repoEndpoint.Name())
	if err != nil {
		return nil, errors.Wrapf(err, "failed to parse repo name from %s", ref)
	}
	httpTransport, err := c.getHTTPTransportForRepoEndpoint(ctx, repoEndpoint)
	if err != nil {
		if !strings.Contains(err.Error(), "server gave HTTP response to HTTPS client") {
			return nil, err
		}
		if !repoEndpoint.endpoint.TLSConfig.InsecureSkipVerify {
			return nil, ErrHTTPProto{OrigErr: err.Error()}
		}
		// --insecure was set; fall back to plain HTTP
		if url := repoEndpoint.endpoint.URL; url != nil && url.Scheme == "https" {
			url.Scheme = "http"
			httpTransport, err = c.getHTTPTransportForRepoEndpoint(ctx, repoEndpoint)
			if err != nil {
				return nil, err
			}
		}
	}
	return distributionclient.NewRepository(repoName, repoEndpoint.BaseURL(), httpTransport)
}

func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoint repositoryEndpoint) (http.RoundTripper, error) {
	httpTransport, err := getHTTPTransport(
		c.authConfigResolver(ctx, repoEndpoint.info.Index),
		repoEndpoint.endpoint,
		repoEndpoint.Name(),
		c.userAgent)
	return httpTransport, errors.Wrap(err, "failed to configure transport")
}

// GetManifest returns an ImageManifest for the reference
func (c *client) GetManifest(ctx context.Context, ref reference.Named) (manifesttypes.ImageManifest, error) {
	var result manifesttypes.ImageManifest
	fetch := func(ctx context.Context, repo distribution.Repository, ref reference.Named) (bool, error) {
		var err error
		result, err = fetchManifest(ctx, repo, ref)
		return result.Ref != nil, err
	}

	err := c.iterateEndpoints(ctx, ref, fetch)
	return result, err
}

// GetManifestList returns a list of ImageManifest for the reference
func (c *client) GetManifestList(ctx context.Context, ref reference.Named) ([]manifesttypes.ImageManifest, error) {
	result := []manifesttypes.ImageManifest{}
	fetch := func(ctx context.Context, repo distribution.Repository, ref reference.Named) (bool, error) {
		var err error
		result, err = fetchList(ctx, repo, ref)
		return len(result) > 0, err
	}

	err := c.iterateEndpoints(ctx, ref, fetch)
	return result, err
}

func getManifestOptionsFromReference(ref reference.Named) (digest.Digest, []distribution.ManifestServiceOption, error) {
	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
		tag := tagged.Tag()
		return "", []distribution.ManifestServiceOption{distribution.WithTag(tag)}, nil
	}
	if digested, isDigested := ref.(reference.Canonical); isDigested {
		return digested.Digest(), []distribution.ManifestServiceOption{}, nil
	}
	return "", nil, errors.Errorf("%s no tag or digest", ref)
}
<|endoftext|>


<commit_before>package radix

import (
	"fmt"
	"net"
	"sync"
	"time"
)

type sentinelOpts struct {
	cf ConnFunc
	pf ClientFunc
}

// SentinelOpt is an optional behavior which can be applied to the NewSentinel
// function to effect a Sentinel's behavior.
type SentinelOpt func(*sentinelOpts)

// SentinelConnFunc tells the Sentinel to use the given ConnFunc when connecting
// to sentinel instances.
func SentinelConnFunc(cf ConnFunc) SentinelOpt {
	return func(so *sentinelOpts) {
		so.cf = cf
	}
}

// SentinelPoolFunc tells the Sentinel to use the given ClientFunc when creating
// a pool of connections to the sentinel's primary.
func SentinelPoolFunc(pf ClientFunc) SentinelOpt {
	return func(so *sentinelOpts) {
		so.pf = pf
	}
}

// Sentinel is a Client which, in the background, connects to an available
// sentinel node and handles all of the following:
//
// * Creates a pool to the current primary instance, as advertised by the
// sentinel
//
// * Listens for events indicating the primary has changed, and automatically
// creates a new Client to the new primary
//
// * Keeps track of other sentinels in the cluster, and uses them if the
// currently connected one becomes unreachable
//
type Sentinel struct {
	so        sentinelOpts
	initAddrs []string
	name      string

	// we read lock when calling methods on prim, and normal lock when swapping
	// the value of prim, primAddr, and sentAddrs
	l             sync.RWMutex
	primAddr      string
	clients       map[string]Client
	sentinelAddrs map[string]bool // the known sentinel addresses

	// We use a persistent PubSubConn here, so we don't need to do much after
	// initialization. The pconn is only really kept around for closing
	pconn   PubSubConn
	pconnCh chan PubSubMessage

	// Any errors encountered internally will be written to this channel. If
	// nothing is reading the channel the errors will be dropped. The channel
	// will be closed when the Close is called.
	ErrCh chan error

	closeCh   chan bool
	closeWG   sync.WaitGroup
	closeOnce sync.Once

	// only used by tests to ensure certain actions have happened before
	// continuing on during the test
	testEventCh chan string
}

// NewSentinel creates and returns a *Sentinel instance. NewSentinel takes in a
// number of options which can overwrite its default behavior. The default
// options NewSentinel uses are:
//
//	SentinelConnFunc(DefaultConnFunc)
//	SentinelPoolFunc(DefaultClientFunc)
//
func NewSentinel(primaryName string, sentinelAddrs []string, opts ...SentinelOpt) (*Sentinel, error) {
	addrs := map[string]bool{}
	for _, addr := range sentinelAddrs {
		addrs[addr] = true
	}

	sc := &Sentinel{
		initAddrs:     sentinelAddrs,
		name:          primaryName,
		sentinelAddrs: addrs,
		pconnCh:       make(chan PubSubMessage, 1),
		ErrCh:         make(chan error, 1),
		closeCh:       make(chan bool),
		testEventCh:   make(chan string, 1),
	}

	defaultSentinelOpts := []SentinelOpt{
		SentinelConnFunc(DefaultConnFunc),
		SentinelPoolFunc(DefaultClientFunc),
	}

	for _, opt := range append(defaultSentinelOpts, opts...) {
		// the other args to NewSentinel used to be a ConnFunc and a ClientFunc,
		// which someone might have left as nil, in which case this now gives a
		// weird panic. Just handle it
		if opt != nil {
			opt(&(sc.so))
		}
	}

	// first thing is to retrieve the state and create a pool using the first
	// connectable connection. This connection is only used during
	// initialization, it gets closed right after
	{
		conn, err := sc.dialSentinel()
		if err != nil {
			return nil, err
		}
		defer conn.Close()

		if err := sc.ensureSentinelAddrs(conn); err != nil {
			return nil, err
		} else if err := sc.ensureClients(conn); err != nil {
			return nil, err
		}
	}

	// because we're using persistent these can't _really_ fail
	sc.pconn = PersistentPubSub("", "", func(_, _ string) (Conn, error) {
		return sc.dialSentinel()
	})
	sc.pconn.Subscribe(sc.pconnCh, "switch-master")

	sc.closeWG.Add(1)
	go sc.spin()
	return sc, nil
}

func (sc *Sentinel) err(err error) {
	select {
	case sc.ErrCh <- err:
	default:
	}
}

func (sc *Sentinel) testEvent(event string) {
	select {
	case sc.testEventCh <- event:
	default:
	}
}

func (sc *Sentinel) dialSentinel() (Conn, error) {
	sc.l.RLock()
	defer sc.l.RUnlock()

	var conn Conn
	var err error
	for addr := range sc.sentinelAddrs {
		conn, err = sc.so.cf("tcp", addr)
		if err == nil {
			return conn, nil
		}
	}

	// try the initAddrs as a last ditch, but don't return their error if this
	// doesn't work
	for _, addr := range sc.initAddrs {
		if conn, err := sc.so.cf("tcp", addr); err == nil {
			return conn, nil
		}
	}

	return nil, err
}

// Do implements the method for the Client interface. It will pass the given
// action on to the current primary.
//
// NOTE it's possible that in between Do being called and the Action being
// actually carried out that there could be a failover event. In that case, the
// Action will likely fail and return an error.
func (sc *Sentinel) Do(a Action) error {
	sc.l.RLock()
	defer sc.l.RUnlock()
	return sc.clients[sc.primAddr].Do(a)
}

// Addrs returns the currently known network address of the current primary
// instance and the addresses of the secondaries.
func (sc *Sentinel) Addrs() (string, []string) {
	sc.l.RLock()
	defer sc.l.RUnlock()
	secAddrs := make([]string, 0, len(sc.clients))
	for addr := range sc.clients {
		if addr == sc.primAddr {
			continue
		}
		secAddrs = append(secAddrs, addr)
	}
	return sc.primAddr, secAddrs
}

// SentinelAddrs returns the currently known network address of sentinels
func (sc *Sentinel) SentinelAddrs() []string {
	sc.l.RLock()
	defer sc.l.RUnlock()

	sentAddrs := make([]string, 0, len(sc.sentinelAddrs))
	for addr := range sc.sentinelAddrs {
		sentAddrs = append(sentAddrs, addr)
	}
	return sentAddrs
}

// Client returns a Client for the given address, which could be either the
// primary or one of the secondaries (see Addrs method for retrieving known
// addresses).
//
// NOTE that if there is a failover while a Client returned by this method is
// being used the Client may or may not continue to work as expected, depending
// on the nature of the failover.
//
// NOTE the Client should _not_ be closed.
func (sc *Sentinel) Client(addr string) (Client, error) {
	sc.l.RLock()
	client, ok := sc.clients[addr]
	sc.l.RUnlock()

	if client != nil {
		return client, nil
	} else if !ok {
		return nil, errUnknownAddress
	}

	// if client was nil but ok was true it means the address is a secondary but
	// a Client for it has never been created. Create one now and store it into
	// clients.
	newClient, err := sc.so.pf("tcp", addr)
	if err != nil {
		return nil, err
	}

	// two routines might be requesting the same addr at the same time, and
	// both create the client. The second one needs to make sure it closes its
	// own pool when it sees the other got there first.
	sc.l.Lock()
	if client = sc.clients[addr]; client == nil {
		sc.clients[addr] = newClient
	}
	sc.l.Unlock()

	if client != nil {
		newClient.Close()
		return client, nil
	}

	return newClient, nil
}

// Close implements the method for the Client interface.
func (sc *Sentinel) Close() error {
	sc.l.Lock()
	defer sc.l.Unlock()
	closeErr := errClientClosed
	sc.closeOnce.Do(func() {
		close(sc.closeCh)
		sc.closeWG.Wait()
		closeErr = nil
		for _, client := range sc.clients {
			if client != nil {
				client.Close()
			}
		}
	})
	return closeErr
}

// cmd should be the command called which generated m
func sentinelMtoAddr(m map[string]string, cmd string) (string, error) {
	if m["ip"] == "" || m["port"] == "" {
		return "", fmt.Errorf("malformed %s response", cmd)
	}
	return net.JoinHostPort(m["ip"], m["port"]), nil
}

// given a connection to a sentinel, ensures that the Clients currently being
// held agrees with what the sentinel thinks they should be
func (sc *Sentinel) ensureClients(conn Conn) error {
	var primM map[string]string
	var secMM []map[string]string
	if err := conn.Do(Pipeline(
		Cmd(&primM, "SENTINEL", "MASTER", sc.name),
		Cmd(&secMM, "SENTINEL", "SLAVES", sc.name),
	)); err != nil {
		return err
	}

	newPrimAddr, err := sentinelMtoAddr(primM, "SENTINEL MASTER")
	if err != nil {
		return err
	}

	newClients := map[string]Client{newPrimAddr: nil}
	for _, secM := range secMM {
		newSecAddr, err := sentinelMtoAddr(secM, "SENTINEL SLAVES")
		if err != nil {
			return err
		}
		newClients[newSecAddr] = nil
	}

	return sc.setClients(newPrimAddr, newClients)
}

// all values of newClients should be nil
func (sc *Sentinel) setClients(newPrimAddr string, newClients map[string]Client) error {
	newClients[newPrimAddr] = nil
	var toClose []Client

	sc.l.RLock()

	// stateChanged may be set to true in other ways later in the method
	stateChanged := sc.primAddr != newPrimAddr

	// for each actual Client instance in sc.client, either move it over to
	// newClients (if the address is shared) or make sure it is closed
	for addr, client := range sc.clients {
		if client == nil {
			// do nothing
		} else if _, ok := newClients[addr]; ok {
			newClients[addr] = client
		} else {
			toClose = append(toClose, client)
		}

		// separately, if the newClients doesn't have address it means the state
		// has changed
		if _, ok := newClients[addr]; !ok {
			stateChanged = true
		}
	}

	// this is only checks if a client was added so we know the replica set
	// state has changed later in the method.
	for addr := range newClients {
		if _, ok := sc.clients[addr]; !ok {
			stateChanged = true
		}
	}

	sc.l.RUnlock()
	if !stateChanged {
		return nil
	}

	// if the primary doesn't have a client created, create it here outside the
	// lock where it won't block everything else
	if newClients[newPrimAddr] == nil {
		var err error
		if newClients[newPrimAddr], err = sc.so.pf("tcp", newPrimAddr); err != nil {
			return err
		}
	}

	sc.l.Lock()
	sc.primAddr = newPrimAddr
	sc.clients = newClients
	sc.l.Unlock()

	for _, client := range toClose {
		client.Close()
	}

	return nil
}

// annoyingly the SENTINEL SENTINELS <name> command doesn't return _this_
// sentinel instance, only the others it knows about for that primary
func (sc *Sentinel) ensureSentinelAddrs(conn Conn) error {
	var mm []map[string]string
	err := conn.Do(Cmd(&mm, "SENTINEL", "SENTINELS", sc.name))
	if err != nil {
		return err
	}

	addrs := map[string]bool{conn.NetConn().RemoteAddr().String(): true}
	for _, m := range mm {
		addrs[net.JoinHostPort(m["ip"], m["port"])] = true
	}

	sc.l.Lock()
	sc.sentinelAddrs = addrs
	sc.l.Unlock()
	return nil
}

func (sc *Sentinel) spin() {
	defer sc.closeWG.Done()
	defer sc.pconn.Close()
	for {
		if err := sc.innerSpin(); err != nil {
			sc.err(err)
			// sleep a second so we don't end up in a tight loop
			time.Sleep(1 * time.Second)
		}
		// This also gets checked within innerSpin to short-circuit that, but
		// we also must check in here to short-circuit this
		select {
		case <-sc.closeCh:
			return
		default:
		}
	}
}

// makes connection to an address in sc.addrs and handles
// the sentinel until that connection goes bad.
//
// Things this handles:
// * Listening for switch-master events (from pconn, which has reconnect logic
//   external to this package)
// * Periodically re-ensuring that the list of sentinel addresses is up-to-date
// * Periodically re-checking the current primary, in case the switch-master was
//   missed somehow
func (sc *Sentinel) innerSpin() error {
	conn, err := sc.dialSentinel()
	if err != nil {
		return err
	}
	defer conn.Close()

	tick := time.NewTicker(5 * time.Second)
	defer tick.Stop()

	var switchMaster bool
	for {
		if err := sc.ensureSentinelAddrs(conn); err != nil {
			return err
		} else if err := sc.ensureClients(conn); err != nil {
			return err
		}
		sc.pconn.Ping()

		// the tests want to know when the client state has been updated due to
		// a switch-master event
		if switchMaster {
			sc.testEvent("switch-master completed")
			switchMaster = false
		}

		select {
		case <-tick.C:
			// loop
		case <-sc.pconnCh:
			switchMaster = true
			// loop
		case <-sc.closeCh:
			return nil
		}
	}
}
<commit_msg>nice comment<commit_after>package radix

import (
	"fmt"
	"net"
	"sync"
	"time"
)

type sentinelOpts struct {
	cf ConnFunc
	pf ClientFunc
}

// SentinelOpt is an optional behavior which can be applied to the NewSentinel
// function to effect a Sentinel's behavior.
type SentinelOpt func(*sentinelOpts)

// SentinelConnFunc tells the Sentinel to use the given ConnFunc when connecting
// to sentinel instances.
func SentinelConnFunc(cf ConnFunc) SentinelOpt {
	return func(so *sentinelOpts) {
		so.cf = cf
	}
}

// SentinelPoolFunc tells the Sentinel to use the given ClientFunc when creating
// a pool of connections to the sentinel's primary.
func SentinelPoolFunc(pf ClientFunc) SentinelOpt {
	return func(so *sentinelOpts) {
		so.pf = pf
	}
}

// Sentinel is a Client which, in the background, connects to an available
// sentinel node and handles all of the following:
//
// * Creates a pool to the current primary instance, as advertised by the
// sentinel
//
// * Listens for events indicating the primary has changed, and automatically
// creates a new Client to the new primary
//
// * Keeps track of other sentinels in the cluster, and uses them if the
// currently connected one becomes unreachable
//
type Sentinel struct {
	so        sentinelOpts
	initAddrs []string
	name      string

	// we read lock when calling methods on prim, and normal lock when swapping
	// the value of prim, primAddr, and sentAddrs
	l             sync.RWMutex
	primAddr      string
	clients       map[string]Client
	sentinelAddrs map[string]bool // the known sentinel addresses

	// We use a persistent PubSubConn here, so we don't need to do much after
	// initialization. The pconn is only really kept around for closing
	pconn   PubSubConn
	pconnCh chan PubSubMessage

	// Any errors encountered internally will be written to this channel. If
	// nothing is reading the channel the errors will be dropped. The channel
	// will be closed when the Close is called.
	ErrCh chan error

	closeCh   chan bool
	closeWG   sync.WaitGroup
	closeOnce sync.Once

	// only used by tests to ensure certain actions have happened before
	// continuing on during the test
	testEventCh chan string
}

// NewSentinel creates and returns a *Sentinel instance. NewSentinel takes in a
// number of options which can overwrite its default behavior. The default
// options NewSentinel uses are:
//
//	SentinelConnFunc(DefaultConnFunc)
//	SentinelPoolFunc(DefaultClientFunc)
//
func NewSentinel(primaryName string, sentinelAddrs []string, opts ...SentinelOpt) (*Sentinel, error) {
	addrs := map[string]bool{}
	for _, addr := range sentinelAddrs {
		addrs[addr] = true
	}

	sc := &Sentinel{
		initAddrs:     sentinelAddrs,
		name:          primaryName,
		sentinelAddrs: addrs,
		pconnCh:       make(chan PubSubMessage, 1),
		ErrCh:         make(chan error, 1),
		closeCh:       make(chan bool),
		testEventCh:   make(chan string, 1),
	}

	defaultSentinelOpts := []SentinelOpt{
		SentinelConnFunc(DefaultConnFunc),
		SentinelPoolFunc(DefaultClientFunc),
	}

	for _, opt := range append(defaultSentinelOpts, opts...) {
		// the other args to NewSentinel used to be a ConnFunc and a ClientFunc,
		// which someone might have left as nil, in which case this now gives a
		// weird panic. Just handle it
		if opt != nil {
			opt(&(sc.so))
		}
	}

	// first thing is to retrieve the state and create a pool using the first
	// connectable connection. This connection is only used during
	// initialization, it gets closed right after
	{
		conn, err := sc.dialSentinel()
		if err != nil {
			return nil, err
		}
		defer conn.Close()

		if err := sc.ensureSentinelAddrs(conn); err != nil {
			return nil, err
		} else if err := sc.ensureClients(conn); err != nil {
			return nil, err
		}
	}

	// because we're using persistent these can't _really_ fail
	sc.pconn = PersistentPubSub("", "", func(_, _ string) (Conn, error) {
		return sc.dialSentinel()
	})
	sc.pconn.Subscribe(sc.pconnCh, "switch-master")

	sc.closeWG.Add(1)
	go sc.spin()
	return sc, nil
}

func (sc *Sentinel) err(err error) {
	select {
	case sc.ErrCh <- err:
	default:
	}
}

func (sc *Sentinel) testEvent(event string) {
	select {
	case sc.testEventCh <- event:
	default:
	}
}

func (sc *Sentinel) dialSentinel() (Conn, error) {
	sc.l.RLock()
	defer sc.l.RUnlock()

	var conn Conn
	var err error
	for addr := range sc.sentinelAddrs {
		conn, err = sc.so.cf("tcp", addr)
		if err == nil {
			return conn, nil
		}
	}

	// try the initAddrs as a last ditch, but don't return their error if this
	// doesn't work
	for _, addr := range sc.initAddrs {
		if conn, err := sc.so.cf("tcp", addr); err == nil {
			return conn, nil
		}
	}

	return nil, err
}

// Do implements the method for the Client interface. It will pass the given
// action on to the current primary.
//
// NOTE it's possible that in between Do being called and the Action being
// actually carried out that there could be a failover event. In that case, the
// Action will likely fail and return an error.
func (sc *Sentinel) Do(a Action) error {
	sc.l.RLock()
	defer sc.l.RUnlock()
	return sc.clients[sc.primAddr].Do(a)
}

// Addrs returns the currently known network address of the current primary
// instance and the addresses of the secondaries.
func (sc *Sentinel) Addrs() (string, []string) {
	sc.l.RLock()
	defer sc.l.RUnlock()
	secAddrs := make([]string, 0, len(sc.clients))
	for addr := range sc.clients {
		if addr == sc.primAddr {
			continue
		}
		secAddrs = append(secAddrs, addr)
	}
	return sc.primAddr, secAddrs
}

// SentinelAddrs returns the addresses of all known sentinels.
func (sc *Sentinel) SentinelAddrs() []string {
	sc.l.RLock()
	defer sc.l.RUnlock()

	sentAddrs := make([]string, 0, len(sc.sentinelAddrs))
	for addr := range sc.sentinelAddrs {
		sentAddrs = append(sentAddrs, addr)
	}
	return sentAddrs
}

// Client returns a Client for the given address, which could be either the
// primary or one of the secondaries (see Addrs method for retrieving known
// addresses).
//
// NOTE that if there is a failover while a Client returned by this method is
// being used the Client may or may not continue to work as expected, depending
// on the nature of the failover.
//
// NOTE the Client should _not_ be closed.
func (sc *Sentinel) Client(addr string) (Client, error) {
	sc.l.RLock()
	client, ok := sc.clients[addr]
	sc.l.RUnlock()

	if client != nil {
		return client, nil
	} else if !ok {
		return nil, errUnknownAddress
	}

	// if client was nil but ok was true it means the address is a secondary but
	// a Client for it has never been created. Create one now and store it into
	// clients.
	newClient, err := sc.so.pf("tcp", addr)
	if err != nil {
		return nil, err
	}

	// two routines might be requesting the same addr at the same time, and
	// both create the client. The second one needs to make sure it closes its
	// own pool when it sees the other got there first.
	sc.l.Lock()
	if client = sc.clients[addr]; client == nil {
		sc.clients[addr] = newClient
	}
	sc.l.Unlock()

	if client != nil {
		newClient.Close()
		return client, nil
	}

	return newClient, nil
}

// Close implements the method for the Client interface.
func (sc *Sentinel) Close() error {
	sc.l.Lock()
	defer sc.l.Unlock()
	closeErr := errClientClosed
	sc.closeOnce.Do(func() {
		close(sc.closeCh)
		sc.closeWG.Wait()
		closeErr = nil
		for _, client := range sc.clients {
			if client != nil {
				client.Close()
			}
		}
	})
	return closeErr
}

// cmd should be the command called which generated m
func sentinelMtoAddr(m map[string]string, cmd string) (string, error) {
	if m["ip"] == "" || m["port"] == "" {
		return "", fmt.Errorf("malformed %s response", cmd)
	}
	return net.JoinHostPort(m["ip"], m["port"]), nil
}

// given a connection to a sentinel, ensures that the Clients currently being
// held agrees with what the sentinel thinks they should be
func (sc *Sentinel) ensureClients(conn Conn) error {
	var primM map[string]string
	var secMM []map[string]string
	if err := conn.Do(Pipeline(
		Cmd(&primM, "SENTINEL", "MASTER", sc.name),
		Cmd(&secMM, "SENTINEL", "SLAVES", sc.name),
	)); err != nil {
		return err
	}

	newPrimAddr, err := sentinelMtoAddr(primM, "SENTINEL MASTER")
	if err != nil {
		return err
	}

	newClients := map[string]Client{newPrimAddr: nil}
	for _, secM := range secMM {
		newSecAddr, err := sentinelMtoAddr(secM, "SENTINEL SLAVES")
		if err != nil {
			return err
		}
		newClients[newSecAddr] = nil
	}

	return sc.setClients(newPrimAddr, newClients)
}

// all values of newClients should be nil
func (sc *Sentinel) setClients(newPrimAddr string, newClients map[string]Client) error {
	newClients[newPrimAddr] = nil
	var toClose []Client

	sc.l.RLock()

	// stateChanged may be set to true in other ways later in the method
	stateChanged := sc.primAddr != newPrimAddr

	// for each actual Client instance in sc.client, either move it over to
	// newClients (if the address is shared) or make sure it is closed
	for addr, client := range sc.clients {
		if client == nil {
			// do nothing
		} else if _, ok := newClients[addr]; ok {
			newClients[addr] = client
		} else {
			toClose = append(toClose, client)
		}

		// separately, if the newClients doesn't have address it means the state
		// has changed
		if _, ok := newClients[addr]; !ok {
			stateChanged = true
		}
	}

	// this is only checks if a client was added so we know the replica set
	// state has changed later in the method.
	for addr := range newClients {
		if _, ok := sc.clients[addr]; !ok {
			stateChanged = true
		}
	}

	sc.l.RUnlock()
	if !stateChanged {
		return nil
	}

	// if the primary doesn't have a client created, create it here outside the
	// lock where it won't block everything else
	if newClients[newPrimAddr] == nil {
		var err error
		if newClients[newPrimAddr], err = sc.so.pf("tcp", newPrimAddr); err != nil {
			return err
		}
	}

	sc.l.Lock()
	sc.primAddr = newPrimAddr
	sc.clients = newClients
	sc.l.Unlock()

	for _, client := range toClose {
		client.Close()
	}

	return nil
}

// annoyingly the SENTINEL SENTINELS <name> command doesn't return _this_
// sentinel instance, only the others it knows about for that primary
func (sc *Sentinel) ensureSentinelAddrs(conn Conn) error {
	var mm []map[string]string
	err := conn.Do(Cmd(&mm, "SENTINEL", "SENTINELS", sc.name))
	if err != nil {
		return err
	}

	addrs := map[string]bool{conn.NetConn().RemoteAddr().String(): true}
	for _, m := range mm {
		addrs[net.JoinHostPort(m["ip"], m["port"])] = true
	}

	sc.l.Lock()
	sc.sentinelAddrs = addrs
	sc.l.Unlock()
	return nil
}

func (sc *Sentinel) spin() {
	defer sc.closeWG.Done()
	defer sc.pconn.Close()
	for {
		if err := sc.innerSpin(); err != nil {
			sc.err(err)
			// sleep a second so we don't end up in a tight loop
			time.Sleep(1 * time.Second)
		}
		// This also gets checked within innerSpin to short-circuit that, but
		// we also must check in here to short-circuit this
		select {
		case <-sc.closeCh:
			return
		default:
		}
	}
}

// makes connection to an address in sc.addrs and handles
// the sentinel until that connection goes bad.
//
// Things this handles:
// * Listening for switch-master events (from pconn, which has reconnect logic
//   external to this package)
// * Periodically re-ensuring that the list of sentinel addresses is up-to-date
// * Periodically re-checking the current primary, in case the switch-master was
//   missed somehow
func (sc *Sentinel) innerSpin() error {
	conn, err := sc.dialSentinel()
	if err != nil {
		return err
	}
	defer conn.Close()

	tick := time.NewTicker(5 * time.Second)
	defer tick.Stop()

	var switchMaster bool
	for {
		if err := sc.ensureSentinelAddrs(conn); err != nil {
			return err
		} else if err := sc.ensureClients(conn); err != nil {
			return err
		}
		sc.pconn.Ping()

		// the tests want to know when the client state has been updated due to
		// a switch-master event
		if switchMaster {
			sc.testEvent("switch-master completed")
			switchMaster = false
		}

		select {
		case <-tick.C:
			// loop
		case <-sc.pconnCh:
			switchMaster = true
			// loop
		case <-sc.closeCh:
			return nil
		}
	}
}
<|endoftext|>


<commit_before>package providers

import (
	"errors"
	"fmt"
	"github.com/bitly/go-simplejson"
	"github.com/bitly/oauth2_proxy/api"
	"log"
	"net/http"
	"net/url"
)

type AzureProvider struct {
	*ProviderData
	Tenant string
}

func NewAzureProvider(p *ProviderData) *AzureProvider {
	p.ProviderName = "Azure"

	if p.ProfileURL == nil || p.ProfileURL.String() == "" {
		p.ProfileURL = &url.URL{
			Scheme:   "https",
			Host:     "idoco360train.api.crm9.dynamics.com/",
			RawQuery: "api-version=1.6",

		}
	}
	if p.ProtectedResource == nil || p.ProtectedResource.String() == "" {
		p.ProtectedResource = &url.URL{
			Scheme: "https",
			Host:   "idoco360train.api.crm9.dynamics.com/",
		}
	}
	if p.Scope == "" {
		p.Scope = "openid"
	}

	return &AzureProvider{ProviderData: p}
}

func (p *AzureProvider) Configure(tenant string) {
	p.Tenant = tenant
	if tenant == "" {
		p.Tenant = "idocO360.onmicrosoft.com"
	}

	if p.LoginURL == nil || p.LoginURL.String() == "" {
		p.LoginURL = &url.URL{
			Scheme: "https",
			Host:   "login.windows.net",
			Path:   "/" + p.Tenant + "/oauth2/authorize"}
	}
	if p.RedeemURL == nil || p.RedeemURL.String() == "" {
		p.RedeemURL = &url.URL{
			Scheme: "https",
			Host:   "login.windows.net",
			Path:   "/" + p.Tenant + "/oauth2/token",
		}
	}
}

func getAzureHeader(access_token string) http.Header {
	header := make(http.Header)
	header.Set("Authorization", fmt.Sprintf("Bearer %s", access_token))
	return header
}

func getEmailFromJSON(json *simplejson.Json) (string, error) {
	var email string
	var err error

	email, err = json.Get("mail").String()

	if err != nil || email == "" {
		otherMails, otherMailsErr := json.Get("otherMails").Array()
		if len(otherMails) > 0 {
			email = otherMails[0].(string)
		}
		err = otherMailsErr
	}

	return email, err
}

func (p *AzureProvider) GetEmailAddress(s *SessionState) (string, error) {
	var email string
	var err error

	if s.AccessToken == "" {
		return "", errors.New("missing access token")
	}
	req, err := http.NewRequest("GET", p.ProfileURL.String(), nil)
	if err != nil {
		return "", err
	}
	req.Header = getAzureHeader(s.AccessToken)

	json, err := api.Request(req)

	if err != nil {
		return "", err
	}

	email, err = getEmailFromJSON(json)

	if err == nil && email != "" {
		return email, err
	}

	email, err = json.Get("userPrincipalName").String()

	if err != nil {
		log.Printf("failed making request %s", err)
		return "", err
	}

	if email == "" {
		log.Printf("failed to get email address")
		return "", err
	}

	return email, err
}
<commit_msg>updated<commit_after>package providers

import (
	"errors"
	"fmt"
	"github.com/bitly/go-simplejson"
	"github.com/bitly/oauth2_proxy/api"
	"log"
	"net/http"
	"net/url"
)

type AzureProvider struct {
	*ProviderData
	Tenant string
}

func NewAzureProvider(p *ProviderData) *AzureProvider {
	p.ProviderName = "Azure"

	if p.ProfileURL == nil || p.ProfileURL.String() == "" {
		p.ProfileURL = &url.URL{
			Scheme:   "https",
			Host:     "idoco360train.api.crm9.dynamics.com",
			RawQuery: "api-version=1.6",

		}
	}
	if p.ProtectedResource == nil || p.ProtectedResource.String() == "" {
		p.ProtectedResource = &url.URL{
			Scheme: "https",
			Host:   "idoco360train.api.crm9.dynamics.com",
		}
	}
	if p.Scope == "" {
		p.Scope = "openid"
	}

	return &AzureProvider{ProviderData: p}
}

func (p *AzureProvider) Configure(tenant string) {
	p.Tenant = tenant
	if tenant == "" {
		p.Tenant = "idocO360.onmicrosoft.com"
	}

	if p.LoginURL == nil || p.LoginURL.String() == "" {
		p.LoginURL = &url.URL{
			Scheme: "https",
			Host:   "login.windows.net",
			Path:   "/" + p.Tenant + "/oauth2/authorize"}
	}
	if p.RedeemURL == nil || p.RedeemURL.String() == "" {
		p.RedeemURL = &url.URL{
			Scheme: "https",
			Host:   "login.windows.net",
			Path:   "/" + p.Tenant + "/oauth2/token",
		}
	}
}

func getAzureHeader(access_token string) http.Header {
	header := make(http.Header)
	header.Set("Authorization", fmt.Sprintf("Bearer %s", access_token))
	return header
}

func getEmailFromJSON(json *simplejson.Json) (string, error) {
	var email string
	var err error

	email, err = json.Get("mail").String()

	if err != nil || email == "" {
		otherMails, otherMailsErr := json.Get("otherMails").Array()
		if len(otherMails) > 0 {
			email = otherMails[0].(string)
		}
		err = otherMailsErr
	}

	return email, err
}

func (p *AzureProvider) GetEmailAddress(s *SessionState) (string, error) {
	var email string
	var err error

	if s.AccessToken == "" {
		return "", errors.New("missing access token")
	}
	req, err := http.NewRequest("GET", p.ProfileURL.String(), nil)
	if err != nil {
		return "", err
	}
	req.Header = getAzureHeader(s.AccessToken)

	json, err := api.Request(req)

	if err != nil {
		return "", err
	}

	email, err = getEmailFromJSON(json)

	if err == nil && email != "" {
		return email, err
	}

	email, err = json.Get("userPrincipalName").String()

	if err != nil {
		log.Printf("failed making request %s", err)
		return "", err
	}

	if email == "" {
		log.Printf("failed to get email address")
		return "", err
	}

	return email, err
}
<|endoftext|>


<commit_before>package app

import (
	"testing"

	"github.com/stretchr/testify/assert"
	abci "github.com/tendermint/abci/types"
	"github.com/tendermint/merkleeyes/iavl"
	wire "github.com/tendermint/go-wire"
)

func makeSet(key, value []byte) []byte {
	tx := make([]byte, 1+wire.ByteSliceSize(key)+wire.ByteSliceSize(value))
	buf := tx
	buf[0] = WriteSet // Set TypeByte
	buf = buf[1:]
	n, err := wire.PutByteSlice(buf, key)
	if err != nil {
		panic(err)
	}
	buf = buf[n:]
	n, err = wire.PutByteSlice(buf, value)
	if err != nil {
		panic(err)
	}
	return tx
}

func makeRemove(key []byte) []byte {
	tx := make([]byte, 1+wire.ByteSliceSize(key))
	buf := tx
	buf[0] = WriteRem // Set TypeByte
	buf = buf[1:]
	_, err := wire.PutByteSlice(buf, key)
	if err != nil {
		panic(err)
	}
	return tx
}

func makeQuery(key []byte, prove bool, height uint64) (reqQuery abci.RequestQuery) {
	reqQuery.Path = "/key"
	reqQuery.Data = key
	reqQuery.Prove = prove
	reqQuery.Height = height
	return
}

func TestAppQueries(t *testing.T) {
	assert := assert.New(t)

	app := NewMerkleEyesApp("", 0)
	info := app.Info().Data
	assert.Equal("size:0", info)
	com := app.Commit()
	assert.Equal([]byte(nil), com.Data)

	// prepare some actions
	key, value := []byte("foobar"), []byte("works!")
	addTx := makeSet(key, value)
	removeTx := makeRemove(key)

	// need to commit append before it shows in queries
	append := app.DeliverTx(addTx)
	assert.True(append.IsOK(), append.Log)
	info = app.Info().Data
	assert.Equal("size:0", info)
	resQuery := app.Query(makeQuery(key, false, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal([]byte(nil), resQuery.Value)

	com = app.Commit()
	hash := com.Data
	assert.NotEqual(t, nil, hash)
	info = app.Info().Data
	assert.Equal("size:1", info)
	resQuery = app.Query(makeQuery(key, false, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal(value, resQuery.Value)

	// modifying check has no effect
	check := app.CheckTx(removeTx)
	assert.True(check.IsOK(), check.Log)
	com = app.Commit()
	assert.True(com.IsOK(), com.Log)
	hash2 := com.Data
	assert.Equal(hash, hash2)
	info = app.Info().Data
	assert.Equal("size:1", info)

	// proofs come from the last commited state, not working state
	append = app.DeliverTx(removeTx)
	assert.True(append.IsOK(), append.Log)
	// currently don't support specifying block height
	resQuery = app.Query(makeQuery(key, true, 1))
	assert.False(resQuery.Code.IsOK(), resQuery.Log)
	resQuery = app.Query(makeQuery(key, true, 0))
	if assert.NotEmpty(resQuery.Value) {
		proof, err := iavl.ReadProof(resQuery.Proof)
		if assert.Nil(err) {
			assert.True(proof.Verify(key, resQuery.Value, proof.RootHash))
		}
	}

	// commit remove actually removes it now
	com = app.Commit()
	assert.True(com.IsOK(), com.Log)
	hash3 := com.Data
	assert.NotEqual(hash, hash3)
	info = app.Info().Data
	assert.Equal("size:0", info)

	// nothing here...
	resQuery = app.Query(makeQuery(key, false, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal([]byte(nil), resQuery.Value)
	// neither with proof...
	resQuery = app.Query(makeQuery(key, true, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal([]byte(nil), resQuery.Value)
	assert.Empty(resQuery.Proof)
}
<commit_msg>fix test<commit_after>package app

import (
	"testing"

	"github.com/stretchr/testify/assert"
	abci "github.com/tendermint/abci/types"
	wire "github.com/tendermint/go-wire"
	"github.com/tendermint/merkleeyes/iavl"
)

func makeSet(key, value []byte) []byte {
	tx := make([]byte, 1+wire.ByteSliceSize(key)+wire.ByteSliceSize(value))
	buf := tx
	buf[0] = WriteSet // Set TypeByte
	buf = buf[1:]
	n, err := wire.PutByteSlice(buf, key)
	if err != nil {
		panic(err)
	}
	buf = buf[n:]
	n, err = wire.PutByteSlice(buf, value)
	if err != nil {
		panic(err)
	}
	return tx
}

func makeRemove(key []byte) []byte {
	tx := make([]byte, 1+wire.ByteSliceSize(key))
	buf := tx
	buf[0] = WriteRem // Set TypeByte
	buf = buf[1:]
	_, err := wire.PutByteSlice(buf, key)
	if err != nil {
		panic(err)
	}
	return tx
}

func makeQuery(key []byte, prove bool, height uint64) (reqQuery abci.RequestQuery) {
	reqQuery.Path = "/key"
	reqQuery.Data = key
	reqQuery.Prove = prove
	reqQuery.Height = height
	return
}

func TestAppQueries(t *testing.T) {
	assert := assert.New(t)

	app := NewMerkleEyesApp("", 0)
	info := app.Info().Data
	assert.Equal("size:0", info)
	com := app.Commit()
	assert.EqualValues([]byte(nil), com.Data)

	// prepare some actions
	key, value := []byte("foobar"), []byte("works!")
	addTx := makeSet(key, value)
	removeTx := makeRemove(key)

	// need to commit append before it shows in queries
	append := app.DeliverTx(addTx)
	assert.True(append.IsOK(), append.Log)
	info = app.Info().Data
	assert.Equal("size:0", info)
	resQuery := app.Query(makeQuery(key, false, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal([]byte(nil), resQuery.Value)

	com = app.Commit()
	hash := com.Data
	assert.NotEqual(t, nil, hash)
	info = app.Info().Data
	assert.Equal("size:1", info)
	resQuery = app.Query(makeQuery(key, false, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal(value, resQuery.Value)

	// modifying check has no effect
	check := app.CheckTx(removeTx)
	assert.True(check.IsOK(), check.Log)
	com = app.Commit()
	assert.True(com.IsOK(), com.Log)
	hash2 := com.Data
	assert.Equal(hash, hash2)
	info = app.Info().Data
	assert.Equal("size:1", info)

	// proofs come from the last commited state, not working state
	append = app.DeliverTx(removeTx)
	assert.True(append.IsOK(), append.Log)
	// currently don't support specifying block height
	resQuery = app.Query(makeQuery(key, true, 1))
	assert.False(resQuery.Code.IsOK(), resQuery.Log)
	resQuery = app.Query(makeQuery(key, true, 0))
	if assert.NotEmpty(resQuery.Value) {
		proof, err := iavl.ReadProof(resQuery.Proof)
		if assert.Nil(err) {
			assert.True(proof.Verify(key, resQuery.Value, proof.RootHash))
		}
	}

	// commit remove actually removes it now
	com = app.Commit()
	assert.True(com.IsOK(), com.Log)
	hash3 := com.Data
	assert.NotEqual(hash, hash3)
	info = app.Info().Data
	assert.Equal("size:0", info)

	// nothing here...
	resQuery = app.Query(makeQuery(key, false, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal([]byte(nil), resQuery.Value)
	// neither with proof...
	resQuery = app.Query(makeQuery(key, true, 0))
	assert.True(resQuery.Code.IsOK(), resQuery.Log)
	assert.Equal([]byte(nil), resQuery.Value)
	assert.Empty(resQuery.Proof)
}
<|endoftext|>