<commit_before>package main

import (
	"flag"
	"github.com/gorilla/csrf"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"net"
	"os"
	"time"
	"net/http/fcgi"
)

var (
	mandrillApiUrl   string
	mandrillKey      string
	casgoDestination string
	casgoAPIKey      string
)

func main() {

	// We can set the CASGO_API_KEY environment variable, or it defaults to a new random one!

	if os.Getenv("CASGO_API_KEY") == "" {
		log.Println("Generating Random API Key...")

		// The length of the API key can be modified here.
		casgoAPIKey = GenerateAPIKey(20)

		// Print new GenerateAPIKey
		log.Println("CASGO_API_KEY:", getKey())
	} else {
		casgoAPIKey = os.Getenv("CASGO_API_KEY")
		// Print selected CASGO_API_KEY
		log.Println("CASGO_API_KEY:", getKey())
	}
	//
	port := flag.String("port", "8080", "HTTP Port to listen on")
	debug := flag.Bool("debug", false, "be verbose, dont switch to logfile")
	insecure := flag.Bool("insecure", false, "accept insecure cookie transfer")
	mailbox := flag.Bool("mailbox", false, "save messages to an local mbox file")
	fastcgi := flag.Bool("fastcgi", false, "use fastcgi")
	bind := flag.String("bind", "127.0.0.1", "default: 127.0.0.1")
	flag.Parse()

	mandrillApiUrl = "https://mandrillapp.com/api/1.0/"
	mandrillKey = os.Getenv("MANDRILL_KEY")
	if mandrillKey == "" {
		log.Fatal("MANDRILL_KEY is Crucial. Type: export MANDRILL_KEY=123456789")
		os.Exit(1)
	}

	casgoDestination = os.Getenv("CASGO_DESTINATION")
	if casgoDestination == "" {
		log.Fatal("CASGO_DESTINATION is Crucial. Type: export CASGO_DESTINATION=\"your@email.com\"")
		os.Exit(1)
	}

	log.Printf("listening on http://127.0.0.1:%s", *port)

	r := mux.NewRouter()

	// Custom 404 redirect to /
	r.NotFoundHandler = http.HandlerFunc(RedirectHomeHandler)

	// Should be called BlankPageHandler
	r.HandleFunc("/", HomeHandler)

	// This is the meat, for behind a reverse proxy.
	r.HandleFunc("/"+casgoAPIKey+"/form", ContactHandler)
	r.HandleFunc("/"+casgoAPIKey+"/form/", ContactHandler)
	//	r.HandleFunc("/contact/", ContactHandler)

	// Magic URL Generator for API endpoint
	r.HandleFunc("/"+casgoAPIKey+"/send", EmailHandler)

	// Fun for 404s
	r.HandleFunc("/{whatever}", LoveHandler)

	http.Handle("/", r)

	// Switch to file log so we can ctrl+c and launch another instance :)

	if *mailbox == true {
		log.Println("mailbox mode: [sending mail to casgo.mbox]")
		//CreateMailBox()
	}

	if *debug == false {
		log.Println("quiet mode: [switching logs to casgo.log]")
		OpenLogFile()
	} else {
		log.Println("debug on: [not using casgo.log]")
	}

	if *fastcgi == true {
		log.Println("fastcgi [on]")
		log.Println("secure [off]")
		listener, err := net.Listen("tcp", *bind+":"+*port)
		if err != nil {
			log.Fatal("Could not bind: ", err)
		}
		log.Println("info: Listening on", *port)
		log.Fatal(fcgi.Serve( listener, csrf.Protect([]byte("LI80PNK1xcT01jmQBsEyxyrNCrbyyFPjPU8CKnxwmCruxNijgnyb3hXXD3p1RBc0+LIRQUUbTtis6hc6LD4I/A=="), csrf.HttpOnly(true), csrf.Secure(false))(r)))

	}else
	if *insecure == true {
		log.Println("info: Listening on", *port)
		log.Println("secure [off]")
		log.Fatal(http.ListenAndServe(":"+*port, csrf.Protect([]byte("LI80PNK1xcT01jmQBsEyxyrNCrbyyFPjPU8CKnxwmCruxNijgnyb3hXXD3p1RBc0+LIRQUUbTtis6hc6LD4I/A=="), csrf.HttpOnly(true), csrf.Secure(false))(r)))
	}else {
		log.Println("info: Listening on", *port)
		// Change this CSRF auth token in production!
		log.Println("secure [on]")
		log.Fatal(http.ListenAndServe(":"+*port, csrf.Protect([]byte("LI80PNK1xcT01jmQBsEyxyrNCrbyyFPjPU8CKnxwmCruxNijgnyb3hXXD3p1RBc0+LIRQUUbTtis6hc6LD4I/A=="), csrf.HttpOnly(true), csrf.Secure(true))(r)))
	}

}

// Key Generator
func init() {
	rand.Seed(time.Now().UnixNano())
}

var runes = []rune("____ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890123456789012345678901234567890")

func GenerateAPIKey(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = runes[rand.Intn(len(runes))]
	}
	return string(b)
}

// Which Key are we using again?
func getKey() string {
	return casgoAPIKey
}

// This function opens a log file. "debug.log"
func OpenLogFile() {
	f, err := os.OpenFile("./casgo.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0660)
	if err != nil {
		log.Fatal("error opening file: %v", err)
		os.Exit(1)
	}
	log.SetOutput(f)
}

// This is the home page it is blank. "This server is broken"
<commit_msg>works with nginx + fastcgi!<commit_after>package main

import (
	"flag"
	"github.com/gorilla/csrf"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"net"
	"os"
	"time"
	"net/http/fcgi"
)

var (
	mandrillApiUrl   string
	mandrillKey      string
	casgoDestination string
	casgoAPIKey      string
)

func main() {

	// We can set the CASGO_API_KEY environment variable, or it defaults to a new random one!

	if os.Getenv("CASGO_API_KEY") == "" {
		log.Println("Generating Random API Key...")

		// The length of the API key can be modified here.
		casgoAPIKey = GenerateAPIKey(20)

		// Print new GenerateAPIKey
		log.Println("CASGO_API_KEY:", getKey())
	} else {
		casgoAPIKey = os.Getenv("CASGO_API_KEY")
		// Print selected CASGO_API_KEY
		log.Println("CASGO_API_KEY:", getKey())
	}
	//
	port := flag.String("port", "8080", "HTTP Port to listen on")
	debug := flag.Bool("debug", false, "be verbose, dont switch to logfile")
	insecure := flag.Bool("insecure", false, "accept insecure cookie transfer")
	mailbox := flag.Bool("mailbox", false, "save messages to an local mbox file")
	fastcgi := flag.Bool("fastcgi", false, "use fastcgi")
	bind := flag.String("bind", "127.0.0.1", "default: 127.0.0.1")
	flag.Parse()

	mandrillApiUrl = "https://mandrillapp.com/api/1.0/"
	mandrillKey = os.Getenv("MANDRILL_KEY")
	if mandrillKey == "" {
		log.Fatal("MANDRILL_KEY is Crucial. Type: export MANDRILL_KEY=123456789")
		os.Exit(1)
	}

	casgoDestination = os.Getenv("CASGO_DESTINATION")
	if casgoDestination == "" {
		log.Fatal("CASGO_DESTINATION is Crucial. Type: export CASGO_DESTINATION=\"your@email.com\"")
		os.Exit(1)
	}

	log.Printf("listening on http://127.0.0.1:%s", *port)

	r := mux.NewRouter()

	// Custom 404 redirect to /
	r.NotFoundHandler = http.HandlerFunc(RedirectHomeHandler)

	// Should be called BlankPageHandler
	r.HandleFunc("/", HomeHandler)

	// This is the meat, for behind a reverse proxy.
	r.HandleFunc("/"+casgoAPIKey+"/form", ContactHandler)
	r.HandleFunc("/"+casgoAPIKey+"/form/", ContactHandler)
	//	r.HandleFunc("/contact/", ContactHandler)

	// Magic URL Generator for API endpoint
	r.HandleFunc("/"+casgoAPIKey+"/send", EmailHandler)

	// Fun for 404s
	r.HandleFunc("/{whatever}", LoveHandler)

	http.Handle("/", r)

	// Switch to file log so we can ctrl+c and launch another instance :)

	if *mailbox == true {
		log.Println("mailbox mode: [sending mail to casgo.mbox]")
		//CreateMailBox()
	}

	if *debug == false {
		log.Println("quiet mode: [switching logs to casgo.log]")
		OpenLogFile()
	} else {
		log.Println("debug on: [not using casgo.log]")
	}

	if *fastcgi == true {
		log.Println("fastcgi [on]")
		log.Println("secure [off]")
		listener, err := net.Listen("tcp", *bind+":"+*port)
		if err != nil {
			log.Fatal("Could not bind: ", err)
		}
		log.Println("info: Listening on", *port)
		fcgi.Serve(listener, nil)
		//log.Fatal(fcgi.Serve( listener, csrf.Protect([]byte("LI80PNK1xcT01jmQBsEyxyrNCrbyyFPjPU8CKnxwmCruxNijgnyb3hXXD3p1RBc0+LIRQUUbTtis6hc6LD4I/A=="), csrf.HttpOnly(true), csrf.Secure(false))(r)))

	}else	if *insecure == true {
		log.Println("info: Listening on", *port)
		log.Println("secure [off]")
		log.Fatal(http.ListenAndServe(":"+*port, csrf.Protect([]byte("LI80PNK1xcT01jmQBsEyxyrNCrbyyFPjPU8CKnxwmCruxNijgnyb3hXXD3p1RBc0+LIRQUUbTtis6hc6LD4I/A=="), csrf.HttpOnly(true), csrf.Secure(false))(r)))
	}else {
		log.Println("info: Listening on", *port)
		// Change this CSRF auth token in production!
		log.Println("secure [on]")
		log.Fatal(http.ListenAndServe(":"+*port, csrf.Protect([]byte("LI80PNK1xcT01jmQBsEyxyrNCrbyyFPjPU8CKnxwmCruxNijgnyb3hXXD3p1RBc0+LIRQUUbTtis6hc6LD4I/A=="), csrf.HttpOnly(true), csrf.Secure(true))(r)))
	}

}

// Key Generator
func init() {
	rand.Seed(time.Now().UnixNano())
}

var runes = []rune("____ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890123456789012345678901234567890")

func GenerateAPIKey(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = runes[rand.Intn(len(runes))]
	}
	return string(b)
}

// Which Key are we using again?
func getKey() string {
	return casgoAPIKey
}

// This function opens a log file. "debug.log"
func OpenLogFile() {
	f, err := os.OpenFile("./casgo.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0660)
	if err != nil {
		log.Fatal("error opening file: %v", err)
		os.Exit(1)
	}
	log.SetOutput(f)
}

// This is the home page it is blank. "This server is broken"
<|endoftext|>


<commit_before>package main

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

	"github.com/trinchan/slackbot/Godeps/_workspace/src/github.com/gorilla/schema"
	_ "github.com/trinchan/slackbot/importer"
	"github.com/trinchan/slackbot/robots"
)

func main() {
	http.HandleFunc("/slack", slashCommandHandler)
	http.HandleFunc("/slack_hook", hookHandler)
	startServer()
}

func hookHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.OutgoingWebHook)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	if command.Text == "" || command.Token != os.Getenv(fmt.Sprintf("%s_OUT_TOKEN", strings.ToUpper(command.TeamDomain))) {
		log.Printf("[DEBUG] Ignoring request from unidentified source: %s - %s", command.Token, r.Host)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	com := strings.TrimPrefix(command.Text, command.TriggerWord+" ")
	c := strings.Split(com, " ")
	command.Robot = c[0]
	command.Text = strings.Join(c[1:], " ")

	robots := getRobots(command.Robot)
	if len(robots) == 0 {
		jsonResp(w, "No robot for that command yet :(")
		return
	}
	resp := ""
	for _, robot := range robots {
		resp += fmt.Sprintf("\n%s", robot.Run(&command.Payload))
	}
	w.WriteHeader(http.StatusOK)
	jsonResp(w, strings.TrimSpace(resp))
}

func slashCommandHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.SlashCommand)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	if command.Command == "" || command.Token == "" {
		log.Printf("[DEBUG] Ignoring request from unidentified source: %s - %s", command.Token, r.Host)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	command.Robot = command.Command[1:]

	if token := os.Getenv(fmt.Sprintf("%s_SLACK_TOKEN", strings.ToUpper(command.Robot))); token != "" && token != command.Token {
		log.Printf("[DEBUG] Ignoring request from unidentified source: %s - %s", command.Token, r.Host)
		w.WriteHeader(http.StatusBadRequest)
	}
	robots := getRobots(command.Robot)
	if len(robots) == 0 {
		plainResp(w, "No robot for that command yet :(")
		return
	}
	resp := ""
	for _, robot := range robots {
		resp += fmt.Sprintf("\n%s", robot.Run(&command.Payload))
	}
	plainResp(w, strings.TrimSpace(resp))
}

func jsonResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	resp := map[string]string{"text": msg}
	r, err := json.Marshal(resp)
	if err != nil {
		log.Println("Couldn't marshal hook response:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(r)
}

func plainResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write([]byte(msg))
}

func startServer() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("PORT not set")
	}
	log.Printf("Starting HTTP server on %s", port)
	err := http.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Fatal("Server start error: ", err)
	}
}

func getRobots(command string) []robots.Robot {
	if r, ok := robots.Robots[command]; ok {
		return r
	}
	return nil
}
<commit_msg>Better error message when command not found<commit_after>package main

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

	"github.com/trinchan/slackbot/Godeps/_workspace/src/github.com/gorilla/schema"
	_ "github.com/trinchan/slackbot/importer"
	"github.com/trinchan/slackbot/robots"
)

func main() {
	http.HandleFunc("/slack", slashCommandHandler)
	http.HandleFunc("/slack_hook", hookHandler)
	startServer()
}

func hookHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.OutgoingWebHook)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	if command.Text == "" || command.Token != os.Getenv(fmt.Sprintf("%s_OUT_TOKEN", strings.ToUpper(command.TeamDomain))) {
		log.Printf("[DEBUG] Ignoring request from unidentified source: %s - %s", command.Token, r.Host)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	com := strings.TrimPrefix(command.Text, command.TriggerWord+" ")
	c := strings.Split(com, " ")
	command.Robot = c[0]
	command.Text = strings.Join(c[1:], " ")

	robots := getRobots(command.Robot)
	if len(robots) == 0 {
		msg := fmt.Sprintf("No robot for %s (%s)", command.Robot, command.Text)
		jsonResp(w, msg)
		return
	}
	resp := ""
	for _, robot := range robots {
		resp += fmt.Sprintf("\n%s", robot.Run(&command.Payload))
	}
	w.WriteHeader(http.StatusOK)
	jsonResp(w, strings.TrimSpace(resp))
}

func slashCommandHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.SlashCommand)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	if command.Command == "" || command.Token == "" {
		log.Printf("[DEBUG] Ignoring request from unidentified source: %s - %s", command.Token, r.Host)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	command.Robot = command.Command[1:]

	if token := os.Getenv(fmt.Sprintf("%s_SLACK_TOKEN", strings.ToUpper(command.Robot))); token != "" && token != command.Token {
		log.Printf("[DEBUG] Ignoring request from unidentified source: %s - %s", command.Token, r.Host)
		w.WriteHeader(http.StatusBadRequest)
	}
	robots := getRobots(command.Robot)
	if len(robots) == 0 {
		plainResp(w, "No robot for that command yet :(")
		return
	}
	resp := ""
	for _, robot := range robots {
		resp += fmt.Sprintf("\n%s", robot.Run(&command.Payload))
	}
	plainResp(w, strings.TrimSpace(resp))
}

func jsonResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	resp := map[string]string{"text": msg}
	r, err := json.Marshal(resp)
	if err != nil {
		log.Println("Couldn't marshal hook response:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(r)
}

func plainResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write([]byte(msg))
}

func startServer() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("PORT not set")
	}
	log.Printf("Starting HTTP server on %s", port)
	err := http.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Fatal("Server start error: ", err)
	}
}

func getRobots(command string) []robots.Robot {
	if r, ok := robots.Robots[command]; ok {
		return r
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/vaughan0/go-ini"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"ponydownloader/settings"
	"strconv"

	//	"errors"
	//	"net"
)

//	defaults:
var (
	QDEPTH    int64  = 10    //depth of the queue of processed images
	IMGDIR    string = "img" //default download directory
	TAG       string = ""    //default string is empty, it can only ge extracted from command line
	STARTPAGE int    = 1     //default start page, derpiboo.ru 1-indexed
	STOPPAGE  int    = 0     //default stop page, would stop parsing json when stop page is reached or site reaches the end of search
	elog      *log.Logger
)

func main() {

	fmt.Println("Derpiboo.ru Downloader version 0.1.4")

	elog, logfile := settings.SetLog() //setting up logging of errors

	defer logfile.Close() //Almost forgot. Always close the file in the end.

	config, err := ini.LoadFile("config.ini") // Loading default config file and checking for various errors.

	if os.IsNotExist(err) {
		elog.Fatalln("Config.ini does not exist, create it")
	}

	if err != nil {
		elog.Panicln(err)
	}

	//Getting stuff from config, overwriting defaults

	key, ok := config.Get("main", "key")

	if !ok {
		elog.Println("'key' variable missing from 'main' section")
	}

	Q_temp, _ := config.Get("main", "workers")

	if Q_temp != "" {
		QDEPTH, err = strconv.ParseInt(Q_temp, 10, 0)

		if err != nil {
			elog.Fatalln("Wrong configuration: Amount of workers is not a number")

		}
	}

	ID_temp, _ := config.Get("main", "downdir")

	if ID_temp != "" {
		IMGDIR = ID_temp
	}

	//Here we are parsing all the flags

	flag.StringVar(&TAG, "t", TAG, "Tags to download")
	flag.IntVar(&STARTPAGE, "p", STARTPAGE, "Starting page for search")
	flag.IntVar(&STOPPAGE, "sp", STOPPAGE, "Stopping page for search, 0 - parse all all search pages")

	flag.Parse()

	if flag.NArg() == 0 && TAG == "" { //If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.
		log.SetPrefix("Done at ")
		log.Println("Nothing to download, bye!")
		os.Exit(0)
	}

	//	creating directory for downloads if not yet done
	if err := os.MkdirAll(IMGDIR, 0777); err != nil { //Execute? No need to execute any image
		elog.Fatalln(err) //We can not create folder for images, dying horribly
	}

	//	creating channels to pass info to downloader and to signal job well done
	imgdat := make(chan Image, QDEPTH)
	done := make(chan bool)

	if TAG == "" { //Because we can put imgid with flags. Why not?

		//	checking argument for being a number and then getting image data

		imgid := flag.Arg(0)
		_, err = strconv.Atoi(imgid)

		if err != nil {
			elog.Fatalln("Wrong input: can not parse", imgid, "as a number")
		}

		log.Println("Processing image No", imgid)

		go ParseImg(imgdat, imgid, key)

	} else {

		//	and here we send tags to getter/parser

		log.Println("Processing tags", TAG)
		go ParseTag(imgdat, TAG, key)
	}

	log.Println("Starting worker")
	go DlImg(imgdat, done)

	<-done
	log.SetPrefix("Done at ")
	log.Println("Finised")

}

type Image struct {
	imgid    int
	url      string
	filename string
	hash     string
}

func ParseImg(imgchan chan<- Image, imgid string, key string) {

	source := "http://derpiboo.ru/" + imgid + ".json?nofav=&nocomments="
	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Getting image info at:", source)

	resp, err := http.Get(source) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
	if err != nil {
		elog.Println(err)
		return
	}

	defer resp.Body.Close() //and not forgetting to close it when it's done

	var dat map[string]interface{}

	body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
	if err != nil {
		elog.Println(err)
		return
	}

	if err := json.Unmarshal(body, &dat); //transforming json into native map

	err != nil {
		elog.Println(err)
		return
	}

	InfoToChannel(dat, imgchan)

	close(imgchan) //closing channel, we are done here

	return
}

func DlImg(imgchan <-chan Image, done chan bool) {

	fmt.Println("Worker started; reading channel") //nice notification that we are not forgotten

	for {

		imgdata, more := <-imgchan

		if more { //checking that there is an image in channel

			if imgdata.filename == "" {
				elog.Println("Empty filename. Oops?") //something somewhere had gone wrong, going to the next image
			} else {

				fmt.Println("Saving as", imgdata.filename)

				func() { // to not hold all the files open when there is no need

					output, err := os.Create(IMGDIR + string(os.PathSeparator) + imgdata.filename) //And now, THE FILE!
					if err != err {
						elog.Println("Error when creating file for image" + strconv.Itoa(imgdata.imgid))
						elog.Println(err)
						return
					}
					defer output.Close() //Not forgetting to deal with it after completing download

					response, err := http.Get(imgdata.url)
					if err != nil {
						elog.Println("Error when gettint image", imgdata.imgid)
						elog.Println(err)
						return
					}
					defer response.Body.Close() //Same, we shall not listen to the void when we finished getting image

					hash := sha512.New()

					io.Copy(io.MultiWriter(output, hash), response.Body) //	Writing things we got from Derpibooru into the

					b := make([]byte, hash.Size())
					hash.Sum(b[:0])

					//	fmt.Println("\n", hex.EncodeToString(b), "\n", imgdata.hash )

					if hex.EncodeToString(b) != imgdata.hash {
						elog.Println("Hash wrong with imageid", imgdata.imgid)
					}
				}()
			}

			//fmt.Println("\n", hex.EncodeToString(hash.Sum(nil)), "\n", imgdata.hash )

		} else {
			done <- true //well, there is no images in channel, it means we got them all, so synchronization is kicking in and ending the process
			break        //Just in case, so it would not stupidly die when program finishes - it will die smartly

		}
	}
}

func ParseTag(imgchan chan<- Image, tag string, key string) {

	source := "http://derpiboo.ru/search.json?nofav=&nocomments=" //yay hardwiring url strings!

	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Searching as", source+"&q="+tag)
	var working bool = true
	i := STARTPAGE
	for working {
		func() {
			fmt.Println("Searching page", i)
			resp, err := http.Get(source + "&q=" + tag + "&page=" + strconv.Itoa(i)) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
			defer resp.Body.Close()                                                  //and not forgetting to close it when it's done. And before we panic and die horribly.
			if err != nil {
				elog.Println("Error while getting search page", i)
				elog.Println(err)
				return
			}

			var dats []map[string]interface{} //Because we got array incoming instead of single object, we using an slive of maps!

			//fmt.Println(resp)

			body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
			if err != nil {
				elog.Println("Error while reading search page", i)
				elog.Println(err)
				return
			}

			//fmt.Println(body)

			if err := json.Unmarshal(body, &dats); //transforming json into native slice of maps

			err != nil {
				elog.Println("Error while parsing search page", i)
				elog.Println(err)
				return

			}

			if len(dats) == 0 {
				fmt.Println("Pages are over")
				working = false
				return
			} //exit due to finishing all pages

			for _, dat := range dats {
				InfoToChannel(dat, imgchan)
			}
			if i == STOPPAGE {
				working = false
				return
			}
			i++

		}()
	}

	close(imgchan)
}

func InfoToChannel(dat map[string]interface{}, imgchan chan<- Image) {

	var imgdata Image

	imgdata.url = "http:" + dat["image"].(string)
	imgdata.hash = dat["sha512_hash"].(string)
	imgdata.filename = (strconv.FormatFloat(dat["id_number"].(float64), 'f', -1, 64) + "." + dat["file_name"].(string) + "." + dat["original_format"].(string))
	imgdata.imgid = int(dat["id_number"].(float64))

	//	for troubleshooting later
	//	fmt.Println(dat)
	//	fmt.Println(imgdata.url)
	//	fmt.Println(imgdata.hash)
	//	fmt.Println(imgdata.filename)

	imgchan <- imgdata
}
<commit_msg>something is wrong. Attempting to find and fix<commit_after>package main

import (
	"crypto/sha512"
	//"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/vaughan0/go-ini"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"ponydownloader/settings"
	"strconv"

	//	"errors"
	//	"net"
)

//	defaults:
var (
	QDEPTH    int64  = 10    //depth of the queue of processed images
	IMGDIR    string = "img" //default download directory
	TAG       string = ""    //default string is empty, it can only ge extracted from command line
	STARTPAGE int    = 1     //default start page, derpiboo.ru 1-indexed
	STOPPAGE  int    = 0     //default stop page, would stop parsing json when stop page is reached or site reaches the end of search
	elog      *log.Logger
)

func main() {

	fmt.Println("Derpiboo.ru Downloader version 0.1.4")

	elog, logfile := settings.SetLog() //setting up logging of errors

	defer logfile.Close() //Almost forgot. Always close the file in the end.

	config, err := ini.LoadFile("config.ini") // Loading default config file and checking for various errors.

	if os.IsNotExist(err) {
		elog.Fatalln("Config.ini does not exist, create it")
	}

	if err != nil {
		elog.Panicln(err)
	}

	//Getting stuff from config, overwriting defaults

	key, ok := config.Get("main", "key")

	if !ok {
		elog.Println("'key' variable missing from 'main' section")
	}

	Q_temp, _ := config.Get("main", "workers")

	if Q_temp != "" {
		QDEPTH, err = strconv.ParseInt(Q_temp, 10, 0)

		if err != nil {
			elog.Fatalln("Wrong configuration: Amount of workers is not a number")

		}
	}

	ID_temp, _ := config.Get("main", "downdir")

	if ID_temp != "" {
		IMGDIR = ID_temp
	}

	//Here we are parsing all the flags

	flag.StringVar(&TAG, "t", TAG, "Tags to download")
	flag.IntVar(&STARTPAGE, "p", STARTPAGE, "Starting page for search")
	flag.IntVar(&STOPPAGE, "sp", STOPPAGE, "Stopping page for search, 0 - parse all all search pages")

	flag.Parse()

	if flag.NArg() == 0 && TAG == "" { //If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.
		log.SetPrefix("Done at ")
		log.Println("Nothing to download, bye!")
		os.Exit(0)
	}

	//	creating directory for downloads if not yet done
	if err := os.MkdirAll(IMGDIR, 0777); err != nil { //Execute? No need to execute any image
		elog.Fatalln(err) //We can not create folder for images, dying horribly
	}

	//	creating channels to pass info to downloader and to signal job well done
	imgdat := make(chan Image, QDEPTH)
	done := make(chan bool)

	if TAG == "" { //Because we can put imgid with flags. Why not?

		//	checking argument for being a number and then getting image data

		imgid := flag.Arg(0)
		_, err = strconv.Atoi(imgid)

		if err != nil {
			elog.Fatalln("Wrong input: can not parse", imgid, "as a number")
		}

		log.Println("Processing image No", imgid)

		go ParseImg(imgdat, imgid, key)

	} else {

		//	and here we send tags to getter/parser

		log.Println("Processing tags", TAG)
		go ParseTag(imgdat, TAG, key)
	}

	log.Println("Starting worker")
	go DlImg(imgdat, done)

	<-done
	log.SetPrefix("Done at ")
	log.Println("Finised")

}

type Image struct {
	imgid    int
	url      string
	filename string
	hash     string
}

func ParseImg(imgchan chan<- Image, imgid string, key string) {

	source := "http://derpiboo.ru/images/" + imgid + ".json?nofav=&nocomments="
	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Getting image info at:", source)

	resp, err := http.Get(source) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
	if err != nil {
		elog.Println(err)
		return
	}

	defer resp.Body.Close() //and not forgetting to close it when it's done

	var dat map[string]interface{}

	body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
	if err != nil {
		elog.Println(err)
		return
	}

	if err := json.Unmarshal(body, &dat); //transforming json into native map

	err != nil {
		elog.Println(err)
		return
	}

	InfoToChannel(dat, imgchan)

	close(imgchan) //closing channel, we are done here

	return
}

func DlImg(imgchan <-chan Image, done chan bool) {

	fmt.Println("Worker started; reading channel") //nice notification that we are not forgotten

	for {

		imgdata, more := <-imgchan

		if more { //checking that there is an image in channel

			if imgdata.filename == "" {
				elog.Println("Empty filename. Oops?") //something somewhere had gone wrong, going to the next image
			} else {

				fmt.Println("Saving as", imgdata.filename)

				func() { // to not hold all the files open when there is no need

					output, err := os.Create(IMGDIR + string(os.PathSeparator) + imgdata.filename) //And now, THE FILE!
					if err != err {
						elog.Println("Error when creating file for image" + strconv.Itoa(imgdata.imgid))
						elog.Println(err)
						return
					}
					defer output.Close() //Not forgetting to deal with it after completing download

					response, err := http.Get(imgdata.url)
					if err != nil {
						elog.Println("Error when gettint image", imgdata.imgid)
						elog.Println(err)
						return
					}
					defer response.Body.Close() //Same, we shall not listen to the void when we finished getting image

					hash := sha512.New()

					io.Copy(io.MultiWriter(output, hash), response.Body) //	Writing things we got from Derpibooru into the

					b := make([]byte, hash.Size())
					hash.Sum(b[:0])

					//	fmt.Println("\n", hex.EncodeToString(b), "\n", imgdata.hash )

					//if hex.EncodeToString(b) != imgdata.hash {
						//elog.Println("Hash wrong with imageid", imgdata.imgid)
					//}
				}()
			}

			//fmt.Println("\n", hex.EncodeToString(hash.Sum(nil)), "\n", imgdata.hash )

		} else {
			done <- true //well, there is no images in channel, it means we got them all, so synchronization is kicking in and ending the process
			break        //Just in case, so it would not stupidly die when program finishes - it will die smartly

		}
	}
}

func ParseTag(imgchan chan<- Image, tag string, key string) {

	source := "http://derpiboo.ru/search.json?nofav=&nocomments=" //yay hardwiring url strings!

	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Searching as", source+"&q="+tag)
	var working bool = true
	i := STARTPAGE
	for working {
		func() {
			fmt.Println("Searching page", i)
			resp, err := http.Get(source + "&q=" + tag + "&page=" + strconv.Itoa(i)) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
			defer resp.Body.Close()                                                  //and not forgetting to close it when it's done. And before we panic and die horribly.
			if err != nil {
				elog.Println("Error while getting search page", i)
				elog.Println(err)
				return
			}

			var dats []map[string]interface{} //Because we got array incoming instead of single object, we using an slive of maps!

			//fmt.Println(resp)

			body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
			if err != nil {
				elog.Println("Error while reading search page", i)
				elog.Println(err)
				return
			}

			//fmt.Println(body)

			if err := json.Unmarshal(body, &dats); //transforming json into native slice of maps

			err != nil {
				elog.Println("Error while parsing search page", i)
				elog.Println(err)
				return

			}

			if len(dats) == 0 {
				fmt.Println("Pages are over")
				working = false
				return
			} //exit due to finishing all pages

			for _, dat := range dats {
				InfoToChannel(dat, imgchan)
			}
			if i == STOPPAGE {
				working = false
				return
			}
			i++

		}()
	}

	close(imgchan)
}

func InfoToChannel(dat map[string]interface{}, imgchan chan<- Image) {

	var imgdata Image

	imgdata.url = "http:" + dat["image"].(string)
	imgdata.hash = dat["sha512_hash"].(string)
	imgdata.filename = (strconv.FormatFloat(dat["id_number"].(float64), 'f', -1, 64) + "." + dat["file_name"].(string) + "." + dat["original_format"].(string))
	imgdata.imgid = int(dat["id_number"].(float64))

	//	for troubleshooting later
	//	fmt.Println(dat)
	//	fmt.Println(imgdata.url)
	//	fmt.Println(imgdata.hash)
	//	fmt.Println(imgdata.filename)

	imgchan <- imgdata
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/x509"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
	"time"
)

var pemName string
var certsRoot string
var expireTime string

type CertPem struct {
	Cert *x509.Certificate
	Pem  []byte
}

func (certPem *CertPem) GetCertPool() *x509.CertPool {
	pool := x509.NewCertPool()

	ok := pool.AppendCertsFromPEM(certPem.Pem)

	if !ok {
		log.Fatal("Couldn't add pem")
	}

	return pool
}

func NewCertPem(pem []byte) CertPem {
	certPem := CertPem{
		Pem: pem,
	}

	certPem.ParseCert()

	return certPem
}

func (certPem *CertPem) ParseCert() {
	block, _ := pem.Decode(certPem.Pem)

	cert, err := x509.ParseCertificate(block.Bytes)

	if err != nil {
		log.Fatal(err)
	}

	certPem.Cert = cert
}

func getCertDirectoryNames(dir string) []string {
	f, err := os.Open(dir)

	if err != nil {
		log.Fatal(err)
	}

	names, err := f.Readdirnames(0)

	if err != nil {
		log.Fatal(err)
	}

	return names
}

func readPem(dir string) []byte {
	f, err := ioutil.ReadFile(path.Join(dir, pemName))

	if err != nil {
		log.Fatal(err)
	}

	return f
}

func filterExpiringCerts(certs []CertPem, expire time.Time) []*x509.Certificate {
	output := make([]*x509.Certificate, 0, len(certs))

	for _, cert := range certs {

		verifyOptions := x509.VerifyOptions{
			CurrentTime:   expire,
			Intermediates: cert.GetCertPool(),
		}

		if _, err := cert.Cert.Verify(verifyOptions); err != nil {
			output = append(output, cert.Cert)
		}
	}

	return output
}

func getDefaultExpireTime() time.Time {
	return time.Now().Add(time.Hour * 24 * 7 * 2)
}

func getUserDefinedExpireTime(expireTime string) time.Time {
	expire, err := time.Parse(time.UnixDate, expireTime)

	if err != nil {
		log.Fatal(err)
	}

	return expire
}

func getExpireTime(expireTime string) time.Time {
	if expireTime == "" {
		return getDefaultExpireTime()
	} else {
		return getUserDefinedExpireTime(expireTime)
	}
}

func getCertificates(dirs []string) []CertPem {
	certificates := make([]CertPem, len(dirs))

	for index, dir := range dirs {
		certPath := path.Join(certsRoot, dir)
		pem := readPem(certPath)

		certPem := NewCertPem(pem)

		certificates[index] = certPem
	}

	return certificates
}

func collectDomains(expiringCerts []*x509.Certificate) [][]string {
	domains := make([][]string, 0, len(expiringCerts))

	for _, cert := range expiringCerts {
		domains = append(domains, cert.DNSNames)
	}

	return domains
}

func printDomains(domains [][]string) {
	for _, domain := range domains {
		fmt.Println(strings.Join(domain, " "))
	}
}

func init() {
	flag.StringVar(&pemName, "pem-name", "fullchain.pem", "The name of the pem file, usually fullchain.pem")
	flag.StringVar(&certsRoot, "certs-path", "/etc/letsencrypt/live", "The path to the directory which stores the certificates")
	flag.StringVar(&expireTime, "expire", "", "Expire time of the certificates in unix date format (run date command \"$(date --date='15/03/2016')\"), eg.: Mon Dec 14 13:36:37 CET 2015")

	flag.Parse()
}

func main() {

	expire := getExpireTime(expireTime)

	dirs := getCertDirectoryNames(certsRoot)

	certificates := getCertificates(dirs)

	expiringCerts := filterExpiringCerts(certificates, expire)

	domains := collectDomains(expiringCerts)

	printDomains(domains)
}
<commit_msg>Fix example date in help<commit_after>package main

import (
	"crypto/x509"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
	"time"
)

var pemName string
var certsRoot string
var expireTime string

type CertPem struct {
	Cert *x509.Certificate
	Pem  []byte
}

func (certPem *CertPem) GetCertPool() *x509.CertPool {
	pool := x509.NewCertPool()

	ok := pool.AppendCertsFromPEM(certPem.Pem)

	if !ok {
		log.Fatal("Couldn't add pem")
	}

	return pool
}

func NewCertPem(pem []byte) CertPem {
	certPem := CertPem{
		Pem: pem,
	}

	certPem.ParseCert()

	return certPem
}

func (certPem *CertPem) ParseCert() {
	block, _ := pem.Decode(certPem.Pem)

	cert, err := x509.ParseCertificate(block.Bytes)

	if err != nil {
		log.Fatal(err)
	}

	certPem.Cert = cert
}

func getCertDirectoryNames(dir string) []string {
	f, err := os.Open(dir)

	if err != nil {
		log.Fatal(err)
	}

	names, err := f.Readdirnames(0)

	if err != nil {
		log.Fatal(err)
	}

	return names
}

func readPem(dir string) []byte {
	f, err := ioutil.ReadFile(path.Join(dir, pemName))

	if err != nil {
		log.Fatal(err)
	}

	return f
}

func filterExpiringCerts(certs []CertPem, expire time.Time) []*x509.Certificate {
	output := make([]*x509.Certificate, 0, len(certs))

	for _, cert := range certs {

		verifyOptions := x509.VerifyOptions{
			CurrentTime:   expire,
			Intermediates: cert.GetCertPool(),
		}

		if _, err := cert.Cert.Verify(verifyOptions); err != nil {
			output = append(output, cert.Cert)
		}
	}

	return output
}

func getDefaultExpireTime() time.Time {
	return time.Now().Add(time.Hour * 24 * 7 * 2)
}

func getUserDefinedExpireTime(expireTime string) time.Time {
	expire, err := time.Parse(time.UnixDate, expireTime)

	if err != nil {
		log.Fatal(err)
	}

	return expire
}

func getExpireTime(expireTime string) time.Time {
	if expireTime == "" {
		return getDefaultExpireTime()
	} else {
		return getUserDefinedExpireTime(expireTime)
	}
}

func getCertificates(dirs []string) []CertPem {
	certificates := make([]CertPem, len(dirs))

	for index, dir := range dirs {
		certPath := path.Join(certsRoot, dir)
		pem := readPem(certPath)

		certPem := NewCertPem(pem)

		certificates[index] = certPem
	}

	return certificates
}

func collectDomains(expiringCerts []*x509.Certificate) [][]string {
	domains := make([][]string, 0, len(expiringCerts))

	for _, cert := range expiringCerts {
		domains = append(domains, cert.DNSNames)
	}

	return domains
}

func printDomains(domains [][]string) {
	for _, domain := range domains {
		fmt.Println(strings.Join(domain, " "))
	}
}

func init() {
	flag.StringVar(&pemName, "pem-name", "fullchain.pem", "The name of the pem file, usually fullchain.pem")
	flag.StringVar(&certsRoot, "certs-path", "/etc/letsencrypt/live", "The path to the directory which stores the certificates")
	flag.StringVar(&expireTime, "expire", "", "Expire time of the certificates in unix date format (run date command \"$(date --date='03/15/2016')\"), eg.: Tue Mar 15 11:28:00 CET 2016")

	flag.Parse()
}

func main() {

	expire := getExpireTime(expireTime)

	dirs := getCertDirectoryNames(certsRoot)

	certificates := getCertificates(dirs)

	expiringCerts := filterExpiringCerts(certificates, expire)

	domains := collectDomains(expiringCerts)

	printDomains(domains)
}
<|endoftext|>


<commit_before>// http://askubuntu.com/a/50000 was a great help to cover edge cases
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os/exec"
	"os"
	"strconv"
	"strings"
)

// If an error exists, print message and panic
func checkError(msg string, err error) {
	if err != nil {
		fmt.Println(msg)
		panic(err)
	}
}

func main() {
	// Shell
	sh := "/bin/sh"
	// Comamnd flag
	c := "-c"

	whoamiFlag := flag.String("whoami", "faraz", "Current Username") // user.Current doesn't work when cross-compiling macOS -> Linux
	userFlag := flag.String("user", "", "Username")
	keyFlag := flag.String("key", "", "Public Key")
	tldFlag := flag.String("tld", "ml", "TLD (ml/cf)")
	tunnelOfflineMessageFlag := flag.String("tunneloffline", "Tunnel offline", "Tunnel offline message to show on a 502 error.")

	flag.Parse()

	whoami := *whoamiFlag
	user := *userFlag
	key := *keyFlag
	tld := *tldFlag
	tunnelOfflineMessage := *tunnelOfflineMessageFlag

	// Validate user & key flags
	if (len(user) < 2 || len(key) < 10) {
		fmt.Println("Please pass in all required arguments")
		return
	}

	ip := getIP()
	port := getFreePort()

	users, err := exec.Command(sh, c, "sudo cat /etc/passwd").Output()
	checkError("Error getting users", err)

	// Check if user exists
	if strings.Contains(user, "root") || strings.Contains(string(users), user) {
		fmt.Println("User already exists")
		return
	}

	// Add user
	addusrcmd := fmt.Sprintf(`sudo /usr/sbin/adduser --disabled-password --gecos "" %s`, user)
	_, err = exec.Command(sh, c, addusrcmd).Output()
	checkError("Error creating user", err)
	fmt.Printf("Added user: %s\n", user)

	// Modify .ssh externally
	modsshcmd := fmt.Sprintf(`cd /home/%s && sudo mkdir .ssh && sudo chown -R %s:%s .ssh && cd .ssh && touch authorized_keys && sudo chown %s:%s authorized_keys`, user, user, user, whoami, whoami)
	_, err = exec.Command(modsshcmd).Output()
	checkError("Error modifying .ssh", err)
	fmt.Println("Created .ssh skeleton")

	// Add SSH key & prevent user from running other commands
	reversecommand := fmt.Sprintf(`ssh %s@%s -N -R PORT:localhost:%s`, user, ip, port)

	restrictcmd := fmt.Sprintf(`cd /home/%s/.ssh && sudo echo "command=\"SHELL=/bin/false && printf 'You cannot login. To tunnel, use the following:\n%s and replace PORT with your local port.\n'\",no-agent-forwarding,no-X11-forwarding,permitopen=\"localhost:%s\" %s" > authorized_keys && sudo chown %s:%s authorized_keys`, user, reversecommand, port, key, user, user)
	_, err = exec.Command(sh, c, restrictcmd).Output()
	checkError("Error restricting .ssh to tunnel only", err)
	fmt.Printf("Restricted %s tunneling ability for port %s only\n\n", user, port)

	subdomain := user + ".shownow." + tld

	// Add NGINX configuration for reverse proxying subdomain
	nginxConfig, err := os.Create("/etc/nginx/sites-enabled/"+user+".conf")
	checkError("Error creating NGINX configuration", err)
		nginxConf := fmt.Sprintf("server { listen 80; server_name %s.shownow.ml www.%s.shownow.ml; location / { proxy_pass http://localhost:%s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } error_page 502 /502.html; location = /502.html { return 502 '%s'; add_header Content-Type text/plain; } }", user, user, port, tunnelOfflineMessage)
	nginxConfig.WriteString(nginxConf)
	nginxConfig.Sync()

	err = exec.Command(sh, c, "sudo systemctl reload nginx").Start()
	checkError("Error restarting NGINX", err)

	// Configured port alias - modify PORT & add to shell rc, then simply run: shownow
	fmt.Printf("alias shownow=\"%s && open %s\"\n", reversecommand, subdomain)

	// Function which takes a port number and sets up the tunnel - add to shell rc, and run like so: shownow 1000
	fmt.Printf(`shownow() { ssh %s@%s -N -R $1\:localhost:%s; }`, user, ip, port)
}

// https://api.ipify.org - better than myexternalip
func getIP() string {
	resp, err := http.Get("https://api.ipify.org")
	checkError("Error getting IP", err)
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	return string(body)
}

// https://github.com/phayes/freeport/blob/master/freeport.go
func getFreePort() string {
	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	checkError("resolve", err)

	l, err := net.ListenTCP("tcp", addr)
	checkError("listen", err)

	defer l.Close()
	free := strconv.Itoa(l.Addr().(*net.TCPAddr).Port)
	fmt.Println("Port: " + free)
	if len(free) < 4 {
		panic("Error getting port")
	}
	return free
}
<commit_msg>Fix typo<commit_after>// http://askubuntu.com/a/50000 was a great help to cover edge cases
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os/exec"
	"os"
	"strconv"
	"strings"
)

// If an error exists, print message and panic
func checkError(msg string, err error) {
	if err != nil {
		fmt.Println(msg)
		panic(err)
	}
}

func main() {
	// Shell
	sh := "/bin/sh"
	// Comamnd flag
	c := "-c"

	whoamiFlag := flag.String("whoami", "faraz", "Current Username") // user.Current doesn't work when cross-compiling macOS -> Linux
	userFlag := flag.String("user", "", "Username")
	keyFlag := flag.String("key", "", "Public Key")
	tldFlag := flag.String("tld", "ml", "TLD (ml/cf)")
	tunnelOfflineMessageFlag := flag.String("tunneloffline", "Tunnel offline", "Tunnel offline message to show on a 502 error.")

	flag.Parse()

	whoami := *whoamiFlag
	user := *userFlag
	key := *keyFlag
	tld := *tldFlag
	tunnelOfflineMessage := *tunnelOfflineMessageFlag

	// Validate user & key flags
	if (len(user) < 2 || len(key) < 10) {
		fmt.Println("Please pass in all required arguments")
		return
	}

	ip := getIP()
	port := getFreePort()

	users, err := exec.Command(sh, c, "sudo cat /etc/passwd").Output()
	checkError("Error getting users", err)

	// Check if user exists
	if strings.Contains(user, "root") || strings.Contains(string(users), user) {
		fmt.Println("User already exists")
		return
	}

	// Add user
	addusrcmd := fmt.Sprintf(`sudo /usr/sbin/adduser --disabled-password --gecos "" %s`, user)
	_, err = exec.Command(sh, c, addusrcmd).Output()
	checkError("Error creating user", err)
	fmt.Printf("Added user: %s\n", user)

	// Modify .ssh externally
	modsshcmd := fmt.Sprintf(`cd /home/%s && mkdir .ssh && sudo chown -R %s:%s .ssh && cd .ssh && touch authorized_keys && sudo chown %s:%s authorized_keys`, user, user, user, whoami, whoami)
	_, err = exec.Command(sh, c, modsshcmd).Output()
	checkError("Error modifying .ssh", err)
	fmt.Println("Created .ssh skeleton")

	// Add SSH key & prevent user from running other commands
	reversecommand := fmt.Sprintf(`ssh %s@%s -N -R PORT:localhost:%s`, user, ip, port)

	restrictcmd := fmt.Sprintf(`cd /home/%s/.ssh && sudo echo "command=\"SHELL=/bin/false && printf 'You cannot login. To tunnel, use the following:\n%s and replace PORT with your local port.\n'\",no-agent-forwarding,no-X11-forwarding,permitopen=\"localhost:%s\" %s" > authorized_keys && sudo chown %s:%s authorized_keys`, user, reversecommand, port, key, user, user)
	_, err = exec.Command(sh, c, restrictcmd).Output()
	checkError("Error restricting .ssh to tunnel only", err)
	fmt.Printf("Restricted %s tunneling ability for port %s only\n\n", user, port)

	subdomain := user + ".shownow." + tld

	// Add NGINX configuration for reverse proxying subdomain
	nginxConfig, err := os.Create("/etc/nginx/sites-enabled/"+user+".conf")
	checkError("Error creating NGINX configuration", err)
		nginxConf := fmt.Sprintf("server { listen 80; server_name %s.shownow.ml www.%s.shownow.ml; location / { proxy_pass http://localhost:%s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } error_page 502 /502.html; location = /502.html { return 502 '%s'; add_header Content-Type text/plain; } }", user, user, port, tunnelOfflineMessage)
	nginxConfig.WriteString(nginxConf)
	nginxConfig.Sync()

	err = exec.Command(sh, c, "sudo systemctl reload nginx").Start()
	checkError("Error restarting NGINX", err)

	// Configured port alias - modify PORT & add to shell rc, then simply run: shownow
	fmt.Printf("alias shownow=\"%s && open %s\"\n", reversecommand, subdomain)

	// Function which takes a port number and sets up the tunnel - add to shell rc, and run like so: shownow 1000
	fmt.Printf(`shownow() { ssh %s@%s -N -R $1\:localhost:%s; }`, user, ip, port)
}

// https://api.ipify.org - better than myexternalip
func getIP() string {
	resp, err := http.Get("https://api.ipify.org")
	checkError("Error getting IP", err)
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	return string(body)
}

// https://github.com/phayes/freeport/blob/master/freeport.go
func getFreePort() string {
	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	checkError("resolve", err)

	l, err := net.ListenTCP("tcp", addr)
	checkError("listen", err)

	defer l.Close()
	free := strconv.Itoa(l.Addr().(*net.TCPAddr).Port)
	fmt.Println("Port: " + free)
	if len(free) < 4 {
		panic("Error getting port")
	}
	return free
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	viper.SetConfigName("config")

	viper.AddConfigPath("$HOME/.gotator")
	viper.AddConfigPath(".")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("firefox_ip")
	viper.BindEnv("firefox_port")
	viper.BindEnv("gotator_port")

	if !viper.IsSet("firefox_ip") || !viper.IsSet("firefox_port") {
		fmt.Fprintln(os.Stderr, "Configuration error.  Both FIREFOX_IP and FIREFOX_PORT must be set via either config or environment.")
		os.Exit(1)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("\nConfig file changed:", e.Name)
		skip <- struct{}{}
		fmt.Printf("Content will change immediately.\n\n")
	})

}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	fmt.Printf("Loading programs from %s\n", filename)

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))
	r.LazyQuotes = true

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Printf("Error reading line from program file: %s.  Abandoning attempt to read programs.\n", filename)
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		if err != nil {
			fmt.Println("Program rejected.  Invalid duration.")
		}

		fmt.Printf("  Loaded program %.50s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	ip := viper.Get("FIREFOX_IP")
	port := viper.GetInt("FIREFOX_PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("It is possible Firefox needs to be started or restarted.")
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	log.Printf("Running program for %s:  %s\n", program.Duration, program.URL)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("  %s", status)

	select {
	case <-time.After(program.Duration):
		// Do nothing.
		Unpause()
	case <-skip:
		fmt.Println("Current program skipped")
		return
	}
}

func Pause() {
	mu.Lock()
	pause = true
	mu.Unlock()
}

func Unpause() {
	mu.Lock()
	pause = false
	mu.Unlock()
}

func IsPaused() bool {
	mu.Lock()
	defer mu.Unlock()

	return pause == true
}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")
		for IsPaused() {
			fmt.Println("Paused.")
			time.Sleep(1 * time.Second)
		}

		pl := loadProgramList(filename)

		for _, p := range pl {
			for IsPaused() {
				fmt.Println("Program list is paused.")
				time.Sleep(1 * time.Second)
			}
			runProgram(p)
		}

		fmt.Printf("\nLooping back to play program list from beginning\n\n")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	fmt.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	fmt.Printf("Duration: %s\n", d)

	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		w.Write([]byte("Program rejected.  Invalid duration.\n"))
		return
	}

	// Needs validation...

	// Now do something with the program.. play it?

	// Stop normal rotation
	Pause()
	skip <- struct{}{}

	go runProgram(p)
	w.Write([]byte("Program accepted\n"))

}

func PauseHandler(w http.ResponseWriter, r *http.Request) {
	Pause()
	log.Println("Pausing from web request")
	w.Write([]byte("Ok, paused.\n"))
}

func ResumeHandler(w http.ResponseWriter, r *http.Request) {
	Unpause()
	log.Println("Unpausing from web request")
	w.Write([]byte("Ok, unpaused.\n"))
}
func SkipHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Skippingfrom web request")
	Unpause()
	skip <- struct{}{}

	w.Write([]byte("Skipping current programming and resume program list runner from web request.\n"))
}

func readKeyboardLoop() {
	for {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		fmt.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		Unpause()
		skip <- struct{}{}
	}
}

// Control channel to stop running programs immediately (yes, global)

var skip = make(chan struct{})
var exitprogram = make(chan struct{})
var pause bool
var mu = &sync.Mutex{}
var version = "0.0.4"

func main() {

	if len(os.Args) > 1 {
		if os.Args[1] == "version" {
			fmt.Println("Gotator version:", version)
			os.Exit(0)
		}
	}
	fmt.Println("Starting gotator: version", version)
	Unpause()

	InitializeConfig()

	go LoadAndRunLoop()
	go readKeyboardLoop()

	if viper.IsSet("apienabled") && viper.Get("apienabled") == true {
		listen_port := ":8080"
		if viper.IsSet("gotator_port") {
			listen_port = ":" + viper.GetString("gotator_port")
		}

		fmt.Printf("Starting API server on port %s.  Notice:  This allows UNAUTHENTICATED remote control of Firefox. set 'apienabled: false' in config.yaml to disable.\n",
			listen_port)

		r := mux.NewRouter()
		r.HandleFunc("/play", PlayHandler)
		r.HandleFunc("/pause", PauseHandler)
		r.HandleFunc("/resume", ResumeHandler)
		r.HandleFunc("/skip", SkipHandler)

		go log.Fatal(http.ListenAndServe(listen_port, r))
	} else {
		fmt.Println("notice: rest API not enabled in configuration and will be unavailable.  set 'apienabled: true' in config.yaml if you want to use it.\n")
		// If we aren't doing http.ListenAndServe() we need to block here or else gotator would exit immediately
		<-exitprogram
	}

}
<commit_msg>Added simple status for result of URL load.<commit_after>package main

import (
	"bufio"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	viper.SetConfigName("config")

	viper.AddConfigPath("$HOME/.gotator")
	viper.AddConfigPath(".")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("firefox_ip")
	viper.BindEnv("firefox_port")
	viper.BindEnv("gotator_port")

	if !viper.IsSet("firefox_ip") || !viper.IsSet("firefox_port") {
		fmt.Fprintln(os.Stderr, "Configuration error.  Both FIREFOX_IP and FIREFOX_PORT must be set via either config or environment.")
		os.Exit(1)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("\nConfig file changed:", e.Name)
		skip <- struct{}{}
		fmt.Printf("Content will change immediately.\n\n")
	})

}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	fmt.Printf("Loading programs from %s\n", filename)

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))
	r.LazyQuotes = true

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Printf("Error reading line from program file: %s.  Abandoning attempt to read programs.\n", filename)
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		if err != nil {
			fmt.Println("Program rejected.  Invalid duration.")
		}

		fmt.Printf("  Loaded program %.50s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	ip := viper.Get("FIREFOX_IP")
	port := viper.GetInt("FIREFOX_PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("It is possible Firefox needs to be started or restarted.")
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	fmt.Printf("Running program for %s:  %s -> RESULT: ", program.Duration, program.URL)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	if err != nil {
		fmt.Println("ERROR - URL didn't load as desired.")
	}

	var statusParsed interface{}
	err = json.Unmarshal([]byte(status), &statusParsed)

	m := statusParsed.(map[string]interface{})

	if m["result"] == program.URL {
		fmt.Println("OK")
	} else {
		fmt.Println("ERROR - URL didn't load as desired.")
	}

	// fmt.Printf("  %s", status)

	select {
	case <-time.After(program.Duration):
		// Do nothing.
		Unpause()
	case <-skip:
		fmt.Println("Current program skipped")
		return
	}
}

func Pause() {
	mu.Lock()
	pause = true
	mu.Unlock()
}

func Unpause() {
	mu.Lock()
	pause = false
	mu.Unlock()
}

func IsPaused() bool {
	mu.Lock()
	defer mu.Unlock()

	return pause == true
}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")
		for IsPaused() {
			fmt.Println("Paused.")
			time.Sleep(1 * time.Second)
		}

		pl := loadProgramList(filename)

		for _, p := range pl {
			for IsPaused() {
				fmt.Println("Program list is paused.")
				time.Sleep(1 * time.Second)
			}
			runProgram(p)
		}

		fmt.Printf("\nLooping back to play program list from beginning\n\n")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	fmt.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	fmt.Printf("Duration: %s\n", d)

	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		w.Write([]byte("Program rejected.  Invalid duration.\n"))
		return
	}

	// Needs validation...

	// Now do something with the program.. play it?

	// Stop normal rotation
	Pause()
	skip <- struct{}{}

	go runProgram(p)
	w.Write([]byte("Program accepted\n"))

}

func PauseHandler(w http.ResponseWriter, r *http.Request) {
	Pause()
	log.Println("Pausing from web request")
	w.Write([]byte("Ok, paused.\n"))
}

func ResumeHandler(w http.ResponseWriter, r *http.Request) {
	Unpause()
	log.Println("Unpausing from web request")
	w.Write([]byte("Ok, unpaused.\n"))
}
func SkipHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Skippingfrom web request")
	Unpause()
	skip <- struct{}{}

	w.Write([]byte("Skipping current programming and resume program list runner from web request.\n"))
}

func readKeyboardLoop() {
	for {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		fmt.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		Unpause()
		skip <- struct{}{}
	}
}

// Control channel to stop running programs immediately (yes, global)

var skip = make(chan struct{})
var exitprogram = make(chan struct{})
var pause bool
var mu = &sync.Mutex{}
var version = "0.0.4"

func main() {

	if len(os.Args) > 1 {
		if os.Args[1] == "version" {
			fmt.Println("Gotator version:", version)
			os.Exit(0)
		}
	}
	fmt.Println("Starting gotator: version", version)
	Unpause()

	InitializeConfig()

	go LoadAndRunLoop()
	go readKeyboardLoop()

	if viper.IsSet("apienabled") && viper.Get("apienabled") == true {
		listen_port := ":8080"
		if viper.IsSet("gotator_port") {
			listen_port = ":" + viper.GetString("gotator_port")
		}

		fmt.Printf("Starting API server on port %s.  Notice:  This allows UNAUTHENTICATED remote control of Firefox. set 'apienabled: false' in config.yaml to disable.\n",
			listen_port)

		r := mux.NewRouter()
		r.HandleFunc("/play", PlayHandler)
		r.HandleFunc("/pause", PauseHandler)
		r.HandleFunc("/resume", ResumeHandler)
		r.HandleFunc("/skip", SkipHandler)

		go log.Fatal(http.ListenAndServe(listen_port, r))
	} else {
		fmt.Println("notice: rest API not enabled in configuration and will be unavailable.  set 'apienabled: true' in config.yaml if you want to use it.\n")
		// If we aren't doing http.ListenAndServe() we need to block here or else gotator would exit immediately
		<-exitprogram
	}

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/omakoto/mlib"
	"github.com/omakoto/tabular/tabular"
)

var (
	useCsv             = flag.Bool("c", false, "input is CSV")
	useTsv             = flag.Bool("t", false, "input is TSV")
	useSpaceSeparated  = flag.Bool("s", true, "input is space-separated")
	useCustomSeparator = flag.String("p", "", "use regex as a separator")
)

func main() {
	flag.Parse()

	in := mlib.GetFilesReaderFromArgs()

	var reader <-chan []string
	switch {
	case *useCsv:
		reader = tabular.CsvReader(in)
	case *useTsv:
		reader = tabular.TsvReader(in)
	case *useCustomSeparator != "":
		reader = tabular.RegexpSeparatedReader(in, *useCustomSeparator)
	case *useSpaceSeparated: // Default, check it last.
		reader = tabular.RegexpSeparatedReader(in, `\s+`)
	}

	for l := range tabular.Tabular(reader) {
		fmt.Print(l)
		fmt.Print("\n")
	}
}
<commit_msg>Use bashcomp<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/omakoto/bashcomp"
	"github.com/omakoto/mlib"
	"github.com/omakoto/tabular/tabular"
)

var (
	useCsv             = flag.Bool("c", false, "input is CSV")
	useTsv             = flag.Bool("t", false, "input is TSV")
	useSpaceSeparated  = flag.Bool("s", true, "input is space-separated")
	useCustomSeparator = flag.String("p", "", "use regex as a separator")
)

func main() {
	flag.Parse()
	bashcomp.HandleBashCompletion()

	in := mlib.GetFilesReaderFromArgs()

	var reader <-chan []string
	switch {
	case *useCsv:
		reader = tabular.CsvReader(in)
	case *useTsv:
		reader = tabular.TsvReader(in)
	case *useCustomSeparator != "":
		reader = tabular.RegexpSeparatedReader(in, *useCustomSeparator)
	case *useSpaceSeparated: // Default, check it last.
		reader = tabular.RegexpSeparatedReader(in, `\s+`)
	}

	for l := range tabular.Tabular(reader) {
		fmt.Print(l)
		fmt.Print("\n")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"

	"github.com/gorilla/sessions"
	"github.com/joeshaw/envdecode"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

type configuration struct {
	ClientID              string   `env:"CLIENT_ID,required"`                                       // Google Client ID
	ClientSecret          string   `env:"CLIENT_SECRET,required"`                                   // Google Client Secret
	SessionSecret         string   `env:"SESSION_SECRET,required"`                                  // Random session auth key
	SessionEncrypttionKey string   `env:"SESSION_ENCRYPTION_KEY,required"`                          // Random session encryption key
	DNSName               string   `env:"DNS_NAME,required"`                                        // Public facing DNS Hostname
	CookieMaxAge          int      `env:"COOKIE_MAX_AGE,default=1440"`                              // Cookie MaxAge, Defaults to 1 day
	CookieName            string   `env:"COOKIE_NAME,default=sproxy_session"`                       // The name of the cookie
	ProxyURL              *url.URL `env:"PROXY_URL,default=http://localhost:8000/"`                 // URL to Proxy to
	CallbackPath          string   `env:"CALLBACK_PATH,default=/auth/callback/google"`              // Callback URL
	HealthCheckPath       string   `env:"HEALTH_CHECK_PATH,default=/en-US/static/html/credit.html"` // Health Check path in splunk, this path is proxied w/o auth. The default is a static file served by the splunk web server
	EmailSuffix           string   `env:"EMAIL_SUFFIX,default=@heroku.com"`                         // Required email suffix. Emails w/o this suffix will not be let in
	StateToken            string   `env:"STATE_TOKEN,required"`                                     // Token used when communicating with Google Oauth2 provider
	ServerHost            string   `env:"HOST"`                                                     // Host
	ServerPort            uint16   `env:"PORT,default=5000"`                                        // Port
}

var config configuration

func newOauth2Config() *oauth2.Config {
	return &oauth2.Config{
		ClientID:     config.ClientID,
		ClientSecret: config.ClientSecret,
		Scopes:       oauthScopes,
		Endpoint:     google.Endpoint,
	}
}

// Authorize the user based on the email stored in the named session and matching the suffix. If the email doesn't exist
// in the session or if the 'OpenIDUser' isn't set in the session, then redirect, otherwise set the X-Openid-User
// header to what was stored in the session.
func authorize(s sessions.Store, h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logPrefix := fmt.Sprintf("app=sproxy fn=authorize method=%s path=%s\n",
			r.Method, r.URL.Path)

		session, err := s.Get(r, config.CookieName)
		if err != nil {
			log.Printf("%s auth=failed error=%q\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		redirect := o2c.AuthCodeURL(config.StateToken, oauth2.AccessTypeOnline)

		session.Values["return_to"] = r.URL.RequestURI()
		session.Save(r, w)

		email, ok := session.Values["email"]
		if !ok || email == nil || !strings.HasSuffix(email.(string), config.EmailSuffix) {
			if email == nil {
				email = ""
			}
			log.Printf("%s auth=failed missing=Email email=%s redirect=%s\n", logPrefix, email.(string), redirect)
			http.Redirect(w, r, redirect, http.StatusTemporaryRedirect)
			return
		}

		openIDUser, ok := session.Values["OpenIDUser"]
		if !ok || openIDUser == nil {
			if openIDUser == nil {
				openIDUser = ""
			}
			log.Printf("%s auth=failed missing=OpenIDUser user=%s redirect=%s\n", logPrefix, openIDUser.(string), redirect)
			http.Redirect(w, r, redirect, http.StatusFound)
			return
		}

		r.Header.Set("X-Openid-User", openIDUser.(string))
		h.ServeHTTP(w, r)
	})
}

// enforceXForwardedProto header is set before processing the handler.
// If it's not then redirect to the https version of the URL.
func enforceXForwardedProto(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		xff := r.Header.Get("X-Forwarded-Proto")
		if xff == "https" {
			h.ServeHTTP(w, r)
			return
		}

		u := new(url.URL)
		*u = *r.URL
		u.Scheme = "https"
		if u.Host == "" {
			u.Host = r.Host
		}

		http.Redirect(w, r, u.String(), http.StatusFound)
	})
}

// Set the OpenIDUser and other session values based on the data from Google
func handleGoogleCallback(s sessions.Store) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logPrefix := fmt.Sprintf("app=sproxy fn=callback method=%s path=%s\n",
			r.Method, r.URL.Path)

		o2c := newOauth2Config()

		if v := r.FormValue("state"); v != config.StateToken {
			log.Printf("%s callback=failed error=%s\n", logPrefix, fmt.Sprintf("Bad state token: %s", v))
			http.Error(w, "Bad Request", http.StatusBadRequest)
			return
		}

		ctx := context.Background()
		t, err := o2c.Exchange(r.Context(), r.FormValue("code"))
		if err != nil {
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		gp, err := fetchGoogleProfile(ctx, t, o2c)
		if err != nil {
			log.Printf("%s %s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if gp.Email == "" || !strings.HasSuffix(gp.Email, config.EmailSuffix) {
			err := fmt.Errorf("Invalid Google Profile Email: %q", gp.Email)
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusForbidden)
			return
		}

		session, err := s.Get(r, config.CookieName)
		if err != nil {
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		session.Values["email"] = gp.Email
		session.Values["GoogleID"] = gp.ID

		parts := strings.SplitN(gp.Email, "@", 2)
		if len(parts) < 2 {
			err := fmt.Errorf("Unable to determine OpenIDUser from email %q", gp.Email)
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		session.Values["OpenIDUser"] = strings.ToLower(parts[0])
		target, ok := session.Values["return_to"].(string)
		if !ok {
			target = "/"
		}

		if err := session.Save(r, w); err != nil {
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		log.Printf("%s callback=successful\n", logPrefix)
		http.Redirect(w, r, target, http.StatusFound)
	})
}

func handleAuthLogout(s sessions.Store) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logPrefix := fmt.Sprintf("app=sproxy fn=logout method=%s path=%s\n",
			r.Method, r.URL.Path)

		session, err := s.Get(r, config.CookieName)
		if err != nil || session == nil {
			log.Printf("%s logout=failed error=%s\n", logPrefix, err.Error())
			return
		}

		// clear out session values
		session.Values = map[interface{}]interface{}{}
		session.Save(r, w)

		log.Printf("%s logout=successful\n", logPrefix)
		http.Redirect(w, r, "/", http.StatusFound)
	})
}

func main() {
	if err := envdecode.Decode(&config); err != nil {
		log.Fatal(err)
	}

	switch len(config.SessionEncrypttionKey) {
	case 16, 24, 32:
	default:
		log.Fatal("Length of SESSION_ENCRYPTION_KEY is not 16, 24 or 32")
	}

	store := sessions.NewCookieStore([]byte(config.SessionSecret), []byte(config.SessionEncrypttionKey))
	store.Options.MaxAge = config.CookieMaxAge
	store.Options.Secure = true

	proxy := httputil.NewSingleHostReverseProxy(config.ProxyURL)

	// Handle Google Callback
	http.Handle(config.CallbackPath, handleGoogleCallback(store))

	// Health Check
	http.Handle(config.HealthCheckPath, proxy)

	// Base HTTP Request handler
	http.Handle("/", enforceXForwardedProto(authorize(store, proxy)))

	http.Handle("/auth/logout", handleAuthLogout(store))
	http.Handle("/logout", handleAuthLogout(store))

	listen := host + ":" + port
	log.Println("Listening on", listen)

	log.Fatal(http.ListenAndServe(listen, nil))
}
<commit_msg>removing unused imports<commit_after>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"github.com/gorilla/sessions"
	"github.com/joeshaw/envdecode"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

type configuration struct {
	ClientID              string   `env:"CLIENT_ID,required"`                                       // Google Client ID
	ClientSecret          string   `env:"CLIENT_SECRET,required"`                                   // Google Client Secret
	SessionSecret         string   `env:"SESSION_SECRET,required"`                                  // Random session auth key
	SessionEncrypttionKey string   `env:"SESSION_ENCRYPTION_KEY,required"`                          // Random session encryption key
	DNSName               string   `env:"DNS_NAME,required"`                                        // Public facing DNS Hostname
	CookieMaxAge          int      `env:"COOKIE_MAX_AGE,default=1440"`                              // Cookie MaxAge, Defaults to 1 day
	CookieName            string   `env:"COOKIE_NAME,default=sproxy_session"`                       // The name of the cookie
	ProxyURL              *url.URL `env:"PROXY_URL,default=http://localhost:8000/"`                 // URL to Proxy to
	CallbackPath          string   `env:"CALLBACK_PATH,default=/auth/callback/google"`              // Callback URL
	HealthCheckPath       string   `env:"HEALTH_CHECK_PATH,default=/en-US/static/html/credit.html"` // Health Check path in splunk, this path is proxied w/o auth. The default is a static file served by the splunk web server
	EmailSuffix           string   `env:"EMAIL_SUFFIX,default=@heroku.com"`                         // Required email suffix. Emails w/o this suffix will not be let in
	StateToken            string   `env:"STATE_TOKEN,required"`                                     // Token used when communicating with Google Oauth2 provider
}

var config configuration

func newOauth2Config() *oauth2.Config {
	return &oauth2.Config{
		ClientID:     config.ClientID,
		ClientSecret: config.ClientSecret,
		Scopes:       []string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile"},
		Endpoint:     google.Endpoint,
	}
}

// Authorize the user based on the email stored in the named session and matching the suffix. If the email doesn't exist
// in the session or if the 'OpenIDUser' isn't set in the session, then redirect, otherwise set the X-Openid-User
// header to what was stored in the session.
func authorize(s sessions.Store, h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logPrefix := fmt.Sprintf("app=sproxy fn=authorize method=%s path=%s\n",
			r.Method, r.URL.Path)

		session, err := s.Get(r, config.CookieName)
		if err != nil {
			log.Printf("%s auth=failed error=%q\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		redirect := o2c.AuthCodeURL(config.StateToken, oauth2.AccessTypeOnline)

		session.Values["return_to"] = r.URL.RequestURI()
		session.Save(r, w)

		email, ok := session.Values["email"]
		if !ok || email == nil || !strings.HasSuffix(email.(string), config.EmailSuffix) {
			if email == nil {
				email = ""
			}
			log.Printf("%s auth=failed missing=Email email=%s redirect=%s\n", logPrefix, email.(string), redirect)
			http.Redirect(w, r, redirect, http.StatusTemporaryRedirect)
			return
		}

		openIDUser, ok := session.Values["OpenIDUser"]
		if !ok || openIDUser == nil {
			if openIDUser == nil {
				openIDUser = ""
			}
			log.Printf("%s auth=failed missing=OpenIDUser user=%s redirect=%s\n", logPrefix, openIDUser.(string), redirect)
			http.Redirect(w, r, redirect, http.StatusFound)
			return
		}

		r.Header.Set("X-Openid-User", openIDUser.(string))
		h.ServeHTTP(w, r)
	})
}

// enforceXForwardedProto header is set before processing the handler.
// If it's not then redirect to the https version of the URL.
func enforceXForwardedProto(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		xff := r.Header.Get("X-Forwarded-Proto")
		if xff == "https" {
			h.ServeHTTP(w, r)
			return
		}

		u := new(url.URL)
		*u = *r.URL
		u.Scheme = "https"
		if u.Host == "" {
			u.Host = r.Host
		}

		http.Redirect(w, r, u.String(), http.StatusFound)
	})
}

// Set the OpenIDUser and other session values based on the data from Google
func handleGoogleCallback(s sessions.Store) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logPrefix := fmt.Sprintf("app=sproxy fn=callback method=%s path=%s\n",
			r.Method, r.URL.Path)

		o2c := newOauth2Config()

		if v := r.FormValue("state"); v != config.StateToken {
			log.Printf("%s callback=failed error=%s\n", logPrefix, fmt.Sprintf("Bad state token: %s", v))
			http.Error(w, "Bad Request", http.StatusBadRequest)
			return
		}

		ctx := context.Background()
		t, err := o2c.Exchange(r.Context(), r.FormValue("code"))
		if err != nil {
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		gp, err := fetchGoogleProfile(ctx, t, o2c)
		if err != nil {
			log.Printf("%s %s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if gp.Email == "" || !strings.HasSuffix(gp.Email, config.EmailSuffix) {
			err := fmt.Errorf("Invalid Google Profile Email: %q", gp.Email)
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusForbidden)
			return
		}

		session, err := s.Get(r, config.CookieName)
		if err != nil {
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		session.Values["email"] = gp.Email
		session.Values["GoogleID"] = gp.ID

		parts := strings.SplitN(gp.Email, "@", 2)
		if len(parts) < 2 {
			err := fmt.Errorf("Unable to determine OpenIDUser from email %q", gp.Email)
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		session.Values["OpenIDUser"] = strings.ToLower(parts[0])
		target, ok := session.Values["return_to"].(string)
		if !ok {
			target = "/"
		}

		if err := session.Save(r, w); err != nil {
			log.Printf("%s callback=failed error=%s\n", logPrefix, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		log.Printf("%s callback=successful\n", logPrefix)
		http.Redirect(w, r, target, http.StatusFound)
	})
}

func handleAuthLogout(s sessions.Store) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logPrefix := fmt.Sprintf("app=sproxy fn=logout method=%s path=%s\n",
			r.Method, r.URL.Path)

		session, err := s.Get(r, config.CookieName)
		if err != nil || session == nil {
			log.Printf("%s logout=failed error=%s\n", logPrefix, err.Error())
			return
		}

		// clear out session values
		session.Values = map[interface{}]interface{}{}
		session.Save(r, w)

		log.Printf("%s logout=successful\n", logPrefix)
		http.Redirect(w, r, "/", http.StatusFound)
	})
}

func main() {
	if err := envdecode.Decode(&config); err != nil {
		log.Fatal(err)
	}

	switch len(config.SessionEncrypttionKey) {
	case 16, 24, 32:
	default:
		log.Fatal("Length of SESSION_ENCRYPTION_KEY is not 16, 24 or 32")
	}

	store := sessions.NewCookieStore([]byte(config.SessionSecret), []byte(config.SessionEncrypttionKey))
	store.Options.MaxAge = config.CookieMaxAge
	store.Options.Secure = true

	proxy := httputil.NewSingleHostReverseProxy(config.ProxyURL)

	// Handle Google Callback
	http.Handle(config.CallbackPath, handleGoogleCallback(store))

	// Health Check
	http.Handle(config.HealthCheckPath, proxy)

	// Base HTTP Request handler
	http.Handle("/", enforceXForwardedProto(authorize(store, proxy)))

	http.Handle("/auth/logout", handleAuthLogout(store))
	http.Handle("/logout", handleAuthLogout(store))

  host := os.Getenv("HOST")

	port := os.Getenv("PORT")
	if port == "" {
		port = "5000"
	}

	listen := host + ":" + port
	log.Println("Listening on", listen)

	log.Fatal(http.ListenAndServe(listen, nil))
}
<|endoftext|>


<commit_before>// Copyright 2016 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/tsuru/tsuru-autoscale/alarm"
	"github.com/tsuru/tsuru-autoscale/api"
	"github.com/tsuru/tsuru-autoscale/web"
)

func port() string {
	var p string
	if p = os.Getenv("PORT"); p != "" {
		return p
	}
	return "8080"
}

func router() http.Handler {
	m := mux.NewRouter()
	apiRouter := m.PathPrefix("/").Subrouter()
	api.Router(apiRouter)
	webRouter := m.PathPrefix("/web").Subrouter()
	web.Router(webRouter)
	n := negroni.New()
	n.Use(negroni.NewRecovery())
	n.Use(negroni.NewLogger())
	n.UseHandler(m)
	return n
}

func runServer() {
	http.Handle("/", router())
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port()), nil))
}

func main() {
	if os.Args[1] == "agent" {
		alarm.StartAutoScale()
	} else {
		runServer()
	}
}
<commit_msg>serving statics<commit_after>// Copyright 2016 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/tsuru/tsuru-autoscale/alarm"
	"github.com/tsuru/tsuru-autoscale/api"
	"github.com/tsuru/tsuru-autoscale/web"
)

func port() string {
	var p string
	if p = os.Getenv("PORT"); p != "" {
		return p
	}
	return "8080"
}

func router() http.Handler {
	m := mux.NewRouter()
	apiRouter := m.PathPrefix("/").Subrouter()
	api.Router(apiRouter)
	webRouter := m.PathPrefix("/web").Subrouter()
	web.Router(webRouter)
	n := negroni.New()
	n.Use(negroni.NewRecovery())
	n.Use(negroni.NewLogger())
	n.UseHandler(m)
	return n
}

func runServer() {
	http.Handle("/", router())
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port()), nil))
}

func main() {
	if os.Args[1] == "agent" {
		alarm.StartAutoScale()
	} else {
		runServer()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/carbocation/forum.git/forum"
	"github.com/carbocation/util.git/datatypes/binarytree"
	"github.com/carbocation/util.git/datatypes/closuretable"
	//"math/rand"
	"net/http"
	"time"
	//"html/template"
	"encoding/json"
)

func main() {
	http.HandleFunc("/hello/", helloHandler)
	http.HandleFunc("/", defaultHandler)
	http.ListenAndServe("localhost:9999", nil)
}

func defaultHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/"):]
	fmt.Fprintf(w, "
Welcome, %s
Say hello", remPartOfURL)

	fmt.Fprint(w, "")
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/hello/"):] //get everything after the /hello/ part of the URL
	//w.Header().Set("Content-Type", "text/html")

	fmt.Fprint(w, "")
	fmt.Fprintf(w, "Hello %s!", remPartOfURL)

	PrintNestedComments(w, ClosureTree())

	fmt.Fprint(w, "")

}

func PrintNestedComments(w http.ResponseWriter, el *binarytree.Tree) {
	if el == nil {
		return
	}

	fmt.Fprint(w, "
")
	//Self
	e := el.Value.(forum.Entry)
	fmt.Fprintf(w, "Title: %s", e.Title)

	//Children are nested
	PrintNestedComments(w, el.Left())
	fmt.Fprint(w, "
")

	//Siblings are parallel
	PrintNestedComments(w, el.Right())
}

func PrintComments(ct *binarytree.Tree) string {
	x := binarytree.Walker(ct)
	val := ""
	for y := range x {
		js, err := json.Marshal(y)
		if err != nil {
			fmt.Println(err)
			return "ERROR"
		}
		val += string(js) + "::"
	}

	return val
}

func ClosureTree() *binarytree.Tree {
	//Make some entries
	entries := map[int64]forum.Entry{
		0: forum.Entry{Id: 100, Title: "Title 100", Body: "Body 100", Created: time.Now(), AuthorId: 0},
		1: forum.Entry{Id: 101, Title: "Title 101", Body: "Body 101", Created: time.Now(), AuthorId: 1},
		2: forum.Entry{Id: 102, Title: "Title 102", Body: "Body 102", Created: time.Now(), AuthorId: 2},
		3: forum.Entry{Id: 103, Title: "Title 103", Body: "Body 103", Created: time.Now(), AuthorId: 3},
	}

	ct := closureTable()

	// Obligatory boxing step
	// Convert to interface type so the generic TableToTree method can be called on these entries
	boxedEntries := map[int64]interface{}{}
	for k, v := range entries {
		boxedEntries[k] = v
	}

	tree := ct.TableToTree(boxedEntries)

	return tree
}

func closureTable() *closuretable.ClosureTable {
	//Make a hierarchy for these entries
	ct := closuretable.New(0)
	ct.AddChild(closuretable.Child{Parent: 0, Child: 1})
	ct.AddChild(closuretable.Child{Parent: 0, Child: 2})
	ct.AddChild(closuretable.Child{Parent: 1, Child: 3})

	return ct
}

/*
func binaryTree() *binarytree.Tree {
	L := binarytree.New(forum.Entry{Id: 1, Title: "Hello, world", Body: "This is a body.", Created: time.Now(), AuthorId: 1})
	L.PushLeft(forum.Entry{Id: 2, Title: "Hello, world", Body: "This is a body.", Created: time.Now(), AuthorId: 1})
	L.Left().PushLeft(forum.Entry{Id: 3, Title: "Hello, world", Body: "This is a body.", Created: time.Now(), AuthorId: 1})
	L.Left().PushRight(forum.Entry{Id: 4, Title: "Hello, world", Body: "This is a body.", Created: time.Now(), AuthorId: 1})

	channel := binarytree.Walker(L)

	for i := range channel {
		fmt.Printf("%#v\n", i)
	}

    return L
}
*/
<commit_msg>Removed deadcode from the main.go example.<commit_after>package main

import (
	"fmt"
	"github.com/carbocation/forum.git/forum"
	"github.com/carbocation/util.git/datatypes/binarytree"
	"github.com/carbocation/util.git/datatypes/closuretable"
	//"math/rand"
	"net/http"
	"time"
	//"html/template"
	"encoding/json"
)

func main() {
	http.HandleFunc("/hello/", commentHandler)
	http.HandleFunc("/", defaultHandler)
	http.ListenAndServe("localhost:9999", nil)
}

func defaultHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/"):]
	fmt.Fprintf(w, "
Welcome, %s
Say hello", remPartOfURL)

	fmt.Fprint(w, "")
}

func commentHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/hello/"):] //get everything after the /hello/ part of the URL
	//w.Header().Set("Content-Type", "text/html")

	fmt.Fprint(w, "")
	fmt.Fprintf(w, "Hello %s!", remPartOfURL)

	PrintNestedComments(w, ClosureTree())

	fmt.Fprint(w, "")

}

func PrintNestedComments(w http.ResponseWriter, el *binarytree.Tree) {
	if el == nil {
		return
	}

	fmt.Fprint(w, "
")
	//Self
	e := el.Value.(forum.Entry)
	fmt.Fprintf(w, "Title: %s", e.Title)

	//Children are nested
	PrintNestedComments(w, el.Left())
	fmt.Fprint(w, "
")

	//Siblings are parallel
	PrintNestedComments(w, el.Right())
}

func ClosureTree() *binarytree.Tree {
	//Make some entries
	entries := map[int64]forum.Entry{
		0: forum.Entry{Id: 100, Title: "Title 100", Body: "Body 100", Created: time.Now(), AuthorId: 0},
		1: forum.Entry{Id: 101, Title: "Title 101", Body: "Body 101", Created: time.Now(), AuthorId: 1},
		2: forum.Entry{Id: 102, Title: "Title 102", Body: "Body 102", Created: time.Now(), AuthorId: 2},
		3: forum.Entry{Id: 103, Title: "Title 103", Body: "Body 103", Created: time.Now(), AuthorId: 3},
	}

	ct := closureTable()

	// Obligatory boxing step
	// Convert to interface type so the generic TableToTree method can be called on these entries
	boxedEntries := map[int64]interface{}{}
	for k, v := range entries {
		boxedEntries[k] = v
	}

	tree := ct.TableToTree(boxedEntries)

	return tree
}

func closureTable() *closuretable.ClosureTable {
	//Make a hierarchy for these entries
	ct := closuretable.New(0)
	ct.AddChild(closuretable.Child{Parent: 0, Child: 1})
	ct.AddChild(closuretable.Child{Parent: 0, Child: 2})
	ct.AddChild(closuretable.Child{Parent: 1, Child: 3})

	return ct
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"github.com/ricbra/rabbitmq-cli-consumer/command"
	"github.com/ricbra/rabbitmq-cli-consumer/config"
	"github.com/ricbra/rabbitmq-cli-consumer/consumer"
	"io"
	"log"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "rabbitmq-cli-consumer"
	app.Usage = "Consume RabbitMQ easily to any cli program"
	app.Author = "Richard van den Brand"
	app.Email = "richard@vandenbrand.org"
	app.Version = "1.0.3"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "executable, e",
			Usage: "Location of executable",
		},
		cli.StringFlag{
			Name:  "configuration, c",
			Usage: "Location of configuration file",
		},
		cli.BoolFlag{
			Name:  "verbose, V",
			Usage: "Enable verbose mode (logs to stdout and stderr)",
		},
	}
	app.Action = func(c *cli.Context) {
		if c.String("configuration") == "" && c.String("executable") == "" {
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		verbose := c.Bool("verbose")

		logger := log.New(os.Stderr, "", log.Ldate|log.Ltime)
		cfg, err := config.LoadAndParse(c.String("configuration"))

		if err != nil {
			logger.Fatalf("Failed parsing configuration: %s\n", err)
		}

		errLogger, err := createLogger(cfg.Logs.Error, verbose, os.Stderr)
		if err != nil {
			logger.Fatalf("Failed creating error log: %s", err)
		}

		infLogger, err := createLogger(cfg.Logs.Info, verbose, os.Stdout)
		if err != nil {
			logger.Fatalf("Failed creating info log: %s", err)
		}

		factory := command.Factory(c.String("executable"))

		client, err := consumer.New(cfg, factory, errLogger, infLogger)
		if err != nil {
			errLogger.Fatalf("Failed creating consumer: %s", err)
		}

		client.Consume()
	}

	app.Run(os.Args)
}

func createLogger(filename string, verbose bool, out io.Writer) (*log.Logger, error) {
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)

	if err != nil {
		return nil, err
	}

	var writers = []io.Writer{
		file,
	}

	if verbose {
		writers = append(writers, out)
	}

	return log.New(io.MultiWriter(writers...), "", log.Ldate|log.Ltime), nil
}
<commit_msg>Prepared version 1.1.0<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"github.com/ricbra/rabbitmq-cli-consumer/command"
	"github.com/ricbra/rabbitmq-cli-consumer/config"
	"github.com/ricbra/rabbitmq-cli-consumer/consumer"
	"io"
	"log"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "rabbitmq-cli-consumer"
	app.Usage = "Consume RabbitMQ easily to any cli program"
	app.Author = "Richard van den Brand"
	app.Email = "richard@vandenbrand.org"
	app.Version = "1.1.0"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "executable, e",
			Usage: "Location of executable",
		},
		cli.StringFlag{
			Name:  "configuration, c",
			Usage: "Location of configuration file",
		},
		cli.BoolFlag{
			Name:  "verbose, V",
			Usage: "Enable verbose mode (logs to stdout and stderr)",
		},
	}
	app.Action = func(c *cli.Context) {
		if c.String("configuration") == "" && c.String("executable") == "" {
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		verbose := c.Bool("verbose")

		logger := log.New(os.Stderr, "", log.Ldate|log.Ltime)
		cfg, err := config.LoadAndParse(c.String("configuration"))

		if err != nil {
			logger.Fatalf("Failed parsing configuration: %s\n", err)
		}

		errLogger, err := createLogger(cfg.Logs.Error, verbose, os.Stderr)
		if err != nil {
			logger.Fatalf("Failed creating error log: %s", err)
		}

		infLogger, err := createLogger(cfg.Logs.Info, verbose, os.Stdout)
		if err != nil {
			logger.Fatalf("Failed creating info log: %s", err)
		}

		factory := command.Factory(c.String("executable"))

		client, err := consumer.New(cfg, factory, errLogger, infLogger)
		if err != nil {
			errLogger.Fatalf("Failed creating consumer: %s", err)
		}

		client.Consume()
	}

	app.Run(os.Args)
}

func createLogger(filename string, verbose bool, out io.Writer) (*log.Logger, error) {
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)

	if err != nil {
		return nil, err
	}

	var writers = []io.Writer{
		file,
	}

	if verbose {
		writers = append(writers, out)
	}

	return log.New(io.MultiWriter(writers...), "", log.Ldate|log.Ltime), nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"syscall"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/gruntwork-io/terragrunt/cli"
	"github.com/gruntwork-io/terragrunt/errors"
)

// This variable is set at build time using -ldflags parameters. For more info, see:
// http://stackoverflow.com/a/11355611/483528
var VERSION string

// The main entrypoint for Terragrunt
func main() {
	defer errors.Recover(checkForErrorsAndExit)

	app := cli.CreateTerragruntCli(VERSION)
	err := app.Run(os.Args)

	checkForErrorsAndExit(err)
}

// If there is an error, display it in the console and exit with a non-zero exit code. Otherwise, exit 0.
func checkForErrorsAndExit(err error) {
	if err == nil {
		os.Exit(0)
	} else {
		logger := util.CreateLogger("")
		if os.Getenv("TERRAGRUNT_DEBUG") != "" {
			logger.Println(errors.PrintErrorWithStackTrace(err))
		} else {
			logger.Println(err)
		}
		// exit with the underlying error code
		var retCode int = 1
		if exiterr, ok := errors.Unwrap(err).(*exec.ExitError); ok {
			status := exiterr.Sys().(syscall.WaitStatus)
			retCode = status.ExitStatus()
		}
		os.Exit(retCode)
	}

}<commit_msg>Get exit code from shell package<commit_after>package main

import (
	"os"
	"github.com/gruntwork-io/terragrunt/shell"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/gruntwork-io/terragrunt/cli"
	"github.com/gruntwork-io/terragrunt/errors"
)

// This variable is set at build time using -ldflags parameters. For more info, see:
// http://stackoverflow.com/a/11355611/483528
var VERSION string

// The main entrypoint for Terragrunt
func main() {
	defer errors.Recover(checkForErrorsAndExit)

	app := cli.CreateTerragruntCli(VERSION)
	err := app.Run(os.Args)

	checkForErrorsAndExit(err)
}

// If there is an error, display it in the console and exit with a non-zero exit code. Otherwise, exit 0.
func checkForErrorsAndExit(err error) {
	if err == nil {
		os.Exit(0)
	} else {
		logger := util.CreateLogger("")
		if os.Getenv("TERRAGRUNT_DEBUG") != "" {
			logger.Println(errors.PrintErrorWithStackTrace(err))
		} else {
			logger.Println(err)
		}
		// exit with the underlying error code
		var retCode int
		retCode, err := shell.GetExitCode(err)
		if err != nil {
			retCode = 1
		}
		os.Exit(retCode)
	}

}<|endoftext|>


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

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" OK!")).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}
<commit_msg>remove message id<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.Text+" OK!")).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}
<|endoftext|>