Aries' Blog

Freestyle technical blog

Trace dependency origin in maven pom

In large maven project sometime it’s hard to trace the origin of a dependency’s version (Especially with multi-level parent pom / spring-boot parent). In this case below command can help.

1. For maven version 3.2.0+

Use help:effective-pom with -Dverbose=true flag

mvn help:effective-pom -Dverbose=true

Sample output

<project>
...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>  <!-- org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE, line 208 -->
        <artifactId>spring-boot</artifactId>  <!-- org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE, line 209 -->
        <version>2.0.5.RELEASE</version>  <!-- org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE, line 210 -->
      </dependency>
      ...
    </dependencies>
  </dependencyManagement>
</project>

Debug spring-boot app with IntelliJ IDEA community

In intelliJ IDEA, if you debug a spring boot app by right-clicking the “main” class (e.g. Application.java) and select “Debug”, ClassNotFoundException may happen.

As suggested on stackoverflow, we should use maven goal spring-boot:run to debug spring boot app.

Also we should disable maven “forkmode”, otherwise breakpoint won’t work (I think we could use remote debugging with forkmode but haven’t tried).

Setup maven debug with “spring-boot:run” goal

  1. In IntelliJ menu, select Run -> Edit Configurations
  2. Click the “+” sign to Add New Configuration, select Maven in the dropdown
  3. Use spring-boot:run -Dfork=false as the Command line
  4. Click OK to save the configuration and debug as usual

JQuery UI 1.12 Datepicker wrong position issue (and fix)

jQuery UI 1.12 has a Datepicker component, which renders under the text input box.

In some scenario, when the page is scrolled down, the Datepicker will appear in wrong position. It’s due to the scroll distance not catered.

Fortunately, the Datepicker has a beforeShow properties which accept a function to modify the Datepicker’s height. So we can fix the issue as below

1. Create function to fix the position

function setDatepickerPos(input, inst) {
        var rect = input.getBoundingClientRect();
        // use 'setTimeout' to prevent effect overridden by other scripts
        setTimeout(function () {
            var scrollTop = $("body").scrollTop();
    	    inst.dpDiv.css({ top: rect.top + input.offsetHeight + scrollTop });
        }, 0);
    }

2. Add the function to ‘beforeShow’ properties of Datepicker

$('#MyDatepicker').datepicker({
	dateFormat: "yy-mm-dd",
	changeMonth: true,
	changeYear: true,
	defaultDate: +0,
	inline: true,
	beforeShow: function (input, inst) { setDatepickerPos(input, inst) },
});

Install Docker on Ubuntu

There are 2 ways to install Docker engine on Ubuntu, one is easy but the version not as updated. The other one is more complex but is the official way in docker.com

1. Easy Way (For older docker version)

Note the docker.io package name

sudo apt-get install docker.io

2. Hard Way (For latest docker version)

Follow this guide.

  1. Uninstall old versions
    sudo apt-get remove docker docker-engine docker.io containerd runc
  2. Setup apt-repository for docker
  3. Install Docker engine
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io
  4. Verify that Docker engine is installed correctly
    sudo docker run hello-world

Bonus – Install docker-compose

Follow this docker-compose guide.

  1. Download current stable release of Docker Compose
    sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  2. Apply executable permissions to the binary
    sudo chmod +x /usr/local/bin/docker-compose
  3. Test installation
    docker-compose --version

Quickly build a Hyperledger Fabric network

Introduction for using Hyperledger Fabric Samples

1. Install Pre-requisites

  • cURL –  latest version
  • Docker –  version 17.06.2-ce or greater
  • Docker Compose –  version 1.14.0 or greater
  • Golang  – version 1.11.x
  • Nodejs –  version 8.x (other versions are not in support yet)
  • NPM – version 5.x
  • Python 2.7

2. Install Hyperledger Fabric Samples (TL;DR)

  1. Download Samples, Binaries and Docker Images
    curl -sSL http://bit.ly/2ysbOFE | bash -s

    To download for specific version, add <fabric_version> <fabric-ca_version> <thirdparty_version> parameters

    curl -sSL http://bit.ly/2ysbOFE | bash -s -- 1.4.1 1.4.1 0.4.15
  2. Go to “fabric-samples/first-network”
    cd fabric-samples/first-network
  3. Start the network
    ./byfn.sh up
  4. After test, bring down the network
    ./byfn.sh down

3. Breakdown of Steps to build Hyperledger Fabric Network

  1. Download HLF Binaries and Docker images
  2. Configure configtx.yaml & crypto-config.yaml file
  3. Generate certs
  4. Generate genesis block
  5. Generate Channel creation file channel.tx
  6. Generate Anchor Peer update file
  7. Bring up the network, by creating the HLF docker containers from images, can use docker-compose or kubernetes
  8. Create channel by Channel creation file
  9. Have all peers join the channel
  10. Update anchor peers by Anchor Peer update file
  11. Install chaincode on endorsing peer
  12. Instantiate chaincode

Handle concurrent login in web app

In many web applications, there are requirements to limit concurrent login of a single account.

We assume these scenario are considered as “concurrent login”:

  • Login from 2 different devices (e.g. 1 PC & 1 mobile phone)
  • Login from 2 different browsers
  • Login from browser private mode and normal mode

Multi-tab is not considered as “concurrent login”

There are 2 approach to tackle this problem, we can either

  • Kick the 1st login when new login detected, or
  • Block the 2nd login attempt when someone is already logged in

1. Kick 1st login

New login kicked previous login, there are several benefits of this approach

  • No need to consider logout action, nowadays many users don’t bother logging out from web app when they close browser. This approach works in this case
  • No need to detect session close event, detecting tab / browser close event on client-side is difficult if not impossible. Behavior of onbeforeunload(), onunload(), Navigator.sendBeacon() is different even in major browsers
  • Best cross browser/device compatibility, the only client-side technology involved is Session Cookie (or a means to store the LoginID on client)
  • Easy to implement, no polling on client-side / daemon task on server, just simple request / response call.

Basically there are 2 parts:

  1. On Login a LoginID is generated and stored in a shared Dictionary (e.g. DB) as UserID / LoginID key-value pair, then the LoginID is encrypted and store in Session Cookie. Encryption prevent LoginID from maliciously modified on client-side
  2. On each request the LoginID is retrieved and decrypted from Cookie, then compared against Dictionary value (for that UserID). If the values match then proceed the request, if not it means the request is from previous login session that is already invalidated.

One security concern is Session Hijacking, SSL + secure flag on Cookie could prevent hacker from accessing the Cookie by network sniffing.

 

2. Block 2nd login

Block new login attempts after first login.

The key is to determine when the first login session ended:

  1. User logout action
  2. User close tab / browser
  3. Crash of tab / browser

Point 1 is easy but 2 & 3 are tricky, we can detect tab close by onbeforeunload(), onunload() but browser close is hard to detect. Also, sending request to server in onbeforeunload(), onunload() can only be done by Navigator.sendBeacon() that not all browsers support.

For browser crash, there is no ways to detect by JavaScript.

Another approach is to send Heartbeat messages to server, and logout the user once Heartbeat expired. This approach should work in most circumstances, but note should be taken in multi-tab scenario to avoid sending too many Heartbeat requests to server.

Prevent “Enter” button to submit form

When we have more than 1 submit button in a HTML form, we may want to disable the “Enter” button from triggering the default submit button. Below shows 2 ways to do it:

1. Using JavaScript

Detect “Enter” key on “Text” & “Password” input. This approach works on all major browsers (including I.E. 11)

Add below jQuery event handler in every page (put it in a global js file)

$("form.noEnterKeySubmit").find("input[type='text'], input[type='password']")
        .on('keyup keypress', function (e) {
            if (e.keyCode == 13) {
                e.preventDefault();
                return false;
            }
        });

Then mark the form with class noEnterKeySubmit

<form action="myAction" class="noEnterKeySubmit" method="post">
...

2. Using “disabled” submit button

As per HTML5 spec, the default button is the first submit button in a form. So we can effectively prevent “Enter” key form submitting by putting a disabled & hidden submit button as the first button in the form.

The advantage is no JavaScript needed, but the downside is this does not work on I.E. & Safari

<form action="...">
  <!-- Prevent implicit submission of the form -->
  <button type="submit" disabled style="display: none" aria-hidden="true"></button>

  <!-- ... -->

  <button type="submit">Submit</button>
</form>