├── .gitignore ├── Godeps ├── Godeps.json ├── Readme └── _workspace │ ├── .gitignore │ └── src │ ├── bitbucket.org │ └── liamstask │ │ └── goose │ │ ├── cmd │ │ └── goose │ │ │ ├── cmd.go │ │ │ ├── cmd_create.go │ │ │ ├── cmd_dbversion.go │ │ │ ├── cmd_down.go │ │ │ ├── cmd_redo.go │ │ │ ├── cmd_status.go │ │ │ ├── cmd_up.go │ │ │ └── main.go │ │ └── lib │ │ └── goose │ │ ├── dbconf.go │ │ ├── dbconf_test.go │ │ ├── dialect.go │ │ ├── migrate.go │ │ ├── migrate_test.go │ │ ├── migration_go.go │ │ ├── migration_sql.go │ │ ├── migration_sql_test.go │ │ └── util.go │ ├── github.com │ ├── Sirupsen │ │ └── logrus │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── entry.go │ │ │ ├── entry_test.go │ │ │ ├── examples │ │ │ ├── basic │ │ │ │ └── basic.go │ │ │ └── hook │ │ │ │ └── hook.go │ │ │ ├── exported.go │ │ │ ├── formatter.go │ │ │ ├── formatter_bench_test.go │ │ │ ├── hook_test.go │ │ │ ├── hooks.go │ │ │ ├── hooks │ │ │ ├── airbrake │ │ │ │ └── airbrake.go │ │ │ ├── papertrail │ │ │ │ ├── README.md │ │ │ │ ├── papertrail.go │ │ │ │ └── papertrail_test.go │ │ │ ├── sentry │ │ │ │ ├── README.md │ │ │ │ ├── sentry.go │ │ │ │ └── sentry_test.go │ │ │ └── syslog │ │ │ │ ├── README.md │ │ │ │ ├── syslog.go │ │ │ │ └── syslog_test.go │ │ │ ├── json_formatter.go │ │ │ ├── logger.go │ │ │ ├── logrus.go │ │ │ ├── logrus_test.go │ │ │ ├── terminal_darwin.go │ │ │ ├── terminal_freebsd.go │ │ │ ├── terminal_linux.go │ │ │ ├── terminal_notwindows.go │ │ │ ├── terminal_windows.go │ │ │ ├── text_formatter.go │ │ │ └── text_formatter_test.go │ ├── codegangsta │ │ └── negroni │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── logger.go │ │ │ ├── logger_test.go │ │ │ ├── negroni.go │ │ │ ├── negroni_test.go │ │ │ ├── recovery.go │ │ │ ├── recovery_test.go │ │ │ ├── response_writer.go │ │ │ ├── response_writer_test.go │ │ │ ├── static.go │ │ │ └── static_test.go │ ├── coopernurse │ │ └── gorp │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── dialect.go │ │ │ ├── errors.go │ │ │ ├── gorp.go │ │ │ ├── gorp_test.go │ │ │ └── test_all.sh │ ├── gorilla │ │ ├── context │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── context.go │ │ │ ├── context_test.go │ │ │ └── doc.go │ │ ├── handlers │ │ │ ├── .travis.yml │ │ │ ├── README.md │ │ │ ├── compress.go │ │ │ ├── compress_test.go │ │ │ ├── handlers.go │ │ │ └── handlers_test.go │ │ ├── mux │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bench_test.go │ │ │ ├── doc.go │ │ │ ├── mux.go │ │ │ ├── mux_test.go │ │ │ ├── old_test.go │ │ │ ├── regexp.go │ │ │ └── route.go │ │ ├── securecookie │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── securecookie.go │ │ │ └── securecookie_test.go │ │ └── sessions │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── sessions.go │ │ │ ├── sessions_test.go │ │ │ ├── store.go │ │ │ └── store_test.go │ ├── guregu │ │ └── null │ │ │ ├── .gitignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bool.go │ │ │ ├── bool_test.go │ │ │ ├── float.go │ │ │ ├── float_test.go │ │ │ ├── int.go │ │ │ ├── int_test.go │ │ │ ├── string.go │ │ │ ├── string_test.go │ │ │ └── zero │ │ │ ├── bool.go │ │ │ ├── bool_test.go │ │ │ ├── float.go │ │ │ ├── float_test.go │ │ │ ├── int.go │ │ │ ├── int_test.go │ │ │ ├── string.go │ │ │ └── string_test.go │ ├── justinas │ │ └── nosurf │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── context.go │ │ │ ├── context_test.go │ │ │ ├── crypto.go │ │ │ ├── crypto_test.go │ │ │ ├── examples │ │ │ ├── advanced.go │ │ │ ├── goji.go │ │ │ ├── simple.go │ │ │ └── web.go │ │ │ ├── exempt.go │ │ │ ├── exempt_test.go │ │ │ ├── handler.go │ │ │ ├── handler_test.go │ │ │ ├── testutils.go │ │ │ ├── token.go │ │ │ ├── token_test.go │ │ │ ├── utils.go │ │ │ └── utils_test.go │ ├── kylelemons │ │ └── go-gypsy │ │ │ └── yaml │ │ │ ├── Makefile │ │ │ ├── config.go │ │ │ ├── config_test.go │ │ │ ├── doc.go │ │ │ ├── parser.go │ │ │ ├── parser_test.go │ │ │ ├── types.go │ │ │ └── types_test.go │ ├── lib │ │ └── pq │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ ├── bench_test.go │ │ │ ├── buf.go │ │ │ ├── conn.go │ │ │ ├── conn_test.go │ │ │ ├── conn_xact_test.go │ │ │ ├── copy.go │ │ │ ├── copy_test.go │ │ │ ├── doc.go │ │ │ ├── encode.go │ │ │ ├── encode_test.go │ │ │ ├── error.go │ │ │ ├── hstore │ │ │ ├── hstore.go │ │ │ └── hstore_test.go │ │ │ ├── listen_example │ │ │ └── doc.go │ │ │ ├── notify.go │ │ │ ├── notify_test.go │ │ │ ├── oid │ │ │ ├── doc.go │ │ │ ├── gen.go │ │ │ └── types.go │ │ │ ├── url.go │ │ │ ├── url_test.go │ │ │ ├── user_posix.go │ │ │ └── user_windows.go │ ├── mattn │ │ └── go-sqlite3 │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── backup.go │ │ │ ├── doc.go │ │ │ ├── error.go │ │ │ ├── error_test.go │ │ │ ├── sqlite3.c │ │ │ ├── sqlite3.go │ │ │ ├── sqlite3.h │ │ │ ├── sqlite3_other.go │ │ │ ├── sqlite3_test.go │ │ │ ├── sqlite3_test │ │ │ └── sqltest.go │ │ │ ├── sqlite3_windows.go │ │ │ └── sqlite3ext.h │ ├── stretchr │ │ ├── graceful │ │ │ ├── .gitignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── graceful.go │ │ │ ├── graceful_test.go │ │ │ ├── tests │ │ │ │ └── main.go │ │ │ └── wercker.yml │ │ └── pat │ │ │ └── stop │ │ │ ├── doc.go │ │ │ ├── stop.go │ │ │ └── stop_test.go │ └── ziutek │ │ └── mymysql │ │ ├── godrv │ │ ├── appengine.go │ │ ├── driver.go │ │ └── driver_test.go │ │ ├── mysql │ │ ├── errors.go │ │ ├── field.go │ │ ├── interface.go │ │ ├── row.go │ │ ├── types.go │ │ ├── types_test.go │ │ └── utils.go │ │ └── native │ │ ├── LICENSE │ │ ├── addons.go │ │ ├── bind_test.go │ │ ├── binding.go │ │ ├── codecs.go │ │ ├── command.go │ │ ├── common.go │ │ ├── consts.go │ │ ├── init.go │ │ ├── mysql.go │ │ ├── native_test.go │ │ ├── packet.go │ │ ├── paramvalue.go │ │ ├── passwd.go │ │ ├── prepared.go │ │ ├── result.go │ │ └── unsafe.go-disabled │ └── golang.org │ └── x │ └── net │ └── netutil │ ├── listen.go │ └── listen_test.go ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── db ├── dbconf.yml └── migrations │ └── 20150207110852_initial.sql ├── install_goose.go ├── lib ├── auth.go ├── db.go ├── handlers.go ├── mail.go ├── middleware.go ├── models.go ├── routes.go ├── template.go └── templates │ ├── home.html │ ├── login-success.html │ ├── partials │ ├── footer.html │ └── header.html │ ├── profile.html │ └── verify.html ├── passwordless.go └── public ├── css └── bootstrap.min.css └── fonts ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff └── glyphicons-halflings-regular.woff2 /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .env 3 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | /bin 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | ) 6 | 7 | // shamelessly snagged from the go tool 8 | // each command gets its own set of args, 9 | // defines its own entry point, and provides its own help 10 | type Command struct { 11 | Run func(cmd *Command, args ...string) 12 | Flag flag.FlagSet 13 | 14 | Name string 15 | Usage string 16 | 17 | Summary string 18 | Help string 19 | } 20 | 21 | func (c *Command) Exec(args []string) { 22 | c.Flag.Usage = func() { 23 | // helpFunc(c, c.Name) 24 | } 25 | c.Flag.Parse(args) 26 | c.Run(c, c.Flag.Args()...) 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_create.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "fmt" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "time" 10 | ) 11 | 12 | var createCmd = &Command{ 13 | Name: "create", 14 | Usage: "", 15 | Summary: "Create the scaffolding for a new migration", 16 | Help: `create extended help here...`, 17 | Run: createRun, 18 | } 19 | 20 | func createRun(cmd *Command, args ...string) { 21 | 22 | if len(args) < 1 { 23 | log.Fatal("goose create: migration name required") 24 | } 25 | 26 | migrationType := "go" // default to Go migrations 27 | if len(args) >= 2 { 28 | migrationType = args[1] 29 | } 30 | 31 | conf, err := dbConfFromFlags() 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | if err = os.MkdirAll(conf.MigrationsDir, 0777); err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | n, err := goose.CreateMigration(args[0], migrationType, conf.MigrationsDir, time.Now()) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | a, e := filepath.Abs(n) 46 | if e != nil { 47 | log.Fatal(e) 48 | } 49 | 50 | fmt.Println("goose: created", a) 51 | } 52 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_dbversion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | var dbVersionCmd = &Command{ 10 | Name: "dbversion", 11 | Usage: "", 12 | Summary: "Print the current version of the database", 13 | Help: `dbversion extended help here...`, 14 | Run: dbVersionRun, 15 | } 16 | 17 | func dbVersionRun(cmd *Command, args ...string) { 18 | conf, err := dbConfFromFlags() 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | current, err := goose.GetDBVersion(conf) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | fmt.Printf("goose: dbversion %v\n", current) 29 | } 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_down.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "log" 6 | ) 7 | 8 | var downCmd = &Command{ 9 | Name: "down", 10 | Usage: "", 11 | Summary: "Roll back the version by 1", 12 | Help: `down extended help here...`, 13 | Run: downRun, 14 | } 15 | 16 | func downRun(cmd *Command, args ...string) { 17 | 18 | conf, err := dbConfFromFlags() 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | current, err := goose.GetDBVersion(conf) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | previous, err := goose.GetPreviousDBVersion(conf.MigrationsDir, current) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | if err = goose.RunMigrations(conf, conf.MigrationsDir, previous); err != nil { 34 | log.Fatal(err) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_redo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "log" 6 | ) 7 | 8 | var redoCmd = &Command{ 9 | Name: "redo", 10 | Usage: "", 11 | Summary: "Re-run the latest migration", 12 | Help: `redo extended help here...`, 13 | Run: redoRun, 14 | } 15 | 16 | func redoRun(cmd *Command, args ...string) { 17 | conf, err := dbConfFromFlags() 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | 22 | current, err := goose.GetDBVersion(conf) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | 27 | previous, err := goose.GetPreviousDBVersion(conf.MigrationsDir, current) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | if err := goose.RunMigrations(conf, conf.MigrationsDir, previous); err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | if err := goose.RunMigrations(conf, conf.MigrationsDir, current); err != nil { 37 | log.Fatal(err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_status.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "database/sql" 6 | "fmt" 7 | "log" 8 | "path/filepath" 9 | "time" 10 | ) 11 | 12 | var statusCmd = &Command{ 13 | Name: "status", 14 | Usage: "", 15 | Summary: "dump the migration status for the current DB", 16 | Help: `status extended help here...`, 17 | Run: statusRun, 18 | } 19 | 20 | type StatusData struct { 21 | Source string 22 | Status string 23 | } 24 | 25 | func statusRun(cmd *Command, args ...string) { 26 | 27 | conf, err := dbConfFromFlags() 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | // collect all migrations 33 | min := int64(0) 34 | max := int64((1 << 63) - 1) 35 | migrations, e := goose.CollectMigrations(conf.MigrationsDir, min, max) 36 | if e != nil { 37 | log.Fatal(e) 38 | } 39 | 40 | db, e := goose.OpenDBFromDBConf(conf) 41 | if e != nil { 42 | log.Fatal("couldn't open DB:", e) 43 | } 44 | defer db.Close() 45 | 46 | // must ensure that the version table exists if we're running on a pristine DB 47 | if _, e := goose.EnsureDBVersion(conf, db); e != nil { 48 | log.Fatal(e) 49 | } 50 | 51 | fmt.Printf("goose: status for environment '%v'\n", conf.Env) 52 | fmt.Println(" Applied At Migration") 53 | fmt.Println(" =======================================") 54 | for _, m := range migrations { 55 | printMigrationStatus(db, m.Version, filepath.Base(m.Source)) 56 | } 57 | } 58 | 59 | func printMigrationStatus(db *sql.DB, version int64, script string) { 60 | var row goose.MigrationRecord 61 | q := fmt.Sprintf("SELECT tstamp, is_applied FROM goose_db_version WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", version) 62 | e := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied) 63 | 64 | if e != nil && e != sql.ErrNoRows { 65 | log.Fatal(e) 66 | } 67 | 68 | var appliedAt string 69 | 70 | if row.IsApplied { 71 | appliedAt = row.TStamp.Format(time.ANSIC) 72 | } else { 73 | appliedAt = "Pending" 74 | } 75 | 76 | fmt.Printf(" %-24s -- %v\n", appliedAt, script) 77 | } 78 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_up.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "log" 6 | ) 7 | 8 | var upCmd = &Command{ 9 | Name: "up", 10 | Usage: "", 11 | Summary: "Migrate the DB to the most recent version available", 12 | Help: `up extended help here...`, 13 | Run: upRun, 14 | } 15 | 16 | func upRun(cmd *Command, args ...string) { 17 | 18 | conf, err := dbConfFromFlags() 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | target, err := goose.GetMostRecentDBVersion(conf.MigrationsDir) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | if err := goose.RunMigrations(conf, conf.MigrationsDir, target); err != nil { 29 | log.Fatal(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "strings" 9 | "text/template" 10 | ) 11 | 12 | // global options. available to any subcommands. 13 | var flagPath = flag.String("path", "db", "folder containing db info") 14 | var flagEnv = flag.String("env", "development", "which DB environment to use") 15 | var flagPgSchema = flag.String("pgschema", "", "which postgres-schema to migrate (default = none)") 16 | 17 | // helper to create a DBConf from the given flags 18 | func dbConfFromFlags() (dbconf *goose.DBConf, err error) { 19 | return goose.NewDBConf(*flagPath, *flagEnv, *flagPgSchema) 20 | } 21 | 22 | var commands = []*Command{ 23 | upCmd, 24 | downCmd, 25 | redoCmd, 26 | statusCmd, 27 | createCmd, 28 | dbVersionCmd, 29 | } 30 | 31 | func main() { 32 | 33 | flag.Usage = usage 34 | flag.Parse() 35 | 36 | args := flag.Args() 37 | if len(args) == 0 || args[0] == "-h" { 38 | flag.Usage() 39 | return 40 | } 41 | 42 | var cmd *Command 43 | name := args[0] 44 | for _, c := range commands { 45 | if strings.HasPrefix(c.Name, name) { 46 | cmd = c 47 | break 48 | } 49 | } 50 | 51 | if cmd == nil { 52 | fmt.Printf("error: unknown command %q\n", name) 53 | flag.Usage() 54 | os.Exit(1) 55 | } 56 | 57 | cmd.Exec(args[1:]) 58 | } 59 | 60 | func usage() { 61 | fmt.Print(usagePrefix) 62 | flag.PrintDefaults() 63 | usageTmpl.Execute(os.Stdout, commands) 64 | } 65 | 66 | var usagePrefix = ` 67 | goose is a database migration management system for Go projects. 68 | 69 | Usage: 70 | goose [options] [subcommand options] 71 | 72 | Options: 73 | ` 74 | var usageTmpl = template.Must(template.New("usage").Parse( 75 | ` 76 | Commands:{{range .}} 77 | {{.Name | printf "%-10s"}} {{.Summary}}{{end}} 78 | `)) 79 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/lib/goose/dbconf_test.go: -------------------------------------------------------------------------------- 1 | package goose 2 | 3 | import ( 4 | "os" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestBasics(t *testing.T) { 10 | 11 | dbconf, err := NewDBConf("../../db-sample", "test", "") 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | 16 | got := []string{dbconf.MigrationsDir, dbconf.Env, dbconf.Driver.Name, dbconf.Driver.OpenStr} 17 | want := []string{"../../db-sample/migrations", "test", "postgres", "user=liam dbname=tester sslmode=disable"} 18 | 19 | for i, s := range got { 20 | if s != want[i] { 21 | t.Errorf("Unexpected DBConf value. got %v, want %v", s, want[i]) 22 | } 23 | } 24 | } 25 | 26 | func TestImportOverride(t *testing.T) { 27 | 28 | dbconf, err := NewDBConf("../../db-sample", "customimport", "") 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | got := dbconf.Driver.Import 34 | want := "github.com/custom/driver" 35 | if got != want { 36 | t.Errorf("bad custom import. got %v want %v", got, want) 37 | } 38 | } 39 | 40 | func TestDriverSetFromEnvironmentVariable(t *testing.T) { 41 | 42 | databaseUrlEnvVariableKey := "DB_DRIVER" 43 | databaseUrlEnvVariableVal := "sqlite3" 44 | databaseOpenStringKey := "DATABASE_URL" 45 | databaseOpenStringVal := "db.db" 46 | 47 | os.Setenv(databaseUrlEnvVariableKey, databaseUrlEnvVariableVal) 48 | os.Setenv(databaseOpenStringKey, databaseOpenStringVal) 49 | 50 | dbconf, err := NewDBConf("../../db-sample", "environment_variable_config", "") 51 | if err != nil { 52 | t.Fatal(err) 53 | } 54 | 55 | got := reflect.TypeOf(dbconf.Driver.Dialect) 56 | want := reflect.TypeOf(&Sqlite3Dialect{}) 57 | 58 | if got != want { 59 | t.Errorf("Not able to read the driver type from environment variable."+ 60 | "got %v want %v", got, want) 61 | } 62 | 63 | gotOpenString := dbconf.Driver.OpenStr 64 | wantOpenString := databaseOpenStringVal 65 | 66 | if gotOpenString != wantOpenString { 67 | t.Errorf("Not able to read the open string from the environment."+ 68 | "got %v want %v", gotOpenString, wantOpenString) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/lib/goose/migrate_test.go: -------------------------------------------------------------------------------- 1 | package goose 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestMigrationMapSortUp(t *testing.T) { 8 | 9 | ms := migrationSorter{} 10 | 11 | // insert in any order 12 | ms = append(ms, newMigration(20120000, "test")) 13 | ms = append(ms, newMigration(20128000, "test")) 14 | ms = append(ms, newMigration(20129000, "test")) 15 | ms = append(ms, newMigration(20127000, "test")) 16 | 17 | ms.Sort(true) // sort Upwards 18 | 19 | sorted := []int64{20120000, 20127000, 20128000, 20129000} 20 | 21 | validateMigrationSort(t, ms, sorted) 22 | } 23 | 24 | func TestMigrationMapSortDown(t *testing.T) { 25 | 26 | ms := migrationSorter{} 27 | 28 | // insert in any order 29 | ms = append(ms, newMigration(20120000, "test")) 30 | ms = append(ms, newMigration(20128000, "test")) 31 | ms = append(ms, newMigration(20129000, "test")) 32 | ms = append(ms, newMigration(20127000, "test")) 33 | 34 | ms.Sort(false) // sort Downwards 35 | 36 | sorted := []int64{20129000, 20128000, 20127000, 20120000} 37 | 38 | validateMigrationSort(t, ms, sorted) 39 | } 40 | 41 | func validateMigrationSort(t *testing.T, ms migrationSorter, sorted []int64) { 42 | 43 | for i, m := range ms { 44 | if sorted[i] != m.Version { 45 | t.Error("incorrect sorted version") 46 | } 47 | 48 | var next, prev int64 49 | 50 | if i == 0 { 51 | prev = -1 52 | next = ms[i+1].Version 53 | } else if i == len(ms)-1 { 54 | prev = ms[i-1].Version 55 | next = -1 56 | } else { 57 | prev = ms[i-1].Version 58 | next = ms[i+1].Version 59 | } 60 | 61 | if m.Next != next { 62 | t.Errorf("mismatched Next. v: %v, got %v, wanted %v\n", m, m.Next, next) 63 | } 64 | 65 | if m.Previous != prev { 66 | t.Errorf("mismatched Previous v: %v, got %v, wanted %v\n", m, m.Previous, prev) 67 | } 68 | } 69 | 70 | t.Log(ms) 71 | } 72 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/lib/goose/util.go: -------------------------------------------------------------------------------- 1 | package goose 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "text/template" 7 | ) 8 | 9 | // common routines 10 | 11 | func writeTemplateToFile(path string, t *template.Template, data interface{}) (string, error) { 12 | f, e := os.Create(path) 13 | if e != nil { 14 | return "", e 15 | } 16 | defer f.Close() 17 | 18 | e = t.Execute(f, data) 19 | if e != nil { 20 | return "", e 21 | } 22 | 23 | return f.Name(), nil 24 | } 25 | 26 | func copyFile(dst, src string) (int64, error) { 27 | sf, err := os.Open(src) 28 | if err != nil { 29 | return 0, err 30 | } 31 | defer sf.Close() 32 | 33 | df, err := os.Create(dst) 34 | if err != nil { 35 | return 0, err 36 | } 37 | defer df.Close() 38 | 39 | return io.Copy(df, sf) 40 | } 41 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore: -------------------------------------------------------------------------------- 1 | logrus 2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.2 4 | - 1.3 5 | - tip 6 | install: 7 | - go get github.com/stretchr/testify 8 | - go get github.com/stvp/go-udp-testing 9 | - go get github.com/tobi/airbrake-go 10 | - go get github.com/getsentry/raven-go 11 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/entry_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestEntryPanicln(t *testing.T) { 12 | errBoom := fmt.Errorf("boom time") 13 | 14 | defer func() { 15 | p := recover() 16 | assert.NotNil(t, p) 17 | 18 | switch pVal := p.(type) { 19 | case *Entry: 20 | assert.Equal(t, "kaboom", pVal.Message) 21 | assert.Equal(t, errBoom, pVal.Data["err"]) 22 | default: 23 | t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 24 | } 25 | }() 26 | 27 | logger := New() 28 | logger.Out = &bytes.Buffer{} 29 | entry := NewEntry(logger) 30 | entry.WithField("err", errBoom).Panicln("kaboom") 31 | } 32 | 33 | func TestEntryPanicf(t *testing.T) { 34 | errBoom := fmt.Errorf("boom again") 35 | 36 | defer func() { 37 | p := recover() 38 | assert.NotNil(t, p) 39 | 40 | switch pVal := p.(type) { 41 | case *Entry: 42 | assert.Equal(t, "kaboom true", pVal.Message) 43 | assert.Equal(t, errBoom, pVal.Data["err"]) 44 | default: 45 | t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 46 | } 47 | }() 48 | 49 | logger := New() 50 | logger.Out = &bytes.Buffer{} 51 | entry := NewEntry(logger) 52 | entry.WithField("err", errBoom).Panicf("kaboom %v", true) 53 | } 54 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | ) 6 | 7 | var log = logrus.New() 8 | 9 | func init() { 10 | log.Formatter = new(logrus.JSONFormatter) 11 | log.Formatter = new(logrus.TextFormatter) // default 12 | } 13 | 14 | func main() { 15 | defer func() { 16 | err := recover() 17 | if err != nil { 18 | log.WithFields(logrus.Fields{ 19 | "omg": true, 20 | "err": err, 21 | "number": 100, 22 | }).Fatal("The ice breaks!") 23 | } 24 | }() 25 | 26 | log.WithFields(logrus.Fields{ 27 | "animal": "walrus", 28 | "size": 10, 29 | }).Info("A group of walrus emerges from the ocean") 30 | 31 | log.WithFields(logrus.Fields{ 32 | "omg": true, 33 | "number": 122, 34 | }).Warn("The group's number increased tremendously!") 35 | 36 | log.WithFields(logrus.Fields{ 37 | "animal": "orca", 38 | "size": 9009, 39 | }).Panic("It's over 9000!") 40 | } 41 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "github.com/Sirupsen/logrus/hooks/airbrake" 6 | "github.com/tobi/airbrake-go" 7 | ) 8 | 9 | var log = logrus.New() 10 | 11 | func init() { 12 | log.Formatter = new(logrus.TextFormatter) // default 13 | log.Hooks.Add(new(logrus_airbrake.AirbrakeHook)) 14 | } 15 | 16 | func main() { 17 | airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml" 18 | airbrake.ApiKey = "whatever" 19 | airbrake.Environment = "production" 20 | 21 | log.WithFields(logrus.Fields{ 22 | "animal": "walrus", 23 | "size": 10, 24 | }).Info("A group of walrus emerges from the ocean") 25 | 26 | log.WithFields(logrus.Fields{ 27 | "omg": true, 28 | "number": 122, 29 | }).Warn("The group's number increased tremendously!") 30 | 31 | log.WithFields(logrus.Fields{ 32 | "omg": true, 33 | "number": 100, 34 | }).Fatal("The ice breaks!") 35 | } 36 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // The Formatter interface is used to implement a custom Formatter. It takes an 4 | // `Entry`. It exposes all the fields, including the default ones: 5 | // 6 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. 7 | // * `entry.Data["time"]`. The timestamp. 8 | // * `entry.Data["level"]. The level the entry was logged at. 9 | // 10 | // Any additional fields added with `WithField` or `WithFields` are also in 11 | // `entry.Data`. Format is expected to return an array of bytes which are then 12 | // logged to `logger.Out`. 13 | type Formatter interface { 14 | Format(*Entry) ([]byte, error) 15 | } 16 | 17 | // This is to not silently overwrite `time`, `msg` and `level` fields when 18 | // dumping it. If this code wasn't there doing: 19 | // 20 | // logrus.WithField("level", 1).Info("hello") 21 | // 22 | // Would just silently drop the user provided level. Instead with this code 23 | // it'll logged as: 24 | // 25 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} 26 | // 27 | // It's not exported because it's still using Data in an opinionated way. It's to 28 | // avoid code duplication between the two default formatters. 29 | func prefixFieldClashes(data Fields) { 30 | _, ok := data["time"] 31 | if ok { 32 | data["fields.time"] = data["time"] 33 | } 34 | 35 | _, ok = data["msg"] 36 | if ok { 37 | data["fields.msg"] = data["msg"] 38 | } 39 | 40 | _, ok = data["level"] 41 | if ok { 42 | data["fields.level"] = data["level"] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter_bench_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | // smallFields is a small size data set for benchmarking 9 | var smallFields = Fields{ 10 | "foo": "bar", 11 | "baz": "qux", 12 | "one": "two", 13 | "three": "four", 14 | } 15 | 16 | // largeFields is a large size data set for benchmarking 17 | var largeFields = Fields{ 18 | "foo": "bar", 19 | "baz": "qux", 20 | "one": "two", 21 | "three": "four", 22 | "five": "six", 23 | "seven": "eight", 24 | "nine": "ten", 25 | "eleven": "twelve", 26 | "thirteen": "fourteen", 27 | "fifteen": "sixteen", 28 | "seventeen": "eighteen", 29 | "nineteen": "twenty", 30 | "a": "b", 31 | "c": "d", 32 | "e": "f", 33 | "g": "h", 34 | "i": "j", 35 | "k": "l", 36 | "m": "n", 37 | "o": "p", 38 | "q": "r", 39 | "s": "t", 40 | "u": "v", 41 | "w": "x", 42 | "y": "z", 43 | "this": "will", 44 | "make": "thirty", 45 | "entries": "yeah", 46 | } 47 | 48 | func BenchmarkSmallTextFormatter(b *testing.B) { 49 | doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) 50 | } 51 | 52 | func BenchmarkLargeTextFormatter(b *testing.B) { 53 | doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) 54 | } 55 | 56 | func BenchmarkSmallColoredTextFormatter(b *testing.B) { 57 | doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) 58 | } 59 | 60 | func BenchmarkLargeColoredTextFormatter(b *testing.B) { 61 | doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) 62 | } 63 | 64 | func BenchmarkSmallJSONFormatter(b *testing.B) { 65 | doBenchmark(b, &JSONFormatter{}, smallFields) 66 | } 67 | 68 | func BenchmarkLargeJSONFormatter(b *testing.B) { 69 | doBenchmark(b, &JSONFormatter{}, largeFields) 70 | } 71 | 72 | func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { 73 | entry := &Entry{ 74 | Time: time.Time{}, 75 | Level: InfoLevel, 76 | Message: "message", 77 | Data: fields, 78 | } 79 | var d []byte 80 | var err error 81 | for i := 0; i < b.N; i++ { 82 | d, err = formatter.Format(entry) 83 | if err != nil { 84 | b.Fatal(err) 85 | } 86 | b.SetBytes(int64(len(d))) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hook_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | type TestHook struct { 10 | Fired bool 11 | } 12 | 13 | func (hook *TestHook) Fire(entry *Entry) error { 14 | hook.Fired = true 15 | return nil 16 | } 17 | 18 | func (hook *TestHook) Levels() []Level { 19 | return []Level{ 20 | DebugLevel, 21 | InfoLevel, 22 | WarnLevel, 23 | ErrorLevel, 24 | FatalLevel, 25 | PanicLevel, 26 | } 27 | } 28 | 29 | func TestHookFires(t *testing.T) { 30 | hook := new(TestHook) 31 | 32 | LogAndAssertJSON(t, func(log *Logger) { 33 | log.Hooks.Add(hook) 34 | assert.Equal(t, hook.Fired, false) 35 | 36 | log.Print("test") 37 | }, func(fields Fields) { 38 | assert.Equal(t, hook.Fired, true) 39 | }) 40 | } 41 | 42 | type ModifyHook struct { 43 | } 44 | 45 | func (hook *ModifyHook) Fire(entry *Entry) error { 46 | entry.Data["wow"] = "whale" 47 | return nil 48 | } 49 | 50 | func (hook *ModifyHook) Levels() []Level { 51 | return []Level{ 52 | DebugLevel, 53 | InfoLevel, 54 | WarnLevel, 55 | ErrorLevel, 56 | FatalLevel, 57 | PanicLevel, 58 | } 59 | } 60 | 61 | func TestHookCanModifyEntry(t *testing.T) { 62 | hook := new(ModifyHook) 63 | 64 | LogAndAssertJSON(t, func(log *Logger) { 65 | log.Hooks.Add(hook) 66 | log.WithField("wow", "elephant").Print("test") 67 | }, func(fields Fields) { 68 | assert.Equal(t, fields["wow"], "whale") 69 | }) 70 | } 71 | 72 | func TestCanFireMultipleHooks(t *testing.T) { 73 | hook1 := new(ModifyHook) 74 | hook2 := new(TestHook) 75 | 76 | LogAndAssertJSON(t, func(log *Logger) { 77 | log.Hooks.Add(hook1) 78 | log.Hooks.Add(hook2) 79 | 80 | log.WithField("wow", "elephant").Print("test") 81 | }, func(fields Fields) { 82 | assert.Equal(t, fields["wow"], "whale") 83 | assert.Equal(t, hook2.Fired, true) 84 | }) 85 | } 86 | 87 | type ErrorHook struct { 88 | Fired bool 89 | } 90 | 91 | func (hook *ErrorHook) Fire(entry *Entry) error { 92 | hook.Fired = true 93 | return nil 94 | } 95 | 96 | func (hook *ErrorHook) Levels() []Level { 97 | return []Level{ 98 | ErrorLevel, 99 | } 100 | } 101 | 102 | func TestErrorHookShouldntFireOnInfo(t *testing.T) { 103 | hook := new(ErrorHook) 104 | 105 | LogAndAssertJSON(t, func(log *Logger) { 106 | log.Hooks.Add(hook) 107 | log.Info("test") 108 | }, func(fields Fields) { 109 | assert.Equal(t, hook.Fired, false) 110 | }) 111 | } 112 | 113 | func TestErrorHookShouldFireOnError(t *testing.T) { 114 | hook := new(ErrorHook) 115 | 116 | LogAndAssertJSON(t, func(log *Logger) { 117 | log.Hooks.Add(hook) 118 | log.Error("test") 119 | }, func(fields Fields) { 120 | assert.Equal(t, hook.Fired, true) 121 | }) 122 | } 123 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // A hook to be fired when logging on the logging levels returned from 4 | // `Levels()` on your implementation of the interface. Note that this is not 5 | // fired in a goroutine or a channel with workers, you should handle such 6 | // functionality yourself if your call is non-blocking and you don't wish for 7 | // the logging calls for levels returned from `Levels()` to block. 8 | type Hook interface { 9 | Levels() []Level 10 | Fire(*Entry) error 11 | } 12 | 13 | // Internal type for storing the hooks on a logger instance. 14 | type levelHooks map[Level][]Hook 15 | 16 | // Add a hook to an instance of logger. This is called with 17 | // `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. 18 | func (hooks levelHooks) Add(hook Hook) { 19 | for _, level := range hook.Levels() { 20 | hooks[level] = append(hooks[level], hook) 21 | } 22 | } 23 | 24 | // Fire all the hooks for the passed level. Used by `entry.log` to fire 25 | // appropriate hooks for a log entry. 26 | func (hooks levelHooks) Fire(level Level, entry *Entry) error { 27 | for _, hook := range hooks[level] { 28 | if err := hook.Fire(entry); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go: -------------------------------------------------------------------------------- 1 | package logrus_airbrake 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "github.com/tobi/airbrake-go" 6 | ) 7 | 8 | // AirbrakeHook to send exceptions to an exception-tracking service compatible 9 | // with the Airbrake API. You must set: 10 | // * airbrake.Endpoint 11 | // * airbrake.ApiKey 12 | // * airbrake.Environment (only sends exceptions when set to "production") 13 | // 14 | // Before using this hook, to send an error. Entries that trigger an Error, 15 | // Fatal or Panic should now include an "error" field to send to Airbrake. 16 | type AirbrakeHook struct{} 17 | 18 | func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error { 19 | if entry.Data["error"] == nil { 20 | entry.Logger.WithFields(logrus.Fields{ 21 | "source": "airbrake", 22 | "endpoint": airbrake.Endpoint, 23 | }).Warn("Exceptions sent to Airbrake must have an 'error' key with the error") 24 | return nil 25 | } 26 | 27 | err, ok := entry.Data["error"].(error) 28 | if !ok { 29 | entry.Logger.WithFields(logrus.Fields{ 30 | "source": "airbrake", 31 | "endpoint": airbrake.Endpoint, 32 | }).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`") 33 | return nil 34 | } 35 | 36 | airErr := airbrake.Notify(err) 37 | if airErr != nil { 38 | entry.Logger.WithFields(logrus.Fields{ 39 | "source": "airbrake", 40 | "endpoint": airbrake.Endpoint, 41 | "error": airErr, 42 | }).Warn("Failed to send error to Airbrake") 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (hook *AirbrakeHook) Levels() []logrus.Level { 49 | return []logrus.Level{ 50 | logrus.ErrorLevel, 51 | logrus.FatalLevel, 52 | logrus.PanicLevel, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md: -------------------------------------------------------------------------------- 1 | # Papertrail Hook for Logrus :walrus: 2 | 3 | [Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts). 4 | 5 | In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible. 6 | 7 | ## Usage 8 | 9 | You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`. 10 | 11 | For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs. 12 | 13 | ```go 14 | import ( 15 | "log/syslog" 16 | "github.com/Sirupsen/logrus" 17 | "github.com/Sirupsen/logrus/hooks/papertrail" 18 | ) 19 | 20 | func main() { 21 | log := logrus.New() 22 | hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME) 23 | 24 | if err == nil { 25 | log.Hooks.Add(hook) 26 | } 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go: -------------------------------------------------------------------------------- 1 | package logrus_papertrail 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "time" 8 | 9 | "github.com/Sirupsen/logrus" 10 | ) 11 | 12 | const ( 13 | format = "Jan 2 15:04:05" 14 | ) 15 | 16 | // PapertrailHook to send logs to a logging service compatible with the Papertrail API. 17 | type PapertrailHook struct { 18 | Host string 19 | Port int 20 | AppName string 21 | UDPConn net.Conn 22 | } 23 | 24 | // NewPapertrailHook creates a hook to be added to an instance of logger. 25 | func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) { 26 | conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port)) 27 | return &PapertrailHook{host, port, appName, conn}, err 28 | } 29 | 30 | // Fire is called when a log event is fired. 31 | func (hook *PapertrailHook) Fire(entry *logrus.Entry) error { 32 | date := time.Now().Format(format) 33 | payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Level, entry.Message) 34 | 35 | bytesWritten, err := hook.UDPConn.Write([]byte(payload)) 36 | if err != nil { 37 | fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err) 38 | return err 39 | } 40 | 41 | return nil 42 | } 43 | 44 | // Levels returns the available logging levels. 45 | func (hook *PapertrailHook) Levels() []logrus.Level { 46 | return []logrus.Level{ 47 | logrus.PanicLevel, 48 | logrus.FatalLevel, 49 | logrus.ErrorLevel, 50 | logrus.WarnLevel, 51 | logrus.InfoLevel, 52 | logrus.DebugLevel, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go: -------------------------------------------------------------------------------- 1 | package logrus_papertrail 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/stvp/go-udp-testing" 9 | ) 10 | 11 | func TestWritingToUDP(t *testing.T) { 12 | port := 16661 13 | udp.SetAddr(fmt.Sprintf(":%d", port)) 14 | 15 | hook, err := NewPapertrailHook("localhost", port, "test") 16 | if err != nil { 17 | t.Errorf("Unable to connect to local UDP server.") 18 | } 19 | 20 | log := logrus.New() 21 | log.Hooks.Add(hook) 22 | 23 | udp.ShouldReceive(t, "foo", func() { 24 | log.Info("foo") 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/README.md: -------------------------------------------------------------------------------- 1 | # Sentry Hook for Logrus :walrus: 2 | 3 | [Sentry](https://getsentry.com) provides both self-hosted and hosted 4 | solutions for exception tracking. 5 | Both client and server are 6 | [open source](https://github.com/getsentry/sentry). 7 | 8 | ## Usage 9 | 10 | Every sentry application defined on the server gets a different 11 | [DSN](https://www.getsentry.com/docs/). In the example below replace 12 | `YOUR_DSN` with the one created for your application. 13 | 14 | ```go 15 | import ( 16 | "github.com/Sirupsen/logrus" 17 | "github.com/Sirupsen/logrus/hooks/sentry" 18 | ) 19 | 20 | func main() { 21 | log := logrus.New() 22 | hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{ 23 | logrus.PanicLevel, 24 | logrus.FatalLevel, 25 | logrus.ErrorLevel, 26 | }) 27 | 28 | if err == nil { 29 | log.Hooks.Add(hook) 30 | } 31 | } 32 | ``` 33 | 34 | ## Special fields 35 | 36 | Some logrus fields have a special meaning in this hook, 37 | these are server_name and logger. 38 | When logs are sent to sentry these fields are treated differently. 39 | - server_name (also known as hostname) is the name of the server which 40 | is logging the event (hostname.example.com) 41 | - logger is the part of the application which is logging the event. 42 | In go this usually means setting it to the name of the package. 43 | 44 | ## Timeout 45 | 46 | `Timeout` is the time the sentry hook will wait for a response 47 | from the sentry server. 48 | 49 | If this time elapses with no response from 50 | the server an error will be returned. 51 | 52 | If `Timeout` is set to 0 the SentryHook will not wait for a reply 53 | and will assume a correct delivery. 54 | 55 | The SentryHook has a default timeout of `100 milliseconds` when created 56 | with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field: 57 | 58 | ```go 59 | hook, _ := logrus_sentry.NewSentryHook(...) 60 | hook.Timeout = 20*time.Seconds 61 | ``` 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go: -------------------------------------------------------------------------------- 1 | package logrus_sentry 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/getsentry/raven-go" 9 | ) 10 | 11 | var ( 12 | severityMap = map[logrus.Level]raven.Severity{ 13 | logrus.DebugLevel: raven.DEBUG, 14 | logrus.InfoLevel: raven.INFO, 15 | logrus.WarnLevel: raven.WARNING, 16 | logrus.ErrorLevel: raven.ERROR, 17 | logrus.FatalLevel: raven.FATAL, 18 | logrus.PanicLevel: raven.FATAL, 19 | } 20 | ) 21 | 22 | func getAndDel(d logrus.Fields, key string) (string, bool) { 23 | var ( 24 | ok bool 25 | v interface{} 26 | val string 27 | ) 28 | if v, ok = d[key]; !ok { 29 | return "", false 30 | } 31 | 32 | if val, ok = v.(string); !ok { 33 | return "", false 34 | } 35 | delete(d, key) 36 | return val, true 37 | } 38 | 39 | // SentryHook delivers logs to a sentry server. 40 | type SentryHook struct { 41 | // Timeout sets the time to wait for a delivery error from the sentry server. 42 | // If this is set to zero the server will not wait for any response and will 43 | // consider the message correctly sent 44 | Timeout time.Duration 45 | 46 | client *raven.Client 47 | levels []logrus.Level 48 | } 49 | 50 | // NewSentryHook creates a hook to be added to an instance of logger 51 | // and initializes the raven client. 52 | // This method sets the timeout to 100 milliseconds. 53 | func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) { 54 | client, err := raven.NewClient(DSN, nil) 55 | if err != nil { 56 | return nil, err 57 | } 58 | return &SentryHook{100 * time.Millisecond, client, levels}, nil 59 | } 60 | 61 | // Called when an event should be sent to sentry 62 | // Special fields that sentry uses to give more information to the server 63 | // are extracted from entry.Data (if they are found) 64 | // These fields are: logger and server_name 65 | func (hook *SentryHook) Fire(entry *logrus.Entry) error { 66 | packet := &raven.Packet{ 67 | Message: entry.Message, 68 | Timestamp: raven.Timestamp(entry.Time), 69 | Level: severityMap[entry.Level], 70 | Platform: "go", 71 | } 72 | 73 | d := entry.Data 74 | 75 | if logger, ok := getAndDel(d, "logger"); ok { 76 | packet.Logger = logger 77 | } 78 | if serverName, ok := getAndDel(d, "server_name"); ok { 79 | packet.ServerName = serverName 80 | } 81 | packet.Extra = map[string]interface{}(d) 82 | 83 | _, errCh := hook.client.Capture(packet, nil) 84 | timeout := hook.Timeout 85 | if timeout != 0 { 86 | timeoutCh := time.After(timeout) 87 | select { 88 | case err := <-errCh: 89 | return err 90 | case <-timeoutCh: 91 | return fmt.Errorf("no response from sentry server in %s", timeout) 92 | } 93 | } 94 | return nil 95 | } 96 | 97 | // Levels returns the available logging levels. 98 | func (hook *SentryHook) Levels() []logrus.Level { 99 | return hook.levels 100 | } 101 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go: -------------------------------------------------------------------------------- 1 | package logrus_sentry 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "strings" 10 | "testing" 11 | 12 | "github.com/Sirupsen/logrus" 13 | "github.com/getsentry/raven-go" 14 | ) 15 | 16 | const ( 17 | message = "error message" 18 | server_name = "testserver.internal" 19 | logger_name = "test.logger" 20 | ) 21 | 22 | func getTestLogger() *logrus.Logger { 23 | l := logrus.New() 24 | l.Out = ioutil.Discard 25 | return l 26 | } 27 | 28 | func WithTestDSN(t *testing.T, tf func(string, <-chan *raven.Packet)) { 29 | pch := make(chan *raven.Packet, 1) 30 | s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { 31 | defer req.Body.Close() 32 | d := json.NewDecoder(req.Body) 33 | p := &raven.Packet{} 34 | err := d.Decode(p) 35 | if err != nil { 36 | t.Fatal(err.Error()) 37 | } 38 | 39 | pch <- p 40 | })) 41 | defer s.Close() 42 | 43 | fragments := strings.SplitN(s.URL, "://", 2) 44 | dsn := fmt.Sprintf( 45 | "%s://public:secret@%s/sentry/project-id", 46 | fragments[0], 47 | fragments[1], 48 | ) 49 | tf(dsn, pch) 50 | } 51 | 52 | func TestSpecialFields(t *testing.T) { 53 | WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { 54 | logger := getTestLogger() 55 | 56 | hook, err := NewSentryHook(dsn, []logrus.Level{ 57 | logrus.ErrorLevel, 58 | }) 59 | 60 | if err != nil { 61 | t.Fatal(err.Error()) 62 | } 63 | logger.Hooks.Add(hook) 64 | logger.WithFields(logrus.Fields{ 65 | "server_name": server_name, 66 | "logger": logger_name, 67 | }).Error(message) 68 | 69 | packet := <-pch 70 | if packet.Logger != logger_name { 71 | t.Errorf("logger should have been %s, was %s", logger_name, packet.Logger) 72 | } 73 | 74 | if packet.ServerName != server_name { 75 | t.Errorf("server_name should have been %s, was %s", server_name, packet.ServerName) 76 | } 77 | }) 78 | } 79 | 80 | func TestSentryHandler(t *testing.T) { 81 | WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { 82 | logger := getTestLogger() 83 | hook, err := NewSentryHook(dsn, []logrus.Level{ 84 | logrus.ErrorLevel, 85 | }) 86 | if err != nil { 87 | t.Fatal(err.Error()) 88 | } 89 | logger.Hooks.Add(hook) 90 | 91 | logger.Error(message) 92 | packet := <-pch 93 | if packet.Message != message { 94 | t.Errorf("message should have been %s, was %s", message, packet.Message) 95 | } 96 | }) 97 | } 98 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md: -------------------------------------------------------------------------------- 1 | # Syslog Hooks for Logrus :walrus: 2 | 3 | ## Usage 4 | 5 | ```go 6 | import ( 7 | "log/syslog" 8 | "github.com/Sirupsen/logrus" 9 | logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" 10 | ) 11 | 12 | func main() { 13 | log := logrus.New() 14 | hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 15 | 16 | if err == nil { 17 | log.Hooks.Add(hook) 18 | } 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go: -------------------------------------------------------------------------------- 1 | package logrus_syslog 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Sirupsen/logrus" 6 | "log/syslog" 7 | "os" 8 | ) 9 | 10 | // SyslogHook to send logs via syslog. 11 | type SyslogHook struct { 12 | Writer *syslog.Writer 13 | SyslogNetwork string 14 | SyslogRaddr string 15 | } 16 | 17 | // Creates a hook to be added to an instance of logger. This is called with 18 | // `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` 19 | // `if err == nil { log.Hooks.Add(hook) }` 20 | func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { 21 | w, err := syslog.Dial(network, raddr, priority, tag) 22 | return &SyslogHook{w, network, raddr}, err 23 | } 24 | 25 | func (hook *SyslogHook) Fire(entry *logrus.Entry) error { 26 | line, err := entry.String() 27 | if err != nil { 28 | fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) 29 | return err 30 | } 31 | 32 | switch entry.Level { 33 | case logrus.PanicLevel: 34 | return hook.Writer.Crit(line) 35 | case logrus.FatalLevel: 36 | return hook.Writer.Crit(line) 37 | case logrus.ErrorLevel: 38 | return hook.Writer.Err(line) 39 | case logrus.WarnLevel: 40 | return hook.Writer.Warning(line) 41 | case logrus.InfoLevel: 42 | return hook.Writer.Info(line) 43 | case logrus.DebugLevel: 44 | return hook.Writer.Debug(line) 45 | default: 46 | return nil 47 | } 48 | } 49 | 50 | func (hook *SyslogHook) Levels() []logrus.Level { 51 | return []logrus.Level{ 52 | logrus.PanicLevel, 53 | logrus.FatalLevel, 54 | logrus.ErrorLevel, 55 | logrus.WarnLevel, 56 | logrus.InfoLevel, 57 | logrus.DebugLevel, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go: -------------------------------------------------------------------------------- 1 | package logrus_syslog 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "log/syslog" 6 | "testing" 7 | ) 8 | 9 | func TestLocalhostAddAndPrint(t *testing.T) { 10 | log := logrus.New() 11 | hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 12 | 13 | if err != nil { 14 | t.Errorf("Unable to connect to local syslog.") 15 | } 16 | 17 | log.Hooks.Add(hook) 18 | 19 | for _, level := range hook.Levels() { 20 | if len(log.Hooks[level]) != 1 { 21 | t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level])) 22 | } 23 | } 24 | 25 | log.Info("Congratulations!") 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type JSONFormatter struct{} 10 | 11 | func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { 12 | data := make(Fields, len(entry.Data)+3) 13 | for k, v := range entry.Data { 14 | data[k] = v 15 | } 16 | prefixFieldClashes(data) 17 | data["time"] = entry.Time.Format(time.RFC3339) 18 | data["msg"] = entry.Message 19 | data["level"] = entry.Level.String() 20 | 21 | serialized, err := json.Marshal(data) 22 | if err != nil { 23 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 24 | } 25 | return append(serialized, '\n'), nil 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | ) 7 | 8 | // Fields type, used to pass to `WithFields`. 9 | type Fields map[string]interface{} 10 | 11 | // Level type 12 | type Level uint8 13 | 14 | // Convert the Level to a string. E.g. PanicLevel becomes "panic". 15 | func (level Level) String() string { 16 | switch level { 17 | case DebugLevel: 18 | return "debug" 19 | case InfoLevel: 20 | return "info" 21 | case WarnLevel: 22 | return "warning" 23 | case ErrorLevel: 24 | return "error" 25 | case FatalLevel: 26 | return "fatal" 27 | case PanicLevel: 28 | return "panic" 29 | } 30 | 31 | return "unknown" 32 | } 33 | 34 | // ParseLevel takes a string level and returns the Logrus log level constant. 35 | func ParseLevel(lvl string) (Level, error) { 36 | switch lvl { 37 | case "panic": 38 | return PanicLevel, nil 39 | case "fatal": 40 | return FatalLevel, nil 41 | case "error": 42 | return ErrorLevel, nil 43 | case "warn", "warning": 44 | return WarnLevel, nil 45 | case "info": 46 | return InfoLevel, nil 47 | case "debug": 48 | return DebugLevel, nil 49 | } 50 | 51 | var l Level 52 | return l, fmt.Errorf("not a valid logrus Level: %q", lvl) 53 | } 54 | 55 | // These are the different logging levels. You can set the logging level to log 56 | // on your instance of logger, obtained with `logrus.New()`. 57 | const ( 58 | // PanicLevel level, highest level of severity. Logs and then calls panic with the 59 | // message passed to Debug, Info, ... 60 | PanicLevel Level = iota 61 | // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the 62 | // logging level is set to Panic. 63 | FatalLevel 64 | // ErrorLevel level. Logs. Used for errors that should definitely be noted. 65 | // Commonly used for hooks to send errors to an error tracking service. 66 | ErrorLevel 67 | // WarnLevel level. Non-critical entries that deserve eyes. 68 | WarnLevel 69 | // InfoLevel level. General operational entries about what's going on inside the 70 | // application. 71 | InfoLevel 72 | // DebugLevel level. Usually only enabled when debugging. Very verbose logging. 73 | DebugLevel 74 | ) 75 | 76 | // Won't compile if StdLogger can't be realized by a log.Logger 77 | var _ StdLogger = &log.Logger{} 78 | 79 | // StdLogger is what your logrus-enabled library should take, that way 80 | // it'll accept a stdlib logger and a logrus logger. There's no standard 81 | // interface, this is the closest we get, unfortunately. 82 | type StdLogger interface { 83 | Print(...interface{}) 84 | Printf(string, ...interface{}) 85 | Println(...interface{}) 86 | 87 | Fatal(...interface{}) 88 | Fatalf(string, ...interface{}) 89 | Fatalln(...interface{}) 90 | 91 | Panic(...interface{}) 92 | Panicf(string, ...interface{}) 93 | Panicln(...interface{}) 94 | } 95 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package logrus 7 | 8 | import "syscall" 9 | 10 | const ioctlReadTermios = syscall.TIOCGETA 11 | 12 | type Termios syscall.Termios 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin. 3 | */ 4 | package logrus 5 | 6 | import ( 7 | "syscall" 8 | ) 9 | 10 | const ioctlReadTermios = syscall.TIOCGETA 11 | 12 | type Termios struct { 13 | Iflag uint32 14 | Oflag uint32 15 | Cflag uint32 16 | Lflag uint32 17 | Cc [20]uint8 18 | Ispeed uint32 19 | Ospeed uint32 20 | } 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package logrus 7 | 8 | import "syscall" 9 | 10 | const ioctlReadTermios = syscall.TCGETS 11 | 12 | type Termios syscall.Termios 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build linux,!appengine darwin freebsd 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | // IsTerminal returns true if the given file descriptor is a terminal. 16 | func IsTerminal() bool { 17 | fd := syscall.Stdout 18 | var termios Termios 19 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 20 | return err == 0 21 | } 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build windows 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 16 | 17 | var ( 18 | procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 19 | ) 20 | 21 | // IsTerminal returns true if the given file descriptor is a terminal. 22 | func IsTerminal() bool { 23 | fd := syscall.Stdout 24 | var st uint32 25 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 26 | return r != 0 && e == 0 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestQuoting(t *testing.T) { 11 | tf := &TextFormatter{DisableColors: true} 12 | 13 | checkQuoting := func(q bool, value interface{}) { 14 | b, _ := tf.Format(WithField("test", value)) 15 | idx := bytes.Index(b, ([]byte)("test=")) 16 | cont := bytes.Contains(b[idx+5:], []byte{'"'}) 17 | if cont != q { 18 | if q { 19 | t.Errorf("quoting expected for: %#v", value) 20 | } else { 21 | t.Errorf("quoting not expected for: %#v", value) 22 | } 23 | } 24 | } 25 | 26 | checkQuoting(false, "abcd") 27 | checkQuoting(false, "v1.0") 28 | checkQuoting(true, "/foobar") 29 | checkQuoting(true, "x y") 30 | checkQuoting(true, "x,y") 31 | checkQuoting(false, errors.New("invalid")) 32 | checkQuoting(true, errors.New("invalid argument")) 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/doc.go: -------------------------------------------------------------------------------- 1 | // Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers. 2 | // 3 | // If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit. 4 | // 5 | // For a full guide visit http://github.com/codegangsta/negroni 6 | // 7 | // package main 8 | // 9 | // import ( 10 | // "github.com/codegangsta/negroni" 11 | // "net/http" 12 | // "fmt" 13 | // ) 14 | // 15 | // func main() { 16 | // mux := http.NewServeMux() 17 | // mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 18 | // fmt.Fprintf(w, "Welcome to the home page!") 19 | // }) 20 | // 21 | // n := negroni.Classic() 22 | // n.UseHandler(mux) 23 | // n.Run(":3000") 24 | // } 25 | package negroni 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/logger.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | "time" 8 | ) 9 | 10 | // Logger is a middleware handler that logs the request as it goes in and the response as it goes out. 11 | type Logger struct { 12 | // Logger inherits from log.Logger used to log messages with the Logger middleware 13 | *log.Logger 14 | } 15 | 16 | // NewLogger returns a new Logger instance 17 | func NewLogger() *Logger { 18 | return &Logger{log.New(os.Stdout, "[negroni] ", 0)} 19 | } 20 | 21 | func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 22 | start := time.Now() 23 | l.Printf("Started %s %s", r.Method, r.URL.Path) 24 | 25 | next(rw, r) 26 | 27 | res := rw.(ResponseWriter) 28 | l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start)) 29 | } 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/logger_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | ) 10 | 11 | func Test_Logger(t *testing.T) { 12 | buff := bytes.NewBufferString("") 13 | recorder := httptest.NewRecorder() 14 | 15 | l := NewLogger() 16 | l.Logger = log.New(buff, "[negroni] ", 0) 17 | 18 | n := New() 19 | // replace log for testing 20 | n.Use(l) 21 | n.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 22 | rw.WriteHeader(http.StatusNotFound) 23 | })) 24 | 25 | req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil) 26 | if err != nil { 27 | t.Error(err) 28 | } 29 | 30 | n.ServeHTTP(recorder, req) 31 | expect(t, recorder.Code, http.StatusNotFound) 32 | refute(t, len(buff.String()), 0) 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/negroni_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | /* Test Helpers */ 11 | func expect(t *testing.T, a interface{}, b interface{}) { 12 | if a != b { 13 | t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 14 | } 15 | } 16 | 17 | func refute(t *testing.T, a interface{}, b interface{}) { 18 | if a == b { 19 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 20 | } 21 | } 22 | 23 | func TestNegroniRun(t *testing.T) { 24 | // just test that Run doesn't bomb 25 | go New().Run(":3000") 26 | } 27 | 28 | func TestNegroniServeHTTP(t *testing.T) { 29 | result := "" 30 | response := httptest.NewRecorder() 31 | 32 | n := New() 33 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 34 | result += "foo" 35 | next(rw, r) 36 | result += "ban" 37 | })) 38 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 39 | result += "bar" 40 | next(rw, r) 41 | result += "baz" 42 | })) 43 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 44 | result += "bat" 45 | rw.WriteHeader(http.StatusBadRequest) 46 | })) 47 | 48 | n.ServeHTTP(response, (*http.Request)(nil)) 49 | 50 | expect(t, result, "foobarbatbazban") 51 | expect(t, response.Code, http.StatusBadRequest) 52 | } 53 | 54 | // Ensures that a Negroni middleware chain 55 | // can correctly return all of its handlers. 56 | func TestHandlers(t *testing.T) { 57 | response := httptest.NewRecorder() 58 | n := New() 59 | handlers := n.Handlers() 60 | expect(t, 0, len(handlers)) 61 | 62 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 63 | rw.WriteHeader(http.StatusOK) 64 | })) 65 | 66 | // Expects the length of handlers to be exactly 1 67 | // after adding exactly one handler to the middleware chain 68 | handlers = n.Handlers() 69 | expect(t, 1, len(handlers)) 70 | 71 | // Ensures that the first handler that is in sequence behaves 72 | // exactly the same as the one that was registered earlier 73 | handlers[0].ServeHTTP(response, (*http.Request)(nil), nil) 74 | expect(t, response.Code, http.StatusOK) 75 | } 76 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/recovery.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | "runtime" 9 | ) 10 | 11 | // Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. 12 | type Recovery struct { 13 | Logger *log.Logger 14 | PrintStack bool 15 | StackAll bool 16 | StackSize int 17 | } 18 | 19 | // NewRecovery returns a new instance of Recovery 20 | func NewRecovery() *Recovery { 21 | return &Recovery{ 22 | Logger: log.New(os.Stdout, "[negroni] ", 0), 23 | PrintStack: true, 24 | StackAll: false, 25 | StackSize: 1024 * 8, 26 | } 27 | } 28 | 29 | func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 30 | defer func() { 31 | if err := recover(); err != nil { 32 | rw.WriteHeader(http.StatusInternalServerError) 33 | stack := make([]byte, rec.StackSize) 34 | stack = stack[:runtime.Stack(stack, rec.StackAll)] 35 | 36 | f := "PANIC: %s\n%s" 37 | rec.Logger.Printf(f, err, stack) 38 | 39 | if rec.PrintStack { 40 | fmt.Fprintf(rw, f, err, stack) 41 | } 42 | } 43 | }() 44 | 45 | next(rw, r) 46 | } 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/recovery_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | ) 10 | 11 | func TestRecovery(t *testing.T) { 12 | buff := bytes.NewBufferString("") 13 | recorder := httptest.NewRecorder() 14 | 15 | rec := NewRecovery() 16 | rec.Logger = log.New(buff, "[negroni] ", 0) 17 | 18 | n := New() 19 | // replace log for testing 20 | n.Use(rec) 21 | n.UseHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { 22 | panic("here is a panic!") 23 | })) 24 | n.ServeHTTP(recorder, (*http.Request)(nil)) 25 | expect(t, recorder.Code, http.StatusInternalServerError) 26 | refute(t, recorder.Body.Len(), 0) 27 | refute(t, len(buff.String()), 0) 28 | } 29 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/response_writer.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "net/http" 8 | ) 9 | 10 | // ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about 11 | // the response. It is recommended that middleware handlers use this construct to wrap a responsewriter 12 | // if the functionality calls for it. 13 | type ResponseWriter interface { 14 | http.ResponseWriter 15 | http.Flusher 16 | // Status returns the status code of the response or 0 if the response has not been written. 17 | Status() int 18 | // Written returns whether or not the ResponseWriter has been written. 19 | Written() bool 20 | // Size returns the size of the response body. 21 | Size() int 22 | // Before allows for a function to be called before the ResponseWriter has been written to. This is 23 | // useful for setting headers or any other operations that must happen before a response has been written. 24 | Before(func(ResponseWriter)) 25 | } 26 | 27 | type beforeFunc func(ResponseWriter) 28 | 29 | // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter 30 | func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { 31 | return &responseWriter{rw, 0, 0, nil} 32 | } 33 | 34 | type responseWriter struct { 35 | http.ResponseWriter 36 | status int 37 | size int 38 | beforeFuncs []beforeFunc 39 | } 40 | 41 | func (rw *responseWriter) WriteHeader(s int) { 42 | rw.status = s 43 | rw.callBefore() 44 | rw.ResponseWriter.WriteHeader(s) 45 | } 46 | 47 | func (rw *responseWriter) Write(b []byte) (int, error) { 48 | if !rw.Written() { 49 | // The status will be StatusOK if WriteHeader has not been called yet 50 | rw.WriteHeader(http.StatusOK) 51 | } 52 | size, err := rw.ResponseWriter.Write(b) 53 | rw.size += size 54 | return size, err 55 | } 56 | 57 | func (rw *responseWriter) Status() int { 58 | return rw.status 59 | } 60 | 61 | func (rw *responseWriter) Size() int { 62 | return rw.size 63 | } 64 | 65 | func (rw *responseWriter) Written() bool { 66 | return rw.status != 0 67 | } 68 | 69 | func (rw *responseWriter) Before(before func(ResponseWriter)) { 70 | rw.beforeFuncs = append(rw.beforeFuncs, before) 71 | } 72 | 73 | func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { 74 | hijacker, ok := rw.ResponseWriter.(http.Hijacker) 75 | if !ok { 76 | return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface") 77 | } 78 | return hijacker.Hijack() 79 | } 80 | 81 | func (rw *responseWriter) CloseNotify() <-chan bool { 82 | return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() 83 | } 84 | 85 | func (rw *responseWriter) callBefore() { 86 | for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { 87 | rw.beforeFuncs[i](rw) 88 | } 89 | } 90 | 91 | func (rw *responseWriter) Flush() { 92 | flusher, ok := rw.ResponseWriter.(http.Flusher) 93 | if ok { 94 | flusher.Flush() 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/static.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "net/http" 5 | "path" 6 | "strings" 7 | ) 8 | 9 | // Static is a middleware handler that serves static files in the given directory/filesystem. 10 | type Static struct { 11 | // Dir is the directory to serve static files from 12 | Dir http.FileSystem 13 | // Prefix is the optional prefix used to serve the static directory content 14 | Prefix string 15 | // IndexFile defines which file to serve as index if it exists. 16 | IndexFile string 17 | } 18 | 19 | // NewStatic returns a new instance of Static 20 | func NewStatic(directory http.FileSystem) *Static { 21 | return &Static{ 22 | Dir: directory, 23 | Prefix: "", 24 | IndexFile: "index.html", 25 | } 26 | } 27 | 28 | func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 29 | if r.Method != "GET" && r.Method != "HEAD" { 30 | next(rw, r) 31 | return 32 | } 33 | file := r.URL.Path 34 | // if we have a prefix, filter requests by stripping the prefix 35 | if s.Prefix != "" { 36 | if !strings.HasPrefix(file, s.Prefix) { 37 | next(rw, r) 38 | return 39 | } 40 | file = file[len(s.Prefix):] 41 | if file != "" && file[0] != '/' { 42 | next(rw, r) 43 | return 44 | } 45 | } 46 | f, err := s.Dir.Open(file) 47 | if err != nil { 48 | // discard the error? 49 | next(rw, r) 50 | return 51 | } 52 | defer f.Close() 53 | 54 | fi, err := f.Stat() 55 | if err != nil { 56 | next(rw, r) 57 | return 58 | } 59 | 60 | // try to serve index file 61 | if fi.IsDir() { 62 | // redirect if missing trailing slash 63 | if !strings.HasSuffix(r.URL.Path, "/") { 64 | http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) 65 | return 66 | } 67 | 68 | file = path.Join(file, s.IndexFile) 69 | f, err = s.Dir.Open(file) 70 | if err != nil { 71 | next(rw, r) 72 | return 73 | } 74 | defer f.Close() 75 | 76 | fi, err = f.Stat() 77 | if err != nil || fi.IsDir() { 78 | next(rw, r) 79 | return 80 | } 81 | } 82 | 83 | http.ServeContent(rw, r, file, fi.ModTime(), f) 84 | } 85 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/negroni/static_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | ) 9 | 10 | func TestStatic(t *testing.T) { 11 | response := httptest.NewRecorder() 12 | response.Body = new(bytes.Buffer) 13 | 14 | n := New() 15 | n.Use(NewStatic(http.Dir("."))) 16 | 17 | req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil) 18 | if err != nil { 19 | t.Error(err) 20 | } 21 | n.ServeHTTP(response, req) 22 | expect(t, response.Code, http.StatusOK) 23 | expect(t, response.Header().Get("Expires"), "") 24 | if response.Body.Len() == 0 { 25 | t.Errorf("Got empty body for GET request") 26 | } 27 | } 28 | 29 | func TestStaticHead(t *testing.T) { 30 | response := httptest.NewRecorder() 31 | response.Body = new(bytes.Buffer) 32 | 33 | n := New() 34 | n.Use(NewStatic(http.Dir("."))) 35 | n.UseHandler(http.NotFoundHandler()) 36 | 37 | req, err := http.NewRequest("HEAD", "http://localhost:3000/negroni.go", nil) 38 | if err != nil { 39 | t.Error(err) 40 | } 41 | 42 | n.ServeHTTP(response, req) 43 | expect(t, response.Code, http.StatusOK) 44 | if response.Body.Len() != 0 { 45 | t.Errorf("Got non-empty body for HEAD request") 46 | } 47 | } 48 | 49 | func TestStaticAsPost(t *testing.T) { 50 | response := httptest.NewRecorder() 51 | 52 | n := New() 53 | n.Use(NewStatic(http.Dir("."))) 54 | n.UseHandler(http.NotFoundHandler()) 55 | 56 | req, err := http.NewRequest("POST", "http://localhost:3000/negroni.go", nil) 57 | if err != nil { 58 | t.Error(err) 59 | } 60 | 61 | n.ServeHTTP(response, req) 62 | expect(t, response.Code, http.StatusNotFound) 63 | } 64 | 65 | func TestStaticBadDir(t *testing.T) { 66 | response := httptest.NewRecorder() 67 | 68 | n := Classic() 69 | n.UseHandler(http.NotFoundHandler()) 70 | 71 | req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil) 72 | if err != nil { 73 | t.Error(err) 74 | } 75 | 76 | n.ServeHTTP(response, req) 77 | refute(t, response.Code, http.StatusOK) 78 | } 79 | 80 | func TestStaticOptionsServeIndex(t *testing.T) { 81 | response := httptest.NewRecorder() 82 | 83 | n := New() 84 | s := NewStatic(http.Dir(".")) 85 | s.IndexFile = "negroni.go" 86 | n.Use(s) 87 | 88 | req, err := http.NewRequest("GET", "http://localhost:3000/", nil) 89 | if err != nil { 90 | t.Error(err) 91 | } 92 | 93 | n.ServeHTTP(response, req) 94 | expect(t, response.Code, http.StatusOK) 95 | } 96 | 97 | func TestStaticOptionsPrefix(t *testing.T) { 98 | response := httptest.NewRecorder() 99 | 100 | n := New() 101 | s := NewStatic(http.Dir(".")) 102 | s.Prefix = "/public" 103 | n.Use(s) 104 | 105 | // Check file content behaviour 106 | req, err := http.NewRequest("GET", "http://localhost:3000/public/negroni.go", nil) 107 | if err != nil { 108 | t.Error(err) 109 | } 110 | 111 | n.ServeHTTP(response, req) 112 | expect(t, response.Code, http.StatusOK) 113 | } 114 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/.gitignore: -------------------------------------------------------------------------------- 1 | _test 2 | _testmain.go 3 | _obj 4 | *~ 5 | *.6 6 | 6.out 7 | gorptest.bin 8 | tmp 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.1 4 | - tip 5 | 6 | services: 7 | - mysql 8 | - postgres 9 | - sqlite3 10 | 11 | before_script: 12 | - mysql -e "CREATE DATABASE gorptest;" 13 | - mysql -u root -e "GRANT ALL ON gorptest.* TO gorptest@localhost IDENTIFIED BY 'gorptest'" 14 | - psql -c "CREATE DATABASE gorptest;" -U postgres 15 | - psql -c "CREATE USER "gorptest" WITH SUPERUSER PASSWORD 'gorptest';" -U postgres 16 | - go get github.com/lib/pq 17 | - go get github.com/mattn/go-sqlite3 18 | - go get github.com/ziutek/mymysql/godrv 19 | - go get github.com/go-sql-driver/mysql 20 | 21 | script: ./test_all.sh 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 James Cooper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/Makefile: -------------------------------------------------------------------------------- 1 | include $(GOROOT)/src/Make.inc 2 | 3 | TARG = github.com/coopernurse/gorp 4 | GOFILES = gorp.go dialect.go 5 | 6 | include $(GOROOT)/src/Make.pkg -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/errors.go: -------------------------------------------------------------------------------- 1 | package gorp 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // A non-fatal error, when a select query returns columns that do not exist 8 | // as fields in the struct it is being mapped to 9 | type NoFieldInTypeError struct { 10 | TypeName string 11 | MissingColNames []string 12 | } 13 | 14 | func (err *NoFieldInTypeError) Error() string { 15 | return fmt.Sprintf("gorp: No fields %+v in type %s", err.MissingColNames, err.TypeName) 16 | } 17 | 18 | // returns true if the error is non-fatal (ie, we shouldn't immediately return) 19 | func NonFatalError(err error) bool { 20 | switch err.(type) { 21 | case *NoFieldInTypeError: 22 | return true 23 | default: 24 | return false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/test_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # on macs, you may need to: 4 | # export GOBUILDFLAG=-ldflags -linkmode=external 5 | 6 | set -e 7 | 8 | export GORP_TEST_DSN=gorptest/gorptest/gorptest 9 | export GORP_TEST_DIALECT=mysql 10 | go test $GOBUILDFLAG . 11 | 12 | export GORP_TEST_DSN=gorptest:gorptest@/gorptest 13 | export GORP_TEST_DIALECT=gomysql 14 | go test $GOBUILDFLAG . 15 | 16 | export GORP_TEST_DSN="user=gorptest password=gorptest dbname=gorptest sslmode=disable" 17 | export GORP_TEST_DIALECT=postgres 18 | go test $GOBUILDFLAG . 19 | 20 | export GORP_TEST_DSN=/tmp/gorptest.bin 21 | export GORP_TEST_DIALECT=sqlite 22 | go test $GOBUILDFLAG . 23 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/README.md: -------------------------------------------------------------------------------- 1 | context 2 | ======= 3 | [![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) 4 | 5 | gorilla/context is a general purpose registry for global request variables. 6 | 7 | Read the full documentation here: http://www.gorillatoolkit.org/pkg/context 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package context stores values shared during a request lifetime. 7 | 8 | For example, a router can set variables extracted from the URL and later 9 | application handlers can access those values, or it can be used to store 10 | sessions values to be saved at the end of a request. There are several 11 | others common uses. 12 | 13 | The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: 14 | 15 | http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 16 | 17 | Here's the basic usage: first define the keys that you will need. The key 18 | type is interface{} so a key can be of any type that supports equality. 19 | Here we define a key using a custom int type to avoid name collisions: 20 | 21 | package foo 22 | 23 | import ( 24 | "github.com/gorilla/context" 25 | ) 26 | 27 | type key int 28 | 29 | const MyKey key = 0 30 | 31 | Then set a variable. Variables are bound to an http.Request object, so you 32 | need a request instance to set a value: 33 | 34 | context.Set(r, MyKey, "bar") 35 | 36 | The application can later access the variable using the same key you provided: 37 | 38 | func MyHandler(w http.ResponseWriter, r *http.Request) { 39 | // val is "bar". 40 | val := context.Get(r, foo.MyKey) 41 | 42 | // returns ("bar", true) 43 | val, ok := context.GetOk(r, foo.MyKey) 44 | // ... 45 | } 46 | 47 | And that's all about the basic usage. We discuss some other ideas below. 48 | 49 | Any type can be stored in the context. To enforce a given type, make the key 50 | private and wrap Get() and Set() to accept and return values of a specific 51 | type: 52 | 53 | type key int 54 | 55 | const mykey key = 0 56 | 57 | // GetMyKey returns a value for this package from the request values. 58 | func GetMyKey(r *http.Request) SomeType { 59 | if rv := context.Get(r, mykey); rv != nil { 60 | return rv.(SomeType) 61 | } 62 | return nil 63 | } 64 | 65 | // SetMyKey sets a value for this package in the request values. 66 | func SetMyKey(r *http.Request, val SomeType) { 67 | context.Set(r, mykey, val) 68 | } 69 | 70 | Variables must be cleared at the end of a request, to remove all values 71 | that were stored. This can be done in an http.Handler, after a request was 72 | served. Just call Clear() passing the request: 73 | 74 | context.Clear(r) 75 | 76 | ...or use ClearHandler(), which conveniently wraps an http.Handler to clear 77 | variables at the end of a request lifetime. 78 | 79 | The Routers from the packages gorilla/mux and gorilla/pat call Clear() 80 | so if you are using either of them you don't need to clear the context manually. 81 | */ 82 | package context 83 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/handlers/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - 1.3 8 | - tip 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/handlers/README.md: -------------------------------------------------------------------------------- 1 | gorilla/handlers 2 | ================ 3 | [![Build Status](https://travis-ci.org/gorilla/handlers.png?branch=master)](https://travis-ci.org/gorilla/handlers) 4 | 5 | *Warning:* This package is a work in progress and the APIs are subject to change. 6 | Consider this a v0 project. 7 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/handlers/compress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package handlers 6 | 7 | import ( 8 | "compress/flate" 9 | "compress/gzip" 10 | "io" 11 | "net/http" 12 | "strings" 13 | ) 14 | 15 | type compressResponseWriter struct { 16 | io.Writer 17 | http.ResponseWriter 18 | } 19 | 20 | func (w *compressResponseWriter) Header() http.Header { 21 | return w.ResponseWriter.Header() 22 | } 23 | 24 | func (w *compressResponseWriter) Write(b []byte) (int, error) { 25 | h := w.ResponseWriter.Header() 26 | if h.Get("Content-Type") == "" { 27 | h.Set("Content-Type", http.DetectContentType(b)) 28 | } 29 | 30 | return w.Writer.Write(b) 31 | } 32 | 33 | func CompressHandler(h http.Handler) http.Handler { 34 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 35 | L: 36 | for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") { 37 | switch strings.TrimSpace(enc) { 38 | case "gzip": 39 | w.Header().Set("Content-Encoding", "gzip") 40 | w.Header().Add("Vary", "Accept-Encoding") 41 | 42 | gw := gzip.NewWriter(w) 43 | defer gw.Close() 44 | 45 | w = &compressResponseWriter{ 46 | Writer: gw, 47 | ResponseWriter: w, 48 | } 49 | break L 50 | case "deflate": 51 | w.Header().Set("Content-Encoding", "deflate") 52 | w.Header().Add("Vary", "Accept-Encoding") 53 | 54 | fw, _ := flate.NewWriter(w, flate.DefaultCompression) 55 | defer fw.Close() 56 | 57 | w = &compressResponseWriter{ 58 | Writer: fw, 59 | ResponseWriter: w, 60 | } 61 | break L 62 | } 63 | } 64 | 65 | h.ServeHTTP(w, r) 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/handlers/compress_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package handlers 6 | 7 | import ( 8 | "io" 9 | "net/http" 10 | "net/http/httptest" 11 | "testing" 12 | ) 13 | 14 | func compressedRequest(w *httptest.ResponseRecorder, compression string) { 15 | CompressHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 16 | for i := 0; i < 1024; i++ { 17 | io.WriteString(w, "Gorilla!\n") 18 | } 19 | })).ServeHTTP(w, &http.Request{ 20 | Method: "GET", 21 | Header: http.Header{ 22 | "Accept-Encoding": []string{compression}, 23 | }, 24 | }) 25 | 26 | } 27 | 28 | func TestCompressHandlerGzip(t *testing.T) { 29 | w := httptest.NewRecorder() 30 | compressedRequest(w, "gzip") 31 | if w.HeaderMap.Get("Content-Encoding") != "gzip" { 32 | t.Fatalf("wrong content encoding, got %d want %d", w.HeaderMap.Get("Content-Encoding"), "gzip") 33 | } 34 | if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { 35 | t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") 36 | } 37 | if w.Body.Len() != 72 { 38 | t.Fatalf("wrong len, got %d want %d", w.Body.Len(), 72) 39 | } 40 | } 41 | 42 | func TestCompressHandlerDeflate(t *testing.T) { 43 | w := httptest.NewRecorder() 44 | compressedRequest(w, "deflate") 45 | if w.HeaderMap.Get("Content-Encoding") != "deflate" { 46 | t.Fatalf("wrong content encoding, got %d want %d", w.HeaderMap.Get("Content-Encoding"), "deflate") 47 | } 48 | if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { 49 | t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") 50 | } 51 | if w.Body.Len() != 54 { 52 | t.Fatalf("wrong len, got %d want %d", w.Body.Len(), 54) 53 | } 54 | } 55 | 56 | func TestCompressHandlerGzipDeflate(t *testing.T) { 57 | w := httptest.NewRecorder() 58 | compressedRequest(w, "gzip, deflate ") 59 | if w.HeaderMap.Get("Content-Encoding") != "gzip" { 60 | t.Fatalf("wrong content encoding, got %s want %s", w.HeaderMap.Get("Content-Encoding"), "gzip") 61 | } 62 | if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { 63 | t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/mux/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/mux/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/mux/README.md: -------------------------------------------------------------------------------- 1 | mux 2 | === 3 | [![Build Status](https://travis-ci.org/gorilla/mux.png?branch=master)](https://travis-ci.org/gorilla/mux) 4 | 5 | gorilla/mux is a powerful URL router and dispatcher. 6 | 7 | Read the full documentation here: http://www.gorillatoolkit.org/pkg/mux 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/mux/bench_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mux 6 | 7 | import ( 8 | "net/http" 9 | "testing" 10 | ) 11 | 12 | func BenchmarkMux(b *testing.B) { 13 | router := new(Router) 14 | handler := func(w http.ResponseWriter, r *http.Request) {} 15 | router.HandleFunc("/v1/{v1}", handler) 16 | 17 | request, _ := http.NewRequest("GET", "/v1/anything", nil) 18 | for i := 0; i < b.N; i++ { 19 | router.ServeHTTP(nil, request) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/README.md: -------------------------------------------------------------------------------- 1 | securecookie 2 | ============ 3 | [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie) 4 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package gorilla/securecookie encodes and decodes authenticated and optionally 7 | encrypted cookie values. 8 | 9 | Secure cookies can't be forged, because their values are validated using HMAC. 10 | When encrypted, the content is also inaccessible to malicious eyes. 11 | 12 | To use it, first create a new SecureCookie instance: 13 | 14 | var hashKey = []byte("very-secret") 15 | var blockKey = []byte("a-lot-secret") 16 | var s = securecookie.New(hashKey, blockKey) 17 | 18 | The hashKey is required, used to authenticate the cookie value using HMAC. 19 | It is recommended to use a key with 32 or 64 bytes. 20 | 21 | The blockKey is optional, used to encrypt the cookie value -- set it to nil 22 | to not use encryption. If set, the length must correspond to the block size 23 | of the encryption algorithm. For AES, used by default, valid lengths are 24 | 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. 25 | 26 | Strong keys can be created using the convenience function GenerateRandomKey(). 27 | 28 | Once a SecureCookie instance is set, use it to encode a cookie value: 29 | 30 | func SetCookieHandler(w http.ResponseWriter, r *http.Request) { 31 | value := map[string]string{ 32 | "foo": "bar", 33 | } 34 | if encoded, err := s.Encode("cookie-name", value); err == nil { 35 | cookie := &http.Cookie{ 36 | Name: "cookie-name", 37 | Value: encoded, 38 | Path: "/", 39 | } 40 | http.SetCookie(w, cookie) 41 | } 42 | } 43 | 44 | Later, use the same SecureCookie instance to decode and validate a cookie 45 | value: 46 | 47 | func ReadCookieHandler(w http.ResponseWriter, r *http.Request) { 48 | if cookie, err := r.Cookie("cookie-name"); err == nil { 49 | value := make(map[string]string) 50 | if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil { 51 | fmt.Fprintf(w, "The value of foo is %q", value["foo"]) 52 | } 53 | } 54 | } 55 | 56 | We stored a map[string]string, but secure cookies can hold any value that 57 | can be encoded using encoding/gob. To store custom types, they must be 58 | registered first using gob.Register(). For basic types this is not needed; 59 | it works out of the box. 60 | */ 61 | package securecookie 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/README.md: -------------------------------------------------------------------------------- 1 | sessions 2 | ======== 3 | 4 | Store Implementations 5 | --------------------- 6 | Other implementations of the sessions.Store interface: 7 | 8 | * [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt 9 | * [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase 10 | * [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache 11 | * [github.com/hnakamur/gaesessions](https://github.com/hnakamur/gaesessions) - Memcache on GAE 12 | * [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB 13 | * [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL 14 | * [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL 15 | * [github.com/boj/redistore](https://github.com/boj/redistore) - Redis 16 | * [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak 17 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/store_test.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "encoding/base64" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | ) 9 | 10 | // Test for GH-8 for CookieStore 11 | func TestGH8CookieStore(t *testing.T) { 12 | originalPath := "/" 13 | store := NewCookieStore() 14 | store.Options.Path = originalPath 15 | req, err := http.NewRequest("GET", "http://www.example.com", nil) 16 | if err != nil { 17 | t.Fatal("failed to create request", err) 18 | } 19 | 20 | session, err := store.New(req, "hello") 21 | if err != nil { 22 | t.Fatal("failed to create session", err) 23 | } 24 | 25 | store.Options.Path = "/foo" 26 | if session.Options.Path != originalPath { 27 | t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath) 28 | } 29 | } 30 | 31 | // Test for GH-8 for FilesystemStore 32 | func TestGH8FilesystemStore(t *testing.T) { 33 | originalPath := "/" 34 | store := NewFilesystemStore("") 35 | store.Options.Path = originalPath 36 | req, err := http.NewRequest("GET", "http://www.example.com", nil) 37 | if err != nil { 38 | t.Fatal("failed to create request", err) 39 | } 40 | 41 | session, err := store.New(req, "hello") 42 | if err != nil { 43 | t.Fatal("failed to create session", err) 44 | } 45 | 46 | store.Options.Path = "/foo" 47 | if session.Options.Path != originalPath { 48 | t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath) 49 | } 50 | } 51 | 52 | // Test for GH-2. 53 | func TestGH2MaxLength(t *testing.T) { 54 | store := NewFilesystemStore("", []byte("some key")) 55 | req, err := http.NewRequest("GET", "http://www.example.com", nil) 56 | if err != nil { 57 | t.Fatal("failed to create request", err) 58 | } 59 | w := httptest.NewRecorder() 60 | 61 | session, err := store.New(req, "my session") 62 | session.Values["big"] = make([]byte, base64.StdEncoding.DecodedLen(4096*2)) 63 | err = session.Save(req, w) 64 | if err == nil { 65 | t.Fatal("expected an error, got nil") 66 | } 67 | 68 | store.MaxLength(4096 * 3) // A bit more than the value size to account for encoding overhead. 69 | err = session.Save(req, w) 70 | if err != nil { 71 | t.Fatal("failed to Save:", err) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/guregu/null/.gitignore: -------------------------------------------------------------------------------- 1 | coverage.out -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/guregu/null/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Greg Roseberry 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/guregu/null/README.md: -------------------------------------------------------------------------------- 1 | ## null [![GoDoc](https://godoc.org/github.com/guregu/null?status.svg)](https://godoc.org/github.com/guregu/null) [![Coverage](http://gocover.io/_badge/github.com/guregu/null)](http://gocover.io/github.com/guregu/null) 2 | `import "gopkg.in/guregu/null.v2"` 3 | 4 | null is a library with reasonable options for dealing with nullable SQL and JSON values 5 | 6 | There are two packages: `null` and its subpackage `zero`. 7 | 8 | Types in `null` will only be considered null on null input, and will JSON encode to `null`. If you need zero and null be considered separate values, use these. 9 | 10 | Types in `zero` are treated like zero values in Go: blank string input will produce a null `zero.String`, and null Strings will JSON encode to `""`. If you need zero and null treated the same, use these. 11 | 12 | All types implement `sql.Scanner` and `driver.Valuer`, so you can use this library in place of `sql.NullXXX`. All types also implement: `encoding.TextMarshaler`, `encoding.TextUnmarshaler`, `json.Marshaler`, and `json.Unmarshaler`. 13 | 14 | #### zero.String 15 | A nullable string. 16 | 17 | Will marshal to a blank string if null. Blank string input produces a null String. In other words, null values and empty values are considered equivalent. Can unmarshal from `sql.NullString` JSON input. 18 | 19 | #### zero.Int 20 | A nullable int64. 21 | 22 | Will marshal to 0 if null. Blank string or 0 input produces a null Int. In other words, null values and empty values are considered equivalent. Can unmarshal from `sql.NullInt64` JSON input. 23 | 24 | #### zero.Float 25 | A nullable float64. 26 | 27 | Will marshal to 0 if null. Blank string or 0 input produces a null Float. In other words, null values and empty values are considered equivalent. Can unmarshal from `sql.NullFloat64` JSON input. 28 | 29 | #### zero.Bool 30 | A nullable bool. 31 | 32 | Will marshal to false if null. Blank string or false input produces a null Float. In other words, null values and empty values are considered equivalent. Can unmarshal from `sql.NullBool` JSON input. 33 | 34 | #### null.String 35 | An even nuller nullable string. 36 | 37 | Unlike `zero.String`, `null.String` will marshal to null if null. Zero (blank) input will not produce a null String. Can unmarshal from `sql.NullString` JSON input. 38 | 39 | #### null.Int 40 | An even nuller nullable int64. 41 | 42 | Unlike `zero.Int`, `null.Int` will marshal to null if null. Zero input will not produce a null Int. Can unmarshal from `sql.NullInt64` JSON input. 43 | 44 | #### null.Float 45 | An even nuller nullable float64. 46 | 47 | Unlike `zero.Float`, `null.Float` will marshal to null if null. Zero input will not produce a null Float. Can unmarshal from `sql.NullFloat64` JSON input. 48 | 49 | #### null.Bool 50 | An even nuller nullable float64. 51 | 52 | Unlike `zero.Bool`, `null.Bool` will marshal to null if null. False input will not produce a null Bool. Can unmarshal from `sql.NullBool` JSON input. 53 | 54 | ### Bugs 55 | `json`'s `",omitempty"` struct tag does not work correctly right now. It will never omit a null or empty String. This should be [fixed in Go 1.4](https://code.google.com/p/go/issues/detail?id=4357). 56 | 57 | ### License 58 | BSD -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/guregu/null/string.go: -------------------------------------------------------------------------------- 1 | // Package null contains types that consider zero input and null input as separate values. 2 | // Types in this package will always encode to their null value if null. 3 | // Use the zero subpackage if you want empty and null to be treated the same. 4 | package null 5 | 6 | import ( 7 | "database/sql" 8 | "encoding/json" 9 | "fmt" 10 | "reflect" 11 | ) 12 | 13 | // String is an even nuller nullable string. 14 | type String struct { 15 | sql.NullString 16 | } 17 | 18 | // StringFrom creates a new String that will never be blank. 19 | func StringFrom(s string) String { 20 | return NewString(s, true) 21 | } 22 | 23 | // StringFromPtr creates a new String that be null if s is nil. 24 | func StringFromPtr(s *string) String { 25 | if s == nil { 26 | return NewString("", false) 27 | } 28 | return NewString(*s, true) 29 | } 30 | 31 | // NewString creates a new String 32 | func NewString(s string, valid bool) String { 33 | return String{ 34 | NullString: sql.NullString{ 35 | String: s, 36 | Valid: valid, 37 | }, 38 | } 39 | } 40 | 41 | // UnmarshalJSON implements json.Unmarshaler. 42 | // It supports string and null input. Blank string input produces a null String. 43 | // It also supports unmarshalling a sql.NullString. 44 | func (s *String) UnmarshalJSON(data []byte) error { 45 | var err error 46 | var v interface{} 47 | json.Unmarshal(data, &v) 48 | switch x := v.(type) { 49 | case string: 50 | s.String = x 51 | case map[string]interface{}: 52 | err = json.Unmarshal(data, &s.NullString) 53 | case nil: 54 | s.Valid = false 55 | return nil 56 | default: 57 | err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.String", reflect.TypeOf(v).Name()) 58 | } 59 | s.Valid = (err == nil) && (s.String != "") 60 | return err 61 | } 62 | 63 | // MarshalJSON implements json.Marshaler. 64 | // It will encode null if this String is null. 65 | func (s String) MarshalJSON() ([]byte, error) { 66 | if !s.Valid { 67 | return []byte("null"), nil 68 | } 69 | return json.Marshal(s.String) 70 | } 71 | 72 | // UnmarshalText implements encoding.TextUnmarshaler. 73 | // It will unmarshal to a null String if the input is a blank string. 74 | func (s *String) UnmarshalText(text []byte) error { 75 | s.String = string(text) 76 | s.Valid = s.String != "" 77 | return nil 78 | } 79 | 80 | // SetValid changes this String's value and also sets it to be non-null. 81 | func (s *String) SetValid(v string) { 82 | s.String = v 83 | s.Valid = true 84 | } 85 | 86 | // Ptr returns a pointer to this String's value, or a nil pointer if this String is null. 87 | func (s String) Ptr() *string { 88 | if !s.Valid { 89 | return nil 90 | } 91 | return &s.String 92 | } 93 | 94 | // IsZero returns true for null or empty strings, for future omitempty support. (Go 1.4?) 95 | // Will return false s if blank but non-null. 96 | func (s String) IsZero() bool { 97 | return !s.Valid 98 | } 99 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/guregu/null/zero/bool.go: -------------------------------------------------------------------------------- 1 | package zero 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "reflect" 9 | ) 10 | 11 | // Bool is a nullable bool. 12 | type Bool struct { 13 | sql.NullBool 14 | } 15 | 16 | // NewBool creates a new Bool 17 | func NewBool(b bool, valid bool) Bool { 18 | return Bool{ 19 | NullBool: sql.NullBool{ 20 | Bool: b, 21 | Valid: valid, 22 | }, 23 | } 24 | } 25 | 26 | // BoolFrom creates a new Bool that will be null if false. 27 | func BoolFrom(b bool) Bool { 28 | return NewBool(b, b) 29 | } 30 | 31 | // BoolFromPtr creates a new Bool that be null if b is nil. 32 | func BoolFromPtr(b *bool) Bool { 33 | if b == nil { 34 | return NewBool(false, false) 35 | } 36 | return NewBool(*b, true) 37 | } 38 | 39 | // UnmarshalJSON implements json.Unmarshaler. 40 | // "false" will be considered a null Bool. 41 | // It also supports unmarshalling a sql.NullBool. 42 | func (b *Bool) UnmarshalJSON(data []byte) error { 43 | var err error 44 | var v interface{} 45 | json.Unmarshal(data, &v) 46 | switch x := v.(type) { 47 | case bool: 48 | b.Bool = x 49 | case map[string]interface{}: 50 | err = json.Unmarshal(data, &b.NullBool) 51 | case nil: 52 | b.Valid = false 53 | return nil 54 | default: 55 | err = fmt.Errorf("json: cannot unmarshal %v into Go value of type zero.Bool", reflect.TypeOf(v).Name()) 56 | } 57 | b.Valid = (err == nil) && b.Bool 58 | return err 59 | } 60 | 61 | // UnmarshalText implements encoding.TextUnmarshaler. 62 | // It will unmarshal to a null Bool if the input is a false or not a bool. 63 | // It will return an error if the input is not a float, blank, or "null". 64 | func (b *Bool) UnmarshalText(text []byte) error { 65 | str := string(text) 66 | switch str { 67 | case "", "null": 68 | b.Valid = false 69 | return nil 70 | case "true": 71 | b.Bool = true 72 | case "false": 73 | b.Bool = false 74 | default: 75 | b.Valid = false 76 | return errors.New("invalid input:" + str) 77 | } 78 | b.Valid = b.Bool 79 | return nil 80 | } 81 | 82 | // MarshalJSON implements json.Marshaler. 83 | // It will encode null if this Bool is null. 84 | func (b Bool) MarshalJSON() ([]byte, error) { 85 | if !b.Valid || !b.Bool { 86 | return []byte("false"), nil 87 | } 88 | return []byte("true"), nil 89 | } 90 | 91 | // MarshalText implements encoding.TextMarshaler. 92 | // It will encode a zero if this Bool is null. 93 | func (b Bool) MarshalText() ([]byte, error) { 94 | if !b.Valid || !b.Bool { 95 | return []byte("false"), nil 96 | } 97 | return []byte("true"), nil 98 | } 99 | 100 | // SetValid changes this Bool's value and also sets it to be non-null. 101 | func (b *Bool) SetValid(v bool) { 102 | b.Bool = v 103 | b.Valid = true 104 | } 105 | 106 | // Ptr returns a poBooler to this Bool's value, or a nil poBooler if this Bool is null. 107 | func (b Bool) Ptr() *bool { 108 | if !b.Valid { 109 | return nil 110 | } 111 | return &b.Bool 112 | } 113 | 114 | // IsZero returns true for null or zero Bools, for future omitempty support (Go 1.4?) 115 | func (b Bool) IsZero() bool { 116 | return !b.Valid || !b.Bool 117 | } 118 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/guregu/null/zero/string.go: -------------------------------------------------------------------------------- 1 | // Package zero provides a convenient way of handling null values. 2 | // Types in this package consider empty or zero input the same as null input. 3 | // Types in this package will encode to their zero value, even if null. 4 | // Use the null parent package if you don't want this. 5 | package zero 6 | 7 | import ( 8 | "database/sql" 9 | "encoding/json" 10 | "fmt" 11 | "reflect" 12 | ) 13 | 14 | // String is a nullable string. 15 | type String struct { 16 | sql.NullString 17 | } 18 | 19 | // NewString creates a new String 20 | func NewString(s string, valid bool) String { 21 | return String{ 22 | NullString: sql.NullString{ 23 | String: s, 24 | Valid: valid, 25 | }, 26 | } 27 | } 28 | 29 | // StringFrom creates a new String that will be null if s is blank. 30 | func StringFrom(s string) String { 31 | return NewString(s, s != "") 32 | } 33 | 34 | // StringFromPtr creates a new String that be null if s is nil or blank. 35 | // It will make s point to the String's value. 36 | func StringFromPtr(s *string) String { 37 | if s == nil { 38 | return NewString("", false) 39 | } 40 | return NewString(*s, *s != "") 41 | } 42 | 43 | // UnmarshalJSON implements json.Unmarshaler. 44 | // It supports string and null input. Blank string input produces a null String. 45 | // It also supports unmarshalling a sql.NullString. 46 | func (s *String) UnmarshalJSON(data []byte) error { 47 | var err error 48 | var v interface{} 49 | json.Unmarshal(data, &v) 50 | switch x := v.(type) { 51 | case string: 52 | s.String = x 53 | case map[string]interface{}: 54 | err = json.Unmarshal(data, &s.NullString) 55 | case nil: 56 | s.Valid = false 57 | return nil 58 | default: 59 | err = fmt.Errorf("json: cannot unmarshal %v into Go value of type zero.String", reflect.TypeOf(v).Name()) 60 | } 61 | s.Valid = (err == nil) && (s.String != "") 62 | return err 63 | } 64 | 65 | // MarshalText implements encoding.TextMarshaler. 66 | // It will encode a blank string when this String is null. 67 | func (s String) MarshalText() ([]byte, error) { 68 | if !s.Valid { 69 | return []byte{}, nil 70 | } 71 | return []byte(s.String), nil 72 | } 73 | 74 | // UnmarshalText implements encoding.TextUnmarshaler. 75 | // It will unmarshal to a null String if the input is a blank string. 76 | func (s *String) UnmarshalText(text []byte) error { 77 | s.String = string(text) 78 | s.Valid = s.String != "" 79 | return nil 80 | } 81 | 82 | // SetValid changes this String's value and also sets it to be non-null. 83 | func (s *String) SetValid(v string) { 84 | s.String = v 85 | s.Valid = true 86 | } 87 | 88 | // Ptr returns a pointer to this String's value, or a nil pointer if this String is null. 89 | func (s String) Ptr() *string { 90 | if !s.Valid { 91 | return nil 92 | } 93 | return &s.String 94 | } 95 | 96 | // IsZero returns true for null or empty strings, for future omitempty support. (Go 1.4?) 97 | func (s String) IsZero() bool { 98 | return !s.Valid || s.String == "" 99 | } 100 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | 24 | # Vim stuff 25 | *.s[a-w][a-z] 26 | *.un~ 27 | Session.vim 28 | .netrwhist 29 | *~ 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | install: 4 | - go get . 5 | 6 | script: 7 | - go test -v . 8 | 9 | go: 10 | - 1.1 11 | - 1.2 12 | - 1.3 13 | - tip 14 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Justinas Stankevicius 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/README.md: -------------------------------------------------------------------------------- 1 | # nosurf 2 | 3 | [![Build Status](https://travis-ci.org/justinas/nosurf.svg?branch=master)](https://travis-ci.org/justinas/nosurf) 4 | 5 | `nosurf` is an HTTP package for Go 6 | that helps you prevent Cross-Site Request Forgery attacks. 7 | It acts like a middleware and therefore 8 | is compatible with basically any Go HTTP application. 9 | 10 | ### Why? 11 | Even though CSRF is a prominent vulnerability, 12 | Go's web-related package infrastructure mostly consists of 13 | micro-frameworks that neither do implement CSRF checks, 14 | nor should they. 15 | 16 | `nosurf` solves this problem by providing a `CSRFHandler` 17 | that wraps your `http.Handler` and checks for CSRF attacks 18 | on every non-safe (non-GET/HEAD/OPTIONS/TRACE) method. 19 | 20 | `nosurf` requires Go 1.1 or later. 21 | 22 | ### Features 23 | 24 | * Supports any `http.Handler` (frameworks, your own handlers, etc.) 25 | and acts like one itself. 26 | * Allows exempting specific endpoints from CSRF checks by 27 | an exact URL, a glob, or a regular expression. 28 | * Allows specifying your own failure handler. 29 | Want to present the hacker with an ASCII middle finger 30 | instead of the plain old `HTTP 400`? No problem. 31 | * Uses masked tokens to mitigate the BREACH attack 32 | * Has no dependencies outside the Go standard library. 33 | 34 | ### Example 35 | ```go 36 | package main 37 | 38 | import ( 39 | "fmt" 40 | "github.com/justinas/nosurf" 41 | "html/template" 42 | "net/http" 43 | ) 44 | 45 | var templateString string = ` 46 | 47 | 48 | 49 | {{ if .name }} 50 |

Your name: {{ .name }}

51 | {{ end }} 52 |
53 | 54 | 55 | 57 | 58 | 59 |
60 | 61 | 62 | ` 63 | var templ = template.Must(template.New("t1").Parse(templateString)) 64 | 65 | func myFunc(w http.ResponseWriter, r *http.Request) { 66 | context := make(map[string]string) 67 | context["token"] = nosurf.Token(r) 68 | if r.Method == "POST" { 69 | context["name"] = r.FormValue("name") 70 | } 71 | 72 | templ.Execute(w, context) 73 | } 74 | 75 | func main() { 76 | myHandler := http.HandlerFunc(myFunc) 77 | fmt.Println("Listening on http://127.0.0.1:8000/") 78 | http.ListenAndServe(":8000", nosurf.New(myHandler)) 79 | } 80 | ``` 81 | 82 | More examples can be found in the 83 | [examples/](https://github.com/justinas/nosurf/tree/master/examples/) directory. 84 | Feel free to add one for your favorite framework 85 | or an unusual setup of the default HTTP tools. 86 | 87 | ### API Docs 88 | 89 | ... are at [GoDoc](http://godoc.org/github.com/justinas/nosurf). No big surprise, right? 90 | 91 | ### Contributing 92 | 93 | 0. Find an issue that bugs you / open a new one. 94 | 1. Discuss. 95 | 2. Branch off the `develop` branch, commit, test. 96 | 3. Make a pull request / attach the commits to the issue. 97 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/context.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "net/http" 5 | "sync" 6 | ) 7 | 8 | // This file implements a context similar to one found 9 | // in gorilla/context, but tailored specifically for our use case 10 | // and not using gorilla's package just because. 11 | 12 | type csrfContext struct { 13 | // The masked, base64 encoded token 14 | // That's suitable for use in form fields, etc. 15 | token string 16 | // reason for the failure of CSRF check 17 | reason error 18 | } 19 | 20 | var ( 21 | contextMap = make(map[*http.Request]*csrfContext) 22 | cmMutex = new(sync.RWMutex) 23 | ) 24 | 25 | // Token() takes an HTTP request and returns 26 | // the CSRF token for that request 27 | // or an empty string if the token does not exist. 28 | // 29 | // Note that the token won't be available after 30 | // CSRFHandler finishes 31 | // (that is, in another handler that wraps it, 32 | // or after the request has been served) 33 | func Token(req *http.Request) string { 34 | cmMutex.RLock() 35 | defer cmMutex.RUnlock() 36 | 37 | ctx, ok := contextMap[req] 38 | 39 | if !ok { 40 | return "" 41 | } 42 | 43 | return ctx.token 44 | } 45 | 46 | // Reason() takes an HTTP request and returns 47 | // the reason of failure of the CSRF check for that request 48 | // 49 | // Note that the same availability restrictions apply for Reason() as for Token(). 50 | func Reason(req *http.Request) error { 51 | cmMutex.RLock() 52 | defer cmMutex.RUnlock() 53 | 54 | ctx, ok := contextMap[req] 55 | 56 | if !ok { 57 | return nil 58 | } 59 | 60 | return ctx.reason 61 | } 62 | 63 | // Takes a raw token, masks it with a per-request key, 64 | // encodes in base64 and makes it available to the wrapped handler 65 | func ctxSetToken(req *http.Request, token []byte) { 66 | cmMutex.Lock() 67 | defer cmMutex.Unlock() 68 | 69 | ctx, ok := contextMap[req] 70 | if !ok { 71 | ctx = new(csrfContext) 72 | contextMap[req] = ctx 73 | } 74 | 75 | ctx.token = b64encode(maskToken(token)) 76 | } 77 | 78 | func ctxSetReason(req *http.Request, reason error) { 79 | cmMutex.Lock() 80 | defer cmMutex.Unlock() 81 | 82 | ctx, ok := contextMap[req] 83 | if !ok { 84 | panic("Reason should never be set when there's no token" + 85 | " (context) yet.") 86 | } 87 | 88 | ctx.reason = reason 89 | } 90 | 91 | func ctxClear(req *http.Request) { 92 | cmMutex.Lock() 93 | defer cmMutex.Unlock() 94 | 95 | delete(contextMap, req) 96 | } 97 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/context_test.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "testing" 7 | ) 8 | 9 | func TestSetsReasonCorrectly(t *testing.T) { 10 | req := dummyGet() 11 | 12 | // set token first, as it's required for ctxSetReason 13 | ctxSetToken(req, []byte("abcdef")) 14 | 15 | err := errors.New("universe imploded") 16 | ctxSetReason(req, err) 17 | 18 | got := contextMap[req].reason 19 | 20 | if got != err { 21 | t.Errorf("Reason set incorrectly: expected %v, got %v", err, got) 22 | } 23 | } 24 | 25 | func TestSettingReasonFailsWithoutContext(t *testing.T) { 26 | req := dummyGet() 27 | err := errors.New("universe imploded") 28 | 29 | defer func() { 30 | r := recover() 31 | if r == nil { 32 | t.Error("ctxSetReason() didn't panic on no context") 33 | } 34 | }() 35 | 36 | ctxSetReason(req, err) 37 | } 38 | 39 | func TestSetsTokenCorrectly(t *testing.T) { 40 | req := dummyGet() 41 | token := []byte("12345678901234567890123456789012") 42 | ctxSetToken(req, token) 43 | 44 | got := contextMap[req].token 45 | 46 | if !bytes.Equal(token, unmaskToken(b64decode(got))) { 47 | t.Errorf("Token set incorrectly: expected %v, got %v", token, got) 48 | } 49 | } 50 | 51 | func TestGetsTokenCorrectly(t *testing.T) { 52 | req := dummyGet() 53 | token := Token(req) 54 | 55 | if len(token) != 0 { 56 | t.Errorf("Token hasn't been set yet, but it's not an empty slice, it's %v", token) 57 | } 58 | 59 | intended := []byte("12345678901234567890123456789012") 60 | ctxSetToken(req, intended) 61 | 62 | token = Token(req) 63 | decToken := unmaskToken(b64decode(token)) 64 | if !bytes.Equal(intended, decToken) { 65 | t.Errorf("Token has been set to %v, but it's %v", intended, token) 66 | } 67 | } 68 | 69 | func TestGetsReasonCorrectly(t *testing.T) { 70 | req := dummyGet() 71 | 72 | reason := Reason(req) 73 | if reason != nil { 74 | t.Errorf("Reason hasn't been set yet, but it's not nil, it's %v", reason) 75 | } 76 | 77 | // again, needed for ctxSetReason() to work 78 | ctxSetToken(req, []byte("dummy")) 79 | 80 | intended := errors.New("universe imploded") 81 | ctxSetReason(req, intended) 82 | 83 | reason = Reason(req) 84 | if reason != intended { 85 | t.Errorf("Reason has been set to %v, but it's %v", intended, reason) 86 | } 87 | } 88 | 89 | func TestClearsContextEntry(t *testing.T) { 90 | req := dummyGet() 91 | 92 | ctxSetToken(req, []byte("dummy")) 93 | ctxSetReason(req, errors.New("some error")) 94 | 95 | ctxClear(req) 96 | 97 | entry, found := contextMap[req] 98 | 99 | if found { 100 | t.Errorf("Context entry %v found for the request %v, even though"+ 101 | " it should have been cleared.", entry, req) 102 | } 103 | } 104 | 105 | func TestClearsContextEntryEvenIfNotSet(t *testing.T) { 106 | r := dummyGet() 107 | defer func() { 108 | if r := recover(); r != nil { 109 | t.Errorf("ctxClear(r) panicked with %v", r) 110 | } 111 | }() 112 | ctxClear(r) 113 | } 114 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/crypto.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "crypto/rand" 5 | "io" 6 | ) 7 | 8 | // Masks/unmasks the given data *in place* 9 | // with the given key 10 | // Slices must be of the same length, or oneTimePad will panic 11 | func oneTimePad(data, key []byte) { 12 | n := len(data) 13 | if n != len(key) { 14 | panic("Lengths of slices are not equal") 15 | } 16 | 17 | for i := 0; i < n; i++ { 18 | data[i] ^= key[i] 19 | } 20 | } 21 | 22 | func maskToken(data []byte) []byte { 23 | if len(data) != tokenLength { 24 | return nil 25 | } 26 | 27 | // tokenLength*2 == len(enckey + token) 28 | result := make([]byte, 2*tokenLength) 29 | // the first half of the result is the OTP 30 | // the second half is the masked token itself 31 | key := result[:tokenLength] 32 | token := result[tokenLength:] 33 | copy(token, data) 34 | 35 | // generate the random token 36 | io.ReadFull(rand.Reader, key) 37 | 38 | oneTimePad(token, key) 39 | return result 40 | } 41 | 42 | func unmaskToken(data []byte) []byte { 43 | if len(data) != tokenLength*2 { 44 | return nil 45 | } 46 | 47 | key := data[:tokenLength] 48 | token := data[tokenLength:] 49 | oneTimePad(token, key) 50 | 51 | return token 52 | } 53 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/crypto_test.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestOtpPanicsOnLengthMismatch(t *testing.T) { 9 | data := make([]byte, 1) 10 | key := make([]byte, 2) 11 | 12 | defer func() { 13 | if r := recover(); r == nil { 14 | t.Error("One time pad should've panicked on receiving slices" + 15 | "of different length, but it didn't") 16 | } 17 | }() 18 | oneTimePad(data, key) 19 | } 20 | func TestOtpMasksCorrectly(t *testing.T) { 21 | data := []byte("Inventors of the shish-kebab") 22 | key := []byte("They stop Cthulhu eating ye.") 23 | // precalculated 24 | expected := []byte("\x1d\x06\x13\x1cN\x07\x1b\x1d\x03\x00,\x12H\x01\x04" + 25 | "\rUS\r\x08\x07\x01C\x0cE\x1b\x04L") 26 | 27 | oneTimePad(data, key) 28 | 29 | if !bytes.Equal(data, expected) { 30 | t.Errorf("oneTimePad masked the data incorrectly: expected %#v, got %#v", 31 | expected, data) 32 | } 33 | } 34 | 35 | func TestOtpUnmasksCorrectly(t *testing.T) { 36 | orig := []byte("a very secret message") 37 | data := make([]byte, len(orig)) 38 | copy(data, orig) 39 | if !bytes.Equal(orig, data) { 40 | t.Fatal("copy failed") 41 | } 42 | 43 | key := []byte("even more secret key!") 44 | 45 | oneTimePad(data, key) 46 | oneTimePad(data, key) 47 | 48 | if !bytes.Equal(orig, data) { 49 | t.Errorf("2x oneTimePad didn't return the original data:"+ 50 | " expected %#v, got %#v", orig, data) 51 | } 52 | } 53 | 54 | func TestMasksTokenCorrectly(t *testing.T) { 55 | // needs to be of tokenLength 56 | token := []byte("12345678901234567890123456789012") 57 | fullToken := maskToken(token) 58 | 59 | if len(fullToken) != 2*tokenLength { 60 | t.Errorf("len(fullToken) is not %d, but %d", 2*tokenLength, len(fullToken)) 61 | } 62 | 63 | key := fullToken[:tokenLength] 64 | encToken := fullToken[tokenLength:] 65 | 66 | // perform unmasking 67 | oneTimePad(encToken, key) 68 | 69 | if !bytes.Equal(encToken, token) { 70 | t.Errorf("Unmasked token is invalid: expected %v, got %v", token, encToken) 71 | } 72 | } 73 | 74 | func TestUnmasksTokenCorrectly(t *testing.T) { 75 | token := []byte("12345678901234567890123456789012") 76 | fullToken := maskToken(token) 77 | 78 | decToken := unmaskToken(fullToken) 79 | 80 | if !bytes.Equal(decToken, token) { 81 | t.Errorf("Unmasked token is invalid: expected %v, got %v", token, decToken) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/examples/advanced.go: -------------------------------------------------------------------------------- 1 | // Demonstrates advanced usage of nosurf in conjuction with net/http: 2 | // * wrapping DefaultServeMux (http.Handle(), etc.) 3 | // * exempting URLs 4 | // * setting your own failure handler 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "html/template" 10 | "net/http" 11 | 12 | "github.com/justinas/nosurf" 13 | ) 14 | 15 | var templateString = ` 16 | 17 | 18 | 19 | {{ if .name }} 20 |

Your name: {{ .name }}

21 | {{ end }} 22 |
23 | 24 | 25 | 26 |
27 | 28 | 29 | ` 30 | 31 | var templ = template.Must(template.New("t1").Parse(templateString)) 32 | 33 | var esc = template.HTMLEscapeString 34 | 35 | func Index(w http.ResponseWriter, r *http.Request) { 36 | context := map[string]string{ 37 | "token": nosurf.Token(r), 38 | } 39 | if r.Method == "POST" { 40 | context["name"] = r.FormValue("name") 41 | } 42 | 43 | templ.Execute(w, context) 44 | } 45 | 46 | func Handler(w http.ResponseWriter, r *http.Request) { 47 | fmt.Fprintf(w, "Name: %s", esc(r.FormValue("name"))) 48 | } 49 | 50 | func failHand(w http.ResponseWriter, r *http.Request) { 51 | // will return the reason of the failure 52 | fmt.Fprintf(w, "%s\n", nosurf.Reason(r)) 53 | } 54 | 55 | func main() { 56 | http.HandleFunc("/", Index) 57 | 58 | // when you route urls with .Handle[Func]() they end up on DefaultServeMux 59 | csrfHandler := nosurf.New(http.DefaultServeMux) 60 | 61 | // exempting by an exact path... 62 | // won't exempt /faq/question-1 63 | csrfHandler.ExemptPath("/faq") 64 | 65 | // exempting by a glob 66 | // will exempt /post, /post1, /post2, etc. 67 | // won't exempt /post1/comments, as * stops at a / 68 | csrfHandler.ExemptGlob("/post*") 69 | 70 | // exempting by a regexp 71 | // will exempt /static, /static/, /static/favicon.ico, /static/css/style.css, etc. 72 | csrfHandler.ExemptRegexp("/static(.*)") 73 | 74 | // setting the failureHandler. Will call this in case the CSRF check fails. 75 | csrfHandler.SetFailureHandler(http.HandlerFunc(failHand)) 76 | 77 | http.ListenAndServe(":8000", csrfHandler) 78 | } 79 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/examples/goji.go: -------------------------------------------------------------------------------- 1 | // Demonstrates how to tie together Goji (https://goji.io) and nosurf. 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "html/template" 7 | "net/http" 8 | 9 | "github.com/zenazn/goji" 10 | "github.com/zenazn/goji/web" 11 | 12 | "github.com/justinas/nosurf" 13 | ) 14 | 15 | var templateString = ` 16 | 17 | 18 | 19 | {{ if .name }} 20 |

Your name: {{ .name }}

21 | {{ end }} 22 |
23 | 24 | 25 | 27 | 28 | 29 |
30 | 31 | 32 | ` 33 | 34 | var templ = template.Must(template.New("t1").Parse(templateString)) 35 | 36 | type M map[string]interface{} 37 | 38 | func IndexHandler(w http.ResponseWriter, r *http.Request) { 39 | fmt.Fprintf(w, "Our index page") 40 | } 41 | 42 | func ShowSignupForm(c web.C, w http.ResponseWriter, r *http.Request) { 43 | templ.Execute(w, M{ 44 | "csrf_token": nosurf.Token(r), // Pass the CSRF token to the template 45 | }) 46 | } 47 | 48 | func SubmitSignupForm(c web.C, w http.ResponseWriter, r *http.Request) { 49 | err := r.ParseForm() 50 | if err != nil { 51 | http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 52 | return 53 | } 54 | 55 | fmt.Fprintf(w, "Successfully submitted, %s!", r.FormValue("name")) 56 | } 57 | 58 | func main() { 59 | goji.Get("/", IndexHandler) // Doesn't need CSRF protection (no POST/PUT/DELETE actions). 60 | 61 | signup := web.New() 62 | goji.Handle("/signup/*", signup) 63 | // But our signup forms do, so we add nosurf to their middleware stack (only). 64 | signup.Use(nosurf.NewPure) 65 | signup.Get("/signup/new", ShowSignupForm) 66 | signup.Post("/signup/submit", SubmitSignupForm) 67 | 68 | admin := web.New() 69 | // A more advanced example: we enforce secure cookies (HTTPS only), 70 | // set a domain and keep the expiry time low. 71 | a := nosurf.New(admin) 72 | a.SetBaseCookie(http.Cookie{ 73 | Name: "csrf_token", 74 | Domain: "localhost", 75 | Path: "/admin", 76 | MaxAge: 3600 * 4, 77 | HttpOnly: true, 78 | Secure: true, 79 | }) 80 | 81 | // Our /admin/* routes now have CSRF protection. 82 | goji.Handle("/admin/*", a) 83 | 84 | goji.Serve() 85 | } 86 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/examples/simple.go: -------------------------------------------------------------------------------- 1 | // Demonstrates the simplest usage of nosurf 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "html/template" 7 | "net/http" 8 | 9 | "github.com/justinas/nosurf" 10 | ) 11 | 12 | var templateString = ` 13 | 14 | 15 | 16 | {{ if .name }} 17 |

Your name: {{ .name }}

18 | {{ end }} 19 |
20 | 21 | 22 | 24 | 25 | 26 |
27 | 28 | 29 | ` 30 | 31 | var templ = template.Must(template.New("t1").Parse(templateString)) 32 | 33 | func myFunc(w http.ResponseWriter, r *http.Request) { 34 | context := make(map[string]string) 35 | context["token"] = nosurf.Token(r) 36 | 37 | if r.Method == "POST" { 38 | context["name"] = r.FormValue("name") 39 | } 40 | 41 | templ.Execute(w, context) 42 | } 43 | 44 | func main() { 45 | myHandler := http.HandlerFunc(myFunc) 46 | fmt.Println("Listening on http://127.0.0.1:8000/") 47 | http.ListenAndServe(":8000", nosurf.New(myHandler)) 48 | } 49 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/examples/web.go: -------------------------------------------------------------------------------- 1 | // Demonstrates usage of nosurf with the web.go package 2 | package main 3 | 4 | import ( 5 | "html/template" 6 | "net/http" 7 | 8 | "github.com/hoisie/web" 9 | "github.com/justinas/nosurf" 10 | ) 11 | 12 | var templateString = ` 13 | 14 | 15 | 16 | {{ if .name }} 17 |

Your name: {{ .name }}

18 | {{ end }} 19 |
20 | 21 | 22 | 23 |
24 | 25 | 26 | ` 27 | 28 | var templ = template.Must(template.New("t1").Parse(templateString)) 29 | 30 | func myHandler(ctx *web.Context) { 31 | templateCtx := make(map[string]string) 32 | templateCtx["token"] = nosurf.Token(ctx.Request) 33 | 34 | if ctx.Request.Method == "POST" { 35 | templateCtx["name"] = ctx.Params["name"] 36 | } 37 | 38 | templ.Execute(ctx, templateCtx) 39 | } 40 | 41 | func main() { 42 | server := web.NewServer() 43 | server.Get("/", myHandler) 44 | server.Post("/", myHandler) 45 | 46 | http.ListenAndServe(":8000", nosurf.New(server)) 47 | } 48 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/testutils.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "errors" 5 | "net/http" 6 | "net/url" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | // A reader that always fails on Read() 12 | // Suitable for testing the case of crypto/rand unavailability 13 | type failReader struct{} 14 | 15 | func (f failReader) Read(p []byte) (n int, err error) { 16 | err = errors.New("dummy error") 17 | return 18 | } 19 | 20 | func dummyGet() *http.Request { 21 | req, err := http.NewRequest("GET", "http://dum.my/", nil) 22 | if err != nil { 23 | panic(err) 24 | } 25 | return req 26 | } 27 | 28 | func succHand(w http.ResponseWriter, r *http.Request) { 29 | w.WriteHeader(200) 30 | w.Write([]byte("success")) 31 | } 32 | 33 | // Returns a HandlerFunc 34 | // that tests for the correct failure reason 35 | func correctReason(t *testing.T, reason error) http.Handler { 36 | fn := func(w http.ResponseWriter, r *http.Request) { 37 | got := Reason(r) 38 | if got != reason { 39 | t.Errorf("CSRF check should have failed with the reason %#v,"+ 40 | " but it failed with the reason %#v", reason, got) 41 | } 42 | // Writes the default failure code 43 | w.WriteHeader(FailureCode) 44 | } 45 | 46 | return http.HandlerFunc(fn) 47 | } 48 | 49 | // Gets a cookie with the specified name from the Response 50 | // Returns nil on not finding a suitable cookie 51 | func getRespCookie(resp *http.Response, name string) *http.Cookie { 52 | for _, c := range resp.Cookies() { 53 | if c.Name == name { 54 | return c 55 | } 56 | } 57 | return nil 58 | } 59 | 60 | // Encodes a slice of key-value pairs to a form value string 61 | func formBody(pairs [][]string) string { 62 | vals := url.Values{} 63 | for _, pair := range pairs { 64 | vals.Add(pair[0], pair[1]) 65 | } 66 | 67 | return vals.Encode() 68 | } 69 | 70 | // The same as formBody(), but wraps the string in a Reader 71 | func formBodyR(pairs [][]string) *strings.Reader { 72 | return strings.NewReader(formBody(pairs)) 73 | } 74 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/token.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/subtle" 6 | "encoding/base64" 7 | "fmt" 8 | "io" 9 | ) 10 | 11 | const ( 12 | tokenLength = 32 13 | ) 14 | 15 | /* 16 | There are two types of tokens. 17 | 18 | * The unmasked "real" token consists of 32 random bytes. 19 | It is stored in a cookie (base64-encoded) and it's the 20 | "reference" value that sent tokens get compared to. 21 | 22 | * The masked "sent" token consists of 64 bytes: 23 | 32 byte key used for one-time pad masking and 24 | 32 byte "real" token masked with the said key. 25 | It is used as a value (base64-encoded as well) 26 | in forms and/or headers. 27 | 28 | Upon processing, both tokens are base64-decoded 29 | and then treated as 32/64 byte slices. 30 | */ 31 | 32 | // A token is generated by returning tokenLength bytes 33 | // from crypto/rand 34 | func generateToken() []byte { 35 | bytes := make([]byte, tokenLength) 36 | _, _ = io.ReadFull(rand.Reader, bytes) 37 | 38 | // I'm not sure how to handle the error from the above call. 39 | // It shouldn't EVER really happen, 40 | // as we check for the availablity of crypto/random 41 | // in the init() function 42 | // and both /dev/urandom and CryptGenRandom() 43 | // should be inexhaustible. 44 | 45 | return bytes 46 | } 47 | 48 | func b64encode(data []byte) string { 49 | return base64.StdEncoding.EncodeToString(data) 50 | } 51 | 52 | func b64decode(data string) []byte { 53 | decoded, err := base64.StdEncoding.DecodeString(data) 54 | if err != nil { 55 | return nil 56 | } 57 | return decoded 58 | } 59 | 60 | // Verifies the sent token equals the real one 61 | // and returns a bool value indicating if tokens are equal. 62 | // Supports masked tokens. 63 | func verifyToken(realToken, sentToken []byte) bool { 64 | realN := len(realToken) 65 | sentN := len(sentToken) 66 | 67 | // sentN == tokenLength means the token is unmasked 68 | // sentN == 2*tokenLength means the token is masked. 69 | 70 | if realN == tokenLength && sentN == 2*tokenLength { 71 | return verifyMasked(realToken, sentToken) 72 | } else { 73 | return false 74 | } 75 | } 76 | 77 | // Verifies the masked token 78 | func verifyMasked(realToken, sentToken []byte) bool { 79 | sentPlain := unmaskToken(sentToken) 80 | return subtle.ConstantTimeCompare(realToken, sentPlain) == 1 81 | } 82 | 83 | func checkForPRNG() { 84 | // Check that cryptographically secure PRNG is available 85 | // In case it's not, panic. 86 | buf := make([]byte, 1) 87 | _, err := io.ReadFull(rand.Reader, buf) 88 | 89 | if err != nil { 90 | panic(fmt.Sprintf("crypto/rand is unavailable: Read() failed with %#v", err)) 91 | } 92 | } 93 | 94 | func init() { 95 | checkForPRNG() 96 | } 97 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/token_test.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | func TestChecksForPRNG(t *testing.T) { 9 | // Monkeypatch crypto/rand with an always-failing reader 10 | oldReader := rand.Reader 11 | rand.Reader = failReader{} 12 | // Restore it later for other tests 13 | defer func() { 14 | rand.Reader = oldReader 15 | }() 16 | 17 | defer func() { 18 | r := recover() 19 | if r == nil { 20 | t.Errorf("Expected checkForPRNG() to panic") 21 | } 22 | }() 23 | 24 | checkForPRNG() 25 | } 26 | 27 | func TestGeneratesAValidToken(t *testing.T) { 28 | // We can't test much with any certainity here, 29 | // since we generate tokens randomly 30 | // Basically we check that the length of the 31 | // token is what it should be 32 | 33 | token := generateToken() 34 | l := len(token) 35 | 36 | if l != tokenLength { 37 | t.Errorf("Bad decoded token length: expected %d, got %d", tokenLength, l) 38 | } 39 | } 40 | 41 | func TestVerifyTokenChecksLengthCorrectly(t *testing.T) { 42 | for i := 0; i < 64; i++ { 43 | slice := make([]byte, i) 44 | result := verifyToken(slice, slice) 45 | if result != false { 46 | t.Errorf("verifyToken should've returned false with slices of length %d", i) 47 | } 48 | } 49 | 50 | slice := make([]byte, 64) 51 | result := verifyToken(slice[:32], slice) 52 | if result != true { 53 | t.Errorf("verifyToken should've returned true on a zeroed slice of length 64") 54 | } 55 | } 56 | 57 | func TestVerifiesMaskedTokenCorrectly(t *testing.T) { 58 | realToken := []byte("qwertyuiopasdfghjklzxcvbnm123456") 59 | sentToken := []byte("qwertyuiopasdfghjklzxcvbnm123456" + 60 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 61 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") 62 | 63 | if !verifyToken(realToken, sentToken) { 64 | t.Errorf("verifyToken returned a false negative") 65 | } 66 | 67 | realToken[0] = 'x' 68 | 69 | if verifyToken(realToken, sentToken) { 70 | t.Errorf("verifyToken returned a false positive") 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/utils.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "net/url" 5 | ) 6 | 7 | func sContains(slice []string, s string) bool { 8 | // checks if the given slice contains the given string 9 | for _, v := range slice { 10 | if v == s { 11 | return true 12 | } 13 | } 14 | return false 15 | } 16 | 17 | // Checks if the given URLs have the same origin 18 | // (that is, they share the host, the port and the scheme) 19 | func sameOrigin(u1, u2 *url.URL) bool { 20 | // we take pointers, as url.Parse() returns a pointer 21 | // and http.Request.URL is a pointer as well 22 | 23 | // Host is either host or host:port 24 | return (u1.Scheme == u2.Scheme && u1.Host == u2.Host) 25 | } 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/justinas/nosurf/utils_test.go: -------------------------------------------------------------------------------- 1 | package nosurf 2 | 3 | import ( 4 | "net/url" 5 | "testing" 6 | ) 7 | 8 | func TestsContains(t *testing.T) { 9 | slice := []string{"abc", "def", "ghi"} 10 | 11 | s1 := "abc" 12 | if !sContains(slice, s1) { 13 | t.Errorf("sContains said that %v doesn't contain %v, but it does.", slice, s1) 14 | } 15 | 16 | s2 := "xyz" 17 | if !sContains(slice, s2) { 18 | t.Errorf("sContains said that %v contains %v, but it doesn't.", slice, s2) 19 | } 20 | } 21 | 22 | func TestsameOrigin(t *testing.T) { 23 | // a little helper that saves us time 24 | p := func(rawurl string) *url.URL { 25 | u, err := url.Parse(rawurl) 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | return u 30 | } 31 | 32 | truthy := [][]*url.URL{ 33 | {p("http://dummy.us/"), p("http://dummy.us/faq")}, 34 | {p("https://dummy.us/some/page"), p("https://dummy.us/faq")}, 35 | } 36 | 37 | falsy := [][]*url.URL{ 38 | // different ports 39 | {p("http://dummy.us/"), p("http://dummy.us:8080")}, 40 | // different scheme 41 | {p("https://dummy.us/"), p("http://dummy.us/")}, 42 | // different host 43 | {p("https://dummy.us/"), p("http://dummybook.us/")}, 44 | // slightly different host 45 | {p("https://beta.dummy.us/"), p("http://dummy.us/")}, 46 | } 47 | 48 | for _, v := range truthy { 49 | if !sameOrigin(v[0], v[1]) { 50 | t.Errorf("%v and %v have the same origin, but sameOrigin() said otherwise.", 51 | v[0], v[1]) 52 | } 53 | } 54 | 55 | for _, v := range falsy { 56 | if sameOrigin(v[0], v[1]) { 57 | t.Errorf("%v and %v don't have the same origin, but sameOrigin() said otherwise.", 58 | v[0], v[1]) 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/kylelemons/go-gypsy/yaml/Makefile: -------------------------------------------------------------------------------- 1 | include $(GOROOT)/src/Make.inc 2 | 3 | TARG=github.com/kylelemons/go-gypsy/yaml 4 | GOFILES=\ 5 | types.go\ 6 | parser.go\ 7 | config.go\ 8 | 9 | include $(GOROOT)/src/Make.pkg 10 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/kylelemons/go-gypsy/yaml/config_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package yaml 16 | 17 | import ( 18 | "testing" 19 | ) 20 | 21 | var dummyConfigFile = ` 22 | mapping: 23 | key1: value1 24 | key2: value2 25 | key3: 5 26 | key4: true 27 | key5: false 28 | list: 29 | - item1 30 | - item2 31 | config: 32 | server: 33 | - www.google.com 34 | - www.cnn.com 35 | - www.example.com 36 | admin: 37 | - username: god 38 | password: z3u5 39 | - username: lowly 40 | password: f!r3m3 41 | ` 42 | 43 | var configGetTests = []struct { 44 | Spec string 45 | Want string 46 | Err string 47 | }{ 48 | {"mapping.key1", "value1", ""}, 49 | {"mapping.key2", "value2", ""}, 50 | {"list[0]", "item1", ""}, 51 | {"list[1]", "item2", ""}, 52 | {"list", "", `yaml: list: type mismatch: "list" is yaml.List, want yaml.Scalar (at "$")`}, 53 | {"list.0", "", `yaml: .list.0: type mismatch: ".list" is yaml.List, want yaml.Map (at ".0")`}, 54 | {"config.server[0]", "www.google.com", ""}, 55 | {"config.server[1]", "www.cnn.com", ""}, 56 | {"config.server[2]", "www.example.com", ""}, 57 | {"config.server[3]", "", `yaml: .config.server[3]: ".config.server[3]" not found`}, 58 | {"config.listen[0]", "", `yaml: .config.listen[0]: ".config.listen" not found`}, 59 | {"config.admin[0].username", "god", ""}, 60 | {"config.admin[1].username", "lowly", ""}, 61 | {"config.admin[2].username", "", `yaml: .config.admin[2].username: ".config.admin[2]" not found`}, 62 | } 63 | 64 | func TestGet(t *testing.T) { 65 | config := Config(dummyConfigFile) 66 | 67 | for _, test := range configGetTests { 68 | got, err := config.Get(test.Spec) 69 | if want := test.Want; got != want { 70 | t.Errorf("Get(%q) = %q, want %q", test.Spec, got, want) 71 | } 72 | 73 | switch err { 74 | case nil: 75 | got = "" 76 | default: 77 | got = err.Error() 78 | } 79 | if want := test.Err; got != want { 80 | t.Errorf("Get(%q) error %#q, want %#q", test.Spec, got, want) 81 | } 82 | } 83 | 84 | i, err := config.GetInt("mapping.key3") 85 | if err != nil || i != 5 { 86 | t.Errorf("GetInt mapping.key3 wrong") 87 | } 88 | 89 | b, err := config.GetBool("mapping.key4") 90 | if err != nil || b != true { 91 | t.Errorf("GetBool mapping.key4 wrong") 92 | } 93 | 94 | b, err = config.GetBool("mapping.key5") 95 | if err != nil || b != false { 96 | t.Errorf("GetBool mapping.key5 wrong") 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/.gitignore: -------------------------------------------------------------------------------- 1 | .db 2 | *.test 3 | *~ 4 | *.swp 5 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0.2 5 | - 1.0.3 6 | - 1.1 7 | - 1.2 8 | - 1.3 9 | - tip 10 | 11 | before_install: 12 | - psql --version 13 | - sudo /etc/init.d/postgresql stop 14 | - sudo apt-get -y --purge remove postgresql libpq-dev libpq5 postgresql-client-common postgresql-common 15 | - sudo rm -rf /var/lib/postgresql 16 | - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - 17 | - sudo sh -c "echo deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main $PGVERSION >> /etc/apt/sources.list.d/postgresql.list" 18 | - sudo apt-get update -qq 19 | - sudo apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::="--force-confnew" install postgresql-$PGVERSION postgresql-server-dev-$PGVERSION postgresql-contrib-$PGVERSION 20 | - sudo chmod 777 /etc/postgresql/$PGVERSION/main/pg_hba.conf 21 | - sudo echo "local all postgres trust" > /etc/postgresql/$PGVERSION/main/pg_hba.conf 22 | - sudo echo "local all all trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf 23 | - sudo echo "host all all 127.0.0.1/32 trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf 24 | - sudo echo "host all all ::1/128 trust" >> /etc/postgresql/$PGVERSION/main/pg_hba.conf 25 | - sudo /etc/init.d/postgresql restart 26 | 27 | env: 28 | matrix: 29 | - PGVERSION=9.3 30 | - PGVERSION=9.2 31 | - PGVERSION=9.1 32 | - PGVERSION=9.0 33 | - PGVERSION=8.4 34 | 35 | script: 36 | - env PGUSER=postgres go test -v ./... 37 | 38 | before_script: 39 | - psql -c 'create database pqgotest;' -U postgres 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to pq 2 | 3 | `pq` has a backlog of pull requests, but contributions are still very 4 | much welcome. You can help with patch review, submitting bug reports, 5 | or adding new functionality. There is no formal style guide, but 6 | please conform to the style of existing code and general Go formatting 7 | conventions when submitting patches. 8 | 9 | ### Patch review 10 | 11 | Help review existing open pull requests by commenting on the code or 12 | proposed functionality. 13 | 14 | ### Bug reports 15 | 16 | We appreciate any bug reports, but especially ones with self-contained 17 | (doesn't depend on code outside of pq), minimal (can't be simplified 18 | further) test cases. It's especially helpful if you can submit a pull 19 | request with just the failing test case (you'll probably want to 20 | pattern it after the tests in 21 | [conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). 22 | 23 | ### New functionality 24 | 25 | There are a number of pending patches for new functionality, so 26 | additional feature patches will take a while to merge. Still, patches 27 | are generally reviewed based on usefulness and complexity in addition 28 | to time-in-queue, so if you have a knockout idea, take a shot. Feel 29 | free to open an issue discussion your proposed patch beforehand. 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013, 'pq' Contributors 2 | Portions Copyright (C) 2011 Blake Mizerany 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/README.md: -------------------------------------------------------------------------------- 1 | # pq - A pure Go postgres driver for Go's database/sql package 2 | 3 | [![Build Status](https://travis-ci.org/lib/pq.png?branch=master)](https://travis-ci.org/lib/pq) 4 | 5 | ## Install 6 | 7 | go get github.com/lib/pq 8 | 9 | ## Docs 10 | 11 | For detailed documentation and basic usage examples, please see the package 12 | documentation at . 13 | 14 | ## Tests 15 | 16 | `go test` is used for testing. A running PostgreSQL server is 17 | required, with the ability to log in. The default database to connect 18 | to test with is "pqgotest," but it can be overridden using environment 19 | variables. 20 | 21 | Example: 22 | 23 | PGHOST=/var/run/postgresql go test github.com/lib/pq 24 | 25 | Optionally, a benchmark suite can be run as part of the tests: 26 | 27 | PGHOST=/var/run/postgresql go test -bench . 28 | 29 | ## Features 30 | 31 | * SSL 32 | * Handles bad connections for `database/sql` 33 | * Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) 34 | * Scan binary blobs correctly (i.e. `bytea`) 35 | * Package for `hstore` support 36 | * COPY FROM support 37 | * pq.ParseURL for converting urls to connection strings for sql.Open. 38 | * Many libpq compatible environment variables 39 | * Unix socket support 40 | * Notifications: `LISTEN`/`NOTIFY` 41 | 42 | ## Future / Things you can help with 43 | 44 | * Better COPY FROM / COPY TO (see discussion in #181) 45 | 46 | ## Thank you (alphabetical) 47 | 48 | Some of these contributors are from the original library `bmizerany/pq.go` whose 49 | code still exists in here. 50 | 51 | * Andy Balholm (andybalholm) 52 | * Ben Berkert (benburkert) 53 | * Benjamin Heatwole (bheatwole) 54 | * Bill Mill (llimllib) 55 | * Bjørn Madsen (aeons) 56 | * Blake Gentry (bgentry) 57 | * Brad Fitzpatrick (bradfitz) 58 | * Chris Walsh (cwds) 59 | * Daniel Farina (fdr) 60 | * Eric Chlebek (echlebek) 61 | * Everyone at The Go Team 62 | * Evan Shaw (edsrzf) 63 | * Ewan Chou (coocood) 64 | * Federico Romero (federomero) 65 | * Fumin (fumin) 66 | * Gary Burd (garyburd) 67 | * Heroku (heroku) 68 | * Jason McVetta (jmcvetta) 69 | * Jeremy Jay (pbnjay) 70 | * Joakim Sernbrant (serbaut) 71 | * John Gallagher (jgallagher) 72 | * Joël Stemmer (jstemmer) 73 | * Kamil Kisiel (kisielk) 74 | * Kelly Dunn (kellydunn) 75 | * Keith Rarick (kr) 76 | * Kir Shatrov (kirs) 77 | * Lann Martin (lann) 78 | * Maciek Sakrejda (deafbybeheading) 79 | * Marc Brinkmann (mbr) 80 | * Marko Tiikkaja (johto) 81 | * Matt Newberry (MattNewberry) 82 | * Matt Robenolt (mattrobenolt) 83 | * Martin Olsen (martinolsen) 84 | * Mike Lewis (mikelikespie) 85 | * Nicolas Patry (Narsil) 86 | * Oliver Tonnhofer (olt) 87 | * Patrick Hayes (phayes) 88 | * Paul Hammond (paulhammond) 89 | * Ryan Smith (ryandotsmith) 90 | * Samuel Stauffer (samuel) 91 | * Timothée Peignier (cyberdelia) 92 | * notedit (notedit) 93 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/buf.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "github.com/lib/pq/oid" 7 | ) 8 | 9 | type readBuf []byte 10 | 11 | func (b *readBuf) int32() (n int) { 12 | n = int(int32(binary.BigEndian.Uint32(*b))) 13 | *b = (*b)[4:] 14 | return 15 | } 16 | 17 | func (b *readBuf) oid() (n oid.Oid) { 18 | n = oid.Oid(binary.BigEndian.Uint32(*b)) 19 | *b = (*b)[4:] 20 | return 21 | } 22 | 23 | func (b *readBuf) int16() (n int) { 24 | n = int(binary.BigEndian.Uint16(*b)) 25 | *b = (*b)[2:] 26 | return 27 | } 28 | 29 | func (b *readBuf) string() string { 30 | i := bytes.IndexByte(*b, 0) 31 | if i < 0 { 32 | errorf("invalid message format; expected string terminator") 33 | } 34 | s := (*b)[:i] 35 | *b = (*b)[i+1:] 36 | return string(s) 37 | } 38 | 39 | func (b *readBuf) next(n int) (v []byte) { 40 | v = (*b)[:n] 41 | *b = (*b)[n:] 42 | return 43 | } 44 | 45 | func (b *readBuf) byte() byte { 46 | return b.next(1)[0] 47 | } 48 | 49 | type writeBuf []byte 50 | 51 | func (b *writeBuf) int32(n int) { 52 | x := make([]byte, 4) 53 | binary.BigEndian.PutUint32(x, uint32(n)) 54 | *b = append(*b, x...) 55 | } 56 | 57 | func (b *writeBuf) int16(n int) { 58 | x := make([]byte, 2) 59 | binary.BigEndian.PutUint16(x, uint16(n)) 60 | *b = append(*b, x...) 61 | } 62 | 63 | func (b *writeBuf) string(s string) { 64 | *b = append(*b, (s + "\000")...) 65 | } 66 | 67 | func (b *writeBuf) byte(c byte) { 68 | *b = append(*b, c) 69 | } 70 | 71 | func (b *writeBuf) bytes(v []byte) { 72 | *b = append(*b, v...) 73 | } 74 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/conn_xact_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.1 2 | 3 | package pq 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func TestXactMultiStmt(t *testing.T) { 10 | // minified test case based on bug reports from 11 | // pico303@gmail.com and rangelspam@gmail.com 12 | t.Skip("Skipping failing test") 13 | db := openTestConn(t) 14 | defer db.Close() 15 | 16 | tx, err := db.Begin() 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | defer tx.Commit() 21 | 22 | rows, err := tx.Query("select 1") 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | if rows.Next() { 28 | var val int32 29 | if err = rows.Scan(&val); err != nil { 30 | t.Fatal(err) 31 | } 32 | } else { 33 | t.Fatal("Expected at least one row in first query in xact") 34 | } 35 | 36 | rows2, err := tx.Query("select 2") 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | 41 | if rows2.Next() { 42 | var val2 int32 43 | if err := rows2.Scan(&val2); err != nil { 44 | t.Fatal(err) 45 | } 46 | } else { 47 | t.Fatal("Expected at least one row in second query in xact") 48 | } 49 | 50 | if err = rows.Err(); err != nil { 51 | t.Fatal(err) 52 | } 53 | 54 | if err = rows2.Err(); err != nil { 55 | t.Fatal(err) 56 | } 57 | 58 | if err = tx.Commit(); err != nil { 59 | t.Fatal(err) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/oid/doc.go: -------------------------------------------------------------------------------- 1 | // Package oid contains OID constants 2 | // as defined by the Postgres server. 3 | package oid 4 | 5 | // Oid is a Postgres Object ID. 6 | type Oid uint32 7 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/oid/gen.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Generate the table of OID values 4 | // Run with 'go run gen.go'. 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | "os" 11 | "os/exec" 12 | 13 | "database/sql" 14 | _ "github.com/lib/pq" 15 | ) 16 | 17 | func main() { 18 | datname := os.Getenv("PGDATABASE") 19 | sslmode := os.Getenv("PGSSLMODE") 20 | 21 | if datname == "" { 22 | os.Setenv("PGDATABASE", "pqgotest") 23 | } 24 | 25 | if sslmode == "" { 26 | os.Setenv("PGSSLMODE", "disable") 27 | } 28 | 29 | db, err := sql.Open("postgres", "") 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | cmd := exec.Command("gofmt") 34 | cmd.Stderr = os.Stderr 35 | w, err := cmd.StdinPipe() 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | f, err := os.Create("types.go") 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | cmd.Stdout = f 44 | err = cmd.Start() 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | fmt.Fprintln(w, "// generated by 'go run gen.go'; do not edit") 49 | fmt.Fprintln(w, "\npackage oid") 50 | fmt.Fprintln(w, "const (") 51 | rows, err := db.Query(` 52 | SELECT typname, oid 53 | FROM pg_type WHERE oid < 10000 54 | ORDER BY oid; 55 | `) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | var name string 60 | var oid int 61 | for rows.Next() { 62 | err = rows.Scan(&name, &oid) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | fmt.Fprintf(w, "T_%s Oid = %d\n", name, oid) 67 | } 68 | if err = rows.Err(); err != nil { 69 | log.Fatal(err) 70 | } 71 | fmt.Fprintln(w, ")") 72 | w.Close() 73 | cmd.Wait() 74 | } 75 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/url.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "fmt" 5 | nurl "net/url" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | // ParseURL no longer needs to be used by clients of this library since supplying a URL as a 11 | // connection string to sql.Open() is now supported: 12 | // 13 | // sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") 14 | // 15 | // It remains exported here for backwards-compatibility. 16 | // 17 | // ParseURL converts a url to a connection string for driver.Open. 18 | // Example: 19 | // 20 | // "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" 21 | // 22 | // converts to: 23 | // 24 | // "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" 25 | // 26 | // A minimal example: 27 | // 28 | // "postgres://" 29 | // 30 | // This will be blank, causing driver.Open to use all of the defaults 31 | func ParseURL(url string) (string, error) { 32 | u, err := nurl.Parse(url) 33 | if err != nil { 34 | return "", err 35 | } 36 | 37 | if u.Scheme != "postgres" { 38 | return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) 39 | } 40 | 41 | var kvs []string 42 | escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) 43 | accrue := func(k, v string) { 44 | if v != "" { 45 | kvs = append(kvs, k+"="+escaper.Replace(v)) 46 | } 47 | } 48 | 49 | if u.User != nil { 50 | v := u.User.Username() 51 | accrue("user", v) 52 | 53 | v, _ = u.User.Password() 54 | accrue("password", v) 55 | } 56 | 57 | i := strings.Index(u.Host, ":") 58 | if i < 0 { 59 | accrue("host", u.Host) 60 | } else { 61 | accrue("host", u.Host[:i]) 62 | accrue("port", u.Host[i+1:]) 63 | } 64 | 65 | if u.Path != "" { 66 | accrue("dbname", u.Path[1:]) 67 | } 68 | 69 | q := u.Query() 70 | for k := range q { 71 | accrue(k, q.Get(k)) 72 | } 73 | 74 | sort.Strings(kvs) // Makes testing easier (not a performance concern) 75 | return strings.Join(kvs, " "), nil 76 | } 77 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/url_test.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSimpleParseURL(t *testing.T) { 8 | expected := "host=hostname.remote" 9 | str, err := ParseURL("postgres://hostname.remote") 10 | if err != nil { 11 | t.Fatal(err) 12 | } 13 | 14 | if str != expected { 15 | t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) 16 | } 17 | } 18 | 19 | func TestFullParseURL(t *testing.T) { 20 | expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username` 21 | str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database") 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | 26 | if str != expected { 27 | t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected) 28 | } 29 | } 30 | 31 | func TestInvalidProtocolParseURL(t *testing.T) { 32 | _, err := ParseURL("http://hostname.remote") 33 | switch err { 34 | case nil: 35 | t.Fatal("Expected an error from parsing invalid protocol") 36 | default: 37 | msg := "invalid connection protocol: http" 38 | if err.Error() != msg { 39 | t.Fatalf("Unexpected error message:\n+ %s\n- %s", 40 | err.Error(), msg) 41 | } 42 | } 43 | } 44 | 45 | func TestMinimalURL(t *testing.T) { 46 | cs, err := ParseURL("postgres://") 47 | if err != nil { 48 | t.Fatal(err) 49 | } 50 | 51 | if cs != "" { 52 | t.Fatalf("expected blank connection string, got: %q", cs) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/user_posix.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | 3 | // +build darwin freebsd linux nacl netbsd openbsd solaris 4 | 5 | package pq 6 | 7 | import "os/user" 8 | 9 | func userCurrent() (string, error) { 10 | u, err := user.Current() 11 | if err != nil { 12 | return "", err 13 | } 14 | return u.Username, nil 15 | } 16 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/user_windows.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | package pq 3 | 4 | import ( 5 | "path/filepath" 6 | "syscall" 7 | ) 8 | 9 | // Perform Windows user name lookup identically to libpq. 10 | // 11 | // The PostgreSQL code makes use of the legacy Win32 function 12 | // GetUserName, and that function has not been imported into stock Go. 13 | // GetUserNameEx is available though, the difference being that a 14 | // wider range of names are available. To get the output to be the 15 | // same as GetUserName, only the base (or last) component of the 16 | // result is returned. 17 | func userCurrent() (string, error) { 18 | pw_name := make([]uint16, 128) 19 | pwname_size := uint32(len(pw_name)) - 1 20 | err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) 21 | if err != nil { 22 | return "", err 23 | } 24 | s := syscall.UTF16ToString(pw_name) 25 | u := filepath.Base(s) 26 | return u, nil 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - tip 4 | before_install: 5 | - go get github.com/axw/gocov/gocov 6 | - go get github.com/mattn/goveralls 7 | - go get code.google.com/p/go.tools/cmd/cover 8 | script: 9 | - $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx 10 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yasuhiro Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/README.md: -------------------------------------------------------------------------------- 1 | go-sqlite3 2 | ========== 3 | 4 | [![Build Status](https://travis-ci.org/mattn/go-sqlite3.png?branch=master)](https://travis-ci.org/mattn/go-sqlite3) 5 | [![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.png?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master) 6 | 7 | Description 8 | ----------- 9 | 10 | sqlite3 driver conforming to the built-in database/sql interface 11 | 12 | Installation 13 | ------------ 14 | 15 | This package can be installed with the go get command: 16 | 17 | go get github.com/mattn/go-sqlite3 18 | 19 | Documentation 20 | ------------- 21 | 22 | API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3 23 | 24 | Examples can be found under the `./_example` directory 25 | 26 | FAQ 27 | --- 28 | 29 | * Can't build go-sqlite3 on windows 64bit. 30 | 31 | > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. 32 | > See: https://github.com/mattn/go-sqlite3/issues/27 33 | 34 | * Getting insert error while query is opened. 35 | 36 | > You can pass some arguments into the connection string, for example, a URI. 37 | > See: https://github.com/mattn/go-sqlite3/issues/39 38 | 39 | License 40 | ------- 41 | 42 | MIT: http://mattn.mit-license.org/2012 43 | 44 | sqlite.c, sqlite3.h, sqlite3ext.h 45 | 46 | In this repository, those files are amalgamation code that copied from SQLite3. The license of those codes are depend on the license of SQLite3. 47 | 48 | Author 49 | ------ 50 | 51 | Yasuhiro Matsumoto (a.k.a mattn) 52 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/backup.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package sqlite3 7 | 8 | /* 9 | #include 10 | #include 11 | */ 12 | import "C" 13 | import ( 14 | "unsafe" 15 | ) 16 | 17 | type Backup struct { 18 | b *C.sqlite3_backup 19 | } 20 | 21 | func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*Backup, error) { 22 | destptr := C.CString(dest) 23 | defer C.free(unsafe.Pointer(destptr)) 24 | srcptr := C.CString(src) 25 | defer C.free(unsafe.Pointer(srcptr)) 26 | 27 | if b := C.sqlite3_backup_init(c.db, destptr, conn.db, srcptr); b != nil { 28 | return &Backup{b: b}, nil 29 | } 30 | return nil, c.lastError() 31 | } 32 | 33 | // Backs up for one step. Calls the underlying `sqlite3_backup_step` function. 34 | // This function returns a boolean indicating if the backup is done and 35 | // an error signalling any other error. Done is returned if the underlying C 36 | // function returns SQLITE_DONE (Code 101) 37 | func (b *Backup) Step(p int) (bool, error) { 38 | ret := C.sqlite3_backup_step(b.b, C.int(p)) 39 | if ret == C.SQLITE_DONE { 40 | return true, nil 41 | } else if ret != 0 { 42 | return false, Error{Code: ErrNo(ret)} 43 | } 44 | return false, nil 45 | } 46 | 47 | func (b *Backup) Remaining() int { 48 | return int(C.sqlite3_backup_remaining(b.b)) 49 | } 50 | 51 | func (b *Backup) PageCount() int { 52 | return int(C.sqlite3_backup_pagecount(b.b)) 53 | } 54 | 55 | func (b *Backup) Finish() error { 56 | ret := C.sqlite3_backup_finish(b.b) 57 | if ret != 0 { 58 | return Error{Code: ErrNo(ret)} 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package sqlite3 provides interface to SQLite3 databases. 3 | 4 | This works as driver for database/sql. 5 | 6 | Installation 7 | 8 | go get github.com/mattn/go-sqlite3 9 | 10 | Supported Types 11 | 12 | Currently, go-sqlite3 support following data types. 13 | 14 | +------------------------------+ 15 | |go | sqlite3 | 16 | |----------|-------------------| 17 | |nil | null | 18 | |int | integer | 19 | |int64 | integer | 20 | |float64 | float | 21 | |bool | integer | 22 | |[]byte | blob | 23 | |string | text | 24 | |time.Time | timestamp/datetime| 25 | +------------------------------+ 26 | 27 | SQLite3 Extension 28 | 29 | You can write your own extension module for sqlite3. For example, below is a 30 | extension for Regexp matcher operation. 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | SQLITE_EXTENSION_INIT1 38 | static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) { 39 | if (argc >= 2) { 40 | const char *target = (const char *)sqlite3_value_text(argv[1]); 41 | const char *pattern = (const char *)sqlite3_value_text(argv[0]); 42 | const char* errstr = NULL; 43 | int erroff = 0; 44 | int vec[500]; 45 | int n, rc; 46 | pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL); 47 | rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500); 48 | if (rc <= 0) { 49 | sqlite3_result_error(context, errstr, 0); 50 | return; 51 | } 52 | sqlite3_result_int(context, 1); 53 | } 54 | } 55 | 56 | #ifdef _WIN32 57 | __declspec(dllexport) 58 | #endif 59 | int sqlite3_extension_init(sqlite3 *db, char **errmsg, 60 | const sqlite3_api_routines *api) { 61 | SQLITE_EXTENSION_INIT2(api); 62 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 63 | (void*)db, regexp_func, NULL, NULL); 64 | } 65 | 66 | It need to build as so/dll shared library. And you need to register 67 | extension module like below. 68 | 69 | sql.Register("sqlite3_with_extensions", 70 | &sqlite3.SQLiteDriver{ 71 | Extensions: []string{ 72 | "sqlite3_mod_regexp", 73 | }, 74 | }) 75 | 76 | Then, you can use this extension. 77 | 78 | rows, err := db.Query("select text from mytable where name regexp '^golang'") 79 | 80 | Connection Hook 81 | 82 | You can hook and inject your codes when connection established. database/sql 83 | doesn't provide the way to get native go-sqlite3 interfaces. So if you want, 84 | you need to hook ConnectHook and get the SQLiteConn. 85 | 86 | sql.Register("sqlite3_with_hook_example", 87 | &sqlite3.SQLiteDriver{ 88 | ConnectHook: func(conn *sqlite3.SQLiteConn) error { 89 | sqlite3conn = append(sqlite3conn, conn) 90 | return nil 91 | }, 92 | }) 93 | 94 | */ 95 | package sqlite3 96 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_other.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build !windows 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -I. 11 | #cgo linux LDFLAGS: -ldl 12 | #cgo CFLAGS: -DSQLITE_ENABLE_RTREE 13 | */ 14 | import "C" 15 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package sqlite3 7 | 8 | /* 9 | #cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe 10 | #cgo LDFLAGS: -lmingwex -lmingw32 11 | #cgo CFLAGS: -DSQLITE_ENABLE_RTREE 12 | */ 13 | import "C" 14 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/graceful/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/graceful/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Stretchr, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/graceful/tests/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | 7 | "github.com/codegangsta/negroni" 8 | "github.com/stretchr/graceful" 9 | ) 10 | 11 | func main() { 12 | 13 | var wg sync.WaitGroup 14 | 15 | wg.Add(3) 16 | go func() { 17 | n := negroni.New() 18 | fmt.Println("Launching server on :3000") 19 | graceful.Run(":3000", 0, n) 20 | fmt.Println("Terminated server on :3000") 21 | wg.Done() 22 | }() 23 | go func() { 24 | n := negroni.New() 25 | fmt.Println("Launching server on :3001") 26 | graceful.Run(":3001", 0, n) 27 | fmt.Println("Terminated server on :3001") 28 | wg.Done() 29 | }() 30 | go func() { 31 | n := negroni.New() 32 | fmt.Println("Launching server on :3002") 33 | graceful.Run(":3002", 0, n) 34 | fmt.Println("Terminated server on :3002") 35 | wg.Done() 36 | }() 37 | fmt.Println("Press ctrl+c. All servers should terminate.") 38 | wg.Wait() 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/graceful/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang 2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/pat/stop/doc.go: -------------------------------------------------------------------------------- 1 | // Package stop represents a pattern for types that need to do some work 2 | // when stopping. The StopChan method returns a <-chan stop.Signal which 3 | // is closed when the operation has completed. 4 | // 5 | // Stopper types when implementing the stop channel pattern should use stop.Make 6 | // to create and store a stop channel, and close the channel once stopping has completed: 7 | // func New() Type { 8 | // t := new(Type) 9 | // t.stopChan = stop.Make() 10 | // return t 11 | // } 12 | // func (t Type) Stop() { 13 | // go func(){ 14 | // // TODO: tear stuff down 15 | // close(t.stopChan) 16 | // }() 17 | // } 18 | // func (t Type) StopChan() <-chan stop.Signal { 19 | // return t.stopChan 20 | // } 21 | // 22 | // Stopper types can be stopped in the following ways: 23 | // // stop and forget 24 | // t.Stop(1 * time.Second) 25 | // 26 | // // stop and wait 27 | // t.Stop(1 * time.Second) 28 | // <-t.StopChan() 29 | // 30 | // // stop, do more work, then wait 31 | // t.Stop(1 * time.Second); 32 | // // do more work 33 | // <-t.StopChan() 34 | // 35 | // // stop and timeout after 1 second 36 | // t.Stop(1 * time.Second) 37 | // select { 38 | // case <-t.StopChan(): 39 | // case <-time.After(1 * time.Second): 40 | // } 41 | // 42 | // // stop.All is the same as calling Stop() then StopChan() so 43 | // // all above patterns also work on many Stopper types, 44 | // // for example; stop and wait for many things: 45 | // <-stop.All(1 * time.Second, t1, t2, t3) 46 | package stop 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/pat/stop/stop.go: -------------------------------------------------------------------------------- 1 | package stop 2 | 3 | import "time" 4 | 5 | // Signal is the type that gets sent down the stop channel. 6 | type Signal struct{} 7 | 8 | // NoWait represents a time.Duration with zero value. 9 | // Logically meaning no grace wait period when stopping. 10 | var NoWait time.Duration 11 | 12 | // Stopper represents types that implement 13 | // the stop channel pattern. 14 | type Stopper interface { 15 | // Stop instructs the type to halt operations and close 16 | // the stop channel when it is finished. 17 | Stop(wait time.Duration) 18 | // StopChan gets the stop channel which will block until 19 | // stopping has completed, at which point it is closed. 20 | // Callers should never close the stop channel. 21 | // The StopChan should exist from the point at which operations 22 | // begun, not the point at which Stop was called. 23 | StopChan() <-chan Signal 24 | } 25 | 26 | // Stopped returns a channel that signals immediately. Useful for 27 | // cases when no tear-down work is required and stopping is 28 | // immediate. 29 | func Stopped() <-chan Signal { 30 | c := Make() 31 | close(c) 32 | return c 33 | } 34 | 35 | // Make makes a new channel used to indicate when 36 | // stopping has finished. Sends to channel will not block. 37 | func Make() chan Signal { 38 | return make(chan Signal, 0) 39 | } 40 | 41 | // All stops all Stopper types and returns another channel 42 | // which will close once all things have finished stopping. 43 | func All(wait time.Duration, stoppers ...Stopper) <-chan Signal { 44 | all := Make() 45 | go func() { 46 | var allChans []<-chan Signal 47 | for _, stopper := range stoppers { 48 | go stopper.Stop(wait) 49 | allChans = append(allChans, stopper.StopChan()) 50 | } 51 | for _, ch := range allChans { 52 | <-ch 53 | } 54 | close(all) 55 | }() 56 | return all 57 | } 58 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/stretchr/pat/stop/stop_test.go: -------------------------------------------------------------------------------- 1 | package stop_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/pat/stop" 8 | ) 9 | 10 | type testStopper struct { 11 | stopChan chan stop.Signal 12 | } 13 | 14 | func NewTestStopper() *testStopper { 15 | s := new(testStopper) 16 | s.stopChan = stop.Make() 17 | return s 18 | } 19 | 20 | func (t *testStopper) Stop(wait time.Duration) { 21 | go func() { 22 | time.Sleep(100 * time.Millisecond) 23 | close(t.stopChan) 24 | }() 25 | } 26 | func (t *testStopper) StopChan() <-chan stop.Signal { 27 | return t.stopChan 28 | } 29 | 30 | type noopStopper struct{} 31 | 32 | func (t *noopStopper) Stop() { 33 | } 34 | func (t *noopStopper) StopChan() <-chan stop.Signal { 35 | return stop.Stopped() 36 | } 37 | 38 | func TestStop(t *testing.T) { 39 | 40 | s := NewTestStopper() 41 | s.Stop(1 * time.Second) 42 | stopChan := s.StopChan() 43 | select { 44 | case <-stopChan: 45 | case <-time.After(1 * time.Second): 46 | t.Error("Stop signal was never sent (timed out)") 47 | } 48 | 49 | } 50 | 51 | func TestAll(t *testing.T) { 52 | 53 | s1 := NewTestStopper() 54 | s2 := NewTestStopper() 55 | s3 := NewTestStopper() 56 | 57 | select { 58 | case <-stop.All(1*time.Second, s1, s2, s3): 59 | case <-time.After(1 * time.Second): 60 | t.Error("All signal was never sent (timed out)") 61 | } 62 | 63 | } 64 | 65 | func TestNoop(t *testing.T) { 66 | 67 | s := new(noopStopper) 68 | s.Stop() 69 | stopChan := s.StopChan() 70 | select { 71 | case <-stopChan: 72 | case <-time.After(1 * time.Second): 73 | t.Error("Stop signal was never sent (timed out)") 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/godrv/appengine.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package godrv 4 | 5 | import ( 6 | "net" 7 | "time" 8 | 9 | "appengine/cloudsql" 10 | ) 11 | 12 | func init() { 13 | SetDialer(func(proto, laddr, raddr, user, dbname string, timeout time.Duration) (net.Conn, error) { 14 | return cloudsql.Dial(raddr) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/mysql/field.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | type Field struct { 4 | Catalog string 5 | Db string 6 | Table string 7 | OrgTable string 8 | Name string 9 | OrgName string 10 | DispLen uint32 11 | // Charset uint16 12 | Flags uint16 13 | Type byte 14 | Scale byte 15 | } 16 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/mysql/interface.go: -------------------------------------------------------------------------------- 1 | // MySQL Client API written entirely in Go without any external dependences. 2 | package mysql 3 | 4 | import ( 5 | "net" 6 | "time" 7 | ) 8 | 9 | // ConCommon is a common interface to the connection. 10 | // See mymysql/native for method documentation 11 | type ConnCommon interface { 12 | Start(sql string, params ...interface{}) (Result, error) 13 | Prepare(sql string) (Stmt, error) 14 | 15 | Ping() error 16 | ThreadId() uint32 17 | Escape(txt string) string 18 | 19 | Query(sql string, params ...interface{}) ([]Row, Result, error) 20 | QueryFirst(sql string, params ...interface{}) (Row, Result, error) 21 | QueryLast(sql string, params ...interface{}) (Row, Result, error) 22 | } 23 | 24 | // Dialer can be used to dial connections to MySQL. If Dialer returns (nil, nil) 25 | // the hook is skipped and normal dialing proceeds. 26 | type Dialer func(proto, laddr, raddr string, timeout time.Duration) (net.Conn, error) 27 | 28 | // Conn represnts connection to the MySQL server. 29 | // See mymysql/native for method documentation 30 | type Conn interface { 31 | ConnCommon 32 | 33 | Clone() Conn 34 | SetTimeout(time.Duration) 35 | Connect() error 36 | NetConn() net.Conn 37 | SetDialer(Dialer) 38 | Close() error 39 | IsConnected() bool 40 | Reconnect() error 41 | Use(dbname string) error 42 | Register(sql string) 43 | SetMaxPktSize(new_size int) int 44 | NarrowTypeSet(narrow bool) 45 | FullFieldInfo(full bool) 46 | 47 | Begin() (Transaction, error) 48 | } 49 | 50 | // Transaction represents MySQL transaction 51 | // See mymysql/native for method documentation 52 | type Transaction interface { 53 | ConnCommon 54 | 55 | Commit() error 56 | Rollback() error 57 | Do(st Stmt) Stmt 58 | IsValid() bool 59 | } 60 | 61 | // Stmt represents MySQL prepared statement. 62 | // See mymysql/native for method documentation 63 | type Stmt interface { 64 | Bind(params ...interface{}) 65 | Run(params ...interface{}) (Result, error) 66 | Delete() error 67 | Reset() error 68 | SendLongData(pnum int, data interface{}, pkt_size int) error 69 | 70 | Fields() []*Field 71 | NumParam() int 72 | WarnCount() int 73 | 74 | Exec(params ...interface{}) ([]Row, Result, error) 75 | ExecFirst(params ...interface{}) (Row, Result, error) 76 | ExecLast(params ...interface{}) (Row, Result, error) 77 | } 78 | 79 | // Result represents one MySQL result set. 80 | // See mymysql/native for method documentation 81 | type Result interface { 82 | StatusOnly() bool 83 | ScanRow(Row) error 84 | GetRow() (Row, error) 85 | 86 | MoreResults() bool 87 | NextResult() (Result, error) 88 | 89 | Fields() []*Field 90 | Map(string) int 91 | Message() string 92 | AffectedRows() uint64 93 | InsertId() uint64 94 | WarnCount() int 95 | 96 | MakeRow() Row 97 | GetRows() ([]Row, error) 98 | End() error 99 | GetFirstRow() (Row, error) 100 | GetLastRow() (Row, error) 101 | } 102 | 103 | // New can be used to establish a connection. It is set by imported engine 104 | // (see mymysql/native, mymysql/thrsafe) 105 | var New func(proto, laddr, raddr, user, passwd string, db ...string) Conn 106 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/mysql/types_test.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | type sio struct { 9 | in, out string 10 | } 11 | 12 | func checkRow(t *testing.T, examples []sio, conv func(string) interface{}) { 13 | row := make(Row, 1) 14 | for _, ex := range examples { 15 | row[0] = conv(ex.in) 16 | str := row.Str(0) 17 | if str != ex.out { 18 | t.Fatalf("Wrong conversion: '%s' != '%s'", str, ex.out) 19 | } 20 | } 21 | } 22 | 23 | var dates = []sio{ 24 | sio{"2121-11-22", "2121-11-22"}, 25 | sio{"0000-00-00", "0000-00-00"}, 26 | sio{" 1234-12-18 ", "1234-12-18"}, 27 | sio{"\t1234-12-18 \r\n", "1234-12-18"}, 28 | } 29 | 30 | func TestConvDate(t *testing.T) { 31 | conv := func(str string) interface{} { 32 | d, err := ParseDate(str) 33 | if err != nil { 34 | return err 35 | } 36 | return d 37 | } 38 | checkRow(t, dates, conv) 39 | } 40 | 41 | var datetimes = []sio{ 42 | sio{"2121-11-22 11:22:32", "2121-11-22 11:22:32"}, 43 | sio{" 1234-12-18 22:11:22 ", "1234-12-18 22:11:22"}, 44 | sio{"\t 1234-12-18 22:11:22 \r\n", "1234-12-18 22:11:22"}, 45 | sio{"2000-11-11", "2000-11-11 00:00:00"}, 46 | sio{"0000-00-00 00:00:00", "0000-00-00 00:00:00"}, 47 | sio{"0000-00-00", "0000-00-00 00:00:00"}, 48 | sio{"2000-11-22 11:11:11.000111222", "2000-11-22 11:11:11.000111222"}, 49 | } 50 | 51 | func TestConvTime(t *testing.T) { 52 | conv := func(str string) interface{} { 53 | d, err := ParseTime(str, time.Local) 54 | if err != nil { 55 | return err 56 | } 57 | return d 58 | } 59 | checkRow(t, datetimes, conv) 60 | } 61 | 62 | var times = []sio{ 63 | sio{"1:23:45", "1:23:45"}, 64 | sio{"-112:23:45", "-112:23:45"}, 65 | sio{"+112:23:45", "112:23:45"}, 66 | sio{"1:60:00", "invalid MySQL TIME string: 1:60:00"}, 67 | sio{"1:00:60", "invalid MySQL TIME string: 1:00:60"}, 68 | sio{"1:23:45.000111333", "1:23:45.000111333"}, 69 | sio{"-1:23:45.000111333", "-1:23:45.000111333"}, 70 | } 71 | 72 | func TestConvDuration(t *testing.T) { 73 | conv := func(str string) interface{} { 74 | d, err := ParseDuration(str) 75 | if err != nil { 76 | return err 77 | } 78 | return d 79 | 80 | } 81 | checkRow(t, times, conv) 82 | } 83 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Michal Derkacz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/addons.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | func NbinToNstr(nbin *[]byte) *string { 4 | if nbin == nil { 5 | return nil 6 | } 7 | str := string(*nbin) 8 | return &str 9 | } 10 | 11 | func NstrToNbin(nstr *string) *[]byte { 12 | if nstr == nil { 13 | return nil 14 | } 15 | bin := []byte(*nstr) 16 | return &bin 17 | } 18 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/common.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "io" 5 | "runtime" 6 | ) 7 | 8 | var tab8s = " " 9 | 10 | func catchError(err *error) { 11 | if pv := recover(); pv != nil { 12 | switch e := pv.(type) { 13 | case runtime.Error: 14 | panic(pv) 15 | case error: 16 | if e == io.EOF { 17 | *err = io.ErrUnexpectedEOF 18 | } else { 19 | *err = e 20 | } 21 | default: 22 | panic(pv) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/init.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "github.com/ziutek/mymysql/mysql" 5 | "log" 6 | ) 7 | 8 | func (my *Conn) init() { 9 | my.seq = 0 // Reset sequence number, mainly for reconnect 10 | if my.Debug { 11 | log.Printf("[%2d ->] Init packet:", my.seq) 12 | } 13 | pr := my.newPktReader() 14 | 15 | my.info.prot_ver = pr.readByte() 16 | my.info.serv_ver = pr.readNTB() 17 | my.info.thr_id = pr.readU32() 18 | pr.readFull(my.info.scramble[0:8]) 19 | pr.skipN(1) 20 | my.info.caps = pr.readU16() 21 | my.info.lang = pr.readByte() 22 | my.status = pr.readU16() 23 | pr.skipN(13) 24 | if my.info.caps&_CLIENT_PROTOCOL_41 != 0 { 25 | pr.readFull(my.info.scramble[8:]) 26 | } 27 | pr.skipAll() // Skip other information 28 | if my.Debug { 29 | log.Printf(tab8s+"ProtVer=%d, ServVer=\"%s\" Status=0x%x", 30 | my.info.prot_ver, my.info.serv_ver, my.status, 31 | ) 32 | } 33 | if my.info.caps&_CLIENT_PROTOCOL_41 == 0 { 34 | panic(mysql.ErrOldProtocol) 35 | } 36 | } 37 | 38 | func (my *Conn) auth() { 39 | if my.Debug { 40 | log.Printf("[%2d <-] Authentication packet", my.seq) 41 | } 42 | flags := uint32( 43 | _CLIENT_PROTOCOL_41 | 44 | _CLIENT_LONG_PASSWORD | 45 | _CLIENT_LONG_FLAG | 46 | _CLIENT_TRANSACTIONS | 47 | _CLIENT_SECURE_CONN | 48 | _CLIENT_LOCAL_FILES | 49 | _CLIENT_MULTI_STATEMENTS | 50 | _CLIENT_MULTI_RESULTS) 51 | // Reset flags not supported by server 52 | flags &= uint32(my.info.caps) | 0xffff0000 53 | scrPasswd := encryptedPasswd(my.passwd, my.info.scramble[:]) 54 | pay_len := 4 + 4 + 1 + 23 + len(my.user) + 1 + 1 + len(scrPasswd) 55 | if len(my.dbname) > 0 { 56 | pay_len += len(my.dbname) + 1 57 | flags |= _CLIENT_CONNECT_WITH_DB 58 | } 59 | pw := my.newPktWriter(pay_len) 60 | pw.writeU32(flags) 61 | pw.writeU32(uint32(my.max_pkt_size)) 62 | pw.writeByte(my.info.lang) // Charset number 63 | pw.writeZeros(23) // Filler 64 | pw.writeNTB([]byte(my.user)) // Username 65 | pw.writeBin(scrPasswd) // Encrypted password 66 | if len(my.dbname) > 0 { 67 | pw.writeNTB([]byte(my.dbname)) 68 | } 69 | if len(my.dbname) > 0 { 70 | pay_len += len(my.dbname) + 1 71 | flags |= _CLIENT_CONNECT_WITH_DB 72 | } 73 | return 74 | } 75 | 76 | func (my *Conn) oldPasswd() { 77 | if my.Debug { 78 | log.Printf("[%2d <-] Password packet", my.seq) 79 | } 80 | scrPasswd := encryptedOldPassword(my.passwd, my.info.scramble[:]) 81 | pw := my.newPktWriter(len(scrPasswd) + 1) 82 | pw.write(scrPasswd) 83 | pw.writeByte(0) 84 | } 85 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/unsafe.go-disabled: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "github.com/ziutek/mymysql/mysql" 5 | "time" 6 | "unsafe" 7 | ) 8 | 9 | type paramValue struct { 10 | typ uint16 11 | addr unsafe.Pointer 12 | raw bool 13 | length int // >=0 - length of value, <0 - unknown length 14 | } 15 | 16 | func (pv *paramValue) SetAddr(addr uintptr) { 17 | pv.addr = unsafe.Pointer(addr) 18 | } 19 | 20 | func (val *paramValue) Len() int { 21 | if val.addr == nil { 22 | // Invalid Value was binded 23 | return 0 24 | } 25 | // val.addr always points to the pointer - lets dereference it 26 | ptr := *(*unsafe.Pointer)(val.addr) 27 | if ptr == nil { 28 | // Binded Ptr Value is nil 29 | return 0 30 | } 31 | 32 | if val.length >= 0 { 33 | return val.length 34 | } 35 | 36 | switch val.typ { 37 | case MYSQL_TYPE_STRING: 38 | return lenStr(*(*string)(ptr)) 39 | 40 | case MYSQL_TYPE_DATE: 41 | return lenDate(*(*mysql.Date)(ptr)) 42 | 43 | case MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_DATETIME: 44 | return lenTime(*(*time.Time)(ptr)) 45 | 46 | case MYSQL_TYPE_TIME: 47 | return lenDuration(*(*time.Duration)(ptr)) 48 | 49 | case MYSQL_TYPE_TINY: // val.length < 0 so this is bool 50 | return 1 51 | } 52 | // MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_BLOB and type of Raw value 53 | return lenBin(*(*[]byte)(ptr)) 54 | } 55 | 56 | func (pw *pktWriter) writeValue(val *paramValue) { 57 | if val.addr == nil { 58 | // Invalid Value was binded 59 | return 60 | } 61 | // val.addr always points to the pointer - lets dereference it 62 | ptr := *(*unsafe.Pointer)(val.addr) 63 | if ptr == nil { 64 | // Binded Ptr Value is nil 65 | return 66 | } 67 | 68 | if val.raw || val.typ == MYSQL_TYPE_VAR_STRING || 69 | val.typ == MYSQL_TYPE_BLOB { 70 | pw.writeBin(*(*[]byte)(ptr)) 71 | return 72 | } 73 | // We don't need unsigned bit to check type 74 | switch val.typ & ^MYSQL_UNSIGNED_MASK { 75 | case MYSQL_TYPE_NULL: 76 | // Don't write null values 77 | 78 | case MYSQL_TYPE_STRING: 79 | s := *(*string)(ptr) 80 | pw.writeBin([]byte(s)) 81 | 82 | case MYSQL_TYPE_LONG, MYSQL_TYPE_FLOAT: 83 | pw.writeU32(*(*uint32)(ptr)) 84 | 85 | case MYSQL_TYPE_SHORT: 86 | pw.writeU16(*(*uint16)(ptr)) 87 | 88 | case MYSQL_TYPE_TINY: 89 | if val.length == -1 { 90 | // Translate bool value to MySQL tiny 91 | if *(*bool)(ptr) { 92 | pw.writeByte(1) 93 | } else { 94 | pw.writeByte(0) 95 | } 96 | } else { 97 | pw.writeByte(*(*byte)(ptr)) 98 | } 99 | 100 | case MYSQL_TYPE_LONGLONG, MYSQL_TYPE_DOUBLE: 101 | pw.writeU64(*(*uint64)(ptr)) 102 | 103 | case MYSQL_TYPE_DATE: 104 | pw.writeDate(*(*mysql.Date)(ptr)) 105 | 106 | case MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_DATETIME: 107 | pw.writeTime(*(*time.Time)(ptr)) 108 | 109 | case MYSQL_TYPE_TIME: 110 | pw.writeDuration(*(*time.Duration)(ptr)) 111 | 112 | default: 113 | panic(mysql.ErrBindUnkType) 114 | } 115 | return 116 | } 117 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/net/netutil/listen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package netutil provides network utility functions, complementing the more 6 | // common ones in the net package. 7 | package netutil 8 | 9 | import ( 10 | "net" 11 | "sync" 12 | ) 13 | 14 | // LimitListener returns a Listener that accepts at most n simultaneous 15 | // connections from the provided Listener. 16 | func LimitListener(l net.Listener, n int) net.Listener { 17 | return &limitListener{l, make(chan struct{}, n)} 18 | } 19 | 20 | type limitListener struct { 21 | net.Listener 22 | sem chan struct{} 23 | } 24 | 25 | func (l *limitListener) acquire() { l.sem <- struct{}{} } 26 | func (l *limitListener) release() { <-l.sem } 27 | 28 | func (l *limitListener) Accept() (net.Conn, error) { 29 | l.acquire() 30 | c, err := l.Listener.Accept() 31 | if err != nil { 32 | l.release() 33 | return nil, err 34 | } 35 | return &limitListenerConn{Conn: c, release: l.release}, nil 36 | } 37 | 38 | type limitListenerConn struct { 39 | net.Conn 40 | releaseOnce sync.Once 41 | release func() 42 | } 43 | 44 | func (l *limitListenerConn) Close() error { 45 | err := l.Conn.Close() 46 | l.releaseOnce.Do(l.release) 47 | return err 48 | } 49 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/net/netutil/listen_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build go1.3 6 | 7 | // (We only run this test on Go 1.3 because the HTTP client timeout behavior 8 | // was bad in previous releases, causing occasional deadlocks.) 9 | 10 | package netutil 11 | 12 | import ( 13 | "errors" 14 | "fmt" 15 | "io" 16 | "io/ioutil" 17 | "net" 18 | "net/http" 19 | "sync" 20 | "sync/atomic" 21 | "testing" 22 | "time" 23 | ) 24 | 25 | func TestLimitListener(t *testing.T) { 26 | const ( 27 | max = 5 28 | num = 200 29 | ) 30 | 31 | l, err := net.Listen("tcp", "127.0.0.1:0") 32 | if err != nil { 33 | t.Fatalf("Listen: %v", err) 34 | } 35 | defer l.Close() 36 | l = LimitListener(l, max) 37 | 38 | var open int32 39 | go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 40 | if n := atomic.AddInt32(&open, 1); n > max { 41 | t.Errorf("%d open connections, want <= %d", n, max) 42 | } 43 | defer atomic.AddInt32(&open, -1) 44 | time.Sleep(10 * time.Millisecond) 45 | fmt.Fprint(w, "some body") 46 | })) 47 | 48 | var wg sync.WaitGroup 49 | var failed int32 50 | for i := 0; i < num; i++ { 51 | wg.Add(1) 52 | go func() { 53 | defer wg.Done() 54 | c := http.Client{Timeout: 3 * time.Second} 55 | r, err := c.Get("http://" + l.Addr().String()) 56 | if err != nil { 57 | t.Logf("Get: %v", err) 58 | atomic.AddInt32(&failed, 1) 59 | return 60 | } 61 | defer r.Body.Close() 62 | io.Copy(ioutil.Discard, r.Body) 63 | }() 64 | } 65 | wg.Wait() 66 | 67 | // We expect some Gets to fail as the kernel's accept queue is filled, 68 | // but most should succeed. 69 | if failed >= num/2 { 70 | t.Errorf("too many Gets failed: %v", failed) 71 | } 72 | } 73 | 74 | type errorListener struct { 75 | net.Listener 76 | } 77 | 78 | func (errorListener) Accept() (net.Conn, error) { 79 | return nil, errFake 80 | } 81 | 82 | var errFake = errors.New("fake error from errorListener") 83 | 84 | // This used to hang. 85 | func TestLimitListenerError(t *testing.T) { 86 | donec := make(chan bool, 1) 87 | go func() { 88 | const n = 2 89 | ll := LimitListener(errorListener{}, n) 90 | for i := 0; i < n+1; i++ { 91 | _, err := ll.Accept() 92 | if err != errFake { 93 | t.Fatalf("Accept error = %v; want errFake", err) 94 | } 95 | } 96 | donec <- true 97 | }() 98 | select { 99 | case <-donec: 100 | case <-time.After(5 * time.Second): 101 | t.Fatal("timeout. deadlock?") 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jeremy West 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: go-passwordless-demo -port=$PORT 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/iamjem/go-passwordless-demo) 2 | 3 | # Passwordless Demo 4 | This is the project source code from my [blog post](http://www.pixeldonor.com/2015/feb/09/passwordless-authentication-golang/) on [pixeldonor.com](http://www.pixeldonor.com). 5 | 6 | # Running the Project On Heroku 7 | If you're a heroku fan, simply use the heroku button and you'll be up and running with the demo app in moments. 8 | 9 | # Running the Project Local 10 | Should you wish to run the project local, you'll want to make sure you've set all the necessary environment variables. 11 | 12 | # Generating Random Keys 13 | There's two required environment variables `AUTH_KEY` and `ENCRYPT_KEY` which should be random strings. You can use [this snippet](http://play.golang.org/p/TKd3pMLx7c) on play.golang.org to generate your own. Remember, the `ENCRYPT_KEY` should be of a fixed length (16, 24, or 32) so you'll need to adjust the string accordingly. 14 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Passwordless Demo", 3 | "description": "This app is a simple implementation of passwordless authentication using Go.", 4 | "website": "http://www.pixeldonor.com", 5 | "repository": "https://github.com/iamjem/go-passwordless-demo", 6 | "keywords": [ 7 | "passwordless", 8 | "golang" 9 | ], 10 | "scripts": { 11 | "postdeploy": "goose -env production up" 12 | }, 13 | "addons": [ 14 | "heroku-postgresql" 15 | ], 16 | "env": { 17 | "BUILDPACK_URL": "https://github.com/kr/heroku-buildpack-go.git", 18 | "DEBUG": { 19 | "description": "Enable debug mode for logging SQL and http traffic.", 20 | "value": "false" 21 | }, 22 | "AUTH_KEY": { 23 | "description": "A random string for use with gorilla session." 24 | }, 25 | "ENCRYPT_KEY": { 26 | "description": "A random string for use with gorilla session. Should be length 16, 24, or 32." 27 | }, 28 | "EMAIL_FROM": { 29 | "description": "The email to use as the sender for verification emails." 30 | }, 31 | "EMAIL_HOST": { 32 | "description": "Email host, ie smtp.gmail.com." 33 | }, 34 | "EMAIL_PORT": { 35 | "description": "Email port, ie 587." 36 | }, 37 | "EMAIL_HOST_USER": { 38 | "description": "Email username, ie user@gmail.com." 39 | }, 40 | "EMAIL_HOST_PASSWORD": { 41 | "description": "Email password." 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /db/dbconf.yml: -------------------------------------------------------------------------------- 1 | development: 2 | driver: postgres 3 | open: $DATABASE_URL 4 | production: 5 | driver: postgres 6 | open: $DATABASE_URL 7 | -------------------------------------------------------------------------------- /db/migrations/20150207110852_initial.sql: -------------------------------------------------------------------------------- 1 | 2 | -- +goose Up 3 | -- SQL in section 'Up' is executed when this migration is applied 4 | 5 | CREATE TABLE users ( 6 | id integer not null, 7 | email character varying(250) not null, 8 | token character varying(50) not null, 9 | ttl timestamp with time zone not null, 10 | originurl character varying(250) 11 | ); 12 | 13 | -- Sequences 14 | CREATE SEQUENCE users_id_seq 15 | START WITH 1 16 | INCREMENT BY 1 17 | NO MINVALUE 18 | NO MAXVALUE 19 | CACHE 1; 20 | 21 | 22 | ALTER SEQUENCE users_id_seq OWNED BY users.id; 23 | 24 | ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass); 25 | 26 | -- Constraints 27 | ALTER TABLE ONLY users 28 | ADD CONSTRAINT users_pkey PRIMARY KEY (id), 29 | ADD CONSTRAINT users_email_uniq UNIQUE (email); 30 | 31 | 32 | -- +goose Down 33 | -- SQL section 'Down' is executed when this migration is rolled back 34 | 35 | DROP TABLE users CASCADE; 36 | -------------------------------------------------------------------------------- /install_goose.go: -------------------------------------------------------------------------------- 1 | // use build constraints to work around http://code.google.com/p/go/issues/detail?id=4210 2 | // +build heroku 3 | 4 | // note: need at least one blank line after build constraint 5 | package main 6 | 7 | import _ "bitbucket.org/liamstask/goose/cmd/goose" 8 | -------------------------------------------------------------------------------- /lib/auth.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | log "github.com/Sirupsen/logrus" 5 | "github.com/gorilla/context" 6 | "github.com/gorilla/sessions" 7 | "net/http" 8 | "os" 9 | ) 10 | 11 | const ( 12 | contextUser string = "User" 13 | sessionUser string = "_user_id" 14 | ) 15 | 16 | var store *sessions.CookieStore 17 | var secretKey []byte 18 | 19 | // GetSession returns the session for the site. 20 | func GetSession(r *http.Request) *sessions.Session { 21 | session, _ := store.Get(r, "site") 22 | return session 23 | } 24 | 25 | // GetContextUser returns the User for the given request context or nil. 26 | func GetContextUser(r *http.Request) *User { 27 | if user, ok := context.GetOk(r, contextUser); ok { 28 | return user.(*User) 29 | } 30 | return nil 31 | } 32 | 33 | // SetContextUser stores the given user in the request context. 34 | func SetContextUser(user *User, r *http.Request) { 35 | context.Set(r, contextUser, user) 36 | } 37 | 38 | // Login adds the User's id to the session. 39 | func Login(u *User, w http.ResponseWriter, r *http.Request) { 40 | s := GetSession(r) 41 | s.Values[sessionUser] = u.Id 42 | s.Save(r, w) 43 | } 44 | 45 | // Logout removes the User from their session. 46 | func Logout(w http.ResponseWriter, r *http.Request) { 47 | s := GetSession(r) 48 | delete(s.Values, sessionUser) 49 | s.Save(r, w) 50 | } 51 | 52 | // IsLoggedIn is a convenience function for checking if a User exists in the request context. 53 | func IsLoggedIn(r *http.Request) bool { 54 | return GetContextUser(r) != nil 55 | } 56 | 57 | func init() { 58 | authKey := os.Getenv("AUTH_KEY") 59 | if authKey == "" { 60 | log.Panic("Missing required environment variable 'AUTH_KEY'.") 61 | } 62 | 63 | encryptKey := os.Getenv("ENCRYPT_KEY") 64 | if encryptKey == "" { 65 | log.Panic("Missing required environment variable 'ENCRYPT_KEY' (16, 24, 32 bytes in length).") 66 | } 67 | 68 | store = sessions.NewCookieStore([]byte(authKey), []byte(encryptKey)) 69 | } 70 | -------------------------------------------------------------------------------- /lib/db.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | "database/sql" 5 | log "github.com/Sirupsen/logrus" 6 | "github.com/coopernurse/gorp" 7 | _ "github.com/lib/pq" 8 | stdlog "log" 9 | "os" 10 | ) 11 | 12 | var dbmap *gorp.DbMap 13 | 14 | func init() { 15 | dbUrl := os.Getenv("DATABASE_URL") 16 | if dbUrl == "" { 17 | log.Panic("Missing required environment variable 'DATABASE_URL'.") 18 | } 19 | 20 | db, err := sql.Open("postgres", dbUrl) 21 | if nil != err { 22 | log.WithFields(log.Fields{ 23 | "error": err, 24 | }).Fatal("Database connection error") 25 | } 26 | 27 | dbmap = &gorp.DbMap{ 28 | Db: db, 29 | Dialect: gorp.PostgresDialect{}, 30 | } 31 | 32 | if os.Getenv("DEBUG") == "true" { 33 | dbmap.TraceOn("[gorp]", stdlog.New(os.Stdout, "passwordless:", stdlog.Lmicroseconds)) 34 | } 35 | 36 | dbmap.AddTableWithName(User{}, "users").SetKeys(true, "Id") 37 | } 38 | -------------------------------------------------------------------------------- /lib/mail.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | log "github.com/Sirupsen/logrus" 7 | "net/smtp" 8 | "os" 9 | "strings" 10 | "text/template" 11 | ) 12 | 13 | var ( 14 | auth smtp.Auth 15 | authParts map[string]string 16 | fromEmail string 17 | ) 18 | 19 | var emailTemplate = template.Must(template.New("emailTemplate").Parse(`From: {{.From}} 20 | To: {{.To}} 21 | Subject: {{.Subject}} 22 | 23 | {{.Body}}`)) 24 | 25 | func SendMail(to []string, subject, message string) error { 26 | var doc bytes.Buffer 27 | 28 | ctx := struct { 29 | From string 30 | To string 31 | Subject string 32 | Body string 33 | }{ 34 | fromEmail, 35 | strings.Join(to, ", "), 36 | subject, 37 | message, 38 | } 39 | 40 | if err := emailTemplate.Execute(&doc, ctx); err != nil { 41 | return err 42 | } 43 | 44 | return smtp.SendMail( 45 | fmt.Sprintf("%v:%v", authParts["EMAIL_HOST"], authParts["EMAIL_PORT"]), 46 | auth, 47 | fromEmail, 48 | to, 49 | doc.Bytes()) 50 | } 51 | 52 | func init() { 53 | authParts = make(map[string]string) 54 | // get from address 55 | fromEmail = os.Getenv("EMAIL_FROM") 56 | if fromEmail == "" { 57 | log.Panic("Missing required environment variable 'EMAIL_FROM'.") 58 | } 59 | 60 | // initialize smtp auth 61 | for _, part := range []string{"EMAIL_HOST_USER", "EMAIL_HOST_PASSWORD", "EMAIL_HOST", "EMAIL_PORT"} { 62 | envPart := os.Getenv(part) 63 | if envPart == "" { 64 | log.Panicf("Missing required environment variable '%s'.", part) 65 | } 66 | authParts[part] = envPart 67 | } 68 | auth = smtp.PlainAuth("", authParts["EMAIL_HOST_USER"], authParts["EMAIL_HOST_PASSWORD"], authParts["EMAIL_HOST"]) 69 | } 70 | -------------------------------------------------------------------------------- /lib/middleware.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | "github.com/gorilla/context" 5 | "github.com/justinas/nosurf" 6 | "net/http" 7 | ) 8 | 9 | // CsrfMiddleware adds CSRF support via nosurf. 10 | func CsrfMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 11 | var token string 12 | var passed bool 13 | 14 | // nosurf disposes of the token as soon as it calls the http.Handler you provide... 15 | // in order to use it as negroni middleware, pull out token and dispose of it ourselves 16 | csrfHandler := nosurf.NewPure(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { 17 | token = nosurf.Token(r) 18 | passed = true 19 | })) 20 | csrfHandler.ServeHTTP(w, r) 21 | 22 | // csrf passed 23 | if passed { 24 | context.Set(r, "csrf_token", token) 25 | next(w, r) 26 | context.Delete(r, "csrf_token") 27 | } 28 | } 29 | 30 | // UserMiddleware checks for the User in the session and adds them to the request context if they exist. 31 | func UserMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 32 | s := GetSession(r) 33 | if id, ok := s.Values[sessionUser]; ok { 34 | if user, err := dbmap.Get(User{}, id.(int64)); err == nil { 35 | SetContextUser(user.(*User), r) 36 | } 37 | } 38 | next(w, r) 39 | } 40 | 41 | // LoginRequiredMiddleware ensures a User is logged in, otherwise redirects them to the login page. 42 | func LoginRequiredMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 43 | if !IsLoggedIn(r) { 44 | http.Redirect(w, r, "/", http.StatusFound) 45 | return 46 | } 47 | next(w, r) 48 | } 49 | -------------------------------------------------------------------------------- /lib/models.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/subtle" 6 | "encoding/base64" 7 | "github.com/guregu/null" 8 | "io" 9 | "net/url" 10 | "time" 11 | ) 12 | 13 | const ( 14 | TokenLength int = 32 15 | TtlDuration time.Duration = 20 * time.Minute 16 | ) 17 | 18 | type User struct { 19 | Id int64 `db:"id"` 20 | Email string `db:"email"` 21 | Token string `db:"token"` 22 | Ttl time.Time `db:"ttl"` 23 | OriginUrl null.String `db:"originurl"` 24 | } 25 | 26 | // RefreshToken refreshes Ttl and Token for the User. 27 | func (u *User) RefreshToken() error { 28 | token := make([]byte, TokenLength) 29 | if _, err := io.ReadFull(rand.Reader, token); err != nil { 30 | return err 31 | } 32 | u.Token = base64.URLEncoding.EncodeToString(token) 33 | u.Ttl = time.Now().UTC().Add(TtlDuration) 34 | return nil 35 | } 36 | 37 | // IsValidToken returns a bool indicating that the User's current token hasn't 38 | // expired and that the provided token is valid. 39 | func (u *User) IsValidToken(token string) bool { 40 | if u.Ttl.Before(time.Now().UTC()) { 41 | return false 42 | } 43 | return subtle.ConstantTimeCompare([]byte(u.Token), []byte(token)) == 1 44 | } 45 | 46 | func (u *User) UpdateOriginUrl(originUrl *url.URL) error { 47 | var nsOrigin null.String 48 | if err := nsOrigin.Scan(originUrl.String()); err != nil { 49 | return err 50 | } 51 | 52 | u.OriginUrl = nsOrigin 53 | 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /lib/routes.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | "github.com/codegangsta/negroni" 5 | "github.com/gorilla/mux" 6 | "net/http" 7 | ) 8 | 9 | // BuildRoutes returns the routes for the application. 10 | func BuildRoutes() http.Handler { 11 | router := mux.NewRouter() 12 | 13 | router.HandleFunc("/", HomeHandler) 14 | router.HandleFunc("/login-success", LoginSuccessHandler) 15 | router.HandleFunc("/verify", VerifyHandler) 16 | router.HandleFunc("/logout", LogoutHandler) 17 | 18 | // profile routes with LoginRequiredMiddleware 19 | profileRouter := mux.NewRouter() 20 | profileRouter.HandleFunc("/profile", ProfileHandler) 21 | 22 | router.PathPrefix("/profile").Handler(negroni.New( 23 | negroni.HandlerFunc(LoginRequiredMiddleware), 24 | negroni.Wrap(profileRouter), 25 | )) 26 | 27 | // apply the base middleware to the main router 28 | n := negroni.New( 29 | negroni.HandlerFunc(CsrfMiddleware), 30 | negroni.HandlerFunc(UserMiddleware), 31 | ) 32 | n.UseHandler(router) 33 | 34 | return n 35 | } 36 | -------------------------------------------------------------------------------- /lib/template.go: -------------------------------------------------------------------------------- 1 | package passwordless 2 | 3 | import ( 4 | log "github.com/Sirupsen/logrus" 5 | "github.com/gorilla/context" 6 | "html/template" 7 | "net/http" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | "strings" 12 | ) 13 | 14 | var templates *template.Template 15 | 16 | type tmplContext struct { 17 | CsrfToken string 18 | Request *http.Request 19 | Page map[string]interface{} 20 | } 21 | 22 | func newTmplContext(r *http.Request, d map[string]interface{}) *tmplContext { 23 | ctx := tmplContext{ 24 | context.Get(r, "csrf_token").(string), 25 | r, 26 | d, 27 | } 28 | return &ctx 29 | } 30 | 31 | func renderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, d map[string]interface{}) { 32 | err := templates.ExecuteTemplate(w, tmpl, newTmplContext(r, d)) 33 | if err != nil { 34 | http.Error(w, err.Error(), http.StatusInternalServerError) 35 | } 36 | } 37 | 38 | func init() { 39 | // load all templates 40 | root, _ := os.Getwd() 41 | 42 | tmplNames := []string{} 43 | 44 | err := filepath.Walk(path.Join(root, "lib", "templates"), func(path string, info os.FileInfo, err error) error { 45 | if strings.HasSuffix(path, ".html") { 46 | tmplNames = append(tmplNames, path) 47 | } 48 | return nil 49 | }) 50 | 51 | if err != nil { 52 | log.WithFields(log.Fields{ 53 | "error": err, 54 | }).Fatal("Template load error.") 55 | } 56 | 57 | templates = template.New("") 58 | if _, err := templates.ParseFiles(tmplNames...); err != nil { 59 | log.WithFields(log.Fields{ 60 | "error": err, 61 | }).Fatal("Template parsing error.") 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /lib/templates/home.html: -------------------------------------------------------------------------------- 1 | {{ define "home" }} 2 | {{ template "header" . }} 3 | 4 |
5 |
6 |
7 | 10 |

Enter your email below to sign up or login and receive your verification email.

11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 |
19 |
20 |
21 | 22 | {{ template "footer" . }} 23 | {{ end }} 24 | -------------------------------------------------------------------------------- /lib/templates/login-success.html: -------------------------------------------------------------------------------- 1 | {{ define "login-success" }} 2 | {{ template "header" . }} 3 | 4 |
5 |
6 |
7 | 10 |

Check your email for your verification link!

11 |
12 |
13 |
14 | 15 | {{ template "footer" . }} 16 | {{ end }} 17 | -------------------------------------------------------------------------------- /lib/templates/partials/footer.html: -------------------------------------------------------------------------------- 1 | {{ define "footer" }} 2 | 3 | 4 | {{ end }} 5 | -------------------------------------------------------------------------------- /lib/templates/partials/header.html: -------------------------------------------------------------------------------- 1 | {{ define "header" }} 2 | 3 | 4 | 5 | 6 | 7 | Passwordless 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{ end }} 16 | -------------------------------------------------------------------------------- /lib/templates/profile.html: -------------------------------------------------------------------------------- 1 | {{ define "profile" }} 2 | {{ template "header" . }} 3 | 4 |
5 |
6 |
7 | 10 |

You made it to the super secret content!

11 |

Bored already? Log out and do it all over!

12 |
13 |
14 |
15 | 16 | {{ template "footer" . }} 17 | {{ end }} 18 | -------------------------------------------------------------------------------- /lib/templates/verify.html: -------------------------------------------------------------------------------- 1 | {{ define "verify" }} 2 | {{ template "header" . }} 3 | 4 |
5 |
6 |
7 | 10 |

Sorry, we were unable to verify your identity. Try logging in again.

11 |
12 |
13 |
14 | 15 | {{ template "footer" . }} 16 | {{ end }} 17 | -------------------------------------------------------------------------------- /passwordless.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | log "github.com/Sirupsen/logrus" 7 | "github.com/gorilla/handlers" 8 | "github.com/gorilla/mux" 9 | passwordless "github.com/iamjem/go-passwordless-demo/lib" 10 | "github.com/stretchr/graceful" 11 | "net/http" 12 | "os" 13 | "path" 14 | "time" 15 | ) 16 | 17 | var port = flag.String("port", "8080", "listen address") 18 | 19 | func main() { 20 | flag.Parse() 21 | 22 | listen := fmt.Sprintf(":%s", *port) 23 | 24 | router := mux.NewRouter() 25 | 26 | // static files 27 | root, _ := os.Getwd() 28 | router.PathPrefix("/static").Handler(http.StripPrefix("/static", http.FileServer(http.Dir(path.Join(root, "public"))))) 29 | 30 | // web routes 31 | router.PathPrefix("/").Handler(passwordless.BuildRoutes()) 32 | 33 | // setup server 34 | var handler http.Handler 35 | 36 | // if Debug is true, enable logging 37 | if os.Getenv("DEBUG") == "true" { 38 | log.SetLevel(log.DebugLevel) 39 | handler = handlers.CombinedLoggingHandler(os.Stdout, router) 40 | } else { 41 | handler = router 42 | } 43 | 44 | log.WithFields(log.Fields{ 45 | "listen": listen, 46 | }).Info("Server running") 47 | 48 | graceful.Run(listen, 10*time.Second, handler) 49 | } 50 | -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamjem/go-passwordless-demo/20ea2843f28ccd27c5237865230b90ea93d1c25e/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamjem/go-passwordless-demo/20ea2843f28ccd27c5237865230b90ea93d1c25e/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamjem/go-passwordless-demo/20ea2843f28ccd27c5237865230b90ea93d1c25e/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamjem/go-passwordless-demo/20ea2843f28ccd27c5237865230b90ea93d1c25e/public/fonts/glyphicons-halflings-regular.woff2 --------------------------------------------------------------------------------