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

// pox builds a portable executable as a squashfs image.
// It is intended to create files compatible with tinycore
// tcz files. One of more of the files can be programs
// but that is not required.
// This could have been a simple program but mksquashfs does not
// preserve path information.
// Yeah.
//
// Synopsis:
//     pox [-[-debug]|d] -[-run|r] | -[-create]|c  [-[-file]|f tcz-file] file [...file]
//
// Description:
//     pox makes portable executables in squashfs format compatible with
//     tcz format. We don't build in the execution code, rather, we set it
//     up so we can use the command itself. You can either create the TCZ image
//     or run a command within an image that was previously created.
//
// Options:
//     debug|d: verbose
//     file|f file: file name (default /tmp/pox.tcz)
//     run|r: run a file by loopback mounting the squashfs and using the first arg to pox as the command to run.
//     create|c: create the TCZ file.
//     Exactly one of -c and -r must be used on the same command.
//
// Example:
//	$ pox -c /bin/bash /bin/cat /bin/ls /etc/hosts
//	Will build a squashfs, which will be /tmp/pox.tcz
//
//	$ sudo pox -r /bin/bash
//	Will drop you into the /tmp/pox.tcz running bash
//	You can use ls and cat on /etc/hosts.
//
//	Simpler example:
//	$ sudo pox -r /bin/ls
//	will run ls and exit.
//
// Notes:
// - When running a pox, you likely need sudo to access /dev/loop*.
//
// - Your binaries and programs show up in the TCZ using whatever path you
// provided to pox.  For instance, if you are in /home/you/somedir/ and have
// ./bin/foo, and you pox -c bin/foo, your TCZ will contain bin/foo.  If you
// pox /home/you/somedir/bin/foo, your TCZ will contain the full path.
//
// - When creating a pox with an executable with shared libraries that are not
// installed on your system, such as for a project installed in your home
// directory, run pox from the installation prefix directory, such that the
// libraries and binaries are below pox's working directory.
package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"

	flag "github.com/spf13/pflag"
	"github.com/u-root/u-root/pkg/ldd"
	"github.com/u-root/u-root/pkg/loop"
)

const usage = "pox [-[-debug]|d] -[-run|r] | -[-create]|c  [-[-file]|f tcz-file] file [...file]"

var (
	debug  = flag.BoolP("debug", "d", false, "enable debug prints")
	run    = flag.BoolP("run", "r", false, "Run the first file argument")
	create = flag.BoolP("create", "c", false, "create it")
	file   = flag.StringP("output", "f", "/tmp/pox.tcz", "Output file")
	v      = func(string, ...interface{}) {}
)

func poxCreate(names []string) error {
	if len(names) == 0 {
		return fmt.Errorf(usage)
	}
	l, err := ldd.Ldd(names)
	if err != nil {
		var stderr []byte
		if eerr, ok := err.(*exec.ExitError); ok {
			stderr = eerr.Stderr
		}
		return fmt.Errorf("Running ldd on %v: %v %s", names,
			err, stderr)
	}

	for _, dep := range l {
		v("%s", dep.FullName)
		names = append(names, dep.FullName)
	}
	// Now we need to make a template file hierarchy and put
	// the stuff we want in there.
	dir, err := ioutil.TempDir("", "pox")
	if err != nil {
		return err
	}
	if !*debug {
		defer os.RemoveAll(dir)
	}
	// We don't use defer() here to close files as
	// that can cause open failures with a large enough number.
	for _, f := range names {
		v("Process %v", f)
		fi, err := os.Stat(f)
		if err != nil {
			return err
		}
		in, err := os.Open(f)
		if err != nil {
			return err
		}
		dfile := filepath.Join(dir, f)
		d := filepath.Dir(dfile)
		if err := os.MkdirAll(d, 0755); err != nil {
			in.Close()
			return err
		}
		out, err := os.OpenFile(dfile, os.O_WRONLY|os.O_CREATE,
			fi.Mode().Perm())
		if err != nil {
			in.Close()
			return err
		}
		_, err = io.Copy(out, in)
		in.Close()
		out.Close()
		if err != nil {
			return err
		}

	}
	c := exec.Command("mksquashfs", dir, *file, "-noappend")
	o, err := c.CombinedOutput()
	v("%v", string(o))
	if err != nil {
		return fmt.Errorf("%v: %v: %v", c.Args, string(o), err)
	}
	v("Done, your pox is in %v", *file)

	return nil
}

func poxRun(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf(usage)
	}
	dir, err := ioutil.TempDir("", "pox")
	if err != nil {
		return err
	}
	if !*debug {
		defer os.RemoveAll(dir)
	}

	lo, err := loop.New(*file, "squashfs", "")
	if err != nil {
		return err
	}
	defer lo.Free() //nolint:errcheck

	mountPoint, err := lo.Mount(dir, 0)
	if err != nil {
		return err
	}
	defer mountPoint.Unmount(0) //nolint:errcheck

	c := exec.Command(args[0])
	c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr
	c.SysProcAttr = &syscall.SysProcAttr{
		Chroot: dir,
	}

	if err = c.Run(); err != nil {
		log.Printf("Running test: %v", err)
	}

	return err
}

func pox() error {
	flag.Parse()
	if *debug {
		v = log.Printf
	}
	if (*create && *run) || (!*create && !*run) {
		return fmt.Errorf(usage)
	}
	if *create {
		return poxCreate(flag.Args())
	}
	if *run {
		return poxRun(flag.Args())
	}
	return fmt.Errorf(usage)
}

func main() {
	if err := pox(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>pox: allow arguments to programs we execute<commit_after>// Copyright 2012-2018 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// pox builds a portable executable as a squashfs image.
// It is intended to create files compatible with tinycore
// tcz files. One of more of the files can be programs
// but that is not required.
// This could have been a simple program but mksquashfs does not
// preserve path information.
// Yeah.
//
// Synopsis:
//     pox [-[-debug]|d] [-[-file]|f tcz-file] -[-create]|c FILE [...FILE]
//     pox [-[-debug]|d] [-[-file]|f tcz-file] -[-run|r] PROGRAM -- [...ARGS]
//
// Description:
//     pox makes portable executables in squashfs format compatible with
//     tcz format. We don't build in the execution code, rather, we set it
//     up so we can use the command itself. You can either create the TCZ image
//     or run a command within an image that was previously created.
//
// Options:
//     debug|d: verbose
//     file|f file: file name (default /tmp/pox.tcz)
//     run|r: run a program by loopback mounting the squashfs.  Runs the first
//            non-flag argument to pox.  Remaining arguments will be passed to
//            the program.  Use '--' before any flag-like arguments to prevent
//            pox from interpretting the flags.
//     create|c: create the TCZ file.
//     Exactly one of -c and -r must be used on the same command.
//
// Example:
//	$ pox -c /bin/bash /bin/cat /bin/ls /etc/hosts
//	Will build a squashfs, which will be /tmp/pox.tcz
//
//	$ sudo pox -r /bin/bash
//	Will drop you into the /tmp/pox.tcz running bash
//	You can use ls and cat on /etc/hosts.
//
//	Simpler example, with arguments:
//	$ sudo pox -r /bin/ls -- -la
//	will run `ls -la` and exit.
//
//	$ sudo pox -r -- /bin/ls -la
//	Syntactically easier: the program name can come after '--'
//
// Notes:
// - When running a pox, you likely need sudo to access /dev/loop*.
//
// - Your binaries and programs show up in the TCZ using whatever path you
// provided to pox.  For instance, if you are in /home/you/somedir/ and have
// ./bin/foo, and you pox -c bin/foo, your TCZ will contain bin/foo.  If you
// pox /home/you/somedir/bin/foo, your TCZ will contain the full path.
//
// - When creating a pox with an executable with shared libraries that are not
// installed on your system, such as for a project installed in your home
// directory, run pox from the installation prefix directory, such that the
// libraries and binaries are below pox's working directory.
package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"

	flag "github.com/spf13/pflag"
	"github.com/u-root/u-root/pkg/ldd"
	"github.com/u-root/u-root/pkg/loop"
)

const usage = "pox [-[-debug]|d] -[-run|r] | -[-create]|c  [-[-file]|f tcz-file] file [...file]"

var (
	debug  = flag.BoolP("debug", "d", false, "enable debug prints")
	run    = flag.BoolP("run", "r", false, "Run the first file argument")
	create = flag.BoolP("create", "c", false, "create it")
	file   = flag.StringP("output", "f", "/tmp/pox.tcz", "Output file")
	v      = func(string, ...interface{}) {}
)

func poxCreate(names []string) error {
	if len(names) == 0 {
		return fmt.Errorf(usage)
	}
	l, err := ldd.Ldd(names)
	if err != nil {
		var stderr []byte
		if eerr, ok := err.(*exec.ExitError); ok {
			stderr = eerr.Stderr
		}
		return fmt.Errorf("Running ldd on %v: %v %s", names,
			err, stderr)
	}

	for _, dep := range l {
		v("%s", dep.FullName)
		names = append(names, dep.FullName)
	}
	// Now we need to make a template file hierarchy and put
	// the stuff we want in there.
	dir, err := ioutil.TempDir("", "pox")
	if err != nil {
		return err
	}
	if !*debug {
		defer os.RemoveAll(dir)
	}
	// We don't use defer() here to close files as
	// that can cause open failures with a large enough number.
	for _, f := range names {
		v("Process %v", f)
		fi, err := os.Stat(f)
		if err != nil {
			return err
		}
		in, err := os.Open(f)
		if err != nil {
			return err
		}
		dfile := filepath.Join(dir, f)
		d := filepath.Dir(dfile)
		if err := os.MkdirAll(d, 0755); err != nil {
			in.Close()
			return err
		}
		out, err := os.OpenFile(dfile, os.O_WRONLY|os.O_CREATE,
			fi.Mode().Perm())
		if err != nil {
			in.Close()
			return err
		}
		_, err = io.Copy(out, in)
		in.Close()
		out.Close()
		if err != nil {
			return err
		}

	}
	c := exec.Command("mksquashfs", dir, *file, "-noappend")
	o, err := c.CombinedOutput()
	v("%v", string(o))
	if err != nil {
		return fmt.Errorf("%v: %v: %v", c.Args, string(o), err)
	}
	v("Done, your pox is in %v", *file)

	return nil
}

func poxRun(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf(usage)
	}
	dir, err := ioutil.TempDir("", "pox")
	if err != nil {
		return err
	}
	if !*debug {
		defer os.RemoveAll(dir)
	}

	lo, err := loop.New(*file, "squashfs", "")
	if err != nil {
		return err
	}
	defer lo.Free() //nolint:errcheck

	mountPoint, err := lo.Mount(dir, 0)
	if err != nil {
		return err
	}
	defer mountPoint.Unmount(0) //nolint:errcheck

	c := exec.Command(args[0], args[1:]...)
	c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr
	c.SysProcAttr = &syscall.SysProcAttr{
		Chroot: dir,
	}

	if err = c.Run(); err != nil {
		log.Printf("Running test: %v", err)
	}

	return err
}

func pox() error {
	flag.Parse()
	if *debug {
		v = log.Printf
	}
	if (*create && *run) || (!*create && !*run) {
		return fmt.Errorf(usage)
	}
	if *create {
		return poxCreate(flag.Args())
	}
	if *run {
		return poxRun(flag.Args())
	}
	return fmt.Errorf(usage)
}

func main() {
	if err := pox(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
)

func Main() {
	var (
		src        = kingpin.Arg("SRC", "Flickr SET to sync").Required().String()
		dest       = kingpin.Arg("DEST", "Destination path").String()
		api_key    = kingpin.Flag("api_key", "Flickr API key").String()
		api_secret = kingpin.Flag("api_secret", "Flickr API secret").String()
	)

	kingpin.CommandLine.Help = "A Flickr syncing tool"
	kingpin.Version("0.0.1")

	// read configuration in priority order, first the config file
	config, err := parseConfigFile(getConfigFilePath())
	if err == nil {
		*api_key = config.ApiKey
		*api_secret = config.ApiSecret
	}

	// then the environment vars
	if apik := os.Getenv("FLICKRSYNC_API_KEY"); apik != "" {
		*api_key = apik
	}

	if apisec := os.Getenv("FLICKRSYNC_API_SECRET"); apisec != "" {
		*api_secret = apisec
	}

	// then the command line
	kingpin.Parse()

	// give up if api keys were not provided
	if *api_key == "" || *api_secret == "" {
		fmt.Println("Flickr API keys not found, exiting...")
		os.Exit(1)
	}
	fmt.Println("Would sync", *src, *dest)
	fmt.Println("Apikey:", *api_key, "Apisec:", *api_secret)
}
<commit_msg>print authorization url<commit_after>package command

import (
	"fmt"
	"github.com/masci/flick-rsync/flickr"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
)

func Main() {
	var (
		src        = kingpin.Arg("SRC", "Flickr SET to sync").Required().String()
		dest       = kingpin.Arg("DEST", "Destination path").String()
		api_key    = kingpin.Flag("api_key", "Flickr API key").String()
		api_secret = kingpin.Flag("api_secret", "Flickr API secret").String()
	)

	kingpin.CommandLine.Help = "A Flickr syncing tool"
	kingpin.Version("0.0.1")

	// read configuration in priority order, first the config file
	config, err := parseConfigFile(getConfigFilePath())
	if err == nil {
		*api_key = config.ApiKey
		*api_secret = config.ApiSecret
	}

	// then the environment vars
	if apik := os.Getenv("FLICKRSYNC_API_KEY"); apik != "" {
		*api_key = apik
	}

	if apisec := os.Getenv("FLICKRSYNC_API_SECRET"); apisec != "" {
		*api_secret = apisec
	}

	// then the command line
	kingpin.Parse()

	// give up if api keys were not provided
	if *api_key == "" || *api_secret == "" {
		fmt.Println("Flickr API keys not found, exiting...")
		os.Exit(1)
	}
	fmt.Println("Would sync", *src, *dest)
	fmt.Println("Apikey:", *api_key, "Apisec:", *api_secret)

	// get flickr client
	client := flickr.NewFlickrClient(*api_key, *api_secret)

	tok, err := flickr.GetRequestToken(client)
	fmt.Println(tok)
	url, _ := flickr.GetAuthorizeUrl(client, tok)
	fmt.Println(url)
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"github.com/masci/flick-rsync/flickr"
	"github.com/masci/flick-rsync/flickr/test"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
)

func Main() {
	var (
		src        = kingpin.Arg("SRC", "Flickr SET to sync").Required().String()
		dest       = kingpin.Arg("DEST", "Destination path").String()
		api_key    = kingpin.Flag("api_key", "Flickr API key").String()
		api_secret = kingpin.Flag("api_secret", "Flickr API secret").String()
	)

	kingpin.CommandLine.Help = "A Flickr syncing tool"
	kingpin.Version("0.0.1")

	// read configuration in priority order, first the config file
	config, err := loadConfigFile(getConfigFilePath())
	if err == nil {
		*api_key = config.ApiKey
		*api_secret = config.ApiSecret
	}

	// then the environment vars
	if apik := os.Getenv("FLICKRSYNC_API_KEY"); apik != "" {
		*api_key = apik
	}

	if apisec := os.Getenv("FLICKRSYNC_API_SECRET"); apisec != "" {
		*api_secret = apisec
	}

	// then the command line
	kingpin.Parse()

	// give up if api keys were not provided
	if *api_key == "" || *api_secret == "" {
		fmt.Println("Flickr API keys not found, exiting...")
		os.Exit(1)
	}
	fmt.Println("Would sync", *src, *dest)
	fmt.Println("Apikey:", *api_key, "Apisec:", *api_secret)

	// get flickr client
	client := flickr.NewFlickrClient(*api_key, *api_secret)

	var accessTok *flickr.OAuthToken

	if config.OAuthToken == "" || config.OAuthTokenSecret == "" {
		// get request token
		tok, err := flickr.GetRequestToken(client)
		if err != nil {
			fmt.Println(err)
			os.Exit(2)
		}

		// get access token
		url, _ := flickr.GetAuthorizeUrl(client, tok)
		if err != nil {
			fmt.Println(err)
			os.Exit(3)
		}

		// tell user to authorize the app
		var oauthVerifier string
		fmt.Println("Open your browser at this url:", url)
		fmt.Print("Then, insert the code:")
		fmt.Scanln(&oauthVerifier)

		// get the access token
		accessTok, err = flickr.GetAccessToken(client, tok, oauthVerifier)
		client.OAuthToken = accessTok.OAuthToken
		client.OAuthTokenSecret = accessTok.OAuthTokenSecret
	} else {
		client.OAuthToken = config.OAuthToken
		client.OAuthTokenSecret = config.OAuthTokenSecret
	}

	// test
	resp, err := test.Login(client)
	fmt.Println(resp.Status, resp.User)
	fmt.Println(err)
}
<commit_msg>fixed import paths<commit_after>package command

import (
	"fmt"
	"github.com/masci/flickr.go/flickr"
	"github.com/masci/flickr.go/flickr/test"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
)

func Main() {
	var (
		src        = kingpin.Arg("SRC", "Flickr SET to sync").Required().String()
		dest       = kingpin.Arg("DEST", "Destination path").String()
		api_key    = kingpin.Flag("api_key", "Flickr API key").String()
		api_secret = kingpin.Flag("api_secret", "Flickr API secret").String()
	)

	kingpin.CommandLine.Help = "A Flickr syncing tool"
	kingpin.Version("0.0.1")

	// read configuration in priority order, first the config file
	config, err := loadConfigFile(getConfigFilePath())
	if err == nil {
		*api_key = config.ApiKey
		*api_secret = config.ApiSecret
	}

	// then the environment vars
	if apik := os.Getenv("FLICKRSYNC_API_KEY"); apik != "" {
		*api_key = apik
	}

	if apisec := os.Getenv("FLICKRSYNC_API_SECRET"); apisec != "" {
		*api_secret = apisec
	}

	// then the command line
	kingpin.Parse()

	// give up if api keys were not provided
	if *api_key == "" || *api_secret == "" {
		fmt.Println("Flickr API keys not found, exiting...")
		os.Exit(1)
	}
	fmt.Println("Would sync", *src, *dest)
	fmt.Println("Apikey:", *api_key, "Apisec:", *api_secret)

	// get flickr client
	client := flickr.NewFlickrClient(*api_key, *api_secret)

	var accessTok *flickr.OAuthToken

	if config.OAuthToken == "" || config.OAuthTokenSecret == "" {
		// get request token
		tok, err := flickr.GetRequestToken(client)
		if err != nil {
			fmt.Println(err)
			os.Exit(2)
		}

		// get access token
		url, _ := flickr.GetAuthorizeUrl(client, tok)
		if err != nil {
			fmt.Println(err)
			os.Exit(3)
		}

		// tell user to authorize the app
		var oauthVerifier string
		fmt.Println("Open your browser at this url:", url)
		fmt.Print("Then, insert the code:")
		fmt.Scanln(&oauthVerifier)

		// get the access token
		accessTok, err = flickr.GetAccessToken(client, tok, oauthVerifier)
		client.OAuthToken = accessTok.OAuthToken
		client.OAuthTokenSecret = accessTok.OAuthTokenSecret
	} else {
		client.OAuthToken = config.OAuthToken
		client.OAuthTokenSecret = config.OAuthTokenSecret
	}

	// test
	resp, err := test.Login(client)
	fmt.Println(resp.Status, resp.User)
	fmt.Println(err)
}
<|endoftext|>


<commit_before>package command

import (
	"strings"
)

type RegisterCommand struct {
	Meta
}

func (c *RegisterCommand) Run(args []string) int {
	// Write your code here

	return 0
}

func (c *RegisterCommand) Synopsis() string {
	return "Register LoginName and GitHubUsername mapping"
}

func (c *RegisterCommand) Help() string {
	helpText := `

`
	return strings.TrimSpace(helpText)
}
<commit_msg>Implement register<commit_after>package command

import (
	"strings"
	"os"
	"log"
	"fmt"
	"github.com/wantedly/github-username-converter/store"
	"github.com/wantedly/github-username-converter/models"
)

type RegisterCommand struct {
	Meta
}

func (c *RegisterCommand) Run(args []string) int {
	var loginName, githubUsername string
	if len(args) == 1 {
		loginName = os.Getenv("USER")
		githubUsername = args[0]
	} else if len(args) == 2 {
		loginName = args[0]
		githubUsername = args[1]
	} else {
		log.Println(c.Help())
		return 1
	}

	s := store.NewDynamoDB()

	user := models.NewUser(loginName, githubUsername)
	err := s.AddUser(user)
	if err != nil {
		log.Println(err)
		return 1
	}
	fmt.Printf("user %v added.\n", user)

	return 0
}

func (c *RegisterCommand) Synopsis() string {
	return "Register LoginName and GitHubUsername mapping"
}

func (c *RegisterCommand) Help() string {
	helpText := `

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>// These functions extract (and validate) user provided form data.
package common

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// Return the requested branch name, from get or post data.
func GetFormBranch(r *http.Request) (string, error) {
	// If no branch was given in the input, returns an empty string
	c := r.FormValue("branch")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid branch name: '%v'", c))
	}
	return c, nil
}

// Return the requested database commit, from form data.
func GetFormCommit(r *http.Request) (string, error) {
	// If no commit was given in the input, returns an empty string
	c := r.FormValue("commit")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "hexadecimal,min=64,max=64")
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid database commit: '%v'", c))
	}
	return c, nil
}

// Extracts a database name from form data
func GetFormDatabase(r *http.Request) (string, error) {
	dbName := r.PostFormValue("dbname")
	err := ValidateDB(dbName)
	if err != nil {
		log.Printf("Validation failed for database name '%s': %s", dbName, err)
		return "", errors.New("Invalid database name")
	}
	return dbName, nil
}

// Returns the folder name (if any) present in the form data
func GetFormFolder(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	folder := r.PostFormValue("folder")

	// If no folder given, return
	if folder == "" {
		return "", nil
	}

	// Validate the folder name
	err = ValidateFolder(folder)
	if err != nil {
		log.Printf("Validation failed for folder: '%s': %s", folder, err)
		return "", err
	}

	return folder, nil
}

// Returns the licence name (if any) present in the form data
func GetFormLicence(r *http.Request) (licenceName string, err error) {
	// If no licence name given, return an empty string
	l := r.PostFormValue("licence")
	if l == "" {
		return "", nil
	}

	// Validate the licence name
	err = ValidateLicence(l)
	if err != nil {
		log.Printf("Validation failed for licence: '%s': %s", l, err)
		return "", err
	}
	licenceName = l

	return licenceName, nil
}

// Returns the source URL (if any) present in the form data
func GetFormSourceURL(r *http.Request) (sourceURL string, err error) {
	// Gather submitted form data (if any)
	err = r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return sourceURL, err
	}

	// Validate the source URL
	su := r.PostFormValue("sourceurl")
	if su != "" {
		err = Validate.Var(su, "url,min=5,max=255") // 255 seems like a reasonable first guess
		if err != nil {
			return sourceURL, errors.New("Validation failed for source URL field")
		}
		sourceURL = su
	}

	return sourceURL, err
}

// Return the requested release name, from get or post data.
func GetFormRelease(r *http.Request) (release string, err error) {
	// If no release was given in the input, returns an empty string
	c := r.FormValue("release")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid release name: '%v'", c))
	}
	return c, nil
}

// Return the requested tag name, from get or post data.
func GetFormTag(r *http.Request) (tag string, err error) {
	// If no tag was given in the input, returns an empty string
	c := r.FormValue("tag")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid tag name: '%v'", c))
	}
	return c, nil
}

// Return the username, database, and commit (if any) present in the form data.
func GetFormUDC(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbName, commitID, nil
}

// Return the username, folder, and database name (if any) present in the form data.
func GetFormUFD(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the folder
	dbFolder, err := GetFormFolder(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbFolder, dbName, nil
}

// Return the username, password, and source URL from the form data.
func GetFormUPS(r *http.Request) (string, string, string, error) {
	// Get username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Get password and Source URL
	password := r.PostFormValue("pass")
	sourceURL := r.PostFormValue("sourceurl")

	// If no username/password was given, return
	if userName == "" && password == "" {
		return "", "", "", err
	}

	// Check the password isn't blank
	if len(password) < 1 {
		log.Print("Password missing")
		return "", "", "", err
	}

	// Validate the source referrer (if present)
	var bounceURL string
	if sourceURL != "" {
		ref, err := url.Parse(sourceURL)
		if err != nil {
			log.Printf("Error when parsing referrer URL for login form: %s\n", err)
		} else {
			// Only use the referrer path if no hostname is set (eg check if someone is screwing around)
			if ref.Host == "" {
				bounceURL = ref.Path
			}
		}
	}

	return userName, password, bounceURL, nil
}

// Return the username (if any) present in the form data.
func GetFormUsername(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	userName := r.PostFormValue("username")

	// If no username given, return
	if userName == "" {
		return "", nil
	}

	// Validate the username
	err = ValidateUser(userName)
	if err != nil {
		log.Printf("Validation failed for username: %s", err)
		return "", err
	}

	return userName, nil
}

// Returns the requested database owner and database name.
func GetOD(ignore_leading int, r *http.Request) (string, string, error) {
	// Split the request URL into path components
	pathStrings := strings.Split(r.URL.Path, "/")

	// Check that at least an owner/database combination was requested
	if len(pathStrings) < (3 + ignore_leading) {
		log.Printf("Something wrong with the requested URL: %v\n", r.URL.Path)
		return "", "", errors.New("Invalid URL")
	}
	dbOwner := pathStrings[1+ignore_leading]
	dbName := pathStrings[2+ignore_leading]

	// Validate the user supplied owner and database name
	err := ValidateUserDB(dbOwner, dbName)
	if err != nil {
		// Don't bother logging the fairly common case of a bot using an AngularJS phrase in a request
		if dbOwner == "{{ meta.Owner + '" && dbName == "' + row.Database }}" {
			return "", "", errors.New("Invalid owner or database name")
		}

		log.Printf("Validation failed for owner or database name. Owner '%s', DB name '%s': %s",
			dbOwner, dbName, err)
		return "", "", errors.New("Invalid owner or database name")
	}

	// Everything seems ok
	return dbOwner, dbName, nil
}

// Returns the requested database owner, database name, and commit revision.
func GetODC(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit revision
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, commitID, nil
}

// Returns the requested database owner, database name, and table name.
func GetODT(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, nil
}

// Returns the requested database owner, database name, table name, and commit string.
func GetODTC(ignore_leading int, r *http.Request) (string, string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, commitID, nil
}

// Returns the requested "public" variable, if present in the form data.
// If something goes wrong, it defaults to "false".
func GetPub(r *http.Request) (bool, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return false, err
	}
	val := r.PostFormValue("public")
	if val == "" {
		// No public/private variable found
		return false, errors.New("No public/private value present")
	}
	pub, err := strconv.ParseBool(val)
	if err != nil {
		log.Printf("Error when converting public value to boolean: %v\n", err)
		return false, err
	}

	return pub, nil
}

// Returns the requested table name (if any).
func GetTable(r *http.Request) (string, error) {
	var requestedTable string
	requestedTable = r.FormValue("table")

	// If a table name was supplied, validate it
	// FIXME: We should probably create a validation function for SQLite table names, not use our one for PG
	if requestedTable != "" {
		err := ValidatePGTable(requestedTable)
		if err != nil {
			// If the failed table name is "{{ db.Tablename }}", don't bother logging it.  It's just a
			// search bot picking up the AngularJS string then doing a request with it
			if requestedTable != "{{ db.Tablename }}" {
				log.Printf("Validation failed for table name: '%s': %s", requestedTable, err)
			}
			return "", errors.New("Invalid table name")
		}
	}

	// Everything seems ok
	return requestedTable, nil
}
<commit_msg>Add another check for common search engines sending invalid requests<commit_after>// These functions extract (and validate) user provided form data.
package common

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// Return the requested branch name, from get or post data.
func GetFormBranch(r *http.Request) (string, error) {
	// If no branch was given in the input, returns an empty string
	c := r.FormValue("branch")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid branch name: '%v'", c))
	}
	return c, nil
}

// Return the requested database commit, from form data.
func GetFormCommit(r *http.Request) (string, error) {
	// If no commit was given in the input, returns an empty string
	c := r.FormValue("commit")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "hexadecimal,min=64,max=64")
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid database commit: '%v'", c))
	}
	return c, nil
}

// Extracts a database name from form data
func GetFormDatabase(r *http.Request) (string, error) {
	dbName := r.PostFormValue("dbname")
	err := ValidateDB(dbName)
	if err != nil {
		log.Printf("Validation failed for database name '%s': %s", dbName, err)
		return "", errors.New("Invalid database name")
	}
	return dbName, nil
}

// Returns the folder name (if any) present in the form data
func GetFormFolder(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	folder := r.PostFormValue("folder")

	// If no folder given, return
	if folder == "" {
		return "", nil
	}

	// Validate the folder name
	err = ValidateFolder(folder)
	if err != nil {
		log.Printf("Validation failed for folder: '%s': %s", folder, err)
		return "", err
	}

	return folder, nil
}

// Returns the licence name (if any) present in the form data
func GetFormLicence(r *http.Request) (licenceName string, err error) {
	// If no licence name given, return an empty string
	l := r.PostFormValue("licence")
	if l == "" {
		return "", nil
	}

	// Validate the licence name
	err = ValidateLicence(l)
	if err != nil {
		log.Printf("Validation failed for licence: '%s': %s", l, err)
		return "", err
	}
	licenceName = l

	return licenceName, nil
}

// Returns the source URL (if any) present in the form data
func GetFormSourceURL(r *http.Request) (sourceURL string, err error) {
	// Gather submitted form data (if any)
	err = r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return sourceURL, err
	}

	// Validate the source URL
	su := r.PostFormValue("sourceurl")
	if su != "" {
		err = Validate.Var(su, "url,min=5,max=255") // 255 seems like a reasonable first guess
		if err != nil {
			return sourceURL, errors.New("Validation failed for source URL field")
		}
		sourceURL = su
	}

	return sourceURL, err
}

// Return the requested release name, from get or post data.
func GetFormRelease(r *http.Request) (release string, err error) {
	// If no release was given in the input, returns an empty string
	c := r.FormValue("release")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid release name: '%v'", c))
	}
	return c, nil
}

// Return the requested tag name, from get or post data.
func GetFormTag(r *http.Request) (tag string, err error) {
	// If no tag was given in the input, returns an empty string
	c := r.FormValue("tag")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid tag name: '%v'", c))
	}
	return c, nil
}

// Return the username, database, and commit (if any) present in the form data.
func GetFormUDC(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbName, commitID, nil
}

// Return the username, folder, and database name (if any) present in the form data.
func GetFormUFD(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the folder
	dbFolder, err := GetFormFolder(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbFolder, dbName, nil
}

// Return the username, password, and source URL from the form data.
func GetFormUPS(r *http.Request) (string, string, string, error) {
	// Get username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Get password and Source URL
	password := r.PostFormValue("pass")
	sourceURL := r.PostFormValue("sourceurl")

	// If no username/password was given, return
	if userName == "" && password == "" {
		return "", "", "", err
	}

	// Check the password isn't blank
	if len(password) < 1 {
		log.Print("Password missing")
		return "", "", "", err
	}

	// Validate the source referrer (if present)
	var bounceURL string
	if sourceURL != "" {
		ref, err := url.Parse(sourceURL)
		if err != nil {
			log.Printf("Error when parsing referrer URL for login form: %s\n", err)
		} else {
			// Only use the referrer path if no hostname is set (eg check if someone is screwing around)
			if ref.Host == "" {
				bounceURL = ref.Path
			}
		}
	}

	return userName, password, bounceURL, nil
}

// Return the username (if any) present in the form data.
func GetFormUsername(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	userName := r.PostFormValue("username")

	// If no username given, return
	if userName == "" {
		return "", nil
	}

	// Validate the username
	err = ValidateUser(userName)
	if err != nil {
		log.Printf("Validation failed for username: %s", err)
		return "", err
	}

	return userName, nil
}

// Returns the requested database owner and database name.
func GetOD(ignore_leading int, r *http.Request) (string, string, error) {
	// Split the request URL into path components
	pathStrings := strings.Split(r.URL.Path, "/")

	// Check that at least an owner/database combination was requested
	if len(pathStrings) < (3 + ignore_leading) {
		log.Printf("Something wrong with the requested URL: %v\n", r.URL.Path)
		return "", "", errors.New("Invalid URL")
	}
	dbOwner := pathStrings[1+ignore_leading]
	dbName := pathStrings[2+ignore_leading]

	// Validate the user supplied owner and database name
	err := ValidateUserDB(dbOwner, dbName)
	if err != nil {
		// Don't bother logging the fairly common case of a bot using an AngularJS phrase in a request
		if (dbOwner == "{{ meta.Owner + '" && dbName == "' + row.Database }}") ||
			(dbOwner == "{{ row.owner + '" && dbName == "' + row.dbname }}") {
			return "", "", errors.New("Invalid owner or database name")
		}

		log.Printf("Validation failed for owner or database name. Owner '%s', DB name '%s': %s",
			dbOwner, dbName, err)
		return "", "", errors.New("Invalid owner or database name")
	}

	// Everything seems ok
	return dbOwner, dbName, nil
}

// Returns the requested database owner, database name, and commit revision.
func GetODC(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit revision
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, commitID, nil
}

// Returns the requested database owner, database name, and table name.
func GetODT(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, nil
}

// Returns the requested database owner, database name, table name, and commit string.
func GetODTC(ignore_leading int, r *http.Request) (string, string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, commitID, nil
}

// Returns the requested "public" variable, if present in the form data.
// If something goes wrong, it defaults to "false".
func GetPub(r *http.Request) (bool, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return false, err
	}
	val := r.PostFormValue("public")
	if val == "" {
		// No public/private variable found
		return false, errors.New("No public/private value present")
	}
	pub, err := strconv.ParseBool(val)
	if err != nil {
		log.Printf("Error when converting public value to boolean: %v\n", err)
		return false, err
	}

	return pub, nil
}

// Returns the requested table name (if any).
func GetTable(r *http.Request) (string, error) {
	var requestedTable string
	requestedTable = r.FormValue("table")

	// If a table name was supplied, validate it
	// FIXME: We should probably create a validation function for SQLite table names, not use our one for PG
	if requestedTable != "" {
		err := ValidatePGTable(requestedTable)
		if err != nil {
			// If the failed table name is "{{ db.Tablename }}", don't bother logging it.  It's just a
			// search bot picking up the AngularJS string then doing a request with it
			if requestedTable != "{{ db.Tablename }}" {
				log.Printf("Validation failed for table name: '%s': %s", requestedTable, err)
			}
			return "", errors.New("Invalid table name")
		}
	}

	// Everything seems ok
	return requestedTable, nil
}
<|endoftext|>


<commit_before>package golib

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"reflect"
	"sync"
	"time"
)

// ========= Task interface
type StopChan <-chan error

// Semantics: Start() may only be called once, but Stop() should be idempotent.
// One error must be sent on StopChan upon stopping. The error can be nil.
type Task interface {
	Start(wg *sync.WaitGroup) StopChan
	Stop()
	String() string // Tasks are frequently printed
}

type NoopTask struct {
	Chan        chan error
	Description string
}

func (task *NoopTask) Start(*sync.WaitGroup) StopChan {
	return task.Chan
}
func (task *NoopTask) Stop() {
	task.Chan <- nil
}
func (task *NoopTask) String() string {
	return fmt.Sprintf("Task(%s)", task.Description)
}

type CleanupTask struct {
	Cleanup     func()
	Description string
	once        sync.Once
}

func (task *CleanupTask) Start(*sync.WaitGroup) StopChan {
	return nil
}
func (task *CleanupTask) Stop() {
	task.once.Do(func() {
		if cleanup := task.Cleanup; cleanup != nil {
			cleanup()
		}
	})
}
func (task *CleanupTask) String() string {
	return fmt.Sprintf("Cleanup(%s)", task.Description)
}

type LoopTask struct {
	*OneshotCondition
	loop        func(stop StopChan) error
	Err         error
	Description string
	StopHook    func()
}

func (task *LoopTask) Start(wg *sync.WaitGroup) StopChan {
	cond := task.OneshotCondition
	if loop := task.loop; loop != nil {
		stop := WaitCondition(wg, cond)
		if wg != nil {
			wg.Add(1)
		}
		go func() {
			if wg != nil {
				defer wg.Done()
			}
			for !cond.Enabled() {
				task.Err = loop(stop)
				if task.Err != nil {
					cond.EnableErr(task.Err)
				}
			}
			if hook := task.StopHook; hook != nil {
				hook()
			}
		}()
	}
	return cond.Start(wg)
}

func (task *LoopTask) String() string {
	return fmt.Sprintf("LoopTask(%s)", task.Description)
}

func NewLoopTask(description string, loop func(stop StopChan)) *LoopTask {
	return NewErrLoopTask(description, func(stop StopChan) error {
		loop(stop)
		return nil
	})
}

func NewErrLoopTask(description string, loop func(stop StopChan) error) *LoopTask {
	return &LoopTask{
		OneshotCondition: NewOneshotCondition(),
		loop:             loop,
		Description:      description,
	}
}

// ========= Helpers to implement Task interface

func TaskFinished() StopChan {
	return TaskFinishedError(nil)
}

func TaskFinishedError(err error) StopChan {
	res := make(chan error, 1)
	res <- err
	return res
}

func WaitErrFunc(wg *sync.WaitGroup, wait func() error) StopChan {
	if wg != nil {
		wg.Add(1)
	}
	finished := make(chan error, 1)
	go func() {
		if wg != nil {
			defer wg.Done()
		}
		var err error
		if wait != nil {
			err = wait()
		}
		finished <- err
		close(finished)
	}()
	return finished
}

func WaitFunc(wg *sync.WaitGroup, wait func()) StopChan {
	return WaitErrFunc(wg, func() error {
		wait()
		return nil
	})
}

func WaitCondition(wg *sync.WaitGroup, cond *OneshotCondition) StopChan {
	if cond == nil {
		return nil
	}
	return WaitErrFunc(wg, func() error {
		cond.Wait()
		return cond.Err
	})
}

func WaitForAny(channels []StopChan) (int, error) {
	if len(channels) < 1 {
		return -1, nil
	}
	// Use reflect package to wait for any of the given channels
	var cases []reflect.SelectCase
	for _, ch := range channels {
		if ch != nil {
			refCase := reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
			cases = append(cases, refCase)
		}
	}
	choice, result, _ := reflect.Select(cases)
	channels[choice] = nil // Already received
	if err, ok := result.Interface().(error); ok {
		return choice, err
	} else {
		return choice, nil
	}
}

func WaitForAnyTask(wg *sync.WaitGroup, tasks []Task) (Task, error, []Task, []StopChan) {
	channels := make([]StopChan, 0, len(tasks))
	waitingTasks := make([]Task, 0, len(tasks))
	for _, task := range tasks {
		if channel := task.Start(wg); channel != nil {
			channels = append(channels, channel)
			waitingTasks = append(waitingTasks, task)
		}
	}
	choice, err := WaitForAny(channels)
	return waitingTasks[choice], err, waitingTasks, channels
}

func WaitForSetup(wg *sync.WaitGroup, setup func() error) StopChan {
	if wg != nil {
		wg.Add(1)
	}
	failed := make(chan error, 1)
	go func() {
		if wg != nil {
			defer wg.Done()
		}
		if setup != nil {
			if err := setup(); err != nil {
				failed <- err
				close(failed)
			}
		}
	}()
	return failed
}

// ========= Task Group

type TaskGroup struct {
	names  []string          // Track order of added new groups
	groups map[string][]Task // Groups will be stopped sequentially, but Tasks in one group in parallel
	all    []Task
}

func NewTaskGroup(tasks ...Task) *TaskGroup {
	group := &TaskGroup{
		groups: make(map[string][]Task),
	}
	for _, o := range tasks {
		group.Add(o)
	}
	return group
}

func (group *TaskGroup) Add(tasks ...Task) {
	group.AddNamed("default", tasks...)
}

func (group *TaskGroup) AddNamed(name string, tasks ...Task) {
	var list []Task
	if existingList, ok := group.groups[name]; ok {
		list = existingList
	} else {
		group.names = append(group.names, name)
	}
	for _, task := range tasks {
		if task != nil {
			group.all = append(group.all, tasks...)
			list = append(list, task)
		}
	}
	group.groups[name] = list
}

func (group *TaskGroup) WaitForAny(wg *sync.WaitGroup) (Task, error, []Task, []StopChan) {
	return WaitForAnyTask(wg, group.all)
}

func (group *TaskGroup) ReverseStop(printTasks bool) {
	for i := len(group.names) - 1; i >= 0; i-- {
		// Stop groups in reverse order
		var wg sync.WaitGroup
		tasks := group.groups[group.names[i]]
		for _, task := range tasks {
			// Stop tasks in one group in parallel
			wg.Add(1)
			go func(task Task) {
				defer wg.Done()
				if printTasks {
					log.Printf("Stopping %v\n", task)
				}
				task.Stop()
			}(task)
		}
		wg.Wait()
	}
}

func PrintErrors(inputs []StopChan, tasks []Task, printWait bool) (numErrors int) {
	for i, input := range inputs {
		if input != nil {
			if printWait {
				task := tasks[i]
				log.Println("Waiting for", task)
			}
			if err := <-input; err != nil {
				numErrors++
				log.Println("Error:", err)
			}
		}
	}
	return
}

func (group *TaskGroup) WaitAndStop(timeout time.Duration, printWait bool) (reason Task, numErrors int) {
	var wg sync.WaitGroup
	reason, err, tasks, channels := group.WaitForAny(&wg)
	if err != nil {
		numErrors++
		log.Println("Error:", err)
	}
	if timeout > 0 {
		time.AfterFunc(timeout, func() {
			panic("Waiting for stopping goroutines timed out")
		})
	}
	group.ReverseStop(printWait)
	wg.Wait()
	numErrors += PrintErrors(channels, tasks, printWait)
	return
}

var (
	DefaultTaskStopTimeout   = time.Duration(0)
	DefaultPrintTaskStopWait = false
)

func init() {
	flag.BoolVar(&DefaultPrintTaskStopWait, "task_stop_print", DefaultPrintTaskStopWait, "Print tasks waited for when stopping (for debugging)")
	flag.DurationVar(&DefaultTaskStopTimeout, "task_stop_timeout", DefaultTaskStopTimeout, "Timeout duration when stopping and waiting for tasks to finish")
}

func (group *TaskGroup) PrintWaitAndStop() int {
	return group.TimeoutPrintWaitAndStop(DefaultTaskStopTimeout, DefaultPrintTaskStopWait)
}

func (group *TaskGroup) TimeoutPrintWaitAndStop(timeout time.Duration, printWait bool) (numErrors int) {
	reason, numErrors := group.WaitAndStop(timeout, printWait)
	log.Printf("Stopped because of %v\n", reason)
	return
}

// ========= Sources of interrupts by the user

func ExternalInterrupt() chan error {
	// This must be done after starting any subprocess that depends
	// the ignore-handler for SIGNIT provided by ./noint
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)
	stop := make(chan error, 2)
	go func() {
		defer signal.Stop(interrupt)
		select {
		case <-interrupt:
		case <-stop:
		}
		stop <- nil
	}()
	return stop
}

func UserInput() chan error {
	userinput := make(chan error, 2)
	go func() {
		reader := bufio.NewReader(os.Stdin)
		_, err := reader.ReadString('\n')
		if err != nil {
			err = fmt.Errorf("Error reading user input: %v", err)
		}
		userinput <- err
	}()
	return userinput
}

func StdinClosed() chan error {
	closed := make(chan error, 2)
	go func() {
		_, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			err = fmt.Errorf("Error reading stdin: %v", err)
		}
		closed <- err
	}()
	return closed
}
<commit_msg>Printing goroutine stacks when wait on exit times out.<commit_after>package golib

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"reflect"
	"runtime/pprof"
	"sync"
	"time"
)

// ========= Task interface
type StopChan <-chan error

// Semantics: Start() may only be called once, but Stop() should be idempotent.
// One error must be sent on StopChan upon stopping. The error can be nil.
type Task interface {
	Start(wg *sync.WaitGroup) StopChan
	Stop()
	String() string // Tasks are frequently printed
}

type NoopTask struct {
	Chan        chan error
	Description string
}

func (task *NoopTask) Start(*sync.WaitGroup) StopChan {
	return task.Chan
}
func (task *NoopTask) Stop() {
	task.Chan <- nil
}
func (task *NoopTask) String() string {
	return fmt.Sprintf("Task(%s)", task.Description)
}

type CleanupTask struct {
	Cleanup     func()
	Description string
	once        sync.Once
}

func (task *CleanupTask) Start(*sync.WaitGroup) StopChan {
	return nil
}
func (task *CleanupTask) Stop() {
	task.once.Do(func() {
		if cleanup := task.Cleanup; cleanup != nil {
			cleanup()
		}
	})
}
func (task *CleanupTask) String() string {
	return fmt.Sprintf("Cleanup(%s)", task.Description)
}

type LoopTask struct {
	*OneshotCondition
	loop        func(stop StopChan) error
	Err         error
	Description string
	StopHook    func()
}

func (task *LoopTask) Start(wg *sync.WaitGroup) StopChan {
	cond := task.OneshotCondition
	if loop := task.loop; loop != nil {
		stop := WaitCondition(wg, cond)
		if wg != nil {
			wg.Add(1)
		}
		go func() {
			if wg != nil {
				defer wg.Done()
			}
			for !cond.Enabled() {
				task.Err = loop(stop)
				if task.Err != nil {
					cond.EnableErr(task.Err)
				}
			}
			if hook := task.StopHook; hook != nil {
				hook()
			}
		}()
	}
	return cond.Start(wg)
}

func (task *LoopTask) String() string {
	return fmt.Sprintf("LoopTask(%s)", task.Description)
}

func NewLoopTask(description string, loop func(stop StopChan)) *LoopTask {
	return NewErrLoopTask(description, func(stop StopChan) error {
		loop(stop)
		return nil
	})
}

func NewErrLoopTask(description string, loop func(stop StopChan) error) *LoopTask {
	return &LoopTask{
		OneshotCondition: NewOneshotCondition(),
		loop:             loop,
		Description:      description,
	}
}

// ========= Helpers to implement Task interface

func TaskFinished() StopChan {
	return TaskFinishedError(nil)
}

func TaskFinishedError(err error) StopChan {
	res := make(chan error, 1)
	res <- err
	return res
}

func WaitErrFunc(wg *sync.WaitGroup, wait func() error) StopChan {
	if wg != nil {
		wg.Add(1)
	}
	finished := make(chan error, 1)
	go func() {
		if wg != nil {
			defer wg.Done()
		}
		var err error
		if wait != nil {
			err = wait()
		}
		finished <- err
		close(finished)
	}()
	return finished
}

func WaitFunc(wg *sync.WaitGroup, wait func()) StopChan {
	return WaitErrFunc(wg, func() error {
		wait()
		return nil
	})
}

func WaitCondition(wg *sync.WaitGroup, cond *OneshotCondition) StopChan {
	if cond == nil {
		return nil
	}
	return WaitErrFunc(wg, func() error {
		cond.Wait()
		return cond.Err
	})
}

func WaitForAny(channels []StopChan) (int, error) {
	if len(channels) < 1 {
		return -1, nil
	}
	// Use reflect package to wait for any of the given channels
	var cases []reflect.SelectCase
	for _, ch := range channels {
		if ch != nil {
			refCase := reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
			cases = append(cases, refCase)
		}
	}
	choice, result, _ := reflect.Select(cases)
	channels[choice] = nil // Already received
	if err, ok := result.Interface().(error); ok {
		return choice, err
	} else {
		return choice, nil
	}
}

func WaitForAnyTask(wg *sync.WaitGroup, tasks []Task) (Task, error, []Task, []StopChan) {
	channels := make([]StopChan, 0, len(tasks))
	waitingTasks := make([]Task, 0, len(tasks))
	for _, task := range tasks {
		if channel := task.Start(wg); channel != nil {
			channels = append(channels, channel)
			waitingTasks = append(waitingTasks, task)
		}
	}
	choice, err := WaitForAny(channels)
	return waitingTasks[choice], err, waitingTasks, channels
}

func WaitForSetup(wg *sync.WaitGroup, setup func() error) StopChan {
	if wg != nil {
		wg.Add(1)
	}
	failed := make(chan error, 1)
	go func() {
		if wg != nil {
			defer wg.Done()
		}
		if setup != nil {
			if err := setup(); err != nil {
				failed <- err
				close(failed)
			}
		}
	}()
	return failed
}

// ========= Task Group

type TaskGroup struct {
	names  []string          // Track order of added new groups
	groups map[string][]Task // Groups will be stopped sequentially, but Tasks in one group in parallel
	all    []Task
}

func NewTaskGroup(tasks ...Task) *TaskGroup {
	group := &TaskGroup{
		groups: make(map[string][]Task),
	}
	for _, o := range tasks {
		group.Add(o)
	}
	return group
}

func (group *TaskGroup) Add(tasks ...Task) {
	group.AddNamed("default", tasks...)
}

func (group *TaskGroup) AddNamed(name string, tasks ...Task) {
	var list []Task
	if existingList, ok := group.groups[name]; ok {
		list = existingList
	} else {
		group.names = append(group.names, name)
	}
	for _, task := range tasks {
		if task != nil {
			group.all = append(group.all, tasks...)
			list = append(list, task)
		}
	}
	group.groups[name] = list
}

func (group *TaskGroup) WaitForAny(wg *sync.WaitGroup) (Task, error, []Task, []StopChan) {
	return WaitForAnyTask(wg, group.all)
}

func (group *TaskGroup) ReverseStop(printTasks bool) {
	for i := len(group.names) - 1; i >= 0; i-- {
		// Stop groups in reverse order
		var wg sync.WaitGroup
		tasks := group.groups[group.names[i]]
		for _, task := range tasks {
			// Stop tasks in one group in parallel
			wg.Add(1)
			go func(task Task) {
				defer wg.Done()
				if printTasks {
					log.Printf("Stopping %v\n", task)
				}
				task.Stop()
			}(task)
		}
		wg.Wait()
	}
}

func PrintErrors(inputs []StopChan, tasks []Task, printWait bool) (numErrors int) {
	for i, input := range inputs {
		if input != nil {
			if printWait {
				task := tasks[i]
				log.Println("Waiting for", task)
			}
			if err := <-input; err != nil {
				numErrors++
				log.Println("Error:", err)
			}
		}
	}
	return
}

func (group *TaskGroup) WaitAndStop(timeout time.Duration, printWait bool) (reason Task, numErrors int) {
	var wg sync.WaitGroup
	reason, err, tasks, channels := group.WaitForAny(&wg)
	if err != nil {
		numErrors++
		log.Println("Error:", err)
	}
	if timeout > 0 {
		time.AfterFunc(timeout, func() {
			pprof.Lookup("goroutine").WriteTo(os.Stdout, 2)
			panic("Waiting for stopping goroutines timed out")
		})
	}
	group.ReverseStop(printWait)
	wg.Wait()
	numErrors += PrintErrors(channels, tasks, printWait)
	return
}

var (
	DefaultTaskStopTimeout   = time.Duration(0)
	DefaultPrintTaskStopWait = false
)

func init() {
	flag.BoolVar(&DefaultPrintTaskStopWait, "task_stop_print", DefaultPrintTaskStopWait, "Print tasks waited for when stopping (for debugging)")
	flag.DurationVar(&DefaultTaskStopTimeout, "task_stop_timeout", DefaultTaskStopTimeout, "Timeout duration when stopping and waiting for tasks to finish")
}

func (group *TaskGroup) PrintWaitAndStop() int {
	return group.TimeoutPrintWaitAndStop(DefaultTaskStopTimeout, DefaultPrintTaskStopWait)
}

func (group *TaskGroup) TimeoutPrintWaitAndStop(timeout time.Duration, printWait bool) (numErrors int) {
	reason, numErrors := group.WaitAndStop(timeout, printWait)
	log.Printf("Stopped because of %v\n", reason)
	return
}

// ========= Sources of interrupts by the user

func ExternalInterrupt() chan error {
	// This must be done after starting any subprocess that depends
	// the ignore-handler for SIGNIT provided by ./noint
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)
	stop := make(chan error, 2)
	go func() {
		defer signal.Stop(interrupt)
		select {
		case <-interrupt:
		case <-stop:
		}
		stop <- nil
	}()
	return stop
}

func UserInput() chan error {
	userinput := make(chan error, 2)
	go func() {
		reader := bufio.NewReader(os.Stdin)
		_, err := reader.ReadString('\n')
		if err != nil {
			err = fmt.Errorf("Error reading user input: %v", err)
		}
		userinput <- err
	}()
	return userinput
}

func StdinClosed() chan error {
	closed := make(chan error, 2)
	go func() {
		_, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			err = fmt.Errorf("Error reading stdin: %v", err)
		}
		closed <- err
	}()
	return closed
}
<|endoftext|>


<commit_before>package builder

import (
	log "github.com/Sirupsen/logrus"
	"github.com/blablacar/cnt/config"
	"github.com/blablacar/cnt/utils"
)

func (p *Pod) Push() {
	log.Info("Push POD", p.manifest.Name)

	p.Build()

	checkVersion := make(chan bool, 1)

	for _, e := range p.manifest.Pod.Apps {
		aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e), &checkVersion)
		if err != nil {
			panic(err)
		}
		aci.PodName = &p.manifest.Name
		aci.Push()
	}

	for range p.manifest.Pod.Apps {
		<-checkVersion
	}

	if err := utils.ExecCmd("curl", "-i",
		"-F", "r=releases",
		"-F", "hasPom=false",
		"-F", "e=pod",
		"-F", "g=com.blablacar.aci.linux.amd64",
		"-F", "p=pod",
		"-F", "v="+p.manifest.Name.Version(),
		"-F", "a="+p.manifest.Name.ShortName(),
		"-F", "file=@"+p.target+"/pod-manifest.json",
		"-u", config.GetConfig().Push.Username+":"+config.GetConfig().Push.Password,
		config.GetConfig().Push.Url+"/service/local/artifact/maven/content"); err != nil {
		panic("Cannot push pod" + err.Error())
	}

	if err := utils.ExecCmd("curl", "-i",
		"-F", "r=releases",
		"-F", "hasPom=false",
		"-F", "e=service",
		"-F", "g=com.blablacar.aci.linux.amd64",
		"-F", "p=service",
		"-F", "v="+p.manifest.Name.Version(),
		"-F", "a="+p.manifest.Name.ShortName(),
		"-F", "file=@"+p.target+"/"+p.manifest.Name.ShortName()+"@.service",
		"-u", config.GetConfig().Push.Username+":"+config.GetConfig().Push.Password,
		config.GetConfig().Push.Url+"/service/local/artifact/maven/content"); err != nil {
		panic("Cannot push pod" + err.Error())
	}

}
<commit_msg>remove pushing unit on pod push<commit_after>package builder

import (
	log "github.com/Sirupsen/logrus"
	"github.com/blablacar/cnt/config"
	"github.com/blablacar/cnt/utils"
)

func (p *Pod) Push() {
	log.Info("Push POD", p.manifest.Name)

	p.Build()

	checkVersion := make(chan bool, 1)

	for _, e := range p.manifest.Pod.Apps {
		aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e), &checkVersion)
		if err != nil {
			panic(err)
		}
		aci.PodName = &p.manifest.Name
		aci.Push()
	}

	for range p.manifest.Pod.Apps {
		<-checkVersion
	}

	if err := utils.ExecCmd("curl", "-i",
		"-F", "r=releases",
		"-F", "hasPom=false",
		"-F", "e=pod",
		"-F", "g=com.blablacar.aci.linux.amd64",
		"-F", "p=pod",
		"-F", "v="+p.manifest.Name.Version(),
		"-F", "a="+p.manifest.Name.ShortName(),
		"-F", "file=@"+p.target+"/pod-manifest.json",
		"-u", config.GetConfig().Push.Username+":"+config.GetConfig().Push.Password,
		config.GetConfig().Push.Url+"/service/local/artifact/maven/content"); err != nil {
		panic("Cannot push pod" + err.Error())
	}

}
<|endoftext|>


<commit_before>package buildkite

// Logic for this file is largely based on:
// https://github.com/jarib/childprocess/blob/783f7a00a1678b5d929062564ef5ae76822dfd62/lib/childprocess/unix/process.rb

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Process struct {
	Pid           int
	Running       bool
	RunInPty      bool
	ExitStatus    string
	buffer        bytes.Buffer
	command       *exec.Cmd
	startCallback func(*Process)
	lineCallback  func(*Process, string)
}

// Implement the Stringer thingy
func (p Process) String() string {
	return fmt.Sprintf("Process{Pid: %d, Running: %t, ExitStatus: %s}", p.Pid, p.Running, p.ExitStatus)
}

func InitProcess(scriptPath string, env []string, runInPty bool, startCallback func(*Process), lineCallback func(*Process, string)) *Process {
	// Create a new instance of our process struct
	var process Process
	process.RunInPty = runInPty

	// Find the script to run
	absolutePath, _ := filepath.Abs(scriptPath)
	scriptDirectory := filepath.Dir(absolutePath)

	process.command = exec.Command(absolutePath)
	process.command.Dir = scriptDirectory

	// Do cross-platform things to prepare this process to run
	PrepareCommandProcess(&process)

	// Copy the current processes ENV and merge in the new ones. We do this
	// so the sub process gets PATH and stuff. We merge our path in over
	// the top of the current one so the ENV from Buildkite and the agent
	// take precedence over the agent
	currentEnv := os.Environ()
	process.command.Env = append(currentEnv, env...)

	// Set the callbacks
	process.lineCallback = lineCallback
	process.startCallback = startCallback

	return &process
}

func (p *Process) Start() error {
	var waitGroup sync.WaitGroup

	lineReadr, lineWritr := io.Pipe()

	multiWriter := io.MultiWriter(&p.buffer, lineWritr)

	Logger.Infof("Starting to run script: %s", p.command.Path)

	// Toggle between running in a pty
	if p.RunInPty {
		Logger.Debugf("Starting TTY Session")

		pty, err := StartPTY(p.command)
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true

		waitGroup.Add(1)

		go func() {
			Logger.Debug("Starting to copy PTY to the buffer")

			// Copy the pty to our buffer. This will block until it
			// EOF's or something breaks.
			_, err = io.Copy(multiWriter, pty)
			if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
				// We can safely ignore this error, because
				// it's just the PTY telling us that it closed
				// successfully.  See:
				// https://github.com/buildkite/agent/pull/34#issuecomment-46080419
			} else if err != nil {
				Logger.Errorf("io.Copy failed with error: %T: %v", err, err)
			} else {
				Logger.Debug("io.Copy finsihed")
			}

			waitGroup.Done()
		}()
	} else {
		p.command.Stdout = multiWriter
		p.command.Stderr = multiWriter

		err := p.command.Start()
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true
	}

	Logger.Infof("Process is running with PID: %d", p.Pid)

	// Call the startCallback
	p.startCallback(p)

	// Add the line callback routine to the waitGroup
	waitGroup.Add(1)

	go func() {
		Logger.Debug("Starting the line scanner")

		scanner := bufio.NewScanner(lineReadr)
		for scanner.Scan() {
			p.lineCallback(p, scanner.Text())
		}

		if err := scanner.Err(); err != nil {
			Logger.Errorf("Failed to scan lines: (%T: %v)", err, err)
		}

		Logger.Debug("Line scanner has finished")

		waitGroup.Done()
	}()

	// Wait until the process has finished. The returned error is nil if the command runs,
	// has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
	waitResult := p.command.Wait()

	// The process is no longer running at this point
	p.Running = false

	// Find the exit status of the script
	p.ExitStatus = getExitStatus(waitResult)

	Logger.Infof("Process with PID: %d finished with Exit Status: %s", p.Pid, p.ExitStatus)

	// Sometimes (in docker containers) io.Copy never seems to finish. This is a mega
	// hack around it. If it doesn't finish after 1 second, just continue.
	Logger.Debug("Waiting for buffer routines to finish")
	err := timeoutWait(&waitGroup)
	if err != nil {
		Logger.Debugf("Timed out waiting for wait group: (%T: %v)", err, err)
	}

	// No error occured so we can return nil
	return nil
}

func (p *Process) Output() string {
	return p.buffer.String()
}

func (p *Process) Kill() error {
	// Send a sigterm
	err := p.signal(syscall.SIGTERM)
	if err != nil {
		return err
	}

	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)
	checking := true

	// Start a routine that checks to see if the process
	// is still alive.
	go func() {
		for checking {
			Logger.Debugf("Checking to see if PID: %d is still alive", p.Pid)

			foundProcess, err := os.FindProcess(p.Pid)

			// Can't find the process at all
			if err != nil {
				Logger.Debugf("Could not find process with PID: %d", p.Pid)

				break
			}

			// We have some information about the procss
			if foundProcess != nil {
				processState, err := foundProcess.Wait()

				if err != nil || processState.Exited() {
					Logger.Debugf("Process with PID: %d has exited.", p.Pid)

					break
				}
			}

			// Retry in a moment
			sleepTime := time.Duration(1 * time.Second)
			time.Sleep(sleepTime)
		}

		c <- 1
	}()

	// Timeout this process after 3 seconds
	select {
	case _ = <-c:
		// Was successfully terminated
	case <-time.After(10 * time.Second):
		// Stop checking in the routine above
		checking = false

		// Forcefully kill the thing
		err = p.signal(syscall.SIGKILL)

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *Process) signal(sig os.Signal) error {
	Logger.Debugf("Sending signal: %s to PID: %d", sig.String(), p.Pid)

	err := p.command.Process.Signal(syscall.SIGTERM)
	if err != nil {
		Logger.Errorf("Failed to send signal: %s to PID: %d (%T: %v)", sig.String(), p.Pid, err, err)
		return err
	}

	return nil
}

// https://github.com/hnakamur/commango/blob/fe42b1cf82bf536ce7e24dceaef6656002e03743/os/executil/executil.go#L29
// TODO: Can this be better?
func getExitStatus(waitResult error) string {
	exitStatus := -1

	if waitResult != nil {
		if err, ok := waitResult.(*exec.ExitError); ok {
			if s, ok := err.Sys().(syscall.WaitStatus); ok {
				exitStatus = s.ExitStatus()
			} else {
				Logger.Error("Unimplemented for system where exec.ExitError.Sys() is not syscall.WaitStatus.")
			}
		}
	} else {
		exitStatus = 0
	}

	return fmt.Sprintf("%d", exitStatus)
}

func timeoutWait(waitGroup *sync.WaitGroup) error {
	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)

	// Start waiting for the routines to finish
	go func() {
		waitGroup.Wait()
		c <- 1
	}()

	select {
	case _ = <-c:
		return nil
	case <-time.After(5 * time.Second):
		return errors.New("Timeout")
	}

	return nil
}
<commit_msg>Fixes to the pipe management in the script tech.<commit_after>package buildkite

// Logic for this file is largely based on:
// https://github.com/jarib/childprocess/blob/783f7a00a1678b5d929062564ef5ae76822dfd62/lib/childprocess/unix/process.rb

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Process struct {
	Pid           int
	Running       bool
	RunInPty      bool
	ExitStatus    string
	buffer        bytes.Buffer
	command       *exec.Cmd
	startCallback func(*Process)
	lineCallback  func(*Process, string)
}

// Implement the Stringer thingy
func (p Process) String() string {
	return fmt.Sprintf("Process{Pid: %d, Running: %t, ExitStatus: %s}", p.Pid, p.Running, p.ExitStatus)
}

func InitProcess(scriptPath string, env []string, runInPty bool, startCallback func(*Process), lineCallback func(*Process, string)) *Process {
	// Create a new instance of our process struct
	var process Process
	process.RunInPty = runInPty

	// Find the script to run
	absolutePath, _ := filepath.Abs(scriptPath)
	scriptDirectory := filepath.Dir(absolutePath)

	process.command = exec.Command(absolutePath)
	process.command.Dir = scriptDirectory

	// Do cross-platform things to prepare this process to run
	PrepareCommandProcess(&process)

	// Copy the current processes ENV and merge in the new ones. We do this
	// so the sub process gets PATH and stuff. We merge our path in over
	// the top of the current one so the ENV from Buildkite and the agent
	// take precedence over the agent
	currentEnv := os.Environ()
	process.command.Env = append(currentEnv, env...)

	// Set the callbacks
	process.lineCallback = lineCallback
	process.startCallback = startCallback

	return &process
}

func (p *Process) Start() error {
	var waitGroup sync.WaitGroup

	lineReaderPipe, lineWriterPipe := io.Pipe()

	multiWriter := io.MultiWriter(&p.buffer, lineWriterPipe)

	Logger.Infof("Starting to run script: %s", p.command.Path)

	// Toggle between running in a pty
	if p.RunInPty {
		pty, err := StartPTY(p.command)
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true

		waitGroup.Add(1)

		go func() {
			Logger.Debug("Starting to copy PTY to the buffer")

			// Copy the pty to our buffer. This will block until it
			// EOF's or something breaks.
			_, err = io.Copy(multiWriter, pty)
			if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
				// We can safely ignore this error, because
				// it's just the PTY telling us that it closed
				// successfully.  See:
				// https://github.com/buildkite/agent/pull/34#issuecomment-46080419
				err = nil
			}

			if err != nil {
				Logger.Errorf("PTY output copy failed with error: %T: %v", err, err)
			} else {
				Logger.Debug("PTY has finished being copied to the buffer")
			}

			waitGroup.Done()
		}()
	} else {
		p.command.Stdout = multiWriter
		p.command.Stderr = multiWriter

		err := p.command.Start()
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true
	}

	Logger.Infof("Process is running with PID: %d", p.Pid)

	// Add the line callback routine to the waitGroup
	waitGroup.Add(1)

	go func() {
		Logger.Debug("Starting the line scanner")

		scanner := bufio.NewScanner(lineReaderPipe)
		for scanner.Scan() {
			p.lineCallback(p, scanner.Text())
		}

		if err := scanner.Err(); err != nil {
			Logger.Errorf("Failed to scan lines: (%T: %v)", err, err)
		}

		Logger.Debug("Line scanner has finished")

		waitGroup.Done()
	}()

	// Call the startCallback
	p.startCallback(p)

	// Wait until the process has finished. The returned error is nil if the command runs,
	// has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
	waitResult := p.command.Wait()

	// Close the line writer pipe
	lineWriterPipe.Close()

	// The process is no longer running at this point
	p.Running = false

	// Find the exit status of the script
	p.ExitStatus = getExitStatus(waitResult)

	Logger.Infof("Process with PID: %d finished with Exit Status: %s", p.Pid, p.ExitStatus)

	// Sometimes (in docker containers) io.Copy never seems to finish. This is a mega
	// hack around it. If it doesn't finish after 1 second, just continue.
	Logger.Debug("Waiting for routines to finish")
	err := timeoutWait(&waitGroup)
	if err != nil {
		Logger.Debugf("Timed out waiting for wait group: (%T: %v)", err, err)
	}

	// No error occured so we can return nil
	return nil
}

func (p *Process) Output() string {
	return p.buffer.String()
}

func (p *Process) Kill() error {
	// Send a sigterm
	err := p.signal(syscall.SIGTERM)
	if err != nil {
		return err
	}

	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)
	checking := true

	// Start a routine that checks to see if the process
	// is still alive.
	go func() {
		for checking {
			Logger.Debugf("Checking to see if PID: %d is still alive", p.Pid)

			foundProcess, err := os.FindProcess(p.Pid)

			// Can't find the process at all
			if err != nil {
				Logger.Debugf("Could not find process with PID: %d", p.Pid)

				break
			}

			// We have some information about the procss
			if foundProcess != nil {
				processState, err := foundProcess.Wait()

				if err != nil || processState.Exited() {
					Logger.Debugf("Process with PID: %d has exited.", p.Pid)

					break
				}
			}

			// Retry in a moment
			sleepTime := time.Duration(1 * time.Second)
			time.Sleep(sleepTime)
		}

		c <- 1
	}()

	// Timeout this process after 3 seconds
	select {
	case _ = <-c:
		// Was successfully terminated
	case <-time.After(10 * time.Second):
		// Stop checking in the routine above
		checking = false

		// Forcefully kill the thing
		err = p.signal(syscall.SIGKILL)

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *Process) signal(sig os.Signal) error {
	Logger.Debugf("Sending signal: %s to PID: %d", sig.String(), p.Pid)

	err := p.command.Process.Signal(syscall.SIGTERM)
	if err != nil {
		Logger.Errorf("Failed to send signal: %s to PID: %d (%T: %v)", sig.String(), p.Pid, err, err)
		return err
	}

	return nil
}

// https://github.com/hnakamur/commango/blob/fe42b1cf82bf536ce7e24dceaef6656002e03743/os/executil/executil.go#L29
// TODO: Can this be better?
func getExitStatus(waitResult error) string {
	exitStatus := -1

	if waitResult != nil {
		if err, ok := waitResult.(*exec.ExitError); ok {
			if s, ok := err.Sys().(syscall.WaitStatus); ok {
				exitStatus = s.ExitStatus()
			} else {
				Logger.Error("Unimplemented for system where exec.ExitError.Sys() is not syscall.WaitStatus.")
			}
		}
	} else {
		exitStatus = 0
	}

	return fmt.Sprintf("%d", exitStatus)
}

func timeoutWait(waitGroup *sync.WaitGroup) error {
	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)

	// Start waiting for the routines to finish
	go func() {
		waitGroup.Wait()
		c <- 1
	}()

	select {
	case _ = <-c:
		return nil
	case <-time.After(10 * time.Second):
		return errors.New("Timeout")
	}

	return nil
}
<|endoftext|>


<commit_before>package bypasser

import (
	//"bytes"
	"encoding/binary"
	"errors"
	//"fmt"
	//"io"
	"crypto/aes"
	"crypto/cipher"
	"net"
	"strconv"
	//"time"
)

const (
	reserved = 0x00
)

const (
	bufferSize       = 128
	minRequestLength = 10
)

const (
	EncryptMethodAESCFB = iota
	EncryptMethodSimple
)
const (
	commandConnect      = 0x01
	commandBind         = 0x02
	commandUDPAssociate = 0x03
)

const (
	addressTypeIPv4       = 0x01
	addressTypeDomainName = 0x03
	addressTypeIPv6       = 0x04
)

const (
	replySucceeded                 = 0x00
	replyGeneralSOCKSServerFailure = 0x01
	replyConnectionNotAllowed      = 0x02
	replyNetworkUnreachable        = 0x03
	replyHostUnreachable           = 0x04
	replyConnectionRefused         = 0x05
	replyTTLExpired                = 0x06
	replyCommandNotSupported       = 0x07
	replyAddressTypeNotSupported   = 0x08
)

type request struct {
	version            byte
	command            byte
	rsv                byte
	addressType        byte
	destinationAddress []byte
	destinationPort    [2]byte
}

type response struct {
	version      byte
	reply        byte
	rsv          byte
	addressType  byte
	boundAddress []byte
	boundPort    [2]byte
}

func HandleRequest(rqst []byte, conn *net.TCPConn) ([]byte, error) {
	req, ok := formatRequest(rqst)
	if !ok {
		return []byte{}, errors.New("Invalid request packet.")
	}
	switch req.command {
	case commandConnect:
		{
			log("Handling command connect.", 3)
			return parseResponse(handleConnect(req, conn)), nil
		}
	default:
		{
			log("Command not supported.", 3)
			return parseResponse(generateFailureResponse(req.version, replyCommandNotSupported)), nil
		}
	}
}

func handleConnect(req request, conn *net.TCPConn) response {
	switch req.addressType {
	case addressTypeIPv4:
		{
			log("Address type is IPv4, start connecting.", 4)
			return startTcpConnectSession(req.version, req.destinationAddress, addressTypeIPv4, req.destinationPort, conn)
		}
	case addressTypeDomainName:
		{
			log("Address type is Domain name, start connecting.", 4)
			//log("Requested domain name is: "+string(req.destinationAddress[1:]), 4)
			//return generateFailureResponse(req.version, replyAddressTypeNotSupported)
			return startTcpConnectSession(req.version, req.destinationAddress, addressTypeDomainName, req.destinationPort, conn)
		}
	default:
		{
			log("Address type is not supported: "+strconv.Itoa(int(req.addressType)), 4)
			return generateFailureResponse(req.version, replyAddressTypeNotSupported)
		}
	}
}

func generateFailureResponse(version byte, reply byte) response {
	return response{version, reply, reserved, 0, []byte{}, [2]byte{0, 0}}
}

func startTcpConnectSession(version byte, addr []byte, addrType byte, port [2]byte, conn *net.TCPConn) response {
	var addrString string
	if addrType == addressTypeDomainName {
		addrString = string(addr[1:])
	} else {
		addrString = net.IP(addr).String()
	}
	log("Start to resolve the address: "+addrString+":"+formatPort(port), 5)
	targetAddr, err := net.ResolveTCPAddr("tcp", addrString+":"+formatPort(port))
	if err != nil {
		log("Fail to resolve tcp address.", 5)
		resp := generateFailureResponse(version, replyGeneralSOCKSServerFailure)
		return resp
	}
	connToTarget, err := net.DialTCP("tcp", nil, targetAddr)
	if err != nil {
		log("Failed to connect to the target.", 5)
		resp := generateFailureResponse(version, replyHostUnreachable)
		return resp
	} else {
		log("Connected to target.", 5)
		ipAddr, portNumber, _ := net.SplitHostPort(connToTarget.LocalAddr().String())
		ipAddrBytes := net.ParseIP(ipAddr)
		var addrType byte
		if ipAddrBytes.To4() != nil {
			log("Bound ip address is an IPv4 address", 5)
			ipAddrBytes = ipAddrBytes.To4()
			addrType = addressTypeIPv4
		} else {
			log("Bound ip address is an IPv6 address", 5)
			addrType = addressTypeIPv6
		}
		log("Bound port is: "+portNumber, 5)
		go buildTunnel(connToTarget, conn)
		return response{version, replySucceeded, reserved, addrType, ipAddrBytes, parsePort(portNumber)}
		// localAddr, _ := net.ResolveTCPAddr("tcp", ":0")
		// ln, err := net.ListenTCP("tcp", localAddr)
		// if err != nil {
		// 	log("Failed to get the listener to listen client.", 5)
		// 	resp := generateFailureResponse(version, replyGeneralSOCKSServerFailure)
		// 	return resp
		// } else {
		// 	log("Listener created.", 5)
		// 	networkAddr := ln.Addr().String()
		// 	//networkAddr := connToTarget.LocalAddr().String()
		// 	log("Local address is: "+networkAddr+".", 5)
		// 	ipAddr, portNumber, splitError := net.SplitHostPort(networkAddr)
		// 	if splitError != nil {
		// 		log("Failed to split the listen's local address.", 5)
		// 		resp := generateFailureResponse(version, replyGeneralSOCKSServerFailure)
		// 		return resp
		// 	} else {
		// 		ipAddr = "127.0.0.1"
		// ipAddrBytes := net.ParseIP(ipAddr)
		// var addrType byte
		// if ipAddrBytes.To4() != nil {
		// 	log("Bound ip address is an IPv4 address", 5)
		// 	addrType = addressTypeIPv4
		// } else {
		// 	log("Bound ip address is an IPv6 address", 5)
		// 	addrType = addressTypeIPv6
		// }
		// log("Bound port is: "+portNumber, 5)
		// 		resp := response{version, replySucceeded, reserved, addrType, ipAddrBytes, parsePort(portNumber)}

		// 		go waitClientToConnect(ln, connToTarget)
		// 		return resp

		// 	}
		// }
	}
}

// func waitClientToConnect(ln *net.TCPListener, connToTarget *net.TCPConn) {
// 	log("Waiting client to connect.", 5)
// 	connToClient, err := ln.AcceptTCP()
// 	log("Client connected.", 6)
// 	if err != nil {
// 		log("Client connected, but error occurs: "+err.Error(), 6)
// 		//break
// 	} else {
// 		log("Start building tunnel.", 6)
// 		go BuildTunnel(connToTarget, connToClient)
// 	}
// }

func buildTunnel(fromTarget, toClient *net.TCPConn) {
	// defer fromTarget.Close()

	// if _, err := fromTarget.Write(buf.Bytes()); err != nil {
	// 	panic(err)
	// }

	// data := make([]byte, 1024)
	// n, err := fromTarget.Read(data)
	// if err != nil {
	// 	if err != io.EOF {
	// 		panic(err)
	// 	} else {
	// 		toClient.Write(data[:n])

	// 	}
	// }
	// toClient.Close()
	tunnelForward := make(chan []byte)
	tunnelBackward := make(chan []byte)
	errorChannelForward := make(chan error)
	errorChannelBackward := make(chan error)
	go handleTunnel(fromTarget, tunnelForward, tunnelBackward, errorChannelForward, errorChannelBackward, true)
	go handleTunnel(toClient, tunnelBackward, tunnelForward, errorChannelBackward, errorChannelForward, false)

	// go func() {
	// 	for {
	// 		io.Copy(fromTarget, toClient)
	// 	}
	// }()
	// go func() {
	// 	for {
	// 		io.Copy(toClient, fromTarget)
	// 	}
	// }()
}

func handleTunnel(target *net.TCPConn, receiver <-chan []byte, sender chan<- []byte, errorChannelF <-chan error, errorChannelB chan<- error, shouldEncrypt bool) {
	errChan := make(chan error)
	dataChan := make(chan []byte)
	go func(dch chan []byte, ech chan error) {
		for {
			// buf := &bytes.Buffer{}
			// for {
			// 	data := make([]byte, 256)
			// 	n, err := target.Read(data)
			// 	if err != nil {
			// 		if err == io.EOF {
			// 			log("End of file encountered: "+err.Error(), 6)
			// 			break
			// 		} else {
			// 			log("Other error encountered: "+err.Error(), 6)
			// 			ech <- err
			// 			return
			// 		}

			// 	}
			// 	buf.Write(data[:n])
			// 	errChan <- errors.New("")
			// 	if data[n-2] == 13 && data[n-1] == 10 {
			// 		log("End of file encountered.", 6)
			// 		break
			// 	}
			// }
			// dch <- buf.Bytes()
			// return
			buf := make([]byte, bufferSize)
			//target.SetReadDeadline(time.Now())
			length, err := target.Read(buf)
			if err != nil {
				log("Error encountered: "+err.Error(), 6)
				ech <- err
				return
			} else {
				//target.SetReadDeadline(time.Time{})
				log(strconv.FormatInt(int64(length), 10)+" bytes of data received, sent to data channel.", 6)
				result := make([]byte, length)
				if shouldEncrypt {
					Encrypt(result, buf[:length], EncryptMethodSimple)
				} else {
					Decrypt(result, buf[:length], EncryptMethodSimple)
				}
				dch <- result
			}

		}
	}(dataChan, errChan)

	for {
		select {
		case data := <-dataChan:
			//log("Data received: "+string(data), 6)
			log("Data received from data channel, pass it to sender.", 6)
			sender <- data
		case err := <-errChan:
			// handle our error then exit for loop
			log("Error received from error channel: "+err.Error()+", notify the other routine to stop.", 6)
			errorChannelB <- err
			log("Tunnel ended.", 6)
			target.Close()
			return
		case err := <-errorChannelF:
			log("Error received from the other routine: "+err.Error()+", closing the connection.", 6)
			log("Tunnel ended.", 6)
			target.Close()
			return
		case data := <-receiver:
			log("Data received from receiver.", 6)
			target.Write(data)
		}
	}

}

func parsePort(p string) [2]byte {
	portNumber, _ := strconv.ParseUint(p, 10, 16)
	var result [2]byte
	binary.BigEndian.PutUint16(result[0:2], uint16(portNumber))
	return result
}

func formatPort(p [2]byte) string {
	return strconv.FormatUint(uint64(binary.BigEndian.Uint16(p[0:2])), 10)
}

func formatRequest(req []byte) (request, bool) {
	reqLen := len(req)
	if reqLen < minRequestLength {
		return request{}, false
	} else {
		rqst, ok := request{req[0], req[1], req[2], req[3], req[4 : reqLen-2], [2]byte{req[reqLen-2], req[reqLen-1]}}, true
		if rqst.addressType == addressTypeDomainName {
			//log()
		}
		return rqst, ok
	}
}

func parseResponse(resp response) []byte {
	//return []byte{resp.version, resp.reply, resp.rsv, resp.addressType, 0, 0, 0, 0, 0, 0}
	return append(append([]byte{resp.version, resp.reply, resp.rsv, resp.addressType}, resp.boundAddress...), resp.boundPort[:]...)
}

func log(msg string, lvl int) {
	blank := ""
	for i := 0; i < lvl; i++ {
		blank += "   "
	}
	//fmt.Println("GoFWBypasser:", blank, msg)
}

func encryptAESCFB(dst, src, key, iv []byte) error {
	aesBlockEncrypter, err := aes.NewCipher([]byte(key))
	if err != nil {
		return err
	}
	aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncrypter, iv)
	aesEncrypter.XORKeyStream(dst, src)
	return nil
}

func decryptAESCFB(dst, src, key, iv []byte) error {
	aesBlockDecrypter, err := aes.NewCipher([]byte(key))
	if err != nil {
		return nil
	}
	aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, iv)
	aesDecrypter.XORKeyStream(dst, src)
	return nil
}

func Encrypt(dst, src []byte, method int) error {
	key := "1234567890123456"
	iv := []byte(key)[:aes.BlockSize]
	switch method {
	case EncryptMethodSimple:
		{
			return encryptSimple(dst, src)
		}
	case EncryptMethodAESCFB:
		{
			return encryptAESCFB(dst, src, []byte(key), iv)
		}
	default:
		return errors.New("Unknown encryption method.")
	}
}

func Decrypt(dst, src []byte, method int) error {
	key := "1234567890123456"
	iv := []byte(key)[:aes.BlockSize]
	switch method {
	case EncryptMethodSimple:
		{
			return decryptSimple(dst, src)
		}
	case EncryptMethodAESCFB:
		{
			return decryptAESCFB(dst, src, []byte(key), iv)
		}
	default:
		return errors.New("Unknown encryption method.")
	}
}

func encryptSimple(dst, src []byte) error {
	for i := 0; i < len(src); i++ {
		dst[i] = 0xff - src[i]
	}
	return nil
}

func decryptSimple(dst, src []byte) error {
	for i := 0; i < len(src); i++ {
		dst[i] = 0xff - src[i]
	}
	return nil
}
<commit_msg>detect binding request<commit_after>package bypasser

import (
	//"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	//"io"
	"crypto/aes"
	"crypto/cipher"
	"net"
	"strconv"
	//"time"
)

const (
	reserved = 0x00
)

const (
	bufferSize       = 128
	minRequestLength = 10
)

const (
	EncryptMethodAESCFB = iota
	EncryptMethodSimple
)
const (
	commandConnect      = 0x01
	commandBind         = 0x02
	commandUDPAssociate = 0x03
)

const (
	addressTypeIPv4       = 0x01
	addressTypeDomainName = 0x03
	addressTypeIPv6       = 0x04
)

const (
	replySucceeded                 = 0x00
	replyGeneralSOCKSServerFailure = 0x01
	replyConnectionNotAllowed      = 0x02
	replyNetworkUnreachable        = 0x03
	replyHostUnreachable           = 0x04
	replyConnectionRefused         = 0x05
	replyTTLExpired                = 0x06
	replyCommandNotSupported       = 0x07
	replyAddressTypeNotSupported   = 0x08
)

type request struct {
	version            byte
	command            byte
	rsv                byte
	addressType        byte
	destinationAddress []byte
	destinationPort    [2]byte
}

type response struct {
	version      byte
	reply        byte
	rsv          byte
	addressType  byte
	boundAddress []byte
	boundPort    [2]byte
}

func HandleRequest(rqst []byte, conn *net.TCPConn) ([]byte, error) {
	req, ok := formatRequest(rqst)
	if !ok {
		return []byte{}, errors.New("Invalid request packet.")
	}
	switch req.command {
	case commandConnect:
		{
			log("Handling command connect.", 3)
			return parseResponse(handleConnect(req, conn)), nil
		}
	case commandBind:
		{
			fmt.Println("Bind request received! Please implement it asap!")
			return parseResponse(generateFailureResponse(req.version, replyCommandNotSupported)), nil
		}
	default:
		{
			log("Command not supported.", 3)
			return parseResponse(generateFailureResponse(req.version, replyCommandNotSupported)), nil
		}
	}
}

func handleConnect(req request, conn *net.TCPConn) response {
	switch req.addressType {
	case addressTypeIPv4:
		{
			log("Address type is IPv4, start connecting.", 4)
			return startTcpConnectSession(req.version, req.destinationAddress, addressTypeIPv4, req.destinationPort, conn)
		}
	case addressTypeDomainName:
		{
			log("Address type is Domain name, start connecting.", 4)
			//log("Requested domain name is: "+string(req.destinationAddress[1:]), 4)
			//return generateFailureResponse(req.version, replyAddressTypeNotSupported)
			return startTcpConnectSession(req.version, req.destinationAddress, addressTypeDomainName, req.destinationPort, conn)
		}
	default:
		{
			log("Address type is not supported: "+strconv.Itoa(int(req.addressType)), 4)
			return generateFailureResponse(req.version, replyAddressTypeNotSupported)
		}
	}
}

func generateFailureResponse(version byte, reply byte) response {
	return response{version, reply, reserved, 0, []byte{}, [2]byte{0, 0}}
}

func startTcpConnectSession(version byte, addr []byte, addrType byte, port [2]byte, conn *net.TCPConn) response {
	var addrString string
	if addrType == addressTypeDomainName {
		addrString = string(addr[1:])
	} else {
		addrString = net.IP(addr).String()
	}
	log("Start to resolve the address: "+addrString+":"+formatPort(port), 5)
	targetAddr, err := net.ResolveTCPAddr("tcp", addrString+":"+formatPort(port))
	if err != nil {
		log("Fail to resolve tcp address.", 5)
		resp := generateFailureResponse(version, replyGeneralSOCKSServerFailure)
		return resp
	}
	connToTarget, err := net.DialTCP("tcp", nil, targetAddr)
	if err != nil {
		log("Failed to connect to the target.", 5)
		resp := generateFailureResponse(version, replyHostUnreachable)
		return resp
	} else {
		log("Connected to target.", 5)
		ipAddr, portNumber, _ := net.SplitHostPort(connToTarget.LocalAddr().String())
		ipAddrBytes := net.ParseIP(ipAddr)
		var addrType byte
		if ipAddrBytes.To4() != nil {
			log("Bound ip address is an IPv4 address", 5)
			ipAddrBytes = ipAddrBytes.To4()
			addrType = addressTypeIPv4
		} else {
			log("Bound ip address is an IPv6 address", 5)
			addrType = addressTypeIPv6
		}
		log("Bound port is: "+portNumber, 5)
		go buildTunnel(connToTarget, conn)
		return response{version, replySucceeded, reserved, addrType, ipAddrBytes, parsePort(portNumber)}
		// localAddr, _ := net.ResolveTCPAddr("tcp", ":0")
		// ln, err := net.ListenTCP("tcp", localAddr)
		// if err != nil {
		// 	log("Failed to get the listener to listen client.", 5)
		// 	resp := generateFailureResponse(version, replyGeneralSOCKSServerFailure)
		// 	return resp
		// } else {
		// 	log("Listener created.", 5)
		// 	networkAddr := ln.Addr().String()
		// 	//networkAddr := connToTarget.LocalAddr().String()
		// 	log("Local address is: "+networkAddr+".", 5)
		// 	ipAddr, portNumber, splitError := net.SplitHostPort(networkAddr)
		// 	if splitError != nil {
		// 		log("Failed to split the listen's local address.", 5)
		// 		resp := generateFailureResponse(version, replyGeneralSOCKSServerFailure)
		// 		return resp
		// 	} else {
		// 		ipAddr = "127.0.0.1"
		// ipAddrBytes := net.ParseIP(ipAddr)
		// var addrType byte
		// if ipAddrBytes.To4() != nil {
		// 	log("Bound ip address is an IPv4 address", 5)
		// 	addrType = addressTypeIPv4
		// } else {
		// 	log("Bound ip address is an IPv6 address", 5)
		// 	addrType = addressTypeIPv6
		// }
		// log("Bound port is: "+portNumber, 5)
		// 		resp := response{version, replySucceeded, reserved, addrType, ipAddrBytes, parsePort(portNumber)}

		// 		go waitClientToConnect(ln, connToTarget)
		// 		return resp

		// 	}
		// }
	}
}

// func waitClientToConnect(ln *net.TCPListener, connToTarget *net.TCPConn) {
// 	log("Waiting client to connect.", 5)
// 	connToClient, err := ln.AcceptTCP()
// 	log("Client connected.", 6)
// 	if err != nil {
// 		log("Client connected, but error occurs: "+err.Error(), 6)
// 		//break
// 	} else {
// 		log("Start building tunnel.", 6)
// 		go BuildTunnel(connToTarget, connToClient)
// 	}
// }

func buildTunnel(fromTarget, toClient *net.TCPConn) {
	// defer fromTarget.Close()

	// if _, err := fromTarget.Write(buf.Bytes()); err != nil {
	// 	panic(err)
	// }

	// data := make([]byte, 1024)
	// n, err := fromTarget.Read(data)
	// if err != nil {
	// 	if err != io.EOF {
	// 		panic(err)
	// 	} else {
	// 		toClient.Write(data[:n])

	// 	}
	// }
	// toClient.Close()
	tunnelForward := make(chan []byte)
	tunnelBackward := make(chan []byte)
	errorChannelForward := make(chan error)
	errorChannelBackward := make(chan error)
	go handleTunnel(fromTarget, tunnelForward, tunnelBackward, errorChannelForward, errorChannelBackward, true)
	go handleTunnel(toClient, tunnelBackward, tunnelForward, errorChannelBackward, errorChannelForward, false)

	// go func() {
	// 	for {
	// 		io.Copy(fromTarget, toClient)
	// 	}
	// }()
	// go func() {
	// 	for {
	// 		io.Copy(toClient, fromTarget)
	// 	}
	// }()
}

func handleTunnel(target *net.TCPConn, receiver <-chan []byte, sender chan<- []byte, errorChannelF <-chan error, errorChannelB chan<- error, shouldEncrypt bool) {
	errChan := make(chan error)
	dataChan := make(chan []byte)
	go func(dch chan []byte, ech chan error) {
		for {
			// buf := &bytes.Buffer{}
			// for {
			// 	data := make([]byte, 256)
			// 	n, err := target.Read(data)
			// 	if err != nil {
			// 		if err == io.EOF {
			// 			log("End of file encountered: "+err.Error(), 6)
			// 			break
			// 		} else {
			// 			log("Other error encountered: "+err.Error(), 6)
			// 			ech <- err
			// 			return
			// 		}

			// 	}
			// 	buf.Write(data[:n])
			// 	errChan <- errors.New("")
			// 	if data[n-2] == 13 && data[n-1] == 10 {
			// 		log("End of file encountered.", 6)
			// 		break
			// 	}
			// }
			// dch <- buf.Bytes()
			// return
			buf := make([]byte, bufferSize)
			//target.SetReadDeadline(time.Now())
			length, err := target.Read(buf)
			if err != nil {
				log("Error encountered: "+err.Error(), 6)
				ech <- err
				return
			} else {
				//target.SetReadDeadline(time.Time{})
				log(strconv.FormatInt(int64(length), 10)+" bytes of data received, sent to data channel.", 6)
				result := make([]byte, length)
				if shouldEncrypt {
					Encrypt(result, buf[:length], EncryptMethodSimple)
				} else {
					Decrypt(result, buf[:length], EncryptMethodSimple)
				}
				dch <- result
			}

		}
	}(dataChan, errChan)

	for {
		select {
		case data := <-dataChan:
			//log("Data received: "+string(data), 6)
			log("Data received from data channel, pass it to sender.", 6)
			sender <- data
		case err := <-errChan:
			// handle our error then exit for loop
			log("Error received from error channel: "+err.Error()+", notify the other routine to stop.", 6)
			errorChannelB <- err
			log("Tunnel ended.", 6)
			target.Close()
			return
		case err := <-errorChannelF:
			log("Error received from the other routine: "+err.Error()+", closing the connection.", 6)
			log("Tunnel ended.", 6)
			target.Close()
			return
		case data := <-receiver:
			log("Data received from receiver.", 6)
			target.Write(data)
		}
	}

}

func parsePort(p string) [2]byte {
	portNumber, _ := strconv.ParseUint(p, 10, 16)
	var result [2]byte
	binary.BigEndian.PutUint16(result[0:2], uint16(portNumber))
	return result
}

func formatPort(p [2]byte) string {
	return strconv.FormatUint(uint64(binary.BigEndian.Uint16(p[0:2])), 10)
}

func formatRequest(req []byte) (request, bool) {
	reqLen := len(req)
	if reqLen < minRequestLength {
		return request{}, false
	} else {
		rqst, ok := request{req[0], req[1], req[2], req[3], req[4 : reqLen-2], [2]byte{req[reqLen-2], req[reqLen-1]}}, true
		if rqst.addressType == addressTypeDomainName {
			//log()
		}
		return rqst, ok
	}
}

func parseResponse(resp response) []byte {
	//return []byte{resp.version, resp.reply, resp.rsv, resp.addressType, 0, 0, 0, 0, 0, 0}
	return append(append([]byte{resp.version, resp.reply, resp.rsv, resp.addressType}, resp.boundAddress...), resp.boundPort[:]...)
}

func log(msg string, lvl int) {
	blank := ""
	for i := 0; i < lvl; i++ {
		blank += "   "
	}
	//fmt.Println("GoFWBypasser:", blank, msg)
}

func encryptAESCFB(dst, src, key, iv []byte) error {
	aesBlockEncrypter, err := aes.NewCipher([]byte(key))
	if err != nil {
		return err
	}
	aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncrypter, iv)
	aesEncrypter.XORKeyStream(dst, src)
	return nil
}

func decryptAESCFB(dst, src, key, iv []byte) error {
	aesBlockDecrypter, err := aes.NewCipher([]byte(key))
	if err != nil {
		return nil
	}
	aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, iv)
	aesDecrypter.XORKeyStream(dst, src)
	return nil
}

func Encrypt(dst, src []byte, method int) error {
	key := "1234567890123456"
	iv := []byte(key)[:aes.BlockSize]
	switch method {
	case EncryptMethodSimple:
		{
			return encryptSimple(dst, src)
		}
	case EncryptMethodAESCFB:
		{
			return encryptAESCFB(dst, src, []byte(key), iv)
		}
	default:
		return errors.New("Unknown encryption method.")
	}
}

func Decrypt(dst, src []byte, method int) error {
	key := "1234567890123456"
	iv := []byte(key)[:aes.BlockSize]
	switch method {
	case EncryptMethodSimple:
		{
			return decryptSimple(dst, src)
		}
	case EncryptMethodAESCFB:
		{
			return decryptAESCFB(dst, src, []byte(key), iv)
		}
	default:
		return errors.New("Unknown encryption method.")
	}
}

func encryptSimple(dst, src []byte) error {
	for i := 0; i < len(src); i++ {
		dst[i] = 0xff - src[i]
	}
	return nil
}

func decryptSimple(dst, src []byte) error {
	for i := 0; i < len(src); i++ {
		dst[i] = 0xff - src[i]
	}
	return nil
}
<|endoftext|>