Search This Blog

Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Java: check if a String contains only ASCII

import java.nio.charset.Charset;

public boolean isAscii(String v) {
    Charset.forName("US-ASCII").newEncoder().canEncode(v);
}

Java: remove unsafe html tags


public class HtmlTagRemover {
    public static String removeUnsafeTags(String html) {
        // Define the regular expression pattern to match unsafe tags
        String unsafeTagsPattern = "<(script|iframe|object|embed)[^>]*>.*?</\\1>";

        // Remove the unsafe tags from the HTML string
        String safeHtml = html.replaceAll(unsafeTagsPattern, "");

        return safeHtml;
    }

    public static void main(String[] args) {
        String html = "<b>Safe HTML</b><script>alert('XSS')</script>";
        String safeHtml = removeUnsafeTags(html);
        System.out.println(safeHtml);
    }
}

Set Groovy Development Environment

I. Install required SDK and IDE

  1. Install Java SDK 8+
  2. Install Gradle
  3. Install Groovy
  4. Install Intellij Idea



II. Create a new Groovy project using Gradle

  1. Create a new project directory:
    mkdir my-groovy-app
  2. Get into the project directory
    cd my-groovy-app
    and run gradle:
    gradle init
    Select type of project to generate:
      1: basic
      2: application
      3: library
      4: Gradle plugin
    Enter selection (default: basic) [1..4] 1
    
    Select build script DSL:
      1: Groovy
      2: Kotlin
    Enter selection (default: Groovy) [1..2] 1
    
    Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
    Project name (default: my-groovy-app):
    
    > Task :init
    Get more help with your project: Learn more about Gradle by exploring our samples at https://docs.gradle.org/7.6/samples
    
    BUILD SUCCESSFUL in 22s
    2 actionable tasks: 2 executed
        
  3. Edit build.gradle file and add the content (like below):
    plugins {
        id 'groovy'
        id 'application'
    }
    
    group 'myapps'
    version '1.0-SNAPSHOT'
    
    repositories {
        mavenCentral()
        maven {
            url 'https://my.org/mvn-repo'
        }
    }
    
    dependencies {
        implementation 'org.apache.groovy:groovy:4.0.7'
        implementation 'org.apache.ivy:ivy:2.5.0'
    
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    }
    
    application {
    	mainClass = 'my.App'
    }
    
    test {
        useJUnitPlatform()
    }
        
  4. Create source folder structure:
    mkdir src/main/groovy
    mkdir src/main/java
    mkdir src/main/resources
    mkdir src/test/groovy
    mkdir src/test/java
    mkdir src/test/resources
        
  5. Optional: create gradle.properties file at the project root, and add the options below:
    org.gradle.warning.mode=all
    org.gradle.logging.stacktrace=full
  6. Create Application class: my.App.groovy:
    package my
    
    class App {
        static void main(String[] args) {
        	println 'Hello, Wolrd'
        }
    }
      
  7. Start Intellij Idea, open the project directory. Select src/main/groovy directory, Mark directory as -> Sources root

Setup GraalVM and Native Image on Windows 10

  1. Download GraalVM and install it (Instructions)
  2. Install Native Image:
    gu install native-image
  3. Install Build Tools for Visual Studio 20XX
    • Execute the installer and select the components like below:
  4. Start using native-image
    • On Windows, the native-image builder will only work when it’s executed from the x64 Native Tools Command Prompt. You can find it in Start Menu or folder: "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"



See also

Install Eclipse Color Theme plugin

The update site https://eclipse-color-theme.github.com/update/ from Marketplace does NOT work.

Use the site url below:
https://eclipse-color-theme.github.io/update/

Manually add a new site: https://eclipse-color-theme.github.io/update/ and install.

javax.net.ssl.SSLHandshakeException: Insufficient buffer remaining for AEAD cipher fragment (2). Needs to be more than tag size (16)

javax.net.ssl.SSLHandshakeException: Insufficient buffer remaining for AEAD cipher fragment (2). Needs to be more than tag size (16)
        at sun.security.ssl.Alert.createSSLException(Alert.java:131)
        at sun.security.ssl.TransportContext.fatal(TransportContext.java:324)
        at sun.security.ssl.TransportContext.fatal(TransportContext.java:267)
        at sun.security.ssl.TransportContext.fatal(TransportContext.java:262)
        at sun.security.ssl.SSLTransport.decode(SSLTransport.java:130)
        at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1397)
        at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1305)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:440)
        at sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:818)
        at sun.security.ssl.SSLSocketImpl.access$200(SSLSocketImpl.java:73)
        at sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:909)
        at arc.dqV.a(SourceFile:80)
        at arc.dqV.read(SourceFile:56)
        at arc.ud.a(SourceFile:187)
        at arc.ud.a(SourceFile:256)
        at arc.mf.modules.dicom.DicomNetworkService.readNextMessage(SourceFile:250)
        at arc.cQg.run(SourceFile:303)
        at arc.cQh.doExecute(SourceFile:497)
        at arc.utils.Task.a(SourceFile:990)
        at arc.utils.Task.run(SourceFile:939)
        at arc.dFf.a(SourceFile:530)
        at arc.dFf.run(SourceFile:478)
        at arc.dFe.run(SourceFile:321)
Caused by: javax.crypto.BadPaddingException: Insufficient buffer remaining for AEAD cipher fragment (2). Needs to be more than tag size (16)
        at sun.security.ssl.SSLCipher$T13GcmReadCipherGenerator$GcmReadCipher.decrypt(SSLCipher.java:1845)
        at sun.security.ssl.SSLSocketInputRecord.decodeInputRecord(SSLSocketInputRecord.java:262)
        at sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:190)
        at sun.security.ssl.SSLTransport.decode(SSLTransport.java:109)
        ... 18 more

Cause:
javax.crypto.BadPaddingException: Insufficient buffer remaining for AEAD cipher fragment (2). Needs to be more than tag size (16):
Stack:
javax.crypto.BadPaddingException: Insufficient buffer remaining for AEAD cipher fragment (2). Needs to be more than tag size (16)
        at sun.security.ssl.SSLCipher$T13GcmReadCipherGenerator$GcmReadCipher.decrypt(SSLCipher.java:1845)
        at sun.security.ssl.SSLSocketInputRecord.decodeInputRecord(SSLSocketInputRecord.java:262)
        at sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:190)
        at sun.security.ssl.SSLTransport.decode(SSLTransport.java:109)
        at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1397)
        at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1305)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:440)
        at sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:818)
        at sun.security.ssl.SSLSocketImpl.access$200(SSLSocketImpl.java:73)
        at sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:909)
        at arc.dqV.a(SourceFile:80)
        at arc.dqV.read(SourceFile:56)
        at arc.ud.a(SourceFile:187)
        at arc.ud.a(SourceFile:256)
        at arc.mf.modules.dicom.DicomNetworkService.readNextMessage(SourceFile:250)
        at arc.cQg.run(SourceFile:303)
        at arc.cQh.doExecute(SourceFile:497)
        at arc.utils.Task.a(SourceFile:990)
        at arc.utils.Task.run(SourceFile:939)
        at arc.dFf.a(SourceFile:530)
        at arc.dFf.run(SourceFile:478)
        at arc.dFe.run(SourceFile:321)



Cause

This is known Oracle issue. For details, visit the following links:


Solution

There are two solutions for this issue:
  • Add -DUseSunHttpHandler=true in the startup arguments.
  • Identify on which cipher the handshake was negoitiated by enabling the JSSE debug and disable that cipher in the jre/lib/security/java.security file.



see also

Secure Java SSL by updating jdk.tls.disabledAlgorithms in java.security file

Disable SSL/TLS Diffie-Hellman keys less that 2048 bits

    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, \
    TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, \
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,    \
    TLS_DHE_DSS_WITH_AES_256_CBC_SHA,    \
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, \
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, \
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,    \
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA,    \
    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, \
    TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, \
    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, \
    TLS_DHE_DSS_WITH_AES_128_GCM_SHA256



Disable following algorithms to enforce Perfect Forward Secrecy

    TLS_RSA_WITH_AES_128_CBC_SHA256, \
    TLS_RSA_WITH_AES_128_CBC_SHA, \
    TLS_RSA_WITH_AES_128_GCM_SHA256, \
    TLS_RSA_WITH_AES_256_CBC_SHA256, \
    TLS_RSA_WITH_AES_256_CBC_SHA, \
    TLS_RSA_WITH_AES_256_GCM_SHA384, \
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, \
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, \
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA, \
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA



jdk.tls.disabledAlgorithms in jre/lib/security/java.security

jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
    DH keySize < 2048, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
    include jdk.disabled.namedCurves \
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA, \
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, \
    TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, \
    TLS_DHE_DSS_WITH_AES_256_CBC_SHA, \
    TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, \
    TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, \
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA, \
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA, \
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, \
    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, \
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA, \
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA, \
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, \
    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, \
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, \
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, \
    TLS_RSA_WITH_AES_128_CBC_SHA, \
    TLS_RSA_WITH_AES_128_CBC_SHA256, \
    TLS_RSA_WITH_AES_128_GCM_SHA256, \
    TLS_RSA_WITH_AES_256_CBC_SHA, \
    TLS_RSA_WITH_AES_256_CBC_SHA256, \
    TLS_RSA_WITH_AES_256_GCM_SHA384



see also

Java util logging: configure root logger

    Logger rootLogger = Logger.getLogger("");
    Handler[] handlers = rootLogger.getHandlers();
    for (Handler h : handlers) {
        h.setLevel(level);
    }
    rootLogger.setLevel(level);

Java: check if directory is empty

public boolean isEmpty(Path path) throws IOException {
    if (Files.isDirectory(path)) {
        try (Stream<Path> entries = Files.list(path)) {
            return !entries.findFirst().isPresent();
        }
    }
        
    return false;
}

Enable DNS cache for Java applications

To enable DNS cache, there are two options:
  • Enable Java in-memory DNS cache by setting JVM security property: networkaddress.cache.ttl to a positive integer (of seconds).
  • Enable operating system's DNS cache (and no change to Java security property. networkaddress.cache.ttl=-1 by default).

See also:

Java FileInputStream: Seek to offset using file channel

File f = File.createTempFile("aaa", null);

byte[] out = new byte[]{0, 1, 2};

FileOutputStream o = new FileOutputStream(f);
o.write(out);
o.close();

FileInputStream i = new FileInputStream(f);
i.getChannel().position(1);
assert i.read() == out[1];
i.close();
f.delete();

Count lines of Java source code

find . -type f -name "*.java" | xargs cat | grep [alnum{}] | wc -l
or shell script could be:
#!/bin/bash

[[ -z $1 ]] && dir=. || dir=$1

find $dir -type f -name "*.java" | xargs cat | grep [alnum{}] | wc -l

log4j2: conditional appender using routes

<?xml version="1.0"?>
<Configuration status="INFO">
  <Appenders>
    <Console name="SYS_OUT" target="SYSTEM_OUT" />
    <Console name="SYS_ERR" target="SYSTEM_ERR" />

    <Routing name="Router">
      <Routes pattern="$${env:STREAM_TO:-OUT}">
        <Route ref="SYS_OUT" key="OUT" />
        <Route ref="SYS_ERR" key="ERR" />
      </Routes>
    </Routing>
  </Appenders>

  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="Router" />
    </Root>
  </Loggers>
</Configuration>

see also

Maven: conditionally execute plugins using profiles

<project>
<properties>...</properties>
<repositories>...</repositories>
<dependencies>...</dependencies>
<build>
  <plugins>...</plugins>
</build>
<profiles>
  <profile>
    <id>windows</id>
    <activation>
      <os>
        <name>Windows XP</name>
        <family>Windows</family>
        <arch>x86</arch>
        <version>5.1.2600</version>
      </os>
    </activation>
    <properties>...</properties>
    <repositories>...</repositories>
    <dependencies>...</dependencies>
    <build>
      <plugins>...</plugins>
    </build>
  </profile>
</profiles>
</project>
To activate the profile manually:
mvn package -p PROFILE_ID





see also

Java: try with AutoCloseable resources

1. Multiple AutoCloseable resources

  try (InputStream in = getInputStream(); OutputStream out = getOutputStream()) {
      ... ...
  }
  
The resources are closed in the reverse order of declaration.


2. Resource leaking caused by nested constructors

There is possible resource leaking issue for the code below:
  try(InputStream in = new MyFilterInputStream(new BufferedInputStream(new FileInputStream("/tmp/test.file")))) {
      ... ...
  }
  
Because any checked exception from the chain of the constructors can cause resource failing to close. The code below with multiple declared AutoCloseables should be used:
  try(FileInputStream fis = new FileInputStream("/tmp/test.file");
      BufferedInputStream bis = new BufferedInputStream(fis);
      MyFilterInputStream mfis = new MyFilterInputStream(bis)) {
      ... ...
  }
  



3. What will happen if the AutoCloseable is null

A resource is closed only if it initialized to a non-null value. So the code works without having to worry about NPE when in is null.
  try(InputStream in = createNew==true? createInputStream(): null) {
      if(in==null) {
          ... ...
      }
  }
  




see also

Build Java runtime from OpenJDK using jlink

MODULES=$(java --list-modules | sed 's/\@.*//' | paste -sd "," -)
jlink --no-header-files --no-man-pages --compress=2 --add-modules $MODULES --output java-runtime

Modularise legacy jar

  • Run "jdeps --generate-module-info" on the legacy jar to generate module-info.java file.
    jdeps --module-path $ROOT_DIR/modules \
          --add-modules jackson.annotations,jackson.core \
          --generate-module-info ~/work $JACKSON_DATABIND_JAR
    
  • Unjar the legacy jar, add module-info.java from above, re-compile and re-jar:
    javac --module-path $ROOT_DIR/modules \
          --add-modules jackson.annotations,jackson.core \
          -d $ROOT_DIR/classes module-info.java
    





see also