diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java
index fcb2d7e6..74caf565 100644
--- a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java
+++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java
@@ -208,6 +208,33 @@ public interface PerunRegistrarTranslation extends PerunTranslation {
@DefaultMessage("Type to search...")
String typeToSearch();
+ @DefaultMessage("Key \"{0}\" does not have the correct format.")
+ String sshKeyFormat(String key);
+
+ @DefaultMessage("Do not mix commas and new-lines as SSH keys separators.")
+ String mixingNewlinesWithCommas();
+
+ @DefaultMessage("Multiple consecutive commas are not allowed, use a single comma or newline as a separator between SSH keys.")
+ String tooMuchCommas();
+
+ @DefaultMessage("Multiple consecutive commas are not allowed, use a single comma as a separator between SSH keys.")
+ String tooMuchCommasTextField();
+
+ @DefaultMessage("Multiple consecutive newlines are not allowed, use one newline or comma as a separator between SSH keys.")
+ String tooMuchNewlines();
+
+ @DefaultMessage("Missing separator between the SSH keys (comma or newline).")
+ String sshKeyMissingDelimiter();
+
+ @DefaultMessage("Missing comma as a separator between the SSH keys.")
+ String sshKeyMissingCommaDelimiterTextField();
+
+ @DefaultMessage("No spaces are allowed around the SSH key separator (comma or newline).")
+ String sshKeyNoSpaceAroundKeySeparator();
+
+ @DefaultMessage("No spaces are allowed around the SSH key separator (comma).")
+ String sshKeyNoSpaceAroundCommasTextField();
+
// -------------- SUBMITTED APPS PAGE ------------------------ //
@DefaultMessage("Submitted registrations")
diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java
index 4aa9c67e..8e7c7062 100644
--- a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java
+++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java
@@ -7,6 +7,7 @@
import cz.metacentrum.perun.wui.model.beans.ApplicationFormItemData;
import cz.metacentrum.perun.wui.registrar.widgets.PerunForm;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.PerunFormItemValidator;
+import cz.metacentrum.perun.wui.registrar.widgets.items.validators.SshKeysTextAreaValidator;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.TextAreaValidator;
import cz.metacentrum.perun.wui.widgets.boxes.ExtendedTextArea;
import org.gwtbootstrap3.client.ui.html.Paragraph;
@@ -25,7 +26,13 @@ public class TextArea extends PerunFormItemEditable {
public TextArea(PerunForm form, ApplicationFormItemData item, String lang) {
super(form, item, lang);
- this.validator = new TextAreaValidator();
+
+ if ("urn:perun:user:attribute-def:def:sshPublicKey".equals(item.getFormItem().getPerunDestinationAttribute())) {
+ this.validator = new SshKeysTextAreaValidator();
+ } else {
+ this.validator = new TextAreaValidator();
+ }
+
}
protected Widget initWidget() {
diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java
index 6cd3a09a..0a244c8c 100644
--- a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java
+++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java
@@ -7,6 +7,7 @@
import cz.metacentrum.perun.wui.model.beans.ApplicationFormItemData;
import cz.metacentrum.perun.wui.registrar.widgets.PerunForm;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.PerunFormItemValidator;
+import cz.metacentrum.perun.wui.registrar.widgets.items.validators.SshKeysTextFieldValidator;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.TextFieldValidator;
import cz.metacentrum.perun.wui.widgets.boxes.ExtendedTextBox;
import org.gwtbootstrap3.client.ui.constants.ColumnSize;
@@ -28,7 +29,11 @@ public class TextField extends PerunFormItemEditable {
public TextField(PerunForm form, ApplicationFormItemData item, String lang) {
super(form, item, lang);
- this.validator = new TextFieldValidator();
+ if ("urn:perun:user:attribute-def:def:sshPublicKey".equals(item.getFormItem().getPerunDestinationAttribute())) {
+ this.validator = new SshKeysTextFieldValidator();
+ } else {
+ this.validator = new TextFieldValidator();
+ }
}
@Override
diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextAreaValidator.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextAreaValidator.java
new file mode 100644
index 00000000..17e013de
--- /dev/null
+++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextAreaValidator.java
@@ -0,0 +1,106 @@
+package cz.metacentrum.perun.wui.registrar.widgets.items.validators;
+
+import com.google.gwt.regexp.shared.MatchResult;
+import com.google.gwt.regexp.shared.RegExp;
+import cz.metacentrum.perun.wui.registrar.widgets.items.TextArea;
+import org.gwtbootstrap3.client.ui.constants.ValidationState;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Pavel Zlámal
+ */
+public class SshKeysTextAreaValidator extends TextAreaValidator {
+
+ RegExp regExp = RegExp.compile("^(" +
+ "(ssh-(rsa|dss|ed25519)(-cert-v01@openssh.com)?)|" +
+ "(sk-(ssh-ed25519|ecdsa-sha2-nistp256)(-cert-v01)?@openssh.com)|" +
+ "(ecdsa-sha2-nistp(256|384|521)(-cert-v01@openssh.com)?))" +
+ " (([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?)( [^,\n]+)?$");
+
+ @Override
+ public boolean validateLocal(TextArea textArea) {
+
+ if (textArea.isRequired() && isNullOrEmpty(textArea.getValue())) {
+ setResult(Result.EMPTY);
+ textArea.setRawStatus(getTransl().cantBeEmpty(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (!textArea.getBox().isValid()) {
+ setResult(Result.INVALID_FORMAT);
+ textArea.setStatus(getErrorMsgOrDefault(textArea), ValidationState.ERROR);
+ return false;
+ }
+
+ if (textArea.getValue() != null && textArea.getValue().length() > textArea.MAX_LENGTH) {
+ setResult(Result.TOO_LONG);
+ textArea.setStatus(getTransl().tooLong(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (textArea.getValue() != null && !textArea.getValue().isEmpty()) {
+
+ String sshKeys = textArea.getValue();
+
+ if (sshKeys.contains(",,")) {
+ setResult(Result.INVALID_FORMAT);
+ textArea.setStatus(getTransl().tooMuchCommas(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (sshKeys.contains("\n\n")) {
+ setResult(Result.INVALID_FORMAT);
+ textArea.setStatus(getTransl().tooMuchNewlines(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (sshKeys.contains(",") && sshKeys.contains("\n")) {
+ setResult(Result.INVALID_FORMAT);
+ textArea.setStatus(getTransl().mixingNewlinesWithCommas(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (sshKeys.contains(", ") || sshKeys.contains(" ,") || sshKeys.contains("\n ") || sshKeys.contains(" \n")) {
+ setResult(Result.INVALID_FORMAT);
+ textArea.setStatus(getTransl().sshKeyNoSpaceAroundKeySeparator(), ValidationState.ERROR);
+ return false;
+ }
+
+ // FIXME - this doesn't make sense anymore, as we have multiple different SSH keys prefixes, which needs to be checked.
+ /*
+ if (sshKeys.indexOf("ssh-") != sshKeys.lastIndexOf("ssh-")) {
+ // there are at least two keys
+ if (!sshKeys.contains(",ssh-") && !sshKeys.contains("\nssh-")) {
+ setResult(Result.INVALID_FORMAT);
+ textArea.setStatus(getTransl().sshKeyMissingDelimiter(), ValidationState.ERROR);
+ return false;
+ }
+ }
+ */
+
+ // normalize value just in case
+ sshKeys = sshKeys.replaceAll("(\n)+", ",");
+ sshKeys = sshKeys.replaceAll("(,)+", ",");
+ List keys = Arrays.stream(sshKeys.split(",")).collect(Collectors.toList());
+
+ for (String key : keys) {
+ MatchResult matcher = regExp.exec(key);
+ if (matcher == null) {
+ int length = Math.min(key.length(), 30);
+ textArea.setRawStatus(getTransl().sshKeyFormat(key.substring(0, length)+((length == 30) ? "..." : "")), ValidationState.ERROR);
+ setResult(Result.INVALID_FORMAT);
+ return false;
+ }
+ }
+
+ }
+
+ textArea.setStatus(ValidationState.SUCCESS);
+ return true;
+
+ }
+
+}
diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextFieldValidator.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextFieldValidator.java
new file mode 100644
index 00000000..16a0d999
--- /dev/null
+++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextFieldValidator.java
@@ -0,0 +1,93 @@
+package cz.metacentrum.perun.wui.registrar.widgets.items.validators;
+
+import com.google.gwt.regexp.shared.MatchResult;
+import com.google.gwt.regexp.shared.RegExp;
+import cz.metacentrum.perun.wui.registrar.widgets.items.TextField;
+import org.gwtbootstrap3.client.ui.constants.ValidationState;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Pavel Zlámal
+ */
+public class SshKeysTextFieldValidator extends TextFieldValidator {
+
+ RegExp regExp = RegExp.compile("^(" +
+ "(ssh-(rsa|dss|ed25519)(-cert-v01@openssh.com)?)|" +
+ "(sk-(ssh-ed25519|ecdsa-sha2-nistp256)(-cert-v01)?@openssh.com)|" +
+ "(ecdsa-sha2-nistp(256|384|521)(-cert-v01@openssh.com)?))" +
+ " (([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?)( [^,\n]+)?$");
+
+ @Override
+ public boolean validateLocal(TextField textField) {
+
+ if (textField.isRequired() && isNullOrEmpty(textField.getValue())) {
+ setResult(Result.EMPTY);
+ textField.setRawStatus(getTransl().cantBeEmpty(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (!textField.getBox().isValid()) {
+ setResult(Result.INVALID_FORMAT);
+ textField.setStatus(getErrorMsgOrDefault(textField), ValidationState.ERROR);
+ return false;
+ }
+
+ if (textField.getValue() != null && textField.getValue().length() > textField.MAX_LENGTH) {
+ setResult(Result.TOO_LONG);
+ textField.setStatus(getTransl().tooLong(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (textField.getValue() != null && !textField.getValue().isEmpty()) {
+
+ String sshKeys = textField.getValue();
+
+ if (sshKeys.contains(",,")) {
+ setResult(Result.INVALID_FORMAT);
+ textField.setStatus(getTransl().tooMuchCommasTextField(), ValidationState.ERROR);
+ return false;
+ }
+
+ if (sshKeys.contains(", ") || sshKeys.contains(" ,")) {
+ setResult(Result.INVALID_FORMAT);
+ textField.setStatus(getTransl().sshKeyNoSpaceAroundCommasTextField(), ValidationState.ERROR);
+ return false;
+ }
+
+ // FIXME - this doesn't make sense anymore, as we have multiple different SSH keys prefixes, which needs to be checked.
+ /*
+ if (sshKeys.indexOf("ssh-") != sshKeys.lastIndexOf("ssh-")) {
+ // there are at least two keys
+ if (!sshKeys.contains(",ssh-")) {
+ setResult(Result.INVALID_FORMAT);
+ textField.setStatus(getTransl().sshKeyMissingCommaDelimiterTextField(), ValidationState.ERROR);
+ return false;
+ }
+ }
+ */
+
+ // normalize value just in case
+ sshKeys = sshKeys.replaceAll("(,)+", ",");
+ List keys = Arrays.stream(sshKeys.split(",")).collect(Collectors.toList());
+
+ for (String key : keys) {
+ MatchResult matcher = regExp.exec(key);
+ if (matcher == null) {
+ int length = Math.min(key.length(), 30);
+ textField.setRawStatus(getTransl().sshKeyFormat(key.substring(0, length)+((length == 30) ? "..." : "")), ValidationState.ERROR);
+ setResult(Result.INVALID_FORMAT);
+ return false;
+ }
+ }
+
+ }
+
+ textField.setStatus(ValidationState.SUCCESS);
+ return true;
+
+ }
+
+}
diff --git a/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties b/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties
index 2afcb75e..50fd2463 100644
--- a/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties
+++ b/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties
@@ -78,6 +78,15 @@ federation=hodnota ověřena Poskytovatelem identity
undefinedFormItem=NEDEFINOVANÝ
clearRadiobox=žádný z předchozích
typeToSearch=Hledej psaním...
+sshKeyFormat=Klíč "{0}" nemá správný formát.
+mixingNewlinesWithCommas=Nemíchejte čárky a nové řádky jako oddělovače SSH klíčů.
+tooMuchCommas=Více čárek za sebou není dovoleno, jako oddělovač mezi SSH klíči používejte jednu čárku nebo nový řádek.
+tooMuchCommasTextField=Více čárek za sebou není dovoleno, jako oddělovač mezi SSH klíči používejte jednu čárku.
+tooMuchNewlines=Více nových řádků za sebou není dovoleno, jako oddělovač mezi SSH klíči používejte jeden nový řádek nebo čárku.
+sshKeyMissingDelimiter=Mezi SSH klíči chybí oddělovač (čárka nebo nový řádek).
+sshKeyMissingCommaDelimiterTextField=Mezi SSH klíči chybí oddělovač (čárka).
+sshKeyNoSpaceAroundKeySeparator=Kolem oddělovače SSH klíčů (čárky nebo nového řádku) nejsou dovoleny mezery.
+sshKeyNoSpaceAroundCommasTextField=Kolem oddělovače SSH klíčů (čárky) nejsou dovoleny mezery.
# // -------------- SUBMITTED APPS PAGE ------------------------ //