User:Jacek Antonelli/Plugin System/Local and Remote Plugins

Introduction
This page describes local plugins and remote plugins from a moderately technical perspective. In particular, it focuses on the differences in how the two categories of plugins are run and connect to the viewer.

The basic difference between the two is that local plugins run on the same computer as the viewer, while remote plugins run on a different computer and connect to the viewer over the internet or LAN. But, there are also other important technical and usage differences to keep in mind.

Local Plugins
Local plugins are characterized by three things:
 * 1) They are launched by the viewer, either at startup or when the user chooses to activate them.
 * 2) They run alongside the viewer on the same computer.
 * 3) They connect to the viewer via.

Each local plugin has its own directory within the viewer's plugins directory (e.g. Imprudence/plugins/My_Plugin_v1.0). This directory contains the files that belongs to the plugin, including the script or executable to be launched, as well as any images, sounds, data or XML files, etc. that the plugin uses.

Within its directory, the plugin has freedom about the organization and naming of almost all of its files. However, there is one file which must be present in the plugin's top-level directory and named correctly: plugin.xml. This file must contain certain information about the plugin, in an XML format (the exact format is still to be determined). The viewer reads this information to find the plugin's name, version, description, the path to the executable file to launch, the script language or executable type, names and versions of other plugins it depends on, etc.

When the viewer starts up, it scans each plugin directory and reads the plugin.xml files. It uses this information to construct a list of available plugins, and allows the user to choose which ones to activate.

When a plugin is activated, the viewer uses the information about the executable type and path to the executable file to determine how to launch the plugin. The viewer has a list of scripting languages and executable type names, along with information about how to launch executables of each type. It matches the plugin's type with one of its stored types, and uses that information to launch the plugin executable. (If the viewer does not know how to handle the plugin's type, it would display a message to the user indicating such, and maybe allowing them to set up a new rule for handling that type.)

When launching a plugin, the viewer provides that plugin with the path to a file, as the only argument to the plugin executable. The viewer will be accepting connections through that socket, and the plugin must initiate the connection.

After that point, local plugins and remote plugins behave in the same way: they negotiate the connection format and options using the Plugin Link Negotiation Protocol, introduce themselves, and then start using the API to provide their functionality.

Remote Plugins
Remote plugins are characterized by three things:


 * 1) They are launched on another computer, either manually when needed, or as a server running all the time.
 * 2) They run on a different computer than the viewer (or on another  on the same computer).
 * 3) They connect to the viewer via  &mdash; over the Internet, LAN, or other network.

Because of their remote nature (i.e. being on a different computer), the viewer does not have as direct control over remote plugins as it does over local plugins. In particular, the viewer does not launch remote plugin executables itself. Nor are there any rules about where remote plugins must be stored, what programming language they are written in, or other such details. The relationship of the viewer to a remote plugin can be likened to being "pen pals": they know each other only through the messages they exchanged.

Establishing a Connection
There are two models of how a remote plugin can establish a connection with the viewer: unsolicited and solicited. The difference lies in the way the remote plugin learns the IP address and port number of the viewer.

Unsolicited Model
Unsolicited connections are the most basic (and somewhat naïve) way. In this model, the remote plugin must already know the IP address and port number of the viewer socket. The plugin simply attempts to connect to that address, and hopes that the viewer is active and will accept the connection. If the connection fails (e.g. because the viewer isn't running), it just tries again after some time.

This model requires the least viewer-side configuration. All the viewer has to do is listen for and accept any incoming connections.

Solicited Model
In the solicited model, the plugin waits for a message from the viewer before attempting a connection. The viewer knows the address and port to contact the plugin, and sends it a brief message asking the plugin to connect, and providing the address and port the plugin should use to connect to the viewer.

This model involves more viewer-side configuration, but also gives the user more control over when the plugin connects. The viewer stores a list of entries for known remote plugins, and the user can add or remove entries from this list. The user can activate (trigger the viewer to send the message) or deactivate (conclude the connection) plugins from this list at any time. The user can also mark any plugin to have it be activated automatically at viewer startup.

Choosing The Best Model
Which model should a plugin be programmed to use? The answer depends on how the plugin will be hosted, what it does, how many people will be using it, and other such circumstances.

The unsolicited model is most appropriate when the viewer and the remote computer are both controlled by the same person, especially if the viewer is always at the same address. In that case, the plugin can be configured to know the usual address of the viewer, and it can be stopped and started at will, so that the plugin doesn't needlessly attempt to connect to a viewer that's not running.

On the other hand, the more "server-like" the plugin is, the more appropriate the solicited model is. For example, if the viewer's address is unknown or not constant, or if there are many viewers that may connect to the plugin (either separately or simultaneously), you should strongly consider the solicited model. In such a case, it's more practical to have the plugin's address remain constant, and act as a server, with the viewer reaching out to initiate the connection process.

Final Outcome
Regardless of which model the plugin uses to determine how to connect to the viewer, it behaves the same way once connected: negotiate the connection format and options with the Plugin Link Negotiation Protocol, introduce itself to the viewer, and start using the API to provide its functionality &mdash; the same process local plugins use once connected.

Access Control
One of the unfortunate side effects of allowing arbitrary remote computers to connect to the viewer, is the possibility of unwanted, even harmful connections. If every incoming connection were blindly accepted and granted access to the API, this would present a prime target to griefers, pranksters, and other unscrupulous individuals. Therefore, it is imperative that an access control system be implemented in the viewer before remote plugins can be supported.

There are many possible access control schemes that can be applied. Those listed here are all compatible with each other, and it would be wise to apply as many as is feasible.

Allow/Deny Dialogue
The most basic scheme is a simple allow/deny dialogue presented to the user when a remote plugin attempts to connect. The dialogue would be shown after the connection has been opened and some initial handshaking has taken place, but before the remote plugin has any access to the API. The remote plugin is granted access to the API only if the user allows it. If the user denies it, a "permission denied" error is sent back to the plugin and the connection is closed.

To aide the user's decision, the dialogue should display the plugin's reported name and version, and the IP address from which it is connecting. If feasible, a reverse DNS lookup would be helpful, to present the user with the domain name corresponding to that IP address.

If the connection is coming from within a local network, the dialogue should indicate such, since many users cannot identify which IP addresses indicate a LAN connection. This should likewise be done for connections coming from the same computer the viewer is running on.

Pitfalls
Although the allow/deny dialogue gives a lot of control to the user, it can also be distracting and frustrating if the user has to handle every incoming connection individually! Also, if presented with too many dialogues, clicking them becomes habitual, to the point where the user reflexively accepts every incoming connection, defeating the purpose. (See: Windows Vista's User Account Control feature.)

For these reasons, the user should be given the option of adding the plugin that triggered the dialogue to the black list or white list, discussed below. This allows unwanted plugins to be automatically refused (from the black list), and wanted plugins to be automatically accepted (from the white list), vastly reducing the number of dialogues the user has to deal with, while not restricting the user's level of control.

Black List / White List
The black list and white list are lists of remote plugins that should be automatically handled:


 * Black list: plugins that should be automatically denied every time.
 * White list: plugins that should be automatically accepted every time.

As explained in the Allow/Deny Dialogue Section, these lists helps reduce the number of plugins that the user must deal with manually.

Applying the Lists
These lists can be applied in three ways:


 * Always ask for non-listed plugins. Plugins on the black list are denied, plugins on the white list are accepted, and all other plugins trigger a dialogue asking the user what to do.
 * Deny all except white-listed plugins. Plugins on the white list are accepted, and all other plugins are denied. The black list is not used.
 * Accept all except black-listed plugins. Plugins on the black list are denied, and all other plugins are accepted. The white list is not used.
 * Note: This option is very poor security: a malicious plugin could fake its plugin name or connect from an unexpected IP address, and thus could bypass the black list and gain access to the API!

List Entries
Each entry in the lists contains a plugin name (and optional version number), an IP address, or both. This information is used to check whether or not to apply the list action (for the black list, deny; for the white list, accept) on each plugin when it connects.


 * If the host is empty, all plugins matching the plugin name (and version, if given) trigger the list action, regardless of which IP address it is connecting from.
 * Note: This way is potentially unsecure when used with the white list, because a malicous plugin could fake its name and pretend to be a plugin on your white list, and thus could gain access to the API!
 * Conversely, if the plugin name is empty, all plugins connecting from the IP address trigger the list action, regardless of the plugin name or version.
 * If both the plugin name and IP address are given, only plugins which match the name and come from that IP address will trigger the list action.

Allow Solicited Connections
TBW