func slaveHandler(s *websocket.Conn, sessionID int, dbStore *Store, redisAddr string) { xlog.Debugf("entering SlaveHandler") c, err := redis.Dial("tcp", redisAddr) if err != nil { xlog.Errorf("redis.Dial failed: %v", err) return } defer c.Close() psc := redis.PubSubConn{Conn: c} topic := fmt.Sprintf("session.%d", sessionID) psc.Subscribe(topic) defer psc.Unsubscribe(topic) for { switch v := psc.Receive().(type) { case redis.Message: StatCount("command for slave", 1) var cmd Command if err := json.Unmarshal(v.Data, &cmd); err != nil { break } if err := websocket.JSON.Send(s, cmd); err != nil { xlog.Errorf("slaveHandler: JSON.Send failed: %v", err) return } if cmd.Cmd == "close" { return } case redis.Subscription: xlog.Debugf("mkay... redis.Subscription received: %#v", v) } } }
func Connect(w http.ResponseWriter, r *http.Request, u auth.User, sessionStore sessions.Store, secureCookie *securecookie.SecureCookie, dbStore *Store) { StatCount("connect call", 1) session, err := sessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Errorf("Error fetching session: %v", err) session, _ = sessionStore.New(r, SESSIONNAME) } if userID, ok := session.Values["userID"].(int); ok { xlog.Debugf("Connect: already logged in (userID = %d), connecting account", userID) // we have a valid session -> connect account to user username := u.Provider() + ":" + u.Id() err := dbStore.AddUser(username, userID) if err != nil { xlog.Errorf("Error adding user: %v", err) http.Error(w, err.Error(), http.StatusForbidden) return } w.Header().Set("Location", "/settings") } else { xlog.Debugf("Connect: not logged in, actually log in user.") // no valid session -> actually login user username := u.Provider() + ":" + u.Id() xlog.Debugf("Connect: username = %s", username) userID, err := dbStore.CreateUser(username) if err != nil { xlog.Errorf("Error creating user: %v", err) http.Error(w, err.Error(), http.StatusForbidden) return } xlog.Debugf("Connect: userID = %d", userID) // set session values session.Values["userID"] = userID session.Values["username"] = username session.Values["email"] = u.Email() session.Values["name"] = u.Name() session.Save(r, w) // set XSRF-TOKEN for AngularJS xsrftoken, _ := secureCookie.Encode(XSRFTOKEN, username) http.SetCookie(w, &http.Cookie{Name: XSRFTOKEN, Value: xsrftoken, Path: "/"}) w.Header().Set("Location", "/") } w.WriteHeader(http.StatusFound) }
func (h *GetSessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["username"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } StatCount("get sessions", 1) result, err := h.DBStore.GetSessions(session.Values["userID"].(int)) if err != nil { xlog.Errorf("Querying sessions failed: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) }
func (h *StopSessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) { return } session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["userID"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } StatCount("stop session", 1) requestData := struct { PublicID string `json:"session_id"` }{} if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } ownerID, sessionID, err := h.DBStore.GetOwnerForSession(requestData.PublicID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if ownerID != session.Values["userID"].(int) { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } h.DBStore.StopSession(requestData.PublicID) w.WriteHeader(http.StatusNoContent) c, err := redis.Dial("tcp", h.RedisAddr) if err != nil { xlog.Errorf("redis.Dial failed: %v", err) return } defer c.Close() cmdJSON, _ := json.Marshal(&Command{ Cmd: "close", SessionID: sessionID, Timestamp: time.Now(), }) c.Send("PUBLISH", fmt.Sprintf("session.%d", sessionID), string(cmdJSON)) c.Flush() }
// GetSessions returns a slice of SessionData objects for the specified user. func (s *Store) GetSessions(userID int) ([]*SessionData, error) { xlog.Debugf("GetSessions: userID = %d", userID) result := []*SessionData{} err := meddler.QueryAll(s.sqlDB, &result, `SELECT sessions.public_id AS public_id, sessions.started AS started, sessions.ended AS ended, uploads.title AS title FROM uploads, sessions WHERE sessions.upload_id = uploads.id AND uploads.user_id = ? ORDER BY sessions.started DESC`, userID) if err != nil { result = nil } else { // XXX: ugly hack. for _, entry := range result { formatted := entry.Ended.Format(time.RFC3339) if formatted != "0001-01-01T00:00:00Z" { entry.EndedJSON = formatted } } } return result, err }
func (h *GetSessionInfoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { StatCount("session info", 1) session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } userID := 0 if session.Values["userID"] != nil { userID = session.Values["userID"].(int) } publicID := r.URL.Query().Get(":id") result, err := h.DBStore.GetSessionInfoByPublicID(publicID, userID) if err != nil { xlog.Errorf("Loading session information failed: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) }
func (h *GetUploadsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } userID, ok := session.Values["userID"].(int) if !ok { http.Error(w, "no userID in session", http.StatusForbidden) return } StatCount("get uploads", 1) result, err := h.DBStore.GetUploadsForUser(userID) if err != nil { xlog.Errorf("Couldn't query uploads: %v", err) http.Error(w, "query failed", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) }
// AddUser adds a new account (identified by username) to a user, identified by its // userID. func (s *Store) AddUser(username string, userID int) error { userData := []*struct { UserID int `meddler:"user_id"` }{} err := meddler.QueryAll(s.sqlDB, &userData, "SELECT user_id FROM accounts WHERE username = ? LIMIT 1", username) if err != nil { xlog.Errorf("AddUser: SELECT for username %s failed: %v", username, err) return err } if len(userData) > 0 { // account already logged in previously, migrate data to this user. if userData[0].UserID == userID { xlog.Debugf("userID is the same, not doing anything.") return nil } xlog.Debugf("AddUser: user exists, migrating data to this user. userID %d -> %d", userData[0].UserID, userID) // first, set account entries to current user. _, err := s.sqlDB.Exec("UPDATE accounts SET user_id = ? WHERE user_id = ?", userID, userData[0].UserID) if err != nil { xlog.Errorf("AddUser: migrating accounts for username %s to userID %d failed: %v", username, userID, err) return err } // then migrate uploads to current user. _, err = s.sqlDB.Exec("UPDATE uploads SET user_id = ? WHERE user_id = ?", userID, userData[0].UserID) if err != nil { xlog.Errorf("AddUser: migrating uploads for username %s to userID %d failed: %v", username, userID, err) return err } // finally, delete old user. ON DELETE CASCADE should clean up any old cruft. _, err = s.sqlDB.Exec("DELETE FROM users WHERE id = ?", userData[0].UserID) } else { // account is unknown, simply add new entry to accounts table. _, err := s.sqlDB.Exec("INSERT INTO accounts (username, user_id) VALUES (?, ?)", username, userID) if err != nil { xlog.Errorf("AddUser: INSERT failed: %v", err) return err } } return nil }
func (h *StartSessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) { return } session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["userID"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } StatCount("start session", 1) data := struct { UploadID string `json:"upload_id"` }{} if err := json.NewDecoder(r.Body).Decode(&data); err != nil { xlog.Errorf("Decoding POST body failed: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } uploadEntry, err := h.DBStore.GetUploadByPublicID(data.UploadID, session.Values["userID"].(int)) if err != nil { xlog.Errorf("Querying upload %s failed: %v", data.UploadID, err) http.Error(w, err.Error(), http.StatusNotFound) return } id := generateID() if err := h.DBStore.InsertSession(&Session{ UploadID: uploadEntry.ID, PublicID: id, Started: time.Now().UTC(), }); err != nil { xlog.Errorf("Insert failed: %v", err) http.Error(w, "insert failed", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{"id": id}) }
func masterHandler(s *websocket.Conn, sessionID int, dbStore *Store, redisAddr string) { xlog.Debugf("entering MasterHandler") c, err := redis.Dial("tcp", redisAddr) if err != nil { xlog.Errorf("redis.Dial failed: %v", err) return } defer c.Close() for { var cmd Command if err := websocket.JSON.Receive(s, &cmd); err != nil { xlog.Errorf("masterHandler: JSON.Receive failed: %v", err) break } xlog.Debugf("masterHandler: received command: %#v", cmd) cmd.SessionID = sessionID cmd.Timestamp = time.Now() if cmd.Cmd != "clearSlide" { if err := dbStore.InsertCommand(&cmd); err != nil { xlog.Errorf("Inserting command failed: %v", err) break } } executeCommand(cmd, dbStore) cmdJSON, _ := json.Marshal(cmd) c.Send("PUBLISH", fmt.Sprintf("session.%d", sessionID), string(cmdJSON)) c.Flush() } xlog.Debugf("masterHandler: closing connection") }
func (c *Converter) HandleMessage(message *nsq.Message) error { xlog.Debugf("Processing Message %s: %s", message.Id, string(message.Body)) msg, err := simplejson.NewJson(message.Body) if err != nil { xlog.Errorf("HandleMessage: parsing message %s failed: %v", message.Id, err) return err } srcFile := msg.Get("src_file").MustString() targetFile := msg.Get("target_file").MustString() publicId := msg.Get("upload_id").MustString() if _, err := os.Stat(targetFile); err == nil { xlog.Debugf("target file %s already exists.", targetFile) return nil } if err := ConvertFileToPDF(srcFile, targetFile); err != nil { xlog.Errorf("Converting %s to %s failed: %v", srcFile, targetFile, err) _, err = c.DB.Exec("UPDATE uploads SET conversion = 'error' WHERE public_id = ?", publicId) if err != nil { xlog.Errorf("Updating conversion status for %s failed: %v", publicId, err) } os.Remove(srcFile) os.Remove(targetFile) return nil } else { _, err = c.DB.Exec("UPDATE uploads SET conversion = 'success' WHERE public_id = ?", publicId) if err != nil { xlog.Errorf("Updating conversion status for %s failed: %v", publicId, err) } } xlog.Debugf("Conversion of upload %s finished.", publicId) return nil }
func (h *DeleteSessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) { return } session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["userID"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } StatCount("delete session", 1) requestData := struct { PublicID string `json:"session_id"` }{} if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } ownerID, _, err := h.DBStore.GetOwnerForSession(requestData.PublicID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if ownerID != session.Values["userID"].(int) { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } h.DBStore.DeleteSession(requestData.PublicID) w.WriteHeader(http.StatusNoContent) }
func (h *DeleteUploadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) { return } session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["userID"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } StatCount("delete upload", 1) requestData := struct { UploadID string `json:"upload_id"` }{} if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } rowsAffected, err := h.DBStore.DeleteUploadByPublicID(requestData.UploadID, session.Values["userID"].(int)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if rowsAffected > 0 { h.UploadStore.Remove(requestData.UploadID) } w.WriteHeader(http.StatusNoContent) }
// WebsocketHandler handles an incoming WebSocket and dispatches to the correct // handler based on whether the user is authenticated and whether the session // he's viewing belongs to him. func WebsocketHandler(s *websocket.Conn, dbStore *Store, sessionStore sessions.Store, redisAddr string) { StatCount("websocket", 1) xlog.Infof("WebsocketHandler: opened connection") r := s.Request() session, err := sessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) return } sessionData := struct { SessionID string `json:"session_id"` }{} if err := websocket.JSON.Receive(s, &sessionData); err != nil { xlog.Errorf("WebsocketHandler: JSON.Receive failed: %v", err) return } owner, sessionID, err := dbStore.GetOwnerForSession(sessionData.SessionID) if err != nil { xlog.Errorf("GetOwnerForSession failed: %v", err) return } if session.Values["userID"] == nil { xlog.Errorf("WebsocketHandler is not authenticated -> slave handler") slaveHandler(s, sessionID, dbStore, redisAddr) } else if owner == session.Values["userID"].(int) { xlog.Infof("WebSocketHandler owner matches -> master handler") masterHandler(s, sessionID, dbStore, redisAddr) } else { xlog.Infof("WebSocketHandler owner doesn't match -> slave handler") slaveHandler(s, sessionID, dbStore, redisAddr) } }
// Store stores a new file with a specified id in the filesystem. If the // file isn't a PDF file, it also attempts a conversion to a PDF file. func (store *FileUploadStore) Store(id string, uploadedFile io.Reader, origFileName string) (isPDF bool, err error) { filename := path.Join(store.UploadDir, id+".pdf") tmpFile := path.Join(store.TmpDir, id+"_"+origFileName) tmpf, err := os.OpenFile(tmpFile, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return false, err } io.Copy(tmpf, uploadedFile) tmpf.Close() f, err := os.Open(tmpFile) if err != nil { return false, err } defer f.Close() buf := make([]byte, 4) if _, err = f.Read(buf); err != nil { return false, err } if bytes.Equal(buf, []byte("%PDF")) { xlog.Debugf("%s is a PDF file, renaming to %s", tmpFile, filename) os.Rename(tmpFile, filename) return true, nil } if err = store.ConvertFileToPDF(id, tmpFile, filename); err != nil { xlog.Errorf("conversion to PDF of %s failed: %v", tmpFile, err) os.Remove(tmpFile) os.Remove(filename) return false, err } return false, nil }
func (h *RenameUploadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) { return } session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["userID"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } requestData := struct { UploadID string `json:"upload_id"` NewTitle string `json:"new_title"` }{} StatCount("rename upload", 1) if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if err := h.DBStore.SetTitleForPresentation(requestData.NewTitle, requestData.UploadID, session.Values["userID"].(int)); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }
func (h *PersonaAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Errorf("Error fetching session: %v", err) session, _ = h.SessionStore.New(r, SESSIONNAME) } assertionData := struct { Assertion string `json:"assertion"` }{} if err := json.NewDecoder(r.Body).Decode(&assertionData); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } form := url.Values{"assertion": []string{assertionData.Assertion}, "audience": []string{h.Audience}} xlog.Debugf("Verifying Persona assertion...") resp, err := http.PostForm("https://verifier.login.persona.org/verify", form) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } verifierResponse := struct { Status string `json:"status"` Email string `json:"email"` Audience string `json:"audience"` Expires uint64 `json:"expires"` Issuer string `json:"issuer"` }{} if err := json.NewDecoder(resp.Body).Decode(&verifierResponse); err != nil { http.Error(w, err.Error(), http.StatusForbidden) return } xlog.Debugf("Verifier response: %#v", verifierResponse) if verifierResponse.Status != "okay" { http.Error(w, "Not authenticated", http.StatusForbidden) return } if userID, ok := session.Values["userID"].(int); ok { xlog.Debugf("Persona: already logged in (userID = %d), connecting account", userID) // we have a valid session -> connect account to user username := "******" + verifierResponse.Email err := h.DBStore.AddUser(username, userID) if err != nil { xlog.Errorf("Persona: error adding user: %v", err) http.Error(w, err.Error(), http.StatusForbidden) return } w.WriteHeader(http.StatusOK) // TODO: maybe deliver some additional information? } else { username := "******" + verifierResponse.Email xlog.Debugf("Persona: username = %s", username) userID, err := h.DBStore.CreateUser(username) if err != nil { xlog.Errorf("Error creating user: %v", err) http.Error(w, err.Error(), http.StatusForbidden) } xlog.Debugf("Persona: userID = %d", userID) session.Values["userID"] = userID session.Values["username"] = username session.Values["email"] = verifierResponse.Email session.Save(r, w) xsrftoken, _ := h.SecureCookie.Encode(XSRFTOKEN, username) http.SetCookie(w, &http.Cookie{Name: XSRFTOKEN, Value: xsrftoken, Path: "/"}) w.WriteHeader(http.StatusOK) } }
func main() { xlog.SetOutput(os.Stdout) options := struct { Addr string `goptions:"-L, --listen, description='Listen address'"` HashKey string `goptions:"--hashkey, description='Hash key for cookie store and XSRF', obligatory"` BlockKey string `goptions:"--blockkey, description='Crypto key for cookie store and XSRF', obligatory"` GplusClientID string `goptions:"--gplusclientid, description='Google+ Client ID', obligatory"` GplusClientSecret string `goptions:"--gplusclientsecret, description='Google+ Client Secret', obligatory"` GPlusAuthURL string `goptions:"--gplusauthurl, description='Google+ Authentication URL', obligatory"` TwitterClientKey string `goptions:"--twitterclientkey, description='Twitter Client Key', obligatory"` TwitterClientSecret string `goptions:"--twitterclientsecret, description='Twitter Client Secret', obligatory"` TwitterAuthURL string `goptions:"--twitterauthurl, description='Twitter Authentication URL', obligatory"` DSN string `goptions:"--dsn, description='MySQL DSN string', obligatory"` HtdocsDir string `goptions:"--htdocs, description='htdocs directory', obligatory"` UploadDir string `goptions:"--uploaddir, description='Upload directory', obligatory"` TmpDir string `goptions:"--tmpdir, description='directory for temporary files', obligatory"` RedisAddr string `goptions:"--redis, description='redis address', obligatory"` AccessLog bool `goptions:"--accesslog, description='log HTTP requests'"` StatHat string `goptions:"--stathat, description='Enable StatHat tracking and set user key'"` Topic string `goptions:"--topic, description='Topic to which uploads shall be published for conversions'"` NSQAddr string `goptions:"--nsqd, description='address:port of nsqd to publish messages to'"` PersonaAudience string `goptions:"--persona-audience, description='Persona audience, e.g. http://localhost:8080'"` }{ Addr: "[::]:8080", RedisAddr: ":6379", } goptions.ParseAndFail(&options) if options.StatHat != "" { enableStatHat = true stathatUserKey = options.StatHat } xlog.Debug("Creating cookie store...") sessionStore := sessions.NewCookieStore([]byte(options.HashKey), []byte(options.BlockKey)) secureCookie := securecookie.New([]byte(options.HashKey), []byte(options.BlockKey)) auth.Config.CookieSecret = []byte(options.HashKey) auth.Config.LoginSuccessRedirect = "/api/connect" auth.Config.CookieSecure = false xlog.Debugf("Connecting to database %s...", options.DSN) var dbStore *Store if sqldb, err := sql.Open("mysql", options.DSN); err != nil { xlog.Fatalf("sql.Open failed: %v", err) } else { dbStore = NewStore(sqldb) } fileStore := &FileUploadStore{UploadDir: options.UploadDir, TmpDir: options.TmpDir, Topic: options.Topic, NSQ: nsq.NewWriter(options.NSQAddr)} xlog.Debugf("Creating upload directory %s...", options.UploadDir) os.Mkdir(options.UploadDir, 0755) os.Mkdir(options.TmpDir, 0755) xlog.Debugf("Setting up HTTP server...") mux := http.NewServeMux() // auth calls mux.Handle("/auth/gplus", auth.Google(options.GplusClientID, options.GplusClientSecret, options.GPlusAuthURL)) mux.Handle("/auth/twitter", auth.Twitter(options.TwitterClientKey, options.TwitterClientSecret, options.TwitterAuthURL)) mux.Handle("/auth/persona", &PersonaAuthHandler{Audience: options.PersonaAudience, SessionStore: sessionStore, DBStore: dbStore, SecureCookie: secureCookie}) // API calls. apiRouter := pat.New() apiRouter.Get("/api/loggedin", &LoggedInHandler{SessionStore: sessionStore}) apiRouter.Get("/api/connect", http.HandlerFunc(auth.SecureUser(func(w http.ResponseWriter, r *http.Request, u auth.User) { Connect(w, r, u, sessionStore, secureCookie, dbStore) }))) apiRouter.Get("/api/connected", &ConnectedHandler{SessionStore: sessionStore, DBStore: dbStore}) apiRouter.Post("/api/disconnect", &DisconnectHandler{SessionStore: sessionStore, SecureCookie: secureCookie}) apiRouter.Post("/api/upload", &UploadHandler{SessionStore: sessionStore, DBStore: dbStore, UploadStore: fileStore, SecureCookie: secureCookie}) apiRouter.Get("/api/getuploads", &GetUploadsHandler{SessionStore: sessionStore, DBStore: dbStore}) apiRouter.Post("/api/renameupload", &RenameUploadHandler{SessionStore: sessionStore, DBStore: dbStore, SecureCookie: secureCookie}) apiRouter.Post("/api/delupload", &DeleteUploadHandler{SessionStore: sessionStore, DBStore: dbStore, SecureCookie: secureCookie, UploadStore: fileStore}) apiRouter.Post("/api/startsession", &StartSessionHandler{SessionStore: sessionStore, DBStore: dbStore, SecureCookie: secureCookie}) apiRouter.Post("/api/stopsession", &StopSessionHandler{SessionStore: sessionStore, DBStore: dbStore, SecureCookie: secureCookie, RedisAddr: options.RedisAddr}) apiRouter.Post("/api/delsession", &DeleteSessionHandler{SessionStore: sessionStore, DBStore: dbStore, SecureCookie: secureCookie}) apiRouter.Get("/api/getsessions", &GetSessionsHandler{SessionStore: sessionStore, DBStore: dbStore}) apiRouter.Get("/api/sessioninfo/:id", &GetSessionInfoHandler{SessionStore: sessionStore, DBStore: dbStore}) mux.Handle("/api/ws", websocket.Handler(func(c *websocket.Conn) { WebsocketHandler(c, dbStore, sessionStore, options.RedisAddr) })) // let all API things go through autogzip. mux.Handle("/api/", autogzip.Handle(apiRouter)) // deliver index.html through autogzip. deliverIndex := autogzip.HandleFunc(func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, path.Join(options.HtdocsDir, "index.html")) }) // deliver index.html for AngularJS routes. mux.HandleFunc("/v/", deliverIndex) mux.HandleFunc("/s/", deliverIndex) // XXX make sure that files from /userdata/ don't go through autogzip. That messes up // the load progress of pdf.js. mux.Handle("/userdata/", http.StripPrefix("/userdata/", fileStore)) mux.HandleFunc("/contact", deliverIndex) mux.HandleFunc("/tos", deliverIndex) mux.HandleFunc("/settings", deliverIndex) // deliver static files from htdocs, autogzip'd. mux.Handle("/", autogzip.Handle(http.FileServer(http.Dir(options.HtdocsDir)))) handler := http.Handler(mux) if options.AccessLog { handler = Logger(handler) } l, ppid, err := goagain.GetEnvs() if err != nil { StatCount("satsuma start", 1) xlog.Debugf("Starting HTTP server on %s", options.Addr) laddr, err := net.ResolveTCPAddr("tcp", options.Addr) if err != nil { xlog.Fatalf("net.ResolveTCPAddr failed: %v", err) } l, err = net.ListenTCP("tcp", laddr) if err != nil { xlog.Fatalf("net.ListenTCP failed: %v", err) } go http.Serve(l, handler) } else { StatCount("satsuma reload", 1) go http.Serve(l, handler) if err := goagain.KillParent(ppid); err != nil { xlog.Fatalf("goagain.KillParent failed: %v", err) } } if err := goagain.AwaitSignals(l); nil != err { xlog.Fatalf("goagain.AwaitSignals failed: %v", err) } if err := l.Close(); err != nil { xlog.Fatalf("Closing listening socket failed: %v", err) } // TODO: make sure all requests are finished before exiting, e.g. through a common waitgroup. time.Sleep(1 * time.Second) }
// Remove removes an uploaded file from the file store. func (store *FileUploadStore) Remove(uploadID string) { filePath := path.Join(store.UploadDir, uploadID+".pdf") xlog.Debugf("FileUploadStore: remove %s", filePath) os.Remove(filePath) }
func (h *UploadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { /* // re-enable as soon as ng-upload can do that. if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) { return } */ session, err := h.SessionStore.Get(r, SESSIONNAME) if err != nil { xlog.Debugf("Getting session failed: %v", err) StatCount("getting session failed", 1) http.Error(w, err.Error(), http.StatusForbidden) return } if session.Values["userID"] == nil { http.Error(w, "authentication required", http.StatusForbidden) return } if err := r.ParseMultipartForm(10 * 1024 * 1024); err != nil { http.Error(w, "couldn't parse form", http.StatusInternalServerError) return } StatCount("upload presentation", 1) title := r.FormValue("title") if title == "" { http.Error(w, "empty title", http.StatusNotAcceptable) return } file, fhdr, err := r.FormFile("file") if err != nil { http.Error(w, "couldn't read form", http.StatusInternalServerError) return } id := generateID() conversion := "success" if isPDF, err := h.UploadStore.Store(id, file, fhdr.Filename); err != nil { xlog.Errorf("Storing file for upload %s failed: %v", id, err) http.Error(w, err.Error(), http.StatusInternalServerError) } else if !isPDF { conversion = "progress" } if err := h.DBStore.InsertUpload(&Upload{ PublicID: id, UserID: session.Values["userID"].(int), Title: title, Uploaded: time.Now(), Conversion: conversion, }); err != nil { xlog.Errorf("Insert failed: %v", err) http.Error(w, "insert failed", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{"id": id}) }