def initialize(self): """ Called inside of :meth:`TerminalApplication.initialize` shortly after the WebSocket is instantiated. Attaches our two `terminal:authenticate` events (to create the user's .ssh dir and send our CSS template) and ensures that the ssh_connect.py script is executable. """ ssh_connect_path = os.path.join(PLUGIN_PATH, 'scripts', 'ssh_connect.py') if os.path.exists(ssh_connect_path): import stat st = os.stat(ssh_connect_path) if not bool(st.st_mode & stat.S_IXOTH): try: os.chmod(ssh_connect_path, 0o755) except OSError: ssh_log.error(_( "Could not set %s as executable. You will need to 'chmod " "a+x' that script manually.") % ssh_connect_path) user_msg = _( "Error loading SSH plugin: The ssh_connect.py script is " "not executable. See the logs for more details.") send_msg = partial(self.ws.send_message, user_msg) events = ["terminal:authenticate", "terminal:new_terminal"] self.on(events, send_msg) self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh') # NOTE: Why not use the 'Events' hook for these? You can't attach two # functions to the same event via that mechanism because it's a dict # (one would override the other). # An alternative would be to write a single function say, on_auth() that # calls both of these functions then assign it to 'terminal:authenticate' in # the 'Events' hook. I think this way is better since it is more explicit. self.on('terminal:authenticate', bind(send_ssh_css_template, self)) self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
def initialize(self): """ Called inside of :meth:`TerminalApplication.initialize` shortly after the WebSocket is instantiated. """ self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh') # NOTE: Why not use the 'Events' hook for these? You can't attach two # functions to the same event via that mechanism because it's a dict # (one would override the other). # An alternative would be to write a single function say, on_auth() that # calls both of these functions then assign it to 'terminal:authenticate' in # the 'Events' hook. I think this way is better since it is more explicit. self.on('terminal:authenticate', bind(send_ssh_css_template, self)) self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
def initialize(self): """ Called inside of :meth:`TerminalApplication.initialize` shortly after the WebSocket is instantiated. Attaches our two `terminal:authenticate` events (to create the user's .ssh dir and send our CSS template) and ensures that the ssh_connect.py script is executable. """ ssh_connect_path = os.path.join(PLUGIN_PATH, 'scripts', 'ssh_connect.py') if os.path.exists(ssh_connect_path): import stat st = os.stat(ssh_connect_path) if not bool(st.st_mode & stat.S_IXOTH): os.chmod(ssh_connect_path, 0o755) self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh') # NOTE: Why not use the 'Events' hook for these? You can't attach two # functions to the same event via that mechanism because it's a dict # (one would override the other). # An alternative would be to write a single function say, on_auth() that # calls both of these functions then assign it to 'terminal:authenticate' in # the 'Events' hook. I think this way is better since it is more explicit. self.on('terminal:authenticate', bind(send_ssh_css_template, self)) self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
def initialize(self): """ Called when the WebSocket is instantiated, sets up our WebSocket actions, security policies, and attaches all of our plugin hooks/events. """ example_log.debug("ExampleApplication.initialize()") # Register our security policy function in the 'security' dict self.ws.security.update({'example': example_policies}) # Register some WebSocket actions... # These can be called from the client like so: # GateOne.ws.send(JSON.stringify({'example:test_example': whatever})); self.ws.actions.update({ 'example:test_example': self.test_example, }) # Gate One provides a location where you can store information that you # want to be persistent across user sesions/connections and whatnot: if 'example' not in self.ws.persist: # If it doesn't belong in SESSIONS but you still need it to stick # around after the user disconnects put it here: self.ws.persist['example'] = {} # NOTE: If you don't care about your app having its own plugins you can # delete everything from here until the end of this function. # -- BEGIN PLUGIN CODE -- # If you want your app to support plugins here's how you do it: # First let's check if someone has explicitly given us a list of plugins # that should be enabled (so we can exclude the others): enabled_plugins = self.ws.prefs['*']['example'].get( 'enabled_plugins', []) # Now we'll use Gate One's utils.get_plugins() function to fetch a dict # containing all our Python, JavaScript, and CSS plugin files. This is # really only so we can log which plugins are enabled because the # process of importing Python plugins happens inside of init() and # JS/CSS plugin files get sent via the send_plugin_static_files() # function inside of authenticate(). self.plugins = get_plugins( # Get everything in example/plugins/ os.path.join(APPLICATION_PATH, 'plugins'), enabled_plugins) # Now let's separate the plugins by type (to save some typing) js_plugins = [] for js_path in self.plugins['js']: name = js_path.split(os.path.sep)[-2] name = os.path.splitext(name)[0] js_plugins.append(name) css_plugins = [] for css_path in css_plugins: name = css_path.split(os.path.sep)[-2] css_plugins.append(name) plugin_list = list(set(self.plugins['py'] + js_plugins + css_plugins)) plugin_list.sort() # So there's consistent ordering example_log.info(_( "Active Example Plugins: %s" % ", ".join(plugin_list))) # Now let's attach plugin hooks. Plugin hooks can be whatever you like # and called from anywhere in your application. There's three types of # hooks you'll definitely want though: initialize(), 'WebSocket' and # 'Events' # # The initialize() hook just calls a given plugin's "initializ()" # function if it has one. The function will be passed `self` (the # current instance of your app). This allows plugins to take care of # any initialization stuff that needs to happen before anything else. # # 'WebSocket' hooks are what allow plugins to add their own WebSocket # actions such as, "myplugin:do_something" which is a very important # part of Gate One. # # 'Events' hooks allow plugins to attach functions to `OnOff` events # such as 'self.on("example:some_event", handle_some_event)' # # With those three kinds of hooks plugins can add or override pretty # much anything. # # NOTE: All GOApplication instances include the OnOff mixin class so # they can use self.on(), self.off, self.trigger(), and self.once() # # How do plugins assign these hooks? They simply include a 'hooks' dict # somewhere in the global scope of their .py files. Example: # hooks = { # 'WebSocket': {'myplugin:some_func': some_func} # 'Events': {'example:authenticate': auth_func} # } self.plugin_hooks = {} # We'll store our plugin hooks here imported = load_modules(self.plugins['py']) for plugin in imported: try: # Add the plugin's hooks dict to self.plugin_hooks: self.plugin_hooks.update({plugin.__name__: plugin.hooks}) # Now we'll call the plugin's initialize() function: if hasattr(plugin, 'initialize'): plugin.initialize(self) except AttributeError: pass # No hooks--probably just a supporting .py file. # Now we hook up the hooks: for plugin_name, hooks in self.plugin_hooks.items(): if 'WebSocket' in hooks: # Apply the plugin's WebSocket actions to ApplicationWebSocket for ws_command, func in hooks['WebSocket'].items(): self.ws.actions.update({ws_command: bind(func, self)}) # Attach the plugin's event hooks to their respective events: if 'Events' in hooks: for event, callback in hooks['Events'].items(): self.on(event, bind(callback, self))
def initialize(self): """ Called when the WebSocket is instantiated, sets up our WebSocket actions, security policies, and attaches all of our plugin hooks/events. """ example_log.debug("ExampleApplication.initialize()") # Register our security policy function in the 'security' dict self.ws.security.update({'example': example_policies}) # Register some WebSocket actions... # These can be called from the client like so: # GateOne.ws.send(JSON.stringify({'example:test_example': whatever})); self.ws.actions.update({ 'example:test_example': self.test_example, }) # Gate One provides a location where you can store information that you # want to be persistent across user sesions/connections and whatnot: if 'example' not in self.ws.persist: # If it doesn't belong in SESSIONS but you still need it to stick # around after the user disconnects put it here: self.ws.persist['example'] = {} # NOTE: If you don't care about your app having its own plugins you can # delete everything from here until the end of this function. # -- BEGIN PLUGIN CODE -- # If you want your app to support plugins here's how you do it: # First let's check if someone has explicitly given us a list of plugins # that should be enabled (so we can exclude the others): enabled_plugins = self.ws.prefs['*']['example'].get( 'enabled_plugins', []) # Now we'll use Gate One's utils.get_plugins() function to fetch a dict # containing all our Python, JavaScript, and CSS plugin files. This is # really only so we can log which plugins are enabled because the # process of importing Python plugins happens inside of init() and # JS/CSS plugin files get sent via the send_plugin_static_files() # function inside of authenticate(). self.plugins = get_plugins( # Get everything in example/plugins/ os.path.join(APPLICATION_PATH, 'plugins'), enabled_plugins) # Now let's separate the plugins by type (to save some typing) js_plugins = [] for js_path in self.plugins['js']: name = js_path.split(os.path.sep)[-2] name = os.path.splitext(name)[0] js_plugins.append(name) css_plugins = [] for css_path in css_plugins: name = css_path.split(os.path.sep)[-2] css_plugins.append(name) plugin_list = list(set(self.plugins['py'] + js_plugins + css_plugins)) plugin_list.sort() # So there's consistent ordering example_log.info( _("Active Example Plugins: %s" % ", ".join(plugin_list))) # Now let's attach plugin hooks. Plugin hooks can be whatever you like # and called from anywhere in your application. There's three types of # hooks you'll definitely want though: initialize(), 'WebSocket' and # 'Events' # # The initialize() hook just calls a given plugin's "initializ()" # function if it has one. The function will be passed `self` (the # current instance of your app). This allows plugins to take care of # any initialization stuff that needs to happen before anything else. # # 'WebSocket' hooks are what allow plugins to add their own WebSocket # actions such as, "myplugin:do_something" which is a very important # part of Gate One. # # 'Events' hooks allow plugins to attach functions to `OnOff` events # such as 'self.on("example:some_event", handle_some_event)' # # With those three kinds of hooks plugins can add or override pretty # much anything. # # NOTE: All GOApplication instances include the OnOff mixin class so # they can use self.on(), self.off, self.trigger(), and self.once() # # How do plugins assign these hooks? They simply include a 'hooks' dict # somewhere in the global scope of their .py files. Example: # hooks = { # 'WebSocket': {'myplugin:some_func': some_func} # 'Events': {'example:authenticate': auth_func} # } self.plugin_hooks = {} # We'll store our plugin hooks here imported = load_modules(self.plugins['py']) for plugin in imported: try: # Add the plugin's hooks dict to self.plugin_hooks: self.plugin_hooks.update({plugin.__name__: plugin.hooks}) # Now we'll call the plugin's initialize() function: if hasattr(plugin, 'initialize'): plugin.initialize(self) except AttributeError: pass # No hooks--probably just a supporting .py file. # Now we hook up the hooks: for plugin_name, hooks in self.plugin_hooks.items(): if 'WebSocket' in hooks: # Apply the plugin's WebSocket actions to ApplicationWebSocket for ws_command, func in hooks['WebSocket'].items(): self.ws.actions.update({ws_command: bind(func, self)}) # Attach the plugin's event hooks to their respective events: if 'Events' in hooks: for event, callback in hooks['Events'].items(): self.on(event, bind(callback, self))