diff --git a/route/v1/storage.go b/route/v1/storage.go index bdc3294..5946207 100644 --- a/route/v1/storage.go +++ b/route/v1/storage.go @@ -98,14 +98,19 @@ func GetStorageList(ctx echo.Context) error { } func PostAddStorage(ctx echo.Context) error { - js := make(map[string]interface{}) - if err := ctx.Bind(&js); err != nil { + // Typed rather than a map: a field of the wrong type is Bind's 400, where the + // map's type assertions panicked, and a missing one is its zero value -- an + // empty path is refused below, before any disk is touched. + var request struct { + Path string `json:"path"` + Name string `json:"name"` + Format bool `json:"format"` + } + if err := ctx.Bind(&request); err != nil { return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()}) } - path := js["path"].(string) - name := js["name"].(string) - format := js["format"].(bool) + path, name, format := request.Path, request.Name, request.Format if len(path) == 0 { return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) diff --git a/route/v1/storage_test.go b/route/v1/storage_test.go index c0d878e..eb1aa27 100644 --- a/route/v1/storage_test.go +++ b/route/v1/storage_test.go @@ -5,6 +5,7 @@ import ( "errors" "net/http" "net/http/httptest" + "strings" "testing" model1 "github.com/ReCasaOS/CasaOS-LocalStorage/model" @@ -181,3 +182,26 @@ func TestGetDiskListNeverOffersAnArrayMemberForFormatting(t *testing.T) { } } } + +// The body of the call that formats a disk used to be read with type assertions, +// so a field of the wrong type, or a missing path, panicked in the handler. Each +// is a bad request now, answered before anything reaches a disk -- the services +// are not even set up here, so a call that went further would fail the test. +func TestAMalformedAddStorageRequestIsABadRequest(t *testing.T) { + for _, body := range []string{ + `{"path": "/dev/sdb", "name": "data", "format": "yes"}`, + `{"path": 42, "name": "data", "format": false}`, + `{"name": "data"}`, + } { + request := httptest.NewRequest(http.MethodPost, "/v1/storage", strings.NewReader(body)) + request.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + + if err := PostAddStorage(echo.New().NewContext(request, rec)); err != nil { + t.Fatalf("%s: %v", body, err) + } + if rec.Code != http.StatusBadRequest { + t.Errorf("%s: status %d, want 400: %s", body, rec.Code, rec.Body.String()) + } + } +}