Goit

Simple and lightweight Git web server
git clone https://git.omkov.net/Goit
git clone [email protected]:Goit
Log | Tree | Refs | README | Download

Goit/src/user/keys.go (138 lines, 3.2 KiB) -rw-r--r-- blame download

0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
// Copyright (C) 2025, Jakob Wakeling
// All rights reserved.

package user

import (
	"fmt"
	"html/template"
	"net/http"
	"strconv"
	"strings"

	"github.com/Jamozed/Goit/src/goit"
	"github.com/Jamozed/Goit/src/util"
	"github.com/gorilla/csrf"
	"golang.org/x/crypto/ssh"
)

func HandleKeys(w http.ResponseWriter, r *http.Request) {
	auth, user, err := goit.Auth(w, r, true)
	if err != nil {
		util.PrintFuncError(err)
		goit.HttpError(w, http.StatusInternalServerError)
		return
	}

	if !auth {
		goit.HttpError(w, http.StatusUnauthorized)
		return
	}

	data := struct {
		Title     string
		Keys      []goit.Key
		KeyLines  []string
		CSRFField template.HTML
	}{
		Title:     "User - Keys",
		CSRFField: csrf.TemplateField(r),
	}

	if r.Method == http.MethodPost {
		fmt.Println(r.FormValue("submit"))
		if r.FormValue("submit") == "Delete" {
			kid, err := strconv.ParseInt(r.FormValue("kid"), 10, 64)
			if err != nil {
				util.PrintFuncError(err)
				goit.HttpError(w, http.StatusInternalServerError)
				return
			}

			if err := goit.DelKey(kid); err != nil {
				util.PrintFuncError(err)
				goit.HttpError(w, http.StatusInternalServerError)
				return
			}

			/* Redirect to user keys page on success. */
			http.Redirect(w, r, "/user/keys", http.StatusFound)
			return
		}
	}

	if keys, err := goit.GetKeys(user.Id); err != nil {
		util.PrintFuncError(err)
		goit.HttpError(w, http.StatusInternalServerError)
		return
	} else {
		data.Keys = keys
	}

	for _, key := range data.Keys {
		k, err := ssh.ParsePublicKey(key.Key)
		if err != nil {
			util.PrintFuncError(err)
			goit.HttpError(w, http.StatusInternalServerError)
			return
		}
		data.KeyLines = append(data.KeyLines, strings.TrimSuffix(string(ssh.MarshalAuthorizedKey(k)), "\n"))
	}

	if err := goit.Tmpl.ExecuteTemplate(w, "user/keys", data); err != nil {
		util.PrintFuncError(err)
	}
}

func HandleKeysAdd(w http.ResponseWriter, r *http.Request) {
	auth, user, err := goit.Auth(w, r, true)
	if err != nil {
		util.PrintFuncError(err)
		goit.HttpError(w, http.StatusInternalServerError)
		return
	}

	if !auth {
		goit.HttpError(w, http.StatusUnauthorized)
		return
	}

	data := struct {
		Title, Message string

		Form      struct{ Key string }
		CSRFField template.HTML
	}{
		Title:     "User - Add Key",
		CSRFField: csrf.TemplateField(r),
	}

	if r.Method == http.MethodPost {
		data.Form.Key = r.FormValue("key")

		if data.Form.Key == "" {
			data.Message = "Key cannot be empty"
		} else if key, comment, options, _, err := ssh.ParseAuthorizedKey([]byte(data.Form.Key)); err != nil {
			data.Message = "Invalid SSH public key"
		} else if len(options) != 0 {
			data.Message = "Key options are not permitted"
		} else if comment == "" {
			data.Message = "Key comment is required"
		} else if err := goit.AddKey(goit.Key{
			OwnerID: user.Id, Description: comment, Key: key.Marshal(), Type: goit.SSH_Auth,
		}); err != nil {
			util.PrintFuncError(err)
			goit.HttpError(w, http.StatusInternalServerError)
			return
		} else {
			/* Redirect to user keys page on success. */
			http.Redirect(w, r, "/user/keys", http.StatusFound)
			return
		}
	}

	if err := goit.Tmpl.ExecuteTemplate(w, "user/keys/add", data); err != nil {
		util.PrintFuncError(err)
	}
}