luminus-framework/luminus

Can't make method spoofing on HTML forms

juniorgarcia opened this issue · 1 comments

I looked at the documentation and can't make method spoofing on my forms. I'm unable to use methods other than GET and POST. I don't believe that's an error in my routes because I can use other HTTP methods through cURL or similar.

Currently I have a button to delete a row which is a submit to the following form:

<form action="/todos/{{todo.id}}" class="ml-3" method="POST">
  {% csrf-field %}
  <input type="hidden" name="_method" value="delete">
  <input type="hidden" name="todo" value="{{todo.id}}">
  <input type="submit" value="Delete" class="btn btn-danger">
</form>

Look at the input named _method. Is this the right way to spoof methods in Luminus?

Here is my route function for this entity:

(defn todos-routes []
  [["/todos"
    {:middleware [middleware/wrap-csrf
                  middleware/wrap-formats]
     :get list}]
   ["/todos/:todo"
    {:middleware [middleware/wrap-csrf
                  middleware/wrap-formats]
     :get edit
     :delete delete}]])

I know that there isn't a :post key, but I assumed I didn't have to handle that unless I would like to use the POST method directly, which is not the case yet.

The delete method mapped to the :delete key on the routes is like the following:

(defn delete [todo]
  (delete-todo todo)
  (redirect "/todos"))

Anyway, everytime I submit a form, the only methods that work are GET and POST. But as I said before, using cURL directly setting the method to any other compliant to the HTTP specification works.

There's no built in support for method spoofing as it's not part of HTTP spec, but you could add a middleware function to spoof the HTTP method in the <app>.middleware namespace as follows:

(defn wrap-spoof-method [handler]
  (fn [request]
    (handler
     (update request :request-method
             #(or (some-> request :params :_method keyword) %)))))

(defn wrap-base [handler]
  (-> ((:middleware defaults) handler)
      wrap-spoof-method
      (wrap-defaults
        (-> site-defaults
            (assoc-in [:security :anti-forgery] false)
            (assoc-in  [:session :store] (ttl-memory-store (* 60 30)))))
      wrap-internal-error))