Esempio n. 1
0
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)
		}
	}
}
Esempio n. 2
0
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)
}
Esempio n. 3
0
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)
}
Esempio n. 4
0
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()
}
Esempio n. 5
0
// 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
}
Esempio n. 6
0
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)
}
Esempio n. 7
0
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)
}
Esempio n. 8
0
// 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
}
Esempio n. 9
0
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})
}
Esempio n. 10
0
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")
}
Esempio n. 11
0
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
}
Esempio n. 12
0
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)
}
Esempio n. 13
0
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)
}
Esempio n. 14
0
// 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)
	}
}
Esempio n. 15
0
// 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
}
Esempio n. 16
0
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)
}
Esempio n. 17
0
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)
	}
}
Esempio n. 18
0
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)
}
Esempio n. 19
0
// 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)
}
Esempio n. 20
0
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})
}