// Init is called to initialize the application. func Init(configKey string) { // Init the configuration system. if err := cfg.Init(cfg.EnvProvider{Namespace: configKey}); err != nil { fmt.Println("Error initalizing configuration system", err) os.Exit(1) } // Init the log system. logLevel := func() int { ll, err := cfg.Int(cfgLoggingLevel) if err != nil { return log.USER } return ll } log.Init(os.Stderr, logLevel) // Log all the configuration options log.User("startup", "Init", "\n\nConfig Settings: %s\n%s\n", configKey, cfg.Log()) // Init MongoDB if configured. if _, err := cfg.String(cfgMongoHost); err == nil { app.useMongo = true cfg := mongo.Config{ Host: cfg.MustString(cfgMongoHost), AuthDB: cfg.MustString(cfgMongoAuthDB), DB: cfg.MustString(cfgMongoDB), User: cfg.MustString(cfgMongoUser), Password: cfg.MustString(cfgMongoPassword), } if err := mongo.Init(cfg); err != nil { log.Error("startup", "Init", err, "Initializing MongoDB") os.Exit(1) } } // Load user defined custom headers. HEADERS should be key:value,key:value if hs, err := cfg.String("HEADERS"); err == nil { hdrs := strings.Split(hs, ",") for _, hdr := range hdrs { if kv := strings.Split(hdr, ":"); len(kv) == 2 { log.User("startup", "Init", "User Headers : %s:%s", kv[0], kv[1]) app.userHeaders[kv[0]] = kv[1] } } } }
func main() { app.Init(cfg.EnvProvider{Namespace: Namespace}) // Pull options from the config. var conn *db.DB if _, errHost := cfg.String(cfgWebHost); errHost != nil { xenia.Println("Configuring MongoDB") mongoURI := cfg.MustURL(cfgMongoURI) err := db.RegMasterSession("startup", mongoURI.Path, mongoURI.String(), 0) if err != nil { xenia.Println("Unable to initialize MongoDB") os.Exit(1) } conn, err = db.NewMGO("startup", mongoURI.Path) if err != nil { xenia.Println("Unable to get MongoDB session") os.Exit(1) } defer conn.CloseMGO("startup") } xenia.AddCommand( cmddb.GetCommands(conn), cmdquery.GetCommands(), cmdscript.GetCommands(), cmdregex.GetCommands(), cmdmask.GetCommands(), cmdrelationship.GetCommands(), cmdview.GetCommands(), ) xenia.Execute() }
// Init is called to initialize the application. func Init(configKey string) { // Init the configuration system. if err := cfg.Init(cfg.EnvProvider{Namespace: configKey}); err != nil { fmt.Println("Error initalizing configuration system", err) os.Exit(1) } // Init the log system. logLevel := func() int { ll, err := cfg.Int(cfgLoggingLevel) if err != nil { return log.USER } return ll } log.Init(os.Stderr, logLevel) // Log all the configuration options log.User("startup", "Init", "\n\nConfig Settings: %s\n%s\n", configKey, cfg.Log()) // Load user defined custom headers. HEADERS should be key:value,key:value if hs, err := cfg.String("HEADERS"); err == nil { hdrs := strings.Split(hs, ",") for _, hdr := range hdrs { if kv := strings.Split(hdr, ":"); len(kv) == 2 { log.User("startup", "Init", "User Headers : %s:%s", kv[0], kv[1]) app.userHeaders[kv[0]] = kv[1] } } } }
// Mongo handles session management. func Mongo(h app.Handler) app.Handler { // Check if mongodb is configured. dbName, err := cfg.String(cfgMongoDB) if err != nil { return func(c *app.Context) error { log.Dev(c.SessionID, "Mongo", "******> Mongo Not Configured") return h(c) } } // Wrap the handlers inside a session copy/close. return func(c *app.Context) error { mgoDB, err := db.NewMGO("Mongo", dbName) if err != nil { log.Error(c.SessionID, "Mongo", err, "Method[%s] URL[%s] RADDR[%s]", c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr) return app.ErrDBNotConfigured } log.Dev(c.SessionID, "Mongo", "******> Capture Mongo Session") c.DB = mgoDB defer func() { log.Dev(c.SessionID, "Mongo", "******> Release Mongo Session") mgoDB.CloseMGO("Mongo") }() return h(c) } }
// API returns a handler for a set of routes. func API() http.Handler { mongoURI := cfg.MustURL(cfgMongoURI) // The web framework middleware for Mongo is using the name of the // database as the name of the master session by convention. So use // cfg.DB as the second argument when creating the master session. if err := db.RegMasterSession("startup", mongoURI.Path, mongoURI.String(), 25*time.Second); err != nil { log.Error("startup", "Init", err, "Initializing MongoDB") os.Exit(1) } w := web.New(logm.Midware, errorm.Midware) publicKey, err := cfg.String(cfgAuthPublicKey) if err != nil || publicKey == "" { log.User("startup", "Init", "%s is missing, internal authentication is disabled", cfgAuthPublicKey) } // If the public key is provided then add the auth middleware or fail using // the provided public key. if publicKey != "" { log.Dev("startup", "Init", "Initializing Auth") authm, err := authm.Midware(publicKey, authm.MidwareOpts{}) if err != nil { log.Error("startup", "Init", err, "Initializing Auth") os.Exit(1) } // Apply the authentication middleware on top of the application as the // first middleware. w.Use(authm) } // Add the Mongo and Cayley middlewares possibly after the auth middleware. w.Use(mongo.Midware(mongoURI), cayley.Midware(mongoURI)) if cors, err := cfg.Bool(cfgEnableCORS); err == nil && cors { log.Dev("startup", "Init", "Initializing CORS : CORS Enabled") w.Use(w.CORS()) } else { log.Dev("startup", "Init", "CORS Disabled") } log.Dev("startup", "Init", "Initalizing routes") routes(w) return w }
// API returns a handler for a set of routes. func API() http.Handler { mongoURI := cfg.MustURL(cfgMongoURI) // The web framework middleware for Mongo is using the name of the // database as the name of the master session by convention. So use // cfg.DB as the second argument when creating the master session. if err := db.RegMasterSession("startup", mongoURI.Path, mongoURI.String(), 25*time.Second); err != nil { log.Error("startup", "Init", err, "Initializing MongoDB") os.Exit(1) } // Ensure that the database indexes are setup on the underlying MongoDB // database. if err := ensureDBIndexes(mongoURI); err != nil { log.Error("startup", "Init", err, "Initializing DB Indexes") os.Exit(1) } w := web.New(logm.Midware, errorm.Midware, mongo.Midware(mongoURI)) // Load in the recaptcha secret from the config. if recaptcha, err := cfg.String(cfgRecaptchaSecret); err == nil && recaptcha != "" { w.Ctx["recaptcha"] = recaptcha log.Dev("startup", "Init", "Recaptcha Enabled") } else { log.Dev("startup", "Init", "%s is missing, recaptcha is disabled", cfgRecaptchaSecret) } if cors, err := cfg.Bool(cfgEnableCORS); err == nil && cors { log.Dev("startup", "Init", "Initializing CORS : CORS Enabled") w.Use(w.CORS()) } else { log.Dev("startup", "Init", "CORS Disabled") } log.Dev("startup", "Init", "Initalizing routes") routes(w) return w }
// Run is called to start the web service. func Run(defaultHost string, routes http.Handler) { log.Dev("startup", "Run", "Start : defaultHost[%s]", defaultHost) // Check for a configured host value. host, err := cfg.String(cfgHost) if err != nil { host = defaultHost } // Create this goroutine to run the web server. go func() { log.Dev("listener", "Run", "Listening on: %s", host) http.ListenAndServe(host, routes) }() // Listen for an interrupt signal from the OS. sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) <-sigChan log.Dev("shutdown", "Run", "Complete") }
func init() { if err := cfg.Init(cfg.EnvProvider{Namespace: "XENIA"}); err != nil { log.Println("Unable to initialize configuration") os.Exit(1) } // Insert the base url for requests by this client. DefaultClient.BaseURL = cfg.MustURL(cfgWebHost).String() platformPrivateKey, err := cfg.String(cfgPlatformPrivateKey) if err != nil || platformPrivateKey == "" { if err != nil { log.Printf("Downstream Auth : Disabled : %s\n", err.Error()) return } log.Printf("Downstream Auth : Disabled\n") return } // If the platformPrivateKey is provided, then we should generate the token // signing function to be used when composing requests down to the platform. signer, err := auth.NewSigner(platformPrivateKey) if err != nil { log.Printf("Downstream Auth : Error : %s", err.Error()) os.Exit(1) } // Requests can now be signed with the given signer function which we will // save on the application wide context. In the event that a function // requires a call down to a downstream platform, we will include a signed // header using the signer function here. DefaultClient.Signer = signer log.Println("Downstream Auth : Enabled") }
// TestExists validates the ability to load configuration values // using the OS-level environment variables and read them back. func TestExists(t *testing.T) { t.Log("Given the need to read environment variables.") { uStr := "postgres://*****:*****@127.0.0.1:8080/postgres?sslmode=disable" os.Setenv("MYAPP_PROC_ID", "322") os.Setenv("MYAPP_SOCKET", "./tmp/sockets.po") os.Setenv("MYAPP_PORT", "4034") os.Setenv("MYAPP_FLAG", "true") os.Setenv("MYAPP_DSN", uStr) cfg.Init("MYAPP") t.Log("\tWhen given a namspace key to search for that exists.") { proc, err := cfg.Int("PROC_ID") if err != nil { t.Errorf("\t\t%s Should not return error when valid key %q", failed, "PROC_ID") } else { t.Logf("\t\t%s Should not return error when valid key %q", succeed, "PROC_ID") if proc != 322 { t.Errorf("\t\t%s Should have key %q with value %d", failed, "PROC_ID", 322) } else { t.Logf("\t\t%s Should have key %q with value %d", succeed, "PROC_ID", 322) } } socket, err := cfg.String("SOCKET") if err != nil { t.Errorf("\t\t%s Should not return error when valid key %q", failed, "SOCKET") } else { t.Logf("\t\t%s Should not return error when valid key %q", succeed, "SOCKET") if socket != "./tmp/sockets.po" { t.Errorf("\t\t%s Should have key %q with value %q", failed, "SOCKET", "./tmp/sockets.po") } else { t.Logf("\t\t%s Should have key %q with value %q", succeed, "SOCKET", "./tmp/sockets.po") } } port, err := cfg.Int("PORT") if err != nil { t.Errorf("\t\t%s Should not return error when valid key %q", failed, "PORT") } else { t.Logf("\t\t%s Should not return error when valid key %q", succeed, "PORT") if port != 4034 { t.Errorf("\t\t%s Should have key %q with value %d", failed, "PORT", 4034) } else { t.Logf("\t\t%s Should have key %q with value %d", succeed, "PORT", 4034) } } flag, err := cfg.Bool("FLAG") if err != nil { t.Errorf("\t\t%s Should not return error when valid key %q", failed, "FLAG") } else { t.Logf("\t\t%s Should not return error when valid key %q", succeed, "FLAG") if flag == false { t.Errorf("\t\t%s Should have key %q with value %v", failed, "FLAG", true) } else { t.Logf("\t\t%s Should have key %q with value %v", succeed, "FLAG", true) } } u, err := cfg.URL("DSN") if err != nil { t.Errorf("\t\t%s Should not return error when valid key %q", failed, "DSN") } else { t.Logf("\t\t%s Should not return error when valid key %q", succeed, "DSN") if u.String() != uStr { t.Errorf("\t\t%s Should have key %q with value %v", failed, "DSN", true) } else { t.Logf("\t\t%s Should have key %q with value %v", succeed, "DSN", true) } } } } }
// API returns a handler for a set of routes. func API() http.Handler { w := web.New(logm.Midware, errorm.Midware) publicKey, err := cfg.String(cfgAuthPublicKey) if err != nil || publicKey == "" { log.User("startup", "Init", "%s is missing, internal authentication is disabled", cfgAuthPublicKey) } // If the public key is provided then add the auth middleware or fail using // the provided public key. if publicKey != "" { log.Dev("startup", "Init", "Initializing Auth") authm, err := authm.Midware(publicKey, authm.MidwareOpts{}) if err != nil { log.Error("startup", "Init", err, "Initializing Auth") os.Exit(1) } // Apply the authentication middleware on top of the application as the // first middleware. w.Use(authm) } platformPrivateKey, err := cfg.String(cfgPlatformPrivateKey) if err != nil || platformPrivateKey == "" { log.User("startup", "Init", "%s is missing, downstream platform authentication is disabled", cfgPlatformPrivateKey) } // If the platformPrivateKey is provided, then we should generate the token // signing function to be used when composing requests down to the platform. if platformPrivateKey != "" { log.Dev("startup", "Init", "Initializing Downstream Platform Auth") signer, err := auth.NewSigner(platformPrivateKey) if err != nil { log.Error("startup", "Init", err, "Initializing Downstream Platform Auth") os.Exit(1) } // Requests can now be signed with the given signer function which we will // save on the application wide context. In the event that a function // requires a call down to a downstream platform, we will include a signed // header using the signer function here. w.Ctx["signer"] = signer } if cors, err := cfg.Bool(cfgEnableCORS); err == nil && cors { log.Dev("startup", "Init", "Initializing CORS : CORS Enabled") w.Use(w.CORS()) } else { log.Dev("startup", "Init", "CORS Disabled") } // We need the URL for the services Sponged and Xeniad that needs to be running. spongedURL, err = cfg.String(cfgSpongedURL) if err != nil || spongedURL == "" { log.Error("startup", "Init", err, "Service Sponged needs to be setup.") os.Exit(1) } w.Ctx["spongedURL"] = cfg.MustURL(cfgSpongedURL).String() xeniadURL, err = cfg.String(cfgXeniadURL) if err != nil || xeniadURL == "" { log.Error("startup", "Init", err, "Service Xeniad needs to be setup.") os.Exit(1) } w.Ctx["xeniadURL "] = cfg.MustURL(cfgXeniadURL).String() log.Dev("startup", "Init", "Initalizing routes") routes(w) return w }
func routes(w *web.Web) { // Create a new app group which will be for internal functions that may have // an optional layer of auth added to it. internal := w.Group() // Now we will load in the public key from the config. If found, we'll add a // middleware to all internal endpoints that will ensure that we validate the // requests coming in. publicKey, err := cfg.String(cfgAuthPublicKey) if err != nil || publicKey == "" { log.User("startup", "Init", "%s is missing, internal authentication is disabled", cfgAuthPublicKey) } // If the public key is provided then add the auth middleware or fail using // the provided public key. if publicKey != "" { log.Dev("startup", "Init", "Initializing Auth") // We are allowing the query string to act as the access token provider // because this service has endpoints that are accessed directly currently // and we need someway to authenticate to these endpoints. authmOpts := auth.MidwareOpts{ AllowQueryString: true, } authm, err := auth.Midware(publicKey, authmOpts) if err != nil { log.Error("startup", "Init", err, "Initializing Auth") os.Exit(1) } // Apply the authentication middleware on top of the application as the // first middleware. internal.Use(authm) } // global internal.Handle("GET", "/v1/version", handlers.Version.List) // forms internal.Handle("POST", "/v1/form", handlers.Form.Upsert) internal.Handle("GET", "/v1/form", handlers.Form.List) internal.Handle("PUT", "/v1/form/:id", handlers.Form.Upsert) internal.Handle("PUT", "/v1/form/:id/status/:status", handlers.Form.UpdateStatus) internal.Handle("GET", "/v1/form/:id", handlers.Form.Retrieve) internal.Handle("DELETE", "/v1/form/:id", handlers.Form.Delete) // form aggregations internal.Handle("GET", "/v1/form/:form_id/digest", handlers.Aggregation.Digest) internal.Handle("GET", "/v1/form/:form_id/aggregate", handlers.Aggregation.Aggregate) internal.Handle("GET", "/v1/form/:form_id/aggregate/:group_id", handlers.Aggregation.AggregateGroup) internal.Handle("GET", "/v1/form/:form_id/aggregate/:group_id/submission", handlers.Aggregation.SubmissionGroup) // form submissions internal.Handle("GET", "/v1/form/:form_id/submission", handlers.FormSubmission.Search) internal.Handle("GET", "/v1/form/:form_id/submission/:id", handlers.FormSubmission.Retrieve) internal.Handle("PUT", "/v1/form/:form_id/submission/:id/status/:status", handlers.FormSubmission.UpdateStatus) internal.Handle("POST", "/v1/form/:form_id/submission/:id/flag/:flag", handlers.FormSubmission.AddFlag) internal.Handle("DELETE", "/v1/form/:form_id/submission/:id/flag/:flag", handlers.FormSubmission.RemoveFlag) internal.Handle("PUT", "/v1/form/:form_id/submission/:id/answer/:answer_id", handlers.FormSubmission.UpdateAnswer) internal.Handle("DELETE", "/v1/form/:form_id/submission/:id", handlers.FormSubmission.Delete) // temporal route to get CSV file - TO DO : move into a different service internal.Handle("GET", "/v1/form/:form_id/submission/export", handlers.FormSubmission.Download) // form form galleries internal.Handle("GET", "/v1/form/:form_id/gallery", handlers.FormGallery.RetrieveForForm) // form galleries internal.Handle("GET", "/v1/form_gallery/:id", handlers.FormGallery.Retrieve) internal.Handle("PUT", "/v1/form_gallery/:id", handlers.FormGallery.Update) internal.Handle("POST", "/v1/form_gallery/:id/submission/:submission_id/:answer_id", handlers.FormGallery.AddAnswer) internal.Handle("DELETE", "/v1/form_gallery/:id/submission/:submission_id/:answer_id", handlers.FormGallery.RemoveAnswer) // Create a new app group which will be for external functions that will need // to be publically exposed. external := w.Group() external.Handle("POST", "/v1/form/:form_id/submission", handlers.FormSubmission.Create) }
// TestSets validates the ability to manually set configuration values. func TestSets(t *testing.T) { t.Log("Given the need to manually set configuration values.") { /* uStr := "postgres://*****:*****@127.0.0.1:8080/postgres?sslmode=disable" Map: map[string]string{ "PROC_ID": "322", "SOCKET": "./tmp/sockets.po", "PORT": "4034", "FLAG": "on", "DSN": uStr, }, */ cfg.Init(cfg.MapProvider{ Map: map[string]string{}, }) t.Log("\tWhen setting values.") { key := "key1" strVal := "bill" cfg.SetString(key, strVal) retStrVal, err := cfg.String(key) if err != nil { t.Errorf("\t\t%s Should find a value for the specified key %q.", failed, key) } else { t.Logf("\t\t%s Should find a value for the specified key %q.", success, key) } if strVal != retStrVal { t.Log(strVal) t.Log(retStrVal) t.Errorf("\t\t%s Should return the string value %q that was set.", failed, strVal) } else { t.Logf("\t\t%s Should return the string value %q that was set.", success, strVal) } key = "key2" intVal := 223 cfg.SetInt(key, intVal) retIntVal, err := cfg.Int(key) if err != nil { t.Errorf("\t\t%s Should find a value for the specified key %q.", failed, key) } else { t.Logf("\t\t%s Should find a value for the specified key %q.", success, key) } if intVal != retIntVal { t.Log(intVal) t.Log(retIntVal) t.Errorf("\t\t%s Should return the int value %d that was set.", failed, intVal) } else { t.Logf("\t\t%s Should return the int value %d that was set.", success, intVal) } key = "key3" timeVal, _ := time.Parse(time.UnixDate, "Mon Oct 27 20:18:15 EST 2016") cfg.SetTime(key, timeVal) retTimeVal, err := cfg.Time(key) if err != nil { t.Errorf("\t\t%s Should find a value for the specified key %q.", failed, key) } else { t.Logf("\t\t%s Should find a value for the specified key %q.", success, key) } if timeVal != retTimeVal { t.Log(timeVal) t.Log(retTimeVal) t.Errorf("\t\t%s Should return the time value %q that was set.", failed, timeVal) } else { t.Logf("\t\t%s Should return the time value %q that was set.", success, timeVal) } key = "key4" boolVal := true cfg.SetBool(key, boolVal) retBoolVal, err := cfg.Bool(key) if err != nil { t.Errorf("\t\t%s Should find a value for the specified key %q.", failed, key) } else { t.Logf("\t\t%s Should find a value for the specified key %q.", success, key) } if boolVal != retBoolVal { t.Log(boolVal) t.Log(retBoolVal) t.Errorf("\t\t%s Should return the bool value \"%v\" that was set.", failed, boolVal) } else { t.Logf("\t\t%s Should return the bool value \"%v\" that was set.", success, boolVal) } key = "key5" urlVal, _ := url.Parse("postgres://*****:*****@127.0.0.1:8080/postgres?sslmode=disable") cfg.SetURL(key, urlVal) retURLVal, err := cfg.URL(key) if err != nil { t.Errorf("\t\t%s Should find a value for the specified key %q.", failed, key) } else { t.Logf("\t\t%s Should find a value for the specified key %q.", success, key) } if urlVal.String() != retURLVal.String() { t.Log(urlVal) t.Log(retURLVal) t.Errorf("\t\t%s Should return the bool value \"%v\" that was set.", failed, urlVal) } else { t.Logf("\t\t%s Should return the bool value \"%v\" that was set.", success, urlVal) } } } }