Auth: Add unique index to user_slug in auth_users table #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
85561547cc
commit
5e7ff6b1b2
10 changed files with 31 additions and 35 deletions
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
)
|
||||
|
||||
// ResetCommand resets the index, clears the cache, and removes sidecar files after confirmation.
|
||||
|
@ -181,8 +180,8 @@ func resetIndexDb(c *config.Config) {
|
|||
// Reset admin account?
|
||||
if c.AdminPassword() == "" {
|
||||
log.Warnf("password required to reset admin account")
|
||||
} else if entity.Admin.InitAccount(c.AdminUser(), c.AdminPassword()) {
|
||||
log.Infof("user %s has been restored", clean.LogQuote(c.AdminUser()))
|
||||
} else {
|
||||
entity.Admin.InitAccount(c.AdminUser(), c.AdminPassword())
|
||||
}
|
||||
|
||||
log.Infof("database reset completed in %s", time.Since(start))
|
||||
|
|
|
@ -275,8 +275,8 @@ func (c *Config) MigrateDb(runFailed bool, ids []string) {
|
|||
// Init admin account?
|
||||
if c.AdminPassword() == "" {
|
||||
log.Warnf("config: password required to initialize %s account", clean.LogQuote(c.AdminUser()))
|
||||
} else if entity.Admin.InitAccount(c.AdminUser(), c.AdminPassword()) {
|
||||
log.Infof("config: %s account has been initialized", clean.LogQuote(c.AdminUser()))
|
||||
} else {
|
||||
entity.Admin.InitAccount(c.AdminUser(), c.AdminPassword())
|
||||
}
|
||||
|
||||
go entity.SaveErrorMessages()
|
||||
|
@ -290,8 +290,8 @@ func (c *Config) InitTestDb() {
|
|||
|
||||
if c.AdminPassword() == "" {
|
||||
// Do nothing.
|
||||
} else if entity.Admin.InitAccount(c.AdminUser(), c.AdminPassword()) {
|
||||
log.Debugf("config: %s account has been initialized", clean.LogQuote(c.AdminUser()))
|
||||
} else {
|
||||
entity.Admin.InitAccount(c.AdminUser(), c.AdminPassword())
|
||||
}
|
||||
|
||||
go entity.SaveErrorMessages()
|
||||
|
|
|
@ -25,7 +25,7 @@ type Users []User
|
|||
type User struct {
|
||||
ID int `gorm:"primary_key" json:"-" yaml:"-"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
UserSlug string `gorm:"type:VARBINARY(160);index;" json:"Slug" yaml:"Slug,omitempty"`
|
||||
UserSlug string `gorm:"type:VARBINARY(160);unique_index;" json:"Slug" yaml:"Slug,omitempty"`
|
||||
Username string `gorm:"size:64;index;" json:"Username" yaml:"Username,omitempty"`
|
||||
Email string `gorm:"size:255;index;" json:"Email" yaml:"Email,omitempty"`
|
||||
UserRole string `gorm:"size:32;" json:"Role" yaml:"Role,omitempty"`
|
||||
|
@ -102,12 +102,6 @@ func (m *User) InitAccount(login, password string) (updated bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
// Update username as well if needed.
|
||||
if err := m.UpdateName(login); err != nil {
|
||||
log.Errorf("user: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
existing := FindPassword(m.UserUID)
|
||||
|
||||
if existing != nil {
|
||||
|
@ -116,12 +110,17 @@ func (m *User) InitAccount(login, password string) (updated bool) {
|
|||
|
||||
pw := NewPassword(m.UserUID, password)
|
||||
|
||||
// Update password in database.
|
||||
// Save password.
|
||||
if err := pw.Save(); err != nil {
|
||||
log.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
// Change username.
|
||||
if err := m.UpdateName(login); err != nil {
|
||||
log.Debugf("auth: cannot change username of %s to %s (%s)", clean.Log(m.UserUID), clean.LogQuote(login), err.Error())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -174,7 +173,7 @@ func FirstOrCreateUser(m *User) *User {
|
|||
|
||||
m.UserSlug = m.GenerateSlug()
|
||||
|
||||
if err := Db().Where("id = ? OR user_uid = ?", m.ID, m.UserUID).First(&result).Error; err == nil {
|
||||
if err := Db().Where("id = ? OR (user_uid = ? AND user_uid <> '') OR (user_slug = ? AND user_slug <> '') OR (username = ? AND username <> '')", m.ID, m.UserUID, m.UserSlug, m.Username).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else if err := m.Create(); err != nil {
|
||||
log.Debugf("user: %s", err)
|
||||
|
@ -307,7 +306,7 @@ func (m *User) SetUsername(login string) (err error) {
|
|||
m.UserSlug = m.GenerateSlug()
|
||||
|
||||
// Update display name.
|
||||
if m.DisplayName == "" || m.DisplayName == DefaultAdminFullName {
|
||||
if m.DisplayName == "" || m.DisplayName == AdminDisplayName {
|
||||
m.DisplayName = clean.Name(login)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,19 +5,17 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
)
|
||||
|
||||
const DefaultAdminUserName = "admin"
|
||||
const DefaultAdminFullName = "Admin"
|
||||
|
||||
const DisplayNameUnknown = "Public"
|
||||
const DisplayNameGuest = "Guest"
|
||||
const AdminUserName = "admin"
|
||||
const AdminDisplayName = "Admin"
|
||||
const GuestDisplayName = "Guest"
|
||||
|
||||
// Admin is the default admin user.
|
||||
var Admin = User{
|
||||
ID: 1,
|
||||
UserSlug: "admin",
|
||||
Username: DefaultAdminUserName,
|
||||
Username: AdminUserName,
|
||||
UserRole: acl.RoleAdmin.String(),
|
||||
DisplayName: DefaultAdminFullName,
|
||||
DisplayName: AdminDisplayName,
|
||||
SuperAdmin: true,
|
||||
CanLogin: true,
|
||||
CanInvite: true,
|
||||
|
@ -27,11 +25,11 @@ var Admin = User{
|
|||
// UnknownUser is an anonymous, public user without own account.
|
||||
var UnknownUser = User{
|
||||
ID: -1,
|
||||
UserSlug: "1",
|
||||
UserSlug: "",
|
||||
UserUID: "u000000000000001",
|
||||
UserRole: "",
|
||||
Username: "",
|
||||
DisplayName: DisplayNameUnknown,
|
||||
DisplayName: "",
|
||||
SuperAdmin: false,
|
||||
CanLogin: false,
|
||||
CanInvite: false,
|
||||
|
@ -41,11 +39,11 @@ var UnknownUser = User{
|
|||
// Guest is a user without own account e.g. for link sharing.
|
||||
var Guest = User{
|
||||
ID: -2,
|
||||
UserSlug: "2",
|
||||
UserSlug: "guest",
|
||||
UserUID: "u000000000000002",
|
||||
UserRole: acl.RoleGuest.String(),
|
||||
Username: "",
|
||||
DisplayName: DisplayNameGuest,
|
||||
Username: "guest",
|
||||
DisplayName: GuestDisplayName,
|
||||
SuperAdmin: false,
|
||||
CanLogin: false,
|
||||
CanInvite: false,
|
||||
|
|
|
@ -232,7 +232,7 @@ func TestFindUserByUID(t *testing.T) {
|
|||
|
||||
assert.Equal(t, -2, m.ID)
|
||||
assert.NotEmpty(t, m.UserUID)
|
||||
assert.Equal(t, "", m.Username)
|
||||
assert.Equal(t, "guest", m.Username)
|
||||
assert.Equal(t, "Guest", m.DisplayName)
|
||||
assert.NotEmpty(t, m.CreatedAt)
|
||||
assert.NotEmpty(t, m.UpdatedAt)
|
||||
|
|
|
@ -101,6 +101,6 @@ var DialectMySQL = Migrations{
|
|||
{
|
||||
ID: "20220901-000100",
|
||||
Dialect: "mysql",
|
||||
Statements: []string{"INSERT IGNORE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, role_admin, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE user_name <> '' AND user_name IS NOT NULL AND role_admin = 1 AND user_disabled = 0;"},
|
||||
Statements: []string{"REPLACE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, role_admin, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE role_admin = 1 AND user_name NOT IN (SELECT user_slug FROM auth_users UNION SELECT user_slug FROM auth_users) AND user_name <> '' AND user_name IS NOT NULL;"},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -61,6 +61,6 @@ var DialectSQLite3 = Migrations{
|
|||
{
|
||||
ID: "20220901-000100",
|
||||
Dialect: "sqlite3",
|
||||
Statements: []string{"INSERT OR IGNORE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, 1, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE user_name <> '' AND user_name IS NOT NULL AND user_uid <> '' AND user_uid IS NOT NULL AND role_admin = 1 AND user_disabled = 0 ON CONFLICT DO NOTHING;"},
|
||||
Statements: []string{"REPLACE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, 1, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE user_name <> '' AND user_name IS NOT NULL AND user_uid <> '' AND user_uid IS NOT NULL AND role_admin = 1 AND user_disabled = 0;"},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ func (m *Migration) Execute(db *gorm.DB) error {
|
|||
} else if strings.HasPrefix(q, "DROP TABLE ") &&
|
||||
strings.Contains(e, "DROP") {
|
||||
log.Tracef("migrate: %s (ignored, probably didn't exist anymore)", err)
|
||||
} else if strings.Contains(q, " IGNORE ") &&
|
||||
} else if (strings.Contains(q, " IGNORE ") || strings.Contains(q, "REPLACE")) &&
|
||||
(strings.Contains(e, "NO SUCH TABLE") || strings.Contains(e, "DOESN'T EXIST")) {
|
||||
log.Tracef("migrate: %s (ignored, old table does not exist anymore)", err)
|
||||
} else {
|
||||
|
|
|
@ -1 +1 @@
|
|||
INSERT IGNORE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, role_admin, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE user_name <> '' AND user_name IS NOT NULL AND role_admin = 1 AND user_disabled = 0;
|
||||
REPLACE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, role_admin, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE role_admin = 1 AND user_name NOT IN (SELECT user_slug FROM auth_users UNION SELECT user_slug FROM auth_users) AND user_name <> '' AND user_name IS NOT NULL;
|
|
@ -1 +1 @@
|
|||
INSERT OR IGNORE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, 1, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE user_name <> '' AND user_name IS NOT NULL AND user_uid <> '' AND user_uid IS NOT NULL AND role_admin = 1 AND user_disabled = 0 ON CONFLICT DO NOTHING;
|
||||
REPLACE INTO auth_users (id, user_uid, super_admin, user_role, display_name, user_slug, username, email, login_attempts, login_at, created_at, updated_at) SELECT id, user_uid, 1, 'admin', full_name, user_name, user_name, primary_email, login_attempts, login_at, created_at, updated_at FROM users WHERE user_name <> '' AND user_name IS NOT NULL AND user_uid <> '' AND user_uid IS NOT NULL AND role_admin = 1 AND user_disabled = 0;
|
Loading…
Reference in a new issue