making progress
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/forgeo/forgebucket/internal/api/middleware"
|
||||
"github.com/forgeo/forgebucket/internal/models"
|
||||
)
|
||||
|
||||
type SSHKeyHandler struct {
|
||||
db *xorm.Engine
|
||||
}
|
||||
|
||||
func NewSSHKeyHandler(db *xorm.Engine) *SSHKeyHandler {
|
||||
return &SSHKeyHandler{db: db}
|
||||
}
|
||||
|
||||
func (h *SSHKeyHandler) List(w http.ResponseWriter, r *http.Request) {
|
||||
userID, _ := middleware.UserIDFromContext(r.Context())
|
||||
var keys []models.SSHKey
|
||||
if err := h.db.Where("user_id = ?", userID).Find(&keys); err != nil {
|
||||
jsonError(w, "could not list SSH keys", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if keys == nil {
|
||||
keys = []models.SSHKey{}
|
||||
}
|
||||
jsonOK(w, keys)
|
||||
}
|
||||
|
||||
func (h *SSHKeyHandler) Add(w http.ResponseWriter, r *http.Request) {
|
||||
userID, _ := middleware.UserIDFromContext(r.Context())
|
||||
|
||||
var body struct {
|
||||
Title string `json:"title"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
jsonError(w, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if body.Title == "" || body.PublicKey == "" {
|
||||
jsonError(w, "title and publicKey are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse and validate the public key
|
||||
pubKeyBytes := []byte(strings.TrimSpace(body.PublicKey))
|
||||
pub, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyBytes)
|
||||
if err != nil {
|
||||
jsonError(w, "invalid SSH public key format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Compute MD5 fingerprint (standard display format)
|
||||
fingerprint := fingerprintMD5(pub)
|
||||
|
||||
key := &models.SSHKey{
|
||||
UserID: userID,
|
||||
Title: body.Title,
|
||||
Fingerprint: fingerprint,
|
||||
PublicKey: strings.TrimSpace(body.PublicKey),
|
||||
}
|
||||
if _, err := h.db.Insert(key); err != nil {
|
||||
jsonError(w, "key already exists or could not be saved", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(key)
|
||||
}
|
||||
|
||||
func (h *SSHKeyHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
userID, _ := middleware.UserIDFromContext(r.Context())
|
||||
keyID, err := strconv.ParseInt(chi.URLParam(r, "keyID"), 10, 64)
|
||||
if err != nil {
|
||||
jsonError(w, "invalid key ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
n, err := h.db.Where("id = ? AND user_id = ?", keyID, userID).Delete(&models.SSHKey{})
|
||||
if err != nil || n == 0 {
|
||||
jsonError(w, "key not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func fingerprintMD5(pub ssh.PublicKey) string {
|
||||
hash := md5.Sum(pub.Marshal())
|
||||
parts := make([]string, len(hash))
|
||||
for i, b := range hash {
|
||||
parts[i] = fmt.Sprintf("%02x", b)
|
||||
}
|
||||
return strings.Join(parts, ":")
|
||||
}
|
||||
Reference in New Issue
Block a user