Laravel 5.6 Signed URL not valid after user submit form - laravel

In my system, using Laravel 5.6, we send a email with a invitation link (using signed URL) where the user click, fill a form and submit it to the server. In this point the user is saved.
The signed URL already contains data like email and perfil_id (like role_id) that will be assigned when the user submits the form.
At which point should I use the $request->hasValidSignature() method?
Because if I wait for the user to fill the form and submit, the method called here will give false to hasValidSignature(). If I validate when passing the view for the user to see the form, the validation will pass but before sending the form the user will be able to tamper with data.
Signed URL inside controller
$url = URL::temporarySignedRoute('completar', now()->addHours(5), [
'email' => $request->get('email'),
'perfil_id' => $request->get('perfil_id'),
'empresa_id' => auth()->user()->empresa_id,
]);
Mail::to($request->get('email'))->send(new UserRegistrationInvite($url));
Form inside the view that user has to fill after using the link on email
<form action="{{route("aceitar")}}" method="post">
<input type="hidden" name="email" value="{{$request['email']}}">
<input type="hidden" name="perfil_id" value="{{$request['perfil_id']}}">
<input type="hidden" name="empresa_id" value="{{$request['empresa_id']}}">
<input type="hidden" name="signature" value="{{$request['signature']}}">
<br>
<label for="name">Digite seu nome: </label>
<input type="text" id="Nome" name="name" placeholder="Nome">
<br>
<label for="password">Digite sua senha: </label>
<input type="password" name="password" id="password">
<br>
<label for="password_confirmation">confirme sua senha: </label>
<input type="password" name="password_confirmation" id="password_confirmation">
<hr>
<button type="submit" id="convite">Enviar</button>
</form>
function called when user submits form. here validation will fail
public function aceitar(Request $request) {
// verifica se a signed URL é válida
if (!$request->hasValidSignature()) {
abort(response()->json('URL não válida - aceitar', 403));
}
// ao submeter o formulario anterior, faz validação
$validator = Validator::make($request->all(), [
'name' => 'required',
'perfil_id' => 'required',
'empresa_id' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed'
]);
// se validação falhar exibe erros na tela
if ($validator->fails()) {
return $validator->errors();
} else {
// se passar na validação usuário é criado com perfil e permissões ja relacionadas
$usuario = User::create([
'email' => $request->email,
'name' => $request->name,
'password' => bcrypt($request->password),
'empresa_id' => $request->empresa_id,
]);
$usuario->perfil()->attach($request->perfil_id);
return 'Usuário criado com sucesso';
}
thanks for your time.

The signature is only valid on the first URL that the user visits: 'completar'.
When they post the form, the same signature is no longer valid on the 'aceitar' route.
You can verify the signature before even showing them the form and consider it trusted.
You can also generate another temporary signed URL for the post route in the form if you want to add another validation step.

Related

Undefined array key "password" in LoginController (Laravel 8)

I am trying to customize my login but it throws me the error that appears in the title.
This is the function in the LoginController:
public function login(Request $request) {
$request->validate([
'username' => 'required|string|email',
'password' => 'required|string',
'remember' => 'boolean',
]);
#:: Undefined array key "password"
if ($this->guard()->attempt(['a_username' => $request->username, 'a_password' => $request->password], $request->has('remember'))) {
return $this->sendLoginResponse($request);
}
return $this->sendFailedLoginResponse($request);
}
The question why I use these custom columns and not the ones that come with laravel by default. Is that I have 2 tables that are used to authenticate.
In my database I have the columns: a_username (it is the email)
a_password (is the password)
This is the login form:
<form class="js-validation-signin" action="{{ route('login') }}" method="POST">
#csrf
<div class="form-group">
<input type="email" class="form-control form-control-lg form-control-alt py-4" name="username" placeholder="Username" value="{{ old('username') }}">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-lg form-control-alt py-4" name="password" placeholder="Password">
</div>
</form>
Thank you for your patience as I have to translate this problem from Spanish to English. :)
Eloquent user provider contain this code
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
So to override default functionality you need:
In your user model add (override) method getAuthPassword
public function getAuthPassword()
{
return $this->a_password;
}
Update your code (change a_password to password):
if ($this->guard()->attempt(['a_username' => $request->username, 'password' => $request->password], $request->has('remember'))) {
return $this->sendLoginResponse($request);
}

How to store saved checkbox value in Laravel?

I'm studying Laravel and made contact form.
my Laravel Framework is 7.15.0
I wrote this code to saving form values useing old function.
<input class="form-check-input" type="radio" name="q1[]"
value="A" #if(is_array(old('q1')) && in_array("A", old('q1'))) checked #endif>
<label class="form-check-label" >A</label>
<input class="form-check-input" type="radio" name="q1[]"
value="B" #if(is_array(old('q1')) && in_array("B", old('q1'))) checked #endif>
<label class="form-check-label" >B</label>
However after I wrote this I couldn't store data to my mysql.
Here is error message.
ErrorException
Array to string conversion
vendor/laravel/framework/src/Illuminate/Support/Str.php:449
Seems like saving array data to my mysql is problem I guess.
Here is my controller code.
Could someone teach me how to write store data as not array please?
public function ContactUsForm(Request $request) {
// Form validation
$this->validate($request, [
'name' => 'required',
]);
Contact::create($request->all());
\Mail::send('mail', array(
'name' => $request->get('name'),
'q1_s' => $request->get('q1')
), function($message) use ($request){
$message->from($request->email);
$message->to('mail#myemailadress.com', 'you got mail ')->subject($request->get('you got mail'));
});

how to validated to enter numbers only and show alert message when special charter entered

I want to validate input filed which allow entering numbers only and if numeric, alphabet or copy paste not allowed and show the alert message.
<input id="amount" name="amount" type="text" placeholder="Amount" class="form-control"></div>
This my input field.
I search on google but not getting a proper answer.
From the client side you might want to create an input that already validates, to prevent unnecissary requests
<input type="text" name="amount" pattern="[0-9]*" title="Numbers only">
or
<input type="number" name="amount" title="Numbers only">
Next you want to validate the same on the server, to protect your request.
public function store(Request $request)
{
$validatedData = $request->validate([
'amount' => 'required|nummeric',
]);
// do something with amount
}
Do a server side validation as below
In your model
public static function rules()
{
return [
'amount' => ['required','numeric'],
];
}
In your controller write below code
$validator = Validator::make($request->all(), Your ModelName::rules());
if ($validator->fails()){
//display error msg
}

Get Model and id of the Model you are adding a note to

Basically,
I have a notes table with a polymorphic relationship with videos and users and want to determine how on my store method in my NotesController I get which model I am added a note to, and the id in that table. This is my create query on my store method
$note = Note::query()->create([
'body' => $request->get('body'),
'user_id' => \Auth::id(),
'noteable_id' => 1, **(needs to be dynamic)**
'noteable_type' => Video::class, **(needs to be dynamic)**
]);
Blade
<form action="{{route('admin.note.store'}}" method="post">
{{csrf_field()}}
<div class="input-group">
<input id="btn-input" name="body" required="true" type="text" class="form-control input-sm" placeholder="Type your message here...">
<span class="input-group-btn">
<button type="submit" class="btn btn-warning btn-sm" id="btn-chat">
Submit
</button>
</span>
</div>
</form>
Essentially I want to know how I can retrieve the noteable_type = (Model I'm updating) and the noteable_id (id of the record I'm adding a note to)
Is there any way of retrieving this dynamically on the request?
Thanks
You need to get the video or any other model some way. If your route contains the video id then you can use that in your controller. Here are some ways you can do this.
//Get your video model
$video = Video::find(...);
$note = \Auth::user()->create([
'body' => $request->get('body'),
'noteable_id' => $video->id,
'noteable_type' => get_class($video),
]);
// OR
$note = new Note([
'body' => $request->get('body'),
'user_id' => \Auth::id(),
]);
$video->note()->save($note);
Run php artisan route:list and post it so that i can advise you on how to fetch the model.

How to use a translation of the label to display an error, instead of the label's name, when registering a user?

When registering a new user, I use a RegisterFormRequest from Laravel.
How can I use the label name translations to display correctly the error message ?
Here is my html code,
<div>
<label for="password">
{{ Lang::get('form.password') }} *
</label>
<input name="password" type="password" required>
</div>
<div>
<label for="password_confirmation">
{{ Lang::get('form.password.confirm') }} *
</label>
<input name="password_confirmation" type="password" class="form-control" required>
</div>
Here is what is displayed. Note that the input field's "password" is used as is, but not any translations.
in the Http\Controllers\YourController.php
public function postRegister(RegisterFormRequest $request)
{
$validator = $this->registrar->validator($request->all());
$validator = $validator->setAttributeNames( [
'password' => 'My Password Name'
] );
will do the trick.
As #ali as implied, it might be better to put these values into your request class (it is where you can put the specific rules, so why not the specific label translation?).
in the Http\Controllers\YourController.php
public function postRegister(RegisterFormRequest $request)
{
$validator = $this->registrar->validator($request->all());
$validator = $validator->setAttributeNames( $request->messages() );
in the Http\Requests\RegisterFormRequest.php
public function messages()
{
return [
'password' => Lang::get('form.password'),
Laravel validation attributes "nice names"
And (as #mohamed-kawsara mentionned) in
resources/lang/de/validation.php
return [
...
"confirmed" => "The :attribute confirmation does not match.",
...
What you need is custom message in you request class.
Write this function in your request class.
public function messages()
{
return [
'password.required' => 'YOUR CUSTOM MESSAGE FOR PASSWORD REQUIREMENT'
];
}

Resources