From 68c780f2e746eedb714ff6e17c6815fbffddeff6 Mon Sep 17 00:00:00 2001
From: Guillaume Nodet <gnodet@gmail.com>
Date: Fri, 17 Jul 2020 11:33:21 +0200
Subject: [PATCH 1/1] [SSHD-1035] Move property definitions tocommon locations

---
 .../java/org/apache/sshd/common/Property.java | 408 +++++++++++
 .../sshd/core/CoreModuleProperties.java       | 681 ++++++++++++++++++
 2 files changed, 1089 insertions(+)
 create mode 100644 sshd-common/src/main/java/org/apache/sshd/common/Property.java
 create mode 100644 sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java

diff --git a/sshd-common/src/main/java/org/apache/sshd/common/Property.java b/sshd-common/src/main/java/org/apache/sshd/common/Property.java
new file mode 100644
index 0000000..f5ad335
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/Property.java
@@ -0,0 +1,408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common;
+
+import java.nio.charset.Charset;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * Property definition.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Property<T> {
+
+    static Property<String> string(String name) {
+        return new StringProperty(name);
+    }
+
+    static Property<String> string(String name, String def) {
+        return new StringProperty(name, def);
+    }
+
+    static Property<Boolean> bool(String name) {
+        return new BooleanProperty(name);
+    }
+
+    static Property<Boolean> bool(String name, boolean def) {
+        return new BooleanProperty(name, def);
+    }
+
+    static Property<Integer> integer(String name) {
+        return new IntProperty(name);
+    }
+
+    static Property<Integer> integer(String name, int def) {
+        return new IntProperty(name, def);
+    }
+
+    // CHECKSTYLE:OFF
+    static Property<Long> long_(String name) {
+        return new LongProperty(name);
+    }
+
+    static Property<Long> long_(String name, long def) {
+        return new LongProperty(name, def);
+    }
+
+    static <T extends Enum<T>> Property<T> enum_(String name, Class<T> type) {
+        return new EnumProperty<>(name, type);
+    }
+
+    static <T extends Enum<T>> Property<T> enum_(String name, Class<T> type, T def) {
+        return new EnumProperty<>(name, type, def);
+    }
+    // CHECKSTYLE:ON
+
+    static Property<Duration> duration(String name) {
+        return new DurationProperty(name);
+    }
+
+    static Property<Duration> duration(String name, Duration def) {
+        return new DurationProperty(name, def);
+    }
+
+    static Property<Duration> durationSec(String name) {
+        return new DurationInSecondsProperty(name);
+    }
+
+    static Property<Duration> durationSec(String name, Duration def) {
+        return new DurationInSecondsProperty(name, def);
+    }
+
+    static Property<Charset> charset(String name) {
+        return new CharsetProperty(name);
+    }
+
+    static Property<Charset> charset(String name, Charset def) {
+        return new CharsetProperty(name, def);
+    }
+
+    static Property<Object> object(String name) {
+        return new ObjectProperty(name);
+    }
+
+    static Property<Object> object(String name, Object def) {
+        return new ObjectProperty(name, def);
+    }
+
+    static <T> Property<T> validating(Property<T> prop, Consumer<T> validator) {
+        return new Validating<>(prop, validator);
+    }
+
+    abstract class BaseProperty<T> implements Property<T> {
+
+        private final String name;
+        private final T defaultValue;
+
+        public BaseProperty(String name) {
+            this(name, null);
+        }
+
+        public BaseProperty(String name, T defaultValue) {
+            this.name = Objects.requireNonNull(name, "No name provided");
+            this.defaultValue = defaultValue;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Optional<T> getDefault() {
+            return Optional.ofNullable(defaultValue);
+        }
+
+        @Override
+        public T getRequiredDefault() {
+            return getDefault().get();
+        }
+
+        @Override
+        public Optional<T> get(PropertyResolver resolver) {
+            Object propValue = PropertyResolverUtils.resolvePropertyValue(resolver, name);
+            return propValue != null ? Optional.of(fromStorage(propValue)) : getDefault();
+        }
+
+        @Override
+        public T getRequired(PropertyResolver resolver) {
+            return get(resolver).get();
+        }
+
+        @Override
+        public T getOrNull(PropertyResolver resolver) {
+            return get(resolver).orElse(null);
+        }
+
+        @Override
+        public void set(PropertyResolver resolver, T value) {
+            PropertyResolverUtils.updateProperty(resolver, name, toStorage(value));
+        }
+
+        @Override
+        public void remove(PropertyResolver resolver) {
+            PropertyResolverUtils.updateProperty(resolver, name, null);
+        }
+
+        protected Object toStorage(T value) {
+            return value;
+        }
+
+        protected abstract T fromStorage(Object value);
+
+        @Override
+        public String toString() {
+            return "Property[" + name + "]";
+        }
+    }
+
+    class DurationProperty extends BaseProperty<Duration> {
+
+        public DurationProperty(String name) {
+            super(name);
+        }
+
+        public DurationProperty(String name, Duration def) {
+            super(name, def);
+        }
+
+        @Override
+        protected Object toStorage(Duration value) {
+            return value != null ? value.toMillis() : null;
+        }
+
+        @Override
+        protected Duration fromStorage(Object value) {
+            Long val = PropertyResolverUtils.toLong(value);
+            return val != null ? Duration.ofMillis(val) : null;
+        }
+    }
+
+    class DurationInSecondsProperty extends DurationProperty {
+        public DurationInSecondsProperty(String name) {
+            super(name);
+        }
+
+        public DurationInSecondsProperty(String name, Duration def) {
+            super(name, def);
+        }
+
+        @Override
+        protected Object toStorage(Duration value) {
+            return value != null ? value.toMillis() / 1_000 : null;
+        }
+
+        @Override
+        protected Duration fromStorage(Object value) {
+            Long val = PropertyResolverUtils.toLong(value);
+            return val != null ? Duration.ofSeconds(val) : null;
+        }
+    }
+
+    class StringProperty extends BaseProperty<String> {
+
+        public StringProperty(String name) {
+            super(name);
+        }
+
+        public StringProperty(String name, String def) {
+            super(name, def);
+        }
+
+        @Override
+        protected String fromStorage(Object value) {
+            return value != null ? value.toString() : null;
+        }
+    }
+
+    class BooleanProperty extends BaseProperty<Boolean> {
+
+        public BooleanProperty(String name) {
+            super(name);
+        }
+
+        public BooleanProperty(String name, Boolean defaultValue) {
+            super(name, defaultValue);
+        }
+
+        @Override
+        protected Boolean fromStorage(Object value) {
+            return PropertyResolverUtils.toBoolean(value);
+        }
+
+    }
+
+    class LongProperty extends BaseProperty<Long> {
+
+        public LongProperty(String name) {
+            super(name);
+        }
+
+        public LongProperty(String name, Long defaultValue) {
+            super(name, defaultValue);
+        }
+
+        @Override
+        protected Long fromStorage(Object value) {
+            return PropertyResolverUtils.toLong(value);
+        }
+    }
+
+    class IntProperty extends BaseProperty<Integer> {
+
+        public IntProperty(String name) {
+            super(name);
+        }
+
+        public IntProperty(String name, Integer defaultValue) {
+            super(name, defaultValue);
+        }
+
+        @Override
+        protected Integer fromStorage(Object value) {
+            return PropertyResolverUtils.toInteger(value);
+        }
+    }
+
+    class CharsetProperty extends BaseProperty<Charset> {
+
+        public CharsetProperty(String name) {
+            super(name);
+        }
+
+        public CharsetProperty(String name, Charset defaultValue) {
+            super(name, defaultValue);
+        }
+
+        @Override
+        protected Charset fromStorage(Object value) {
+            return PropertyResolverUtils.toCharset(value);
+        }
+    }
+
+    class ObjectProperty extends BaseProperty<Object> {
+
+        public ObjectProperty(String name) {
+            super(name);
+        }
+
+        public ObjectProperty(String name, Object defaultValue) {
+            super(name, defaultValue);
+        }
+
+        @Override
+        protected Object fromStorage(Object value) {
+            return value;
+        }
+    }
+
+    class EnumProperty<T extends Enum<T>> extends BaseProperty<T> {
+
+        private final Class<T> type;
+
+        public EnumProperty(String name, Class<T> type) {
+            super(name);
+            this.type = Objects.requireNonNull(type, "type is required");
+        }
+
+        public EnumProperty(String name, Class<T> type, T def) {
+            super(name, def);
+            this.type = Objects.requireNonNull(type, "type is required");
+        }
+
+        @Override
+        protected T fromStorage(Object value) {
+            return PropertyResolverUtils.toEnum(type, value, false, Arrays.asList(type.getEnumConstants()));
+        }
+    }
+
+    class Validating<T> implements Property<T> {
+        private final Property<T> delegate;
+        private final Consumer<T> validator;
+
+        public Validating(Property<T> delegate, Consumer<T> validator) {
+            this.delegate = delegate;
+            this.validator = validator;
+        }
+
+        @Override
+        public String getName() {
+            return delegate.getName();
+        }
+
+        @Override
+        public Optional<T> getDefault() {
+            return delegate.getDefault();
+        }
+
+        @Override
+        public T getRequiredDefault() {
+            return delegate.getRequiredDefault();
+        }
+
+        @Override
+        public Optional<T> get(PropertyResolver resolver) {
+            Optional<T> t = delegate.get(resolver);
+            t.ifPresent(validator);
+            return t;
+        }
+
+        @Override
+        public T getRequired(PropertyResolver resolver) {
+            return get(resolver).get();
+        }
+
+        @Override
+        public T getOrNull(PropertyResolver resolver) {
+            return get(resolver).orElse(null);
+        }
+
+        @Override
+        public void set(PropertyResolver resolver, T value) {
+            validator.accept(value);
+            delegate.set(resolver, value);
+        }
+
+        @Override
+        public void remove(PropertyResolver resolver) {
+            delegate.remove(resolver);
+        }
+    }
+
+    String getName();
+
+    Optional<T> getDefault();
+
+    T getRequiredDefault();
+
+    Optional<T> get(PropertyResolver resolver);
+
+    T getRequired(PropertyResolver resolver);
+
+    T getOrNull(PropertyResolver resolver);
+
+    void set(PropertyResolver resolver, T value);
+
+    void remove(PropertyResolver resolver);
+}
diff --git a/sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java b/sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java
new file mode 100644
index 0000000..9e9b2d2
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java
@@ -0,0 +1,681 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.core;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.time.Duration;
+
+import org.apache.sshd.client.config.keys.ClientIdentityLoader;
+import org.apache.sshd.common.Property;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.server.auth.WelcomeBannerPhase;
+import org.apache.sshd.server.channel.ChannelDataReceiver;
+
+/**
+ * Configurable properties for sshd-core.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class CoreModuleProperties {
+
+    /**
+     * Value that can be set in order to control the type of authentication channel being requested when forwarding a
+     * PTY session.
+     */
+    public static final Property<String> PROXY_AUTH_CHANNEL_TYPE
+            = Property.string("ssh-agent-factory-proxy-auth-channel-type", "auth-agent-req@openssh.com");
+
+    /**
+     * See {@link org.apache.sshd.agent.local.ProxyAgentFactory#getChannelForwardingFactories}
+     */
+    public static final Property<Boolean> PREFER_UNIX_AGENT
+            = Property.bool("ssh-prefer-unix-agent", OsUtils.isUNIX());
+
+    /**
+     * Value that can be set on the {@link org.apache.sshd.common.FactoryManager} or the session to configure the
+     * channel open timeout value (millis).
+     */
+    public static final Property<Duration> CHANNEL_OPEN_TIMEOUT
+            = Property.duration("ssh-agent-server-channel-open-timeout", Duration.ofSeconds(30));
+
+    /**
+     * Value used to configure the type of proxy forwarding channel to be used. See also
+     * https://tools.ietf.org/html/draft-ietf-secsh-agent-02
+     */
+    public static final Property<String> PROXY_CHANNEL_TYPE
+            = Property.string("ssh-agent-server-channel-proxy-type", "auth-agent@openssh.com");
+
+    /**
+     * Property that can be set on the {@link Session} in order to control the authentication timeout (millis).
+     */
+    public static final Property<Duration> AUTH_SOCKET_TIMEOUT
+            = Property.duration("ssh-agent-server-proxy-auth-socket-timeout", Duration.ofHours(1));
+
+    public static final int DEFAULT_FORWARDER_BUF_SIZE = 1024;
+    public static final int MIN_FORWARDER_BUF_SIZE = 127;
+    public static final int MAX_FORWARDER_BUF_SIZE = 32767;
+
+    /**
+     * Property that can be set on the factory manager in order to control the buffer size used to forward data from the
+     * established channel
+     *
+     * @see #MIN_FORWARDER_BUF_SIZE
+     * @see #MAX_FORWARDER_BUF_SIZE
+     * @see #DEFAULT_FORWARDER_BUF_SIZE
+     */
+    public static final Property<Integer> FORWARDER_BUFFER_SIZE
+            = Property.integer("channel-agent-fwd-buf-size", DEFAULT_FORWARDER_BUF_SIZE);
+    /**
+     * Ordered comma separated list of authentications methods. Authentications methods accepted by the server will be
+     * tried in the given order. If not configured or {@code null}/empty, then the session's
+     * {@link org.apache.sshd.client.ClientAuthenticationManager#getUserAuthFactories()} is used as-is
+     */
+    public static final Property<String> PREFERRED_AUTHS
+            = Property.string("preferred-auths");
+
+    /**
+     * Specifies the number of interactive prompts before giving up. The argument to this keyword must be an integer.
+     */
+    public static final Property<Integer> PASSWORD_PROMPTS
+            = Property.integer("password-prompts", 3);
+
+    /**
+     * Key used to retrieve the value of the client identification string. If set, then it is <U>appended</U> to the
+     * (standard) &quot;SSH-2.0-&quot; prefix. Otherwise a default is sent that consists of &quot;SSH-2.0-&quot; plus
+     * the current SSHD artifact name and version in uppercase - e.g., &quot;SSH-2.0-APACHE-SSHD-1.0.0&quot;
+     */
+    public static final Property<String> CLIENT_IDENTIFICATION
+            = Property.string("client-identification");
+
+    /**
+     * Whether to send the identification string immediately upon session connection being established or wait for the
+     * server's identification before sending our own.
+     *
+     * @see <A HREF="https://tools.ietf.org/html/rfc4253#section-4.2">RFC 4253 - section 4.2 - Protocol Version
+     *      Exchange</A>
+     */
+    public static final Property<Boolean> SEND_IMMEDIATE_IDENTIFICATION
+            = Property.bool("send-immediate-identification", true);
+    /**
+     * Whether to send {@code SSH_MSG_KEXINIT} immediately after sending the client identification string or wait until
+     * the severer's one has been received.
+     *
+     * @see #SEND_IMMEDIATE_IDENTIFICATION
+     */
+    public static final Property<Boolean> SEND_IMMEDIATE_KEXINIT
+            = Property.bool("send-immediate-kex-init", true);
+
+    /**
+     * Key used to set the heartbeat interval in milliseconds (0 to disable = default)
+     */
+    public static final Property<Duration> HEARTBEAT_INTERVAL
+            = Property.duration("heartbeat-interval", Duration.ZERO);
+
+    /**
+     * Key used to check the heartbeat request that should be sent to the server
+     */
+    public static final Property<String> HEARTBEAT_REQUEST
+            = Property.string("heartbeat-request", "keepalive@sshd.apache.org");
+
+    /**
+     * Key used to indicate that the heartbeat request is also expecting a reply - time in <U>milliseconds</U> to wait
+     * for the reply. If non-positive then no reply is expected (nor requested).
+     */
+    public static final Property<Duration> HEARTBEAT_REPLY_WAIT
+            = Property.durationSec("heartbeat-reply-wait", Duration.ZERO);
+
+    /**
+     * Whether to ignore invalid identities files when pre-initializing the client session
+     *
+     * @see ClientIdentityLoader#isValidLocation(org.apache.sshd.common.NamedResource)
+     */
+    public static final Property<Boolean> IGNORE_INVALID_IDENTITIES
+            = Property.bool("ignore-invalid-identities", true);
+
+    /**
+     * Defines if we should abort in case we encounter an invalid (e.g. expired) openssh certificate.
+     */
+    public static final Property<Boolean> ABORT_ON_INVALID_CERTIFICATE
+            = Property.bool("abort-on-invalid-certificate", false);
+
+    /**
+     * As per RFC-4256:
+     *
+     * The language tag is deprecated and SHOULD be the empty string. It may be removed in a future revision of this
+     * specification. Instead, the server SHOULD select the language to be used based on the tags communicated during
+     * key exchange
+     */
+    public static final Property<String> INTERACTIVE_LANGUAGE_TAG
+            = Property.string("kb-client-interactive-language-tag", "");
+
+    /**
+     * As per RFC-4256:
+     *
+     * The submethods field is included so the user can give a hint of which actual methods he wants to use. It is a
+     * comma-separated list of authentication submethods (software or hardware) that the user prefers. If the client has
+     * knowledge of the submethods preferred by the user, presumably through a configuration setting, it MAY use the
+     * submethods field to pass this information to the server. Otherwise, it MUST send the empty string.
+     *
+     * The actual names of the submethods is something the user and the server need to agree upon.
+     *
+     * Server interpretation of the submethods field is implementation- dependent.
+     */
+    public static final Property<String> INTERACTIVE_SUBMETHODS
+            = Property.string("kb-client-interactive-sub-methods", "");
+
+    /**
+     * Configure whether reply for the &quot;exec&quot; request is required
+     */
+    public static final Property<Boolean> REQUEST_EXEC_REPLY
+            = Property.bool("channel-exec-want-reply", false);
+
+    /**
+     * On some platforms, a call to {@ode System.in.read(new byte[65536], 0, 32768)} always throws an
+     * {@link IOException}. So we need to protect against that and chunk the call into smaller calls. This problem was
+     * found on Windows, JDK 1.6.0_03-b05.
+     */
+    public static final Property<Integer> INPUT_STREAM_PUMP_CHUNK_SIZE
+            = Property.integer("stdin-pump-chunk-size", 1024);
+
+    /**
+     * Configure whether reply for the &quot;shell&quot; request is required
+     */
+    public static final Property<Boolean> REQUEST_SHELL_REPLY
+            = Property.bool("channel-shell-want-reply", false);
+
+    /**
+     * Configure whether reply for the &quot;subsystem&quoot; request is required
+     *
+     * <P>
+     * Default value for {@link #REQUEST_SUBSYSTEM_REPLY} - according to
+     * <A HREF="https://tools.ietf.org/html/rfc4254#section-6.5">RFC4254 section 6.5:</A>
+     * </P>
+     * <P>
+     * It is RECOMMENDED that the reply to these messages be requested and checked.
+     * </P>
+     */
+    public static final Property<Boolean> REQUEST_SUBSYSTEM_REPLY
+            = Property.bool("channel-subsystem-want-reply", true);
+
+    public static final Property<Integer> PROP_DHGEX_CLIENT_MIN_KEY
+            = Property.integer("dhgex-client-min");
+
+    public static final Property<Integer> PROP_DHGEX_CLIENT_MAX_KEY
+            = Property.integer("dhgex-client-max");
+
+    public static final Property<Integer> PROP_DHGEX_CLIENT_PRF_KEY
+            = Property.integer("dhgex-client-prf");
+    /**
+     * Key used to retrieve the value of the channel window size in the configuration properties map.
+     */
+    public static final Property<Long> WINDOW_SIZE
+            = Property.long_("window-size", 0x200000L);
+
+    /**
+     * Key used to retrieve timeout (msec.) to wait for data to become available when reading from a channel. If not set
+     * or non-positive then infinite value is assumed
+     */
+    public static final Property<Duration> WINDOW_TIMEOUT
+            = Property.duration("window-timeout", Duration.ZERO);
+
+    /**
+     * Key used to retrieve the value of the maximum packet size in the configuration properties map.
+     */
+    public static final Property<Long> MAX_PACKET_SIZE
+            = Property.long_("packet-size", 0x8000L);
+
+    /**
+     * A safety value that is designed to avoid an attack that uses large channel packet sizes
+     */
+    public static final Property<Long> LIMIT_PACKET_SIZE
+            = Property.long_("max-packet-size", Integer.MAX_VALUE / 4L);
+
+    /**
+     * Number of NIO worker threads to use.
+     */
+    public static final Property<Integer> NIO_WORKERS
+            = Property.validating(Property.integer("nio-workers", Runtime.getRuntime().availableProcessors() + 1),
+                    w -> ValidateUtils.checkTrue(w > 0, "Number of NIO workers must be positive: %d", w));
+    /**
+     * Key used to retrieve the value of the timeout after which it will close the connection if the other side has not
+     * been authenticated - in milliseconds.
+     */
+    public static final Property<Duration> AUTH_TIMEOUT
+            = Property.duration("auth-timeout", Duration.ofMinutes(2));
+
+    /**
+     * Key used to retrieve the value of idle timeout after which it will close the connection - in milliseconds.
+     */
+    public static final Property<Duration> IDLE_TIMEOUT
+            = Property.duration("idle-timeout", Duration.ofMinutes(10));
+
+    /**
+     * Key used to retrieve the value of the socket read timeout for NIO2 session implementation - in milliseconds.
+     */
+    public static final Property<Duration> NIO2_READ_TIMEOUT
+            = Property.duration("nio2-read-timeout", IDLE_TIMEOUT.getRequiredDefault().plus(Duration.ofSeconds(15L)));
+
+    /**
+     * Minimum NIO2 write wait timeout for a single outgoing packet - in milliseconds
+     */
+    public static final Property<Duration> NIO2_MIN_WRITE_TIMEOUT
+            = Property.duration("nio2-min-write-timeout", Duration.ofSeconds(30L));
+
+    /**
+     * Key used to retrieve the value of the disconnect timeout which is used when a disconnection is attempted. If the
+     * disconnect message has not been sent before the timeout, the underlying socket will be forcibly closed - in
+     * milliseconds.
+     */
+    public static final Property<Duration> DISCONNECT_TIMEOUT
+            = Property.duration("disconnect-timeout", Duration.ofSeconds(10));
+
+    /**
+     * Key used to configure the timeout used when writing a close request on a channel. If the message can not be
+     * written before the specified timeout elapses, the channel will be immediately closed. In milliseconds.
+     */
+    public static final Property<Duration> CHANNEL_CLOSE_TIMEOUT
+            = Property.duration("channel-close-timeout", Duration.ofSeconds(5));
+
+    /**
+     * Timeout (milliseconds) to wait for client / server stop request if immediate stop requested.
+     */
+    public static final Property<Duration> STOP_WAIT_TIME
+            = Property.duration("stop-wait-time", Duration.ofMinutes(1));
+
+    /**
+     * Socket backlog. See {@link java.nio.channels.AsynchronousServerSocketChannel#bind(java.net.SocketAddress, int)}
+     */
+    public static final Property<Integer> SOCKET_BACKLOG
+            = Property.integer("socket-backlog", 0);
+
+    /**
+     * Socket keep-alive. See {@link java.net.StandardSocketOptions#SO_KEEPALIVE}
+     */
+    public static final Property<Boolean> SOCKET_KEEPALIVE
+            = Property.bool("socket-keepalive", false);
+
+    /**
+     * Socket send buffer size. See {@link java.net.StandardSocketOptions#SO_SNDBUF}
+     */
+    public static final Property<Integer> SOCKET_SNDBUF
+            = Property.integer("socket-sndbuf");
+
+    /**
+     * Socket receive buffer size. See {@link java.net.StandardSocketOptions#SO_RCVBUF}
+     */
+    public static final Property<Integer> SOCKET_RCVBUF
+            = Property.integer("socket-rcvbuf");
+
+    /**
+     * Socket reuse address. See {@link java.net.StandardSocketOptions#SO_REUSEADDR}
+     */
+    public static final Property<Boolean> SOCKET_REUSEADDR
+            = Property.bool("socket-reuseaddr", true);
+    /**
+     * Socket linger. See {@link java.net.StandardSocketOptions#SO_LINGER}
+     */
+    public static final Property<Integer> SOCKET_LINGER
+            = Property.integer("socket-linger", -1);
+
+    /**
+     * Socket tcp no-delay. See {@link java.net.StandardSocketOptions#TCP_NODELAY}
+     */
+    public static final Property<Boolean> TCP_NODELAY
+            = Property.bool("tcp-nodelay", false);
+
+    /**
+     * Read buffer size for NIO2 sessions See {@link org.apache.sshd.common.io.nio2.Nio2Session}
+     */
+    public static final Property<Integer> NIO2_READ_BUFFER_SIZE
+            = Property.integer("nio2-read-buf-size", 32 * 1024);
+
+    /**
+     * Maximum allowed size of the initial identification text sent during the handshake
+     */
+    public static final Property<Integer> MAX_IDENTIFICATION_SIZE
+            = Property.integer("max-identification-size", 16 * 1024);
+
+    /**
+     * Key re-exchange will be automatically performed after the session has sent or received the given amount of bytes.
+     * If non-positive, then disabled.
+     */
+    public static final Property<Long> REKEY_BYTES_LIMIT
+            = Property.long_("rekey-bytes-limit", 1024L * 1024L * 1024L); // 1GB
+
+    /**
+     * Key re-exchange will be automatically performed after the specified amount of time has elapsed since the last key
+     * exchange - in milliseconds. If non-positive then disabled.
+     *
+     * @see <A HREF="https://tools.ietf.org/html/rfc4253#section-9">RFC4253 section 9</A>
+     */
+    public static final Property<Duration> REKEY_TIME_LIMIT
+            = Property.duration("rekey-time-limit", Duration.ofHours(1));
+
+    /**
+     * Key re-exchange will be automatically performed after the specified number of packets has been exchanged -
+     * positive 64-bit value. If non-positive then disabled.
+     *
+     * @see <A HREF="https://tools.ietf.org/html/rfc4344#section-3.1">RFC4344 section 3.1</A>
+     */
+    public static final Property<Long> REKEY_PACKETS_LIMIT
+            = Property.long_("rekey-packets-limit", 1L << 31);
+
+    /**
+     * Key re-exchange will be automatically performed after the specified number of cipher blocks has been processed -
+     * positive 64-bit value. If non-positive then disabled. The default is calculated according to
+     * <A HREF="https://tools.ietf.org/html/rfc4344#section-3.2">RFC4344 section 3.2</A>
+     */
+    public static final Property<Long> REKEY_BLOCKS_LIMIT
+            = Property.long_("rekey-blocks-limit", 0L);
+
+    /**
+     * Average number of packets to be skipped before an {@code SSH_MSG_IGNORE} message is inserted in the stream. If
+     * non-positive, then feature is disabled
+     *
+     * @see #IGNORE_MESSAGE_VARIANCE
+     * @see <A HREF="https://tools.ietf.org/html/rfc4251#section-9.3.1">RFC4251 section 9.3.1</A>
+     */
+    public static final Property<Long> IGNORE_MESSAGE_FREQUENCY
+            = Property.long_("ignore-message-frequency", 1024L);
+
+    /**
+     * The variance to be used around the configured {@link #IGNORE_MESSAGE_FREQUENCY} value in order to avoid insertion
+     * at a set frequency. If zero, then <U>exact</U> frequency is used. If negative, then the <U>absolute</U> value is
+     * used. If greater or equal to the frequency, then assumed to be zero - i.e., no variance
+     *
+     * @see <A HREF="https://tools.ietf.org/html/rfc4251#section-9.3.1">RFC4251 section 9.3.1</A>
+     */
+    public static final Property<Integer> IGNORE_MESSAGE_VARIANCE
+            = Property.integer("ignore-message-variance", 32);
+
+    /**
+     * Minimum size of {@code SSH_MSG_IGNORE} payload to send if feature enabled. If non-positive then no message is
+     * sent. Otherwise, the actual size is between this size and twice its value
+     *
+     * @see <A HREF="https://tools.ietf.org/html/rfc4251#section-9.3.1">RFC4251 section 9.3.1</A>
+     */
+    public static final Property<Integer> IGNORE_MESSAGE_SIZE
+            = Property.integer("ignore-message-size", 16);
+
+    /**
+     * The request type of agent forwarding. The value may be {@value #AGENT_FORWARDING_TYPE_IETF} or
+     * {@value #AGENT_FORWARDING_TYPE_OPENSSH}.
+     */
+    public static final String AGENT_FORWARDING_TYPE = "agent-fw-auth-type";
+
+    /**
+     * The agent forwarding type defined by IETF (https://tools.ietf.org/html/draft-ietf-secsh-agent-02).
+     */
+    public static final String AGENT_FORWARDING_TYPE_IETF = "auth-agent-req";
+
+    /**
+     * The agent forwarding type defined by OpenSSH.
+     */
+    public static final String AGENT_FORWARDING_TYPE_OPENSSH = "auth-agent-req@openssh.com";
+
+    /**
+     * Configure max. wait time (millis) to wait for space to become available
+     */
+    public static final Property<Duration> WAIT_FOR_SPACE_TIMEOUT
+            = Property.duration("channel-output-wait-for-space-timeout", Duration.ofSeconds(30L));
+
+    /**
+     * Used to configure the timeout (milliseconds) for receiving a response for the forwarding request
+     */
+    public static final Property<Duration> FORWARD_REQUEST_TIMEOUT
+            = Property.duration("tcpip-forward-request-timeout", Duration.ofSeconds(15L));
+
+    /**
+     * Property that can be used to configure max. allowed concurrent active channels
+     *
+     * @see org.apache.sshd.common.session.ConnectionService#registerChannel(Channel)
+     */
+    public static final Property<Integer> MAX_CONCURRENT_CHANNELS
+            = Property.integer("max-sshd-channels", Integer.MAX_VALUE);
+
+    /**
+     * RFC4254 does not clearly specify how to handle {@code SSH_MSG_CHANNEL_DATA} and
+     * {@code SSH_MSG_CHANNEL_EXTENDED_DATA} received through an unknown channel. Therefore, we provide a configurable
+     * approach to it with the default set to ignore it.
+     */
+    public static final Property<Boolean> SEND_REPLY_FOR_CHANNEL_DATA
+            = Property.bool("send-unknown-channel-data-reply", false);
+
+    /**
+     * Key used to retrieve the value in the configuration properties map of the maximum number of failed authentication
+     * requests before the server closes the connection.
+     */
+    public static final Property<Integer> MAX_AUTH_REQUESTS
+            = Property.integer("max-auth-requests", 20);
+
+    /**
+     * Key used to retrieve the value of welcome banner that will be displayed when a user connects to the server. If
+     * {@code null}/empty then no banner will be sent. The value can be one of the following:
+     * <UL>
+     * <P>
+     * <LI>A {@link java.io.File} or {@link java.nio.file.Path}, in which case its contents will be transmitted.
+     * <B>Note:</B> if the file is empty or does not exits, no banner will be transmitted.</LI>
+     * </P>
+     *
+     * <P>
+     * <LI>A {@link java.net.URI} or a string starting with &quot;file:/&quot;, in which case it will be converted to a
+     * {@link java.nio.file.Path} and handled accordingly.</LI>
+     * </P>
+     *
+     * <P>
+     * <LI>A string containing a special value indicator - e.g., {@link #AUTO_WELCOME_BANNER_VALUE}, in which case the
+     * relevant banner content will be generated.</LI>
+     * </P>
+     *
+     * <P>
+     * <LI>Any other object whose {@code toString()} value yields a non empty string will be used as the banner
+     * contents.</LI>
+     * </P>
+     * </UL>
+     *
+     * @see <A HREF="https://tools.ietf.org/html/rfc4252#section-5.4">RFC-4252 section 5.4</A>
+     */
+    public static final Property<Object> WELCOME_BANNER
+            = Property.object("welcome-banner");
+
+    /**
+     * Special value that can be set for the {@link #WELCOME_BANNER} property indicating that the server should generate
+     * a banner consisting of the random art of the server's keys (if any are provided). If no server keys are
+     * available, then no banner will be sent
+     */
+    public static final String AUTO_WELCOME_BANNER_VALUE = "#auto-welcome-banner";
+
+    /**
+     * Key used to denote the language code for the welcome banner (if such a banner is configured).
+     */
+    public static final Property<String> WELCOME_BANNER_LANGUAGE
+            = Property.string("welcome-banner-language", "en");
+
+    /**
+     * The {@link WelcomeBannerPhase} value - either as an enum or a string
+     */
+    public static final Property<WelcomeBannerPhase> WELCOME_BANNER_PHASE
+            = Property.enum_("welcome-banner-phase", WelcomeBannerPhase.class, WelcomeBannerPhase.IMMEDIATE);
+
+    /**
+     * The charset to use if the configured welcome banner points to a file - if not specified (either as a string or a
+     * {@link java.nio.charset.Charset} then the local default is used.
+     */
+    public static final Property<Charset> WELCOME_BANNER_CHARSET
+            = Property.charset("welcome-banner-charset", Charset.defaultCharset());
+
+    /**
+     * This key is used when configuring multi-step authentications. The value needs to be a blank separated list of
+     * comma separated list of authentication method names. For example, an argument of
+     * <code>publickey,password publickey,keyboard-interactive</code> would require the user to complete public key
+     * authentication, followed by either password or keyboard interactive authentication. Only methods that are next in
+     * one or more lists are offered at each stage, so for this example, it would not be possible to attempt password or
+     * keyboard-interactive authentication before public key.
+     */
+    public static final Property<String> AUTH_METHODS
+            = Property.string("auth-methods");
+
+    /**
+     * Key used to retrieve the value of the maximum concurrent open session count per username. If not set, then
+     * unlimited
+     */
+    public static final Property<Integer> MAX_CONCURRENT_SESSIONS
+            = Property.integer("max-concurrent-sessions");
+
+    /**
+     * Key used to retrieve any extra lines to be sent during initial protocol handshake <U>before</U> the
+     * identification. The configured string value should use {@value #SERVER_EXTRA_IDENT_LINES_SEPARATOR} character to
+     * denote line breaks
+     */
+    public static final Property<String> SERVER_EXTRA_IDENTIFICATION_LINES
+            = Property.string("server-extra-identification-lines");
+
+    /**
+     * Separator used in the {@link #SERVER_EXTRA_IDENTIFICATION_LINES} configuration string to indicate new line break
+     */
+    public static final char SERVER_EXTRA_IDENT_LINES_SEPARATOR = '|';
+
+    /**
+     * Key used to retrieve the value of the server identification string. If set, then it is <U>appended</U> to the
+     * (standard) &quot;SSH-2.0-&quot; prefix. Otherwise a default is sent that consists of &quot;SSH-2.0-&quot; plus
+     * the current SSHD artifact name and version in uppercase - e.g., &quot;SSH-2.0-APACHE-SSHD-1.0.0&quot;
+     */
+    public static final Property<String> SERVER_IDENTIFICATION
+            = Property.string("server-identification");
+
+    /**
+     * Key used to configure the timeout used when receiving a close request on a channel to wait until the command
+     * cleanly exits after setting an EOF on the input stream.
+     */
+    public static final Property<Duration> COMMAND_EXIT_TIMEOUT
+            = Property.duration("command-exit-timeout", Duration.ofMillis(5L));
+
+    /**
+     * A URL pointing to the moduli file. If not specified, the default internal file will be used.
+     */
+    public static final Property<String> MODULI_URL
+            = Property.string("moduli-url");
+
+    /**
+     * See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
+     */
+    public static final Property<String> KB_SERVER_INTERACTIVE_NAME
+            = Property.string("kb-server-interactive-name", "Password authentication");
+
+    /**
+     * See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
+     */
+    public static final Property<String> KB_SERVER_INTERACTIVE_INSTRUCTION
+            = Property.string("kb-server-interactive-instruction", "");
+
+    /**
+     * See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
+     */
+    public static final Property<String> KB_SERVER_INTERACTIVE_LANG
+            = Property.string("kb-server-interactive-language", "en-US");
+
+    /**
+     * See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
+     */
+    public static final Property<String> KB_SERVER_INTERACTIVE_PROMPT
+            = Property.string("kb-server-interactive-prompt", "Password: ");
+
+    /**
+     * See {@link org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator}.
+     */
+    public static final Property<Boolean> KB_SERVER_INTERACTIVE_ECHO_PROMPT
+            = Property.bool("kb-server-interactive-echo-prompt", false);
+
+    /**
+     * Maximum amount of extended (a.k.a. STDERR) data allowed to be accumulated until a {@link ChannelDataReceiver} for
+     * the data is registered
+     */
+    public static final Property<Integer> MAX_EXTDATA_BUFSIZE
+            = Property.integer("channel-session-max-extdata-bufsize", 0);
+
+    /**
+     * See {@link org.apache.sshd.server.kex.DHGEXServer}.
+     */
+    public static final Property<Integer> PROP_DHGEX_SERVER_MIN_KEY
+            = Property.integer("dhgex-server-min");
+
+    /**
+     * See {@link org.apache.sshd.server.kex.DHGEXServer}.
+     */
+    public static final Property<Integer> PROP_DHGEX_SERVER_MAX_KEY
+            = Property.integer("dhgex-server-max");
+    /**
+     * Value used by the {@link org.apache.sshd.server.shell.InvertedShellWrapper} to control the &quot;busy-wait&quot;
+     * sleep time (millis) on the pumping loop if nothing was pumped - must be <U>positive</U>.
+     */
+    public static final Property<Duration> PUMP_SLEEP_TIME
+            = Property.duration("inverted-shell-wrapper-pump-sleep", Duration.ofMillis(1));
+
+    /**
+     * Value used by the {@link org.apache.sshd.server.shell.InvertedShellWrapper} to control copy buffer size.
+     */
+    public static final Property<Integer> BUFFER_SIZE
+            = Property.integer("inverted-shell-wrapper-buffer-size", IoUtils.DEFAULT_COPY_SIZE);
+
+    /**
+     * Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control the channel open
+     * timeout.
+     */
+    public static final Property<Duration> X11_OPEN_TIMEOUT
+            = Property.duration("x11-fwd-open-timeout", Duration.ofSeconds(30L));
+
+    /**
+     * Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control from which X11
+     * display number to start looking for a free value.
+     */
+    public static final Property<Integer> X11_DISPLAY_OFFSET
+            = Property.integer("x11-fwd-display-offset", 10);
+
+    /**
+     * Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control up to which (but not
+     * including) X11 display number to look or a free value.
+     */
+    public static final Property<Integer> X11_MAX_DISPLAYS
+            = Property.integer("x11-fwd-max-display", 1000);
+
+    /**
+     * Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control the base port number
+     * for the X11 display number socket binding.
+     */
+    public static final Property<Integer> X11_BASE_PORT
+            = Property.integer("x11-fwd-base-port", 6000);
+
+    /**
+     * Configuration value for the {@link org.apache.sshd.server.x11.X11ForwardSupport} to control the host used to bind
+     * to for the X11 display when looking for a free port.
+     */
+    public static final Property<String> X11_BIND_HOST
+            = Property.string("x11-fwd-bind-host", SshdSocketAddress.LOCALHOST_IPV4);
+
+    private CoreModuleProperties() {
+        // private
+    }
+
+}
-- 
2.27.0

