package main import ( "encoding/json" "golang.org/x/net/context" "golang.org/x/oauth2" "io/ioutil" "net/http" "fmt" "log" "github.com/go-openapi/strfmt" ESI "client" ESIPlanetaryInteraction "client/planetary_interaction" ESISkills "client/skills" httptransport "github.com/go-openapi/runtime/client" //"database/sql" //_ "github.com/mattn/go-sqlite3" ) // Character - Structure to save the verification data. type Character struct { CharacterID int32 CharacterName string ExpiresOn string } var ( googleOauthConfig = &oauth2.Config{ RedirectURL: "http://localhost:3000/callback", ClientID: "CLIENTKEY", ClientSecret: "SECRETKEY", Scopes: []string{ "esi-skills.read_skillqueue.v1", "esi-skills.read_skills.v1", "esi-planets.manage_planets.v1", }, Endpoint: oauth2.Endpoint{ AuthURL: "https://login.eveonline.com/oauth/authorize/", TokenURL: "https://login.eveonline.com/oauth/token/", }, } // Some random string, random for each request oauthStateString = "random" ) var ctx = context.Background() var messages = make(chan *oauth2.Token) func main() { cToken := getDatabaseToken() if cToken == nil { cToken = getNewAuthorizationToken() } client := googleOauthConfig.Client(oauth2.NoContext, cToken) m := getCharacterInfo(client) fmt.Printf("Character id is %d\n", m.CharacterID) getCharacterPlanets(client, m) } func getCharacterInfo(client *http.Client) *Character { req, _ := http.NewRequest("GET", "https://login.eveonline.com/oauth/verify", nil) response, errDo := client.Do(req) if errDo != nil { fmt.Printf("Request error '%s'\n", errDo) return nil } defer response.Body.Close() contents, _ := ioutil.ReadAll(response.Body) var m Character errJSON := json.Unmarshal(contents, &m) if errJSON != nil { fmt.Printf("JSON read error with '%s'\n", errJSON) return nil } fmt.Printf("Name: %s\n", m.CharacterName) fmt.Printf("Id: %d\n", m.CharacterID) return &m } func getCharacterSkillQueue(client *http.Client, m *Character) { // create the transport transport := httptransport.NewWithClient("esi.tech.ccp.is", "/latest", []string{"https"}, client) // create the API client, with the transport swaggerclient := ESI.New(transport, strfmt.Default) charIDSkilqueue := ESISkills.NewGetCharactersCharacterIDSkillqueueParams().WithCharacterID(m.CharacterID) skillqueueresp, _ := swaggerclient.Skills.GetCharactersCharacterIDSkillqueue(charIDSkilqueue, nil) skillqueue := skillqueueresp.Payload for _, skill := range skillqueue { // element is the element from someSlice for where we are name := "UNK-SKILL" level := skill.FinishedLevel id := skill.SkillID startDate := skill.StartDate endDate := skill.FinishDate fmt.Printf(" %s: %d (%d) - %s to %s\n", name, id, *level, startDate, endDate) } } func getCharacterPlanets(client *http.Client, m *Character) { // create the transport transport := httptransport.NewWithClient("esi.tech.ccp.is", "/latest", []string{"https"}, client) // create the API client, with the transport swaggerclient := ESI.New(transport, strfmt.Default) callParam := ESIPlanetaryInteraction.NewGetCharactersCharacterIDPlanetsParams().WithCharacterID(m.CharacterID) esiresponse, _ := swaggerclient.PlanetaryInteraction.GetCharactersCharacterIDPlanets(callParam, nil) planets := esiresponse.Payload for _, planet := range planets { // element is the element from someSlice for where we are name := "UNK-PLANET" solarSystemName := "UNK-SYSTEM" level := planet.UpgradeLevel id := planet.PlanetID solarSystem := planet.SolarSystemID planetType := planet.PlanetType lastUpdate := planet.LastUpdate pins := planet.NumPins pcallParam := ESIPlanetaryInteraction.NewGetCharactersCharacterIDPlanetsPlanetIDParams().WithCharacterID(m.CharacterID).WithPlanetID(*id) fmt.Printf(" %s (%d) %s (%d) - %s, level %d with %d structures - %s\n", name, *id, solarSystemName, *solarSystem, *planetType, *level, *pins, lastUpdate, ) pesiresponse, _ := swaggerclient.PlanetaryInteraction.GetCharactersCharacterIDPlanetsPlanetID(pcallParam, nil) for _, pin := range pesiresponse.Payload.Pins { if pin.ExtractorDetails != nil { fmt.Printf(" Extractor %d (%s), cycles of %d, %d per cycle\n", *pin.PinID, pin.LastCycleStart, *pin.ExtractorDetails.CycleTime, *pin.ExtractorDetails.QtyPerCycle, ) } else if pin.SchematicID != 0 { // Get the schematic from ESI and cache it fmt.Printf(" Factory %d (%s) %d\n", *pin.PinID, pin.LastCycleStart, pin.SchematicID, ) } else { /* fmt.Printf(" %d %d (%s)\n%v\n", *pin.TypeID, *pin.PinID, pin.LastCycleStart, pin) */ } } } } func getNewAuthorizationToken() *oauth2.Token { http.HandleFunc("/", handleLogin) http.HandleFunc("/callback", handleAuthenticationCallback) go func() { log.Println("No available token. Please visit http://localhost:3000 to renew.") http.ListenAndServe(":3000", nil) }() return <-messages } func handleLogin(w http.ResponseWriter, r *http.Request) { url := googleOauthConfig.AuthCodeURL(oauthStateString, oauth2.AccessTypeOffline) // https://eveonline-third-party-documentation.readthedocs.io/en/latest/sso/authentication.html // response_type: Must be set to “code”. url = url + "&response_type=code" http.Redirect(w, r, url, http.StatusTemporaryRedirect) } func handleAuthenticationCallback(w http.ResponseWriter, r *http.Request) { state := r.FormValue("state") if state != oauthStateString { log.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) // No token to pass, we will get one on the second pass return } code := r.FormValue("code") token, err := googleOauthConfig.Exchange(oauth2.NoContext, code) if err != nil { log.Printf("Code exchange failed with '%s'\n", err) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) // No token to pass, we will get one on the second pass return } client := googleOauthConfig.Client(oauth2.NoContext, token) req, _ := http.NewRequest("GET", "https://login.eveonline.com/oauth/verify", nil) response, _ := client.Do(req) defer response.Body.Close() contents, _ := ioutil.ReadAll(response.Body) var m Character errJSON := json.Unmarshal(contents, &m) if errJSON != nil { fmt.Printf("JSON read error with '%s'\n", errJSON) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) return } fmt.Fprintf(w, "Got token for character %s.\n", m.CharacterName) fmt.Fprintf(w, "You can now close this navigator tab.\n") log.Printf("Refresh token is %s\n", token.RefreshToken) messages <- token } func getDatabaseToken() *oauth2.Token { /* db, err := sql.Open("sqlite3", "./foo.db") defer db.Close() _, err = db.Exec("CREATE TABLE IF NOT EXISTS properties (id text NOT NULL PRIMARY KEY, value TEXT);") if err != nil { log.Fatal(err) } stmt, err := db.Prepare("SELECT value FROM properties WHERE id = ?") if err != nil { log.Fatal(err) } defer stmt.Close() var refreshToken string err = stmt.QueryRow("refreshToken").Scan(&refreshToken) if err != nil { refreshToken = "" } fmt.Println("Found token :" + refreshToken) return refreshToken */ log.Print("Using hardcoded refresh token") token := new(oauth2.Token) token.RefreshToken = "4sNssL9aVy6Sqf8JUT6Q1hPQjo1lpzJ0mrPIB417QFdz6YooWl9g78qaH2DkZVwq0" token.TokenType = "Bearer" return token }