From c9c5a01c07c428800249f2880e8467c196f694cf Mon Sep 17 00:00:00 2001 From: Guillaume Horel Date: Sun, 25 Jun 2017 18:44:37 -0400 Subject: Progress on AuthGetSession --- main.go | 1 + modern.go | 109 ++++++++++++++++++++++++++++++++++++++++++++------------------ web.go | 29 +++++++++++++++++ 3 files changed, 107 insertions(+), 32 deletions(-) diff --git a/main.go b/main.go index b2c221c..875c022 100644 --- a/main.go +++ b/main.go @@ -75,6 +75,7 @@ func (app *App) InitWebServer() *http.Server { sm.HandleFunc("/callback", logg(app.callback)) sm.HandleFunc("/login", logg(app.login)) sm.HandleFunc("/settings", logg(app.settings)) + sm.HandleFunc("/api/auth/", logg(app.auth)) webServer.Addr = ":8000" webServer.Handler = sm return webServer diff --git a/modern.go b/modern.go index cbfbcd3..83feb5d 100644 --- a/modern.go +++ b/modern.go @@ -4,15 +4,17 @@ import ( "database/sql/driver" "encoding/json" "encoding/xml" + "errors" "fmt" "net/http" "strings" + "time" ) type Api interface { - AuthGetToken(*http.Request) ApiResponse - AuthGetSession(*http.Request) ApiResponse - AuthGetMobileSession(*http.Request) ApiResponse + AuthGetToken(*http.Request) (ApiResponse, error) + AuthGetSession(*http.Request) (ApiResponse, error) + AuthGetMobileSession(*http.Request) (ApiResponse, error) TrackScrobble(*http.Request) (ApiResponse, error) } @@ -27,17 +29,15 @@ func (s Scrobbles) MarshalJSON() ([]byte, error) { }{Tag: SuspendScrobbles(s)}) } -func (s *Session) MarshalJSON() ([]byte, error) { - return json.Marshal(s) -} - type Name struct { XMLName xml.Name } type Token struct { - XMLName xml.Name `xml:"token" json:"-"` - Val string `xml:",innerxml" json:"token"` + XMLName xml.Name `xml:"token" json:"-"` + Val string `xml:",innerxml" json:"token"` + Created time.Time `xml:"-" json:"-"` + UserId int `xml:"-" json:"-"` } type LFMResponse struct { @@ -80,34 +80,76 @@ func (n Name) getName() string { return n.XMLName.Local } -func (store *SqlStore) AuthGetToken(r *http.Request) ApiResponse { - token := Token{Val: randomToken(16)} - return token +func (store *SqlStore) AuthGetToken(r *http.Request) (ApiResponse, error) { + if token, err := store.NewToken(); err != nil { + return nil, err + } else { + return Token{Val: token}, nil + } } -func (store *SqlStore) AuthGetMobileSession(r *http.Request) ApiResponse { - return struct{}{} +func (store *SqlStore) AuthGetMobileSession(r *http.Request) (ApiResponse, error) { + return nil, nil } -func (store *SqlStore) AuthGetSession(r *http.Request) ApiResponse { - var response struct { - Session *Session `json:"session"` +func (store *SqlStore) VerifySig(r *http.Request) error { + key := r.FormValue("api_key") + token := r.FormValue("token") + sig := r.FormValue("api_sig") + method := r.FormValue("method") + if c, err := store.GetClient(key); err != nil { + return errors.New("Invalid API key") + } else { + to_hash := fmt.Sprintf("api_key%smethod%stoken%s%s", + key, method, token, c.Secret) + if md5hex(to_hash) == sig { + return nil + } else { + return errors.New("Invalid method signature supplied") + } } - session := &Session{ - User: "thibauthorel", - Client: r.FormValue("api_key"), - Protocol: "2.0", - Key: randomToken(16), +} + +func (store *SqlStore) AuthGetSession(r *http.Request) (ApiResponse, error) { + if err := store.VerifySig(r); err == nil { + if token, err := store.GetToken(r.FormValue("token")); err != nil { + // FIXME: error 4 + return nil, errors.New("Invalid authentication token supplied") + } else { + if time.Since(token.Created) > 5*time.Minute { + // FIXME: error 15 + return nil, errors.New("This token has expired") + } else { + if token.UserId != 0 { + user := &User{Id: token.UserId} + if err := store.GetUser(user); err != nil { + return nil, err + } else { + session := &Session{ + User: user.Name, + Key: randomToken(16), + Client: r.FormValue("api_key"), + UserId: user.Id, + Protocol: "2.0", + } + store.PutSession(session) + return session, nil + } + } else { + //FIXME: error 14 + return nil, errors.New("This token has not been authorized") + } + } + } + } else { + return nil, err } - store.PutSession(session) - response.Session = session - return response } func (store *SqlStore) TrackScrobble(r *http.Request) (ApiResponse, error) { if session, err := store.GetSession(r.FormValue("sk")); err != nil { fmt.Printf("%v\n", err) - return struct{}{}, err + return nil, err } else { scrobbles, ignored := parseScrobbles(r.Form, session) store.PutScrobbles(scrobbles) @@ -119,18 +161,21 @@ func (store *SqlStore) TrackScrobble(r *http.Request) (ApiResponse, error) { func (app *App) ApiHandler(w http.ResponseWriter, r *http.Request) { method := r.FormValue("method") var response ApiResponse + var err error switch strings.ToLower(method) { case "auth.gettoken": - response = app.AuthGetToken(r) + response, err = app.AuthGetToken(r) + if err != nil { + fmt.Printf("%v\n", err) + } case "auth.getsession": - response = app.AuthGetSession(r) + response, err = app.AuthGetSession(r) case "auth.getmobilesession": - response = app.AuthGetSession(r) + response, err = app.AuthGetMobileSession(r) case "track.scrobble": - if r, err := app.DataStore.TrackScrobble(r); err != nil { + response, err = app.TrackScrobble(r) + if err != nil { fmt.Printf("%v\n", err) - } else { - response = r } } var text []byte diff --git a/web.go b/web.go index 25f7b8f..1646b31 100644 --- a/web.go +++ b/web.go @@ -96,6 +96,11 @@ func (app *App) callback(w http.ResponseWriter, r *http.Request) { s.UserName = user.Name app.InsertUserSession(s) app.SetCookie(w, "session", s, 86400*30) + var lfmtoken string + app.GetCookie(r, "lfmtoken", &lfmtoken) + if lfmtoken != "" { + http.Redirect(w, r, "api/auth", http.StatusTemporaryRedirect) + } if newUser { http.Redirect(w, r, "/settings", http.StatusTemporaryRedirect) } else { @@ -103,6 +108,30 @@ func (app *App) callback(w http.ResponseWriter, r *http.Request) { } } +func (app *App) auth(w http.ResponseWriter, r *http.Request) { + se := new(UserSession) + err := app.GetCookie(r, "session", se) + if err != nil { + app.SetCookie(w, "lfmtoken", r.FormValue("token"), 120) + app.SetCookie(w, "lfmkey", r.FormValue("api_key"), 120) + http.Redirect(w, r, "/login", http.StatusFound) + return + } + key := r.FormValue("api_key") + if c, err := app.GetClient(key); err != nil { + fmt.Printf("%v\n", err) + } else { + if token, err := app.GetToken(r.FormValue("token")); err != nil { + return + } else { + token.UserId = se.UserId + app.PutToken(token) + app.Template.ExecuteTemplate(w, "auth.tmpl", c.Name) + } + } + return +} + func (app *App) settings(w http.ResponseWriter, r *http.Request) { se := new(UserSession) err := app.GetCookie(r, "session", se) -- cgit v1.2.3-70-g09d2