Does without using #csrf on livewire component makes my form vulnerable? - laravel-livewire

Since I can use wire:click to submit a livewire component properties, why bother to use <form>?
Using the document ContactForm as a example.
class ContactForm extends Component
{
public $name;
public $email;
protected $rules = [
'name' => 'required|min:6',
'email' => 'required|email',
];
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function saveContact()
{
$validatedData = $this->validate();
Contact::create($validatedData);
}
}
In the beginning, when I wrote a livewire form component, it look like this:(using <form> and #csrf)
<form wire:submit.prevent="saveContact">
#csrf
<input type="text" wire:model="name">
#error('name') <span class="error">{{ $message }}</span> #enderror
<input type="text" wire:model="email">
#error('email') <span class="error">{{ $message }}</span> #enderror
<button type="submit">Save Contact</button>
</form>
But now, I write a form like this:(without <form> and without #csrf)
<div>
<input type="text" wire:model="name">
#error('name') <span class="error">{{ $message }}</span> #enderror
<input type="text" wire:model="email">
#error('email') <span class="error">{{ $message }}</span> #enderror
<button type="button" wire:click="saveContact">Save Contact</button>
</div>
The document says that Livewire use a "checksum" to validate each request and response.
It also say that Livewire re-apply every authentication/authorization middleware.
All my member-restricted forms require users to login before fill and submit forms. So those forms are under protection of middleware('auth') and livewire request/response checksum.
But without using <form> and #csrf, especially without #csrf, does it still makes my form more vulnerable? Thank you!

The security documentation for Livewire outlines how it's internal security is handled. This describes the usage of the "checksum", which ensures that the data between each request is not tampered with.
However it does not mention CSRF explicitly. None the less, since each subsequent Livewire request is a POST request to the /livewire/message endpoint, it must be protected with a CSRF token.
If we check the source-code, you'll see that it does indeed pass in the CSRF token. And since Livewire uses normal Laravel routes, it will by default validate the token in the backend - ensuring all requests are protected.
This means that when using any Livewire action such as wire:click or wire:submit, you don't have to worry about CSRF, as its handled by the framework.

Related

Livewire form submit with multiple wire:model input name

How can I let livewire know that a model is a particular modal
I have this in my livewire component
public $itemname;
public function updateReceivedKg()
{
$this->validate([
'itemname' => 'required',
]);
dump($this->itemname)
}
On livewire view, I have this
#foreach($result->products as $index=>$data)
<form wire:submit.prevent="updateReceivedKg()">
<div class="input-group">
<input required wire:model.defer="itemname" type="text" class="form-control">
<span class="input-group-append">
<button type="submit" class="btn btn-sm btn-success">Update</button>
</span>
</div>
</form>
#endforeach
After generating the form, I have about 11 forms. The issue is that livewire always submit the last itemname that was entered. For example, if on the first form, I entered "Mango" and go to another form and enter "Apple", if I go back to the form which I have already written "Mango" and click the submit (without typing anything) button, if I dump the submitted form and check the itemname, it shows it is the Apple. This is wrong because I submitted the Mango form.
In normal Laravel, I have no issue with this type of form submission. It will detect which form I submitted.
Please how can I achieve the same result using Livewire
You have the same itemname for a lot of elements. You should probably append the index to the modelname.
public $itemname1;
public $itemname2; // etc..
#foreach($result->products as $index=>$data)
<form wire:submit.prevent="updateReceivedKg()">
<div class="input-group">
<input required wire:model.defer="itemname{{$index}}" type="text" class="form-control">
<span class="input-group-append">
<button type="submit" class="btn btn-sm btn-success">Update</button>
</span>
</div>
</form>
#endforeach

How can I get custom form field value from within Django Admin's response_change?

I've added a custom functionality to a model by overriding change_form.html. Basically, I'm letting users change the objects of a model if these changes were approved by the admin. I added two buttons, named accept-suggestion and decline-suggestion and I intend to handle the custom functionality through response_change method:
def response_change(self, request, obj):
if "decline-suggestion" in request.POST:
# do stuff...
if "accept-suggestion" in request.POST:
# do stuff...
Both buttons will send an e-mail to the user saying if the suggestion was declined or approaved. So far so good. The problem is that I want to add the possibility to the admin write a brief justification explaining why the suggestion was declined. So I changed change_form.html again.
<div class="submit-row">
<div class="float-left">
<a class="decline-button-outlined accordion" type="button" href="#">DECLINE SUGGESTION</a>
</div>
<div class="float-right">
<input class="accept-button" type="submit" name="accept-suggestion" value="ACEITAR SUGESTÃO">
</div>
</div>
<div class="additional-infos">
<fieldset class="module aligned">
<div class="form-row">
<label for="decline-reasons">Reasons for rejection:</label>
<textarea
placeholder="If you find necessary, provide information on the reasons that led to the rejection of the suggestion"
id="decline-reasons" class="vLargeTextField" rows="5"></textarea>
</div>
<div class="submit-row">
<div class="float-right">
<input class="decline-button" type="submit" name="decline-suggestion" value="DECLINE">
</div>
</div>
</fieldset>
</div>
Is this the best approach? If so, how can I get the value of the <textarea> above from within response_change? If not, what would you suggest?
Thank you very much!
If you add a name to your <textarea> you will be able to retrieve the contents on the server side. Without a name, the data is not being sent to the server (Django).
So something like this:
<textarea
placeholder="If you find necessary, provide information on the reasons that led to the rejection of the suggestion"
id="decline-reasons" name="decline-reasons" class="vLargeTextField" rows="5"></textarea>
Should allow you to retrieve the text on the Django side with request.POST["decline-reasons"].

How to use django-markdownx in my view in similar way to admin?

I'm stuck using django-markdownx to automatically update page and to submit changes.
I followed this question and answer and managed to get django-markdownx working in admin, and within my view. However in my view editing the textarea does not automatically update the page.
The admin page with django-markdownx is exactly what I want, updating the textarea updates the page, but not the underlying database field until you hit save.
So I then tried to rip out the admin code into my own view.
In my view/template I have a form, textarea similar to admin one. I also included "/static/markdownx/js/markdownx.js" and set my form to mostly be similar to the admin page:
<form method="POST" action="">{% csrf_token %}
<div class="markdownx">
<textarea name="myfield" rows="10" cols="40" required="" data-markdownx-upload-urls-path="/markdownx/upload/" data-markdownx-editor-resizable="" class="markdownx-editor" id="id_myfield" data-markdownx-urls-path="/markdownx/markdownify/" data-markdownx-latency="500" data-markdownx-init="" style="transition: opacity 1s ease;">
{{ note.myfield }}
</textarea>
</div>
<div class="markdownx-preview">
{{ note.formatted_markdown|safe }}
</div>
</form>
This didn't work.
I see periodically there is requests to /markdownx/markdownify/ when you edit in admin, but not mine. I'm not sure if I should aim to do the same or just do some timed javascript page refresh and pass all the data from within my form back to my view to then re-render the page again.
I can't quite get my head around the django-markdownx documentation.
UPDATE:
The Documentation seems to suggest that a call to MarkdownX() should do the initialisation.
<script src="/static/markdownx/js/markdownx.js"></script>
...
<script type="text/javascript">
let parent = document.getElementsByClassName('markdownx');
let md = new MarkdownX( element, element.querySelector('.markdownx-editor'), element.querySelector('.markdownx-preview'));
</script>
But when I try this I get.
Uncaught ReferenceError: MarkdownX is not defined
Also I don't see any initialisation like this within the admin page.
Is there an example of using the django-markdownx in your own views similar to the usage within admin?
Thanks
LB
The following is a broken solution.
The correct method would be to use the MarkdownX's built-in Javascript, but I just can't get it to work, yet. So, I wrote my own. It may be of use to others.
In template html, include js.cookie.min.js in order to get the django csrftoken. Then a callback function which will be called when a change is made to the textarea. We then update the preview div with HTML code we received back from MarkdownX's markdownify call.
<script src="https://cdn.jsdelivr.net/npm/js-cookie#2/src/js.cookie.min.js"></script>
...
<script type="text/javascript">
function myMDFunc( elem ) {
input = elem.value;
var csrftoken = Cookies.get('csrftoken');
$.ajax(
{
type: "POST",
url: "/markdownx/markdownify/",
data: { CSRF: csrftoken, csrfmiddlewaretoken: csrftoken, content: input}
})
.done(function(data, status){
document.getElementById("markdownx-preview").innerHTML = data;
});
}
</script>
Still in the template html, in the form, call this function both for onchange and onkeyup.
<form method="POST" action=""> {% csrf_token %}
{{ note.title }}
<div class="markdownx">
<textarea onchange="myMDFunc(this)" onkeyup="myMDFunc(this)" cols="60" rows="5" name="text" >
{{ note.myfield }}
</textarea>
</div>
<div class="markdownx-preview" id="markdownx-preview">
{{ note.formatted_markdown|safe }}
</div>
<input type="submit" id="submit" name="submit">
</form>
In summary, a change to the textarea means we invoke the 'onchange' or 'onkeyup', which calls myMDFunc. Then myMDFunc does an ajax call with data which is the raw MarkDown code, the response to this call is the pretty HTML data. The callback within myMDFunc updates the preview with that pretty HTML.
It kinda works. I'm sure the real MarkdownX code will handle drag'n'drop of images and pacing the ajax calls to be nice to the server.

Authentication with Ember.js 2.x

I'm new to ember.js and I find it pretty confusing to figure out which is a good way for authentication (version 2.x) since most of the examples on the web seem to be outdated. Also the documentation often doesn't come with easy to understand beginner examples.
Right now I'm following this tutorial. The initializer works apparently, I can also trigger the action login but then it gets stuck on the controller.get bit. The console spits out a TypeError: controller.get(...) is undefinedTypeError: controller.get(...) is undefined.
app/components/login-form
...
actions: {
login: function() {
var controller = this;
controller.get("session").login().then(function(admin) {
// Persist your users details.
}, function() {
// User rejected authentication request
});
}
}
...
app/templates/components/login-form
<form {{action 'login' on='submit'}}>
<div class="form-group">
<label for="email">Login</label>
{{input value=email placeholder='Enter Login' class='form-control'}}
</div>
<div class="form-group">
<label for="password">Password</label>
{{input value=password placeholder='Enter Password' class='form-control' type='password'}}
</div>
<button type="submit" class="btn btn-default">Login</button>
</form>
app/templates/admin.hbs
<div class="page-header">
<h1>Login</h1>
</div>
{{login-form}}
I hope somebody can point me into the right direction to get this working. I'd also appreciate any general advice where to find good examples or explanations concerning the ember 2.x way of authentication.
Edit: I need to have this working with Firebase.
http://ember-simple-auth.com/
looks like your best bet. They have a good video on setting it up too.
For connection to firebase you could create backend to authenticated with and have that check firebase. I'm using express and jwt in node.js to communicate with my mongoDB database.

Passing variables to handlebars partials in Ember.js

What I want to do should be fairly simple.
I want to pass variables to partials for reusability.
I want to do something like this :
<form {{action login content on="submit"}}>
<fieldset>
{{partial 'components/field-email' label="Email" fieldname="email" size="full"}}
[...]
</fieldset>
</form>
Instead of doing this :
<form {{action login content on="submit"}}>
<fieldset>
<div {{bind-attr class=":field :email size"}}>
<label {{bind-attr for=fieldname}}>{{label}}</label>
{{input type="email" id=fieldname name=fieldname valueBinding="email" placeholder=label}}
</div>
[...]
</fieldset>
</form>
coming from Rails, I expected this to just work, but it seems I can't (don't know how to) pass variables to a partial. I looked at all the ways to "include a template part":
partial
view
render
The thing that worked for me is using a View. But I thinks it's overkill. I just want separate sub-templates for reusability and readability, no context change or specifying a controller needed here.
Edit:
I also tried to use this partial as a component :
{{field-email type="email" id="email" name="email" valueBinding="email" placeholder=label size="full"}}
Which works for everything except the valueBinding.
I guess it's also worth mentioning that I have a route setup with an action that calls login on my AuthController :
App.LoginRoute = Ember.Route.extend
model: -> Ember.Object.create()
setupController: (controller, model) ->
controller.set 'content', model
controller.set "errorMsg", ""
actions:
login: ->
log.info "Logging in..."
#controllerFor("auth").login #
This whole thing works if all the markup is in the login template but fails if I try to break it up with partials, components and such.
There has to be something that I didn't see...
You should use a component in this case.
If you setup your template correctly (components/field-email), you can use on this way:
{{field-email label="Email" fieldname="email" size="full"}}
You could setup the html component properties, if you define the component. Based on your example, it could be:
App.FieldEmailComponent = Ember.Component.extend({
classNames: ['size'],
classNameBindings: ['email', 'field'],
field: null,
email: null
});
Example: http://emberjs.jsbin.com/hisug/1/edit
Got it working, I had to use a component. I had messed up the "value" part.
components/field-email.hbs :
<div {{bind-attr class=":field :email size"}}>
<label {{bind-attr for=fieldname}}>{{label}}</label>
{{input type="email" name=fieldname value=value placeholder=label}}
</div>
login.hbs :
<form {{action login content on="submit"}}>
<fieldset>
{{field-email label="Email" fieldname="email" value=email size="full"}}
[...]
</fieldset>
</form>
What I get from this is that in order for attributes to be used in a component they have to be explicitly set when using the component. Once they are set, they are bound.
In my case, when the input value changes, the associated route property is updated as well which is pretty cool.