mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	fix constraints
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
		
							parent
							
								
									60b9595929
								
							
						
					
					
						commit
						4f57410a5b
					
				@ -498,6 +498,25 @@ func NewHeadscaleDatabase(
 | 
				
			|||||||
						return err
 | 
											return err
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Set up indexes and unique constraints outside of GORM, it does not support
 | 
				
			||||||
 | 
										// conditional unique constraints.
 | 
				
			||||||
 | 
										// This ensures the following:
 | 
				
			||||||
 | 
										// - A user name and provider_identifier is unique
 | 
				
			||||||
 | 
										// - A provider_identifier is unique
 | 
				
			||||||
 | 
										// - A user name is unique if there is no provider_identifier is not set
 | 
				
			||||||
 | 
										for _, idx := range []string{
 | 
				
			||||||
 | 
											"DROP INDEX IF EXISTS `idx_provider_identifier`",
 | 
				
			||||||
 | 
											"DROP INDEX IF EXISTS `idx_name_provider_identifier`",
 | 
				
			||||||
 | 
											"CREATE UNIQUE INDEX IF NOT EXISTS `idx_provider_identifier` ON `users` (`provider_identifier`) WHERE provider_identifier IS NOT NULL;",
 | 
				
			||||||
 | 
											"CREATE UNIQUE INDEX IF NOT EXISTS `idx_name_provider_identifier` ON `users` (`name`,`provider_identifier`);",
 | 
				
			||||||
 | 
											"CREATE UNIQUE INDEX IF NOT EXISTS `idx_name_no_provider_identifier` ON `users` (`name`) WHERE provider_identifier IS NULL;",
 | 
				
			||||||
 | 
										} {
 | 
				
			||||||
 | 
											err = tx.Exec(idx).Error
 | 
				
			||||||
 | 
											if err != nil {
 | 
				
			||||||
 | 
												return fmt.Errorf("creating username index: %w", err)
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					return nil
 | 
										return nil
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Rollback: func(db *gorm.DB) error { return nil },
 | 
									Rollback: func(db *gorm.DB) error { return nil },
 | 
				
			||||||
 | 
				
			|||||||
@ -271,8 +271,8 @@ func TestConstraints(t *testing.T) {
 | 
				
			|||||||
				require.NoError(t, err)
 | 
									require.NoError(t, err)
 | 
				
			||||||
				_, err = CreateUser(db, "user1")
 | 
									_, err = CreateUser(db, "user1")
 | 
				
			||||||
				require.Error(t, err)
 | 
									require.Error(t, err)
 | 
				
			||||||
				// assert.Contains(t, err.Error(), "UNIQUE constraint failed: users.username")
 | 
									assert.Contains(t, err.Error(), "UNIQUE constraint failed:")
 | 
				
			||||||
				require.Contains(t, err.Error(), "user already exists")
 | 
									// require.Contains(t, err.Error(), "user already exists")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -295,7 +295,7 @@ func TestConstraints(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				err = db.Save(&user).Error
 | 
									err = db.Save(&user).Error
 | 
				
			||||||
				require.Error(t, err)
 | 
									require.Error(t, err)
 | 
				
			||||||
				require.Contains(t, err.Error(), "UNIQUE constraint failed: users.provider_identifier")
 | 
									require.Contains(t, err.Error(), "UNIQUE constraint failed:")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -318,7 +318,7 @@ func TestConstraints(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				err = db.Save(&user).Error
 | 
									err = db.Save(&user).Error
 | 
				
			||||||
				require.Error(t, err)
 | 
									require.Error(t, err)
 | 
				
			||||||
				require.Contains(t, err.Error(), "UNIQUE constraint failed: users.provider_identifier")
 | 
									require.Contains(t, err.Error(), "UNIQUE constraint failed:")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -328,9 +328,9 @@ func TestConstraints(t *testing.T) {
 | 
				
			|||||||
				require.NoError(t, err)
 | 
									require.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				user := types.User{
 | 
									user := types.User{
 | 
				
			||||||
					Name: "user1",
 | 
										Name:               "user1",
 | 
				
			||||||
 | 
										ProviderIdentifier: sql.NullString{String: "http://test.com/user1", Valid: true},
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				user.ProviderIdentifier.String = "http://test.com/user1"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				err = db.Save(&user).Error
 | 
									err = db.Save(&user).Error
 | 
				
			||||||
				require.NoError(t, err)
 | 
									require.NoError(t, err)
 | 
				
			||||||
@ -340,9 +340,9 @@ func TestConstraints(t *testing.T) {
 | 
				
			|||||||
			name: "allow-duplicate-username-oidc-then-cli",
 | 
								name: "allow-duplicate-username-oidc-then-cli",
 | 
				
			||||||
			run: func(t *testing.T, db *gorm.DB) {
 | 
								run: func(t *testing.T, db *gorm.DB) {
 | 
				
			||||||
				user := types.User{
 | 
									user := types.User{
 | 
				
			||||||
					Name: "user1",
 | 
										Name:               "user1",
 | 
				
			||||||
 | 
										ProviderIdentifier: sql.NullString{String: "http://test.com/user1", Valid: true},
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				user.ProviderIdentifier.String = "http://test.com/user1"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				err := db.Save(&user).Error
 | 
									err := db.Save(&user).Error
 | 
				
			||||||
				require.NoError(t, err)
 | 
									require.NoError(t, err)
 | 
				
			||||||
@ -360,7 +360,7 @@ func TestConstraints(t *testing.T) {
 | 
				
			|||||||
				t.Fatalf("creating database: %s", err)
 | 
									t.Fatalf("creating database: %s", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			tt.run(t, db.DB)
 | 
								tt.run(t, db.DB.Debug())
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ type User struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Username for the user, is used if email is empty
 | 
						// Username for the user, is used if email is empty
 | 
				
			||||||
	// Should not be used, please use Username().
 | 
						// Should not be used, please use Username().
 | 
				
			||||||
	Name string `gorm:"uniqueIndex:idx_name_provider_identifier;index"`
 | 
						Name string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Typically the full name of the user
 | 
						// Typically the full name of the user
 | 
				
			||||||
	DisplayName string
 | 
						DisplayName string
 | 
				
			||||||
@ -39,7 +39,7 @@ type User struct {
 | 
				
			|||||||
	// Unique identifier of the user from OIDC,
 | 
						// Unique identifier of the user from OIDC,
 | 
				
			||||||
	// comes from `sub` claim in the OIDC token
 | 
						// comes from `sub` claim in the OIDC token
 | 
				
			||||||
	// and is used to lookup the user.
 | 
						// and is used to lookup the user.
 | 
				
			||||||
	ProviderIdentifier sql.NullString `gorm:"uniqueIndex:idx_name_provider_identifier;uniqueIndex:idx_provider_identifier"`
 | 
						ProviderIdentifier sql.NullString
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Provider is the origin of the user account,
 | 
						// Provider is the origin of the user account,
 | 
				
			||||||
	// same as RegistrationMethod, without authkey.
 | 
						// same as RegistrationMethod, without authkey.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user