Skip to content

Latest commit

 

History

History
146 lines (146 loc) · 11.4 KB

README.md

File metadata and controls

146 lines (146 loc) · 11.4 KB

Achieve-proxy is a proxy module for the Achieve server . This is an early (pre 1.0) release. It is stable but some features need more work. This guide will explain set-up and use through a few examples. Code for the examples is included with the download. The core concept is to combine achieve based web applications with proxy capabilities on the same server / port. Achieve-proxy is not yet capable of proxying to sites that use advanced authentication / authorization, such as OIDC, although that is an important goal. List of features below.

The Achieve server was originally built for use by beginning programming students and is extremely easy to use. (Easier than Express) It has since been endowed with a variety of professional features, all of which have been implemented with continued concern for efficiency, power, and ease of use in an extremely light-weight product. Backend applications are built on Achieve through JavaScript servlets. Achieve-proxy uses one or more "proxy servlets" to service one or more clients (including itself) to one or more proxied servers. HTTP and HTTPS clients are included in achieve-proxy to support direct access to external services from back-end application components.

All features are subject to improvement. Feel free to submit issues.

Current features

  • Flexible many to many proxying
  • Web-apps, proxies, external service access on same server:port
  • whitelist / blacklist (at least a start - see to do list)
  • Customization
  • Open CORS

Current To Do List

  • OIDC to Solid Linked Data Platform
  • Refine CORS control
  • Refine Whitelist / Blacklist access control
  • More customization examples, perhaps turning some into supported features.

Getting Started with Examples

Select a directory for installing and running the achieve server.

           npm i achieve-proxy

This will install both achieve-proxy and achieve.

You will find the examples directory in the node_modules achieve-proxy subdirectory. Decide where you want your top-level application directory to be. Copy the contents of the examples directory into your chosen app directory.

Move achieveserver.js from the examples directory to the achieve/achieve-proxy install directory. (This is your server start script.)

Edit achieveserver.js. Provide the path to your top-level application directory and set your port. For example:

                achieve.setAppPath("C:/programs/nodeapps"); // defaults to your server install directory (you can also use "root" - see Achieve documentation)
                const server = achieve.listen(8989);  // http defaults to port 80 (achieve options include https and http2)

Examples include a simple "helloserver" server to use as the target; proxied server: /helloserver.js. You can accept running it on port 9898 or (of course) you can edit the file to change it.

Now you can set up the proxy (or simply review). Edit achieveserver.js again. Check to see if the hello proxy has the correct target (http:localhost:9898). The property name ('/proxy/hello') is the path to the proxy from your top-level app directory. It needs to be quoted because of the slashes. The leading slash is required.

     let proxy = {
       '/proxy/hello' : {protocol: 'http:', hostname: 'localhost', port: 9898, method: 'get'},
       '/proxy/login' : {protocol: 'http:', hostname: 'localhost', port: 9898, method: 'post'},
       '/proxy/wbcontrol' : {protocol: 'http:', hostname: 'localhost', port: 9898, method: 'get'},
       '/proxy/solid' : {protocol: 'https:', hostname: 'rogerfgay.solid.hll.nu', port: 7443, method: 'post'}
     }
     achieve.setProxy(proxy);

Achieve is now configured to proxy (with your choice of ports)

           http://localhost:8989/proxy/hello -> http://localhost:9898/

Open consoles to your achieve server and helloserver directories. helloserver should be in your top-level app directory at this point. Start each. (node achieveserver and node helloserver)

Browse http://localhost:8989/proxy/hello/hello.html with the browser console open to watch for errors, including specific back-end errors: An Achieve feature. Sends specific error message instead of crashing. This feature is very solid with synchronous servlets. If the file isn't found, check your setAppPath setting + /proxy/hello to see if that adds up to the correct path.

For the second simple example, open another console to the top level application directory. requester.js is a simple http client. Edit requester.js if you need to change that achieve server port from 8989. Then, with achieveserver and helloserver still running, run node requester

Whitelist / blacklist is under development. You are welcome to look at the proxy servlet named wbcontrol.js to see what has already been used with some success. The concept is a simple list comparison. More time will be taken to explore, support, test and document options for what can / should be compared. The example compares hosts.

See Customization sections below for further thoughts on controlling access.

The examples includes a very simple illustration of customization. The proxy servlet is in [TLD]/proxy/login.js. /proxy/login is configured in the Achieve start-up script. (Be sure that it meets your approval.) The login function in the proxy servlet is not a supported feature of achieve-proxy. It's intended to point out that you can add your own custom features.

Edit requester.js to use /proxy/login. The script already has a username and password that will be sent in headers.

  path: '/proxy/login/hello.html',
 // path: '/proxy/hello/hello.html',

The custom login function in login.js also uses session.proxy.returnError() to handle the response in case of rejection. Note that if you write a custom method that handles the response, you need to set session.allowAsync = true. Otherwise, Achieve will also try to handle the response (See Achieve documentation to discover why.)

Customization and servlets generally (next example) can transform achieve-proxy from a simple pass-through to a flexible and powerful system. Access control and load balancing seem obvious examples of features you might want to add or enhance. Above, achieve-proxy is described as a many to many proxy. So far, the examples use one proxy-servlet for each target, but one proxy servlet can have more than one target. Note that it is only the key (such as '/proxy/hello') that is needed to route a request to a proxy-servlet.

You can create a custom object with any properties that you need - so long as you have custom logic in the proxy-servlet to handle it. The object will reach your proxy servlet as session.proxyOptions. Properties path and url are automatically set by achieve, but you can modify them in your custom handler. Your custom handler needs to ensure that session.proxyOptions is set properly before passing session on to proxy.run(session). It must then provide the set of options used by http(s).request(options). The proxy configuration values in achieveserver.js show the minimum set of values needed (achieve-proxy defaults: get, http, localhost, 80, 443).

You can combine proxy or custom-proxy servlet use with pre and post processing in a non-proxy servlet. Servlets are created with a JavaScript file containing:

          exports.servlet = function (session) {
            // When synchronous with a string response, simply use a return statement
            // Achieve (synchronous) also passes error information back to the client rather than crashing
            // When your code handles the response (required with async), set session.allowAsync=true 
          }

The URL is formed by using the http path to the JavaScript file without the .js extension. The file itself must have the .js extension. There is no need to restart the server when you edit a servlet file. Achieve detects changes and automatically reloads when needed. When using asynchronous code in your servlets, you need to set session.allowAsync = true. This will tell Achieve not to handle the http response. For more information on JavaScript servlets read the Achieve documentation.

To say that my work on proxying to a Solid server has met with limited success could very well be an overstatement. I have retrieved public resources from Solid, which can be done with an ordinary fetch. Nonetheless, working with Solid provided the motivation to create this module and I have included an example that uses solid-auth-client in the browser. Based on expert advice, I will switch to another client app in further efforts.

The example goes directly to the Solid server for login and then attempts to fetch resources. It works for private resources when solid-auth-client goes directly to Solid to fetch, but not when going through the proxy where it suffers authorization failure. (Agent is null ...) I spent a good bit of time trying to sort this out before deciding on an early release of this module.

The webpage is index.htm in your top-level app directory. URLs indicating idp and path to the solid proxy servlet are at the bottom of the script section in index.htm. Modify the proxy configuration in the achieve startup script (achieveserver.js) with your own pod address.

If you can provide expert guidance, please open an issue on github or add to the topic at the Solid forum.

Copyright and License

copyright © 2020, Roger F. Gay, may be freely distributed with the MIT license