shell - string or array or function returning string or
+ * array. Examples: "sh", [ "/bin/bash" ],
+ * function(options) { return [ '/bin/bash' ] }. It affects "local",
+ * "ssh", and "docker" protocols and "remoteHost" option.
+ *
+ *
${protocol}Shell - function, which should generate shell command
+ * for user supplied protocol. Function receives single argument -
+ * user supplied options. Function must return array.
+ *
+ *
remoteHostCommand - function, which should generate command to connect to remote host and execute
+ *
+ *
+ *
+ * User supplied options are:
+ *
+ *
+ *
protocol - protocol to use. Supported protocols are "local" (for
+ * su to local user), "ssh" (for ssh-ing as an user to a remote host),
+ * docker (for entering a running container), or any other
+ * protocol which has ${protocol}Shell() function defined in configuration.
+ *
+ *
remoteHost - address of remote host to execute shell
+ * at via ssh or via an other method defined
+ * in configuration using function remoteHostCommand().
+ *
+ *
+ */
+Session.prototype.prepareShellCommand = function Session_prepareShellCommand(conf, options) {
+
+ // For backward compatibility: get shell command and arguments from configuration
+ var shell = typeof conf.shell === 'function'
+ ? conf.shell(this, options)
+ : conf.shell;
+
+ if(typeof(shell) === 'string') {
+ shell = [ shell ];
+ }
+
+ options = options || {};
+
+ // Chose shell using options
+ if(options.protocol) {
+ try {
+ switch(options.protocol) {
+ // "local" means local user
+ case 'local':
+ shell = conf.localUserShell? conf.localUserShell(options) : [ 'su', '--login', options.user || 'root' ,
+ '--shell=' + shell[0] ].concat( (shell.length>1)? [ '--command='+shell.slice(1).join(' ') ] : [] );
+ break;
+
+ // ssh means access a remote host via ssh. See also "remoteHost" option.
+ //
+ // If host at remote IP will be reinstalled, then it key will be different,
+ // so ssh will complain about that.
+ case 'ssh':
+ shell = conf.sshShell? conf.sshShell(options) : [ 'ssh', '-t', ((options.user)? options.user : 'root') + '@' + options.host ].concat(shell);
+ break;
+
+ // docker means access to a docker container at a host. If tty.js
+ // itself will be ran in a container, then "remoteHost" option will be
+ // required for this protocol to work.
+ case 'docker':
+ shell = conf.dockerShell? conf.dockerShell(options) : [ 'docker', 'exec', '-it', options.container ].concat(shell);
+ break;
+
+ default:
+ // For unknown protocol, try to call protocol handler from configuration with name "${protocol}Shell".
+ shell = conf[options.protocol+"Shell"]();
+ break;
+ }
+ } catch(e) {
+ this.error("Cannot create shell for protocol: \""+options.protocol+"\". Options: ", options, ", error: ", e);
+ return "/bin/false"; // Safe default
+ }
+ }
+
+ if(options.remoteHost) {
+ try {
+ // Execute shell at remote host using ssh with host key checking disabled.
+ // The reason for that is that user hosts can be reinstalled often using
+ shell = (conf.remoteHostCommand)? conf.remoteHostCommand(options.remoteHost, shell, options) :
+ [ 'ssh', '-t', '-q', '-o', 'StrictHostKeyChecking no', '-o', 'UserKnownHostsFile=/dev/null', '-l', 'root', options.remoteHost ].concat(shell);
+ } catch(e) {
+ this.error("Cannot create command to execute shell on remote host: \""+options.remoteHost+"\". Options: ", options, ", error: ", e);
+ return "/bin/false"; // Safe default
+ }
+ }
+
+ //*DEBUG*/this.log("conf.shell: ", conf.shell, ", options: ", options, ", shell: ", shell);
+
+ return shell;
+}
+
+// Options are for prepareShellCommand() function.
+Session.prototype.handleCreate = function(cols, rows, options, func) {
var self = this
, terms = this.terms
, conf = this.server.conf
, socket = this.socket;
+ //*DEBUG*/this.log('Options: ', options);
+
var len = Object.keys(terms).length
, term
, id;
@@ -436,15 +539,10 @@ Session.prototype.handleCreate = function(cols, rows, func) {
return func({ error: 'Terminal limit.' });
}
- var shell = typeof conf.shell === 'function'
- ? conf.shell(this)
- : conf.shell;
-
- var shellArgs = typeof conf.shellArgs === 'function'
- ? conf.shellArgs(this)
- : conf.shellArgs;
+ // Get path to shell binary from configuration
+ var shellCmd = this.prepareShellCommand(conf, options);
- term = pty.fork(shell, shellArgs, {
+ term = pty.fork(shellCmd[0], shellCmd.slice(1), {
name: conf.termName,
cols: cols,
rows: rows,
@@ -478,7 +576,7 @@ Session.prototype.handleCreate = function(cols, rows, func) {
return func(null, {
id: id,
pty: term.pty,
- process: sanitize(conf.shell)
+ process: sanitize(shellCmd[0])
});
};
diff --git a/static/index.html b/static/index.html
index 458d295e..1a4c8b15 100644
--- a/static/index.html
+++ b/static/index.html
@@ -1,4 +1,4 @@
-
+
tty.js
@@ -13,11 +13,47 @@
tty.js
Click the tilde with a modifier to close the window.