Symfony 5 Reset Password how do i get the right url? - symfony

I'll try to explain my problem.
I have recently started a new projet and wanted to implement a reset password functionnality.
Everything seems to work except the generation of the url which is send by email.
picture of my URL
My URL should look like this : http://localhost/projectName/public/reset-password/reset/xOdfPc0iGC7nmReqX02jcemgX4EIlt2tb5vNYgTZ
But the "/projectName/public/" is missing.
I don't understand what i did wrong.
Here is my twig template for the email :
<h1>Bonjour !</h1>
<p>Pour réinitialiser votre mot de passe, merci de vous rendre sur le lien suivant</p>
{{ url('app_reset_password', { token: resetToken.token }) }}
<p>Ce lien expirera dans {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.</p>
<p>A bientôt !</p>
Here is the function in the controller that generates the templated email :
private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer, TranslatorInterface $translator): RedirectResponse
{
$user = $this->entityManager->getRepository(User::class)->findOneBy([
'email' => $emailFormData,
]);
// Do not reveal whether a user account was found or not.
if (!$user) {
return $this->redirectToRoute('app_check_email');
}
try {
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
} catch (ResetPasswordExceptionInterface $e) {
// If you want to tell the user why a reset email was not sent, uncomment
// the lines below and change the redirect to 'app_forgot_password_request'.
// Caution: This may reveal if a user is registered or not.
//
// $this->addFlash('reset_password_error', sprintf(
// '%s - %s',
// $translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_HANDLE, [], 'ResetPasswordBundle'),
// $translator->trans($e->getReason(), [], 'ResetPasswordBundle')
// ));
return $this->redirectToRoute('app_check_email');
}
$email = (new TemplatedEmail())
->from(new Address('assistance#asintel.com', 'AS Intel - Assistance'))
->to($user->getEmail())
->subject('Your password reset request')
->htmlTemplate('reset_password/email.html.twig')
->context([
'resetToken' => $resetToken,
])
;
$mailer->send($email);
// Store the token object in session for retrieval in check-email route.
$this->setTokenObjectInSession($resetToken);
return $this->redirectToRoute('app_check_email');
}
And this is the function with app_reset_password route :
/**
* Validates and process the reset URL that the user clicked in their email.
*
* #Route("/reset/{token}", name="app_reset_password")
*/
public function reset(Request $request, UserPasswordHasherInterface $userPasswordHasher, TranslatorInterface $translator, string $token = null): Response
{
if ($token) {
// We store the token in session and remove it from the URL, to avoid the URL being
// loaded in a browser and potentially leaking the token to 3rd party JavaScript.
$this->storeTokenInSession($token);
return $this->redirectToRoute('app_reset_password');
}
$token = $this->getTokenFromSession();
if (null === $token) {
throw $this->createNotFoundException('No reset password token found in the URL or in the session.');
}
try {
$user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
} catch (ResetPasswordExceptionInterface $e) {
$this->addFlash('reset_password_error', sprintf(
'%s - %s',
$translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_VALIDATE, [], 'ResetPasswordBundle'),
$translator->trans($e->getReason(), [], 'ResetPasswordBundle')
));
return $this->redirectToRoute('app_forgot_password_request');
}
// The token is valid; allow the user to change their password.
$form = $this->createForm(ChangePasswordFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// A password reset token should be used only once, remove it.
$this->resetPasswordHelper->removeResetRequest($token);
// Encode(hash) the plain password, and set it.
$encodedPassword = $userPasswordHasher->hashPassword(
$user,
$form->get('plainPassword')->getData()
);
$user->setPassword($encodedPassword);
$this->entityManager->flush();
// The session is cleaned up after the password has been changed.
$this->cleanSessionAfterReset();
return $this->redirectToRoute('main_index');
}
return $this->render('reset_password/reset.html.twig', [
'resetForm' => $form->createView(),
]);
}
Does someone have an idea what i should do to fix this problem ?
Thanks a lot

Related

Symfony 5 stripe v3 can't find CHECKOUT_SESSION_ID

I'm trying to handle monthly subscription with stripe :
I create a Payment Controller with actions :
create-checkout-session Action :
/**
* #Route ("/create-checkout-session", name="checkout")
*/
public function checkout(Request $request)
{
$data = json_decode($request->getContent());
\Stripe\Stripe::setApiKey('sk_test_...');
try {
$checkout_session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price' => $data->priceId,
// For metered billing, do not pass quantity
'quantity' => 1,
]],
'mode' => 'subscription',
'success_url' => $this->generateUrl('success', ["session_id" => "{CHECKOUT_SESSION_ID}"], UrlGeneratorInterface::ABSOLUTE_URL),
'cancel_url' => $this->generateUrl('error', [], UrlGeneratorInterface::ABSOLUTE_URL),
]);
} catch (\Exception $e) {
return new JsonResponse(["error" => ['message' => $e->getMessage()]]);
}
return new JsonResponse(["sessionId" => $checkout_session['id']]);
}
success Action :
/**
* #Route(
* "/{_locale}/success/{session_id}",
* name="success",
* defaults={"_locale"="en"},
* requirements={"_locale"="en|fr"}
* )
* #param Request $request
* #return Response
*/
public function success(Request $request): Response
{
$locale = $request->getLocale();
// Get current user
$user = $this->getUser();
\Stripe\Stripe::setApiKey('sk_test_...');
$session = \Stripe\Checkout\Session::retrieve($request->get('session_id'));
$customer = \Stripe\Customer::retrieve($session->customer);
return $this->render('payment/success.html.twig', [
'current_language' => $locale,
'user' => $user,
'session' => $session,
'customer' => $customer,
]);
}
And i created a script :
// Create an instance of the Stripe object with your publishable API key
const stripe = Stripe('pk_test_..');
const createCheckoutSession = function (priceId) {
return fetch("/create-checkout-session", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId
})
}).then(function (result) {
return result.json();
});
};
$(".subscription-btn").click(function (e) {
e.preventDefault();
let PRICE_ID = $(this).data('priceCode');
console.log(PRICE_ID);
createCheckoutSession(PRICE_ID).then(function (data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(function (result) {
// If `redirectToCheckout` fails due to a browser or network
// error, you should display the localized error message to your
// customer using `error.message`.
if (result.error) {
alert(result.error.message);
}
})
});
});
The payment work but i got this eror after redirect to success
Invalid checkout.session id: {CHECKOUT_SESSION_ID}
How can i fix this error and how can i handle monthly payment inside my project ?
I had the same problem. I just add :
$this->router->generate('my_confirm_route', ['myrouteparam' => $myRouteParam], UrlGeneratorInterface::ABSOLUTE_URL).'?session_id={CHECKOUT_SESSION_ID}';
And in controller :
$request->query->get('session_id')
Leroy is correct, but I'd suggest you confirm that the success_url you're generating actually looks the way it's supposed to - i.e. isn't having those {}s urlencoded - as that might be what's going on here.
Beyond that I believe your approach is correct, and Leroy's is not - I think you're not providing Stripe with an unencoded URL so it's not recognizing {CHECKOUT_SESSION_ID} as a template string as it should be.
I was able to fix the problem by simply decoding the url before sending it.
urldecode($this->generateUrl('stripe-checkout-success', ['session' => '{CHECKOUT_SESSION_ID}'], UrlGeneratorInterface::ABSOLUTE_URL))
You pass that exact value to your PSP as success_url.
'success_url' => $this->generateUrl('success', ["session_id" => "{CHECKOUT_SESSION_ID}"], UrlGeneratorInterface::ABSOLUTE_URL),
Then you are getting back that redirect url, as literal : /en/success/{CHECKOUT_SESSION_ID}
Next you lookup that exact value {CHECKOUT_SESSION_ID} from some api.
$session = \Stripe\Checkout\Session::retrieve($request->get('session_id'));
I'm not sure, but I think you need to fetch the session id from the success_url's body instead of the the $request object.
I also think you can skip the session_id in the success_url, because that's the users's callback url. While the user is being redirected back to your application, the user is still logged in, You don't want to send your session id to your PSP.
I think your feedback is in the post body, based on what you've configured at stripe. Doing something like this should give you what you want.
First of all, remove the session id from the success_url
'success_url' => $this->generateUrl('success', UrlGeneratorInterface::ABSOLUTE_URL),
Next, change your success url logic to use the post body.
/**
* #Route(
* "/{_locale}/success",
* name="success",
* defaults={"_locale"="en"},
* requirements={"_locale"="en|fr"}
* )
* #param Request $request
* #return Response
*/
public function success(Request $request): Response
{
...
$body = $request->getContent();
$feedback = json_decode($body, true);
$session = \Stripe\Checkout\Session::retrieve($feedback['id']);
...
}
PS, bare in mind that I haven't read the documentation about Stripe. But I strongly believe that they send you their session id (which you created) back in some form.

woocommerce 3: removing cart items for logged in users does not work

we are using wordpress JSON API to signon a user and to add / update / remove cart-items. We are doing this with the register_rest_route function.
We use this code to remove a cart item:
function remove_from_cart(WP_REST_Request $req)
{
$resp = null;
$cart_item = $req['cart_item'];
try {
WC()->cart->remove_cart_item($cart_item);
} catch (Exception $e) {
$resp = $e;
}
return rest_ensure_response(new CartResponse());
}
This is working perfectly fine for guests. but as soon as a logged in user tries it, the cart is back to its normal state after a page reload. The response created by new CartResponse() is correctly showing the cart without the removed item. however, after a page reload the item is still there.
As this only happens for logged in users and not for guests I think it is a session issue.
Also, updating the cart with the following method works for logged in users:
function update_cart_item(WP_REST_Request $req)
{
$resp = null;
$cart_item = $req['cart_item'];
try {
if ($cart_item && $cart_item['quantity']) {
WC()->cart->set_quantity($cart_item['key'], $cart_item['quantity']);
}
} catch (Exception $e) {
$resp = $e;
}
return rest_ensure_response(new CartResponse());
}
Unfortunately, setting the quantity to 0 is also not working.
This is how we signon users:
function login_customer(WP_REST_Request $req)
{
$body = $req->get_body();
$input = json_decode($body, TRUE);
$credentials = ['user_login' => $input['email'], 'user_password' => $input['password']];
$user = wp_signon($credentials, false);
if (is_a($user, 'WP_Error') || !$user) {
// if an error occurs, return null
return rest_ensure_response(null);
}
$resp = new CustomerResponse($user->ID);
return rest_ensure_response($resp);
}
And we are not using any caching plugins. What is wrong here?
Here is a list of all session cookies:
EDIT:
I just inspected the cookies while beeing logged in and removing a cart item.
Cart Hash before deleting: bb35785a228a17ceb85f8ed2dc522b16
Cart Hash directly after deleting: d32e22e278d42022e04b6992b7d65816
Cart Hash after page reload: bb35785a228a17ceb85f8ed2dc522b16 again
So it seems like the cart hash is stored somewhere and restored on a reload, but not correctly updated on deleting a cart item
It seems like you need nonces to authenticate DELETE requests.
Now I am adding nonces to each response in a header:
function add_cors_http_header(){
header("X-WP-Nonce: ".wp_create_nonce('wp_rest'));
}
add_action('init','add_cors_http_header');
And in the frontend I set it:
let nonce: string = null;
export const fetchNoAuth = (endpoint: string, method: string = 'GET', data: any = null): Promise<any> => {
let headers: any = {'Content-Type': 'application/json'};
if (nonce) {
headers['X-WP-Nonce'] = nonce;
}
return fetch('http://' + apiUrl + apiPath + endpoint + '?' + debugQuery, {
method,
credentials: 'include',
headers,
body: data ? JSON.stringify(data) : null
})
.then((data) => {
const nonceFromResponse = data.headers.get('X-WP-Nonce');
if (nonceFromResponse) {
nonce = nonceFromResponse;
} else {
nonce = null;
}
return data;
})
};
Make sure that the header in the request is named X-WP-Nonce

error in mail functionality in laravel 5.3

Im working with laravel 5.3. In that i have mail functionality the variable get after the mail function is not working, below is my controller coding
public function checkEmail(Request $request) {
$email = $request->input('email');
$users = Student::where('email', $email)->select('email')->first();
if(count($users) > 0){
$id =Student::where('email',$email )->value('id');
$url=url('/').'/password-reset/'.$id;
Mail::send('/resetpassword', ['email'=>$email,'url'=>$url ], function($message)
{
$message->to(Input::get('email'))->subject('Reset Password');
});
return redirect()->back()->with('message', 'Link has been sent to your Mail');
} else {
return redirect()->back()->with(['message' => 'No Records Found']);
}
}
I got all the variable values before mail function (i.e.,)
Mail::send('/resetpassword', ['email'=>$email,'url'=>$url ], function($message)
{
$message->to(Input::get('email'))->subject('Reset Password');
});
I got error like this
Class 'App\Http\Controllers\Input' not found
if i use any variable the error is like this
Undefined Variable:url
Please anyone tellme what i did wrong...

Email sending in laravel 5.3

I an using this code in laravel 5.3 for sending email. But it says undefined variable $email, while i have defined the variable already.
This is my code.
$user->save();
if (!empty($user->save())) {
$email = 'ppriyadarshi49#gmail.com';
$mail = Mail::send('email_page', ['verification_key' => $verification_code], function($message) {
$message->from('prince.priyadarshi#fluper.com', 'Verify');
$message->to($email)
->subject('Verify your email address');
});
return view('for_company');
}
And the error is Undefined variable: email
Your are missing use() in closure function as:
$user->save();
if (!empty($user->save())) {
$email = 'ppriyadarshi49#gmail.com';
$mail = Mail::send('email_page', ['verification_key' => $verification_code], function($message) use($email) {
$message->from('prince.priyadarshi#fluper.com', 'Verify');
$message->to($email)
->subject('Verify your email address');
});
return view('for_company');
}

google calendar refresh token and codeigniter

I'm using Google Calendar API to display events on fullcalendar (so using a json object in my view). I'm using codeigniter php framework, and I have a few functions in my controller to create a new client then I use that in the oauth2callback() function to exchange my code for an access_token then I start calling the service in gcalendar() and gcalendar_events. I have set the accessType to offline but that doesn't seem to make me access the events offline. It works great except that I'm redirected to log in again every time the session ends. I don't want that, I want them to display all the time after the session ends. I am trying to use a refresh token in case the access_token expires to see if that would fix the problem.
this is the code in my controller
function getClient() {
$client = new Google_Client();
$client->setApplicationName("DL Calendar");
$client->setAuthConfig('application/client_secrets.json');
$client->addScope('profile');
$client->setIncludeGrantedScopes(true);
$client->setAccessType('offline');
return $client;
}
function gcalendar() {
$this->load->add_package_path(APPPATH . 'vendor/autoload');
$client = $this->getClient();
//$client->setRedirectUri(site_url('calendar/index'));
$client->addScope(Google_Service_Calendar::CALENDAR);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$access_token = $_SESSION['access_token'];
$service = new ]Google_Service_Calendar($client);
$calendar = new Google_Service_Calendar_Calendar();
//$calendarList = $service->calendarList->listCalendarList();
$calendar = $service->calendars->get('primary');
$params = array(
'owner_id' => get_current_user_id(),
'title' => get_current_user(). ' ' .'Google Calendar',
'type' => 'gcal',
'url' => $calendar->id,
);
$calendar_id = $this->Calendar_model->add_calendar($params);
redirect('calendar/index');
} else {
$redirect_uri = site_url('calendar/oauth2callback');
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
$this->session->set_flashdata('success', 'Event Successfully Added');
}
function oauth2callback() {
//Build the client object
$client = $this->getClient();
$client->addScope(Google_Service_Calendar::CALENDAR);
$service = new Google_Service_Calendar($client);
$url = parse_url($_SERVER['REQUEST_URI']); parse_str($url['query'], $params);
$code = $params['code'];
//To exchange an authorization code for an access token, use the authenticate method:
if (! isset($code)) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$token = $client->fetchAccessTokenWithAuthCode($code);
$client->setAccessToken($token);
$client->authenticate($code);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = site_url('calendar/gcalendar');
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
}
function gcalendar_events() {
$client = $this->getClient();
$client->addScope(Google_Service_Calendar::CALENDAR);
// $client->setRedirectUri(site_url('calendar/gcalendar'));
$client->setAccessType('offline'); //need calendar events to appear even if not logged in to google
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$access_token = $_SESSION['access_token'];
$service = new Google_Service_Calendar($client);
$id = 'primary';
$calendar = new Google_Service_Calendar_Calendar();
$calendar = $service->calendars->get('primary');
$event = new Google_Service_Calendar_Event();
$events = $service->events->listEvents($id);
foreach ($events->getItems() as $event) {
$startTime = strtotime($event->getStart()->dateTime) ;
$endTime = strtotime($event->getEnd()->dateTime);
$start = date('Y-m-d H:i:s', $startTime);
$end = date('Y-m-d H:i:s', $endTime);
$eventsArr[] = array(
'title' => $event->getSummary(),
'start'=> $start,
'end' => $end,
);
}
// Return a single `events` with all the `$eventsArr`
echo json_encode($eventsArr);
}
}
Is the problem in my session ending? or does the access token expire and I need a refresh token? where do I set the refresh token cause I tried putting it in more that one place and I get an error message that refresh token has to be set as part off setAccessToken. I put it all over and still got error messages.
Here is the code I used
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($refresh_token);
$_SESSION['access_token'] = $refresh_token;
$this->load->helper('file');
write_file('application/client_secrets.json', json_encode($client->getAccessToken()));
} else {
$access_token = $_SESSION['access_token'];
}
I just noticed that it once used to say 'grant offline access' in my authorization but now it no longer mentions that while google documentation says
"After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed."
During your first authorization with Google, you will receive a token that will expire in 3600 seconds or one hour. So you need to use refresh token to get a new working token.
It is something like this SO question.
$token = $client->getAccessToken();
$authObj = json_decode($token);
if(isset($authObj->refresh_token)) {
save_refresh_token($authObj->refresh_token);
}
Make sure you save this refresh_token.
You can update it with:
$client->refreshToken($your_saved_refresh_token);
And then set your new access token to the session:
$_SESSION['access_token'] = $client->getAccessToken();
I also suggest you to visit this quickstart of Google Calendar for PHP.
For more information, check this related SO question.
How to refresh token with Google API client?

Resources