URL::forceSchema not working before login - laravel

I'm using URL::forceSchema('https') to force SSL on my Laravel 5.3 application. However, it only works after login (even the login page isn't being covered with https).
I'm using TrustedProxy with the following configuration:
'headers' => [
(defined('Illuminate\Http\Request::HEADER_FORWARDED') ? Illuminate\Http\Request::HEADER_FORWARDED : 'forwarded') => null,
\Illuminate\Http\Request::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
\Illuminate\Http\Request::HEADER_CLIENT_HOST => null,
\Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
\Illuminate\Http\Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
]

I finally got it working by adding the following code to register method of AppServiceProvider.
if (env('APP_ENV') === 'production') {
$this->app['request']->server->set('HTTPS', true);
}
Source: https://laracasts.com/discuss/channels/laravel/force-ssl-secure-routes-in-laravel-52?page=1

Add a config called "force_https" in your config file, and don't forget to add it into your .env.
config/app.php
'force_https' => env('FORCE_HTTPS', false),
Then, in app/Providers/AppServiceProvider.php :
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot(UrlGenerator $url)
{
if (config('app.force_https')) {
$url->forceScheme('https');
}
}
This way, whenever you serve your app behind a reverse proxy where connection between proxy and app is insecure, you can set the FORCE_HTTPS to true, and false if your local dev don't require one.

Related

I'm trying to use guzzlehttp/guzzle in Magento 2.2.9 but it's not working

It's throwing me an error
PHP Error: Cannot instantiate interface GuzzleHttp\\ClientInterface in vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php on line 111, referer: http://127.0.0.1/local_m2/admin/admin/system_config/edit/section/active_campaign/key/6a9ce672c9414c57acd889eb50fb82020e13e651b74cf3a81b9cd8b30da45306/ here
I have already run all Magento required commands Like Setup: upgrade, di:compile and deploy but still it's throwing me this error.
I have already checked GuzzleHttp in the vendor folder, it's already installed in Magento 2.2.9
I have tried the composer require guzzlehttp/guzzle:^6.0 to reinstall the library but having no luck.
import this library:
use GuzzleHttp\Client;
use GuzzleHttp\ClientFactory;
use GuzzleHttp\Exception\RequestException;
on __construct use:
$this->client = new Client([
"base_uri" => url_base,
"timeout" => 2,
]);
and then call:
$response = $this->client->get(
url_base . "/" . url_api_point,
['headers' =>
[
'Authorization' => "Bearer {$this->token}" /* if have */
]
]
);
return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
try this way to create an instance of GuzzleClient, im currently using a similar in a magento 2.4.4 and works fine, you don´t have to inyect that on __construct()
/**
* #return \GuzzleHttp\Client
*/
public function getClient()
{
$client = new \GuzzleHttp\Client(["base_uri" => "your url", "verify" => false]);
return $client;
}

Call to undefined method Symfony\Component\HttpFoundation\Response::create() when adding webhook in facebook

BotMan Version: 2.6.1
PHP Version: 8.1
Messaging Service(s): Facebook
Cache Driver: LaravelCache
Laravel: 9.18
Description:
Hi, im geting this error in laravel 9, how to handle it easiest way?
method create not exist, so should i make new class that extends Request with method create ?
I already tried to change all references from use Symfony\Component\HttpFoundation\Response;
to Illuminate\Http\Response (and Request) but this also not work.
curl -X GET "https://somedomain.org/botman?hub.verify_token=MySecretTokenFromDotENV&hub.challenge=CHALLENGE_ACCEPTED&hub.mode=subscribe"
Reponse:
Error: Call to undefined method Symfony\Component\HttpFoundation\Response::create() in file /var/www/nams/botman/driver-facebook/src/FacebookDriver.php on line 120
#0 /var/www/nams/botman/botman/src/Drivers/DriverManager.php(157): BotMan\Drivers\Facebook\FacebookDriver->verifyRequest()
#1 /var/www/nams/botman/botman/src/BotMan.php(542): BotMan\BotMan\Drivers\DriverManager::verifyServices()
#2 /var/www/nams/botman/botman/src/BotMan.php(421): BotMan\BotMan\BotMan->verifyServices()
#3 /var/www/nams/app/Http/Controllers/BotManController.php(40): BotMan\BotMan\BotMan->listen()
#4 /var/www/nams/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\Http\Controllers\BotManController->handle()...
Steps To Reproduce:
Install botman on laravel 9 from local repository (path)
change in composer/json dependencies to fit laravel 9
Try to connect to facebook like:
$config = [
'user_cache_time' => 720,
'config' => [
'conversation_cache_time' => 720 ,
],
// Your driver-specific configuration
'facebook' => [
'token' => env('FACEBOOK_TOKEN'),
'app_secret' => env('FACEBOOK_APP_SECRET'),
'verification' => env('FACEBOOK_VERIFICATION'),
]
];
$botman = app('botman');
DriverManager::loadDriver(\BotMan\Drivers\Facebook\FacebookDriver::class);
BotManFactory::create($config, new LaravelCache());
$botman->listen();
try to get response for facebook by:
curl -X GET "https://somedomain.org/botman?hub.verify_token=MySecretTokenFromDotENV&hub.challenge=CHALLENGE_ACCEPTED&hub.mode=subscribe"
Function that generates error is below, probably updating it to newest laravel/symfony will work, but I'm not yet so confident to know how to repair this
/**
* #param Request $request
* #return null|Response
*/
public function verifyRequest(Request $request)
{
if ($request->get('hub_mode') === 'subscribe' && $request->get('hub_verify_token') === $this->config->get('verification')) {
return Response::create($request->get('hub_challenge'))->send();
}
}
You can replace
use Symfony\Component\HttpFoundation\Response;
by
use Response; (\Illuminate\Support\Facades\Response)
And in the function do :
/**
* #param Request $request
* #return null|Response
*/
public function verifyRequest(Request $request)
{
if ($request->get('hub_mode') === 'subscribe' && $request->get('hub_verify_token') === $this->config->get('verification')) {
return Response::make($request->get('hub_challenge'))->send();
}
}
At least it worked for me on TwilioDriver

Laravel dusk with browserstack to run tests on multiple devices and browsers

I am using this ("browserstack/browserstack-local": "^1.1") package to run dusk tests on BrowserStack. Now the requirement is to run tests on multiple and different devices with different browsers. Currently, I am following this approach to run tests.
private function browserStackCaps($local_identifier)
{
return [
'project' => config('app.name'),
'browserstack.local' => 'true',
'browser' => env('BROWSER'),
'device' => env('DEVICE'),
'acceptSslCert' => true,
'resolution' => '1920x1080'
];
}
The drawback of this approach is I have to change the device name and browser name in the .env file every time I need to run tests on a different device/browser. Is there any way I can run tests on the provided array? The array that contains devices and browser information.
I know this is old, but I found this page while searching for a solution. I ended up building one myself that would probably meet your use-case. The biggest hurdle that I had was $this->browse() in a normal Dusk test was using a single instance of Laravel\Dusk\Browser and the new capabilities were not being pulled in. This implementation adds a function called performTest to the DuskTestCase.php file. This function loops through a set of capabilities and instantiates a new instance of Laravel\Dusk\Browser for each test. This function works similarly to the existing browse function in Laravel Dusk. You call performTest by passing it a callable that accepts a single parameter which is an instance of Laravel\Dusk\Browser
Dusk Test Case
<?php
namespace Tests;
use Laravel\Dusk\TestCase as BaseTestCase;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
abstract class DuskTestCase extends BaseTestCase
{
use CreatesApplication;
protected array $capabilities;
private const BROWSERS = [
'ios_14_iphone_xs_safari' => [
"os_version" => "14",
"device" => "iPhone XS",
"real_mobile" => "true",
"browserstack.local" => "true",
'acceptSslCerts' => 'true'
],
'mac_osx_catalina_safari' => [
"os" => "OS X",
"os_version" => "Catalina",
"browser" => "Safari",
"browser_version" => "13.0",
"browserstack.local" => "true",
"browserstack.selenium_version" => "3.14.0",
"resolution" => "1920x1080",
'acceptSslCerts' => 'true',
]
];
/**
* Create the RemoteWebDriver instance.
*
* #return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
$browserStackConnectionUrl = config('browserstack.connection_url');
return RemoteWebDriver::create(
$browserStackConnectionUrl, $this->capabilities
);
}
protected function performTest(Callable $test){
foreach(self::BROWSERS as $browserName => $capabilitySet){
try {
$this->capabilities = $capabilitySet;
$browser = $this->newBrowser($this->driver());
$test($browser);
$browser->quit();
fprintf(STDOUT, "\e[0;32m√ {$browserName}\r\n");
}
catch(\Exception $exception){
fprintf(STDOUT, "\e[0;31mX {$browserName}\r\n");
throw $exception;
}
}
}
}
Example Test
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
class ExampleTest extends DuskTestCase
{
public function testExample()
{
$this->performTest(function(Browser $browser){
$browser->visit('/')
->assertDontSee('Foobar');
});
}
}
config/browserstack.php
<?php
return [
'connection_url' => env('BROWSERSTACK_CONNECTION_URL')
];
you can implement this at your end. Fetch the list of Browsers and Devices you want to execute your tests on using the REST API and use the same.
REST API to be used:
curl -u "username:password"
https://api.browserstack.com/automate/browsers.json
Read more on this here:
https://www.browserstack.com/docs/automate/api-reference/selenium/browser#get-browser-list

Laravel localization and routes from Jetstream / Fortify

I have this new Laravel project to work on. We would like to make it available in multiple languages.
I started the project with JetStream. Routes for authentication and such are automatically handled by JetStream / Fortify. I then added https://github.com/mcamara/laravel-localization to handle the localization. it works fine for the routes I created myself :
Route::group(
[
'prefix' => LaravelLocalization::setLocale(),
'middleware' => [ 'localeSessionRedirect', 'localizationRedirect', 'localeViewPath' ]
], function()
{
Route::get('/', function () {
return view('welcome');
});
Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
});
But how can I set the group, prefix and middleware on the routes handled by Jetstream and Fortify?
[EDIT]
So after some suggestions from #TEFO, I'm trying to add a middleware to handle setting the locale. Added :
Fortify.php :
'path' => '{lang}',
'middleware' => ['web', 'setLang']
new middleware setLang :
class SetLang {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(\Illuminate\Http\Request $request, Closure $next) {
// $lang = 'en';
// $request->attributes->add(['lang' => 'en']);
$request->route()->setParameter('lang', 'en');
// $request->request->set('lang', 'en');
return $next($request);
}
}
Added the middleware to $routeMiddleware.
I'm receiving this error when trying to reach http://mylaravel/en/login :
ErrorException
Missing required parameters for [Route: login] [URI: {lang}/login]. (View: /var/www/resources/views/auth/login.blade.php)
Finally successfully nailed this. I simply disabled routes from Fortify and Jetstream, copied them over and shoved them inside my grouped prefix routes. Still using https://github.com/mcamara/laravel-localization but it should work anyway you want it - make your own system or whatever, as long as you control the routes you're good to go.
In JetstreamServiceProvider :
public function register() {
Jetstream::ignoreRoutes();
}
In FortifyServiceProvider :
public function register() {
Fortify::ignoreRoutes();
}
And copy over routes from Fortify vendor/laravel/fortify/routes/routes.php and Jetstream vendor/laravel/jetstream/routes/livewire.php (I guess adapt to Inertia if you're working with this) over to your web.php file, inside a route group with the prefix you need.
I faced almost the same problem with the expection that i do not use mcamara/laravel-localization at the moment.
Based on the useful discussion above between #JeremyBelolo and #TEFO, the following solution worked for me:
Added 'path' => '{locale}/my-secret-path' to config/fortify.php. As #JeremyBelolo and #ETO discussed, the support for that was recenlty added.
Added my middleware before \Laravel\Jetstream\Http\Middleware\AuthenticateSession::class to the web $middlewareGroups
Where my middleware set the locale app()->setLocale($locale); and the default {locale} url parameter URL::defaults(['locale' => $locale]); before passing the request deeper into the application.
Considering Jetstream I had to apply the same steps as #JeremyBelolo did, exept I didn't copy the jetsream/livewire routes but used the following inside the route group:
require base_path('vendor/laravel/jetstream/routes/livewire.php');
Now I can access {locale}/my-secret-path/login where {locale} is a supported locale for my site.
UPDATE [Fortify config option changed]:
The path fortify config option changed to prefix. Thus in config/fortify.php the following key should be used:
'prefix' => '{locale}/my-secret-path'
I made a new Laravel Project using Jetstream. I wanted to use multi-language support in my project, but when I used Prefix (en/login, de/login) according to languages in url, I was also having a problem with Route. I solved my problem by following these steps. I hope you will be useful too:
1 - I have included the package on this https://github.com/mcamara/laravel-localization in my project. and followed the instructions sequentially.
2 - I made the Route settings in the "rautes\web.php" file as follows.
Route::group(['prefix' => LaravelLocalization::setLocale(),'middleware' => [
'localeSessionRedirect', 'localizationRedirect','localeViewPath' ]], function(){
/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
Route::get('/', function () {return view('welcome');});
Route::middleware(['auth', 'verified'])->get('/dashboard', function () {
return view('back.dashboard');})->name('dashboard');
});
3 - I have included the in app\Http\Middleware\Kernel.php. In middlewareGroups end of web prefix.
protected $middlewareGroups = [
'web' => [....
\Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes::class,
\Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter::class,
\Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect::class,
\Mcamara\LaravelLocalization\Middleware\LocaleCookieRedirect::class,
\Mcamara\LaravelLocalization\Middleware\LaravelLocalizationViewPath::class,]
4 - Fortify Routes, include prefix in vendor\laravel\fortify\routes.php - Route::group like this:
Route::group(['prefix' => LaravelLocalization::setLocale(),
'middleware' => config('fortify.middleware', ['web'])], function () {
$enableViews = config('fortify.views', true);
.......
5 - Livewire Routes, include prefix in vendor\laravel\jetstream\routes\livewire.php - Route::group like this:
Route::group(['prefix' => LaravelLocalization::setLocale(),
'middleware' =>config('jetstream.middleware', ['web'])], function () {
if (Jetstream::hasTermsAndPrivacyPolicyFeature()) {
Route::get('/terms-of-service', [TermsOfServiceController::class, 'show'])-
>name('terms.show');
Route::get('/privacy-policy', [PrivacyPolicyController::class, 'show'])-
>name('policy.show');}
6 - If you want to separate backend and frontend, you can add in app\Http\Middleware\Kernel.php end of protected $routeMiddleware with prefix like in this https://github.com/mcamara/laravel-localization.
protected $routeMiddleware = [
........
'localize'=> \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes::class,
'localizationRedirect' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter::class,
'localeSessionRedirect' => \Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect::class,
'localeCookieRedirect' => \Mcamara\LaravelLocalization\Middleware\LocaleCookieRedirect::class,
'localeViewPath' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationViewPath::class,
]
7 - And the happy end...

Laravel4 seed specific environment

We're are developing multiple applications based on Laravel 4. These applications run on the same webserver.
The Laravel4 environment detection is based on the hostname which sucks because we have multiple applications on the same machine.
We created a work-around in the detection area so that it will set the environment based on the url.
We run the artisan --env=my_env migrate command when we update the applications DB. The problem is in the seeding, the seeding command doesn't have a env option so it will try to seed the db based on the hostname wich will not be correct.
I'm trying all day to find a solution but I can't find any on the Internet and my attempts to build a new command is just taking too much time and energy.
Does someone knows how to set the environment when seeding?
PS: I run the commands on the server through Grunt and I know the environment -inject it into the command-.
You pointed it very well, Laravel environment guessing sucks the way we use to use it, but you can change that:
This is how I do set my environment flawlessly, so I don't have to deal with hostnames and still don't get my local environment conflict with staging and production.
Create a .environment file in the root of your application and define your environment and add your sensitive information to it:
<?php
return array(
'APPLICATION_ENV' => 'development', /// this is where you will set your environment
'DB_HOST' => 'localhost',
'DB_DATABASE_NAME' => 'laraveldatabase',
'DB_DATABASE_USER' => 'laraveluser',
'DB_DATABASE_PASSWORD' => '!Bassw0rT',
);
Add it to your .gitignore file, so you don't risk having your passwords sent to Github or any other of your servers.
Right before $app->detectEnvironment, in the file bootstrap/start.php, load your .environment file to PHP environment:
foreach(require __DIR__.'/../.environment' as $key => $value)
{
putenv(sprintf('%s=%s', $key, $value));
}
And then you just have to use it:
$env = $app->detectEnvironment(function () {
return getenv('APPLICATION_ENV'); // your environment name is in that file!
});
And it will work everywhere, so you don't need to have separate dirs for development and production anymore:
<?php
return array(
'connections' => array(
'postgresql' => array(
'driver' => 'pgsql',
'host' => getenv('DB_HOST'),
'database' => getenv('DB_DATABASE_NAME'),
'username' => getenv('DB_DATABASE_USER'),
'password' => getenv('DB_DATABASE_PASSWORD'),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
),
),
);
Note that I don't set a fallback:
return getenv('APPLICATION_ENV') ?: 'local';
Because I want it to fail on every server I deploy my app to, to never forget configuring my environment on them.
Then you just have to select the environment in your DatabaseSeeder class:
public function run()
{
if( App::environment() === 'development' )
{
$this->call('UserTableSeeder');
}
}
I thought about the situation some days and got to the conclusion that what we're trying to do isn't the correct way.
The correct way would be that every application has his own config files -with the different envs-. This way the resolve function of Laravel works fine.
The situation now is that we have multiple clients within one application and strore does -clients- configuration files within one application. In this case the hostname resolve will return the one client's -every time the same client- config beacuse the clients applications run on the same machine.
Our solution
We are going to write a deployment script for the different clients so that every client has his own application with their configs only (copy application, copy/overwrite client config into app).
Work-around
The answer of #Antonio Carlos Ribeiro works offcourse but had to much impact on our application. We use the different environments and with this solution we had to use the same user/pass info on all environments or provide a different .environment file.
I wrote an Artisan command to make our deployment work for the moment. This command can seed a database with the configuration of the provided environment (php artisan db:seed_env my_env).
use Illuminate\Console\Command;
use Illuminate\Config\Repository;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class SeedEnvironmentDb extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'db:seed_env';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Seed a database with the configuration of the environment';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
$cmd = $this;
$app = App::make('app');
// force the environment to the given one.
$env = $app->detectEnvironment(function() use ($cmd) {
return $cmd->argument('environment');
});
// create new config with the correct environment and overwrite the current one.
$app->instance('config', $config = new Repository(
$app->getConfigLoader(), $env
));
// trigger the db seed (now with the correct environment)
$this->call('db:seed');
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array(
array('environment', InputArgument::REQUIRED, 'The environment to seed.'),
);
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array();
}
}

Resources