Friday, 29 July 2022

[Flutter] Fix install error "cmdline-tools component is missing" and "Android license status"

Flutter on windows

Command line tools are very useful during android app development with Flutter. In some cases you may have difficulty installing it due to version incompatibility or conflicts with other software. After installing cmdline-tools you can continue to confirm the Android license.

Sample Flutter doctor analytic info:

C:\Users>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.0.5, on Microsoft Windows [Version 10.0.19043.1826], locale en-US)
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    X Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[√] Chrome - develop for the web
[X] Visual Studio - develop for Windows
    X Visual Studio not installed; this is necessary for Windows development.
      Download at https://visualstudio.microsoft.com/downloads/.
      Please install the "Desktop development with C++" workload, including all of its default components
[√] Android Studio (version 2021.2)
[√] VS Code (version 1.69.2)
[√] Connected device (3 available)
[√] HTTP Host Availability
! Doctor found issues in 2 categories.

As suggested, you just need to run the command: Run `path/to/sdkmanager --install "cmdline-tools;latest"`. But there might be an error: Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema. In this case we can fix it by installing cmdline-tools through Android Studio. This method is always applicable and very easy to do.

Step 1: In the Android Studio software, you click on the menu Tools >> SDK Manager

Step 2: In the SDK Manager setting screen, select the "SDK Tools" tab. Then tick "Android SDK Command-line Tools (lastest)". Finally click "Apply" to start the installation.

Step 3: After installing "Command-line Tools" you can open a command line window to continue to confirm "Android licenses"

flutter doctor --android-licenses

Done ! Check Flutter doctor to make sure everything is fully installed. Good luck.


Tuesday, 26 July 2022

[Laravel] How to find out which Class and File are behind a Facade

Facades in Laravel allow us to call libraries very conveniently. However, developers who are new to a project will find it difficult to investigate errors because Laravel Error Handling does not specify which class caused the error. In particular, the problem is very common with Facades that have many services  available. Ex: DB, Image, Auth, Cache, Mail...

Laravel Facade Flow

* Quick debug:

To find out the PHP class behind a Facade that you don't know where it is, you can debug it with the following code:
$behindClass = get_class(\<<Facade>>::getFacadeRoot());
$classReflector = new \ReflectionClass($behindClass);
dd($behindClass, $classReflector->getFileName(), $classReflector);
ex: 
$behindClass = get_class(\Mail::getFacadeRoot());
$classReflector = new \ReflectionClass($behindClass);
dd($behindClass, $classReflector->getFileName(), $classReflector);
result:

* Understand how the Facade is loaded by Laravel:

To find the underlying class behind a Laravel Facade without debugging you need to understand how a Facade is installed and loaded into Laravel.
Facade looks magical, but it's actually based on PHP's built-in class_alias feature. You can see in the project's config file (/config/app.php) there is a block to declare the Facade class alias.
Ex:
'aliases' => [
  ....
  'Lang' => Illuminate\Support\Facades\Lang::class,
  'Log' => Illuminate\Support\Facades\Log::class,
  'Mail' => Illuminate\Support\Facades\Mail::class,
If you open the class Illuminate\Support\Facades\Mail you will see that the class is almost completely empty. It has very little source code and doesn't really handle any features. In this file, the most special thing we see is the getFacadeAccessor() function and this function does not process anything but just returns a simple string like "mailer". This function is present in all Facades.
protected static function getFacadeAccessor()
{
         return 'mailer';
}
It looks magical, but it's not really here. Illuminate\Support\Facades\Mail inherits another class, Illuminate\Support\Facades\Facade::class . In this superclass Laravel will call getFacadeAccessor() to get the name of the actual service that has been configured by laravel for this facade. The example here is 'mailer'. Laravel will then call the 'mailer' service to return the Facade call - app('mailer').
You may be wondering that until now we still do not know where the 'mailer' service is located and how it is declared in Laravel.
Normally, every Laravel service needs to be declared through a Provider and then be available anywhere. Facades are treated the same way. Usually when you install a service pack from outside you will see in the source code of that service pack in addition to the Class Facade there will be a Class Provider to declare the service with Laravel. This means that once we have found information about Facade's extension in config/main.php, we can next look for Class Provider in that extension's source code to see the exact services that have been provided. How is it declared and what files it leads to.
Ex:
class MailServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register()
    {
        $this->registerSwiftMailer();
        $this->registerIlluminateMailer();
        $this->registerMarkdownRenderer();
    }
    protected function registerIlluminateMailer()
    {
        $this->app->singleton('mailer', function ($app) {
            $config = $app->make('config')->get('mail');
Usually the Providers will be installed automatically when we add the extension package to the project. In addition, Providers can also be manually declared in "config/app.php". There are some services that are core of Laravel, so by default they are declared when laravel starts. For example, with the 'mailer' service we just learned about. For core services, the Facade location and the service source code may be different. As with most package that you install from a third party, the Facade source code, Facade Provider, and Facade-related files are all in the same place in Vendors.

* Note:

we can read the source code in the "vendor" to understand and find a way to fix the error faster, but it is absolutely not recommended to edit the source code directly in the "vendor".

Saturday, 28 May 2022

[Windows 7] Your connection is not private NET::ERR_CERT_AUTHORITY_INVALID for all HTTPS sites

Recently, Windows 7 users reported an error that they could not access the websites "Your connection is not private", "NET::ERR_CERT_AUTHORITY_INVALID". This error is encountered in all browsers on the machine. And it is encountered only when accessing websites with https. In other cases, the website displays a blank page because the static content files cannot be loaded. This error is encountered because the customer's Windows 7 operating system is not fully updated with security patches.

SSL certificate error on all browsers, for all HTTPS sites

Solved

To fix this, If you are using windows 7, please install security update KB3004394 from Microsoft.
You can download the KB3004394 package from the official Microsoft website using the following link:


To install the update successfully, Windows must have the Windows Update feature enabled.

After installing the update above, please clear your browser's browsing history data and restart your computer. HTTPS sites can now be accessed normally.
In addition, you should also install all the latest updates for your windows 7 operating system through the Windows Update feature. This will help keep your computer safe and less prone to problems.

Done !

Thursday, 12 May 2022

[Solved] SSH and Gitlab negotiate error "no matching host key type found"

When using new Linux operating systems like Ubuntu 22.04 you may have trouble with SSH when you want to connect to old Linux servers.

Unable to negotiate with ***.***.***.*** port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

This error can be encountered when you directly access an old server via SSH. Or when you use Git, SVN, or any other software that uses the SSH protocol.

Reason

To be able to make an ssh connection, the Server and the client need to negotiate a secure connection encryption method. That is to find an encryption method that both the server and the client support. OpenSSH in older OS versions like Centos 6 only supports the old encryption standards ssh-rsa and ssh-dss. These 2 encryption standards are outdated and potentially dangerous. Therefore, the new version of OpenSSH disables these encryptions by default. Newer encryption commonly used is ssh-ed25519, ecdsa-sha2 ...

Solved

To solve this error, you need to configure ssh on the new server to accept the old encryption standards as ssh-rsa or ssh-dss (just 1 is enough). We suggest 2 solutions to do just that.

Solution 1:

Enable dss or rsa encryption for ssh on your new server.

To do so open the file "~/.ssh/config"

vi ~/.ssh/config

Then add the following content to the file (change ssh-rsa to ssh-dss if your old server only support it)

Host *
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa

Done ! Now you can connect ssh to old servers via terminal normally. However, if you are using Git over ssh with a privateKey file, this will not work (to solve see solution below).

Tip: you can also restrict opening this encryption method only to a certain ip by substituting that ip in the "Host: oldserverIP" section. This will make your server more secure.

Solution 2:

Enable dss or rsa encryption only when a connection is needed by adding a parameter to the ssh connect statement.

Ex: 

ssh 123.123.123.123

become

ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa 123.123.123.123

Done !

Fix negotiate error for Git/Gitlab via ssh privateKey file

With git or edit the config file as follows

vi yourProjectPath/.git/config

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
sshCommand =  ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa  -oIdentitiesOnly=yes -i /yourPath/privateKeyFile.ppk -F /dev/null
...
Done ! Your Git can now connect to the server normally and it automatically uses the privateKey file to log in instead of having to enter a password.

Friday, 15 April 2022

Laravel 9 Error: Undefined constant Illuminate\Http\Request::HEADER_X_FORWARDED_ALL

Solve the error when upgrading the system to laravel 9 or 10. "Undefined constant Illuminate\Http\Request::HEADER_X_FORWARDED_ALL"

Reason: 

As of Laravel 9, the framework switched to using a built-in middleware to handle proxy queries instead of Fideloper\Proxy\TrustProxies. So when upgrading from lower versions like laravel 5.8, laravel 8 to laravel 9 we also need to edit to replace this middleware. If you don't make changes you will get an error when you run "composer update" and you won't be able to access the website

Solve the problem:

Step 1: Edit your current TrustProxies Middleware (app/Http/Middleware/TrustProxies.php)

Step 2: Update middleware according to the following example

<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array<int, string>|string|null
     */
    protected $proxies;
    /**
     * The headers that should be used to detect proxies.
     *
     * @var int
     */
    // Before...
    // protected $headers = Request::HEADER_X_FORWARDED_ALL;
    // After...
    protected $headers =
        Request::HEADER_X_FORWARDED_FOR |
        Request::HEADER_X_FORWARDED_HOST |
        Request::HEADER_X_FORWARDED_PORT |
        Request::HEADER_X_FORWARDED_PROTO |
        Request::HEADER_X_FORWARDED_AWS_ELB;
}

Step 3: Remove Fideloper TrustProxies from composer file

composer remove fideloper/proxy

Step 4: Done ! run "composer update" to complete update


Friday, 20 August 2021

[Tips] How to use Cloudflare Free SSL for Socket.io Server

Free SSL is a very interesting feature of Cloudflare. Cloudflare SSL has full support for WebSocket protocol. However, if you are using the web in conjunction with a socket.io server on the same server, you may encounter problems with the ssl port. Because the default port for ssl is always 443 but it is already used by the web server.

There are many ways to handle this problem, here I will guide you in a very simple way. That's how to configure Socket.io SSL through a proxy using Apache or Nginx.


Prepare:

NodeJs SocketIO server is listen on port 8088

Webserver (Apache or Nginx) is listen on port 80 and 443

Step 1: SocketServer config

Configure NodeJs SocketIO server to run in long polling mode without ssl on a certain port, eg port 8088.

Eg:

var app = require('express')(); //npm install express
var http = require('http').createServer(app);
var socketServer = require('socket.io')(http, { //npm install socketio
cors: {
origin: "*",
methods: ["GET", "POST"]
},
  transports: ['polling']
});
http.listen(8088, () => {
console.log('listening on port 8088');
});

Configure socket.io client to use 'polling' mode

Eg:

var socket = io('https://subdomain.yourdomain.com', { });
socket.on('connect', function () {
console.log('connected');
});

Step 2: Configure virtualhost proxy for Socket Server

Configure virtual host proxy to forward port 80 from cloudflare to the actual port of our Socket Server (I listen on port 80 because I am using Cloudflare flexible ssl, if you use Cloudflare full ssl or full strict ssl then listen on port 443 like your other virtualhost)

Apache:

<VirtualHost *:80>
    ServerAdmin admin@yourdomain.com
    ProxyPreserveHost On
    ServerName subdomain.yourdomain.com
    ProxyPass / http://127.0.0.1:8088/
    ProxyPassReverse / http://127.0.0.1:8088/
</VirtualHost>

Nginx:

server {
    listen 80;
    server_name subdomain.yourdomain.com;
    location / {
        proxy_set_header   X-Forwarded-For $remote_addr;
        proxy_set_header   Host $http_host;
        proxy_pass         http://127.0.0.1:8088;
    }
}

Done !

Remember to reload your web server 

Now your NodeJs Socket Server is working perfectly with free ssl from CLoudflare

 

Tuesday, 3 August 2021

Ubuntu - MySQL Can't set password for root account, even though all command are successful

After a fresh install of MySQL or MariaDB on an Ubuntu server, you can run the "mysql" command line without being asked for your password, even if you have successfully changed the password. While you still cannot access root account from other software like Navicat, php ... the error encountered is "Access denied for user 'root'@'localhost' (using password: YES)"

What happened ?

you can run the "mysql" command without any password because by default, the root account is configured to login via the AUTH_SOCKET plugin. So MySQL Command-Line Client can always connect successfully without being asked for a password while other software can't connect even if the correct password is entered.

Security issue?

In a way, the mysql root account should only be accessed from the server, and a person who already has root privileges with Ubuntu can obviously optionally reset the mysql root account password. So this default configuration should not be a problem.
However, if you are a strict person or are familiar with other operating systems like Centos, you will be very uncomfortable with this configuration. If so, bring it back to the same as mysql on Centos by following the steps below.

Solving problems

Access the MySQL command-line. 
mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.21-0ubuntu20.0 (Ubuntu)

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
Switch to the 'mysql' database
use mysql;
Verify current status
select Host,User,authentication_string,plugin from mysql.user;
You can see: The MySQL ROOT account has no password configured and using the authentication plugin named auth_socket.
Now configure the ROOT account to use mysql_native_password plugin
ALTER USER root@localhost IDENTIFIED WITH mysql_native_password;
Set new password for root account
ALTER USER root@localhost IDENTIFIED BY 'newpassword';
Flush privileges
FLUSH PRIVILEGES;
exit;
Done

Problem solved !

Tuesday, 29 December 2020

Gitlab Error: couldn't deduce an advertise address: no private IP found, explicit advertise addr not provided

Gitlab log view:

gitlab-ctl tail

Something error:

cluster.go:154 component=cluster err="couldn't deduce an advertise address: no private IP found, explicit advertise addr not provided"

How to fix !

edit file gitlab.rb

vi /etc/gitlab/gitlab.rb

Add the following code

alertmanager['flags'] = {

  'cluster.advertise-address' => "127.0.0.1:9093",

}

Then

gitlab-ctl reconfigure

gitlab-ctl restart

Done ! now recheck gitlab log

gitlab-ctl tail alertmanager

Check alertmanager service

netstat -tulpn | grep LISTEN

output 

tcp        0      0 127.0.0.1:9093              0.0.0.0:*                   LISTEN      30633/alertmanager


Monday, 28 December 2020

Centos 6 - Yum Error: Cannot find a valid baseurl for repo base

When using the commands "yum install/update" on Centos 6 you will get an error:

Loaded plugins: fastestmirror, replace
Setting up Update Process
Determining fastest mirrors
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
 Eg. Invalid release/repo/arch combination/
removing mirrorlist with no valid mirrors: /var/cache/yum/x86_64/6/base/mirrorlist.txt
Error: Cannot find a valid baseurl for repo: base (base/updates/contrib)

Reason: Centos 6 is out of date and is no longer officially supported.

Solution: Manual change CentOS-Base.repo

Step 1:

Open the following files one by one:

/var/cache/yum/x86_64/6/base/mirrorlist.txt
/var/cache/yum/x86_64/6/extras/mirrorlist.txt
/var/cache/yum/x86_64/6/updates/mirrorlist.txt

Add the following line at the end of the files:

https://vault.centos.org/6.10/

Step 2:

Open file "CentOS-Base.repo" and modify all blocks according to the form below 

vi /etc/yum.repos.d/Centos-Base.repo

 [base]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=http://vault.centos.org/6.10/centosplus/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
gpgcheck=1

 

#released updates
[updates]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=http://vault.centos.org/6.10/centosplus/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
gpgcheck=1

 

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=http://vault.centos.org/6.10/centosplus/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
gpgcheck=1

 

#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=http://vault.centos.org/6.10/centosplus/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
gpgcheck=1

Step 3: Done ! Solved !

Now on you can continue to use yum normally

Tuesday, 6 October 2020

Laravel: Force to use HTTPS for all routes and url (Support Cloudflare Flexible SSL)

Laravel - In some special cases but especially when you are using Cloudflare Flexible SSL. We need a solution so that all URL on our website (created by url, route function) must be https even though our server currently doesn't support ssl.

Solution:

Edit App\Providers\AppServiceProvider.php in the boot() method

public function boot()
{
       
// custom for cloudflase flexible ssl
        if($this->checkHTTPSStatus()){
            URL::forceScheme('https');
        }
/*...some other code...*/
}
private function checkHTTPSStatus()
{
/*Select code in an option below*/
}

Option 1: Switch to https according to the configuration in the env file

private function checkHTTPSStatus()
{
return env('APP_HTTPS',false) === true;
}

In .env file you must to declare APP_HTTPS parameter

APP_HTTPS=true

Option 2: Automatically switch to https if the user comes from Cloudflare Flexible SSL

private function checkHTTPSStatus()
{
return (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])&&$_SERVER['HTTP_X_FORWARDED_PROTO']==='https');
}

Option 3: Full SSL

private function checkHTTPSStatus()
{
return !empty($_SERVER['HTTPS']);
}

Solved !