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 19:15:40 +01:00
1 parent fe260f5adf
commit 060f145ac6
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.
func credentialToPreAuthKey(c *types.Credential) *types.PreAuthKey {
return &types.PreAuthKey{
ID: c.ID,
Prefix: c.Identifier,
Hash: c.Hash,
UserID: c.UserID,
User: c.User,
Description: c.Description,
Reusable: c.Reusable,
Ephemeral: c.Ephemeral,
Used: c.Used,
Tags: c.Tags,
CreatedAt: c.CreatedAt,
Expiration: c.Expiration,
Revoked: c.Revoked,
ID: c.ID,
Prefix: c.Identifier,
Hash: c.Hash,
UserID: c.UserID,
User: c.User,
Description: c.Description,
Reusable: c.Reusable,
Ephemeral: c.Ephemeral,
Used: c.Used,
Tags: c.Tags,
CreatedByToken: c.CreatedByToken,
CreatedAt: c.CreatedAt,
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 },
},
{
// 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,
expiration 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 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,
expiration 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 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,
expiration 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 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.
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
Expiration *time.Time
Revoked *time.Time
@@ -72,19 +76,20 @@ func (pak *PreAuthKey) AsCredential() *Credential {
}
return &Credential{
ID: pak.ID,
Kind: CredentialPreAuthKey,
Identifier: pak.Prefix,
Hash: pak.Hash,
UserID: pak.UserID,
User: pak.User,
Description: pak.Description,
Reusable: pak.Reusable,
Ephemeral: pak.Ephemeral,
Used: pak.Used,
Tags: pak.Tags,
CreatedAt: pak.CreatedAt,
Expiration: pak.Expiration,
Revoked: pak.Revoked,
ID: pak.ID,
Kind: CredentialPreAuthKey,
Identifier: pak.Prefix,
Hash: pak.Hash,
UserID: pak.UserID,
User: pak.User,
Description: pak.Description,
Reusable: pak.Reusable,
Ephemeral: pak.Ephemeral,
Used: pak.Used,
Tags: pak.Tags,
CreatedByToken: pak.CreatedByToken,
CreatedAt: pak.CreatedAt,
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).
Tags []string `gorm:"serializer:json"`
// CreatedByToken is set when an OAuth access token made the key.
CreatedByToken bool
CreatedAt *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.
var _PreAuthKeyCloneNeedsRegeneration = PreAuthKey(struct {
ID uint64
Prefix string
Hash []byte
UserID *uint
User *User
Description string
Reusable bool
Ephemeral bool
Used bool
Tags []string
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
ID uint64
Prefix string
Hash []byte
UserID *uint
User *User
Description string
Reusable bool
Ephemeral bool
Used bool
Tags []string
CreatedByToken bool
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
}{})
// 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.
var _CredentialCloneNeedsRegeneration = Credential(struct {
ID uint64
Kind CredentialKind
Identifier string
Hash []byte
UserID *uint
User *User
Description string
Scopes []string
Tags []string
Reusable bool
Ephemeral bool
Used bool
LastSeen *time.Time
ClientID string
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
ID uint64
Kind CredentialKind
Identifier string
Hash []byte
UserID *uint
User *User
Description string
Scopes []string
Tags []string
Reusable bool
Ephemeral bool
Used bool
LastSeen *time.Time
ClientID string
CreatedByToken bool
CreatedAt *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.
// If non-empty, this creates tagged nodes (not user-owned).
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] {
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.
var _PreAuthKeyViewNeedsRegeneration = PreAuthKey(struct {
ID uint64
Prefix string
Hash []byte
UserID *uint
User *User
Description string
Reusable bool
Ephemeral bool
Used bool
Tags []string
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
ID uint64
Prefix string
Hash []byte
UserID *uint
User *User
Description string
Reusable bool
Ephemeral bool
Used bool
Tags []string
CreatedByToken bool
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
}{})
// 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
// the Identifier of its issuing OAuth client.
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] {
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.
var _CredentialViewNeedsRegeneration = Credential(struct {
ID uint64
Kind CredentialKind
Identifier string
Hash []byte
UserID *uint
User *User
Description string
Scopes []string
Tags []string
Reusable bool
Ephemeral bool
Used bool
LastSeen *time.Time
ClientID string
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
ID uint64
Kind CredentialKind
Identifier string
Hash []byte
UserID *uint
User *User
Description string
Scopes []string
Tags []string
Reusable bool
Ephemeral bool
Used bool
LastSeen *time.Time
ClientID string
CreatedByToken bool
CreatedAt *time.Time
Expiration *time.Time
Revoked *time.Time
}{})