James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
commit | author | age
e725e1 1 /*
56b3f3 2  * Copyright (C) 2009 The Android Open Source Project
e725e1 3  * Copyright 2014 gitblit.com.
JM 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
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.text.MessageFormat;
25
26 import org.apache.sshd.common.Factory;
27 import org.apache.sshd.server.Command;
28 import org.apache.sshd.server.Environment;
29 import org.apache.sshd.server.ExitCallback;
30 import org.apache.sshd.server.SessionAware;
31 import org.apache.sshd.server.session.ServerSession;
32 import org.eclipse.jgit.lib.Constants;
33 import org.eclipse.jgit.util.SystemReader;
34
35 import com.gitblit.IStoredSettings;
36 import com.gitblit.Keys;
37 import com.gitblit.models.UserModel;
01b529 38 import com.gitblit.transport.ssh.commands.DispatchCommand;
261ddf 39 import com.gitblit.transport.ssh.commands.SshCommandFactory;
e725e1 40 import com.gitblit.utils.StringUtils;
JM 41
42 /**
43  * Class that displays a welcome message for any shell requests.
44  *
45  */
46 public class WelcomeShell implements Factory<Command> {
47
48     private final IStoredSettings settings;
49
50     public WelcomeShell(IStoredSettings settings) {
51         this.settings = settings;
52     }
53
54     @Override
55     public Command create() {
56         return new SendMessage(settings);
57     }
58
59     private static class SendMessage implements Command, SessionAware {
60
61         private final IStoredSettings settings;
01b529 62         private ServerSession session;
e725e1 63
JM 64         private InputStream in;
65         private OutputStream out;
66         private OutputStream err;
67         private ExitCallback exit;
68
69         SendMessage(IStoredSettings settings) {
70             this.settings = settings;
71         }
72
73         @Override
74         public void setInputStream(final InputStream in) {
75             this.in = in;
76         }
77
78         @Override
79         public void setOutputStream(final OutputStream out) {
80             this.out = out;
81         }
82
83         @Override
84         public void setErrorStream(final OutputStream err) {
85             this.err = err;
86         }
87
88         @Override
89         public void setExitCallback(final ExitCallback callback) {
90             this.exit = callback;
91         }
92
93         @Override
94         public void setSession(final ServerSession session) {
01b529 95             this.session = session;
e725e1 96         }
JM 97
98         @Override
99         public void start(final Environment env) throws IOException {
100             err.write(Constants.encode(getMessage()));
101             err.flush();
102
103             in.close();
104             out.close();
105             err.close();
106             exit.onExit(127);
107         }
108
109         @Override
110         public void destroy() {
01b529 111             this.session = null;
e725e1 112         }
JM 113
114         String getMessage() {
01b529 115             SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
e725e1 116             UserModel user = client.getUser();
617909 117             String hostname = getHostname();
JM 118             int port = settings.getInteger(Keys.git.sshPort, 0);
119
120             final String b1 = StringUtils.rightPad("", 72, '═');
121             final String b2 = StringUtils.rightPad("", 72, '─');
122             final String nl = "\r\n";
e725e1 123
JM 124             StringBuilder msg = new StringBuilder();
617909 125             msg.append(nl);
JM 126             msg.append(b1);
127             msg.append(nl);
128             msg.append(" ");
129             msg.append(com.gitblit.Constants.getGitBlitVersion());
130             msg.append(nl);
131             msg.append(b1);
132             msg.append(nl);
133             msg.append(nl);
134             msg.append(" Hi ");
e725e1 135             msg.append(user.getDisplayName());
617909 136             msg.append(", you have successfully connected over SSH.");
JM 137             msg.append(nl);
556f69 138             msg.append(" Interactive shells are not available.");
617909 139             msg.append(nl);
8d96b9 140             msg.append(nl);
JM 141             msg.append("   client:   ");
01b529 142             msg.append(session.getClientVersion());
617909 143             msg.append(nl);
JM 144             msg.append(nl);
e725e1 145
617909 146             msg.append(b2);
JM 147             msg.append(nl);
148             msg.append(nl);
149             msg.append(" You may clone a repository with the following Git syntax:");
150             msg.append(nl);
151             msg.append(nl);
e725e1 152
01b529 153             msg.append("   git clone ");
617909 154             msg.append(formatUrl(hostname, port, user.username));
JM 155             msg.append(nl);
156             msg.append(nl);
157
158             msg.append(b2);
159             msg.append(nl);
160             msg.append(nl);
161
8d96b9 162             if (client.getKey() == null) {
JM 163                 // user has authenticated with a password
164                 // display add public key instructions
165                 msg.append(" You may upload an SSH public key with the following syntax:");
166                 msg.append(nl);
167                 msg.append(nl);
617909 168
413e9b 169                 msg.append(String.format("   cat ~/.ssh/id_rsa.pub | ssh -l %s -p %d %s keys add", user.username, port, hostname));
8d96b9 170                 msg.append(nl);
JM 171                 msg.append(nl);
617909 172
8d96b9 173                 msg.append(b2);
JM 174                 msg.append(nl);
175                 msg.append(nl);
176             }
e725e1 177
01b529 178             // display the core commands
JM 179             SshCommandFactory cmdFactory = (SshCommandFactory) session.getFactoryManager().getCommandFactory();
180             DispatchCommand root = cmdFactory.createRootDispatcher(client, "");
617909 181             String usage = root.usage().replace("\n", nl);
01b529 182             msg.append(usage);
JM 183
e725e1 184             return msg.toString();
JM 185         }
186
617909 187         private String getHostname() {
e725e1 188             String host = null;
JM 189             String url = settings.getString(Keys.web.canonicalUrl, "https://localhost:8443");
190             if (url != null) {
191                 try {
192                     host = new URL(url).getHost();
193                 } catch (MalformedURLException e) {
194                 }
195             }
196             if (StringUtils.isEmpty(host)) {
197                 host = SystemReader.getInstance().getHostname();
198             }
617909 199             return host;
JM 200         }
e725e1 201
617909 202         private String formatUrl(String hostname, int port, String username) {
b3aabb 203             int displayPort = settings.getInteger(Keys.git.sshAdvertisedPort, port);
JM 204             String displayHostname = settings.getString(Keys.git.sshAdvertisedHost, "");
182312 205             if(displayHostname.isEmpty()) {
MB 206                 displayHostname = hostname;
207             }
208             if (displayPort == 22) {
e725e1 209                 // standard port
182312 210                 return MessageFormat.format("{0}@{1}/REPOSITORY.git", username, displayHostname);
e725e1 211             } else {
JM 212                 // non-standard port
213                 return MessageFormat.format("ssh://{0}@{1}:{2,number,0}/REPOSITORY.git",
182312 214                         username, displayHostname, displayPort);
e725e1 215             }
JM 216         }
217     }
218 }