mirror of
https://github.com/lordmathis/llamactl.git
synced 2025-12-22 17:14:22 +00:00
Compare commits
2 Commits
80d5d44a0b
...
99927160c2
| Author | SHA1 | Date | |
|---|---|---|---|
| 99927160c2 | |||
| c37c1b8161 |
@@ -20,7 +20,6 @@ type APIKey struct {
|
|||||||
UserID string
|
UserID string
|
||||||
PermissionMode PermissionMode
|
PermissionMode PermissionMode
|
||||||
ExpiresAt *int64
|
ExpiresAt *int64
|
||||||
Enabled bool
|
|
||||||
CreatedAt int64
|
CreatedAt int64
|
||||||
UpdatedAt int64
|
UpdatedAt int64
|
||||||
LastUsedAt *int64
|
LastUsedAt *int64
|
||||||
@@ -29,7 +28,6 @@ type APIKey struct {
|
|||||||
type KeyPermission struct {
|
type KeyPermission struct {
|
||||||
KeyID int
|
KeyID int
|
||||||
InstanceID int
|
InstanceID int
|
||||||
CanInfer bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateKey generates a cryptographically secure API key with the given prefix
|
// GenerateKey generates a cryptographically secure API key with the given prefix
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ func (db *sqliteDB) CreateKey(ctx context.Context, key *auth.APIKey, permissions
|
|||||||
|
|
||||||
// Insert the API key
|
// Insert the API key
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO api_keys (key_hash, name, user_id, permission_mode, expires_at, enabled, created_at, updated_at)
|
INSERT INTO api_keys (key_hash, name, user_id, permission_mode, expires_at, created_at, updated_at)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
`
|
`
|
||||||
|
|
||||||
var expiresAt sql.NullInt64
|
var expiresAt sql.NullInt64
|
||||||
@@ -29,7 +29,7 @@ func (db *sqliteDB) CreateKey(ctx context.Context, key *auth.APIKey, permissions
|
|||||||
|
|
||||||
result, err := tx.ExecContext(ctx, query,
|
result, err := tx.ExecContext(ctx, query,
|
||||||
key.KeyHash, key.Name, key.UserID, key.PermissionMode,
|
key.KeyHash, key.Name, key.UserID, key.PermissionMode,
|
||||||
expiresAt, key.Enabled, key.CreatedAt, key.UpdatedAt,
|
expiresAt, key.CreatedAt, key.UpdatedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to insert API key: %w", err)
|
return fmt.Errorf("failed to insert API key: %w", err)
|
||||||
@@ -45,10 +45,10 @@ func (db *sqliteDB) CreateKey(ctx context.Context, key *auth.APIKey, permissions
|
|||||||
if key.PermissionMode == auth.PermissionModePerInstance {
|
if key.PermissionMode == auth.PermissionModePerInstance {
|
||||||
for _, perm := range permissions {
|
for _, perm := range permissions {
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO key_permissions (key_id, instance_id, can_infer)
|
INSERT INTO key_permissions (key_id, instance_id)
|
||||||
VALUES (?, ?, ?)
|
VALUES (?, ?)
|
||||||
`
|
`
|
||||||
_, err := tx.ExecContext(ctx, query, key.ID, perm.InstanceID, perm.CanInfer)
|
_, err := tx.ExecContext(ctx, query, key.ID, perm.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to insert permission for instance %d: %w", perm.InstanceID, err)
|
return fmt.Errorf("failed to insert permission for instance %d: %w", perm.InstanceID, err)
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func (db *sqliteDB) CreateKey(ctx context.Context, key *auth.APIKey, permissions
|
|||||||
// GetKeyByID retrieves an API key by ID
|
// GetKeyByID retrieves an API key by ID
|
||||||
func (db *sqliteDB) GetKeyByID(ctx context.Context, id int) (*auth.APIKey, error) {
|
func (db *sqliteDB) GetKeyByID(ctx context.Context, id int) (*auth.APIKey, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, key_hash, name, user_id, permission_mode, expires_at, enabled, created_at, updated_at, last_used_at
|
SELECT id, key_hash, name, user_id, permission_mode, expires_at, created_at, updated_at, last_used_at
|
||||||
FROM api_keys
|
FROM api_keys
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`
|
`
|
||||||
@@ -72,7 +72,7 @@ func (db *sqliteDB) GetKeyByID(ctx context.Context, id int) (*auth.APIKey, error
|
|||||||
|
|
||||||
err := db.QueryRowContext(ctx, query, id).Scan(
|
err := db.QueryRowContext(ctx, query, id).Scan(
|
||||||
&key.ID, &key.KeyHash, &key.Name, &key.UserID, &key.PermissionMode,
|
&key.ID, &key.KeyHash, &key.Name, &key.UserID, &key.PermissionMode,
|
||||||
&expiresAt, &key.Enabled, &key.CreatedAt, &key.UpdatedAt, &lastUsedAt,
|
&expiresAt, &key.CreatedAt, &key.UpdatedAt, &lastUsedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
@@ -94,7 +94,7 @@ func (db *sqliteDB) GetKeyByID(ctx context.Context, id int) (*auth.APIKey, error
|
|||||||
// GetUserKeys retrieves all API keys for a user
|
// GetUserKeys retrieves all API keys for a user
|
||||||
func (db *sqliteDB) GetUserKeys(ctx context.Context, userID string) ([]*auth.APIKey, error) {
|
func (db *sqliteDB) GetUserKeys(ctx context.Context, userID string) ([]*auth.APIKey, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, key_hash, name, user_id, permission_mode, expires_at, enabled, created_at, updated_at, last_used_at
|
SELECT id, key_hash, name, user_id, permission_mode, expires_at, created_at, updated_at, last_used_at
|
||||||
FROM api_keys
|
FROM api_keys
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@@ -114,7 +114,7 @@ func (db *sqliteDB) GetUserKeys(ctx context.Context, userID string) ([]*auth.API
|
|||||||
|
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&key.ID, &key.KeyHash, &key.Name, &key.UserID, &key.PermissionMode,
|
&key.ID, &key.KeyHash, &key.Name, &key.UserID, &key.PermissionMode,
|
||||||
&expiresAt, &key.Enabled, &key.CreatedAt, &key.UpdatedAt, &lastUsedAt,
|
&expiresAt, &key.CreatedAt, &key.UpdatedAt, &lastUsedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to scan API key: %w", err)
|
return nil, fmt.Errorf("failed to scan API key: %w", err)
|
||||||
@@ -133,12 +133,12 @@ func (db *sqliteDB) GetUserKeys(ctx context.Context, userID string) ([]*auth.API
|
|||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActiveKeys retrieves all enabled, non-expired API keys
|
// GetActiveKeys retrieves all non-expired API keys
|
||||||
func (db *sqliteDB) GetActiveKeys(ctx context.Context) ([]*auth.APIKey, error) {
|
func (db *sqliteDB) GetActiveKeys(ctx context.Context) ([]*auth.APIKey, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, key_hash, name, user_id, permission_mode, expires_at, enabled, created_at, updated_at, last_used_at
|
SELECT id, key_hash, name, user_id, permission_mode, expires_at, created_at, updated_at, last_used_at
|
||||||
FROM api_keys
|
FROM api_keys
|
||||||
WHERE enabled = 1 AND (expires_at IS NULL OR expires_at > ?)
|
WHERE expires_at IS NULL OR expires_at > ?
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ func (db *sqliteDB) GetActiveKeys(ctx context.Context) ([]*auth.APIKey, error) {
|
|||||||
|
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&key.ID, &key.KeyHash, &key.Name, &key.UserID, &key.PermissionMode,
|
&key.ID, &key.KeyHash, &key.Name, &key.UserID, &key.PermissionMode,
|
||||||
&expiresAt, &key.Enabled, &key.CreatedAt, &key.UpdatedAt, &lastUsedAt,
|
&expiresAt, &key.CreatedAt, &key.UpdatedAt, &lastUsedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to scan API key: %w", err)
|
return nil, fmt.Errorf("failed to scan API key: %w", err)
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ CREATE TABLE IF NOT EXISTS api_keys (
|
|||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
permission_mode TEXT NOT NULL CHECK(permission_mode IN ('allow_all', 'per_instance')) DEFAULT 'per_instance',
|
permission_mode TEXT NOT NULL CHECK(permission_mode IN ('allow_all', 'per_instance')) DEFAULT 'per_instance',
|
||||||
expires_at INTEGER NULL,
|
expires_at INTEGER NULL,
|
||||||
enabled INTEGER NOT NULL DEFAULT 1,
|
|
||||||
created_at INTEGER NOT NULL,
|
created_at INTEGER NOT NULL,
|
||||||
updated_at INTEGER NOT NULL,
|
updated_at INTEGER NOT NULL,
|
||||||
last_used_at INTEGER NULL
|
last_used_at INTEGER NULL
|
||||||
@@ -48,7 +47,6 @@ CREATE TABLE IF NOT EXISTS api_keys (
|
|||||||
CREATE TABLE IF NOT EXISTS key_permissions (
|
CREATE TABLE IF NOT EXISTS key_permissions (
|
||||||
key_id INTEGER NOT NULL,
|
key_id INTEGER NOT NULL,
|
||||||
instance_id INTEGER NOT NULL,
|
instance_id INTEGER NOT NULL,
|
||||||
can_infer INTEGER NOT NULL DEFAULT 0,
|
|
||||||
PRIMARY KEY (key_id, instance_id),
|
PRIMARY KEY (key_id, instance_id),
|
||||||
FOREIGN KEY (key_id) REFERENCES api_keys (id) ON DELETE CASCADE,
|
FOREIGN KEY (key_id) REFERENCES api_keys (id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (instance_id) REFERENCES instances (id) ON DELETE CASCADE
|
FOREIGN KEY (instance_id) REFERENCES instances (id) ON DELETE CASCADE
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
// GetPermissions retrieves all permissions for a key
|
// GetPermissions retrieves all permissions for a key
|
||||||
func (db *sqliteDB) GetPermissions(ctx context.Context, keyID int) ([]auth.KeyPermission, error) {
|
func (db *sqliteDB) GetPermissions(ctx context.Context, keyID int) ([]auth.KeyPermission, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT key_id, instance_id, can_infer
|
SELECT key_id, instance_id
|
||||||
FROM key_permissions
|
FROM key_permissions
|
||||||
WHERE key_id = ?
|
WHERE key_id = ?
|
||||||
ORDER BY instance_id
|
ORDER BY instance_id
|
||||||
@@ -25,7 +25,7 @@ func (db *sqliteDB) GetPermissions(ctx context.Context, keyID int) ([]auth.KeyPe
|
|||||||
var permissions []auth.KeyPermission
|
var permissions []auth.KeyPermission
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var perm auth.KeyPermission
|
var perm auth.KeyPermission
|
||||||
err := rows.Scan(&perm.KeyID, &perm.InstanceID, &perm.CanInfer)
|
err := rows.Scan(&perm.KeyID, &perm.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to scan key permission: %w", err)
|
return nil, fmt.Errorf("failed to scan key permission: %w", err)
|
||||||
}
|
}
|
||||||
@@ -38,13 +38,13 @@ func (db *sqliteDB) GetPermissions(ctx context.Context, keyID int) ([]auth.KeyPe
|
|||||||
// HasPermission checks if key has inference permission for instance
|
// HasPermission checks if key has inference permission for instance
|
||||||
func (db *sqliteDB) HasPermission(ctx context.Context, keyID, instanceID int) (bool, error) {
|
func (db *sqliteDB) HasPermission(ctx context.Context, keyID, instanceID int) (bool, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT can_infer
|
SELECT 1
|
||||||
FROM key_permissions
|
FROM key_permissions
|
||||||
WHERE key_id = ? AND instance_id = ?
|
WHERE key_id = ? AND instance_id = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
var canInfer bool
|
var exists int
|
||||||
err := db.QueryRowContext(ctx, query, keyID, instanceID).Scan(&canInfer)
|
err := db.QueryRowContext(ctx, query, keyID, instanceID).Scan(&exists)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
// No permission record found, deny access
|
// No permission record found, deny access
|
||||||
@@ -53,5 +53,5 @@ func (db *sqliteDB) HasPermission(ctx context.Context, keyID, instanceID int) (b
|
|||||||
return false, fmt.Errorf("failed to check key permission: %w", err)
|
return false, fmt.Errorf("failed to check key permission: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return canInfer, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ import (
|
|||||||
|
|
||||||
// InstancePermission defines the permissions for an API key on a specific instance.
|
// InstancePermission defines the permissions for an API key on a specific instance.
|
||||||
type InstancePermission struct {
|
type InstancePermission struct {
|
||||||
InstanceID int `json:"instance_id"`
|
InstanceID int `json:"instance_id"`
|
||||||
CanInfer bool `json:"can_infer"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateKeyRequest represents the request body for creating a new API key.
|
// CreateKeyRequest represents the request body for creating a new API key.
|
||||||
@@ -32,7 +31,6 @@ type CreateKeyResponse struct {
|
|||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
PermissionMode auth.PermissionMode `json:"permission_mode"`
|
PermissionMode auth.PermissionMode `json:"permission_mode"`
|
||||||
ExpiresAt *int64 `json:"expires_at"`
|
ExpiresAt *int64 `json:"expires_at"`
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
CreatedAt int64 `json:"created_at"`
|
CreatedAt int64 `json:"created_at"`
|
||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
LastUsedAt *int64 `json:"last_used_at"`
|
LastUsedAt *int64 `json:"last_used_at"`
|
||||||
@@ -46,7 +44,6 @@ type KeyResponse struct {
|
|||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
PermissionMode auth.PermissionMode `json:"permission_mode"`
|
PermissionMode auth.PermissionMode `json:"permission_mode"`
|
||||||
ExpiresAt *int64 `json:"expires_at"`
|
ExpiresAt *int64 `json:"expires_at"`
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
CreatedAt int64 `json:"created_at"`
|
CreatedAt int64 `json:"created_at"`
|
||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
LastUsedAt *int64 `json:"last_used_at"`
|
LastUsedAt *int64 `json:"last_used_at"`
|
||||||
@@ -56,7 +53,6 @@ type KeyResponse struct {
|
|||||||
type KeyPermissionResponse struct {
|
type KeyPermissionResponse struct {
|
||||||
InstanceID int `json:"instance_id"`
|
InstanceID int `json:"instance_id"`
|
||||||
InstanceName string `json:"instance_name"`
|
InstanceName string `json:"instance_name"`
|
||||||
CanInfer bool `json:"can_infer"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateKey godoc
|
// CreateKey godoc
|
||||||
@@ -142,7 +138,6 @@ func (h *Handler) CreateKey() http.HandlerFunc {
|
|||||||
UserID: "system",
|
UserID: "system",
|
||||||
PermissionMode: req.PermissionMode,
|
PermissionMode: req.PermissionMode,
|
||||||
ExpiresAt: req.ExpiresAt,
|
ExpiresAt: req.ExpiresAt,
|
||||||
Enabled: true,
|
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
}
|
}
|
||||||
@@ -153,7 +148,6 @@ func (h *Handler) CreateKey() http.HandlerFunc {
|
|||||||
keyPermissions = append(keyPermissions, auth.KeyPermission{
|
keyPermissions = append(keyPermissions, auth.KeyPermission{
|
||||||
KeyID: 0, // Will be set by database after key creation
|
KeyID: 0, // Will be set by database after key creation
|
||||||
InstanceID: perm.InstanceID,
|
InstanceID: perm.InstanceID,
|
||||||
CanInfer: perm.CanInfer,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +165,6 @@ func (h *Handler) CreateKey() http.HandlerFunc {
|
|||||||
UserID: apiKey.UserID,
|
UserID: apiKey.UserID,
|
||||||
PermissionMode: apiKey.PermissionMode,
|
PermissionMode: apiKey.PermissionMode,
|
||||||
ExpiresAt: apiKey.ExpiresAt,
|
ExpiresAt: apiKey.ExpiresAt,
|
||||||
Enabled: apiKey.Enabled,
|
|
||||||
CreatedAt: apiKey.CreatedAt,
|
CreatedAt: apiKey.CreatedAt,
|
||||||
UpdatedAt: apiKey.UpdatedAt,
|
UpdatedAt: apiKey.UpdatedAt,
|
||||||
LastUsedAt: apiKey.LastUsedAt,
|
LastUsedAt: apiKey.LastUsedAt,
|
||||||
@@ -210,7 +203,6 @@ func (h *Handler) ListKeys() http.HandlerFunc {
|
|||||||
UserID: key.UserID,
|
UserID: key.UserID,
|
||||||
PermissionMode: key.PermissionMode,
|
PermissionMode: key.PermissionMode,
|
||||||
ExpiresAt: key.ExpiresAt,
|
ExpiresAt: key.ExpiresAt,
|
||||||
Enabled: key.Enabled,
|
|
||||||
CreatedAt: key.CreatedAt,
|
CreatedAt: key.CreatedAt,
|
||||||
UpdatedAt: key.UpdatedAt,
|
UpdatedAt: key.UpdatedAt,
|
||||||
LastUsedAt: key.LastUsedAt,
|
LastUsedAt: key.LastUsedAt,
|
||||||
@@ -260,7 +252,6 @@ func (h *Handler) GetKey() http.HandlerFunc {
|
|||||||
UserID: key.UserID,
|
UserID: key.UserID,
|
||||||
PermissionMode: key.PermissionMode,
|
PermissionMode: key.PermissionMode,
|
||||||
ExpiresAt: key.ExpiresAt,
|
ExpiresAt: key.ExpiresAt,
|
||||||
Enabled: key.Enabled,
|
|
||||||
CreatedAt: key.CreatedAt,
|
CreatedAt: key.CreatedAt,
|
||||||
UpdatedAt: key.UpdatedAt,
|
UpdatedAt: key.UpdatedAt,
|
||||||
LastUsedAt: key.LastUsedAt,
|
LastUsedAt: key.LastUsedAt,
|
||||||
@@ -359,7 +350,6 @@ func (h *Handler) GetKeyPermissions() http.HandlerFunc {
|
|||||||
response = append(response, KeyPermissionResponse{
|
response = append(response, KeyPermissionResponse{
|
||||||
InstanceID: perm.InstanceID,
|
InstanceID: perm.InstanceID,
|
||||||
InstanceName: instanceNameMap[perm.InstanceID],
|
InstanceName: instanceNameMap[perm.InstanceID],
|
||||||
CanInfer: perm.CanInfer,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,11 +249,7 @@ function ApiKeysSection() {
|
|||||||
<tr key={perm.instance_id} className="border-b">
|
<tr key={perm.instance_id} className="border-b">
|
||||||
<td className="py-2">{perm.instance_name}</td>
|
<td className="py-2">{perm.instance_name}</td>
|
||||||
<td className="py-2">
|
<td className="py-2">
|
||||||
{perm.can_infer ? (
|
<Check className="h-4 w-4 text-green-600" />
|
||||||
<Check className="h-4 w-4 text-green-600" />
|
|
||||||
) : (
|
|
||||||
<X className="h-4 w-4 text-red-600" />
|
|
||||||
)}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export interface ApiKey {
|
|||||||
user_id: string
|
user_id: string
|
||||||
permission_mode: PermissionMode
|
permission_mode: PermissionMode
|
||||||
expires_at: number | null
|
expires_at: number | null
|
||||||
enabled: boolean
|
|
||||||
created_at: number
|
created_at: number
|
||||||
updated_at: number
|
updated_at: number
|
||||||
last_used_at: number | null
|
last_used_at: number | null
|
||||||
@@ -24,7 +23,6 @@ export interface CreateKeyRequest {
|
|||||||
|
|
||||||
export interface InstancePermission {
|
export interface InstancePermission {
|
||||||
InstanceID: number
|
InstanceID: number
|
||||||
CanInfer: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateKeyResponse extends ApiKey {
|
export interface CreateKeyResponse extends ApiKey {
|
||||||
@@ -34,5 +32,4 @@ export interface CreateKeyResponse extends ApiKey {
|
|||||||
export interface KeyPermissionResponse {
|
export interface KeyPermissionResponse {
|
||||||
instance_id: number
|
instance_id: number
|
||||||
instance_name: string
|
instance_name: string
|
||||||
can_infer: boolean
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user