pico

created pr with 90.1 on 2025-12-14T01:53:24Z · by c8ef7d19
cmds
checkout latest patchset:
ssh pr.pico.sh print 90 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print 90.[rev] | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 90
+22 -5 pkg/apps/auth/api.go #
......@@ -23,6 +23,7 @@ import (
2323 "github.com/picosh/utils/pipe"
2424 "github.com/picosh/utils/pipe/metrics"
2525 "github.com/prometheus/client_golang/prometheus/promhttp"
26+ "golang.org/x/crypto/ssh"
2627 )
2728
2829 //go:embed html/* public/*
......@@ -245,22 +246,38 @@ func keyHandler(apiConfig *shared.ApiConfig) http.HandlerFunc {
245246
246247 space := r.URL.Query().Get("space")
247248
248- apiConfig.Cfg.Logger.Info(
249- "handle key",
249+ log := apiConfig.Cfg.Logger.With(
250250 "remoteAddress", data.RemoteAddress,
251251 "user", data.Username,
252252 "space", space,
253253 "publicKey", data.PublicKey,
254254 )
255255
256- user, err := apiConfig.Dbpool.FindUserForKey(data.Username, data.PublicKey)
256+ log.Info("handle key")
257+
258+ key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(data.PublicKey))
257259 if err != nil {
258- apiConfig.Cfg.Logger.Error(err.Error())
260+ log.Error("parse authorized key", "err", err)
261+ http.Error(w, err.Error(), http.StatusBadRequest)
262+ return
263+ }
264+
265+ pubkey, err := shared.PubkeyCertVerify(key, space)
266+ if err != nil {
267+ log.Error("pubkey cert verify", "err", err)
268+ http.Error(w, err.Error(), http.StatusBadRequest)
269+ return
270+ }
271+
272+ user, err := apiConfig.Dbpool.FindUserForKey(data.Username, pubkey)
273+ if err != nil {
274+ log.Error("find user for key", "err", err)
259275 w.WriteHeader(http.StatusUnauthorized)
260276 return
261277 }
262278
263279 if !apiConfig.HasPlusOrSpace(user, space) {
280+ log.Error("key handler unauthorized")
264281 w.WriteHeader(http.StatusUnauthorized)
265282 return
266283 }
......@@ -274,7 +291,7 @@ func keyHandler(apiConfig *shared.ApiConfig) http.HandlerFunc {
274291 w.WriteHeader(http.StatusOK)
275292 err = json.NewEncoder(w).Encode(user)
276293 if err != nil {
277- apiConfig.Cfg.Logger.Error(err.Error())
294+ log.Error("json encode", "err", err)
278295 http.Error(w, err.Error(), http.StatusInternalServerError)
279296 }
280297 }
+1 -1 pkg/apps/auth/api_test.go #
......@@ -97,7 +97,7 @@ func TestKey(t *testing.T) {
9797
9898 data := sishData{
9999 Username: testUsername,
100- PublicKey: "zzz",
100+ PublicKey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxVPgEqtWOa5l0QHZV6TQKhV+l46SAXU07c9RuHlGka test@pico",
101101 }
102102 jso, err := json.Marshal(data)
103103 bail(err)
+19 -14 pkg/shared/ssh.go #
......@@ -33,41 +33,46 @@ func NewSshAuthHandler(dbh AuthFindUser, logger *slog.Logger, principal string)
3333 }
3434 }
3535
36-func (r *SshAuthHandler) PubkeyAuthHandler(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
37- log := r.Logger
38- var user *db.User
39- var err error
40- pubkey := ""
41-
36+func PubkeyCertVerify(key ssh.PublicKey, srcPrincipal string) (string, error) {
4237 cert, ok := key.(*ssh.Certificate)
4338 if ok {
4439 if cert.CertType != ssh.UserCert {
45- return nil, fmt.Errorf("ssh-cert has type %d", cert.CertType)
40+ return "", fmt.Errorf("ssh-cert has type %d", cert.CertType)
4641 }
4742
4843 found := false
4944 for _, princ := range cert.ValidPrincipals {
50- if princ == "admin" || princ == r.Principal {
45+ if princ == "admin" || princ == srcPrincipal {
5146 found = true
5247 break
5348 }
5449 }
5550 if !found {
56- return nil, fmt.Errorf("ssh-cert principals not valid")
51+ return "", fmt.Errorf("ssh-cert principals not valid")
5752 }
5853
5954 clock := time.Now
6055 unixNow := clock().Unix()
6156 if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
62- return nil, fmt.Errorf("ssh-cert is not yet valid")
57+ return "", fmt.Errorf("ssh-cert is not yet valid")
6358 }
6459 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(ssh.CertTimeInfinity) && (unixNow >= before || before < 0) {
65- return nil, fmt.Errorf("ssh-cert has expired")
60+ return "", fmt.Errorf("ssh-cert has expired")
6661 }
6762
68- pubkey = utils.KeyForKeyText(cert.SignatureKey)
69- } else {
70- pubkey = utils.KeyForKeyText(key)
63+ return utils.KeyForKeyText(cert.SignatureKey), nil
64+ }
65+
66+ return utils.KeyForKeyText(key), nil
67+}
68+
69+func (r *SshAuthHandler) PubkeyAuthHandler(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
70+ log := r.Logger
71+ var user *db.User
72+ var err error
73+ pubkey, err := PubkeyCertVerify(key, r.Principal)
74+ if err != nil {
75+ return nil, err
7176 }
7277
7378 user, err = r.DB.FindUserByPubkey(pubkey)
Back to top