func NewTestConfig() Config { return Config{ DatabaseUrl: test.DatabaseUrl(), StellarCoreDatabaseUrl: test.StellarCoreDatabaseUrl(), RateLimit: throttled.PerHour(1000), } }
func NewTestConfig() Config { return Config{ DatabaseURL: test.DatabaseURL(), StellarCoreDatabaseURL: test.StellarCoreDatabaseURL(), RateLimit: throttled.PerHour(1000), LogLevel: hlog.InfoLevel, } }
func initConfig() { if viper.GetString("db-url") == "" { log.Fatal("Invalid config: db-url is blank. Please specify --db-url on the command line or set the DATABASE_URL environment variable.") } if viper.GetString("stellar-core-db-url") == "" { log.Fatal("Invalid config: stellar-core-db-url is blank. Please specify --stellar-core-db-url on the command line or set the STELLAR_CORE_DATABASE_URL environment variable.") } if viper.GetString("stellar-core-url") == "" { log.Fatal("Invalid config: stellar-core-url is blank. Please specify --stellar-core-url on the command line or set the STELLAR_CORE_URL environment variable.") } ll, err := logrus.ParseLevel(viper.GetString("log-level")) if err != nil { log.Fatalf("Could not parse log-level: %v", viper.GetString("log-level")) } hlog.DefaultLogger.Level = ll cert, key := viper.GetString("tls-cert"), viper.GetString("tls-key") switch { case cert != "" && key == "": log.Fatal("Invalid TLS config: key not configured") case cert == "" && key != "": log.Fatal("Invalid TLS config: cert not configured") } config = horizon.Config{ DatabaseURL: viper.GetString("db-url"), StellarCoreDatabaseURL: viper.GetString("stellar-core-db-url"), StellarCoreURL: viper.GetString("stellar-core-url"), Autopump: viper.GetBool("autopump"), Port: viper.GetInt("port"), RateLimit: throttled.PerHour(viper.GetInt("per-hour-rate-limit")), RedisURL: viper.GetString("redis-url"), LogLevel: ll, SentryDSN: viper.GetString("sentry-dsn"), LogglyToken: viper.GetString("loggly-token"), LogglyHost: viper.GetString("loggly-host"), FriendbotSecret: viper.GetString("friendbot-secret"), TLSCert: cert, TLSKey: key, Ingest: viper.GetBool("ingest"), } }
func run(cmd *cobra.Command, args []string) { var err error if viper.GetString("db-url") == "" { rootCmd.Help() os.Exit(1) } if viper.GetString("stellar-core-db-url") == "" { rootCmd.Help() os.Exit(1) } ll, err := logrus.ParseLevel(viper.GetString("log-level")) if err != nil { log.Fatalf("Could not parse log-level: %v", viper.GetString("log-level")) } hlog.DefaultLogger.Level = ll config := horizon.Config{ DatabaseUrl: viper.GetString("db-url"), StellarCoreDatabaseUrl: viper.GetString("stellar-core-db-url"), StellarCoreUrl: viper.GetString("stellar-core-url"), Autopump: viper.GetBool("autopump"), Port: viper.GetInt("port"), RateLimit: throttled.PerHour(viper.GetInt("per-hour-rate-limit")), RedisUrl: viper.GetString("redis-url"), RubyHorizonUrl: viper.GetString("ruby-horizon-url"), LogLevel: ll, SentryDSN: viper.GetString("sentry-dsn"), LogglyToken: viper.GetString("loggly-token"), LogglyHost: viper.GetString("loggly-host"), FriendbotSecret: viper.GetString("friendbot-secret"), } app, err = horizon.NewApp(config) if err != nil { log.Fatal(err.Error()) } app.Serve() }
func TestRateLimitMiddleware(t *testing.T) { Convey("Rate Limiting", t, func() { c := NewTestConfig() c.RateLimit = throttled.PerHour(10) app, _ := NewApp(c) defer app.Close() rh := NewRequestHelper(app) Convey("sets X-RateLimit-Limit headers correctly", func() { w := rh.Get("/", test.RequestHelperNoop) So(w.Code, ShouldEqual, 200) So(w.Header().Get("X-RateLimit-Limit"), ShouldEqual, "10") }) Convey("sets X-RateLimit-Remaining headers correctly", func() { for i := 0; i < 10; i++ { w := rh.Get("/", test.RequestHelperNoop) expected := 10 - (i + 1) So(w.Header().Get("X-RateLimit-Remaining"), ShouldEqual, strconv.Itoa(expected)) } // confirm remaining stays at 0 for i := 0; i < 10; i++ { w := rh.Get("/", test.RequestHelperNoop) So(w.Header().Get("X-RateLimit-Remaining"), ShouldEqual, "0") } }) Convey("sets X-RateLimit-Reset header correctly", func() { w := rh.Get("/", test.RequestHelperNoop) So(w.Header().Get("X-RateLimit-Reset"), ShouldEqual, "3599") }) Convey("Restricts based on RemoteAddr IP after too many requests", func() { for i := 0; i < 10; i++ { w := rh.Get("/", test.RequestHelperNoop) So(w.Code, ShouldEqual, 200) } w := rh.Get("/", test.RequestHelperNoop) So(w.Code, ShouldEqual, 429) w = rh.Get("/", test.RequestHelperRemoteAddr("127.0.0.2")) So(w.Code, ShouldEqual, 200) // Ignores ports w = rh.Get("/", test.RequestHelperRemoteAddr("127.0.0.1:4312")) So(w.Code, ShouldEqual, 429) }) Convey("Restrict based upon X-Forwarded-For correctly", func() { for i := 0; i < 10; i++ { w := rh.Get("/", test.RequestHelperXFF("4.4.4.4")) So(w.Code, ShouldEqual, 200) } w := rh.Get("/", test.RequestHelperXFF("4.4.4.4")) So(w.Code, ShouldEqual, 429) // allow other ips w = rh.Get("/", test.RequestHelperRemoteAddr("4.4.4.3")) So(w.Code, ShouldEqual, 200) // Ignores leading private ips w = rh.Get("/", test.RequestHelperXFF("10.0.0.1, 4.4.4.4")) So(w.Code, ShouldEqual, 429) // Ignores trailing ips w = rh.Get("/", test.RequestHelperXFF("4.4.4.4, 4.4.4.5, 127.0.0.1")) So(w.Code, ShouldEqual, 429) }) }) Convey("Rate Limiting works with redis", t, func() { c := NewTestConfig() c.RateLimit = throttled.PerHour(10) c.RedisUrl = "redis://127.0.0.1:6379/" app, _ := NewApp(c) defer app.Close() rh := NewRequestHelper(app) redis := app.redis.Get() _, err := redis.Do("FLUSHDB") So(err, ShouldBeNil) for i := 0; i < 10; i++ { w := rh.Get("/", test.RequestHelperNoop) So(w.Code, ShouldEqual, 200) } w := rh.Get("/", test.RequestHelperNoop) So(w.Code, ShouldEqual, 429) w = rh.Get("/", test.RequestHelperRemoteAddr("127.0.0.2")) So(w.Code, ShouldEqual, 200) }) }