diff --git a/go.mod b/go.mod
index 17cb2889b..64c68ba11 100644
--- a/go.mod
+++ b/go.mod
@@ -18,7 +18,7 @@ require (
github.com/tidwall/buntdb v1.2.0 // indirect
github.com/tidwall/pretty v1.1.0 // indirect
github.com/urfave/cli/v2 v2.3.0
- golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
+ golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.3.0
)
diff --git a/go.sum b/go.sum
index bafd27c22..b73d02c47 100644
--- a/go.sum
+++ b/go.sum
@@ -240,8 +240,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b h1:wSOdpTq0/eI46Ez/LkDwIsAKA71YP2SRKBODiRWM0as=
+golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
diff --git a/internal/api/server.go b/internal/api/server.go
index ed622210b..8af9e75fa 100644
--- a/internal/api/server.go
+++ b/internal/api/server.go
@@ -35,6 +35,10 @@ type Server interface {
Stop()
}
+type AddsRoutes interface {
+ AddRoutes(s Server) error
+}
+
type server struct {
APIGroup *gin.RouterGroup
logger *logrus.Logger
diff --git a/internal/db/db.go b/internal/db/db.go
index 03e30b41b..4ea4e1af6 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -25,7 +25,6 @@ import (
"github.com/go-fed/activity/pub"
"github.com/gotosocial/gotosocial/internal/config"
- "github.com/gotosocial/oauth2/v4"
"github.com/sirupsen/logrus"
)
@@ -40,11 +39,6 @@ type DB interface {
*/
pub.Database
- /*
- OAUTH2 DATABASE FUNCTIONS
- */
- TokenStore() oauth2.TokenStore
-
/*
ANY ADDITIONAL DESIRED FUNCTIONS
*/
diff --git a/internal/db/postgres.go b/internal/db/postgres.go
index 96452d5ae..dae6b11e2 100644
--- a/internal/db/postgres.go
+++ b/internal/db/postgres.go
@@ -315,8 +315,9 @@ func (ps *postgresService) Stop(ctx context.Context) error {
func (ps *postgresService) CreateSchema(ctx context.Context) error {
models := []interface{}{
- (*gtsmodel.GTSAccount)(nil),
- (*gtsmodel.GTSStatus)(nil),
+ (*gtsmodel.Account)(nil),
+ (*gtsmodel.Status)(nil),
+ (*gtsmodel.User)(nil),
}
ps.log.Info("creating db schema")
diff --git a/internal/email/email.go b/internal/email/email.go
new file mode 100644
index 000000000..d70f6c5b5
--- /dev/null
+++ b/internal/email/email.go
@@ -0,0 +1,20 @@
+/*
+ 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 email provides a service for interacting with an SMTP server
+package email
diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go
index 7cd942ee8..84ba027b2 100644
--- a/internal/gtsmodel/account.go
+++ b/internal/gtsmodel/account.go
@@ -26,10 +26,10 @@ import (
"time"
)
-// GTSAccount represents a GoToSocial user account
-type GTSAccount struct {
- GTSAvatar
- GTSHeader
+// Account represents a GoToSocial user account
+type Account struct {
+ Avatar
+ Header
URI string
URL string
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
@@ -66,7 +66,7 @@ type GTSAccount struct {
SuspensionOrigin int
}
-type GTSAvatar struct {
+type Avatar struct {
AvatarFileName string
AvatarContentType string
AvatarFileSize int
@@ -75,7 +75,7 @@ type GTSAvatar struct {
AvatarStorageSchemaVersion int
}
-type GTSHeader struct {
+type Header struct {
HeaderFileName string
HeaderContentType string
HeaderFileSize int
diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go
index cba8a6ba8..39c450934 100644
--- a/internal/gtsmodel/status.go
+++ b/internal/gtsmodel/status.go
@@ -20,7 +20,7 @@ package gtsmodel
import "time"
-type GTSStatus struct {
+type Status struct {
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
URI string
URL string
diff --git a/internal/gtsmodel/user.go b/internal/gtsmodel/user.go
new file mode 100644
index 000000000..577590ddf
--- /dev/null
+++ b/internal/gtsmodel/user.go
@@ -0,0 +1,65 @@
+/*
+ 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 gtsmodel
+
+import (
+ "net"
+ "time"
+)
+
+type User struct {
+ ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
+ Email string `pg:",notnull"`
+ CreatedAt time.Time `pg:"type:timestamp,notnull"`
+ UpdatedAt time.Time `pg:"type:timestamp,notnull"`
+ EncryptedPassword string `pg:",notnull"`
+ ResetPasswordToken string
+ ResetPasswordSentAt time.Time `pg:"type:timestamp"`
+ SignInCount int
+ CurrentSignInAt time.Time `pg:"type:timestamp"`
+ LastSignInAt time.Time `pg:"type:timestamp"`
+ CurrentSignInIP net.IP
+ LastSignInIP net.IP
+ Admin bool
+ ConfirmationToken string
+ ConfirmedAt time.Time `pg:"type:timestamp"`
+ ConfirmationSentAt time.Time `pg:"type:timestamp"`
+ UnconfirmedEmail string
+ Locale string
+ EncryptedOTPSecret string
+ EncryptedOTPSecretIv string
+ EncryptedOTPSecretSalt string
+ ConsumedTimestamp int
+ OTPRequiredForLogin bool
+ LastEmailedAt time.Time `pg:"type:timestamp"`
+ OTPBackupCodes []string
+ FilteredLanguages []string
+ AccountID string `pg:",notnull"`
+ Disabled bool
+ Moderator bool
+ InviteID string
+ RememberToken string
+ ChosenLanguages []string
+ CreatedByApplicationID string
+ Approved bool
+ SignInToken string
+ SignInTokenSentAt time.Time `pg:"type:timestamp"`
+ WebauthnID string
+ SignUpIP net.IP
+}
diff --git a/internal/oauth/oauth.go b/internal/oauth/oauth.go
index d79db95ed..050c23dab 100644
--- a/internal/oauth/oauth.go
+++ b/internal/oauth/oauth.go
@@ -19,19 +19,25 @@
package oauth
import (
+ "github.com/go-pg/pg/v10"
+ "github.com/gotosocial/gotosocial/internal/api"
+ "github.com/gotosocial/gotosocial/internal/gtsmodel"
"github.com/gotosocial/oauth2/v4"
"github.com/gotosocial/oauth2/v4/errors"
"github.com/gotosocial/oauth2/v4/manage"
"github.com/gotosocial/oauth2/v4/server"
"github.com/sirupsen/logrus"
+ "golang.org/x/crypto/bcrypt"
)
type API struct {
manager *manage.Manager
server *server.Server
+ conn *pg.DB
+ log *logrus.Logger
}
-func New(ts oauth2.TokenStore, cs oauth2.ClientStore, log *logrus.Logger) *API {
+func New(ts oauth2.TokenStore, cs oauth2.ClientStore, conn *pg.DB, log *logrus.Logger) *API {
manager := manage.NewDefaultManager()
manager.MapTokenStorage(ts)
manager.MapClientStorage(cs)
@@ -49,5 +55,41 @@ func New(ts oauth2.TokenStore, cs oauth2.ClientStore, log *logrus.Logger) *API {
return &API{
manager: manager,
server: srv,
+ conn: conn,
+ log: log,
}
}
+
+func (a *API) AddRoutes(s api.Server) error {
+ return nil
+}
+
+func incorrectPassword() (string, error) {
+ return "", errors.New("password/email combination was incorrect")
+}
+
+func (a *API) PasswordAuthorizationHandler(email string, password string) (userid string, err error) {
+ // first we select the user from the database based on email address, bail if no user found for that email
+ gtsUser := >smodel.User{}
+ if err := a.conn.Model(gtsUser).Where("email = ?", email).Select(); err != nil {
+ a.log.Debugf("user %s was not retrievable from db during oauth authorization attempt: %s", email, err)
+ return incorrectPassword()
+ }
+
+ // make sure a password is actually set and bail if not
+ if gtsUser.EncryptedPassword == "" {
+ a.log.Warnf("encrypted password for user %s was empty for some reason", gtsUser.Email)
+ return incorrectPassword()
+ }
+
+ // compare the provided password with the encrypted one from the db, bail if they don't match
+ if err := bcrypt.CompareHashAndPassword([]byte(gtsUser.EncryptedPassword), []byte(password)); err != nil {
+ a.log.Debugf("password hash didn't match for user %s during login attempt: %s", gtsUser.Email, err)
+ return incorrectPassword()
+ }
+
+ // If we've made it this far the email/password is correct so we need the oauth client-id of the user
+ // This is, conveniently, the same as the user ID, so we can just return it.
+ userid = gtsUser.ID
+ return
+}
diff --git a/internal/oauth/pgclientstore.go b/internal/oauth/pgclientstore.go
index dda5fb3d6..22bb54f55 100644
--- a/internal/oauth/pgclientstore.go
+++ b/internal/oauth/pgclientstore.go
@@ -37,9 +37,9 @@ func NewPGClientStore(conn *pg.DB) oauth2.ClientStore {
return pts
}
-func (pcs *pgClientStore) GetByID(ctx context.Context, id string) (oauth2.ClientInfo, error) {
+func (pcs *pgClientStore) GetByID(ctx context.Context, clientID string) (oauth2.ClientInfo, error) {
poc := &oauthClient{
- ID: id,
+ ID: clientID,
}
if err := pcs.conn.WithContext(ctx).Model(poc).Where("id = ?", poc.ID).Select(); err != nil {
return nil, err
diff --git a/internal/oauth/pgclientstore_test.go b/internal/oauth/pgclientstore_test.go
index 3f8de064d..d6a76981f 100644
--- a/internal/oauth/pgclientstore_test.go
+++ b/internal/oauth/pgclientstore_test.go
@@ -13,10 +13,10 @@ import (
type PgClientStoreTestSuite struct {
suite.Suite
- conn *pg.DB
- testClientID string
- testClientSecret string
- testClientDomain string
+ conn *pg.DB
+ testClientID string
+ testClientSecret string
+ testClientDomain string
testClientUserID string
}