/home/wpollock1/public_html/AJava/SafeInput.java
//package safehello;
import java.text.Normalizer;
import static java.text.Normalizer.Form.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.*;
import javafx.stage.Stage;
/**
* Main class for safe I18N coding practices, JavaFX demo.
* This code shows (in a simple JavaFX GUI) how to normalize, sanitize,
* and validate user input.
*
* @author Wayne Pollock, Tampa Florida USA
*/
public class SafeInput extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Safe I18N Coding Demo");
// Use JavaFX Grid Layout:
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(24);
grid.setPadding(new Insets(25, 25, 25, 25));
Scene scene = new Scene(grid, 350, 275);
primaryStage.setScene(scene);
// Add components to the stage, via the layout object:
Text title = new Text("Safe I18N Coding Demo");
title.setFont(Font.font("sans-serif", FontWeight.NORMAL, 20));
grid.add(title, 0, 0, 2, 1);
Label userNameLbl = new Label("User Name:");
grid.add(userNameLbl, 0, 1);
final ComboBox<String> userName = new ComboBox<>();
userName.getItems().addAll(
"",
"Joe-Bob Jr., 3rd.",
"touch" + "\u00e9", // Accent
"a" + "\ufb03" + "ance", // Ligature
"fa" + "\u00e7" + "ade", // Cedilla
"\uff81\uff6e\uff7a\uff9a\uff70\uff84", //half-width Katakana
"<em>HTML</em>", // illegal characters
"Hubert Blaine Wolfeschlegelsteinhausenbergerdorff"
);
userName.setEditable(true);
userName.setValue("");
grid.add(userName, 1, 1);
Text greeting = new Text();
greeting.setFill(Color.BLACK);
grid.add(greeting, 0, 3, 2, 1);
Button btn = new Button( "Greet");
btn.setDefaultButton(true);
grid.add(btn, 1, 2);
// Hook up event handling:
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
String name = nsv( userName.getValue().toString() );
if ( name == null || name.length() == 0 ) {
greeting.setText("<no valid name selected>");
} else {
greeting.setText("Howdy, " + name + "!");
}
}
});
// Make UI visible:
primaryStage.show();
}
/**
* nsv will Normalize Unicode, then Sanitize via a whitelist regular
* expression, and finally validate the data (starts with a letter and
* is less than 20 characters long. The resulting String
* (which may be empty) is returned. In a secure context (user name
* for login purposes), this method should throw an exception for bad
* input, which should include an encoded (safe) version to include in
* log messages.
*
* @param rawInput - The untrusted String
* @return a normalized, sanitized, and validated String
*/
public String nsv ( String rawInput ) {
// Normalize Unicode first: use NFC; for identifiers (such as
// user names for logins) and passwords, use NFKC:
if ( ! Normalizer.isNormalized(rawInput, NFC) ) {
rawInput = Normalizer.normalize(rawInput, NFC);
}
// Sanitize: Remove any illegal (not a letter, digit, dash, space,
// period, or comma) characters:
String clean = rawInput.replaceAll("[^-\\p{Alnum} .,]", "");
// Validate: Ensure userName has letters, and length is <20:
if ( clean.length() > 20) {
clean = clean.substring(0, 20);
}
if ( ! clean.matches("^\\p{Alpha}.*")) {
clean = ""; // String should start with a letter
}
return clean;
}
}