Make userapi control account creation entirely (#1139)

This makes a chokepoint with which we can finally fix
'database is locked' errors on sqlite during account creation
This commit is contained in:
Kegsay 2020-06-17 11:22:26 +01:00 committed by GitHub
parent 04c99092a4
commit a66a3b830c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 131 additions and 113 deletions

View file

@ -89,16 +89,18 @@ type QueryProfileResponse struct {
// PerformAccountCreationRequest is the request for PerformAccountCreation
type PerformAccountCreationRequest struct {
Localpart string
AppServiceID string
Password string
AccountType AccountType // Required: whether this is a guest or user account
Localpart string // Required: The localpart for this account. Ignored if account type is guest.
AppServiceID string // optional: the application service ID (not user ID) creating this account, if any.
Password string // optional: if missing then this account will be a passwordless account
OnConflict Conflict
}
// PerformAccountCreationResponse is the response for PerformAccountCreation
type PerformAccountCreationResponse struct {
AccountCreated bool
UserID string
Account *Account
}
// PerformDeviceCreationRequest is the request for PerformDeviceCreation
@ -115,8 +117,7 @@ type PerformDeviceCreationRequest struct {
// PerformDeviceCreationResponse is the response for PerformDeviceCreation
type PerformDeviceCreationResponse struct {
DeviceCreated bool
AccessToken string
DeviceID string
Device *Device
}
// Device represents a client's device (mobile, web, etc)
@ -134,6 +135,16 @@ type Device struct {
DisplayName string
}
// Account represents a Matrix account on this home server.
type Account struct {
UserID string
Localpart string
ServerName gomatrixserverlib.ServerName
AppServiceID string
// TODO: Other flags like IsAdmin, IsGuest
// TODO: Associations (e.g. with application services)
}
// ErrorForbidden is an error indicating that the supplied access token is forbidden
type ErrorForbidden struct {
Message string
@ -155,9 +166,17 @@ func (e *ErrorConflict) Error() string {
// Conflict is an enum representing what to do when encountering conflicting when creating profiles/devices
type Conflict int
// AccountType is an enum representing the kind of account
type AccountType int
const (
// ConflictUpdate will update matching records returning no error
ConflictUpdate Conflict = 1
// ConflictAbort will reject the request with ErrorConflict
ConflictAbort Conflict = 2
// AccountTypeUser indicates this is a user account
AccountTypeUser AccountType = 1
// AccountTypeGuest indicates this is a guest account
AccountTypeGuest AccountType = 2
)

View file

@ -39,6 +39,15 @@ type UserInternalAPI struct {
}
func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.PerformAccountCreationRequest, res *api.PerformAccountCreationResponse) error {
if req.AccountType == api.AccountTypeGuest {
acc, err := a.AccountDB.CreateGuestAccount(ctx)
if err != nil {
return err
}
res.AccountCreated = true
res.Account = acc
return nil
}
acc, err := a.AccountDB.CreateAccount(ctx, req.Localpart, req.Password, req.AppServiceID)
if err != nil {
if errors.Is(err, sqlutil.ErrUserExists) { // This account already exists
@ -51,12 +60,18 @@ func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.P
}
}
}
// account already exists
res.AccountCreated = false
res.UserID = fmt.Sprintf("@%s:%s", req.Localpart, a.ServerName)
res.Account = &api.Account{
AppServiceID: req.AppServiceID,
Localpart: req.Localpart,
ServerName: a.ServerName,
UserID: fmt.Sprintf("@%s:%s", req.Localpart, a.ServerName),
}
return nil
}
res.AccountCreated = true
res.UserID = acc.UserID
res.Account = acc
return nil
}
func (a *UserInternalAPI) PerformDeviceCreation(ctx context.Context, req *api.PerformDeviceCreationRequest, res *api.PerformDeviceCreationResponse) error {
@ -65,8 +80,7 @@ func (a *UserInternalAPI) PerformDeviceCreation(ctx context.Context, req *api.Pe
return err
}
res.DeviceCreated = true
res.AccessToken = dev.AccessToken
res.DeviceID = dev.ID
res.Device = dev
return nil
}