From 71a49e2b43218d34f97b2276c43bdeb2df4a53d2 Mon Sep 17 00:00:00 2001
From: Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com>
Date: Thu, 1 Apr 2021 20:46:45 +0200
Subject: Api/v1/accounts (#8)
* start work on accounts module
* plodding away on the accounts endpoint
* groundwork for other account routes
* add password validator
* validation utils
* require account approval flags
* comments
* comments
* go fmt
* comments
* add distributor stub
* rename api to federator
* tidy a bit
* validate new account requests
* rename r router
* comments
* add domain blocks
* add some more shortcuts
* add some more shortcuts
* check email + username availability
* email block checking for signups
* chunking away at it
* tick off a few more things
* some fiddling with tests
* add mock package
* relocate repo
* move mocks around
* set app id on new signups
* initialize oauth server properly
* rename oauth server
* proper mocking tests
* go fmt ./...
* add required fields
* change name of func
* move validation to account.go
* more tests!
* add some file utility tools
* add mediaconfig
* new shortcut
* add some more fields
* add followrequest model
* add notify
* update mastotypes
* mock out storage interface
* start building media interface
* start on update credentials
* mess about with media a bit more
* test image manipulation
* media more or less working
* account update nearly working
* rearranging my package ;) ;) ;)
* phew big stuff!!!!
* fix type checking
* *fiddles*
* Add CreateTables func
* account registration flow working
* tidy
* script to step through auth flow
* add a lil helper for generating user uris
* fiddling with federation a bit
* update progress
* Tidying and linting
---
internal/apimodule/app/app.go | 71 ++++++++++++++++++++++
internal/apimodule/app/app_test.go | 21 +++++++
internal/apimodule/app/appcreate.go | 113 ++++++++++++++++++++++++++++++++++++
3 files changed, 205 insertions(+)
create mode 100644 internal/apimodule/app/app.go
create mode 100644 internal/apimodule/app/app_test.go
create mode 100644 internal/apimodule/app/appcreate.go
(limited to 'internal/apimodule/app')
diff --git a/internal/apimodule/app/app.go b/internal/apimodule/app/app.go
new file mode 100644
index 000000000..534f4cd3e
--- /dev/null
+++ b/internal/apimodule/app/app.go
@@ -0,0 +1,71 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+package app
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/sirupsen/logrus"
+ "github.com/superseriousbusiness/gotosocial/internal/apimodule"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/db/model"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+ "github.com/superseriousbusiness/gotosocial/internal/router"
+)
+
+const appsPath = "/api/v1/apps"
+
+type appModule struct {
+ server oauth.Server
+ db db.DB
+ log *logrus.Logger
+}
+
+// New returns a new auth module
+func New(srv oauth.Server, db db.DB, log *logrus.Logger) apimodule.ClientAPIModule {
+ return &appModule{
+ server: srv,
+ db: db,
+ log: log,
+ }
+}
+
+// Route satisfies the RESTAPIModule interface
+func (m *appModule) Route(s router.Router) error {
+ s.AttachHandler(http.MethodPost, appsPath, m.appsPOSTHandler)
+ return nil
+}
+
+func (m *appModule) CreateTables(db db.DB) error {
+ models := []interface{}{
+ &oauth.Client{},
+ &oauth.Token{},
+ &model.User{},
+ &model.Account{},
+ &model.Application{},
+ }
+
+ for _, m := range models {
+ if err := db.CreateTable(m); err != nil {
+ return fmt.Errorf("error creating table: %s", err)
+ }
+ }
+ return nil
+}
diff --git a/internal/apimodule/app/app_test.go b/internal/apimodule/app/app_test.go
new file mode 100644
index 000000000..d45b04e74
--- /dev/null
+++ b/internal/apimodule/app/app_test.go
@@ -0,0 +1,21 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+package app
+
+// TODO: write tests
diff --git a/internal/apimodule/app/appcreate.go b/internal/apimodule/app/appcreate.go
new file mode 100644
index 000000000..cd5aff701
--- /dev/null
+++ b/internal/apimodule/app/appcreate.go
@@ -0,0 +1,113 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+package app
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/google/uuid"
+ "github.com/superseriousbusiness/gotosocial/internal/db/model"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+ "github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
+)
+
+// appsPOSTHandler should be served at https://example.org/api/v1/apps
+// It is equivalent to: https://docs.joinmastodon.org/methods/apps/
+func (m *appModule) appsPOSTHandler(c *gin.Context) {
+ l := m.log.WithField("func", "AppsPOSTHandler")
+ l.Trace("entering AppsPOSTHandler")
+
+ form := &mastotypes.ApplicationPOSTRequest{}
+ if err := c.ShouldBind(form); err != nil {
+ c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
+ return
+ }
+
+ // permitted length for most fields
+ permittedLength := 64
+ // redirect can be a bit bigger because we probably need to encode data in the redirect uri
+ permittedRedirect := 256
+
+ // check lengths of fields before proceeding so the user can't spam huge entries into the database
+ if len(form.ClientName) > permittedLength {
+ c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("client_name must be less than %d bytes", permittedLength)})
+ return
+ }
+ if len(form.Website) > permittedLength {
+ c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("website must be less than %d bytes", permittedLength)})
+ return
+ }
+ if len(form.RedirectURIs) > permittedRedirect {
+ c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("redirect_uris must be less than %d bytes", permittedRedirect)})
+ return
+ }
+ if len(form.Scopes) > permittedLength {
+ c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("scopes must be less than %d bytes", permittedLength)})
+ return
+ }
+
+ // set default 'read' for scopes if it's not set, this follows the default of the mastodon api https://docs.joinmastodon.org/methods/apps/
+ var scopes string
+ if form.Scopes == "" {
+ scopes = "read"
+ } else {
+ scopes = form.Scopes
+ }
+
+ // generate new IDs for this application and its associated client
+ clientID := uuid.NewString()
+ clientSecret := uuid.NewString()
+ vapidKey := uuid.NewString()
+
+ // generate the application to put in the database
+ app := &model.Application{
+ Name: form.ClientName,
+ Website: form.Website,
+ RedirectURI: form.RedirectURIs,
+ ClientID: clientID,
+ ClientSecret: clientSecret,
+ Scopes: scopes,
+ VapidKey: vapidKey,
+ }
+
+ // chuck it in the db
+ if err := m.db.Put(app); err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // now we need to model an oauth client from the application that the oauth library can use
+ oc := &oauth.Client{
+ ID: clientID,
+ Secret: clientSecret,
+ Domain: form.RedirectURIs,
+ UserID: "", // This client isn't yet associated with a specific user, it's just an app client right now
+ }
+
+ // chuck it in the db
+ if err := m.db.Put(oc); err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+ return
+ }
+
+ // done, return the new app information per the spec here: https://docs.joinmastodon.org/methods/apps/
+ c.JSON(http.StatusOK, app.ToMasto())
+}
--
cgit v1.2.3