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

package cmd

import (
	"github.com/spf13/cobra"
	"github.com/edio/n4dgrpc/convertions"
	"fmt"
	mesh "github.com/linkerd/linkerd/mesh/core/src/main/protobuf"
	"github.com/edio/n4dgrpc/client"
)

type BindConfig struct {
	FailOnNegOrEmpty bool
	Root             *mesh.Path
	Name             *mesh.Path
}

var (
	bindConfig = BindConfig{}
)

var bindCmd = &cobra.Command{
	Use:   "bind NAME [NAMESPACE]",
	Short: "bind name in namespace",
	Long: "bind name in namespace",
	Args: func(cmd *cobra.Command, args []string) error {
		if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
			return err
		}

		{
			var name *mesh.Path
			var err error
			if name, err = convertions.StrToPath(args[0]); err != nil {
				return fmt.Errorf("NAME: %v", err)
			}
			bindConfig.Name = name
		}

		{
			rootStr := DefaultRoot
			if len(args) == 2 {
				rootStr = args[1]
			}

			var root *mesh.Path
			var err error
			if root, err = convertions.StrToPath(rootStr); err != nil {
				return fmt.Errorf("ROOT: %v", err)
			}
			bindConfig.Root = root
		}

		return nil
	},
	Run: func(cmd *cobra.Command, args []string) {
		paths, err := client.Bind(bindConfig.Root, bindConfig.Name)
		if err != nil {
			Exit(ExitBindingError, "Failed to bind: %v", err)
		}
		if len(paths) == 0 && bindConfig.FailOnNegOrEmpty {
			Exit(ExitBindingError, "Binding is negative or empty")
		}

		for _, path := range paths {
			fmt.Println(convertions.PathToStr(path))
		}
		return
	},
}

func init() {
	N4dgrpc.AddCommand(bindCmd)
	bindCmd.Flags().BoolVarP(&bindConfig.FailOnNegOrEmpty, "fail", "f", false, "fail if binding is negative")
}
<commit_msg>Update bind command long description<commit_after>// Copyright © 2017 Dmytro Kostiuchenko edio@archlinux.us
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"github.com/spf13/cobra"
	"github.com/edio/n4dgrpc/convertions"
	"fmt"
	mesh "github.com/linkerd/linkerd/mesh/core/src/main/protobuf"
	"github.com/edio/n4dgrpc/client"
)

type BindConfig struct {
	FailOnNegOrEmpty bool
	Root             *mesh.Path
	Name             *mesh.Path
}

var (
	bindConfig = BindConfig{}
)

var bindCmd = &cobra.Command{
	Use:   "bind NAME [NAMESPACE]",
	Short: "bind NAME in NAMESPACE",
	Long: `bind NAME in NAMESPACE

By default command exits with zero if binding is negative.

To fail if binding is negative flag -f must be set.
	`,
	Args: func(cmd *cobra.Command, args []string) error {
		if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
			return err
		}

		{
			var name *mesh.Path
			var err error
			if name, err = convertions.StrToPath(args[0]); err != nil {
				return fmt.Errorf("NAME: %v", err)
			}
			bindConfig.Name = name
		}

		{
			rootStr := DefaultRoot
			if len(args) == 2 {
				rootStr = args[1]
			}

			var root *mesh.Path
			var err error
			if root, err = convertions.StrToPath(rootStr); err != nil {
				return fmt.Errorf("ROOT: %v", err)
			}
			bindConfig.Root = root
		}

		return nil
	},
	Run: func(cmd *cobra.Command, args []string) {
		paths, err := client.Bind(bindConfig.Root, bindConfig.Name)
		if err != nil {
			Exit(ExitBindingError, "Failed to bind: %v", err)
		}
		if len(paths) == 0 && bindConfig.FailOnNegOrEmpty {
			Exit(ExitBindingError, "Binding is negative or empty")
		}

		for _, path := range paths {
			fmt.Println(convertions.PathToStr(path))
		}
		return
	},
}

func init() {
	N4dgrpc.AddCommand(bindCmd)
	bindCmd.Flags().BoolVarP(&bindConfig.FailOnNegOrEmpty, "fail", "f", false, "fail if binding is negative")
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/hoop33/limo/config"
	"github.com/hoop33/limo/model"
	"github.com/spf13/cobra"
)

var union = false
var intersection = false

var listers = map[string]func(){
	"languages": listLanguages,
	"stars":     listStars,
	"tags":      listTags,
	"trending":  listTrending,
}

// ListCmd lists stars, tags, or trending
var ListCmd = &cobra.Command{
	Use:     "list <languages|stars|tags|trending>",
	Aliases: []string{"ls"},
	Short:   "List languages, stars, trending, or tags",
	Long:    "List languages, stars, trending, or tags that match your specified criteria.",
	Example: fmt.Sprintf("  %s list languages\n  %s list stars -t vim", config.ProgramName, config.ProgramName),
	Run: func(cmd *cobra.Command, args []string) {
		var target string
		if len(args) == 0 {
			target = "stars"
		} else {
			target = args[0]
		}

		if fn, ok := listers[target]; ok {
			fn()
		} else {
			getOutput().Fatal(fmt.Sprintf("'%s' not valid", target))
		}
	},
}

func listLanguages() {
	output := getOutput()

	db, err := getDatabase()
	fatalOnError(err)

	languages, err := model.FindLanguages(db)
	fatalOnError(err)

	for _, language := range languages {
		if language != "" {
			output.Info(language)
		}
	}
}

func listStars() {
	output := getOutput()

	db, err := getDatabase()
	fatalOnError(err)

	var stars []model.Star
	if options.language != "" && options.tag != "" {
		stars, err = model.FindStarsByLanguageAndOrTag(db, options.language, options.tag, union)
	} else if options.language != "" {
		stars, err = model.FindStarsByLanguage(db, options.language)
	} else if options.tag != "" {
		tag, err := model.FindTagByName(db, options.tag)
		fatalOnError(err)

		if tag == nil {
			output.Fatal(fmt.Sprintf("Tag '%s' not found", options.tag))
		}

		err = tag.LoadStars(db)
		fatalOnError(err)

		stars = tag.Stars
	} else {
		stars, err = model.FindStars(db)
	}

	fatalOnError(err)

	if stars != nil {
		for _, star := range stars {
			output.StarLine(&star)
		}
	}
}

func listTags() {
	output := getOutput()

	db, err := getDatabase()
	if err != nil {
		output.Fatal(err.Error())
	}

	tags, err := model.FindTags(db)
	if err != nil {
		output.Error(err.Error())
	} else {
		for _, tag := range tags {
			output.Info(tag.Name)
		}
	}
}

func listTrending() {
	getOutput().Info("Listing trending")
}

func init() {
	ListCmd.Flags().BoolVarP(&union, "union", "u", false, "Show stars matching any arguments")
	RootCmd.AddCommand(ListCmd)
}
<commit_msg>Add example of passing tag and language<commit_after>package cmd

import (
	"fmt"

	"github.com/hoop33/limo/config"
	"github.com/hoop33/limo/model"
	"github.com/spf13/cobra"
)

var union = false
var intersection = false

var listers = map[string]func(){
	"languages": listLanguages,
	"stars":     listStars,
	"tags":      listTags,
	"trending":  listTrending,
}

// ListCmd lists stars, tags, or trending
var ListCmd = &cobra.Command{
	Use:     "list <languages|stars|tags|trending>",
	Aliases: []string{"ls"},
	Short:   "List languages, stars, trending, or tags",
	Long:    "List languages, stars, trending, or tags that match your specified criteria.",
	Example: fmt.Sprintf("  %s list languages\n  %s list stars -t vim\n  %s list stars -t cli -l go", config.ProgramName, config.ProgramName, config.ProgramName),
	Run: func(cmd *cobra.Command, args []string) {
		var target string
		if len(args) == 0 {
			target = "stars"
		} else {
			target = args[0]
		}

		if fn, ok := listers[target]; ok {
			fn()
		} else {
			getOutput().Fatal(fmt.Sprintf("'%s' not valid", target))
		}
	},
}

func listLanguages() {
	output := getOutput()

	db, err := getDatabase()
	fatalOnError(err)

	languages, err := model.FindLanguages(db)
	fatalOnError(err)

	for _, language := range languages {
		if language != "" {
			output.Info(language)
		}
	}
}

func listStars() {
	output := getOutput()

	db, err := getDatabase()
	fatalOnError(err)

	var stars []model.Star
	if options.language != "" && options.tag != "" {
		stars, err = model.FindStarsByLanguageAndOrTag(db, options.language, options.tag, union)
	} else if options.language != "" {
		stars, err = model.FindStarsByLanguage(db, options.language)
	} else if options.tag != "" {
		tag, err := model.FindTagByName(db, options.tag)
		fatalOnError(err)

		if tag == nil {
			output.Fatal(fmt.Sprintf("Tag '%s' not found", options.tag))
		}

		err = tag.LoadStars(db)
		fatalOnError(err)

		stars = tag.Stars
	} else {
		stars, err = model.FindStars(db)
	}

	fatalOnError(err)

	if stars != nil {
		for _, star := range stars {
			output.StarLine(&star)
		}
	}
}

func listTags() {
	output := getOutput()

	db, err := getDatabase()
	if err != nil {
		output.Fatal(err.Error())
	}

	tags, err := model.FindTags(db)
	if err != nil {
		output.Error(err.Error())
	} else {
		for _, tag := range tags {
			output.Info(tag.Name)
		}
	}
}

func listTrending() {
	getOutput().Info("Listing trending")
}

func init() {
	ListCmd.Flags().BoolVarP(&union, "union", "u", false, "Show stars matching any arguments")
	RootCmd.AddCommand(ListCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"
	"runtime"

	"github.com/exercism/cli/api"
	"github.com/spf13/cobra"
)

var BinaryName string

// RootCmd represents the base command when called without any subcommands.
var RootCmd = &cobra.Command{
	Use:   BinaryName,
	Short: "A friendly command-line interface to Exercism.",
	Long: `A command-line interface for https://v2.exercism.io.

Download exercises and submit your solutions.`,
}

// Execute adds all child commands to the root command.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	BinaryName = os.Args[0]
	api.UserAgent = fmt.Sprintf("github.com/exercism/cli v%s (%s/%s)", Version, runtime.GOOS, runtime.GOARCH)
}
<commit_msg>Fix another missed linting issue<commit_after>package cmd

import (
	"fmt"
	"os"
	"runtime"

	"github.com/exercism/cli/api"
	"github.com/spf13/cobra"
)

// BinaryName is the name of the app.
// By default this is exercism, but people
// are free to name this however they want.
// The usage examples and help strings should reflect
// the actual name of the binary.
var BinaryName string

// RootCmd represents the base command when called without any subcommands.
var RootCmd = &cobra.Command{
	Use:   BinaryName,
	Short: "A friendly command-line interface to Exercism.",
	Long: `A command-line interface for https://v2.exercism.io.

Download exercises and submit your solutions.`,
}

// Execute adds all child commands to the root command.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	BinaryName = os.Args[0]
	api.UserAgent = fmt.Sprintf("github.com/exercism/cli v%s (%s/%s)", Version, runtime.GOOS, runtime.GOARCH)
}
<|endoftext|>


<commit_before>package user

import (
	"log"

	"github.com/codegangsta/cli"
	"github.com/garlsecurity/securepassctl/spctl/service"
)

func init() {
	Command.Subcommands = append(Command.Subcommands,
		cli.Command{
			Name:        "xattrs",
			Usage:       "access user xattrs",
			ArgsUsage:   "USERNAME OPERATION [ATTRIBUTE [VALUE]]",
			Description: "Operate on users' extended attributes in SecurePass.",
			Action:      ActionXattrs,
		})
}

// ActionXattrs provides the provision subcommand
func ActionXattrs(c *cli.Context) {
	if len(c.Args()) < 2 {
		log.Fatal("error: too few arguments")
	}
	if len(c.Args()) > 4 {
		log.Fatal("error: too many arguments")
	}

	username := c.Args()[0]
	operation := c.Args()[1]
	switch operation {
	case "list":
		if len(c.Args()) != 2 {
			log.Fatalf("error: too many arguments")
		}
		resp, err := service.Service.UserXattrsList(username)
		if err != nil {
			log.Fatalf("error: %v", err)
		}
		for a, v := range *resp {
			if a != "rc" && a != "errorMsg" {
				log.Printf("%s: %s", a, v)
			}
		}
	case "delete":
		if len(c.Args()) != 3 {
			log.Fatalf("error: must specify an attribute")
		}
		attribute := c.Args()[2]
		_, err := service.Service.UserXattrsDelete(username, attribute)
		if err != nil {
			log.Fatalf("error: %v", err)
		}
		log.Printf("User %q attribute %q deleted", username, attribute)
	case "set":
		if len(c.Args()) != 4 {
			log.Fatalf("error: too few arguments")
		}
		attribute, value := c.Args()[2], c.Args()[3]
		_, err := service.Service.UserXattrsSet(username, attribute, value)
		if err != nil {
			log.Fatalf("error: %v", err)
		}
		log.Printf("Attribute %q set for user %q", attribute, username)
	default:
		log.Fatalf("error: invalid operation: %q", operation)
	}
}
<commit_msg>fix for issue #55, xattrs list not working for few args<commit_after>package user

import (
	"log"

	"github.com/codegangsta/cli"
	"github.com/garlsecurity/securepassctl/spctl/service"
)

func init() {
	Command.Subcommands = append(Command.Subcommands,
		cli.Command{
			Name:        "xattrs",
			Usage:       "access user xattrs",
			ArgsUsage:   "USERNAME OPERATION [ATTRIBUTE [VALUE]]",
			Description: "Operate on users' extended attributes in SecurePass.",
			Action:      ActionXattrs,
		})
}

// ActionXattrs provides the provision subcommand
func ActionXattrs(c *cli.Context) {
	// We do not need to check less than x, because we have checks after
	if len(c.Args()) > 4 {
		log.Fatal("error: too many arguments")
	}

	username := c.Args()[0]
	operation := c.Args()[1]

	switch operation {
		case "list":
			if len(c.Args()) != 2 {
				log.Fatalf("error: too many arguments")
			}
			resp, err := service.Service.UserXattrsList(username)
			if err != nil {
				log.Fatalf("error: %v", err)
			}
			for a, v := range *resp {
				if a != "rc" && a != "errorMsg" {
					log.Printf("%s: %s", a, v)
				}
			}
		case "delete":
			if len(c.Args()) != 3 {
				log.Fatalf("error: must specify an attribute")
			}
			attribute := c.Args()[2]
			_, err := service.Service.UserXattrsDelete(username, attribute)
			if err != nil {
				log.Fatalf("error: %v", err)
			}
			log.Printf("User %q attribute %q deleted", username, attribute)
		case "set":
			if len(c.Args()) != 4 {
				log.Fatalf("error: too few arguments")
			}
			attribute, value := c.Args()[2], c.Args()[3]
			_, err := service.Service.UserXattrsSet(username, attribute, value)
			if err != nil {
				log.Fatalf("error: %v", err)
			}
			log.Printf("Attribute %q set for user %q", attribute, username)
		default:
			log.Fatalf("error: invalid operation: %q", operation)
	}
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "reviewer",
	Short: "Code review your pull requests",
	Long: `By running reviewer your repo's pull requests will get merged
according to the configuration file.`,
    Run: func(cmd *cobra.Command, args []string) {
        // TODO: Work your own magic here
        fmt.Println("root called")
    },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.reviewer.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".reviewer") // name of config file (without extension)
	viper.AddConfigPath("$HOME")  // adding home directory as first search path
	viper.AutomaticEnv()          // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>Adds prefix definition for environment variables<commit_after>// Copyright © 2016 See CONTRIBUTORS <ignasi.fosch@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "reviewer",
	Short: "Code review your pull requests",
	Long: `By running reviewer your repo's pull requests will get merged
according to the configuration file.`,
    Run: func(cmd *cobra.Command, args []string) {
        // TODO: Work your own magic here
        fmt.Println("root called")
    },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.reviewer.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".reviewer") // name of config file (without extension)
	viper.AddConfigPath("$HOME")  // adding home directory as first search path
    viper.SetEnvPrefix("reviewer") // so viper.AutomaticEnv will get matching envvars starting with REVIEWER_
	viper.AutomaticEnv()          // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>package cmd

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

	"github.com/aquasecurity/kube-bench/check"
	"github.com/fatih/color"
	"github.com/golang/glog"
	"github.com/spf13/viper"
)

var (
	// Print colors
	colors = map[check.State]*color.Color{
		check.PASS: color.New(color.FgGreen),
		check.FAIL: color.New(color.FgRed),
		check.WARN: color.New(color.FgYellow),
		check.INFO: color.New(color.FgBlue),
	}
)

var psFunc func(string) string
var statFunc func(string) (os.FileInfo, error)

func init() {
	psFunc = ps
	statFunc = os.Stat
}

func printlnWarn(msg string) {
	fmt.Fprintf(os.Stderr, "[%s] %s\n",
		colors[check.WARN].Sprintf("%s", check.WARN),
		msg,
	)
}

func sprintlnWarn(msg string) string {
	return fmt.Sprintf("[%s] %s",
		colors[check.WARN].Sprintf("%s", check.WARN),
		msg,
	)
}

func exitWithError(err error) {
	fmt.Fprintf(os.Stderr, "\n%v\n", err)
	os.Exit(1)
}

func continueWithError(err error, msg string) string {
	if err != nil {
		glog.V(2).Info(err)
	}

	if msg != "" {
		fmt.Fprintf(os.Stderr, "%s\n", msg)
	}

	return ""
}

func cleanIDs(list string) []string {
	list = strings.Trim(list, ",")
	ids := strings.Split(list, ",")

	for _, id := range ids {
		id = strings.Trim(id, " ")
	}

	return ids
}

// ps execs out to the ps command; it's separated into a function so we can write tests
func ps(proc string) string {
	cmd := exec.Command("ps", "-C", proc, "-o", "cmd", "--no-headers")
	out, err := cmd.Output()
	if err != nil {
		continueWithError(fmt.Errorf("%s: %s", cmd.Args, err), "")
	}

	return string(out)
}

// getBinaries finds which of the set of candidate executables are running
func getBinaries(v *viper.Viper) map[string]string {
	binmap := make(map[string]string)

	for _, component := range v.GetStringSlice("components") {
		s := v.Sub(component)
		if s == nil {
			continue
		}

		optional := s.GetBool("optional")
		bins := s.GetStringSlice("bins")
		if len(bins) > 0 {
			bin, err := findExecutable(bins)
			if err != nil && !optional {
				exitWithError(fmt.Errorf("need %s executable but none of the candidates are running", component))
			}

			// Default the executable name that we'll substitute to the name of the component
			if bin == "" {
				bin = component
				glog.V(2).Info(fmt.Sprintf("Component %s not running", component))
			} else {
				glog.V(2).Info(fmt.Sprintf("Component %s uses running binary %s", component, bin))
			}
			binmap[component] = bin
		}
	}

	return binmap
}

// getConfigFiles finds which of the set of candidate config files exist
// accepts a string 't' which indicates the type of config file, conf,
// podspec or untifile.
func getConfigFiles(v *viper.Viper) map[string]string {
	confmap := make(map[string]string)

	for _, component := range v.GetStringSlice("components") {
		s := v.Sub(component)
		if s == nil {
			continue
		}

		// See if any of the candidate config files exist
		conf := findConfigFile(s.GetStringSlice("confs"))
		if conf == "" {
			if s.IsSet("defaultconf") {
				conf = s.GetString("defaultconf")
				glog.V(2).Info(fmt.Sprintf("Using default config file name '%s' for component %s", conf, component))
			} else {
				// Default the config file name that we'll substitute to the name of the component
				glog.V(2).Info(fmt.Sprintf("Missing config file for %s", component))
				conf = component
			}
		} else {
			glog.V(2).Info(fmt.Sprintf("Component %s uses config file '%s'", component, conf))
		}

		confmap[component] = conf
	}

	return confmap
}

// verifyBin checks that the binary specified is running
func verifyBin(bin string) bool {

	// Strip any quotes
	bin = strings.Trim(bin, "'\"")

	// bin could consist of more than one word
	// We'll search for running processes with the first word, and then check the whole
	// proc as supplied is included in the results
	proc := strings.Fields(bin)[0]
	out := psFunc(proc)

	// There could be multiple lines in the ps output
	// The binary needs to be the first word in the ps output, except that it could be preceded by a path
	// e.g. /usr/bin/kubelet is a match for kubelet
	// but apiserver is not a match for kube-apiserver
	reFirstWord := regexp.MustCompile(`^(\S*\/)*` + bin)
	lines := strings.Split(out, "\n")
	for _, l := range lines {
		if reFirstWord.Match([]byte(l)) {
			return true
		}
	}

	return false
}

// fundConfigFile looks through a list of possible config files and finds the first one that exists
func findConfigFile(candidates []string) string {
	for _, c := range candidates {
		_, err := statFunc(c)
		if err == nil {
			return c
		}
		if !os.IsNotExist(err) {
			exitWithError(fmt.Errorf("error looking for file %s: %v", c, err))
		}
	}

	return ""
}

// findExecutable looks through a list of possible executable names and finds the first one that's running
func findExecutable(candidates []string) (string, error) {
	for _, c := range candidates {
		if verifyBin(c) {
			return c, nil
		}
		glog.V(1).Info(fmt.Sprintf("executable '%s' not running", c))
	}

	return "", fmt.Errorf("no candidates running")
}

func multiWordReplace(s string, subname string, sub string) string {
	f := strings.Fields(sub)
	if len(f) > 1 {
		sub = "'" + sub + "'"
	}

	return strings.Replace(s, subname, sub, -1)
}

func getKubeVersion() string {
	// These executables might not be on the user's path.
	_, err := exec.LookPath("kubectl")

	if err != nil {
		_, err = exec.LookPath("kubelet")
		if err != nil {
			exitWithError(fmt.Errorf("Version check failed: need kubectl or kubelet binaries to get kubernetes version"))
		}
		return getKubeVersionFromKubelet()
	}

	return getKubeVersionFromKubectl()
}

func getKubeVersionFromKubectl() string {
	cmd := exec.Command("kubectl", "version", "--short")
	out, err := cmd.CombinedOutput()
	if err != nil {
		continueWithError(fmt.Errorf("%s", out), "")
	}

	return getVersionFromKubectlOutput(string(out))
}

func getKubeVersionFromKubelet() string {
	cmd := exec.Command("kubelet", "--version")
	out, err := cmd.CombinedOutput()

	if err != nil {
		continueWithError(fmt.Errorf("%s", out), "")
	}

	return getVersionFromKubeletOutput(string(out))
}

func getVersionFromKubectlOutput(s string) string {
	serverVersionRe := regexp.MustCompile(`Server Version: v(\d+.\d+)`)
	subs := serverVersionRe.FindStringSubmatch(s)
	if len(subs) < 2 {
		printlnWarn(fmt.Sprintf("Unable to get kubectl version, using default version: %s", defaultKubeVersion))
		return defaultKubeVersion
	}
	return subs[1]
}

func getVersionFromKubeletOutput(s string) string {
	serverVersionRe := regexp.MustCompile(`Kubernetes v(\d+.\d+)`)
	subs := serverVersionRe.FindStringSubmatch(s)
	if len(subs) < 2 {
		printlnWarn(fmt.Sprintf("Unable to get kubelet version, using default version: %s", defaultKubeVersion))
		return defaultKubeVersion
	}
	return subs[1]
}

func makeSubstitutions(s string, ext string, m map[string]string) string {
	for k, v := range m {
		subst := "$" + k + ext
		if v == "" {
			glog.V(2).Info(fmt.Sprintf("No subsitution for '%s'\n", subst))
			continue
		}
		glog.V(1).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
		s = multiWordReplace(s, subst, v)
	}

	return s
}
<commit_msg>Add tip about the `--version` flag to error output<commit_after>package cmd

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

	"github.com/aquasecurity/kube-bench/check"
	"github.com/fatih/color"
	"github.com/golang/glog"
	"github.com/spf13/viper"
)

var (
	// Print colors
	colors = map[check.State]*color.Color{
		check.PASS: color.New(color.FgGreen),
		check.FAIL: color.New(color.FgRed),
		check.WARN: color.New(color.FgYellow),
		check.INFO: color.New(color.FgBlue),
	}
)

var psFunc func(string) string
var statFunc func(string) (os.FileInfo, error)

func init() {
	psFunc = ps
	statFunc = os.Stat
}

func printlnWarn(msg string) {
	fmt.Fprintf(os.Stderr, "[%s] %s\n",
		colors[check.WARN].Sprintf("%s", check.WARN),
		msg,
	)
}

func sprintlnWarn(msg string) string {
	return fmt.Sprintf("[%s] %s",
		colors[check.WARN].Sprintf("%s", check.WARN),
		msg,
	)
}

func exitWithError(err error) {
	fmt.Fprintf(os.Stderr, "\n%v\n", err)
	os.Exit(1)
}

func continueWithError(err error, msg string) string {
	if err != nil {
		glog.V(2).Info(err)
	}

	if msg != "" {
		fmt.Fprintf(os.Stderr, "%s\n", msg)
	}

	return ""
}

func cleanIDs(list string) []string {
	list = strings.Trim(list, ",")
	ids := strings.Split(list, ",")

	for _, id := range ids {
		id = strings.Trim(id, " ")
	}

	return ids
}

// ps execs out to the ps command; it's separated into a function so we can write tests
func ps(proc string) string {
	cmd := exec.Command("ps", "-C", proc, "-o", "cmd", "--no-headers")
	out, err := cmd.Output()
	if err != nil {
		continueWithError(fmt.Errorf("%s: %s", cmd.Args, err), "")
	}

	return string(out)
}

// getBinaries finds which of the set of candidate executables are running
func getBinaries(v *viper.Viper) map[string]string {
	binmap := make(map[string]string)

	for _, component := range v.GetStringSlice("components") {
		s := v.Sub(component)
		if s == nil {
			continue
		}

		optional := s.GetBool("optional")
		bins := s.GetStringSlice("bins")
		if len(bins) > 0 {
			bin, err := findExecutable(bins)
			if err != nil && !optional {
				exitWithError(fmt.Errorf("need %s executable but none of the candidates are running", component))
			}

			// Default the executable name that we'll substitute to the name of the component
			if bin == "" {
				bin = component
				glog.V(2).Info(fmt.Sprintf("Component %s not running", component))
			} else {
				glog.V(2).Info(fmt.Sprintf("Component %s uses running binary %s", component, bin))
			}
			binmap[component] = bin
		}
	}

	return binmap
}

// getConfigFiles finds which of the set of candidate config files exist
// accepts a string 't' which indicates the type of config file, conf,
// podspec or untifile.
func getConfigFiles(v *viper.Viper) map[string]string {
	confmap := make(map[string]string)

	for _, component := range v.GetStringSlice("components") {
		s := v.Sub(component)
		if s == nil {
			continue
		}

		// See if any of the candidate config files exist
		conf := findConfigFile(s.GetStringSlice("confs"))
		if conf == "" {
			if s.IsSet("defaultconf") {
				conf = s.GetString("defaultconf")
				glog.V(2).Info(fmt.Sprintf("Using default config file name '%s' for component %s", conf, component))
			} else {
				// Default the config file name that we'll substitute to the name of the component
				glog.V(2).Info(fmt.Sprintf("Missing config file for %s", component))
				conf = component
			}
		} else {
			glog.V(2).Info(fmt.Sprintf("Component %s uses config file '%s'", component, conf))
		}

		confmap[component] = conf
	}

	return confmap
}

// verifyBin checks that the binary specified is running
func verifyBin(bin string) bool {

	// Strip any quotes
	bin = strings.Trim(bin, "'\"")

	// bin could consist of more than one word
	// We'll search for running processes with the first word, and then check the whole
	// proc as supplied is included in the results
	proc := strings.Fields(bin)[0]
	out := psFunc(proc)

	// There could be multiple lines in the ps output
	// The binary needs to be the first word in the ps output, except that it could be preceded by a path
	// e.g. /usr/bin/kubelet is a match for kubelet
	// but apiserver is not a match for kube-apiserver
	reFirstWord := regexp.MustCompile(`^(\S*\/)*` + bin)
	lines := strings.Split(out, "\n")
	for _, l := range lines {
		if reFirstWord.Match([]byte(l)) {
			return true
		}
	}

	return false
}

// fundConfigFile looks through a list of possible config files and finds the first one that exists
func findConfigFile(candidates []string) string {
	for _, c := range candidates {
		_, err := statFunc(c)
		if err == nil {
			return c
		}
		if !os.IsNotExist(err) {
			exitWithError(fmt.Errorf("error looking for file %s: %v", c, err))
		}
	}

	return ""
}

// findExecutable looks through a list of possible executable names and finds the first one that's running
func findExecutable(candidates []string) (string, error) {
	for _, c := range candidates {
		if verifyBin(c) {
			return c, nil
		}
		glog.V(1).Info(fmt.Sprintf("executable '%s' not running", c))
	}

	return "", fmt.Errorf("no candidates running")
}

func multiWordReplace(s string, subname string, sub string) string {
	f := strings.Fields(sub)
	if len(f) > 1 {
		sub = "'" + sub + "'"
	}

	return strings.Replace(s, subname, sub, -1)
}

func getKubeVersion() string {
	// These executables might not be on the user's path.
	_, err := exec.LookPath("kubectl")

	if err != nil {
		_, err = exec.LookPath("kubelet")
		if err != nil {
			exitWithError(fmt.Errorf("Version check failed: need kubectl or kubelet binaries to get kubernetes version.\nAlternately, you can specify the version with --version"))
		}
		return getKubeVersionFromKubelet()
	}

	return getKubeVersionFromKubectl()
}

func getKubeVersionFromKubectl() string {
	cmd := exec.Command("kubectl", "version", "--short")
	out, err := cmd.CombinedOutput()
	if err != nil {
		continueWithError(fmt.Errorf("%s", out), "")
	}

	return getVersionFromKubectlOutput(string(out))
}

func getKubeVersionFromKubelet() string {
	cmd := exec.Command("kubelet", "--version")
	out, err := cmd.CombinedOutput()

	if err != nil {
		continueWithError(fmt.Errorf("%s", out), "")
	}

	return getVersionFromKubeletOutput(string(out))
}

func getVersionFromKubectlOutput(s string) string {
	serverVersionRe := regexp.MustCompile(`Server Version: v(\d+.\d+)`)
	subs := serverVersionRe.FindStringSubmatch(s)
	if len(subs) < 2 {
		printlnWarn(fmt.Sprintf("Unable to get kubectl version, using default version: %s", defaultKubeVersion))
		return defaultKubeVersion
	}
	return subs[1]
}

func getVersionFromKubeletOutput(s string) string {
	serverVersionRe := regexp.MustCompile(`Kubernetes v(\d+.\d+)`)
	subs := serverVersionRe.FindStringSubmatch(s)
	if len(subs) < 2 {
		printlnWarn(fmt.Sprintf("Unable to get kubelet version, using default version: %s", defaultKubeVersion))
		return defaultKubeVersion
	}
	return subs[1]
}

func makeSubstitutions(s string, ext string, m map[string]string) string {
	for k, v := range m {
		subst := "$" + k + ext
		if v == "" {
			glog.V(2).Info(fmt.Sprintf("No subsitution for '%s'\n", subst))
			continue
		}
		glog.V(1).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
		s = multiWordReplace(s, subst, v)
	}

	return s
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/urfave/cli"

	"github.com/manifoldco/torus-cli/api"
	"github.com/manifoldco/torus-cli/apitypes"
	"github.com/manifoldco/torus-cli/config"
	"github.com/manifoldco/torus-cli/errs"
)

func init() {
	view := cli.Command{
		Name:     "view",
		Usage:    "View secrets for the current service and environment",
		Category: "SECRETS",
		Flags: []cli.Flag{
			stdOrgFlag,
			stdProjectFlag,
			stdEnvFlag,
			serviceFlag("Use this service.", "default", true),
			stdInstanceFlag,
			cli.BoolFlag{
				Name:  "verbose, v",
				Usage: "list the sources of the values",
			},
		},
		Action: chain(
			ensureDaemon, ensureSession, loadDirPrefs, loadPrefDefaults,
			setUserEnv, checkRequiredFlags, viewCmd,
		),
	}

	Cmds = append(Cmds, view)
}

func viewCmd(ctx *cli.Context) error {
	secrets, path, err := getSecrets(ctx)
	if err != nil {
		return err
	}

	verbose := ctx.Bool("verbose")
	if verbose {
		fmt.Printf("Credential path: %s\n\n", path)
	}
	w := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
	for _, secret := range secrets {
		value := (*secret.Body).GetValue()
		name := (*secret.Body).GetName()
		key := strings.ToUpper(name)
		if verbose {
			spath := (*secret.Body).GetPathExp().String() + "/" + name
			fmt.Fprintf(w, "%s=%s\t%s\n", key, value.String(), spath)
		} else {
			fmt.Fprintf(w, "%s=%s\n", key, value.String())

		}
	}
	w.Flush()
	return nil
}

func getSecrets(ctx *cli.Context) ([]apitypes.CredentialEnvelope, string, error) {
	cfg, err := config.LoadConfig()
	if err != nil {
		return nil, "", err
	}

	client := api.NewClient(cfg)
	c := context.Background()

	session, err := client.Session.Who(c)
	if err != nil {
		return nil, "", errs.NewErrorExitError("Error fetching user details", err)
	}

	parts := []string{
		"", ctx.String("org"), ctx.String("project"), ctx.String("environment"),
		ctx.String("service"), session.Username(), ctx.String("instance"),
	}

	path := strings.Join(parts, "/")

	secrets, err := client.Credentials.Get(c, path)
	if err != nil {
		return nil, "", errs.NewErrorExitError("Error fetching secrets", err)
	}

	cset := credentialSet{}
	for _, c := range secrets {
		cset.Add(c)
	}

	return cset.ToSlice(), path, nil
}
<commit_msg>A machines identity is  prepended with 'machine-'<commit_after>package cmd

import (
	"context"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/urfave/cli"

	"github.com/manifoldco/torus-cli/api"
	"github.com/manifoldco/torus-cli/apitypes"
	"github.com/manifoldco/torus-cli/config"
	"github.com/manifoldco/torus-cli/errs"
)

func init() {
	view := cli.Command{
		Name:     "view",
		Usage:    "View secrets for the current service and environment",
		Category: "SECRETS",
		Flags: []cli.Flag{
			stdOrgFlag,
			stdProjectFlag,
			stdEnvFlag,
			serviceFlag("Use this service.", "default", true),
			stdInstanceFlag,
			cli.BoolFlag{
				Name:  "verbose, v",
				Usage: "list the sources of the values",
			},
		},
		Action: chain(
			ensureDaemon, ensureSession, loadDirPrefs, loadPrefDefaults,
			setUserEnv, checkRequiredFlags, viewCmd,
		),
	}

	Cmds = append(Cmds, view)
}

func viewCmd(ctx *cli.Context) error {
	secrets, path, err := getSecrets(ctx)
	if err != nil {
		return err
	}

	verbose := ctx.Bool("verbose")
	if verbose {
		fmt.Printf("Credential path: %s\n\n", path)
	}
	w := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
	for _, secret := range secrets {
		value := (*secret.Body).GetValue()
		name := (*secret.Body).GetName()
		key := strings.ToUpper(name)
		if verbose {
			spath := (*secret.Body).GetPathExp().String() + "/" + name
			fmt.Fprintf(w, "%s=%s\t%s\n", key, value.String(), spath)
		} else {
			fmt.Fprintf(w, "%s=%s\n", key, value.String())

		}
	}
	w.Flush()
	return nil
}

func getSecrets(ctx *cli.Context) ([]apitypes.CredentialEnvelope, string, error) {
	cfg, err := config.LoadConfig()
	if err != nil {
		return nil, "", err
	}

	client := api.NewClient(cfg)
	c := context.Background()

	session, err := client.Session.Who(c)
	if err != nil {
		return nil, "", errs.NewErrorExitError("Error fetching user details", err)
	}

	identity := session.Username()
	if session.Type() == "machine" {
		identity = "machine-" + identity
	}

	parts := []string{
		"", ctx.String("org"), ctx.String("project"), ctx.String("environment"),
		ctx.String("service"), identity, ctx.String("instance"),
	}

	path := strings.Join(parts, "/")

	secrets, err := client.Credentials.Get(c, path)
	if err != nil {
		return nil, "", errs.NewErrorExitError("Error fetching secrets", err)
	}

	cset := credentialSet{}
	for _, c := range secrets {
		cset.Add(c)
	}

	return cset.ToSlice(), path, nil
}
<|endoftext|>


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

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"code.google.com/p/go.talks/pkg/socket"

	// Imports so that go build/install automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const (
	basePkg    = "code.google.com/p/go-tour/"
	socketPath = "/socket"
)

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput  = flag.Bool("html", false, "render program output as HTML")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)

	// GOPATH containing the tour packages
	gopath = os.Getenv("GOPATH")

	httpAddr string
)

func isRoot(path string) bool {
	_, err := os.Stat(filepath.Join(path, "tour.article"))
	return err == nil
}

func findRoot() (string, error) {
	ctx := build.Default
	p, err := ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(p.Dir) {
		return p.Dir, nil
	}
	tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
	ctx.GOPATH = tourRoot
	p, err = ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(tourRoot) {
		gopath = tourRoot
		return tourRoot, nil
	}
	return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
}

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// find and serve the go tour files
	root, err := findRoot()
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}

	log.Println("Serving content from", root)

	host, port, err := net.SplitHostPort(*httpListen)
	if err != nil {
		log.Fatal(err)
	}
	if host == "" {
		host = "localhost"
	}
	if host != "127.0.0.1" && host != "localhost" {
		log.Print(localhostWarning)
	}
	httpAddr = host + ":" + port

	if err := initTour(root); err != nil {
		log.Fatal(err)
	}

	fs := http.FileServer(http.Dir(root))
	http.Handle("/favicon.ico", fs)
	http.Handle("/static/", fs)
	http.Handle("/talks/", fs)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			if err := renderTour(w); err != nil {
				log.Println(err)
			}
			return
		}
		http.Error(w, "not found", 404)
	})

	http.Handle(socketPath, socket.Handler)

	err = serveScripts(filepath.Join(root, "js"), "socket.js")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		url := "http://" + httpAddr
		if waitServer(url) && *openBrowser && startBrowser(url) {
			log.Printf("A browser window should open. If not, please visit %s", url)
		} else {
			log.Printf("Please open your web browser and visit %s", url)
		}
	}()
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

type response struct {
	Output string `json:"output"`
	Errors string `json:"compile_errors"`
}

// environ returns an execution environment containing only GO* variables
// and replacing GOPATH with the value of the global var gopath.
func environ() (env []string) {
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GO") {
			continue
		}
		if strings.HasPrefix(v, "GOPATH=") {
			v = "GOPATH=" + gopath
		}
		env = append(env, v)
	}
	return
}

// waitServer waits some time for the http Server to start
// serving url and returns whether it starts
func waitServer(url string) bool {
	tries := 20
	for tries > 0 {
		resp, err := http.Get(url)
		if err == nil {
			resp.Body.Close()
			return true
		}
		time.Sleep(100 * time.Millisecond)
		tries--
	}
	return false
}

// startBrowser tries to open the URL in a browser, and returns
// whether it succeed.
func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

// prepContent for the local tour simply returns the content as-is.
func prepContent(r io.Reader) io.Reader { return r }

// socketAddr returns the WebSocket handler address.
func socketAddr() string { return "ws://" + httpAddr + socketPath }
<commit_msg>[x/tour] go-tour: supply alternate GOPATH when building locally<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"code.google.com/p/go.talks/pkg/socket"

	// Imports so that go build/install automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const (
	basePkg    = "code.google.com/p/go-tour/"
	socketPath = "/socket"
)

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput  = flag.Bool("html", false, "render program output as HTML")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)

	// GOPATH containing the tour packages
	gopath = os.Getenv("GOPATH")

	httpAddr string
)

func isRoot(path string) bool {
	_, err := os.Stat(filepath.Join(path, "tour.article"))
	return err == nil
}

func findRoot() (string, error) {
	ctx := build.Default
	p, err := ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(p.Dir) {
		return p.Dir, nil
	}
	tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
	ctx.GOPATH = tourRoot
	p, err = ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(tourRoot) {
		gopath = tourRoot
		return tourRoot, nil
	}
	return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
}

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// find and serve the go tour files
	root, err := findRoot()
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}

	log.Println("Serving content from", root)

	host, port, err := net.SplitHostPort(*httpListen)
	if err != nil {
		log.Fatal(err)
	}
	if host == "" {
		host = "localhost"
	}
	if host != "127.0.0.1" && host != "localhost" {
		log.Print(localhostWarning)
	}
	httpAddr = host + ":" + port

	if err := initTour(root); err != nil {
		log.Fatal(err)
	}

	fs := http.FileServer(http.Dir(root))
	http.Handle("/favicon.ico", fs)
	http.Handle("/static/", fs)
	http.Handle("/talks/", fs)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			if err := renderTour(w); err != nil {
				log.Println(err)
			}
			return
		}
		http.Error(w, "not found", 404)
	})

	http.Handle(socketPath, socket.Handler)

	err = serveScripts(filepath.Join(root, "js"), "socket.js")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		url := "http://" + httpAddr
		if waitServer(url) && *openBrowser && startBrowser(url) {
			log.Printf("A browser window should open. If not, please visit %s", url)
		} else {
			log.Printf("Please open your web browser and visit %s", url)
		}
	}()
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

type response struct {
	Output string `json:"output"`
	Errors string `json:"compile_errors"`
}

func init() {
	socket.Environ = environ
}

// environ returns an execution environment containing only GO* variables
// and replacing GOPATH with the value of the global var gopath.
func environ() (env []string) {
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GO") {
			continue
		}
		if strings.HasPrefix(v, "GOPATH=") {
			v = "GOPATH=" + gopath
		}
		env = append(env, v)
	}
	return
}

// waitServer waits some time for the http Server to start
// serving url and returns whether it starts
func waitServer(url string) bool {
	tries := 20
	for tries > 0 {
		resp, err := http.Get(url)
		if err == nil {
			resp.Body.Close()
			return true
		}
		time.Sleep(100 * time.Millisecond)
		tries--
	}
	return false
}

// startBrowser tries to open the URL in a browser, and returns
// whether it succeed.
func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

// prepContent for the local tour simply returns the content as-is.
func prepContent(r io.Reader) io.Reader { return r }

// socketAddr returns the WebSocket handler address.
func socketAddr() string { return "ws://" + httpAddr + socketPath }
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

package tika

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"

	"golang.org/x/net/context/ctxhttp"
)

// Client represents a connection to a Tika Server.
type Client struct {
	// url is the URL of the Tika Server, including the port (if necessary), but
	// not the trailing slash. For example, http://localhost:9998.
	url string
	// HTTPClient is the client that will be used to call the Tika Server. If no
	// client is specified, a default client will be used. Since http.Clients are
	// thread safe, the same client will be used for all requests by this Client.
	httpClient *http.Client
}

// NewClient creates a new Client. If httpClient is nil, the http.DefaultClient will be
// used.
func NewClient(httpClient *http.Client, urlString string) *Client {
	return &Client{httpClient: httpClient, url: urlString}
}

// A Parser represents a Tika Parser. To get a list of all Parsers, see Parsers().
type Parser struct {
	Name           string
	Decorated      bool
	Composite      bool
	Children       []Parser
	SupportedTypes []string
}

// MIMEType represents a Tika Mime Type. To get a list of all MIMETypes, see
// MimeTypes.
type MIMEType struct {
	Alias     []string
	SuperType string
}

// A Detector represents a Tika Detector. Detectors are used to get the filetype
// of a file. To get a list of all Detectors, see Detectors().
type Detector struct {
	Name      string
	Composite bool
	Children  []Detector
}

// Translator represents the Java package of a Tika Translator.
type Translator string

// Translators available by defult in Tika. You must configure all required
// authentication details in Tika Server (for example, an API key).
const (
	Lingo24Translator   Translator = "org.apache.tika.language.translate.Lingo24Translator"
	GoogleTranslator    Translator = "org.apache.tika.language.translate.GoogleTranslator"
	MosesTranslator     Translator = "org.apache.tika.language.translate.MosesTranslator"
	JoshuaTranslator    Translator = "org.apache.tika.language.translate.JoshuaTranslator"
	MicrosoftTranslator Translator = "org.apache.tika.language.translate.MicrosoftTranslator"
	YandexTranslator    Translator = "org.apache.tika.language.translate.YandexTranslator"
)

// XTIKAContent is the metadata field of the content of a file after recursive
// parsing. See ParseRecursive and MetaRecursive.
const XTIKAContent = "X-TIKA:content"

// call makes the given request to c and returns the result as a []byte and
// error. call returns an error if the response code is not 200 StatusOK.
func (c *Client) call(ctx context.Context, input io.Reader, method, path string, header http.Header) ([]byte, error) {
	if c.httpClient == nil {
		c.httpClient = http.DefaultClient
	}

	req, err := http.NewRequest(method, c.url+path, input)
	if err != nil {
		return nil, err
	}
	req.Header = header

	resp, err := ctxhttp.Do(ctx, c.httpClient, req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("response code %v", resp.StatusCode)
	}
	return ioutil.ReadAll(resp.Body)
}

// callString makes the given request to c and returns the result as a string
// and error. callString returns an error if the response code is not 200 StatusOK.
func (c *Client) callString(ctx context.Context, input io.Reader, method, path string, header http.Header) (string, error) {
	body, err := c.call(ctx, input, method, path, header)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// Parse parses the given input, returning the body of the input and an error.
// If the error is not nil, the body is undefined.
func (c *Client) Parse(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/tika", nil)
}

// ParseRecursive parses the given input and all embedded documents, returning a
// list of the contents of the input with one element per document. See
// MetaRecursive for access to all metadata fields. If the error is not nil, the
// result is undefined.
func (c *Client) ParseRecursive(ctx context.Context, input io.Reader) ([]string, error) {
	m, err := c.MetaRecursive(ctx, input)
	if err != nil {
		return nil, err
	}
	var r []string
	for _, d := range m {
		if content := d[XTIKAContent]; len(content) > 0 {
			r = append(r, content[0])
		}
	}
	return r, nil
}

// Meta parses the metadata from the given input, returning the metadata and an
// error. If the error is not nil, the metadata is undefined.
func (c *Client) Meta(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/meta", nil)
}

// MetaField parses the metadata from the given input and returns the given
// field. If the error is not nil, the result string is undefined.
func (c *Client) MetaField(ctx context.Context, input io.Reader, field string) (string, error) {
	return c.callString(ctx, input, "PUT", fmt.Sprintf("/meta/%v", field), nil)
}

// Detect gets the mimetype of the given input, returning the mimetype and an
// error. If the error is not nil, the mimetype is undefined.
func (c *Client) Detect(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/detect/stream", nil)
}

// Language detects the language of the given input, returning the two letter
// language code and an error. If the error is not nil, the language is
// undefined.
func (c *Client) Language(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/language/stream", nil)
}

// LanguageString detects the language of the given string, returning the two letter
// language code and an error. If the error is not nil, the language is
// undefined.
func (c *Client) LanguageString(ctx context.Context, input string) (string, error) {
	r := strings.NewReader(input)
	return c.callString(ctx, r, "PUT", "/language/string", nil)
}

// MetaRecursive parses the given input and all embedded documents. The result
// is a list of maps from metadata key to value for each document. The content
// of each document is in the XTIKAContent field. See ParseRecursive to just get
// the content of each document. If the error is not nil, the result list is
// undefined.
func (c *Client) MetaRecursive(ctx context.Context, input io.Reader) ([]map[string][]string, error) {
	body, err := c.call(ctx, input, "PUT", "/rmeta/text", nil)
	if err != nil {
		return nil, err
	}
	var m []map[string]interface{}
	if err := json.Unmarshal(body, &m); err != nil {
		return nil, err
	}
	var r []map[string][]string
	for _, d := range m {
		doc := make(map[string][]string)
		r = append(r, doc)
		for k, v := range d {
			switch vt := v.(type) {
			case string:
				doc[k] = []string{vt}
			case []interface{}:
				for _, i := range vt {
					s, ok := i.(string)
					if !ok {
						return nil, fmt.Errorf("field %q has value %v and type %T, expected a string or []string", k, v, vt)
					}
					doc[k] = append(doc[k], s)
				}
			default:
				return nil, fmt.Errorf("field %q has value %v and type %v, expected a string or []string", k, v, reflect.TypeOf(v))
			}
		}
	}
	return r, nil
}

// Translate returns an error and the translated input from src language to
// dst language using t. If the error is not nil, the translation is undefined.
func (c *Client) Translate(ctx context.Context, input io.Reader, t Translator, src, dst string) (string, error) {
	return c.callString(ctx, input, "POST", fmt.Sprintf("/translate/all/%s/%s/%s", t, src, dst), nil)
}

// Version returns the default hello message from Tika server.
func (c *Client) Version(ctx context.Context) (string, error) {
	return c.callString(ctx, nil, "GET", "/version", nil)
}

var jsonHeader = http.Header{"Accept": []string{"application/json"}}

// callUnmarshal is like call, but unmarshals the JSON response into v.
func (c *Client) callUnmarshal(ctx context.Context, method, path string, header http.Header, v interface{}) error {
	body, err := c.call(ctx, nil, method, path, header)
	if err != nil {
		return err
	}
	return json.Unmarshal(body, v)
}

// Parsers returns the list of available parsers and an error. If the error is
// not nil, the list is undefined. To get all available parsers, iterate through
// the Children of every Parser.
func (c *Client) Parsers(ctx context.Context) (*Parser, error) {
	p := new(Parser)
	if err := c.callUnmarshal(ctx, "GET", "/parsers/details", jsonHeader, p); err != nil {
		return nil, err
	}
	return p, nil
}

// MIMETypes returns a map from MIME Type name to MIMEType, or properties about
// that specific MIMEType.
func (c *Client) MIMETypes(ctx context.Context) (map[string]MIMEType, error) {
	mt := new(map[string]MIMEType)
	if err := c.callUnmarshal(ctx, "GET", "/mime-types", jsonHeader, mt); err != nil {
		return nil, err
	}
	return *mt, nil
}

// Detectors returns the list of available Detectors for this server. To get all
// available detectors, iterate through the Children of every Detector.
func (c *Client) Detectors(ctx context.Context) (*Detector, error) {
	d := new(Detector)
	if err := c.callUnmarshal(ctx, "GET", "/detectors", jsonHeader, d); err != nil {
		return nil, err
	}
	return d, nil
}
<commit_msg>Remove unneeded params from callUnmarshal<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

package tika

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"

	"golang.org/x/net/context/ctxhttp"
)

// Client represents a connection to a Tika Server.
type Client struct {
	// url is the URL of the Tika Server, including the port (if necessary), but
	// not the trailing slash. For example, http://localhost:9998.
	url string
	// HTTPClient is the client that will be used to call the Tika Server. If no
	// client is specified, a default client will be used. Since http.Clients are
	// thread safe, the same client will be used for all requests by this Client.
	httpClient *http.Client
}

// NewClient creates a new Client. If httpClient is nil, the http.DefaultClient will be
// used.
func NewClient(httpClient *http.Client, urlString string) *Client {
	return &Client{httpClient: httpClient, url: urlString}
}

// A Parser represents a Tika Parser. To get a list of all Parsers, see Parsers().
type Parser struct {
	Name           string
	Decorated      bool
	Composite      bool
	Children       []Parser
	SupportedTypes []string
}

// MIMEType represents a Tika Mime Type. To get a list of all MIMETypes, see
// MimeTypes.
type MIMEType struct {
	Alias     []string
	SuperType string
}

// A Detector represents a Tika Detector. Detectors are used to get the filetype
// of a file. To get a list of all Detectors, see Detectors().
type Detector struct {
	Name      string
	Composite bool
	Children  []Detector
}

// Translator represents the Java package of a Tika Translator.
type Translator string

// Translators available by defult in Tika. You must configure all required
// authentication details in Tika Server (for example, an API key).
const (
	Lingo24Translator   Translator = "org.apache.tika.language.translate.Lingo24Translator"
	GoogleTranslator    Translator = "org.apache.tika.language.translate.GoogleTranslator"
	MosesTranslator     Translator = "org.apache.tika.language.translate.MosesTranslator"
	JoshuaTranslator    Translator = "org.apache.tika.language.translate.JoshuaTranslator"
	MicrosoftTranslator Translator = "org.apache.tika.language.translate.MicrosoftTranslator"
	YandexTranslator    Translator = "org.apache.tika.language.translate.YandexTranslator"
)

// XTIKAContent is the metadata field of the content of a file after recursive
// parsing. See ParseRecursive and MetaRecursive.
const XTIKAContent = "X-TIKA:content"

// call makes the given request to c and returns the result as a []byte and
// error. call returns an error if the response code is not 200 StatusOK.
func (c *Client) call(ctx context.Context, input io.Reader, method, path string, header http.Header) ([]byte, error) {
	if c.httpClient == nil {
		c.httpClient = http.DefaultClient
	}

	req, err := http.NewRequest(method, c.url+path, input)
	if err != nil {
		return nil, err
	}
	req.Header = header

	resp, err := ctxhttp.Do(ctx, c.httpClient, req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("response code %v", resp.StatusCode)
	}
	return ioutil.ReadAll(resp.Body)
}

// callString makes the given request to c and returns the result as a string
// and error. callString returns an error if the response code is not 200 StatusOK.
func (c *Client) callString(ctx context.Context, input io.Reader, method, path string, header http.Header) (string, error) {
	body, err := c.call(ctx, input, method, path, header)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// Parse parses the given input, returning the body of the input and an error.
// If the error is not nil, the body is undefined.
func (c *Client) Parse(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/tika", nil)
}

// ParseRecursive parses the given input and all embedded documents, returning a
// list of the contents of the input with one element per document. See
// MetaRecursive for access to all metadata fields. If the error is not nil, the
// result is undefined.
func (c *Client) ParseRecursive(ctx context.Context, input io.Reader) ([]string, error) {
	m, err := c.MetaRecursive(ctx, input)
	if err != nil {
		return nil, err
	}
	var r []string
	for _, d := range m {
		if content := d[XTIKAContent]; len(content) > 0 {
			r = append(r, content[0])
		}
	}
	return r, nil
}

// Meta parses the metadata from the given input, returning the metadata and an
// error. If the error is not nil, the metadata is undefined.
func (c *Client) Meta(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/meta", nil)
}

// MetaField parses the metadata from the given input and returns the given
// field. If the error is not nil, the result string is undefined.
func (c *Client) MetaField(ctx context.Context, input io.Reader, field string) (string, error) {
	return c.callString(ctx, input, "PUT", fmt.Sprintf("/meta/%v", field), nil)
}

// Detect gets the mimetype of the given input, returning the mimetype and an
// error. If the error is not nil, the mimetype is undefined.
func (c *Client) Detect(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/detect/stream", nil)
}

// Language detects the language of the given input, returning the two letter
// language code and an error. If the error is not nil, the language is
// undefined.
func (c *Client) Language(ctx context.Context, input io.Reader) (string, error) {
	return c.callString(ctx, input, "PUT", "/language/stream", nil)
}

// LanguageString detects the language of the given string, returning the two letter
// language code and an error. If the error is not nil, the language is
// undefined.
func (c *Client) LanguageString(ctx context.Context, input string) (string, error) {
	r := strings.NewReader(input)
	return c.callString(ctx, r, "PUT", "/language/string", nil)
}

// MetaRecursive parses the given input and all embedded documents. The result
// is a list of maps from metadata key to value for each document. The content
// of each document is in the XTIKAContent field. See ParseRecursive to just get
// the content of each document. If the error is not nil, the result list is
// undefined.
func (c *Client) MetaRecursive(ctx context.Context, input io.Reader) ([]map[string][]string, error) {
	body, err := c.call(ctx, input, "PUT", "/rmeta/text", nil)
	if err != nil {
		return nil, err
	}
	var m []map[string]interface{}
	if err := json.Unmarshal(body, &m); err != nil {
		return nil, err
	}
	var r []map[string][]string
	for _, d := range m {
		doc := make(map[string][]string)
		r = append(r, doc)
		for k, v := range d {
			switch vt := v.(type) {
			case string:
				doc[k] = []string{vt}
			case []interface{}:
				for _, i := range vt {
					s, ok := i.(string)
					if !ok {
						return nil, fmt.Errorf("field %q has value %v and type %T, expected a string or []string", k, v, vt)
					}
					doc[k] = append(doc[k], s)
				}
			default:
				return nil, fmt.Errorf("field %q has value %v and type %v, expected a string or []string", k, v, reflect.TypeOf(v))
			}
		}
	}
	return r, nil
}

// Translate returns an error and the translated input from src language to
// dst language using t. If the error is not nil, the translation is undefined.
func (c *Client) Translate(ctx context.Context, input io.Reader, t Translator, src, dst string) (string, error) {
	return c.callString(ctx, input, "POST", fmt.Sprintf("/translate/all/%s/%s/%s", t, src, dst), nil)
}

// Version returns the default hello message from Tika server.
func (c *Client) Version(ctx context.Context) (string, error) {
	return c.callString(ctx, nil, "GET", "/version", nil)
}

var jsonHeader = http.Header{"Accept": []string{"application/json"}}

// callUnmarshal is like call, but unmarshals the JSON response into v.
func (c *Client) callUnmarshal(ctx context.Context, path string, v interface{}) error {
	body, err := c.call(ctx, nil, "GET", path, jsonHeader)
	if err != nil {
		return err
	}
	return json.Unmarshal(body, v)
}

// Parsers returns the list of available parsers and an error. If the error is
// not nil, the list is undefined. To get all available parsers, iterate through
// the Children of every Parser.
func (c *Client) Parsers(ctx context.Context) (*Parser, error) {
	p := new(Parser)
	if err := c.callUnmarshal(ctx, "/parsers/details", p); err != nil {
		return nil, err
	}
	return p, nil
}

// MIMETypes returns a map from MIME Type name to MIMEType, or properties about
// that specific MIMEType.
func (c *Client) MIMETypes(ctx context.Context) (map[string]MIMEType, error) {
	mt := make(map[string]MIMEType)
	if err := c.callUnmarshal(ctx, "/mime-types", &mt); err != nil {
		return nil, err
	}
	return mt, nil
}

// Detectors returns the list of available Detectors for this server. To get all
// available detectors, iterate through the Children of every Detector.
func (c *Client) Detectors(ctx context.Context) (*Detector, error) {
	d := new(Detector)
	if err := c.callUnmarshal(ctx, "/detectors", d); err != nil {
		return nil, err
	}
	return d, nil
}
<|endoftext|>


<commit_before>package libgomessage

import (
	"errors"
	"time"
	notifylib "github.com/mqu/go-notify"
)

type notify struct {
	abstractSender

	delay int32
	icon string
}

func NewNotify() *notify {
	n := &notify{ }
	n.InitAbstract()
	return n
}

func (n *notify) Send(message *Message, to ToInterface) {
	var notifyWindow *notifylib.NotifyNotification
	var e error = nil
	if e = n.verify(message); e != nil {
		goto out
	}

	notifylib.Init(message.Title)
	notifyWindow = notifylib.NotificationNew(message.Title,
				message.Message, message.Icon)

	if notifyWindow == nil {
		e = errors.New("Unable to create a new notification")
		goto cleanUp
	}

	notifyWindow.SetTimeout(n.delay)

	if glibe := notifyWindow.Show(); glibe != nil {
		// ignore empty error strings
		if glibe.Error() != "" {
			e = errors.New("Cannot show notification! '" +
					glibe.Error() + "'")
			goto cleanUp
		}
	}

out:
	if e != nil {
		n.result <- &Message{ Result: FAILURE, ErrorString: e.Error() }
	} else {
		n.result <- &Message{ Result: SUCCESS }
	}

cleanUp:
	time.Sleep(time.Duration(n.delay) * time.Millisecond)
	notifyWindow.Close()
	notifylib.UnInit()
}

func (n *notify) GetTo() ToInterface {
	return NewTo()
}

func (n *notify) verify(message *Message) error {
	if message.Title == "" {
		return errors.New("No title given!")
	}

	if message.Message == "" {
		return errors.New("No message given!")
	}

	for _, attachment := range message.Attachments {
		if x, ok := attachment.(AttachmentLibNotifyInterface); ok {
			n.delay = x.GetDelay();
		}
		if x, ok := attachment.(AttachmentIconInterface); ok {
			n.icon = x.GetIcon()
			if n.icon == "" {
				n.icon = x.GetIconPath()
			}
		}
	}
	if n.delay <= 0 {
		//return errors.New("Delay must be greater then 0!")
		n.delay = 10000
	}

	return nil
}
<commit_msg>bugfix notify<commit_after>package libgomessage

import (
	"errors"
	"time"
	notifylib "github.com/mqu/go-notify"
)

type notify struct {
	abstractSender

	delay int32
	icon string
}

func NewNotify() *notify {
	n := &notify{ }
	n.InitAbstract()
	return n
}

func (n *notify) Send(message *Message, to ToInterface) {
	var notifyWindow *notifylib.NotifyNotification
	var e error = nil
	if e = n.verify(message); e != nil {
		goto out
	}

	notifylib.Init(message.Title)
	notifyWindow = notifylib.NotificationNew(message.Title,
				message.Message, message.Icon)

	if notifyWindow == nil {
		e = errors.New("Unable to create a new notification")
		goto out
	}

	notifyWindow.SetTimeout(n.delay)

	if glibe := notifyWindow.Show(); glibe != nil {
		// ignore empty error strings
		if glibe.Error() != "" {
			e = errors.New("Cannot show notification! '" +
					glibe.Error() + "'")
			goto out
		}
	}

out:
	if e != nil {
		n.result <- &Message{ Result: FAILURE, ErrorString: e.Error() }
	} else {
		n.result <- &Message{ Result: SUCCESS }
	}

	time.Sleep(time.Duration(n.delay) * time.Millisecond)
	notifyWindow.Close()
	notifylib.UnInit()
}

func (n *notify) GetTo() ToInterface {
	return NewTo()
}

func (n *notify) verify(message *Message) error {
	if message.Title == "" {
		return errors.New("No title given!")
	}

	if message.Message == "" {
		return errors.New("No message given!")
	}

	for _, attachment := range message.Attachments {
		if x, ok := attachment.(AttachmentLibNotifyInterface); ok {
			n.delay = x.GetDelay();
		}
		if x, ok := attachment.(AttachmentIconInterface); ok {
			n.icon = x.GetIcon()
			if n.icon == "" {
				n.icon = x.GetIconPath()
			}
		}
	}
	if n.delay <= 0 {
		//return errors.New("Delay must be greater then 0!")
		n.delay = 10000
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Matthias S. Benkmann

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA  02110-1301, USA.
*/

// Various re-usable utility functions.
package util

import "time"

// Offset that has to be added to a UTC time so that after converting it to Local
// the time is numerically the same. This is a workaround for the problem that you
// can't pass a separate Location to time.Parse() so that if (as is the case with
// siserver timestamps) the string being parsed doesn't contain location information
// the result is always in UTC and using .Local() changes the time.
var local_offset time.Duration
func init() {
  _, ofs := time.Now().Zone()
  local_offset = -time.Duration(ofs) * time.Second
}

// Converts t into a timestamp appropriate for use in siserver messages.
// The timestamp is always in local time, even if t is not.
func MakeTimestamp(t time.Time) string {
  return t.Local().Format("20060102150405")
}

// Converts a timestamp as used in siserver messages into a time.Time.
// Returns time.Unix(0,0) if the timestamp is invalid.
func ParseTimestamp(ts string) time.Time {
  t, err := time.Parse("20060102150405", ts)
  if err != nil {
    Log(0, "ERROR! Illegal timestamp: %v", ts)
    return time.Unix(0,0)
  }
  return t.Add(local_offset).Local()
}
<commit_msg>I hope I handle this winter/summer time crap correctly now in timestamps<commit_after>/*
Copyright (c) 2012 Matthias S. Benkmann

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA  02110-1301, USA.
*/

// Various re-usable utility functions.
package util

import "time"

// Converts t into a timestamp appropriate for use in siserver messages.
// The timestamp loses the time zone information of t. No time zone
// conversion will be performed. IOW "12:00 UTC" and "12:00 PDT" will
// both result in a timestamp that says "yyyymmdd1200ss".
func MakeTimestamp(t time.Time) string {
  return t.Format("20060102150405")
}

// Converts a timestamp as used in siserver messages into a time.Time.
// The returned time will be the time at which the server clock's current
// time converted with MakeTimestamp() is ts. The computation is based on
// the assumption that the server's time zone does not change EXCEPT for
// daylight savings time. IOW on a server running on local time in Berlin
// ParseTimestamp("20140101120000") gives 12:00 CET (winter time) and
// ParseTimestamp("20140601120000") gives 12:00 CEST (summer time).
//
// ParseTimestamp() returns time.Unix(0,0) if the timestamp is invalid.
func ParseTimestamp(ts string) time.Time {
  t, err := time.Parse("20060102150405", ts)
  if err != nil {
    Log(0, "ERROR! Illegal timestamp: %v", ts)
    return time.Unix(0,0)
  }

  // The timestamp doesn't contain information about the time zone it
  // is in, so time.Parse() has interpreted it as UTC. In order to
  // properly get a time in local time, we need to first determine
  // the code of the time zone active at the requested time. Then
  // we reparse with that time zone code appended.
  zone,_ := t.Local().Zone()
  ts += zone
  t, err = time.Parse("20060102150405MST", ts)
  if err != nil {
    Log(0, "ERROR! Could not parse with time zone: %v", ts)
    return time.Unix(0,0)
  }
  return t
}
<|endoftext|>


<commit_before>package tlsconfig

import (
	"crypto/tls"
	"encoding/hex"
	"fmt"
	"strings"
)

//********** ProtocolType

type TLSProtocolVersion uint16

func (pv TLSProtocolVersion) String() string {
	switch pv {
	case tls.VersionSSL30:
		return "SSLv3"
	case tls.VersionTLS10:
		return "TLSv1"
	case tls.VersionTLS11:
		return "TLSv1.1"
	case tls.VersionTLS12:
		return "TLSv1.2"
	}
	return "unknown tls protocol"
}

func (pv *TLSProtocolVersion) fromString(str string) (err error) {
	switch strings.ToUpper(str) {
	case "SSLV3":
		*pv = tls.VersionSSL30
	case "TLSV1":
		*pv = tls.VersionTLS10
	case "TLSV1.1":
		*pv = tls.VersionTLS11
	case "TLSV1.2":
		*pv = tls.VersionTLS12
	default:
		return fmt.Errorf("invalid tls protocol version: '" + str + "'")
	}
	return
}

func (pv TLSProtocolVersion) MarshalText() (data []byte, err error) {
	data = []byte(pv.String())
	return
}

func (pv *TLSProtocolVersion) UnmarshalText(data []byte) (err error) {
	return pv.fromString(string(data))
}

//********** CipherSuite

type TLSCipherSuite uint16

func (cs TLSCipherSuite) String() string {
	switch uint16(cs) {
	case tls.TLS_RSA_WITH_RC4_128_SHA:
		return "RSA_WITH_RC4_128_SHA"
	case tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
		return "RSA_WITH_3DES_EDE_CBC_SHA"
	case tls.TLS_RSA_WITH_AES_128_CBC_SHA:
		return "RSA_WITH_AES_128_CBC_SHA"
	case tls.TLS_RSA_WITH_AES_256_CBC_SHA:
		return "RSA_WITH_AES_256_CBC_SHA"
	case tls.TLS_RSA_WITH_AES_128_CBC_SHA256:
		return "RSA_WITH_AES_128_CBC_SHA256"
	case tls.TLS_RSA_WITH_AES_128_GCM_SHA256:
		return "RSA_WITH_AES_128_GCM_SHA256"
	case tls.TLS_RSA_WITH_AES_256_GCM_SHA384:
		return "RSA_WITH_AES_256_GCM_SHA384"
	case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
		return "ECDHE_ECDSA_WITH_RC4_128_SHA"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
		return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
		return "ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
	case tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
		return "ECDHE_RSA_WITH_RC4_128_SHA"
	case tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
		return "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
	case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
		return "ECDHE_RSA_WITH_AES_128_CBC_SHA"
	case tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
		return "ECDHE_RSA_WITH_AES_256_CBC_SHA"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
		return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
	case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
		return "ECDHE_RSA_WITH_AES_128_CBC_SHA256"
	case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
		return "ECDHE_RSA_WITH_AES_128_GCM_SHA256"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
		return "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
	case tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
		return "ECDHE_RSA_WITH_AES_256_GCM_SHA384"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
		return "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
	case tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:
		return "ECDHE_RSA_WITH_CHACHA20_POLY1305"
	case tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
		return "ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
	}
	return "unknown tls cipher suite"
}

func (cs *TLSCipherSuite) fromString(str string) (err error) {
	switch strings.Replace(strings.ToUpper(str), "-", "_", -1) {
	case "RSA_WITH_RC4_128_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_RC4_128_SHA)
	case "RSA_WITH_3DES_EDE_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
	case "RSA_WITH_AES_128_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA)
	case "RSA_WITH_AES_256_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_256_CBC_SHA)
	case "RSA_WITH_AES_128_CBC_SHA256":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA256)
	case "RSA_WITH_AES_128_GCM_SHA256":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
	case "RSA_WITH_AES_256_GCM_SHA384":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
	case "ECDHE_ECDSA_WITH_RC4_128_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
	case "ECDHE_ECDSA_WITH_AES_128_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
	case "ECDHE_ECDSA_WITH_AES_256_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
	case "ECDHE_RSA_WITH_RC4_128_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
	case "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
	case "ECDHE_RSA_WITH_AES_128_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
	case "ECDHE_RSA_WITH_AES_256_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
	case "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
	case "ECDHE_RSA_WITH_AES_128_CBC_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
	case "ECDHE_RSA_WITH_AES_128_GCM_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
	case "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
	case "ECDHE_RSA_WITH_AES_256_GCM_SHA384":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
	case "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
	case "ECDHE_RSA_WITH_CHACHA20_POLY1305":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305)
	case "ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
	default:
		return fmt.Errorf("invalid tls cipher suite: '" + str + "'")
	}
	return
}

func (cs TLSCipherSuite) MarshalText() (data []byte, err error) {
	data = []byte(cs.String())
	return
}

func (cs *TLSCipherSuite) UnmarshalText(data []byte) (err error) {
	return cs.fromString(string(data))
}

//********** TLSCurve

type TLSCurve tls.CurveID

func (c TLSCurve) String() string {
	switch tls.CurveID(c) {
	case tls.CurveP256:
		return "secp256r1"
	case tls.CurveP384:
		return "secp384r1"
	case tls.CurveP521:
		return "secp521r1"
	case tls.X25519:
		return "x25519"
	}
	return "unknown tls echd curve"
}

func (c *TLSCurve) fromString(str string) (err error) {
	switch strings.ToLower(str) {
	case "prime256v1":
		fallthrough
	case "secp256r1":
		*c = TLSCurve(tls.CurveP256)
	case "prime384v1":
		fallthrough
	case "secp384r1":
		*c = TLSCurve(tls.CurveP384)
	case "prime521v1":
		fallthrough
	case "secp521r1":
		*c = TLSCurve(tls.CurveP521)
	case "x25519":
		*c = TLSCurve(tls.X25519)
	default:
		return fmt.Errorf("invalid tls ecdh curve: '" + str + "'")
	}
	return
}

func (c TLSCurve) MarshalText() (data []byte, err error) {
	data = []byte(c.String())
	return
}

func (c *TLSCurve) UnmarshalText(data []byte) (err error) {
	return c.fromString(string(data))
}

//********** TLSSessionTicketKey

type TLSSessionTicketKey [32]byte

func (stk TLSSessionTicketKey) String() string {
	return hex.EncodeToString([]byte(stk[:]))
}

func (stk *TLSSessionTicketKey) fromString(str string) error {
	key, err := hex.DecodeString(str)
	if err != nil {
		return fmt.Errorf("invalid tls session ticket key: %v", err)
	}
	if len(key) != len(stk) {
		return fmt.Errorf("invalid tls session ticket key length: got %d bytes, expected %d bytes", len(key), len(stk))
	}
	copy(stk[:], key)
	return nil
}

func (stk TLSSessionTicketKey) MarshalText() (data []byte, err error) {
	data = []byte(stk.String())
	return
}

func (stk *TLSSessionTicketKey) UnmarshalText(data []byte) (err error) {
	return stk.fromString(string(data))
}

//********** TLSConfig

type TLSConfig struct {
	CertFile                 string              `json:"certificate" yaml:"certificate" toml:"certificate"`
	KeyFile                  string              `json:"certificate-key" yaml:"certificate-key" toml:"certificate-key"`
	MinVersion               TLSProtocolVersion  `json:"min-protocol-version" yaml:"min-protocol-version" toml:"min-protocol-version"`
	MaxVersion               TLSProtocolVersion  `json:"max-protocol-version" yaml:"max-protocol-version" toml:"max-protocol-version"`
	CipherSuites             []TLSCipherSuite    `json:"ciphers" yaml:"ciphers" toml:"ciphers"`
	PreferServerCipherSuites bool                `json:"prefer-server-ciphers" yaml:"prefer-server-ciphers" toml:"prefer-server-ciphers"`
	CurvePreferences         []TLSCurve          `json:"ecdh-curves" yaml:"ecdh-curves" toml:"ecdh-curves"`
	SessionTickets           bool                `json:"session-tickets" yaml:"session-tickets" toml:"session-tickets"`
	SessionTicketKey         TLSSessionTicketKey `json:"session-ticket-key" yaml:"session-ticket-key" toml:"session-ticket-key"`
}

func (t TLSConfig) ToGoTLSConfig() (*tls.Config, error) {
	cert, err := tls.LoadX509KeyPair(t.CertFile, t.KeyFile)
	if err != nil {
		return nil, err
	}

	cfg := &tls.Config{Certificates: []tls.Certificate{cert}}
	cfg.MinVersion = uint16(t.MinVersion)
	cfg.MaxVersion = uint16(t.MaxVersion)
	for _, cs := range t.CipherSuites {
		cfg.CipherSuites = append(cfg.CipherSuites, uint16(cs))
	}
	cfg.PreferServerCipherSuites = t.PreferServerCipherSuites
	for _, cp := range t.CurvePreferences {
		cfg.CurvePreferences = append(cfg.CurvePreferences, tls.CurveID(cp))
	}
	cfg.SessionTicketsDisabled = !t.SessionTickets
	cfg.SessionTicketKey = [32]byte(t.SessionTicketKey)

	return cfg, nil
}
<commit_msg>expose FromString Functions<commit_after>package tlsconfig

import (
	"crypto/tls"
	"encoding/hex"
	"fmt"
	"strings"
)

//********** ProtocolType

type TLSProtocolVersion uint16

func (pv TLSProtocolVersion) String() string {
	switch pv {
	case tls.VersionSSL30:
		return "SSLv3"
	case tls.VersionTLS10:
		return "TLSv1"
	case tls.VersionTLS11:
		return "TLSv1.1"
	case tls.VersionTLS12:
		return "TLSv1.2"
	}
	return "unknown tls protocol"
}

func (pv *TLSProtocolVersion) FromString(str string) (err error) {
	switch strings.ToUpper(str) {
	case "SSLV3":
		*pv = tls.VersionSSL30
	case "TLSV1":
		*pv = tls.VersionTLS10
	case "TLSV1.1":
		*pv = tls.VersionTLS11
	case "TLSV1.2":
		*pv = tls.VersionTLS12
	default:
		return fmt.Errorf("invalid tls protocol version: '" + str + "'")
	}
	return
}

func (pv TLSProtocolVersion) MarshalText() (data []byte, err error) {
	data = []byte(pv.String())
	return
}

func (pv *TLSProtocolVersion) UnmarshalText(data []byte) (err error) {
	return pv.FromString(string(data))
}

//********** CipherSuite

type TLSCipherSuite uint16

func (cs TLSCipherSuite) String() string {
	switch uint16(cs) {
	case tls.TLS_RSA_WITH_RC4_128_SHA:
		return "RSA_WITH_RC4_128_SHA"
	case tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
		return "RSA_WITH_3DES_EDE_CBC_SHA"
	case tls.TLS_RSA_WITH_AES_128_CBC_SHA:
		return "RSA_WITH_AES_128_CBC_SHA"
	case tls.TLS_RSA_WITH_AES_256_CBC_SHA:
		return "RSA_WITH_AES_256_CBC_SHA"
	case tls.TLS_RSA_WITH_AES_128_CBC_SHA256:
		return "RSA_WITH_AES_128_CBC_SHA256"
	case tls.TLS_RSA_WITH_AES_128_GCM_SHA256:
		return "RSA_WITH_AES_128_GCM_SHA256"
	case tls.TLS_RSA_WITH_AES_256_GCM_SHA384:
		return "RSA_WITH_AES_256_GCM_SHA384"
	case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
		return "ECDHE_ECDSA_WITH_RC4_128_SHA"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
		return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
		return "ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
	case tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
		return "ECDHE_RSA_WITH_RC4_128_SHA"
	case tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
		return "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
	case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
		return "ECDHE_RSA_WITH_AES_128_CBC_SHA"
	case tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
		return "ECDHE_RSA_WITH_AES_256_CBC_SHA"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
		return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
	case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
		return "ECDHE_RSA_WITH_AES_128_CBC_SHA256"
	case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
		return "ECDHE_RSA_WITH_AES_128_GCM_SHA256"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
		return "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
	case tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
		return "ECDHE_RSA_WITH_AES_256_GCM_SHA384"
	case tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
		return "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
	case tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:
		return "ECDHE_RSA_WITH_CHACHA20_POLY1305"
	case tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
		return "ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
	}
	return "unknown tls cipher suite"
}

func (cs *TLSCipherSuite) FromString(str string) (err error) {
	switch strings.Replace(strings.ToUpper(str), "-", "_", -1) {
	case "RSA_WITH_RC4_128_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_RC4_128_SHA)
	case "RSA_WITH_3DES_EDE_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
	case "RSA_WITH_AES_128_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA)
	case "RSA_WITH_AES_256_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_256_CBC_SHA)
	case "RSA_WITH_AES_128_CBC_SHA256":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA256)
	case "RSA_WITH_AES_128_GCM_SHA256":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
	case "RSA_WITH_AES_256_GCM_SHA384":
		*cs = TLSCipherSuite(tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
	case "ECDHE_ECDSA_WITH_RC4_128_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
	case "ECDHE_ECDSA_WITH_AES_128_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
	case "ECDHE_ECDSA_WITH_AES_256_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
	case "ECDHE_RSA_WITH_RC4_128_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
	case "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
	case "ECDHE_RSA_WITH_AES_128_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
	case "ECDHE_RSA_WITH_AES_256_CBC_SHA":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
	case "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
	case "ECDHE_RSA_WITH_AES_128_CBC_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
	case "ECDHE_RSA_WITH_AES_128_GCM_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
	case "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
	case "ECDHE_RSA_WITH_AES_256_GCM_SHA384":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
	case "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
	case "ECDHE_RSA_WITH_CHACHA20_POLY1305":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305)
	case "ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
		*cs = TLSCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
	default:
		return fmt.Errorf("invalid tls cipher suite: '" + str + "'")
	}
	return
}

func (cs TLSCipherSuite) MarshalText() (data []byte, err error) {
	data = []byte(cs.String())
	return
}

func (cs *TLSCipherSuite) UnmarshalText(data []byte) (err error) {
	return cs.FromString(string(data))
}

//********** TLSCurve

type TLSCurve tls.CurveID

func (c TLSCurve) String() string {
	switch tls.CurveID(c) {
	case tls.CurveP256:
		return "secp256r1"
	case tls.CurveP384:
		return "secp384r1"
	case tls.CurveP521:
		return "secp521r1"
	case tls.X25519:
		return "x25519"
	}
	return "unknown tls echd curve"
}

func (c *TLSCurve) FromString(str string) (err error) {
	switch strings.ToLower(str) {
	case "prime256v1":
		fallthrough
	case "secp256r1":
		*c = TLSCurve(tls.CurveP256)
	case "prime384v1":
		fallthrough
	case "secp384r1":
		*c = TLSCurve(tls.CurveP384)
	case "prime521v1":
		fallthrough
	case "secp521r1":
		*c = TLSCurve(tls.CurveP521)
	case "x25519":
		*c = TLSCurve(tls.X25519)
	default:
		return fmt.Errorf("invalid tls ecdh curve: '" + str + "'")
	}
	return
}

func (c TLSCurve) MarshalText() (data []byte, err error) {
	data = []byte(c.String())
	return
}

func (c *TLSCurve) UnmarshalText(data []byte) (err error) {
	return c.FromString(string(data))
}

//********** TLSSessionTicketKey

type TLSSessionTicketKey [32]byte

func (stk TLSSessionTicketKey) String() string {
	return hex.EncodeToString([]byte(stk[:]))
}

func (stk *TLSSessionTicketKey) FromString(str string) error {
	key, err := hex.DecodeString(str)
	if err != nil {
		return fmt.Errorf("invalid tls session ticket key: %v", err)
	}
	if len(key) != len(stk) {
		return fmt.Errorf("invalid tls session ticket key length: got %d bytes, expected %d bytes", len(key), len(stk))
	}
	copy(stk[:], key)
	return nil
}

func (stk TLSSessionTicketKey) MarshalText() (data []byte, err error) {
	data = []byte(stk.String())
	return
}

func (stk *TLSSessionTicketKey) UnmarshalText(data []byte) (err error) {
	return stk.FromString(string(data))
}

//********** TLSConfig

type TLSConfig struct {
	CertFile                 string              `json:"certificate" yaml:"certificate" toml:"certificate"`
	KeyFile                  string              `json:"certificate-key" yaml:"certificate-key" toml:"certificate-key"`
	MinVersion               TLSProtocolVersion  `json:"min-protocol-version" yaml:"min-protocol-version" toml:"min-protocol-version"`
	MaxVersion               TLSProtocolVersion  `json:"max-protocol-version" yaml:"max-protocol-version" toml:"max-protocol-version"`
	CipherSuites             []TLSCipherSuite    `json:"ciphers" yaml:"ciphers" toml:"ciphers"`
	PreferServerCipherSuites bool                `json:"prefer-server-ciphers" yaml:"prefer-server-ciphers" toml:"prefer-server-ciphers"`
	CurvePreferences         []TLSCurve          `json:"ecdh-curves" yaml:"ecdh-curves" toml:"ecdh-curves"`
	SessionTickets           bool                `json:"session-tickets" yaml:"session-tickets" toml:"session-tickets"`
	SessionTicketKey         TLSSessionTicketKey `json:"session-ticket-key" yaml:"session-ticket-key" toml:"session-ticket-key"`
}

func (t TLSConfig) ToGoTLSConfig() (*tls.Config, error) {
	cert, err := tls.LoadX509KeyPair(t.CertFile, t.KeyFile)
	if err != nil {
		return nil, err
	}

	cfg := &tls.Config{Certificates: []tls.Certificate{cert}}
	cfg.MinVersion = uint16(t.MinVersion)
	cfg.MaxVersion = uint16(t.MaxVersion)
	for _, cs := range t.CipherSuites {
		cfg.CipherSuites = append(cfg.CipherSuites, uint16(cs))
	}
	cfg.PreferServerCipherSuites = t.PreferServerCipherSuites
	for _, cp := range t.CurvePreferences {
		cfg.CurvePreferences = append(cfg.CurvePreferences, tls.CurveID(cp))
	}
	cfg.SessionTicketsDisabled = !t.SessionTickets
	cfg.SessionTicketKey = [32]byte(t.SessionTicketKey)

	return cfg, nil
}
<|endoftext|>