[feature] Implement /api/v2/instance endpoint (#1409)

* interim: start adding /api/v2/instance

* finish up
This commit is contained in:
tobi 2023-02-02 14:08:13 +01:00 committed by GitHub
commit 382512a5a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
109 changed files with 1660 additions and 944 deletions

View file

@ -29,7 +29,6 @@ import (
"github.com/google/uuid"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@ -43,7 +42,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
s := sessions.Default(c)
if _, err := apiutil.NegotiateAccept(c, apiutil.HTMLAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
return
}
@ -54,13 +53,13 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
form := &apimodel.OAuthAuthorize{}
if err := c.ShouldBind(form); err != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
if errWithCode := saveAuthFormToSession(s, form); errWithCode != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -73,7 +72,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
if !ok || clientID == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionClientID)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
@ -87,7 +86,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -101,7 +100,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -115,7 +114,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -128,7 +127,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
if !ok || redirect == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionRedirectURI)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
@ -136,13 +135,13 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
if !ok || scope == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionScope)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
instance, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -206,7 +205,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
if len(errs) != 0 {
errs = append(errs, oauth.HelpfulAdvice)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during AuthorizePOSTHandler"), errs...), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during AuthorizePOSTHandler"), errs...), m.processor.InstanceGetV1)
return
}
@ -220,7 +219,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -234,7 +233,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -263,7 +262,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
}
if errWithCode := m.processor.OAuthHandleAuthorizeRequest(c.Writer, c.Request); errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
}
}

View file

@ -49,7 +49,7 @@ type extraInfo struct {
func (m *Module) CallbackGETHandler(c *gin.Context) {
if !config.GetOIDCEnabled() {
err := errors.New("oidc is not enabled for this server")
apiutil.ErrorHandler(c, gtserror.NewErrorNotFound(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotFound(err, err.Error()), m.processor.InstanceGetV1)
return
}
@ -62,7 +62,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if returnedInternalState == "" {
m.clearSession(s)
err := fmt.Errorf("%s parameter not found on callback query", callbackStateParam)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
return
}
@ -71,14 +71,14 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if !ok {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionInternalState)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
return
}
if returnedInternalState != savedInternalState {
m.clearSession(s)
err := errors.New("mismatch between callback state and saved state")
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
return
}
@ -87,14 +87,14 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if code == "" {
m.clearSession(s)
err := fmt.Errorf("%s parameter not found on callback query", callbackCodeParam)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
return
}
claims, errWithCode := m.idp.HandleCallback(c.Request.Context(), code)
if errWithCode != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -104,7 +104,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if !ok || clientID == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionClientID)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
@ -118,21 +118,21 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
user, errWithCode := m.fetchUserForClaims(c.Request.Context(), claims, net.IP(c.ClientIP()), app.ID)
if errWithCode != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
if user == nil {
// no user exists yet - let's ask them for their preferred username
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
instance, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -141,7 +141,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
s.Set(sessionAppID, app.ID)
if err := s.Save(); err != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGetV1)
return
}
c.HTML(http.StatusOK, "finalize.tmpl", gin.H{
@ -154,7 +154,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
s.Set(sessionUserID, user.ID)
if err := s.Save(); err != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGetV1)
return
}
c.Redirect(http.StatusFound, "/oauth"+OauthAuthorizePath)
@ -167,15 +167,15 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
form := &extraInfo{}
if err := c.ShouldBind(form); err != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
// since we have multiple possible validation error, `validationError` is a shorthand for rendering them
validationError := func(err error) {
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
instance, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
c.HTML(http.StatusOK, "finalize.tmpl", gin.H{
@ -195,7 +195,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
// see if the username is still available
usernameAvailable, err := m.db.IsUsernameAvailable(c.Request.Context(), form.Username)
if err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
if !usernameAvailable {
@ -207,7 +207,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
appID, ok := s.Get(sessionAppID).(string)
if !ok {
err := fmt.Errorf("key %s was not found in session", sessionAppID)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
@ -215,7 +215,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
claims, ok := s.Get(sessionClaims).(*oidc.Claims)
if !ok {
err := fmt.Errorf("key %s was not found in session", sessionClaims)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
@ -223,7 +223,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
user, errWithCode := m.createUserFromOIDC(c.Request.Context(), claims, form, net.IP(c.ClientIP()), appID)
if errWithCode != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
s.Delete(sessionClaims)
@ -231,7 +231,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
s.Set(sessionUserID, user.ID)
if err := s.Save(); err != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGetV1)
return
}
c.Redirect(http.StatusFound, "/oauth"+OauthAuthorizePath)

View file

@ -28,21 +28,19 @@ import (
"github.com/gin-gonic/gin"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
func (m *Module) OobHandler(c *gin.Context) {
host := config.GetHost()
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), host)
instance, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
instanceGet := func(ctx context.Context, domain string) (*apimodel.Instance, gtserror.WithCode) {
instanceGet := func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode) {
return instance, nil
}
@ -69,7 +67,7 @@ func (m *Module) OobHandler(c *gin.Context) {
if len(errs) != 0 {
errs = append(errs, oauth.HelpfulAdvice)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during OobHandler"), errs...), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during OobHandler"), errs...), m.processor.InstanceGetV1)
return
}

View file

@ -45,14 +45,14 @@ type login struct {
// If an idp provider is set, then the user will be redirected to that to do their sign in.
func (m *Module) SignInGETHandler(c *gin.Context) {
if _, err := apiutil.NegotiateAccept(c, apiutil.HTMLAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
return
}
if !config.GetOIDCEnabled() {
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
instance, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
@ -71,7 +71,7 @@ func (m *Module) SignInGETHandler(c *gin.Context) {
if !ok {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionInternalState)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
return
}
@ -87,7 +87,7 @@ func (m *Module) SignInPOSTHandler(c *gin.Context) {
form := &login{}
if err := c.ShouldBind(form); err != nil {
m.clearSession(s)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
return
}
@ -95,14 +95,14 @@ func (m *Module) SignInPOSTHandler(c *gin.Context) {
if errWithCode != nil {
// don't clear session here, so the user can just press back and try again
// if they accidentally gave the wrong password or something
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
s.Set(sessionUserID, userid)
if err := s.Save(); err != nil {
err := fmt.Errorf("error saving user id onto session: %s", err)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err, oauth.HelpfulAdvice), m.processor.InstanceGetV1)
}
c.Redirect(http.StatusFound, "/oauth"+OauthAuthorizePath)

View file

@ -42,7 +42,7 @@ type tokenRequestForm struct {
// The idea here is to serve an oauth access token to a user, which can be used for authorizing against non-public APIs.
func (m *Module) TokenPOSTHandler(c *gin.Context) {
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
return
}