db, types: add a credentials column for keys a token made

No released version made keys from tokens, so existing rows stay false.
This commit is contained in:
Kristoffer Dalby committed 2026-11-02 17:46:54 +00:00
1 parent f838b0ab2d
commit 7d8d875c80
8 files changed
+137 -87

No files matched your search

+14 -13
View File
@@ -39,19 +39,20 @@ func credentialToOAuthClient(c *types.Credential) *types.OAuthClient {
// the User association is carried through when preloaded. // the User association is carried through when preloaded.
func credentialToPreAuthKey(c *types.Credential) *types.PreAuthKey { func credentialToPreAuthKey(c *types.Credential) *types.PreAuthKey {
return &types.PreAuthKey{ return &types.PreAuthKey{
ID: c.ID, ID: c.ID,
Prefix: c.Identifier, Prefix: c.Identifier,
Hash: c.Hash, Hash: c.Hash,
UserID: c.UserID, UserID: c.UserID,
User: c.User, User: c.User,
Description: c.Description, Description: c.Description,
Reusable: c.Reusable, Reusable: c.Reusable,
Ephemeral: c.Ephemeral, Ephemeral: c.Ephemeral,
Used: c.Used, Used: c.Used,
Tags: c.Tags, Tags: c.Tags,
CreatedAt: c.CreatedAt, CreatedByToken: c.CreatedByToken,
Expiration: c.Expiration, CreatedAt: c.CreatedAt,
Revoked: c.Revoked, Expiration: c.Expiration,
Revoked: c.Revoked,
} }
} }
+27
View File
@@ -331,6 +331,33 @@ WHERE auth_key_id IN (
}, },
Rollback: func(db *gorm.DB) error { return nil }, Rollback: func(db *gorm.DB) error { return nil },
}, },
{
// Mark the auth keys an OAuth access token makes. A database
// that got the credentials table from the DDL above already
// has the column; no released version made keys from tokens,
// so existing rows stay false.
ID: "202610221200-credential-created-by-token",
Migrate: func(tx *gorm.DB) error {
return tx.Transaction(func(tx *gorm.DB) error {
if tx.Migrator().HasColumn(&types.Credential{}, "created_by_token") {
return nil
}
colType := "numeric"
if tx.Name() != sqlite.DriverName {
colType = "boolean"
}
err := tx.Exec(`ALTER TABLE credentials ADD COLUMN created_by_token ` + colType + ` DEFAULT false`).Error
if err != nil {
return fmt.Errorf("adding created_by_token to credentials: %w", err)
}
return nil
})
},
Rollback: func(db *gorm.DB) error { return nil },
},
}, },
) )
+2
View File
@@ -32,6 +32,7 @@ const credentialsDDLSQLite = `CREATE TABLE credentials(
created_at datetime, created_at datetime,
expiration datetime, expiration datetime,
revoked datetime, revoked datetime,
created_by_token numeric DEFAULT false,
CONSTRAINT fk_credentials_user FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL, CONSTRAINT fk_credentials_user FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT chk_credentials_hash CHECK(hash IS NOT NULL OR revoked IS NOT NULL), CONSTRAINT chk_credentials_hash CHECK(hash IS NOT NULL OR revoked IS NOT NULL),
@@ -59,6 +60,7 @@ const credentialsDDLPostgres = `CREATE TABLE credentials(
created_at timestamptz, created_at timestamptz,
expiration timestamptz, expiration timestamptz,
revoked timestamptz, revoked timestamptz,
created_by_token boolean DEFAULT false,
CONSTRAINT fk_credentials_user FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL, CONSTRAINT fk_credentials_user FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT chk_credentials_hash CHECK(hash IS NOT NULL OR revoked IS NOT NULL), CONSTRAINT chk_credentials_hash CHECK(hash IS NOT NULL OR revoked IS NOT NULL),
+1
View File
@@ -60,6 +60,7 @@ CREATE TABLE credentials(
created_at datetime, created_at datetime,
expiration datetime, expiration datetime,
revoked datetime, revoked datetime,
created_by_token numeric DEFAULT false,
CONSTRAINT fk_credentials_user FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL, CONSTRAINT fk_credentials_user FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT chk_credentials_hash CHECK(hash IS NOT NULL OR revoked IS NOT NULL), CONSTRAINT chk_credentials_hash CHECK(hash IS NOT NULL OR revoked IS NOT NULL),
+19 -14
View File
@@ -52,6 +52,10 @@ type Credential struct {
// the Identifier of its issuing OAuth client. // the Identifier of its issuing OAuth client.
ClientID string ClientID string
// CreatedByToken marks a pre-auth key an OAuth access token made: a token
// lists those without all=true.
CreatedByToken bool `gorm:"default:false"`
CreatedAt *time.Time CreatedAt *time.Time
Expiration *time.Time Expiration *time.Time
Revoked *time.Time Revoked *time.Time
@@ -72,19 +76,20 @@ func (pak *PreAuthKey) AsCredential() *Credential {
} }
return &Credential{ return &Credential{
ID: pak.ID, ID: pak.ID,
Kind: CredentialPreAuthKey, Kind: CredentialPreAuthKey,
Identifier: pak.Prefix, Identifier: pak.Prefix,
Hash: pak.Hash, Hash: pak.Hash,
UserID: pak.UserID, UserID: pak.UserID,
User: pak.User, User: pak.User,
Description: pak.Description, Description: pak.Description,
Reusable: pak.Reusable, Reusable: pak.Reusable,
Ephemeral: pak.Ephemeral, Ephemeral: pak.Ephemeral,
Used: pak.Used, Used: pak.Used,
Tags: pak.Tags, Tags: pak.Tags,
CreatedAt: pak.CreatedAt, CreatedByToken: pak.CreatedByToken,
Expiration: pak.Expiration, CreatedAt: pak.CreatedAt,
Revoked: pak.Revoked, Expiration: pak.Expiration,
Revoked: pak.Revoked,
} }
} }
+3
View File
@@ -65,6 +65,9 @@ type PreAuthKey struct {
// If non-empty, this creates tagged nodes (not user-owned). // If non-empty, this creates tagged nodes (not user-owned).
Tags []string `gorm:"serializer:json"` Tags []string `gorm:"serializer:json"`
// CreatedByToken is set when an OAuth access token made the key.
CreatedByToken bool
CreatedAt *time.Time CreatedAt *time.Time
Expiration *time.Time Expiration *time.Time
+32 -30
View File
@@ -144,19 +144,20 @@ func (src *PreAuthKey) Clone() *PreAuthKey {
// A compilation failure here means this code must be regenerated, with the command at the top of this file. // A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _PreAuthKeyCloneNeedsRegeneration = PreAuthKey(struct { var _PreAuthKeyCloneNeedsRegeneration = PreAuthKey(struct {
ID uint64 ID uint64
Prefix string Prefix string
Hash []byte Hash []byte
UserID *uint UserID *uint
User *User User *User
Description string Description string
Reusable bool Reusable bool
Ephemeral bool Ephemeral bool
Used bool Used bool
Tags []string Tags []string
CreatedAt *time.Time CreatedByToken bool
Expiration *time.Time CreatedAt *time.Time
Revoked *time.Time Expiration *time.Time
Revoked *time.Time
}{}) }{})
// Clone makes a deep copy of Credential. // Clone makes a deep copy of Credential.
@@ -193,21 +194,22 @@ func (src *Credential) Clone() *Credential {
// A compilation failure here means this code must be regenerated, with the command at the top of this file. // A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _CredentialCloneNeedsRegeneration = Credential(struct { var _CredentialCloneNeedsRegeneration = Credential(struct {
ID uint64 ID uint64
Kind CredentialKind Kind CredentialKind
Identifier string Identifier string
Hash []byte Hash []byte
UserID *uint UserID *uint
User *User User *User
Description string Description string
Scopes []string Scopes []string
Tags []string Tags []string
Reusable bool Reusable bool
Ephemeral bool Ephemeral bool
Used bool Used bool
LastSeen *time.Time LastSeen *time.Time
ClientID string ClientID string
CreatedAt *time.Time CreatedByToken bool
Expiration *time.Time CreatedAt *time.Time
Revoked *time.Time Expiration *time.Time
Revoked *time.Time
}{}) }{})
+39 -30
View File
@@ -425,6 +425,9 @@ func (v PreAuthKeyView) Used() bool { return v.ж.Used }
// Tags are copied to the node during registration. // Tags are copied to the node during registration.
// If non-empty, this creates tagged nodes (not user-owned). // If non-empty, this creates tagged nodes (not user-owned).
func (v PreAuthKeyView) Tags() views.Slice[string] { return views.SliceOf(v.ж.Tags) } func (v PreAuthKeyView) Tags() views.Slice[string] { return views.SliceOf(v.ж.Tags) }
// CreatedByToken is set when an OAuth access token made the key.
func (v PreAuthKeyView) CreatedByToken() bool { return v.ж.CreatedByToken }
func (v PreAuthKeyView) CreatedAt() views.ValuePointer[time.Time] { func (v PreAuthKeyView) CreatedAt() views.ValuePointer[time.Time] {
return views.ValuePointerOf(v.ж.CreatedAt) return views.ValuePointerOf(v.ж.CreatedAt)
} }
@@ -442,19 +445,20 @@ func (v PreAuthKeyView) Revoked() views.ValuePointer[time.Time] {
// A compilation failure here means this code must be regenerated, with the command at the top of this file. // A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _PreAuthKeyViewNeedsRegeneration = PreAuthKey(struct { var _PreAuthKeyViewNeedsRegeneration = PreAuthKey(struct {
ID uint64 ID uint64
Prefix string Prefix string
Hash []byte Hash []byte
UserID *uint UserID *uint
User *User User *User
Description string Description string
Reusable bool Reusable bool
Ephemeral bool Ephemeral bool
Used bool Used bool
Tags []string Tags []string
CreatedAt *time.Time CreatedByToken bool
Expiration *time.Time CreatedAt *time.Time
Revoked *time.Time Expiration *time.Time
Revoked *time.Time
}{}) }{})
// View returns a read-only view of Credential. // View returns a read-only view of Credential.
@@ -547,6 +551,10 @@ func (v CredentialView) LastSeen() views.ValuePointer[time.Time] {
// ClientID links an OAuth access token (Kind == CredentialOAuthToken) back to // ClientID links an OAuth access token (Kind == CredentialOAuthToken) back to
// the Identifier of its issuing OAuth client. // the Identifier of its issuing OAuth client.
func (v CredentialView) ClientID() string { return v.ж.ClientID } func (v CredentialView) ClientID() string { return v.ж.ClientID }
// CreatedByToken marks a pre-auth key an OAuth access token made: a token
// lists those without all=true.
func (v CredentialView) CreatedByToken() bool { return v.ж.CreatedByToken }
func (v CredentialView) CreatedAt() views.ValuePointer[time.Time] { func (v CredentialView) CreatedAt() views.ValuePointer[time.Time] {
return views.ValuePointerOf(v.ж.CreatedAt) return views.ValuePointerOf(v.ж.CreatedAt)
} }
@@ -561,21 +569,22 @@ func (v CredentialView) Revoked() views.ValuePointer[time.Time] {
// A compilation failure here means this code must be regenerated, with the command at the top of this file. // A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _CredentialViewNeedsRegeneration = Credential(struct { var _CredentialViewNeedsRegeneration = Credential(struct {
ID uint64 ID uint64
Kind CredentialKind Kind CredentialKind
Identifier string Identifier string
Hash []byte Hash []byte
UserID *uint UserID *uint
User *User User *User
Description string Description string
Scopes []string Scopes []string
Tags []string Tags []string
Reusable bool Reusable bool
Ephemeral bool Ephemeral bool
Used bool Used bool
LastSeen *time.Time LastSeen *time.Time
ClientID string ClientID string
CreatedAt *time.Time CreatedByToken bool
Expiration *time.Time CreatedAt *time.Time
Revoked *time.Time Expiration *time.Time
Revoked *time.Time
}{}) }{})