package db import ( "context" "database/sql" "errors" ) type SSHKey struct { ID int64 UserID int64 Name string PublicKey string Fingerprint string CreatedAt string } func (d *DB) ListSSHKeys(ctx context.Context, userID int64) ([]SSHKey, error) { rows, err := d.QueryContext(ctx, `SELECT id, user_id, name, public_key, fingerprint, created_at FROM ssh_keys WHERE user_id = ?`, userID) if err != nil { return nil, err } defer rows.Close() var out []SSHKey for rows.Next() { var k SSHKey if err := rows.Scan(&k.ID, &k.UserID, &k.Name, &k.PublicKey, &k.Fingerprint, &k.CreatedAt); err != nil { return nil, err } out = append(out, k) } return out, rows.Err() } func (d *DB) CreateSSHKey(ctx context.Context, userID int64, name, publicKey, fingerprint, createdAt string) error { _, err := d.ExecContext(ctx, `INSERT INTO ssh_keys (user_id, name, public_key, fingerprint, created_at) VALUES (?, ?, ?, ?, ?)`, userID, name, publicKey, fingerprint, createdAt) return err } // SSHKeyOwner returns the id and user of one key, used to check ownership // before a delete. func (d *DB) SSHKeyOwner(ctx context.Context, id int64) (int64, bool, error) { var userID int64 err := d.QueryRowContext(ctx, `SELECT user_id FROM ssh_keys WHERE id = ?`, id).Scan(&userID) if errors.Is(err, sql.ErrNoRows) { return 0, false, nil } if err != nil { return 0, false, err } return userID, true, nil } func (d *DB) DeleteSSHKey(ctx context.Context, id int64) error { _, err := d.ExecContext(ctx, `DELETE FROM ssh_keys WHERE id = ?`, id) return err } // SSHKeyUser is the identity behind an SSH public key offered at login. type SSHKeyUser struct { UserID int64 Username string PublicKey string } // SSHKeyByFingerprint resolves an SSH key to its (non-pending) owner. func (d *DB) SSHKeyByFingerprint(ctx context.Context, fingerprint string) (*SSHKeyUser, error) { var k SSHKeyUser err := d.QueryRowContext(ctx, `SELECT users.id, users.username, ssh_keys.public_key FROM ssh_keys JOIN users ON users.id = ssh_keys.user_id WHERE ssh_keys.fingerprint = ? AND users.is_pending = 0`, fingerprint).Scan(&k.UserID, &k.Username, &k.PublicKey) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, err } return &k, nil }