Beispiel #1
0
// AuthenticateHandler returns a web handler function that redirects to a
// session-specific authentication link.
func AuthenticateHandler(auth evesso.Authenticator, sess server.Sessionizer) web.HandlerFunc {
	return func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		url := auth.URL(s.State)
		http.Redirect(w, r, url, http.StatusFound)
	}
}
Beispiel #2
0
// UnusedSalvage returns a web handler function that identifies a user's salvage
// drops that are unused by any blueprint they own.
func UnusedSalvage(localdb db.LocalDB, sde evego.Database, sess server.Sessionizer) web.HandlerFunc {
	return func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		myUserID := s.User
		charID, err := strconv.Atoi(c.URLParams["charID"])
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Invalid character ID supplied."}`,
				http.StatusBadRequest)
			return
		}
		salvage, err := localdb.UnusedSalvage(myUserID, charID)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Unable to access database."}`,
				http.StatusInternalServerError)
			log.Printf("Error accessing database with user %v, character %v: %v", myUserID, charID, err)
			return
		}
		stations := make(map[string]*evego.Station)
		itemInfo := make(map[string]*evego.Item)
		for i := range salvage {
			item := &salvage[i]
			if _, found := stations[strconv.Itoa(item.StationID)]; !found {
				stn, err := localdb.StationForID(item.StationID)
				if err == nil {
					stations[strconv.Itoa(item.StationID)] = stn
				} else {
					// This should really not friggin' happen.
					http.Error(w, `{"status": "Error", "error": "Unable to look up station/outpost."}`,
						http.StatusInternalServerError)
					log.Printf("Unable to look up station/outpost ID %v: %v", item.StationID, err)
					return
				}
			}
			typeIDStr := strconv.Itoa(item.TypeID)
			if _, found := itemInfo[typeIDStr]; !found {
				thisItem, err := sde.ItemForID(item.TypeID)
				if err == nil {
					itemInfo[typeIDStr] = thisItem
				}
			}
		}
		response := struct {
			Items    []evego.InventoryItem     `json:"items"`
			Stations map[string]*evego.Station `json:"stations"`
			ItemInfo map[string]*evego.Item    `json:"itemInfo"`
		}{salvage, stations, itemInfo}
		salvageJSON, err := json.Marshal(&response)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Unable to marshal JSON."}`,
				http.StatusInternalServerError)
			log.Printf("Error marshalling JSON unused salvage with user %v, character %v: %v", myUserID, charID, err)
			return
		}
		w.Write(salvageJSON)
		return

	}
}
Beispiel #3
0
// CRESTCallbackListener returns a web handler function that listens for a CREST
// SSO callback and accepts the results of authentication.
func CRESTCallbackListener(localdb db.LocalDB, auth evesso.Authenticator, sess server.Sessionizer) web.HandlerFunc {
	return func(c web.C, w http.ResponseWriter, r *http.Request) {
		// Verify state value.
		s := sess.GetSession(&c, w, r)
		passedState := r.FormValue("state")
		if passedState != s.State {
			// CSRF attempt or session expired; reject.
			http.Error(w, "Returned state not valid for this user.", http.StatusBadRequest)
			log.Printf("Got state %#v, expected state %#v", passedState, s.State)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		// Extract code from query parameters.
		code := r.FormValue("code")
		// Exchange it for a token.
		tok, err := auth.Exchange(code)
		if err != nil {
			http.Error(w, `{"status": "Error"}`, http.StatusInternalServerError)
			log.Printf("Error exchanging token: %v", err)
			return
		}
		// Get character information.
		charInfo, err := auth.CharacterInfo(tok)
		if err != nil {
			http.Error(w, `{"status": "Error"}`, http.StatusInternalServerError)
			log.Printf("Error getting character information: %v; token was %+v", err, tok)
			return
		}

		// Update session in database.
		err = localdb.AuthenticateSession(s.Cookie, tok, charInfo)
		if err != nil {
			http.Error(w, `{"status": "Error"}`, http.StatusInternalServerError)
			log.Printf("Unable to update session post-auth: %v; info was %+v", err, charInfo)
			return
		}
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`
			<html>
				<head>
					<title>Authenticated</title>
				</head>
				<body>
					<p>OK.</p>
					<script type="text/javascript">
						window.onload = function() {
							window.opener.hasAuthenticated();
							window.close();
						}
					</script>
				</body>
			</html>
			`))
	}
}
Beispiel #4
0
// LogoutHandler returns a web handler function that deletes the user's
// sessions.
func LogoutHandler(localdb db.LocalDB, auth evesso.Authenticator, sess server.Sessionizer) web.HandlerFunc {
	successMsg := []byte("{ \"success\": true }")
	return func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		err := localdb.LogoutSession(s.Cookie)
		if err != nil {
			http.Error(w, "Unable to find session", http.StatusTeapot)
			log.Printf("Error logging out: %v", err)
			return
		}
		// Serve some JSON that confirms success.
		w.Write(successMsg)
	}
}
Beispiel #5
0
// StandingsHandler returns a web handler function that provides information on
// the user's toons' effective standings.
func StandingsHandler(localdb db.LocalDB, sess server.Sessionizer) web.HandlerFunc {
	standingsFunc := func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		userID := s.User
		charID, _ := strconv.Atoi(c.URLParams["charID"])
		npcCorpID, _ := strconv.Atoi(c.URLParams["npcCorpID"])
		corpStanding, facStanding, err := localdb.CharacterStandings(userID, charID, npcCorpID)
		if err != nil {
			errorStr := "Unable to get character standings."
			if err == sql.ErrNoRows {
				errorStr = "Invalid corporation ID passed."
			}
			http.Error(w, fmt.Sprintf(`{"status": "Error", "error": "%v"}`, errorStr),
				http.StatusInternalServerError)
			return
		}
		connections, err := localdb.CharacterSkill(userID, charID, connectionsSkillID)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Ouch"}`,
				http.StatusInternalServerError)
			return
		}
		diplomacy, err := localdb.CharacterSkill(userID, charID, diplomacySkillID)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Ouch"}`,
				http.StatusInternalServerError)
			return
		}
		effectiveStanding := character.EffectiveStanding(corpStanding, facStanding, connections, diplomacy)
		statusMsg := struct {
			Status            string  `json:"status"`
			EffectiveStanding float64 `json:"standing"`
		}{
			"OK",
			effectiveStanding,
		}

		statusJSON, _ := json.Marshal(&statusMsg)
		w.Write(statusJSON)
		return
	}

	return standingsFunc
}
Beispiel #6
0
// SessionInfo returns a web handler function that returns information about the
// current session.
func SessionInfo(auth evesso.Authenticator, sess server.Sessionizer, localdb db.LocalDB) web.HandlerFunc {
	return func(c web.C, w http.ResponseWriter, r *http.Request) {
		curSession := sess.GetSession(&c, w, r)
		returnInfo := sessionInfo{
			Authenticated: curSession.User != 0,
			OAuthURL:      auth.URL(curSession.State),
		}
		if curSession.Token != nil {
			returnInfo.OAuthExpiry = curSession.Token.Expiry
		}
		if curSession.User != 0 {
			// We're authenticated - also pass in the API keys registered to this
			// user.
			keys, err := localdb.APIKeys(curSession.User)
			if err != nil {
				log.Fatalf("Error - unable to retrieve API keys from database.")
			}
			returnInfo.APIKeys = keys
		}
		returnJSON, _ := json.Marshal(&returnInfo)
		w.Write(returnJSON)
	}
}
Beispiel #7
0
// BlueprintsHandlers returns web handler functions that provide information on
// a toon's bluerpints.
func BlueprintsHandlers(localdb db.LocalDB, sde evego.Database, sess server.Sessionizer) (refresh, get web.HandlerFunc) {
	refresh = func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		myUserID := s.User
		charID, _ := strconv.Atoi(c.URLParams["charID"])
		apiKeys, err := localdb.APIKeys(myUserID)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Ouch"}`,
				http.StatusInternalServerError)
			return
		}
		// Find the key for this character.
		var myKey *db.XMLAPIKey
		for _, key := range apiKeys {
			for _, toon := range key.Characters {
				if toon.ID == charID {
					myKey = &key
					break
				}
			}
		}
		if myKey == nil {
			if err != nil {
				http.Error(w, `{"status": "Error", "error": "Invalid character supplied."}`,
					http.StatusUnauthorized)
				return
			}
		}

		err = localdb.GetAssetsBlueprints(*myKey, charID)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Ouch"}`,
				http.StatusInternalServerError)
			return
		}
		return
	}

	get = func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		myUserID := s.User
		charID, err := strconv.Atoi(c.URLParams["charID"])
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Invalid character ID supplied."}`,
				http.StatusBadRequest)
			return
		}
		blueprints, err := localdb.CharacterBlueprints(myUserID, charID)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Unable to access database."}`,
				http.StatusInternalServerError)
			log.Printf("Error accessing database with user %v, character %v: %v", myUserID, charID, err)
			return
		}
		stations := make(map[string]*evego.Station)
		for i := range blueprints {
			bp := &blueprints[i]
			if _, found := stations[strconv.Itoa(bp.StationID)]; !found {
				stn, err := localdb.StationForID(bp.StationID)
				if err == nil {
					stations[strconv.Itoa(bp.StationID)] = stn
				}
			}
		}
		response := struct {
			Blueprints []evego.BlueprintItem     `json:"blueprints"`
			Stations   map[string]*evego.Station `json:"stations"`
		}{blueprints, stations}
		blueprintsJSON, err := json.Marshal(&response)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Unable to marshal JSON."}`,
				http.StatusInternalServerError)
			log.Printf("Error marshalling JSON blueprints with user %v, character %v: %v", myUserID, charID, err)
			return
		}
		w.Write(blueprintsJSON)
		return
	}

	return
}
Beispiel #8
0
// XMLAPIKeysHandlers returns web handler functions that provide information on
// the user's API keys that have been registered with this application.
func XMLAPIKeysHandlers(localdb db.LocalDB, sess server.Sessionizer) (list, delete, add, refresh web.HandlerFunc) {
	// charRefresh refreshes the characters associated with an API key and returns
	// the current list of characters via the passed responseWriter.
	charRefresh := func(s *db.Session, key *db.XMLAPIKey, w http.ResponseWriter) {
		toons, err := localdb.GetAPICharacters(s.User, *key)
		if err != nil {
			http.Error(w, `{"status": "Error", "error": "Database connection error (add characters)"}`,
				http.StatusInternalServerError)
			return
		}
		for _, toon := range toons {
			// Update skills for this character.
			err = localdb.GetAPISkills(*key, toon.ID)
			if err != nil {
				http.Error(w, `{"status": "Error", "error": "Database connection error (add skills)"}`,
					http.StatusInternalServerError)
				return
			}

			// Update standings.
			err = localdb.GetAPIStandings(*key, toon.ID)
			if err != nil {
				http.Error(w, `{"status": "Error", "error": "Database connection error (add standings)"}`,
					http.StatusInternalServerError)
				return
			}

			// Update assets and blueprints.
			err = localdb.GetAssetsBlueprints(*key, toon.ID)
			if err != nil {
				http.Error(w, `{"status": "Error", "error": "Database connection error (add assets)"}`,
					http.StatusInternalServerError)
				log.Printf("Got error in GetAssets: %v", err)
				return
			}

		}
		response := struct {
			Status     string            `json:"status"`
			Characters []evego.Character `json:"characters"`
		}{
			Status:     "OK",
			Characters: toons,
		}
		responseJSON, err := json.Marshal(response)
		w.Write(responseJSON)
		return
	}

	list = func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		userKeys, err := localdb.APIKeys(s.User)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		userKeysJSON, err := json.Marshal(userKeys)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		w.Write(userKeysJSON)
	}

	delete = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		keyID, _ := strconv.Atoi(c.URLParams["keyid"])
		err := localdb.DeleteAPIKey(s.User, keyID)
		if err != nil {
			http.Error(w, "Database connection error", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		w.Write([]byte(`{"status": "OK"}`))
		return
	}

	add = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		key, err := unmarshalKey(r, w)
		if err != nil {
			return
		}
		// Ensure that this key is added under the session's user's account.
		key.User = s.User

		err = localdb.AddAPIKey(*key)
		if err != nil {
			http.Error(w, "Database connection error (add key)", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}

		charRefresh(s, key, w)
		return
	}

	refresh = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		key, err := unmarshalKey(r, w)
		if err != nil {
			return
		}

		// Ensure that this key is added under the session's user's account.
		key.User = s.User
		charRefresh(s, key, w)
		return
	}

	return
}