Sunday, February 11, 2024

Openssl s_client to verify SSL

Syntax general: openssl s_client [-connect host:port] [option]

 

Get and read openssl s_client output 

$ echo "Get HTTP/1.0" | openssl s_client google.com:443
CONNECTED(00000003)
depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1
verify return:1                        <- verification chain 2 ok
depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
verify return:1                        <- verification chain 1 ok
depth=0 CN = *.google.com
verify return:1                        <- verification chain 0 ok
---
Certificate chain
 0 s:CN = *.google.com
   i:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jan  9 06:25:08 2024 GMT; NotAfter: Apr  2 06:25:07 2024 GMT
 1 s:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
   i:C = US, O = Google Trust Services LLC, CN = GTS Root R1
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Aug 13 00:00:42 2020 GMT; NotAfter: Sep 30 00:00:42 2027 GMT
 2 s:C = US, O = Google Trust Services LLC, CN = GTS Root R1
   i:C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
   a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jun 19 00:00:42 2020 GMT; NotAfter: Jan 28 00:00:42 2028 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
... <TRUNCATED> ...
-----END CERTIFICATE-----
subject=CN = *.google.com
issuer=C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 6833 bytes and written 396 bytes
Verification: OK                    <- handshake verification ok
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

Use openssl s_client to export certificate PEM into a file (output file: certfs.pem)

$ echo "Get HTTP/1.0" | openssl s_client -showcerts -connect google.com:443 </dev/null | sed -n -e '/-.BEGIN/,/-.END/ p' > certifs.pem
depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1
verify return:1
depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
verify return:1
depth=0 CN = *.google.com
verify return:1
DONE

Get fingerprint SHA1 in byte

$ echo "Get HTTP/1.0" | openssl s_client -connect google.com:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin

Fingerprint SHA256 in byte

$ echo "Get HTTP/1.0" | openssl s_client -connect google.com:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout -in /dev/stdin

Fingerprint SHA256 in base64 encode

$ echo "Get HTTP/1.0" | openssl s_client -connect google.com:443 | \
    openssl x509 -pubkey -noout | \
    openssl rsa -pubin -outform der | \
    openssl dgst -sha256 -binary | \
    openssl enc -base64 

To get service sertificates

$ echo "Get HTTP/1.0" | openssl s_client -connect google.com.com:443 -showcerts

For Let's Encrypt, here is official information about compatibility platforms (operating system, browser and java virtual machine,  <link>

Reference:

  • https://www.openssl.org/docs/man1.0.2/man1/openssl-s_client.html
  • https://www.baeldung.com/linux/ssl-certificates


Saturday, February 10, 2024

Privacy Policy for Radio Walkman (com.dedetok.RadioWalkman)

Privacy Statement

Your privacy is important to us. This privacy statement explains what Radio Walkman (com.dedetok.RadioWalkman) application does, regarding your personal data.

Personal data we collect

Radio Walkman (com.dedetok.RadioWalkman) application does not requesting any information about your personal data.

Network & Internet Connection:

Radio Walkman (com.dedetok.RadioWalkman) application required internet connection for

  1. Get list of radio from my blogger https://dedetoknotes.blogspot.com/.
  2. Get radio stream from Radio Station Streaming server.
  3. Use to serve Google AdMob.

We do not provide any streaming services. Those streaming services are Radio Station's own and their services may change without any notice that cause this application can not get any radio streaming.

Contact Us:

If You need to contact Us, here is My email address:

dedetoke2021@gmail.com

Wednesday, February 7, 2024

Android java: Tutorial MediaPlayer and Media3 ExoPlayer

Android Studio Hedgehog | 2023.1.2

Note: For personal reference using MediaPlayer and Media3 ExoPlayer in java

build.gradle.kts (Module: app)

dependencies {
    ....
    implementation("androidx.media3:media3-exoplayer:1.2.1") // ExoPlayer
    implementation("androidx.media3:media3-common:1.2.1") // setAudioAttributes; MediaItem
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET" />
...

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MediaPlayer"
        android:id="@+id/b_mediaplayer"
        />
    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ExoPlayer"
        android:id="@+id/b_exoplayer"
        />
</androidx.appcompat.widget.LinearLayoutCompat>

MyExoPlayer.java

package com.dedetok.tutorialexoplayer;

import android.content.Context;
import android.util.Log;
import androidx.media3.common.MediaItem;
import androidx.media3.exoplayer.ExoPlaypackage com.dedetok.tutorialexoplayer;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    MyMediaPlayer myMediaPlayer;
    MyExoPlayer myExoPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myMediaPlayer = new MyMediaPlayer();
        myExoPlayer = new MyExoPlayer(this);

        String myRadioUrl = "https://stream-node1.rri.co.id/streaming/25/9025/rrijakartapro1.mp3";
        //String myRadioUrl = "http://cast1.my-control-panel.com/proxy/radioso1/stream";

        AppCompatButton bMediaPlayer = findViewById(R.id.b_mediaplayer);
        bMediaPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myExoPlayer.stop();
                myMediaPlayer.play(myRadioUrl);
            }
        });

        AppCompatButton bExoPlayer = findViewById(R.id.b_exoplayer);
        bExoPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myMediaPlayer.stop();
                myExoPlayer.play(myRadioUrl);
            }
        });
    }
}er;

public class MyExoPlayer {
    // API level 23 / Android N / Android 6.0
    ExoPlayer myPlayer;

    public MyExoPlayer(Context appContext) {
        myPlayer = new ExoPlayer.Builder(appContext).build();
    }

    public void play(String myRadioUrl) {
        if (myPlayer.isPlaying()) {
            myPlayer.stop();
            Log.e("dedetok", "ExoPlaayer playing Stop"); // debug
        } else {
            try {
                Log.e("dedetok", "ExoPlaayer playing " + myRadioUrl); // debug
                MediaItem myRadio = MediaItem.fromUri(myRadioUrl);
                myPlayer.setMediaItem(myRadio);
                myPlayer.prepare();
                myPlayer.play();
            } catch (IllegalArgumentException e) {
                Log.e("dedetok", "ExoPlayer IllegalArgumentException " + e.getMessage()); // debug
            }
        }
    }

    public void stop() {
        myPlayer.stop();
    }

    public void release() {
        myPlayer.release();
        myPlayer=null;
    }
}

MyMediaPlayer.java

package com.dedetok.tutorialexoplayer;

import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.util.Log;
import java.io.IOException;

public class MyMediaPlayer implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
    MediaPlayer myPlayer;

    boolean isPrepared= false;

    public MyMediaPlayer() {
        myPlayer = new MediaPlayer();
    }

    public void play(String myRadioUrl) {
        if (myPlayer.isPlaying()) {
            myPlayer.stop();
            myPlayer.reset();
            Log.e("dedetok", "MediaPlayer Stop"); // debug
        } else {
            Log.e("dedetok", "MediaPlayer playing " + myRadioUrl); // debug
            myPlayer.setOnPreparedListener(this);
            myPlayer.setAudioAttributes(
                    new AudioAttributes.Builder()
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setLegacyStreamType(AudioAttributes.USAGE_MEDIA)
                            .build()
            );
            myPlayer.setOnErrorListener(this);
            try {
                myPlayer.setDataSource(myRadioUrl);
                isPrepared=true;
                myPlayer.prepareAsync();
            } catch (IOException e) {
                Log.e("dedetok", "IOException " + e.getMessage()); // debug
            } catch (IllegalArgumentException e) {
                Log.e("dedetok", "IllegalArgumentException " + e.getMessage()); // debug
            }
        }
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        /*
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (mediaPlayer.getDrmInfo() != null) {
                myPlayer.prepareDrm();
                //myPlayer.getKeyRequest();
                //myPlayer.provideKeyResponse();
            }
        }

         */
        myPlayer.start();
        isPrepared=false;
    }

    public void stop() {
        if (!isPrepared) {
            myPlayer.stop();
            myPlayer.reset();
            isPrepared = false;
        } else {
            myPlayer.reset();
            isPrepared = false;
        }
    }

    @Override
    public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
        String tmp="";
        if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN)
            tmp = "MediaPlayer.MEDIA_ERROR_UNKNOWN";
        if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED)
            tmp = "MediaPlayer.MEDIA_ERROR_SERVER_DIED";
        if (extra == MediaPlayer.MEDIA_ERROR_IO)
            tmp+=" MediaPlayer.MEDIA_ERROR_IO";
        if (extra == MediaPlayer.MEDIA_ERROR_MALFORMED)
            tmp+=" MediaPlayer.MEDIA_ERROR_MALFORMED";
        if (extra == MediaPlayer.MEDIA_ERROR_UNSUPPORTED)
            tmp+=" MediaPlayer.MEDIA_ERROR_UNSUPPORTED";
        if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT)
            tmp+=" MediaPlayer.MEDIA_ERROR_TIMED_OUT";

        Log.e("dedetok", "OnErrorListener " + tmp); // debug
        myPlayer.reset();
        isPrepared=false;
        return true;
    }

    public void release() {
        myPlayer.release();
        myPlayer=null;
    }
}

MainActivity.java

package com.dedetok.tutorialexoplayer;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    MyMediaPlayer myMediaPlayer;
    MyExoPlayer myExoPlayer;
    int buildVersion=0;
    /*
     * ## activity life cycle 1 ##
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buildVersion = Build.VERSION.SDK_INT; // get android version from device

        String myRadioUrl = "https://stream-node1.rri.co.id/streaming/25/9025/rrijakartapro1.mp3";
        //String myRadioUrl = "http://cast1.my-control-panel.com/proxy/radioso1/stream";

        AppCompatButton bMediaPlayer = findViewById(R.id.b_mediaplayer);
        bMediaPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myExoPlayer.stop();
                myMediaPlayer.play(myRadioUrl);
            }
        });

        AppCompatButton bExoPlayer = findViewById(R.id.b_exoplayer);
        bExoPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myMediaPlayer.stop();
                myExoPlayer.play(myRadioUrl);
            }
        });
    }

    /*
     * ## activity life cycle 2 ##
     */
    @Override
    protected void onStart() {
        super.onStart();
        // Android N Android 7
        if (buildVersion>= Build.VERSION_CODES.N) {
            myMediaPlayer = new MyMediaPlayer();
            myExoPlayer = new MyExoPlayer(this);
        }
    }

    /*
     * ## activity life cycle 3 ##
     */
    @Override
    protected void onResume() {
        super.onResume();
        // Android N Android 7
        if (buildVersion< Build.VERSION_CODES.N) {
            myMediaPlayer = new MyMediaPlayer();
            myExoPlayer = new MyExoPlayer(this);
        }
    }

    /*
     * ## activity life cycle 4 ##
     */
    @Override
    protected void onPause() {
        if (buildVersion<Build.VERSION_CODES.N) {
            myMediaPlayer.release();
            myMediaPlayer=null;
            myExoPlayer.release();
            myExoPlayer=null;
        }
        super.onPause();
    }

    /*
     * ## activity life cycle 5 ##
     */
    @Override
    protected void onStop() {
        if (buildVersion>=Build.VERSION_CODES.N) {
            myMediaPlayer.release();
            myMediaPlayer=null;
            myExoPlayer.release();
            myExoPlayer=null;
        }
        super.onStop();
    }

    /*
     * ## activity life cycle 6 ##
     */

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

Pron using ExoPlayer:

  1. ExoPlayer can handle https media streaming for self signing sertificate but MediaPlayer can not.
  2. Handing media streaming in ExoPlayer uses less code then MediaPlayer.

Cons using ExoPlayer

  • ExoPlayer required minimum API level 23 / Android N / Android 6.0


Monday, January 29, 2024

Jsoup extracting table element

Eclipse 2023-09

Note: For personal reference using Jsoup in java

  1. create a new project
  2. under project root create folder "lib"
  3. download Jsoup binary (jar file) from https://jsoup.org/download and put in folder "lib". Use the latest one, this example use jsoup-1.17.2.jar
  4. in project properties -> Java Build Path -> Libraries -> Modulepath -> Add external JARs and add your Jsoup binary, Apply and Close

Java code to extract element in table from my blog https://dedetoknotes.blogspot.com/2024/01/my-radio-list.html

package com.dedetok;

import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Main {

    public static void main(String[] args) {
        try {
            Document doc = Jsoup.connect("https://dedetoknotes.blogspot.com/2024/01/my-radio-list.html").get();
            if (doc!=null) {
                System.out.println("Ok: "+doc.title()); //debug
                //Elements myTable = doc.getElementsByTag("table");
                Element myTable = doc.getElementById("com.dedetok.myradiolist");
                //System.out.println("size children: "+myTable.childrenSize()); //debug
                Elements myTr = myTable.select("tr");
                System.out.println("number of tr: "+myTr.size());
                //System.out.println(myTr.toString()); //debug

                // iterate row tr
                for (Element e : myTr) {
                    Elements myTd = e.select("td");
                    //System.out.println("number of td: "+myTd.size()); //debug

                    // iterate column td
                    for (Element eTd: myTd) {
                        //get icon url in image or text
                        Element myImg = eTd.select("img").first();
                        if (myImg!=null) {
                            String myIconUrl = myImg.absUrl("src");
                            System.out.print(myIconUrl+"|"+eTd.text()+" ");
                        } else {
                            System.out.print(eTd.text()+";");                           
                        }
                    }
                    System.out.println(); // add a new line
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

For Android Studio 2023.1.1 Patch 1

add build.gradle.kts (Module :app) 

dependencies {
    ...
    implementation("org.jsoup:jsoup:1.17.2") // jsoup
}

 


 

huawei echolife default user for EG & HG series

There are 3 default type/user group available in echolife EG, HG and DSL Home Gateway series, these user name and password are:

type/user group
EG Series HG V300R016C10 and earlier HG V300R017C00 and later DSL Home Gateway
user Epuser/userEp root/admin root/adminHW user/HuaweiUser
admin Epadmin/adminEp root/admin * root/adminHW * user/HuaweiUser *
telnet Eproot/adminEp root/admin * root/adminHW * user/HuaweiUser *

* not tested

if those fail try telecomadmin/admintelecom or admin/@HuaweiHgw or maybe your firmware has been customized by your privder

  1. user: for general use
  2. admin: for more setting then user e.q to change default ntp and time zone; change services
  3. telnet: for connect to router via telnet or SSH

In EG8145V5 default service to access your router are:

  1. Enable the LAN-side PC to access the device using HTTP
  2. Enable devices on the Wi-Fi side to access web pages

Important: 

  1. Change default password immediately and put in a note
  2. DO NOT OPEN ANY SERVICES for WAN

References: https://forum.huawei.com/enterprise/en/huawei-ont-login-account-and-password/thread/667238610795118592-667213871523442688