make tags first class node owner (#2885)
This PR changes tags to be something that exists on nodes in addition to users, to being its own thing. It is part of moving our tags support towards the correct tailscale compatible implementation. There are probably rough edges in this PR, but the intention is to get it in, and then start fixing bugs from 0.28.0 milestone (long standing tags issue) to discover what works and what doesnt. Updates #2417 Closes #2619
This commit is contained in:
parent
705b239677
commit
eb788cd007
49 changed files with 3102 additions and 757 deletions
|
|
@ -577,6 +577,21 @@ AND auth_key_id NOT IN (
|
|||
},
|
||||
Rollback: func(db *gorm.DB) error { return nil },
|
||||
},
|
||||
{
|
||||
// Rename forced_tags column to tags in nodes table.
|
||||
// This must run after migration 202505141324 which creates tables with forced_tags.
|
||||
ID: "202511131445-node-forced-tags-to-tags",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
// Rename the column from forced_tags to tags
|
||||
err := tx.Migrator().RenameColumn(&types.Node{}, "forced_tags", "tags")
|
||||
if err != nil {
|
||||
return fmt.Errorf("renaming forced_tags to tags: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Rollback: func(db *gorm.DB) error { return nil },
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -231,8 +231,7 @@ func TestPostgresMigrationAndDataValidation(t *testing.T) {
|
|||
name string
|
||||
dbPath string
|
||||
wantFunc func(*testing.T, *HSDatabase)
|
||||
}{
|
||||
}
|
||||
}{}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func TestIPAllocatorSequential(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.1"),
|
||||
IPv6: nap("fd7a:115c:a1e0::1"),
|
||||
})
|
||||
|
|
@ -123,7 +123,7 @@ func TestIPAllocatorSequential(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.2"),
|
||||
IPv6: nap("fd7a:115c:a1e0::2"),
|
||||
})
|
||||
|
|
@ -309,7 +309,7 @@ func TestBackfillIPAddresses(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.1"),
|
||||
})
|
||||
|
||||
|
|
@ -334,7 +334,7 @@ func TestBackfillIPAddresses(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv6: nap("fd7a:115c:a1e0::1"),
|
||||
})
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ func TestBackfillIPAddresses(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.1"),
|
||||
IPv6: nap("fd7a:115c:a1e0::1"),
|
||||
})
|
||||
|
|
@ -383,7 +383,7 @@ func TestBackfillIPAddresses(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.1"),
|
||||
IPv6: nap("fd7a:115c:a1e0::1"),
|
||||
})
|
||||
|
|
@ -407,19 +407,19 @@ func TestBackfillIPAddresses(t *testing.T) {
|
|||
db.DB.Save(&user)
|
||||
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.1"),
|
||||
})
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.2"),
|
||||
})
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.3"),
|
||||
})
|
||||
db.DB.Save(&types.Node{
|
||||
User: user,
|
||||
User: &user,
|
||||
IPv4: nap("100.64.0.4"),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -196,8 +196,9 @@ func SetTags(
|
|||
tags []string,
|
||||
) error {
|
||||
if len(tags) == 0 {
|
||||
// if no tags are provided, we remove all forced tags
|
||||
if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("forced_tags", "[]").Error; err != nil {
|
||||
// if no tags are provided, we remove all tags
|
||||
err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("tags", "[]").Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing tags: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +212,8 @@ func SetTags(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("forced_tags", string(b)).Error; err != nil {
|
||||
err = tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("tags", string(b)).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("updating tags: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -349,12 +351,20 @@ func RegisterNodeForTest(tx *gorm.DB, node types.Node, ipv4 *netip.Addr, ipv6 *n
|
|||
panic("RegisterNodeForTest can only be called during tests")
|
||||
}
|
||||
|
||||
log.Debug().
|
||||
logEvent := log.Debug().
|
||||
Str("node", node.Hostname).
|
||||
Str("machine_key", node.MachineKey.ShortString()).
|
||||
Str("node_key", node.NodeKey.ShortString()).
|
||||
Str("user", node.User.Username()).
|
||||
Msg("Registering test node")
|
||||
Str("node_key", node.NodeKey.ShortString())
|
||||
|
||||
if node.User != nil {
|
||||
logEvent = logEvent.Str("user", node.User.Username())
|
||||
} else if node.UserID != nil {
|
||||
logEvent = logEvent.Uint("user_id", *node.UserID)
|
||||
} else {
|
||||
logEvent = logEvent.Str("user", "none")
|
||||
}
|
||||
|
||||
logEvent.Msg("Registering test node")
|
||||
|
||||
// If the a new node is registered with the same machine key, to the same user,
|
||||
// update the existing node.
|
||||
|
|
@ -642,7 +652,7 @@ func (hsdb *HSDatabase) CreateNodeForTest(user *types.User, hostname ...string)
|
|||
}
|
||||
|
||||
// Create a preauth key for the node
|
||||
pak, err := hsdb.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil)
|
||||
pak, err := hsdb.CreatePreAuthKey(user.TypedID(), false, false, nil, nil)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to create preauth key for test node: %v", err))
|
||||
}
|
||||
|
|
@ -656,7 +666,7 @@ func (hsdb *HSDatabase) CreateNodeForTest(user *types.User, hostname ...string)
|
|||
NodeKey: nodeKey.Public(),
|
||||
DiscoKey: discoKey.Public(),
|
||||
Hostname: nodeName,
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(pak.ID),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ func (s *Suite) TestExpireNode(c *check.C) {
|
|||
user, err := db.CreateUser(types.User{Name: "test"})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil)
|
||||
pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
_, err = db.getNode(types.UserID(user.ID), "testnode")
|
||||
|
|
@ -97,7 +97,7 @@ func (s *Suite) TestExpireNode(c *check.C) {
|
|||
MachineKey: machineKey.Public(),
|
||||
NodeKey: nodeKey.Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(pak.ID),
|
||||
Expiry: &time.Time{},
|
||||
|
|
@ -124,7 +124,7 @@ func (s *Suite) TestSetTags(c *check.C) {
|
|||
user, err := db.CreateUser(types.User{Name: "test"})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil)
|
||||
pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
_, err = db.getNode(types.UserID(user.ID), "testnode")
|
||||
|
|
@ -138,7 +138,7 @@ func (s *Suite) TestSetTags(c *check.C) {
|
|||
MachineKey: machineKey.Public(),
|
||||
NodeKey: nodeKey.Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(pak.ID),
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ func (s *Suite) TestSetTags(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
node, err = db.getNode(types.UserID(user.ID), "testnode")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(node.ForcedTags, check.DeepEquals, sTags)
|
||||
c.Assert(node.Tags, check.DeepEquals, sTags)
|
||||
|
||||
// assign duplicate tags, expect no errors but no doubles in DB
|
||||
eTags := []string{"tag:bar", "tag:test", "tag:unknown", "tag:test"}
|
||||
|
|
@ -161,17 +161,10 @@ func (s *Suite) TestSetTags(c *check.C) {
|
|||
node, err = db.getNode(types.UserID(user.ID), "testnode")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(
|
||||
node.ForcedTags,
|
||||
node.Tags,
|
||||
check.DeepEquals,
|
||||
[]string{"tag:bar", "tag:test", "tag:unknown"},
|
||||
)
|
||||
|
||||
// test removing tags
|
||||
err = db.SetTags(node.ID, []string{})
|
||||
c.Assert(err, check.IsNil)
|
||||
node, err = db.getNode(types.UserID(user.ID), "testnode")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(node.ForcedTags, check.DeepEquals, []string{})
|
||||
}
|
||||
|
||||
func TestHeadscale_generateGivenName(t *testing.T) {
|
||||
|
|
@ -430,7 +423,7 @@ func TestAutoApproveRoutes(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tt.routes,
|
||||
|
|
@ -446,12 +439,12 @@ func TestAutoApproveRoutes(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "taggednode",
|
||||
UserID: taggedUser.ID,
|
||||
UserID: &taggedUser.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tt.routes,
|
||||
},
|
||||
ForcedTags: []string{"tag:exit"},
|
||||
Tags: []string{"tag:exit"},
|
||||
IPv4: ptr.To(netip.MustParseAddr("100.64.0.2")),
|
||||
}
|
||||
|
||||
|
|
@ -593,10 +586,10 @@ func TestListEphemeralNodes(t *testing.T) {
|
|||
user, err := db.CreateUser(types.User{Name: "test"})
|
||||
require.NoError(t, err)
|
||||
|
||||
pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil)
|
||||
pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
pakEph, err := db.CreatePreAuthKey(types.UserID(user.ID), false, true, nil, nil)
|
||||
pakEph, err := db.CreatePreAuthKey(user.TypedID(), false, true, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
node := types.Node{
|
||||
|
|
@ -604,7 +597,7 @@ func TestListEphemeralNodes(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(pak.ID),
|
||||
}
|
||||
|
|
@ -614,7 +607,7 @@ func TestListEphemeralNodes(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "ephemeral",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(pakEph.ID),
|
||||
}
|
||||
|
|
@ -657,7 +650,7 @@ func TestNodeNaming(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
@ -667,7 +660,7 @@ func TestNodeNaming(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test",
|
||||
UserID: user2.ID,
|
||||
UserID: &user2.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
@ -680,7 +673,7 @@ func TestNodeNaming(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "我的电脑",
|
||||
UserID: user2.ID,
|
||||
UserID: &user2.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
}
|
||||
|
||||
|
|
@ -688,7 +681,7 @@ func TestNodeNaming(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "a",
|
||||
UserID: user2.ID,
|
||||
UserID: &user2.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
}
|
||||
|
||||
|
|
@ -808,7 +801,7 @@ func TestRenameNodeComprehensive(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
@ -931,7 +924,7 @@ func TestListPeers(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test1",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
@ -941,7 +934,7 @@ func TestListPeers(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test2",
|
||||
UserID: user2.ID,
|
||||
UserID: &user2.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
@ -1016,7 +1009,7 @@ func TestListNodes(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test1",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
@ -1026,7 +1019,7 @@ func TestListNodes(t *testing.T) {
|
|||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test2",
|
||||
UserID: user2.ID,
|
||||
UserID: &user2.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,15 +15,15 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrPreAuthKeyNotFound = errors.New("AuthKey not found")
|
||||
ErrPreAuthKeyExpired = errors.New("AuthKey expired")
|
||||
ErrSingleUseAuthKeyHasBeenUsed = errors.New("AuthKey has already been used")
|
||||
ErrPreAuthKeyNotFound = errors.New("auth-key not found")
|
||||
ErrPreAuthKeyExpired = errors.New("auth-key expired")
|
||||
ErrSingleUseAuthKeyHasBeenUsed = errors.New("auth-key has already been used")
|
||||
ErrUserMismatch = errors.New("user mismatch")
|
||||
ErrPreAuthKeyACLTagInvalid = errors.New("AuthKey tag is invalid")
|
||||
ErrPreAuthKeyACLTagInvalid = errors.New("auth-key tag is invalid")
|
||||
)
|
||||
|
||||
func (hsdb *HSDatabase) CreatePreAuthKey(
|
||||
uid types.UserID,
|
||||
uid *types.UserID,
|
||||
reusable bool,
|
||||
ephemeral bool,
|
||||
expiration *time.Time,
|
||||
|
|
@ -41,17 +41,40 @@ const (
|
|||
)
|
||||
|
||||
// CreatePreAuthKey creates a new PreAuthKey in a user, and returns it.
|
||||
// The uid parameter can be nil for system-created tagged keys.
|
||||
// For tagged keys, uid tracks "created by" (who created the key).
|
||||
// For user-owned keys, uid tracks the node owner.
|
||||
func CreatePreAuthKey(
|
||||
tx *gorm.DB,
|
||||
uid types.UserID,
|
||||
uid *types.UserID,
|
||||
reusable bool,
|
||||
ephemeral bool,
|
||||
expiration *time.Time,
|
||||
aclTags []string,
|
||||
) (*types.PreAuthKeyNew, error) {
|
||||
user, err := GetUserByID(tx, uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Validate: must be tagged OR user-owned, not neither
|
||||
if uid == nil && len(aclTags) == 0 {
|
||||
return nil, ErrPreAuthKeyNotTaggedOrOwned
|
||||
}
|
||||
|
||||
// If uid != nil && len(aclTags) > 0:
|
||||
// Both are allowed: UserID tracks "created by", tags define node ownership
|
||||
// This is valid per the new model
|
||||
|
||||
var (
|
||||
user *types.User
|
||||
userID *uint
|
||||
)
|
||||
|
||||
if uid != nil {
|
||||
var err error
|
||||
|
||||
user, err = GetUserByID(tx, *uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userID = &user.ID
|
||||
}
|
||||
|
||||
// Remove duplicates and sort for consistency
|
||||
|
|
@ -108,15 +131,15 @@ func CreatePreAuthKey(
|
|||
}
|
||||
|
||||
key := types.PreAuthKey{
|
||||
UserID: user.ID,
|
||||
User: *user,
|
||||
UserID: userID, // nil for system-created keys, or "created by" for tagged keys
|
||||
User: user, // nil for system-created keys
|
||||
Reusable: reusable,
|
||||
Ephemeral: ephemeral,
|
||||
CreatedAt: &now,
|
||||
Expiration: expiration,
|
||||
Tags: aclTags,
|
||||
Prefix: prefix, // Store prefix
|
||||
Hash: hash, // Store hash
|
||||
Tags: aclTags, // empty for user-owned keys
|
||||
Prefix: prefix, // Store prefix
|
||||
Hash: hash, // Store hash
|
||||
}
|
||||
|
||||
if err := tx.Save(&key).Error; err != nil {
|
||||
|
|
@ -149,14 +172,19 @@ func ListPreAuthKeysByUser(tx *gorm.DB, uid types.UserID) ([]types.PreAuthKey, e
|
|||
}
|
||||
|
||||
keys := []types.PreAuthKey{}
|
||||
if err := tx.Preload("User").Where(&types.PreAuthKey{UserID: user.ID}).Find(&keys).Error; err != nil {
|
||||
|
||||
err = tx.Preload("User").Where(&types.PreAuthKey{UserID: &user.ID}).Find(&keys).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
var ErrPreAuthKeyFailedToParse = errors.New("failed to parse AuthKey")
|
||||
var (
|
||||
ErrPreAuthKeyFailedToParse = errors.New("failed to parse auth-key")
|
||||
ErrPreAuthKeyNotTaggedOrOwned = errors.New("auth-key must be either tagged or owned by user")
|
||||
)
|
||||
|
||||
func findAuthKey(tx *gorm.DB, keyStr string) (*types.PreAuthKey, error) {
|
||||
var pak types.PreAuthKey
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func TestCreatePreAuthKey(t *testing.T) {
|
|||
test: func(t *testing.T, db *HSDatabase) {
|
||||
t.Helper()
|
||||
|
||||
_, err := db.CreatePreAuthKey(12345, true, false, nil, nil)
|
||||
_, err := db.CreatePreAuthKey(ptr.To(types.UserID(12345)), true, false, nil, nil)
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
|
|
@ -36,7 +36,7 @@ func TestCreatePreAuthKey(t *testing.T) {
|
|||
user, err := db.CreateUser(types.User{Name: "test"})
|
||||
require.NoError(t, err)
|
||||
|
||||
key, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil)
|
||||
key, err := db.CreatePreAuthKey(user.TypedID(), true, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, key.Key)
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ func TestPreAuthKeyACLTags(t *testing.T) {
|
|||
user, err := db.CreateUser(types.User{Name: "test-tags-1"})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, []string{"badtag"})
|
||||
_, err = db.CreatePreAuthKey(user.TypedID(), false, false, nil, []string{"badtag"})
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
|
|
@ -98,7 +98,7 @@ func TestPreAuthKeyACLTags(t *testing.T) {
|
|||
expectedTags := []string{"tag:test1", "tag:test2"}
|
||||
tagsWithDuplicate := []string{"tag:test1", "tag:test2", "tag:test2"}
|
||||
|
||||
_, err = db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, tagsWithDuplicate)
|
||||
_, err = db.CreatePreAuthKey(user.TypedID(), false, false, nil, tagsWithDuplicate)
|
||||
require.NoError(t, err)
|
||||
|
||||
listedPaks, err := db.ListPreAuthKeys(types.UserID(user.ID))
|
||||
|
|
@ -128,13 +128,13 @@ func TestCannotDeleteAssignedPreAuthKey(t *testing.T) {
|
|||
user, err := db.CreateUser(types.User{Name: "test8"})
|
||||
require.NoError(t, err)
|
||||
|
||||
key, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, []string{"tag:good"})
|
||||
key, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, []string{"tag:good"})
|
||||
require.NoError(t, err)
|
||||
|
||||
node := types.Node{
|
||||
ID: 0,
|
||||
Hostname: "testest",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(key.ID),
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ func TestPreAuthKeyAuthentication(t *testing.T) {
|
|||
validateResult: func(t *testing.T, pak *types.PreAuthKey) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, user.ID, pak.UserID)
|
||||
assert.Equal(t, user.ID, *pak.UserID)
|
||||
assert.NotEmpty(t, pak.Key) // Legacy keys have Key populated
|
||||
assert.Empty(t, pak.Prefix) // Legacy keys have empty Prefix
|
||||
assert.Nil(t, pak.Hash) // Legacy keys have nil Hash
|
||||
|
|
@ -191,7 +191,7 @@ func TestPreAuthKeyAuthentication(t *testing.T) {
|
|||
setupKey: func() string {
|
||||
// Create new key via API
|
||||
keyStr, err := db.CreatePreAuthKey(
|
||||
types.UserID(user.ID),
|
||||
user.TypedID(),
|
||||
true, false, nil, []string{"tag:test"},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -203,7 +203,7 @@ func TestPreAuthKeyAuthentication(t *testing.T) {
|
|||
validateResult: func(t *testing.T, pak *types.PreAuthKey) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, user.ID, pak.UserID)
|
||||
assert.Equal(t, user.ID, *pak.UserID)
|
||||
assert.Empty(t, pak.Key) // New keys have empty Key
|
||||
assert.NotEmpty(t, pak.Prefix) // New keys have Prefix
|
||||
assert.NotNil(t, pak.Hash) // New keys have Hash
|
||||
|
|
@ -214,7 +214,7 @@ func TestPreAuthKeyAuthentication(t *testing.T) {
|
|||
name: "new_key_format_validation",
|
||||
setupKey: func() string {
|
||||
keyStr, err := db.CreatePreAuthKey(
|
||||
types.UserID(user.ID),
|
||||
user.TypedID(),
|
||||
true, false, nil, nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -244,7 +244,7 @@ func TestPreAuthKeyAuthentication(t *testing.T) {
|
|||
setupKey: func() string {
|
||||
// Create valid key
|
||||
key, err := db.CreatePreAuthKey(
|
||||
types.UserID(user.ID),
|
||||
user.TypedID(),
|
||||
true, false, nil, nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -415,11 +415,11 @@ func TestMultipleLegacyKeysAllowed(t *testing.T) {
|
|||
assert.Len(t, legacyKeys, 5, "should have created 5 legacy keys")
|
||||
|
||||
// Now create new bcrypt-based keys - these should have unique prefixes
|
||||
key1, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil)
|
||||
key1, err := db.CreatePreAuthKey(user.TypedID(), true, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, key1.Key)
|
||||
|
||||
key2, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil)
|
||||
key2, err := db.CreatePreAuthKey(user.TypedID(), true, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, key2.Key)
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ CREATE TABLE nodes(
|
|||
given_name varchar(63),
|
||||
user_id integer,
|
||||
register_method text,
|
||||
forced_tags text,
|
||||
tags text,
|
||||
auth_key_id integer,
|
||||
last_seen datetime,
|
||||
expiry datetime,
|
||||
|
|
|
|||
|
|
@ -189,7 +189,11 @@ func (hsdb *HSDatabase) GetUserByName(name string) (*types.User, error) {
|
|||
// ListNodesByUser gets all the nodes in a given user.
|
||||
func ListNodesByUser(tx *gorm.DB, uid types.UserID) (types.Nodes, error) {
|
||||
nodes := types.Nodes{}
|
||||
if err := tx.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where(&types.Node{UserID: uint(uid)}).Find(&nodes).Error; err != nil {
|
||||
|
||||
uidPtr := uint(uid)
|
||||
|
||||
err := tx.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where(&types.Node{UserID: &uidPtr}).Find(&nodes).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func TestDestroyUserErrors(t *testing.T) {
|
|||
|
||||
user := db.CreateUserForTest("test")
|
||||
|
||||
pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil)
|
||||
pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = db.DestroyUser(types.UserID(user.ID))
|
||||
|
|
@ -71,13 +71,13 @@ func TestDestroyUserErrors(t *testing.T) {
|
|||
user, err := db.CreateUser(types.User{Name: "test"})
|
||||
require.NoError(t, err)
|
||||
|
||||
pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil)
|
||||
pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
node := types.Node{
|
||||
ID: 0,
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
UserID: &user.ID,
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
AuthKeyID: ptr.To(pak.ID),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue