1
0
mirror of https://github.com/coalaura/up.git synced 2025-07-17 21:44:35 +00:00

msgpack and streaming

This commit is contained in:
Laura
2025-06-20 16:10:38 +02:00
parent 28fad96c76
commit 602e327d03
8 changed files with 143 additions and 98 deletions

View File

@ -3,15 +3,15 @@ package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"io"
"net/http"
"os"
"path/filepath"
"time"
"github.com/coalaura/up/internal"
"github.com/valyala/fasthttp"
"github.com/vmihailenco/msgpack/v5"
"golang.org/x/crypto/ssh"
)
@ -31,11 +31,11 @@ func IsSignatureFormatValid(format string) bool {
return SignatureFormats[format]
}
func HandleChallengeRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.PublicKey) {
func HandleChallengeRequest(w http.ResponseWriter, r *http.Request, authorized map[string]ssh.PublicKey) {
var request internal.AuthRequest
if err := json.Unmarshal(ctx.PostBody(), &request); err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
if err := msgpack.NewDecoder(r.Body).Decode(&request); err != nil {
w.WriteHeader(http.StatusBadRequest)
log.Warning("request: failed to decode request")
log.WarningE(err)
@ -45,7 +45,7 @@ func HandleChallengeRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.
public, err := DecodeAndAuthorizePublicKey(request.Public, authorized)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("request: failed to parse/authorize public key")
log.WarningE(err)
@ -55,7 +55,7 @@ func HandleChallengeRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.
challenge, raw, err := internal.FreshChallenge()
if err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
log.Warning("request: failed to generate challenge")
log.WarningE(err)
@ -71,15 +71,15 @@ func HandleChallengeRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.
log.Println("new auth request")
ctx.SetContentType("application/json")
json.NewEncoder(ctx).Encode(challenge)
w.Header().Set("Content-Type", "application/msgpack")
msgpack.NewEncoder(w).Encode(challenge)
}
func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.PublicKey) {
func HandleCompleteRequest(w http.ResponseWriter, r *http.Request, authorized map[string]ssh.PublicKey) {
var response internal.AuthResponse
if err := json.Unmarshal(ctx.PostBody(), &response); err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
if err := msgpack.NewDecoder(r.Body).Decode(&response); err != nil {
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: failed to decode response")
log.WarningE(err)
@ -89,7 +89,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
public, err := DecodeAndAuthorizePublicKey(response.Public, authorized)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: failed to parse/authorize public key")
log.WarningE(err)
@ -99,7 +99,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
entry, ok := challenges.LoadAndDelete(response.Token)
if !ok {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: invalid challenge token")
@ -109,7 +109,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
challenge := entry.(internal.ChallengeEntry)
if time.Now().After(challenge.Expires) {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: challenge expired")
@ -120,7 +120,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
publicB := challenge.PublicKey.Marshal()
if !bytes.Equal(publicA, publicB) {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: incorrect public key")
@ -128,7 +128,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
}
if !IsSignatureFormatValid(response.Format) {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: unsupported signature format")
@ -137,7 +137,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
signature, err := base64.StdEncoding.DecodeString(response.Signature)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: failed to decode signature")
log.WarningE(err)
@ -151,7 +151,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
}
if err = public.Verify(challenge.Challenge, sig); err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("complete: failed to verify signature")
log.WarningE(err)
@ -161,7 +161,7 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
token, err := RandomToken(64)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
log.Warning("complete: failed to create token")
log.WarningE(err)
@ -176,16 +176,16 @@ func HandleCompleteRequest(ctx *fasthttp.RequestCtx, authorized map[string]ssh.P
log.Println("auth completed")
ctx.SetContentType("application/json")
json.NewEncoder(ctx).Encode(internal.AuthResult{
w.Header().Set("Content-Type", "application/msgpack")
msgpack.NewEncoder(w).Encode(internal.AuthResult{
Token: token,
})
}
func HandleReceiveRequest(ctx *fasthttp.RequestCtx) {
token := string(ctx.Request.Header.Peek("Authorization"))
func HandleReceiveRequest(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("receive: missing token")
@ -194,7 +194,7 @@ func HandleReceiveRequest(ctx *fasthttp.RequestCtx) {
entry, ok := sessions.LoadAndDelete(token)
if !ok {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("receive: invalid token")
@ -204,45 +204,43 @@ func HandleReceiveRequest(ctx *fasthttp.RequestCtx) {
session := entry.(internal.SessionEntry)
if time.Now().After(session.Expires) {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("receive: session expired")
return
}
form, err := ctx.MultipartForm()
reader, err := r.MultipartReader()
if err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
log.Warning("receive: failed to parse multipart form")
log.Warning("receive: failed to open multipart form")
log.WarningE(err)
return
}
files := form.File["file"]
if len(files) == 0 {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
log.Warning("receive: no files received")
return
}
header := files[0]
name := filepath.Base(header.Filename)
source, err := header.Open()
part, err := reader.NextPart()
if err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
w.WriteHeader(http.StatusBadRequest)
log.Warning("receive: failed to open sent file")
log.Warning("receive: failed to read multipart form")
log.WarningE(err)
return
}
defer source.Close()
if part.FormName() != "file" {
w.WriteHeader(http.StatusBadRequest)
log.Warning("receive: invalid multipart part")
log.WarningE(err)
return
}
name := filepath.Base(part.FileName())
if _, err := os.Stat("files"); os.IsNotExist(err) {
os.Mkdir("files", 0755)
@ -250,7 +248,7 @@ func HandleReceiveRequest(ctx *fasthttp.RequestCtx) {
target, err := os.OpenFile(filepath.Join("files", name), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
log.Warning("receive: failed to open target file")
@ -259,15 +257,15 @@ func HandleReceiveRequest(ctx *fasthttp.RequestCtx) {
defer target.Close()
if _, err := io.Copy(target, source); err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
if _, err := io.Copy(target, part); err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Warning("receive: failed to copy sent file")
return
}
ctx.SetStatusCode(fasthttp.StatusOK)
w.WriteHeader(http.StatusOK)
}
func DecodeAndAuthorizePublicKey(public string, authorized map[string]ssh.PublicKey) (ssh.PublicKey, error) {