diff options
author | 2022-12-06 14:15:56 +0100 | |
---|---|---|
committer | 2022-12-06 14:15:56 +0100 | |
commit | 199b685f430910910e43476caa9ccec6a441d020 (patch) | |
tree | b928c97deae38f8194e51b5e7a69766ddd1a0763 /internal/db | |
parent | [feature] media: add webp support (#1155) (diff) | |
download | gotosocial-199b685f430910910e43476caa9ccec6a441d020.tar.xz |
[feature] overhaul the oidc system (#961)
* [feature] overhaul the oidc system
this allows for more flexible username handling and prevents account
takeover using old email addresses
* [feature] add migration path for old OIDC users
* [feature] nicer error reporting for users
* [docs] document the new OIDC flow
* [fix] return early on oidc error
* [docs]: add comments on the finalization logic
Diffstat (limited to 'internal/db')
-rw-r--r-- | internal/db/admin.go | 2 | ||||
-rw-r--r-- | internal/db/bundb/admin.go | 3 | ||||
-rw-r--r-- | internal/db/bundb/migrations/20221103203553_add_external_id.go | 46 | ||||
-rw-r--r-- | internal/db/bundb/user.go | 19 | ||||
-rw-r--r-- | internal/db/user.go | 2 |
5 files changed, 70 insertions, 2 deletions
diff --git a/internal/db/admin.go b/internal/db/admin.go index d8c693e04..1fb96de11 100644 --- a/internal/db/admin.go +++ b/internal/db/admin.go @@ -40,7 +40,7 @@ type Admin interface { // NewSignup creates a new user in the database with the given parameters. // By the time this function is called, it should be assumed that all the parameters have passed validation! - NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, admin bool) (*gtsmodel.User, Error) + NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, externalID string, admin bool) (*gtsmodel.User, Error) // CreateInstanceAccount creates an account in the database with the same username as the instance host value. // Ie., if the instance is hosted at 'example.org' the instance user will have a username of 'example.org'. diff --git a/internal/db/bundb/admin.go b/internal/db/bundb/admin.go index a58f8893b..2a8851684 100644 --- a/internal/db/bundb/admin.go +++ b/internal/db/bundb/admin.go @@ -90,7 +90,7 @@ func (a *adminDB) IsEmailAvailable(ctx context.Context, email string) (bool, db. return a.conn.NotExists(ctx, q) } -func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, admin bool) (*gtsmodel.User, db.Error) { +func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, externalID string, admin bool) (*gtsmodel.User, db.Error) { key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits) if err != nil { log.Errorf("error creating new rsa key: %s", err) @@ -169,6 +169,7 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, UnconfirmedEmail: email, CreatedByApplicationID: appID, Approved: &approved, + ExternalID: externalID, } if emailVerified { diff --git a/internal/db/bundb/migrations/20221103203553_add_external_id.go b/internal/db/bundb/migrations/20221103203553_add_external_id.go new file mode 100644 index 000000000..dab5c01fc --- /dev/null +++ b/internal/db/bundb/migrations/20221103203553_add_external_id.go @@ -0,0 +1,46 @@ +/* + GoToSocial + Copyright (C) 2021-2022 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 <http://www.gnu.org/licenses/>. +*/ + +package migrations + +import ( + "context" + "strings" + + "github.com/uptrace/bun" +) + +func init() { + up := func(ctx context.Context, db *bun.DB) error { + _, err := db.ExecContext(ctx, "ALTER TABLE ? ADD COLUMN ? TEXT", bun.Ident("users"), bun.Ident("external_id")) + if err != nil && !(strings.Contains(err.Error(), "already exists") || strings.Contains(err.Error(), "duplicate column name") || strings.Contains(err.Error(), "SQLSTATE 42701")) { + return err + } + return nil + } + + down := func(ctx context.Context, db *bun.DB) error { + return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + return nil + }) + } + + if err := Migrations.Register(up, down); err != nil { + panic(err) + } +} diff --git a/internal/db/bundb/user.go b/internal/db/bundb/user.go index ab3cc0f67..e7983556f 100644 --- a/internal/db/bundb/user.go +++ b/internal/db/bundb/user.go @@ -40,6 +40,7 @@ func (u *userDB) init() { {Name: "AccountID"}, {Name: "Email"}, {Name: "ConfirmationToken"}, + {Name: "ExternalID"}, }, func(u1 *gtsmodel.User) *gtsmodel.User { u2 := new(gtsmodel.User) *u2 = *u1 @@ -104,6 +105,24 @@ func (u *userDB) GetUserByEmailAddress(ctx context.Context, emailAddress string) return &user, nil }, emailAddress) } +func (u *userDB) GetUserByExternalID(ctx context.Context, id string) (*gtsmodel.User, db.Error) { + + return u.cache.Load("ExternalID", func() (*gtsmodel.User, error) { + var user gtsmodel.User + + q := u.conn. + NewSelect(). + Model(&user). + Relation("Account"). + Where("? = ?", bun.Ident("user.external_id"), id) + + if err := q.Scan(ctx); err != nil { + return nil, u.conn.ProcessError(err) + } + + return &user, nil + }, id) +} func (u *userDB) GetUserByConfirmationToken(ctx context.Context, confirmationToken string) (*gtsmodel.User, db.Error) { return u.cache.Load("ConfirmationToken", func() (*gtsmodel.User, error) { diff --git a/internal/db/user.go b/internal/db/user.go index 1c6118fce..6987a5e11 100644 --- a/internal/db/user.go +++ b/internal/db/user.go @@ -32,6 +32,8 @@ type User interface { GetUserByAccountID(ctx context.Context, accountID string) (*gtsmodel.User, Error) // GetUserByID returns one user with the given email address, or an error if something goes wrong. GetUserByEmailAddress(ctx context.Context, emailAddress string) (*gtsmodel.User, Error) + // GetUserByExternalID returns one user with the given external id, or an error if something goes wrong. + GetUserByExternalID(ctx context.Context, id string) (*gtsmodel.User, Error) // GetUserByConfirmationToken returns one user by its confirmation token, or an error if something goes wrong. GetUserByConfirmationToken(ctx context.Context, confirmationToken string) (*gtsmodel.User, Error) // PutUser will attempt to place user in the database |