fix(09): WR-03 refuse writes that the compiled list and form do not declare
This commit is contained in:
@@ -606,6 +606,9 @@ func (s *service) show(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *service) create(w http.ResponseWriter, r *http.Request) {
|
||||
s.protect(w, r, func(cc *CompiledController) {
|
||||
if !s.operationDeclared(w, r, cc, "create") {
|
||||
return
|
||||
}
|
||||
body, err := decodeObject(r)
|
||||
if err != nil {
|
||||
writeCRUDError(w, err)
|
||||
@@ -627,6 +630,9 @@ func (s *service) create(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *service) update(w http.ResponseWriter, r *http.Request) {
|
||||
s.protect(w, r, func(cc *CompiledController) {
|
||||
if !s.operationDeclared(w, r, cc, "update") {
|
||||
return
|
||||
}
|
||||
id, err := pathID(r)
|
||||
if err != nil {
|
||||
writeCRUDError(w, err)
|
||||
@@ -653,6 +659,9 @@ func (s *service) update(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *service) bulkDelete(w http.ResponseWriter, r *http.Request) {
|
||||
s.protect(w, r, func(cc *CompiledController) {
|
||||
if !s.operationDeclared(w, r, cc, "bulk-delete") {
|
||||
return
|
||||
}
|
||||
in, err := decodeBulk(r)
|
||||
if err != nil {
|
||||
writeCRUDError(w, err)
|
||||
@@ -684,6 +693,9 @@ func decodeBulk(r *http.Request) (BulkDeleteInput, error) {
|
||||
|
||||
func (s *service) deleteRecord(w http.ResponseWriter, r *http.Request) {
|
||||
s.protect(w, r, func(cc *CompiledController) {
|
||||
if !s.operationDeclared(w, r, cc, "delete") {
|
||||
return
|
||||
}
|
||||
id, err := pathID(r)
|
||||
if err != nil {
|
||||
writeCRUDError(w, err)
|
||||
@@ -759,6 +771,23 @@ func (s *service) protect(w http.ResponseWriter, r *http.Request, fn func(*Compi
|
||||
fn(cc)
|
||||
}
|
||||
|
||||
// operationDeclared refuses a write the controller's YAML does not declare, so
|
||||
// the compiled list and form are the capability, not a hint for the SPA. Create
|
||||
// needs a form and a toolbar `create` button; update and single-record delete
|
||||
// (the form screen's delete button, as in Winter) need a form; bulk delete needs
|
||||
// the toolbar `delete` button, which in turn needs showCheckboxes. The answer is
|
||||
// 403 with the same envelope as a permission failure.
|
||||
func (s *service) operationDeclared(w http.ResponseWriter, r *http.Request, cc *CompiledController, op string) bool {
|
||||
if cc.operationDeclared(op) {
|
||||
return true
|
||||
}
|
||||
if principal, _ := bouncer.User(r.Context()); principal != nil {
|
||||
s.logAuth(r, "denied", principal.ID)
|
||||
}
|
||||
WriteError(w, http.StatusForbidden, "forbidden", msgForbidden)
|
||||
return false
|
||||
}
|
||||
|
||||
func projectRow(row any, controller pact.AdminController, cols []ListColumn) map[string]any {
|
||||
v := reflect.ValueOf(row)
|
||||
for v.Kind() == reflect.Pointer {
|
||||
|
||||
Reference in New Issue
Block a user