I'm currently working on an E-learning platform, where we sell courses to users that registers and make payments for that courses.
I have a HTML form and it's integrated with PayPal Checkout (sandbox) and actually the behavior I expect is that when the payment is accepted (onApprove function) the form is submited with the data I need to process on the server.
But, I was trying to imitate malicious behavior and I entered the command: document.forms[0].submit() and the form is submited without the paypal payment in between. So anybody can have the course for free.
I want to fix this issue, and I have no very much knowledge in web security. My questions:
How can I only submit the form when the Paypal payment is successful?
(Optional) Where can I learn more about this and other security issues?
payment.blade.php
<div class="container">
<form action="{{action("RegistersController#inscribir",["curso" => $curso->id])}}" method="POST">
<div class="row">
<div class="col-12 col-md-8">
<h1>Llena el formulario</h1>
#csrf
<div class="form-group">
<label for="Nombre">Ingresa tu nombre</label>
<input class="form-control" name="name" id="name" type="text" value="{{Auth::user()->name}}"/>
</div>
<div class="form-group">
<label for="email">Ingresa tu correo</label>
<input class="form-control" name="email" id="email" type="text" value="{{Auth::user()->email}}"/>
</div>
<div class="form-group">
<label for="phone">Ingresa tu número de teléfono</label>
<input class="form-control" name="phone" placeholder="+01 234 567 8910" id="phone" type="text" value=""/>
</div>
</div>
<div class="col-12 col-md-4">
<h4 class="my-3">Pagar Curso</h4>
<img src="/storage/img/cursos/{{$curso->image_square}}" alt="{{$curso->title}}" width="200px">
<h5 class="p-0 m-0">{{$curso->title}}</h5>
<small>{{substr($curso->description,0,150)}}</small>
<br>
<p>Precio: <b> <span id="price">{{number_format($curso->price,2,".","")}}</span> USD</b></p>
<br>
<input type="submit" class="btn btn-apple" style="display: none">
#if ($curso->price > 0)
<div id="paypal-button-container"></div>
#endif
</div>
</div>
</form>
</div>
<script src="https://www.paypal.com/sdk/js?client-id=<MY_CLIENT_ID>"> // Replace YOUR_SB_CLIENT_ID with your sandbox client ID
</script>
<script>
var price = document.getElementById("price").innerText;
var paypal_button = document.getElementById("paypal-button-container");
paypal.Buttons({
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: {{$curso->price}}
}
}]
});
},
style: {
color: 'blue',
size: 'responsive'
},
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
// Submit the form
console.log(details);
document.forms[0].submit();
});
},
onError: function(err){
alert("Error completando la transacción");
console.error(err);
window.location.href = "/";
}
}).render('#paypal-button-container');
</script>
Marking something as paid and receiving associated form information are two separate things. One part will always need to be completed before the next can proceed. If you require the PayPal payment to be completed before the form is submitted, this will lead to issues if the process is interrupted after payment, which you must design for. Vice-versa also leads to a potential disconnect (receiving form information without a payment), which must be designed for.
The issue in your question is how to verify that a PayPal payment has taken place. This must be done on your server. The most robust way to do it is to capture the payment from your server using a server-side integration.
You'll need two server-side routes, one for 'Create an Order' and one for 'Capture Order', documented here.
The best approval front-end to pair your two routes with is: https://developer.paypal.com/demo/checkout/#/pattern/server
Related
I am using bootstrap-datepicker with vue js. The problem is, when I select date it comes to the input field but whenever I shift to another input field, the date vanishes. how do I make the date stay even if I switch to another field. below is my code
$('.datepicker').datepicker();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js" integrity="sha256-bqVeqGdJ7h/lYPq6xrPv/YGzMEb6dNxlfiTUHSgRCp8=" crossorigin="anonymous"></script>
<div class="input-group">
<div class="input-group-prepend">
<span v-bind:style="{ width: prependWidth + 'px' }" class="input-group-text">Acceptance Date</span>
</div>
<input data-provide="datepicker" v-model="formData.acceptance_date" id="acceptance_date" name="acceptance_date" type="text" placeholder="" class="form-control">
</div>
here is my vue data
formData: {
event_name: '',
ba_alt: '',
bn_alt: '',
acceptance_date: ''
},
I'm trying to store multiple emails in a prospect system. I'm building the system with Laravel 5.8. I'm trying to put the emails using the AJAX request. And not return in a page using redirect, but keep in the same modal.
This is for a system that in the past, can only store one email. But a user says that need to store more than one email to the client. Now i'm trying to create a functionality that in a prospect, you can add multiple emails and when the user will send a proposal, will show all emails stored in that prospect.
I'm need to use the AJAX request to do it. Now I try to use the method "POST" to proceed with my functionality, i put it in my route, my view and my AJAX request.
This is my route
Route::POST('prospect/emails/save','ProspectEmailsController#store')->name('prospectEmails.store');
This is my view
<form id="emailModalProspect" method="POST">
#csrf
<input hidden name="prospect_id" id="prospect_id" type="text">
<div class="form-group mb-3">
<label class="form-control-label" for="prospect-email-name">{{ __('Nome') }}</label>
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-email-83"></i></span>
</div>
<input class="form-control" id="prospect-email-name" name="name" placeholder="Put the email owner" type="text">
</div>
</div>
<div class="form-group mb-3">
<label class="form-control-label" for="prospect-email-email">{{ __('Email') }}</label>
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-email-83"></i></span>
</div>
<input class="form-control" id="prospect-email-email" name="email" placeholder="Put the email" type="email">
</div>
</div>
<div class="text-center">
<button type="submit" id="save-email" class="btn btn-primary my-4 store-email">Store</button>
</div>
</form>
This is my controller
public function store(Request $request){
$prospect_emails = ProspectEmails::where(['prospect_id'=>$request->prospect_id])->get();
ProspectEmails::create(array_merge($request->all(), ['company_id' => Auth::User()->company_id], ['prospect_id'=>$request->prospect_id], ['tag'=>false]));
$p_email = ProspectEmails::where('prospect_id',$request->prospect_id)->get()->count();
$update_at = Carbon\Carbon::now();
Prospect::where('id', $request->prospect_id)->update(['updated_at' => $update_at, 'prospect_emails'=> $p_email]);
return response()->json();
}
And this is my Ajax request
$('.open-email-modal').on('click', function(e) {
e.preventDefault();
let p = JSON.parse($(this).attr('data-entity')); //the id of the prospect that i want to insert the emails
let modal = $('#emailModal');
let form = $('#emailModalProspect');
$('#prospect-email-name').val(p.name);
$('#prospect_id').val(p.id).change();
form.submit(function(e){
if(p.id) {
$.ajax({
url: "{{route('prospectEmails.store')}}",
type: "POST",
data : form.serialize() ,
dataType: "json",
success:function(data) {
if(data){
console.log(data); // here, in console, show a empty array like it "[]".
}
}
});
}
});
modal.modal({show : true});
});
Now always I'm trying to register a new email, show this message:
Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
No message
In console show this error.
POST http://127.0.0.1:8000/prospect 405 (Method Not Allowed)
The strange that store the data in my database, but show it. What happens to show this message?
I change to PUT method. At first it works, but show the token and the things that i store in URL. It's not what i want.
Your route is defined as prospect/emails/save, but you're POSTing to prospect, which apparently doesn't exist as a POST route.
Post to the correct route and it should work fine. Adding an action to your <form> should do the trick:
<form action="{{ route('prospectEmails.store') }}" ...>
please use
Route::any('prospect/emails/save','ProspectEmailsController#store')->name('prospectEmails.store');
or
Route::post('prospect/emails/save','ProspectEmailsController#store')->name('prospectEmails.store');
instead of
Route::POST('prospect/emails/save','ProspectEmailsController#store')->name('prospectEmails.store')
please use routes like this
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
i have a laravel page which contains a reserve form i redirect my user after selecting date now for number of people and counting the price i use vuejs but i want to pass the data to the laravel form and submit that from laravel with all the other data so here is a part of my code :
your final price
<input type="number" style=" background-color:#fff; border:none" v-model="finalPrice" disabled/>
and here is js part i cuted out code for better reading :
<script>
this.epic_price = this.sum_price + (this.total_price * this.sum_day)
this.$emit('input', this.epic_price)
</script>
although this form is not complete yet but i want to use it here in this page so i just paste it consider the form is not complete at all :
<form class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed"
action="/properties/savereserve/" method="post">
<div class="row">
#foreach($price as $key => $prices)
<div class="col-lg-2 text-center">
{{$date[$key]}}
<hr>
{{$prices}}
</div>
#endforeach
</div>
</form>
//exacly on the same page i use my vue component so they are on the same page
<reserve
:sum_price="{{$sumprice}}"
:sum_day="{{$sumday}}"
:base_price="{{$property->base_price}}"
:property_id="{{$property->id}}"
:user_id="{{Auth::user()->id}}"
></reserve>
I know that this is generally frowned upon, but for my specific reasons which I'll state below, I need this functionality:
So what we're doing on this website is that we are allowing users to buy "stores" on which they can sell products, and now those users want to add stuff like "Facebook Pixel" to their stores to allow them to track different activities.
Here's my form responsible for the code
<form action="{{ url('vendor/store/settings/analytics/update') }}" method="POST" style="margin-top: 30px;">
{{ csrf_field() }}
<div class="analytics-form">
<div class="col-md-8 col-md-offset-2 analytics-box">
<div class="form-group">
<label for="">Please pick a type of analytics to install:</label>
<select name="analytic_type[]" id="" class="form-control">
#foreach($analytic_types as $type)
<option value="{{ $type }}">{{ ucwords(str_replace('_', ' ', $type)) }}</option>
#endforeach
</select>
<br>
</div>
<div class="form-group">
<label for="">Please type/paste the code for this analytic:</label>
<textarea class="form-control" cols="5" rows="5" name="analytic_code[]" required></textarea>
<br>
</div>
</div>
</div>
<button class="btn btn-primary btn-block" id="applyAnalytics" type="submit" {{ $store->vendor->hasAnalytics() ? '' : 'disabled'}}>Apply Changes</button>
</form>
And here's the controller method I want to "hit":
public function updateAnalytics(Request $request)
{
try {
$store = auth()->user()->store;
auth()->user()->analytics()->delete();
if($request->has('analytic_type')) {
foreach($request->analytic_type as $index => $value) {
Analytics::create([
'user_id' => auth()->user()->id,
'analyticable_id' => $store->id,
'analyticable_type' => get_class($store),
'method_type' => $request->analytic_type[$index],
'method_code' => $request->analytic_code[$index],
]);
}
}
flash(__("Common.Saved_Successfully"));
} catch (\Exception $e) {
session()->flash('title', __("Common.Error"));
session()->flash('message', __("Common.An_Error_Happened"));
session()->flash('message-class', "error");
}
return redirect()->back();
}
This method works fine locally if I enter either normal text or code into the textarea, but if I tried to enter & submit the below block of code everything blows up, this block of code is the one provided by Facebook Pixel to its users, which I want to save in my database:
<!-- Facebook Pixel Code -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '339673053324500');
fbq('track', 'PageView');
</script>
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=339673053324500&ev=PageView&noscript=1"
/></noscript>
<!-- End Facebook Pixel Code -->
If I put the above code into the text area and submit the data to the server, I get this error below:
Forbidden
You don't have permission to access /app/public/vendor/store/settings/analytics/update on this server.
Additionally, a 403 Forbidden error was encountered while trying to
use an ErrorDocument to handle the request.
The server isn't even allowing me to hit the route in question, or any other route from this form as long as I am submitting code.
Note:
This is probably not an actual permission issue but a security related thing, because I've tried changing permissions on the server for all of the involved files from 0644 to 0755 and nothing changed, of course I might have done something wrong along the way, all suggestions are welcome.
I'm currently developing a system with Laravel framework. Though, I'm not very familiar with MVC architecture yet.
When I'm developing the system, I come across a problem which relates with this bootstrap modal that has a form in it. I'd like to put functions in it so that it could be submitted to the database.
I have followed several tutorials, but didn't come up with a solution because they're all using pages instead of modals.
So, here is the HTML of the modal:
<div class="modal hide fade" id="linkSettings">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Add New Link</h3>
</div>
<div class="modal-body">
<div class="control-group">
<label class="control-label" for="focusedInput">Add A Link:</label>
<div class="controls">
<textarea class="autogrow"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
Here is the Javascript of the above modal:
$('.btn-settingLink').click(function(e){
e.preventDefault();
$('#linkSettings').modal('show');
});
Now, how do I put the function in the Controller so that whenever a user presses Save Changes button, it will store the value in <textarea> into the database? Is there anything to do with the Javascript code? and Do I need to use {{Form::open('main/addLink','POST')}} at the form to pass its values to the controller and model?
Basically, all I ever wanted was to have the CRUD functions by using modal.
First you need to create a form with a route....
<form method="post" action="{{URL::to('Link/addlink')}}>
Or like you showed above, with your Blade {{Form}} ...either way
Then your textarea needs an id and name
<textarea id="mytext" name="mytext"></textarea>
So your HTML becomes...
<form method="post" action="{{URL::to('Link/addlink')}}>
<div class="modal-body">
<div class="control-group">
<label class="control-label" for="focusedInput">Add A Link:</label>
<div class="controls">
<textarea id="mytext" name="mytext" class="autogrow"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
Close
<input type="submit" id="submit" name="submit" class="btn btn-primary">Save changes</input>
</div>
</form>
Then in your Link controller...or wherever you're actually sending this form..no idea what your controllers are named :)
public function addlink(){
$input = Input::all();
//whatever validation you wanna do, with error handling etc...not gonna provide that, thats up to you
$yourmodel = New Model;
$yourmodel->text = $input['mytext'];
$yourmodel->save();
Return Redirect::back();
}
EDIT (for Ajax)
Add this script at the bottom of your page...
<script>
$(document).ready(function(){
$('input#submit').click(function(e){
e.preventDefault();
var text = $('#mytext').val();
var url = 'your url' //we were using Link/addlink in the other example
$.ajax({
type: "POST",
url: url,
data: { mytext: text },
success: function(){
//Probably add the code to close your modal box here if successful
$('#linkSettings').hide();
},
});
});
});
</script>
PS Completely untested....you will need some tweaking, plus the fact that your controller has the Redirect will probably make it not work since this will just be expecting an echoed Json string
But these are the nuts and bolts, and the foundation is there for you to continue on your own I would think...