Web Manager

In v3.3.0, the previous version of blueprint was restored and enhanced, and the plugin installation function was added.

You can register blueprint in your web application and set the blueprint prefix. The steps are as follows:

from flask import Flask
from flask_pluginkit import PluginManager, blueprint
app = Flask(__name__)
PluginManager.init_app(app)
app.register_blueprint(blueprint, url_prefix='/pluginmanager')

Launch the app, visit the /pluginmanager page, take our example-fulldemo as an example, the rendering is:

_images/webmanager-en.png

This page supports Chinese and English bilingual(The picture is old, the new version supports the language of choice), the following is the Chinese page effect:

_images/webmanager-cn.png

Instructions

This blueprint has only one page. This page contains three main features:

  • Disable, Enable Plugins

  • Reload Application

    Disabling or enabling plugins will require a reloaded application to take effect. For security reasons, there are some restrictions on overloaded applications.

    It can only be used in a formal environment that uses Gunicorn or uWSGI background startup, and requires that the value of ENV in the application’s configuration item be production, and you also need to manually install the psutil module, eg: pip install psutil.

    If you use Gunicorn, you need the value of PLUGINKIT_GUNICORN_ENABLED in the application’s configuration item to be True, and the value of PLUGINKIT_PROCESSNAME is the specific program process name.

    Note

    Gunicorn starts in master-worker mode in the background. The required PLUGINKIT_PROCESSNAME is the name of the master process. It does not contain gunicorn: master [], which is the process name in []. There is no default value.

    If you use uWSGI, you need the value of the application configuration item PLUGINKIT_UWSGI_ENABLED to be True, PLUGINKIT_PROCESSNAME is uwsgi by default, generally speaking, you don’t have to modify it.

    The application can be reloaded normally after the appeal is met. Here is an example:

    $ pip install psutil
    
    $ cat app.py
    
    from flask_pluginkit import Flask, blueprint, PluginManager
    app = Flask(__name__)
    app.config.update(
        ENV='production',
        PLUGINKIT_GUNICORN_ENABLED=True,
        PLUGINKIT_PROCESSNAME="app:app"
    )
    pm = PluginManager(app)
    app.register_blueprint(blueprint, url_prefix='/pluginmanager')
    
    $ gunicorn -b 127.0.0.1:5000 app:app --daemon
    
    $ ps aux | grep -v grep | grep gunicorn
    
    root   master-pid   ......   gunicorn: master [app:app]
    root   worker-pid   ......   gunicorn: worker [app:app]
    

    Tip

    Flask v1.0 has an ENV configuration added. The default value is production.

  • Install Plugins

    The first two operations are simple, and the third feature requires detailed instructions.

    There are three situations for installing plugins:

    • Upload Local Plugin

      This will upload a compressed file to your server’s temp directory and extract it to the web application’s plugin directory (controlled by __init__()). Repeatedly uploading a compressed file will overwrite the uncompressed file.

    • Download Remote Plugin

      Similar to the above situation, instead of uploading the local compressed file, download the remote compressed file to the temporary directory of your server. The subsequent steps are the same as above.

      The remote url here is very strict. It must be a valid download address for compressed file and can resolve valid file names(That is, the file suffix is .tar.gz, .tgz or .zip). It is worth mentioning that Flask-PluginKit provides four methods to automatically obtain the file name of the remote url. Basically meet the requirements(Number Represents Priority):

      1. Add url plugin_filename query parameters

      2. The file name is resolved in the url

      3. Parse the Content-Disposition in the return header

      4. Parse the Content-Type in the return header

      Examples of valid URL parameters in the input box:

      for 1, http://xx.com/download?plugin_filename=xx.zip
      for 2, http://xx.xx.com/plugin-v0.0.1.tar.gz
      for 3 and 4, https://codeload.github.com/saintic/flask-pluginkit-demo/zip/master
      
    • Install Package

      This situation is new. It relies on the interface of the pip module to directly install the remote compression package. It can be a pypi package or a VCS project URL. It can be directly installed into the python global environment. You need to manually pass the plugin_packages call.

      Example of input box parameters:

      flask-pluginkit-valine
      git+https://github.com/saintic/flask-pluginkit-demo@master
      

      Note

      Since it takes time to install the module, this will turn on thread processing. After the installation is successful, it will be handed over to a message queue. The page will query the message every 5 seconds and display it.

Authentication

The web management page is actually dangerous for administrators. If others are free to access, it may be harmful to the system. Therefore, before accessing this blueprint, a hook function is run to authenticate the visitor.

Verify that the visitor currently supports four main methods and one helper method. The former is defined by the application configuration item PLUGINKIT_AUTH_METHOD, which is defined by PLUGINKIT_AUTH_AID_METHOD.

  • PLUGINKIT_AUTH_METHOD, supports four types of values.

    • BOOL

      This method will get the value of the PLUGINKIT_AUTH_BOOLFIELD field in the configuration via flask.g (the default value is signin). When it is True, it will be verified.

      Example:

      from flask import Flask, g
      from flask_pluginkit import blueprint, PluginManager
      app = Flask(__name__)
      pm = PluginManager(app)
      app.config.update(
          PLUGINKIT_AUTH_METHOD="BOOL",
          PLUGINKIT_AUTH_BOOLFIELD="auth"
      )
      app.register_blueprint(blueprint, url_prefix='/pluginmanager')
      
      @app.before_request
      def br():
          g.auth = True
      
    • BASIC

      HTTP Basic Auth, a simple but unsafe method, this method requires username and password, so the application configuration item PLUGINKIT_AUTH_USERS is required, which is a dict, the key is username, the value is password, and multiple keys and values are supported. Optional configuration PLUGINKIT_AUTH_REALM to set the prompt information.

      Example:

      from flask_pluginkit import Flask, blueprint, PluginManager
      app = Flask(__name__)
      pm = PluginManager(app)
      app.config.update(
          PLUGINKIT_AUTH_METHOD="BASIC",
          PLUGINKIT_AUTH_USERS=dict(admin="admin", test="test")
      )
      app.register_blueprint(blueprint, url_prefix='/pluginmanager')
      
    • TOKEN

      This requires the browser to carry an authentication header. The header field is defined by the application configuration item PLUGINKIT_AUTH_TOKENFIELD. The default value is AccessToken. At the same time, it is required to configure a function or class method named PLUGINKIT_AUTH_CHECKTOKEN. Receiving a token parameter, Flask-PluginKit will execute this function, and the result will be verified when the non-zero and non-empty.

      Example:

      from flask_pluginkit import Flask, blueprint, PluginManager
      app = Flask(__name__)
      pm = PluginManager()
      pm.init_app(app)
      
      def check_token(token):
          if token == 'test':
              return True
      
      app.config.update(
          PLUGINKIT_AUTH_METHOD="TOKEN",
          PLUGINKIT_AUTH_CHECKTOKEN=check_token
      )
      app.register_blueprint(blueprint, url_prefix='/pluginmanager')
      
    • FUNC

      This should be the easiest, defined by the application configuration item PLUGINKIT_AUTH_FUNC, a function or class method, etc, no parameters, the execution result is non-zero and non-empty when the verification is passed.

      Example:

      from flask_pluginkit import Flask, blueprint, PluginManager
      app = Flask(__name__)
      PluginManager(app)
      app.config.update(
          PLUGINKIT_AUTH_METHOD="FUNC",
          PLUGINKIT_AUTH_FUNC=lambda :True
      )
      app.register_blueprint(blueprint, url_prefix='/pluginmanager')
      
  • PLUGINKIT_AUTH_AID_METHOD, supports one type of value.

    • IP

      Flask-pluginkit will get the client IP, requires application configuration item PLUGINKIT_AUTH_IP_WHITELIST to define IP whitelist, and PLUGINKIT_AUTH_IP_BLACKLIST to define IP blacklist. Both data types are lists, and only when IP is in the whitelist and not on the blacklist, it can be verified.

      Example:

      from flask_pluginkit import Flask, blueprint, PluginManager
      app = Flask(__name__)
      PluginManager(app)
      app.config.update(
          PLUGINKIT_AUTH_AID_METHOD="IP",
          PLUGINKIT_AUTH_IP_WHITELIST=["127.0.0.1"]
      )
      app.register_blueprint(blueprint, url_prefix='/pluginmanager')
      

Note

In an application, the four types of the main method can only be used one or not; the auxiliary method can be used with the main method at the same time, or it can be used alone; in any case, there must be a verification method, otherwise the page prompt permission is rejected.