SafeInput.java
Download SafeInput.java
1: //package safehello;
2:
3: import java.text.Normalizer;
4: import static java.text.Normalizer.Form.*;
5:
6: import javafx.application.Application;
7: import javafx.event.*;
8: import javafx.geometry.*;
9: import javafx.scene.Scene;
10: import javafx.scene.control.*;
11: import javafx.scene.layout.*;
12: import javafx.scene.paint.Color;
13: import javafx.scene.text.*;
14: import javafx.stage.Stage;
15:
16: /**
17: * Main class for safe I18N coding practices, JavaFX demo.
18: * This code shows (in a simple JavaFX GUI) how to normalize, sanitize,
19: * and validate user input.
20: *
21: * @author Wayne Pollock, Tampa Florida USA
22: */
23: public class SafeInput extends Application {
24:
25: public static void main(String[] args) {
26: launch(args);
27: }
28:
29: @Override
30: public void start(Stage primaryStage) {
31: primaryStage.setTitle("Safe I18N Coding Demo");
32:
33: // Use JavaFX Grid Layout:
34: GridPane grid = new GridPane();
35: grid.setAlignment(Pos.CENTER);
36: grid.setHgap(10);
37: grid.setVgap(24);
38: grid.setPadding(new Insets(25, 25, 25, 25));
39: Scene scene = new Scene(grid, 350, 275);
40: primaryStage.setScene(scene);
41:
42: // Add components to the stage, via the layout object:
43: Text title = new Text("Safe I18N Coding Demo");
44: title.setFont(Font.font("sans-serif", FontWeight.NORMAL, 20));
45: grid.add(title, 0, 0, 2, 1);
46:
47: Label userNameLbl = new Label("User Name:");
48: grid.add(userNameLbl, 0, 1);
49:
50:
51: final ComboBox<String> userName = new ComboBox<>();
52: userName.getItems().addAll(
53: "",
54: "Joe-Bob Jr., 3rd.",
55: "touch" + "\u00e9", // Accent
56: "a" + "\ufb03" + "ance", // Ligature
57: "fa" + "\u00e7" + "ade", // Cedilla
58: "\uff81\uff6e\uff7a\uff9a\uff70\uff84", //half-width Katakana
59: "<em>HTML</em>", // illegal characters
60: "Hubert Blaine Wolfeschlegelsteinhausenbergerdorff"
61: );
62: userName.setEditable(true);
63: userName.setValue("");
64: grid.add(userName, 1, 1);
65:
66: Text greeting = new Text();
67: greeting.setFill(Color.BLACK);
68: grid.add(greeting, 0, 3, 2, 1);
69:
70: Button btn = new Button( "Greet");
71: btn.setDefaultButton(true);
72:
73: grid.add(btn, 1, 2);
74:
75: // Hook up event handling:
76: btn.setOnAction(new EventHandler<ActionEvent>() {
77: @Override
78: public void handle(ActionEvent e) {
79: String name = nsv( userName.getValue().toString() );
80: if ( name == null || name.length() == 0 ) {
81: greeting.setText("<no valid name selected>");
82: } else {
83: greeting.setText("Howdy, " + name + "!");
84: }
85: }
86: });
87:
88: // Make UI visible:
89: primaryStage.show();
90: }
91:
92: /**
93: * nsv will Normalize Unicode, then Sanitize via a whitelist regular
94: * expression, and finally validate the data (starts with a letter and
95: * is less than 20 characters long. The resulting String
96: * (which may be empty) is returned. In a secure context (user name
97: * for login purposes), this method should throw an exception for bad
98: * input, which should include an encoded (safe) version to include in
99: * log messages.
100: *
101: * @param rawInput - The untrusted String
102: * @return a normalized, sanitized, and validated String
103: */
104: public String nsv ( String rawInput ) {
105: // Normalize Unicode first: use NFC; for identifiers (such as
106: // user names for logins) and passwords, use NFKC:
107: if ( ! Normalizer.isNormalized(rawInput, NFC) ) {
108: rawInput = Normalizer.normalize(rawInput, NFC);
109: }
110:
111: // Sanitize: Remove any illegal (not a letter, digit, dash, space,
112: // period, or comma) characters:
113: String clean = rawInput.replaceAll("[^-\\p{Alnum} .,]", "");
114:
115: // Validate: Ensure userName has letters, and length is <20:
116: if ( clean.length() > 20) {
117: clean = clean.substring(0, 20);
118: }
119: if ( ! clean.matches("^\\p{Alpha}.*")) {
120: clean = ""; // String should start with a letter
121: }
122: return clean;
123: }
124: }