コード例 #1
0
ファイル: websocket.go プロジェクト: joinmytalk/satsuma
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)
		}
	}
}
コード例 #2
0
ファイル: pdfd.go プロジェクト: joinmytalk/satsuma
func ConvertFileToPDF(src, target string) error {
	cmd := exec.Command("unoconv", "-f", "pdf", "--stdout", src)
	// cmd := exec.Command("cat", src)
	f, err := os.OpenFile(target, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return err
	}

	defer f.Close()
	stdout, _ := cmd.StdoutPipe()
	err = cmd.Start()
	if err != nil {
		xlog.Errorf("running unoconv failed: %v", err)
		return err
	}
	io.Copy(f, stdout)
	err = cmd.Wait()
	if err != nil {
		xlog.Errorf("cmd.Wait returned error: %v", err)
		return err
	}
	fi, _ := f.Stat()
	if fi.Size() == 0 {
		os.Remove(target)
		xlog.Error("file resulting from conversion is empty")
		return errors.New("empty file")
	}

	return nil
}
コード例 #3
0
ファイル: session.go プロジェクト: joinmytalk/satsuma
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})
}
コード例 #4
0
ファイル: login.go プロジェクト: joinmytalk/satsuma
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)
}
コード例 #5
0
ファイル: upload.go プロジェクト: joinmytalk/satsuma
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)
}
コード例 #6
0
ファイル: login.go プロジェクト: joinmytalk/satsuma
func (h *DisconnectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	StatCount("disconnect call", 1)
	if !VerifyXSRFToken(w, r, h.SessionStore, h.SecureCookie) {
		return
	}

	// Only disconnect a connected user
	session, err := h.SessionStore.Get(r, SESSIONNAME)
	if err != nil {
		xlog.Errorf("Error fetching session: %v", err)
		http.Error(w, "Error fetching session", 500)
		return
	}
	token := session.Values["username"]
	if token == nil {
		http.Error(w, "Current user not connected", 401)
		return
	}

	// Reset the user's session
	session.Values["userID"] = nil
	session.Values["username"] = nil
	session.Values["name"] = nil
	session.Values["email"] = nil
	session.Save(r, w)
	w.WriteHeader(http.StatusNoContent)
}
コード例 #7
0
ファイル: pdfd.go プロジェクト: joinmytalk/satsuma
func main() {
	xlog.SetOutput(os.Stdout)

	options := struct {
		Topic   string `goptions:"--topic, description='Topic', obligatory"`
		Channel string `goptions:"--channel, description='Channel', obligatory"`
		Lookupd string `goptions:"--lookupd, description='lookupd address', obligatory"`
		DSN     string `goptions:"--dsn, description='MySQL DSN string', obligatory"`
	}{}

	goptions.ParseAndFail(&options)

	sqldb, err := sql.Open("mysql", options.DSN)
	if err != nil {
		xlog.Fatalf("sql.Open failed: %v", err)
	}

	r, err := nsq.NewReader(options.Topic, options.Channel)
	if err != nil {
		xlog.Fatalf("Opening reader for %s/%s failed: %v", options.Topic, options.Channel, err)
	}

	r.AddHandler(&Converter{DB: sqldb})

	if err := r.ConnectToLookupd(options.Lookupd); err != nil {
		xlog.Errorf("Connecting to %s failed: %v", options.Lookupd, err)
	}

	select {}
}
コード例 #8
0
ファイル: session.go プロジェクト: joinmytalk/satsuma
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)
}
コード例 #9
0
ファイル: session.go プロジェクト: joinmytalk/satsuma
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)
}
コード例 #10
0
ファイル: session.go プロジェクト: joinmytalk/satsuma
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()
}
コード例 #11
0
ファイル: filestore.go プロジェクト: joinmytalk/satsuma
// ConvertFileToPDF attempts to convert a file to PDF.
func (store *FileUploadStore) ConvertFileToPDF(id, src, target string) error {
	msg, _ := json.Marshal(map[string]string{"src_file": src, "target_file": target, "upload_id": id})
	if _, _, err := store.NSQ.Publish(store.Topic, msg); err != nil {
		xlog.Errorf("Queuing message to NSQ %s failed: %v", store.NSQ.Addr, err)
		return err
	}
	return nil
}
コード例 #12
0
ファイル: db.go プロジェクト: joinmytalk/satsuma
// 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
}
コード例 #13
0
ファイル: websocket.go プロジェクト: joinmytalk/satsuma
func executeCommand(cmd Command, dbStore *Store) {
	StatCount("command from master", 1)
	switch cmd.Cmd {
	case "clearSlide":
		if err := dbStore.ClearSlide(cmd.SessionID, cmd.Page); err != nil {
			xlog.Errorf("clearSlide for %d page %d failed: %v", cmd.SessionID, cmd.Page, err)
		}
	}
}
コード例 #14
0
ファイル: login.go プロジェクト: joinmytalk/satsuma
func VerifyXSRFToken(w http.ResponseWriter, r *http.Request, sessionStore sessions.Store, secureCookie *securecookie.SecureCookie) bool {
	xsrftoken := r.Header.Get(XSRFTOKENHEADER)
	userID := ""

	err := secureCookie.Decode(XSRFTOKEN, xsrftoken, &userID)
	if err == nil {
		session, _ := sessionStore.Get(r, SESSIONNAME)

		if userID != "" && userID == session.Values["username"].(string) {
			xlog.Infof("XSRF verification success for user %s", session.Values["username"].(string))
			return true
		}
		xlog.Errorf("XSRF issue: userID = %s session = %s", userID, session.Values["username"].(string))
	}

	xlog.Errorf("XSRF verification failed: %v (Request: %#v", err, *r)
	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
	StatCount("XSRF verification failed", 1)
	return false
}
コード例 #15
0
ファイル: websocket.go プロジェクト: joinmytalk/satsuma
// 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)
	}
}
コード例 #16
0
ファイル: pdfd.go プロジェクト: joinmytalk/satsuma
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
}
コード例 #17
0
ファイル: websocket.go プロジェクト: joinmytalk/satsuma
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")
}
コード例 #18
0
ファイル: login.go プロジェクト: joinmytalk/satsuma
func (h *LoggedInHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	StatCount("loggedin call", 1)
	jsonEncoder := json.NewEncoder(w)
	session, err := h.SessionStore.Get(r, SESSIONNAME)
	if err != nil {
		w.Header().Set("Content-Type", "application/json")
		jsonEncoder.Encode(map[string]bool{"logged_in": false})
		xlog.Errorf("Error fetching session: %v", err)
		return
	}

	loggedIn := false
	username, ok := session.Values["username"].(string)
	if ok {
		loggedIn = true
	}

	w.Header().Set("Content-Type", "application/json")
	jsonEncoder.Encode(map[string]interface{}{"logged_in": loggedIn, "username": username})
}
コード例 #19
0
ファイル: login.go プロジェクト: joinmytalk/satsuma
func (h *ConnectedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	session, err := h.SessionStore.Get(r, SESSIONNAME)
	if err != nil {
		xlog.Errorf("Error fetching session: %v", err)
		http.Error(w, err.Error(), http.StatusForbidden)
		return
	}

	userID := session.Values["userID"].(int)

	systems := h.DBStore.GetConnectedSystemsForUser(userID)

	jsonData := make(map[string]bool)

	for _, s := range systems {
		jsonData[s] = true
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(jsonData)
}
コード例 #20
0
ファイル: filestore.go プロジェクト: joinmytalk/satsuma
// 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
}
コード例 #21
0
ファイル: db.go プロジェクト: joinmytalk/satsuma
// GetConnectedSystemsForUser returns a slice of auth service identifiers
// for which accounts exist that are associated with the specified userID.
func (s *Store) GetConnectedSystemsForUser(userID int) []string {
	systemMappings := map[string]string{
		"google.com":  "gplus",
		"twitter.com": "twitter",
		"persona":     "persona",
	}

	connectedAccounts := []*struct {
		Username string `meddler:"username"`
	}{}

	if err := meddler.QueryAll(s.sqlDB, &connectedAccounts, "SELECT username FROM accounts WHERE user_id = ?", userID); err != nil {
		xlog.Errorf("Querying usernames for userID %d failed: %v", userID, err)
		return []string{}
	}

	systems := make([]string, 0, len(connectedAccounts))

	for _, acc := range connectedAccounts {
		systems = append(systems, systemMappings[strings.Split(acc.Username, ":")[0]])
	}

	return systems
}
コード例 #22
0
ファイル: persona.go プロジェクト: joinmytalk/satsuma
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)
	}
}
コード例 #23
0
ファイル: upload.go プロジェクト: joinmytalk/satsuma
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})
}