func main() { log.Printf("gotcha %s!\n", version) if len(os.Args) >= 2 { cmd := os.Args[1] args := os.Args[2:] switch cmd { case "new": if len(args) == 0 { log.Fatalf("Missing application name, e.g. 'gotcha new MyApp'") } new(args[0]) case "install": if len(args) > 0 { log.Fatalf("No additional arguments required for install: %s", args) } if _, err := os.Stat("Makefile"); os.IsNotExist(err) { log.Fatalf("Current directory doesn't appear to be a Gotcha application") } out, err := exec.Command("make").Output() if err != nil { log.Fatalf("Error installing application: %s", err) } log.Printf("Install successful: %s", out) default: log.Fatalf("Unrecognised command: %s\n", cmd) } } }
func (s *Source) loadBackPANSource() error { log.Info("Loading BackPAN index: backpan-index") file, err := os.Open("backpan-index") if err != nil { log.Warn(err.Error()) return nil } index, err := ioutil.ReadAll(file) file.Close() if err != nil { log.Fatal(err) } for _, p := range strings.Split(string(index), "\n") { if !strings.HasPrefix(p, "authors/id/") { continue } //log.Printf("Parsing: %s\n", p) m := s.ModuleFromBackPANIndex(p) if m != nil { s.ModuleList[m.Name+"-"+m.Version] = m } } log.Printf("Found %d packages for source: %s", len(s.ModuleList), s) return nil }
func (apiv1 *APIv1) download(w http.ResponseWriter, req *http.Request) { id := req.URL.Query().Get(":id") log.Printf("[APIv1] GET /api/v1/messages/%s\n", id) apiv1.defaultOptions(w, req) w.Header().Set("Content-Type", "message/rfc822") w.Header().Set("Content-Disposition", "attachment; filename=\""+id+".eml\"") switch apiv1.config.Storage.(type) { case *storage.MongoDB: message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id) for h, l := range message.Content.Headers { for _, v := range l { w.Write([]byte(h + ": " + v + "\r\n")) } } w.Write([]byte("\r\n" + message.Content.Body)) case *storage.InMemory: message, _ := apiv1.config.Storage.(*storage.InMemory).Load(id) for h, l := range message.Content.Headers { for _, v := range l { w.Write([]byte(h + ": " + v + "\r\n")) } } w.Write([]byte("\r\n" + message.Content.Body)) default: w.WriteHeader(500) } }
func createDir(dir string) { log.Printf("Creating directory %s", dir) err := os.MkdirAll(dir, 0777) if err != nil { log.Fatalf("Error creating directory %s: %s", dir, err) } }
func (h *Router) ServeHTTP(w nethttp.ResponseWriter, r *nethttp.Request) { session := http.CreateSession(h.Config, r, w) tStart := time.Now().UnixNano() h.Serve(session) t := float64(time.Now().UnixNano()-tStart) / 100000 // ms log.Printf("%s %s (%3.2fms) (%d)", r.Method, r.URL, t, session.Response.Status) h.Config.Events.Emit(session, events.AfterResponse, func() {}) }
// AuthFile sets Authorised to a function which validates against file func AuthFile(file string) { users = make(map[string]string) b, err := ioutil.ReadFile(file) if err != nil { log.Fatalf("[HTTP] Error reading auth-file: %s", err) // FIXME - go-log os.Exit(1) } buf := bytes.NewBuffer(b) for { l, err := buf.ReadString('\n') l = strings.TrimSpace(l) if len(l) > 0 { p := strings.SplitN(l, ":", 2) if len(p) < 2 { log.Fatalf("[HTTP] Error reading auth-file, invalid line: %s", l) // FIXME - go-log os.Exit(1) } users[p[0]] = p[1] } switch { case err == io.EOF: break case err != nil: log.Fatalf("[HTTP] Error reading auth-file: %s", err) // FIXME - go-log os.Exit(1) break } if err == io.EOF { break } else if err != nil { } } log.Printf("[HTTP] Loaded %d users from %s", len(users), file) Authorised = func(u, pw string) bool { hpw, ok := users[u] if !ok { return false } err := bcrypt.CompareHashAndPassword([]byte(hpw), []byte(pw)) if err != nil { return false } return true } }
func main() { // Create our Gotcha application var app = gotcha.Create(Asset) // Set the logger output pattern log.Logger().Appender().SetLayout(layout.Pattern("[%d] [%p] %m")) log.Logger().SetLevel(log.Stol("TRACE")) // Get the router r := app.Router // Create some routes r.Get("/", example) r.Post("/", examplepost) r.Get("/foo", example2) r.Get("/bar", example3) r.Get("/stream", streamed) r.Get("/err", err) // Serve static content (but really use a CDN) r.Get("/images/(?P<file>.*)", r.Static("assets/images/{{file}}")) r.Get("/css/(?P<file>.*)", r.Static("assets/css/{{file}}")) // Listen to some events app.On(events.BeforeHandler, func(session *http.Session, next func()) { n := 0 c, ok := session.Request.Cookies["test"] if ok { n, _ = strconv.Atoi(c.Value) } session.Stash["test"] = n log.Printf("Got BeforeHandler event! n = %d", n) next() }) app.On(events.AfterHandler, func(session *http.Session, next func()) { n := session.Stash["test"].(int) + 1 session.Response.Cookies.Set(&nethttp.Cookie{ Name: "test", Value: strconv.Itoa(n), }) log.Println("Got AfterHandler event!") next() }) app.On(events.AfterResponse, func(session *http.Session, next func()) { log.Println("Got AfterResponse event!") next() }) // Start our application app.Start() <-make(chan int) }
func (apiv1 *APIv1) download_part(w http.ResponseWriter, req *http.Request) { id := req.URL.Query().Get(":id") part := req.URL.Query().Get(":part") log.Printf("[APIv1] GET /api/v1/messages/%s/mime/part/%s/download\n", id, part) // TODO extension from content-type? apiv1.defaultOptions(w, req) w.Header().Set("Content-Disposition", "attachment; filename=\""+id+"-part-"+part+"\"") message, _ := apiv1.config.Storage.Load(id) contentTransferEncoding := "" pid, _ := strconv.Atoi(part) for h, l := range message.MIME.Parts[pid].Headers { for _, v := range l { switch strings.ToLower(h) { case "content-disposition": // Prevent duplicate "content-disposition" w.Header().Set(h, v) case "content-transfer-encoding": if contentTransferEncoding == "" { contentTransferEncoding = v } fallthrough default: w.Header().Add(h, v) } } } body := []byte(message.MIME.Parts[pid].Body) if strings.ToLower(contentTransferEncoding) == "base64" { var e error body, e = base64.StdEncoding.DecodeString(message.MIME.Parts[pid].Body) if e != nil { log.Printf("[APIv1] Decoding base64 encoded body failed: %s", e) } } w.Write(body) }
func (app *App) Start() *App { app.Server = &nethttp.Server{ Addr: app.Config.Listen, Handler: app.Router, } log.Printf("Starting application on %s", app.Config.Listen) go func() { err := app.Server.ListenAndServe() if err != nil { log.Fatalf("Error binding to %s: %s", app.Config.Listen, err) } }() return app }
func (apiv1 *APIv1) message(w http.ResponseWriter, req *http.Request) { id := req.URL.Query().Get(":id") log.Printf("[APIv1] GET /api/v1/messages/%s\n", id) apiv1.defaultOptions(w, req) message, err := apiv1.config.Storage.Load(id) if err != nil { log.Printf("- Error: %s", err) w.WriteHeader(500) return } bytes, err := json.Marshal(message) if err != nil { log.Printf("- Error: %s", err) w.WriteHeader(500) return } w.Header().Set("Content-Type", "text/json") w.Write(bytes) }
func CreateAPIv1(conf *config.Config, r *pat.Router) *APIv1 { log.Println("Creating API v1") apiv1 := &APIv1{ config: conf, } stream = goose.NewEventStream() r.Path("/api/v1/messages").Methods("GET").HandlerFunc(apiv1.messages) r.Path("/api/v1/messages").Methods("DELETE").HandlerFunc(apiv1.delete_all) r.Path("/api/v1/messages").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}").Methods("GET").HandlerFunc(apiv1.message) r.Path("/api/v1/messages/{id}").Methods("DELETE").HandlerFunc(apiv1.delete_one) r.Path("/api/v1/messages/{id}").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}/download").Methods("GET").HandlerFunc(apiv1.download) r.Path("/api/v1/messages/{id}/download").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}/mime/part/{part}/download").Methods("GET").HandlerFunc(apiv1.download_part) r.Path("/api/v1/messages/{id}/mime/part/{part}/download").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}/release").Methods("POST").HandlerFunc(apiv1.release_one) r.Path("/api/v1/messages/{id}/release").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/events").Methods("GET").HandlerFunc(apiv1.eventstream) r.Path("/api/v1/events").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) go func() { keepaliveTicker := time.Tick(time.Minute) for { select { case msg := <-apiv1.config.MessageChan: log.Println("Got message in APIv1 event stream") bytes, _ := json.MarshalIndent(msg, "", " ") json := string(bytes) log.Printf("Sending content: %s\n", json) apiv1.broadcast(json) case <-keepaliveTicker: apiv1.keepalive() } } }() return apiv1 }
func (apiv1 *APIv1) delete_one(w http.ResponseWriter, req *http.Request) { id := req.URL.Query().Get(":id") log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id) apiv1.defaultOptions(w, req) w.Header().Add("Content-Type", "text/json") switch apiv1.config.Storage.(type) { case *storage.MongoDB: apiv1.config.Storage.(*storage.MongoDB).DeleteOne(id) case *storage.InMemory: apiv1.config.Storage.(*storage.InMemory).DeleteOne(id) default: w.WriteHeader(500) } }
func writeAsset(input string, output string) { log.Printf("Writing asset %s to %s", input, output) f, err := os.Create(filepath.FromSlash(output)) if err != nil { log.Fatalf("Error creating %s: %s", output, err) } bytes, err := Asset(input) if err != nil { log.Fatalf("Error loading asset %s: %s", input, err) } _, err = f.Write(bytes) if err != nil { log.Fatalf("Error writing output %s: %s", output, err) } }
func new(name string) { log.Printf("Creating application: '%s'\n", name) // TODO clean this up createDir(name) writeAsset("assets/new_app/main.go", name+"/main.go") writeAsset("assets/new_app/Makefile", name+"/Makefile") writeAsset("assets/new_app/README.md", name+"/README.md") createDir(name + "/assets/templates") writeAsset("assets/new_app/assets/templates/index.html", name+"/assets/templates/index.html") writeAsset("assets/new_app/assets/templates/error.html", name+"/assets/templates/error.html") writeAsset("assets/new_app/assets/templates/notfound.html", name+"/assets/templates/notfound.html") createDir(name + "/assets/images") writeAsset("assets/new_app/assets/images/logo-ish.png", name+"/assets/images/logo-ish.png") createDir(name + "/assets/css") writeAsset("assets/new_app/assets/css/default.css", name+"/assets/css/default.css") }
func (apiv1 *APIv1) message(w http.ResponseWriter, req *http.Request) { id := req.URL.Query().Get(":id") log.Printf("[APIv1] GET /api/v1/messages/%s\n", id) apiv1.defaultOptions(w, req) switch apiv1.config.Storage.(type) { case *storage.MongoDB: message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id) bytes, _ := json.Marshal(message) w.Header().Add("Content-Type", "text/json") w.Write(bytes) case *storage.InMemory: message, _ := apiv1.config.Storage.(*storage.InMemory).Load(id) bytes, _ := json.Marshal(message) w.Header().Add("Content-Type", "text/json") w.Write(bytes) default: w.WriteHeader(500) } }
func main() { configure() if comconf.AuthFile != "" { http.AuthFile(comconf.AuthFile) } exitCh = make(chan int) cb := func(r gohttp.Handler) { api.CreateAPIv1(conf, r.(*pat.Router)) api.CreateAPIv2(conf, r.(*pat.Router)) } go http.Listen(conf.APIBindAddr, assets.Asset, exitCh, cb) go smtp.Listen(conf, exitCh) for { select { case <-exitCh: log.Printf("Received exit signal") os.Exit(0) } } }
func main() { configure() // FIXME need to make API URL configurable if comconf.AuthFile != "" { http.AuthFile(comconf.AuthFile) } exitCh = make(chan int) cb := func(r gohttp.Handler) { web.CreateWeb(conf, r.(*pat.Router), assets.Asset) } go http.Listen(conf.UIBindAddr, assets.Asset, exitCh, cb) for { select { case <-exitCh: log.Printf("Received exit signal") os.Exit(0) } } }
func (m *Module) Install() (int, error) { log.Debug("Installing module: %s", m) n := 0 if m.Deps != nil { log.Trace("Installing module dependencies for %s", m) <-install_semaphore o, err := m.Deps.Install() install_semaphore <- 1 n += o if err != nil { log.Error("Error installing module dependencies for %s: %s", m, err) return n, err } } var c *exec.Cmd var stdout *bytes.Buffer var stderr *bytes.Buffer cpanm_cache_dir, err := filepath.Abs(config.CacheDir) if err != nil { log.Error("Failed to get absolute path of gopan cache directory: %s", err) return n, err } os.Setenv("PERL_CPANM_HOME", cpanm_cache_dir) done := false attempts := 0 for !done { time.Sleep(time.Duration(100) * time.Millisecond) c = m.getCmd() stdout = new(bytes.Buffer) stderr = new(bytes.Buffer) c.Stderr = stderr c.Stdout = stdout // brute force cpanm text file busy errors attempts++ if err := c.Start(); err != nil { if attempts > 10 { log.Error("Error installing module %s: %s", m, err) return n, err } } else { done = true } } if err := c.Wait(); err != nil { if !strings.HasPrefix(strings.ToLower(stderr.String()), "plenv: cannot rehash:") && !strings.Contains(strings.ToLower(stderr.String()), "text file busy") && !strings.HasPrefix(strings.ToLower(stdout.String()), "plenv: cannot rehash:") && !strings.Contains(strings.ToLower(stdout.String()), "text file busy") { log.Error(m.Name + "-" + m.Version + " failed to install") log.Error("Error installing %s %s: %s\nSTDERR:\n%sSTDOUT:\n%s", m.Name, m.Version, err, stderr.String(), stdout.String()) return n, err } } n++ log.Printf("Installed " + m.Name + " (" + m.Version + ")") return n, nil }
func (apiv1 *APIv1) release_one(w http.ResponseWriter, req *http.Request) { id := req.URL.Query().Get(":id") log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id) apiv1.defaultOptions(w, req) w.Header().Add("Content-Type", "text/json") msg, _ := apiv1.config.Storage.Load(id) decoder := json.NewDecoder(req.Body) var cfg ReleaseConfig err := decoder.Decode(&cfg) if err != nil { log.Printf("Error decoding request body: %s", err) w.WriteHeader(500) w.Write([]byte("Error decoding request body")) return } log.Printf("%+v", cfg) log.Printf("Got message: %s", msg.ID) if cfg.Save { if _, ok := apiv1.config.OutgoingSMTP[cfg.Name]; ok { log.Printf("Server already exists named %s", cfg.Name) w.WriteHeader(400) return } cf := config.OutgoingSMTP(cfg) apiv1.config.OutgoingSMTP[cfg.Name] = &cf log.Printf("Saved server with name %s", cfg.Name) } if len(cfg.Name) > 0 { if c, ok := apiv1.config.OutgoingSMTP[cfg.Name]; ok { log.Printf("Using server with name: %s", cfg.Name) cfg.Name = c.Name if len(cfg.Email) == 0 { cfg.Email = c.Email } cfg.Host = c.Host cfg.Port = c.Port cfg.Username = c.Username cfg.Password = c.Password cfg.Mechanism = c.Mechanism } else { log.Printf("Server not found: %s", cfg.Name) w.WriteHeader(400) return } } log.Printf("Releasing to %s (via %s:%s)", cfg.Email, cfg.Host, cfg.Port) bytes := make([]byte, 0) for h, l := range msg.Content.Headers { for _, v := range l { bytes = append(bytes, []byte(h+": "+v+"\r\n")...) } } bytes = append(bytes, []byte("\r\n"+msg.Content.Body)...) var auth smtp.Auth if len(cfg.Username) > 0 || len(cfg.Password) > 0 { log.Printf("Found username/password, using auth mechanism: [%s]", cfg.Mechanism) switch cfg.Mechanism { case "CRAMMD5": auth = smtp.CRAMMD5Auth(cfg.Username, cfg.Password) case "PLAIN": auth = smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host) default: log.Printf("Error - invalid authentication mechanism") w.WriteHeader(400) return } } err = smtp.SendMail(cfg.Host+":"+cfg.Port, auth, "nobody@"+apiv1.config.Hostname, []string{cfg.Email}, bytes) if err != nil { log.Printf("Failed to release message: %s", err) w.WriteHeader(500) return } log.Printf("Message released successfully") }
func main() { if len(os.Args) > 1 && os.Args[1] == "sendmail" { args := os.Args os.Args = []string{args[0]} if len(args) > 2 { os.Args = append(os.Args, args[2:]...) } cmd.Go() return } if len(os.Args) > 1 && os.Args[1] == "bcrypt" { var pw string if len(os.Args) > 2 { pw = os.Args[2] } else { // TODO: read from stdin } b, err := bcrypt.GenerateFromPassword([]byte(pw), 4) if err != nil { log.Fatalf("error bcrypting password: %s", err) os.Exit(1) } fmt.Println(string(b)) os.Exit(0) } configure() if comconf.AuthFile != "" { http.AuthFile(comconf.AuthFile) } exitCh = make(chan int) if uiconf.UIBindAddr == apiconf.APIBindAddr { cb := func(r gohttp.Handler) { web.CreateWeb(uiconf, r.(*pat.Router), assets.Asset) api.CreateAPIv1(apiconf, r.(*pat.Router)) api.CreateAPIv2(apiconf, r.(*pat.Router)) } go http.Listen(uiconf.UIBindAddr, assets.Asset, exitCh, cb) } else { cb1 := func(r gohttp.Handler) { api.CreateAPIv1(apiconf, r.(*pat.Router)) api.CreateAPIv2(apiconf, r.(*pat.Router)) } cb2 := func(r gohttp.Handler) { web.CreateWeb(uiconf, r.(*pat.Router), assets.Asset) } go http.Listen(apiconf.APIBindAddr, assets.Asset, exitCh, cb1) go http.Listen(uiconf.UIBindAddr, assets.Asset, exitCh, cb2) } go smtp.Listen(apiconf, exitCh) for { select { case <-exitCh: log.Printf("Received exit signal") os.Exit(0) } } }
func (m *Module) loadDependencies() error { yml, err := ioutil.ReadFile(m.Extracted + "/META.yml") if err != nil { // TODO this isnt an error (it shouldnt make build fail) log.Error("Error opening META.yml for %s: %s", m.Name, err) // return nil to prevent build fail return nil } meta := make(map[interface{}]interface{}) err = yaml.Unmarshal(yml, &meta) if err != nil { // TODO this isnt a real error, probably log.Error("Error parsing YAML: %s", err) // return nil to prevent build fail return nil } if reqs, ok := meta["requires"]; ok { log.Debug("Found dependencies for module %s", m.Name) switch reqs.(type) { case map[interface{}]interface{}: for req, ver := range reqs.(map[interface{}]interface{}) { v := float64(0) switch ver.(type) { case string: v = gopan.VersionFromString(ver.(string)) case int: v = float64(ver.(int)) } log.Printf("=> %s (%f)", req, v) dep, err := DependencyFromString(req.(string), fmt.Sprintf("%f", ver)) if err != nil { log.Error("Error parsing dependency: %s", err) continue } if _, ok := perl_core[dep.Name]; ok { log.Trace("Module is from perl core: %s", dep.Name) continue } m.Deps.AddDependency(dep) } } log.Debug("Resolving module dependency list") if err := m.Deps.Resolve(); err != nil { log.Error("Error resolving dependency list [%s]: %s", m.Name, err) return err } return nil } // FIXME repeat of block above, just with more nested levels if p, ok := meta["prereqs"]; ok { if r, ok := p.(map[interface{}]interface{})["runtime"]; ok { if reqs, ok := r.(map[interface{}]interface{})["requires"]; ok { log.Debug("Found dependencies for module %s", m.Name) switch reqs.(type) { case map[interface{}]interface{}: for req, ver := range reqs.(map[interface{}]interface{}) { v := float64(0) switch ver.(type) { case string: v = gopan.VersionFromString(ver.(string)) case int: v = float64(ver.(int)) } log.Printf("=> %s (%f)", req, v) dep, err := DependencyFromString(req.(string), fmt.Sprintf("%f", ver)) if err != nil { log.Error("Error parsing dependency: %s", err) continue } if _, ok := perl_core[dep.Name]; ok { log.Trace("Module is from perl core: %s", dep.Name) continue } m.Deps.AddDependency(dep) } } } } if t, ok := p.(map[interface{}]interface{})["test"]; ok { if reqs, ok := t.(map[interface{}]interface{})["requires"]; ok { log.Debug("Found dependencies for module %s", m.Name) switch reqs.(type) { case map[interface{}]interface{}: for req, ver := range reqs.(map[interface{}]interface{}) { v := float64(0) switch ver.(type) { case string: v = gopan.VersionFromString(ver.(string)) case int: v = float64(ver.(int)) } log.Printf("=> %s (%f)", req, v) dep, err := DependencyFromString(req.(string), fmt.Sprintf("%f", ver)) if err != nil { log.Error("Error parsing dependency: %s", err) continue } if _, ok := perl_core[dep.Name]; ok { log.Trace("Module is from perl core: %s", dep.Name) continue } m.Deps.AddDependency(dep) } } } } log.Debug("Resolving module dependency list") if err := m.Deps.Resolve(); err != nil { log.Error("Error resolving dependency list: %s", err) return err } return nil } log.Debug("No dependencies for module %s", m.Name) return nil }