You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WelcomeShell.java 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (C) 2009 The Android Open Source Project
  3. * Copyright 2014 gitblit.com.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package com.gitblit.transport.ssh;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;
  21. import java.net.MalformedURLException;
  22. import java.net.URL;
  23. import java.text.MessageFormat;
  24. import org.apache.sshd.common.Factory;
  25. import org.apache.sshd.server.Command;
  26. import org.apache.sshd.server.Environment;
  27. import org.apache.sshd.server.ExitCallback;
  28. import org.apache.sshd.server.SessionAware;
  29. import org.apache.sshd.server.session.ServerSession;
  30. import org.eclipse.jgit.lib.Constants;
  31. import org.eclipse.jgit.util.SystemReader;
  32. import com.gitblit.IStoredSettings;
  33. import com.gitblit.Keys;
  34. import com.gitblit.manager.IGitblit;
  35. import com.gitblit.models.UserModel;
  36. import com.gitblit.transport.ssh.commands.DispatchCommand;
  37. import com.gitblit.transport.ssh.commands.SshCommandFactory;
  38. import com.gitblit.utils.StringUtils;
  39. /**
  40. * Class that displays a welcome message for any shell requests.
  41. *
  42. */
  43. public class WelcomeShell implements Factory<Command> {
  44. private final IGitblit gitblit;
  45. public WelcomeShell(IGitblit gitblit) {
  46. this.gitblit = gitblit;
  47. }
  48. @Override
  49. public Command create() {
  50. return new SendMessage(gitblit);
  51. }
  52. @Override
  53. public Command get() {
  54. return create();
  55. }
  56. private static class SendMessage implements Command, SessionAware {
  57. private final IPublicKeyManager km;
  58. private final IStoredSettings settings;
  59. private ServerSession session;
  60. private InputStream in;
  61. private OutputStream out;
  62. private OutputStream err;
  63. private ExitCallback exit;
  64. SendMessage(IGitblit gitblit) {
  65. this.km = gitblit.getPublicKeyManager();
  66. this.settings = gitblit.getSettings();
  67. }
  68. @Override
  69. public void setInputStream(final InputStream in) {
  70. this.in = in;
  71. }
  72. @Override
  73. public void setOutputStream(final OutputStream out) {
  74. this.out = out;
  75. }
  76. @Override
  77. public void setErrorStream(final OutputStream err) {
  78. this.err = err;
  79. }
  80. @Override
  81. public void setExitCallback(final ExitCallback callback) {
  82. this.exit = callback;
  83. }
  84. @Override
  85. public void setSession(final ServerSession session) {
  86. this.session = session;
  87. }
  88. @Override
  89. public void start(final Environment env) throws IOException {
  90. err.write(Constants.encode(getMessage()));
  91. err.flush();
  92. in.close();
  93. out.close();
  94. err.close();
  95. exit.onExit(127);
  96. }
  97. @Override
  98. public void destroy() {
  99. this.session = null;
  100. }
  101. String getMessage() {
  102. SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
  103. UserModel user = client.getUser();
  104. String hostname = getHostname();
  105. int port = settings.getInteger(Keys.git.sshPort, 0);
  106. boolean writeKeysIsSupported = true;
  107. if (km != null) {
  108. writeKeysIsSupported = km.supportsWritingKeys(user);
  109. }
  110. final String b1 = StringUtils.rightPad("", 72, '═');
  111. final String b2 = StringUtils.rightPad("", 72, '─');
  112. final String nl = "\r\n";
  113. StringBuilder msg = new StringBuilder();
  114. msg.append(nl);
  115. msg.append(b1);
  116. msg.append(nl);
  117. msg.append(" ");
  118. msg.append(com.gitblit.Constants.getGitBlitVersion());
  119. msg.append(nl);
  120. msg.append(b1);
  121. msg.append(nl);
  122. msg.append(nl);
  123. msg.append(" Hi ");
  124. msg.append(user.getDisplayName());
  125. msg.append(", you have successfully connected over SSH.");
  126. msg.append(nl);
  127. msg.append(" Interactive shells are not available.");
  128. msg.append(nl);
  129. msg.append(nl);
  130. msg.append(" client: ");
  131. msg.append(session.getClientVersion());
  132. msg.append(nl);
  133. msg.append(nl);
  134. msg.append(b2);
  135. msg.append(nl);
  136. msg.append(nl);
  137. msg.append(" You may clone a repository with the following Git syntax:");
  138. msg.append(nl);
  139. msg.append(nl);
  140. msg.append(" git clone ");
  141. msg.append(formatUrl(hostname, port, user.username));
  142. msg.append(nl);
  143. msg.append(nl);
  144. msg.append(b2);
  145. msg.append(nl);
  146. msg.append(nl);
  147. if (writeKeysIsSupported && client.getKey() == null) {
  148. // user has authenticated with a password
  149. // display add public key instructions
  150. msg.append(" You may upload an SSH public key with the following syntax:");
  151. msg.append(nl);
  152. msg.append(nl);
  153. msg.append(String.format(" cat ~/.ssh/id_rsa.pub | ssh -l %s -p %d %s keys add", user.username, port, hostname));
  154. msg.append(nl);
  155. msg.append(nl);
  156. msg.append(b2);
  157. msg.append(nl);
  158. msg.append(nl);
  159. }
  160. // display the core commands
  161. SshCommandFactory cmdFactory = (SshCommandFactory) session.getFactoryManager().getCommandFactory();
  162. DispatchCommand root = cmdFactory.createRootDispatcher(client, "");
  163. String usage = root.usage().replace("\n", nl);
  164. msg.append(usage);
  165. return msg.toString();
  166. }
  167. private String getHostname() {
  168. String host = null;
  169. String url = settings.getString(Keys.web.canonicalUrl, "https://localhost:8443");
  170. if (url != null) {
  171. try {
  172. host = new URL(url).getHost();
  173. } catch (MalformedURLException e) {
  174. }
  175. }
  176. if (StringUtils.isEmpty(host)) {
  177. host = SystemReader.getInstance().getHostname();
  178. }
  179. return host;
  180. }
  181. private String formatUrl(String hostname, int port, String username) {
  182. int displayPort = settings.getInteger(Keys.git.sshAdvertisedPort, port);
  183. String displayHostname = settings.getString(Keys.git.sshAdvertisedHost, "");
  184. if(displayHostname.isEmpty()) {
  185. displayHostname = hostname;
  186. }
  187. if (displayPort == 22) {
  188. // standard port
  189. return MessageFormat.format("{0}@{1}/REPOSITORY.git", username, displayHostname);
  190. } else {
  191. // non-standard port
  192. return MessageFormat.format("ssh://{0}@{1}:{2,number,0}/REPOSITORY.git",
  193. username, displayHostname, displayPort);
  194. }
  195. }
  196. }
  197. }