mirror of https://github.com/nucypher/nucypher.git
commit
a161480277
|
@ -462,7 +462,7 @@ commands:
|
|||
- run: sudo chown -R circleci:circleci /usr/local/bin
|
||||
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
|
||||
- save_cache:
|
||||
key: pip-v8-{{ .Branch }}-{{ checksum "Pipfile.lock" }}
|
||||
key: pip-v9-{{ .Branch }}-{{ checksum "Pipfile.lock" }}
|
||||
paths:
|
||||
- "~/.local/bin"
|
||||
- "~/.local/lib/python3.7/site-packages"
|
||||
|
@ -477,7 +477,7 @@ commands:
|
|||
- run: sudo chown -R circleci:circleci /usr/local/bin
|
||||
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
|
||||
- restore_cache: # ensure this step occurs *before* installing dependencies
|
||||
key: pip-v8-{{ .Branch }}-{{ checksum "Pipfile.lock" }}
|
||||
key: pip-v9-{{ .Branch }}-{{ checksum "Pipfile.lock" }}
|
||||
- restore_cache:
|
||||
key: solc-v2-{{ checksum "nucypher/blockchain/eth/sol/__conf__.py" }}
|
||||
|
||||
|
@ -869,7 +869,7 @@ jobs:
|
|||
- setup_remote_docker
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v2-{{ .Branch }}-{{ arch }}
|
||||
- v3-{{ .Branch }}-{{ arch }}
|
||||
paths:
|
||||
- ~/docker/nucypher-porter.tar
|
||||
- run:
|
||||
|
@ -887,7 +887,7 @@ jobs:
|
|||
mkdir -p ~/docker
|
||||
docker save -o ~/docker/nucypher-porter.tar nucypher/porter:circle
|
||||
- save_cache:
|
||||
key: v2-{{ .Branch }}-{{ arch }}
|
||||
key: v3-{{ .Branch }}-{{ arch }}
|
||||
paths:
|
||||
- ~/docker/nucypher-porter.tar
|
||||
|
||||
|
@ -977,7 +977,7 @@ jobs:
|
|||
- setup_remote_docker
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v2-{{ .Branch }}-{{ arch }}
|
||||
- v3-{{ .Branch }}-{{ arch }}
|
||||
paths:
|
||||
- ~/docker/nucypher-porter.tar
|
||||
- run:
|
||||
|
|
|
@ -16,7 +16,8 @@ services:
|
|||
- ~/.local/share/nucypher:/nucypher
|
||||
command: ["nucypher", "porter", "run",
|
||||
"--provider", "${WEB3_PROVIDER_URI}",
|
||||
"--network", "${NUCYPHER_NETWORK}"]
|
||||
"--network", "${NUCYPHER_NETWORK}",
|
||||
"--allow-origins", "${PORTER_CORS_ALLOW_ORIGINS}"] # empty string if env var not defined which translates to CORS not enabled by default
|
||||
|
||||
porter-https:
|
||||
restart: on-failure
|
||||
|
@ -33,7 +34,8 @@ services:
|
|||
"--provider", "${WEB3_PROVIDER_URI}",
|
||||
"--network", "${NUCYPHER_NETWORK}",
|
||||
"--tls-key-filepath", "/etc/porter/tls/key.pem",
|
||||
"--tls-certificate-filepath", "/etc/porter/tls/cert.pem"]
|
||||
"--tls-certificate-filepath", "/etc/porter/tls/cert.pem",
|
||||
"--allow-origins", "${PORTER_CORS_ALLOW_ORIGINS}"] # empty string if env var not defined which translates to CORS not enabled by default
|
||||
|
||||
porter-https-auth:
|
||||
restart: on-failure
|
||||
|
@ -52,4 +54,5 @@ services:
|
|||
"--network", "${NUCYPHER_NETWORK}",
|
||||
"--tls-key-filepath", "/etc/porter/tls/key.pem",
|
||||
"--tls-certificate-filepath", "/etc/porter/tls/cert.pem",
|
||||
"--basic-auth-filepath", "/etc/porter/auth/htpasswd"]
|
||||
"--basic-auth-filepath", "/etc/porter/auth/htpasswd",
|
||||
"--allow-origins", "${PORTER_CORS_ALLOW_ORIGINS}"] # empty string if env var not defined which translates to CORS not enabled by default
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
FROM nginxproxy/nginx-proxy:alpine
|
||||
|
||||
# Copy porter.local virtual host location configuration file
|
||||
COPY ./deploy/docker/porter/nginx/porter.local_location /etc/nginx/vhost.d/
|
|
@ -0,0 +1,37 @@
|
|||
version: '3'
|
||||
|
||||
services:
|
||||
|
||||
nginx-proxy:
|
||||
restart: always
|
||||
image: nginxproxy/nginx-proxy:alpine
|
||||
build:
|
||||
context: ../../../..
|
||||
dockerfile: deploy/docker/porter/nginx/Dockerfile
|
||||
ports:
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
# because of the vhost name used below, the cert and key should be named "porter.local.crt" and "porter.local.key" respectively
|
||||
- "${TLS_DIR}:/etc/nginx/certs/"
|
||||
|
||||
nginx-porter:
|
||||
restart: on-failure
|
||||
image: porter:latest
|
||||
build:
|
||||
context: ../../../..
|
||||
dockerfile: deploy/docker/porter/Dockerfile
|
||||
expose:
|
||||
# Default Porter port
|
||||
- "9155"
|
||||
volumes:
|
||||
- .:/code
|
||||
- ~/.local/share/nucypher:/nucypher
|
||||
command: [ "nucypher", "porter", "run",
|
||||
"--provider", "${WEB3_PROVIDER_URI}",
|
||||
"--network", "${NUCYPHER_NETWORK}" ]
|
||||
environment:
|
||||
- VIRTUAL_HOST=porter.local
|
||||
- VIRTUAL_PORT=9155
|
||||
depends_on:
|
||||
- nginx-proxy
|
|
@ -0,0 +1,27 @@
|
|||
set $allow_origin "";
|
||||
|
||||
#
|
||||
# Allow CORS for any domain by default - comment out if not desired
|
||||
#
|
||||
if ($http_origin ~* (.*)) {
|
||||
set $allow_origin "true";
|
||||
}
|
||||
|
||||
#
|
||||
# Allow CORS for specific domain. For specifying conditions, see https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if.
|
||||
# Uncomment and edit if desired. There can be one or more of these 'if' directives for various origin checks.
|
||||
#
|
||||
#if ($http_origin ~* (.*\.yourdomain\.com$)) {
|
||||
# set $allow_origin "true";
|
||||
#}
|
||||
|
||||
#
|
||||
# For multiple top-level domains:
|
||||
#
|
||||
#if ($http_origin ~* (.*\.yourdomain\.(com|org)$)) {
|
||||
# set $allow_origin "true";
|
||||
#}
|
||||
|
||||
if ($allow_origin = "true") {
|
||||
add_header 'Access-Control-Allow-Origin' '$http_origin';
|
||||
}
|
|
@ -21,6 +21,16 @@ web and mobile experience is accessible to application developers.
|
|||
Running Porter
|
||||
--------------
|
||||
|
||||
There are a variety of possible infrastructure setups for running the Porter service, and two scenarios for running
|
||||
the Porter service are provided here:
|
||||
|
||||
#. Run the Porter service directly via docker, docker-compose, or the CLI (see `Run Porter Directly`_)
|
||||
#. Run the Porter service with a reverse proxy via docker-compose (see `Run Porter with Reverse Proxy`_)
|
||||
|
||||
|
||||
Run Porter Directly
|
||||
*******************
|
||||
|
||||
.. note::
|
||||
|
||||
If running the Porter service using Docker or Docker Compose, it will run on port 80 (HTTP) or 443 (HTTPS). If
|
||||
|
@ -29,32 +39,33 @@ Running Porter
|
|||
Security
|
||||
^^^^^^^^
|
||||
|
||||
HTTPS
|
||||
+++++
|
||||
To run the Porter service over HTTPS, it will require a TLS key (``--tls-key-filepath`` option) and a TLS certificate.
|
||||
* **HTTPS:** To run the Porter service over HTTPS, it will require a TLS key and a TLS certificate. These can be
|
||||
specified via the `` --tls-key-filepath`` and ``--tls-certificate-filepath`` CLI options or via the ``TLS_DIR``
|
||||
environment variable for docker-compose.
|
||||
* **CORS:** Allowed origins for `Cross-Origin Resource Sharing (CORS) <https://en.wikipedia.org/wiki/Cross-origin_resource_sharing>`_
|
||||
is not enabled by default and can be enabled either via the ``--allow-origins`` option for the CLI,
|
||||
or the ``PORTER_CORS_ALLOW_ORIGINS`` environment variable for docker-compose.
|
||||
|
||||
If desired, keys and self-signed certificates can be created for the localhost using the ``openssl`` command:
|
||||
The value is expected to be a comma-delimited list of strings/regular expressions for origins to allow requests from. To allow all origins,
|
||||
simply use "*".
|
||||
|
||||
.. code:: bash
|
||||
.. note::
|
||||
|
||||
$ openssl req -x509 -out cert.pem -keyout key.pem \
|
||||
-newkey rsa:2048 -nodes -sha256 \
|
||||
-subj '/CN=localhost' -extensions EXT -config <( \
|
||||
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
|
||||
Origin values can be a string (for exact matches) or regular expressions (for more complex matches).
|
||||
|
||||
.. important::
|
||||
As part of CORS, the scheme (``https`` or ``http``) is also checked, so using only ``example.com`` is incorrect
|
||||
to allow an origin from that specific domain. For exact matches, you can use ``https://example.com`` for HTTPS or
|
||||
``http://example.com`` for HTTP. For non-default ports (i.e. not 443 or 80), the ports should be specified
|
||||
e.g. ``https://example.com:8000`` or ``http://example.com:8001``.
|
||||
|
||||
Self-signed certificates are not recommended, other than for testing.
|
||||
For regular expressions, to allow all sub-domains of ``example.com``, you could use ``.*\.example\.com$`` which
|
||||
incorporates wildcards for scheme and sub-domain. To allow multiple top-level domains you could use
|
||||
``.*\.example\.(com|org)$`` which allows any origins from both ``example.com`` and ``example.org`` domains.
|
||||
|
||||
|
||||
Authentication
|
||||
++++++++++++++
|
||||
Porter will allow the configuration of Basic Authentication out of the box via
|
||||
an `htpasswd <https://httpd.apache.org/docs/2.4/programs/htpasswd.html>`_ file. The use of Basic Authentication
|
||||
necessitates HTTPS since user credentials will be passed over the network as cleartext.
|
||||
|
||||
Alternative authentication mechanisms can be implemented outside of Porter via an intermediary proxy service, for
|
||||
example an Nginx HTTPS reverse proxy.
|
||||
* **Authentication:** Porter will allow the configuration of Basic Authentication out of the box via
|
||||
an `htpasswd <https://httpd.apache.org/docs/2.4/programs/htpasswd.html>`_ file. This file can be provided via the
|
||||
``--basic-auth-filepath`` CLI option or ``HTPASSWD_FILE`` environment variable for docker-compose. The use
|
||||
of Basic Authentication necessitates HTTPS since user credentials will be passed over the network as cleartext.
|
||||
|
||||
|
||||
via Docker
|
||||
|
@ -101,6 +112,23 @@ Run Porter within Docker without acquiring or installing the ``nucypher`` codeba
|
|||
--tls-key-filepath /etc/porter/tls/<KEY FILENAME> \
|
||||
--tls-certificate-filepath /etc/porter/tls/<CERT FILENAME>
|
||||
|
||||
* Without Basic Authentication, but with CORS enabled to allow all origins:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ docker run -d --rm \
|
||||
--name porter-https-cors \
|
||||
-v ~/.local/share/nucypher/:/root/.local/share/nucypher \
|
||||
-v <TLS DIRECTORY>:/etc/porter/tls \
|
||||
-p 443:9155 \
|
||||
nucypher/porter:latest \
|
||||
nucypher porter run \
|
||||
--provider <YOUR WEB3 PROVIDER URI> \
|
||||
--network <NETWORK NAME> \
|
||||
--tls-key-filepath /etc/porter/tls/<KEY FILENAME> \
|
||||
--tls-certificate-filepath /etc/porter/tls/<CERT FILENAME> \
|
||||
--allow-origins "*"
|
||||
|
||||
* With Basic Authentication:
|
||||
|
||||
.. code:: bash
|
||||
|
@ -119,17 +147,23 @@ Run Porter within Docker without acquiring or installing the ``nucypher`` codeba
|
|||
--tls-certificate-filepath /etc/porter/tls/<CERT FILENAME> \
|
||||
--basic-auth-filepath /etc/porter/auth/htpasswd
|
||||
|
||||
|
||||
The ``<TLS DIRECTORY>`` is expected to contain the TLS key file (``<KEY FILENAME>``) and the
|
||||
certificate (``<CERT FILENAME>``) to run Porter over HTTPS.
|
||||
|
||||
.. note::
|
||||
|
||||
The commands above are for illustrative purposes and can be modified as necessary.
|
||||
|
||||
#. Porter will be available on default ports 80 (HTTP) or 443 (HTTPS). The porter service running will be one of
|
||||
the following depending on the mode chosen:
|
||||
|
||||
* ``porter-http``
|
||||
* ``porter-https``
|
||||
* ``porter-https-cors``
|
||||
* ``porter-https-auth``
|
||||
|
||||
|
||||
#. View Porter logs
|
||||
|
||||
.. code:: bash
|
||||
|
@ -148,7 +182,7 @@ via Docker Compose
|
|||
|
||||
Docker Compose will start the Porter service within a Docker container.
|
||||
|
||||
#. Acquire the ``nucypher`` codebase - see :ref:`acquire_codebase`. There is no need
|
||||
#. :ref:`acquire_codebase`. There is no need
|
||||
to install ``nucypher`` after acquiring the codebase since Docker will be used.
|
||||
|
||||
#. Set the required environment variables:
|
||||
|
@ -170,7 +204,8 @@ Docker Compose will start the Porter service within a Docker container.
|
|||
|
||||
$ export NUCYPHER_NETWORK=<NETWORK NAME>
|
||||
|
||||
* *(Optional)* TLS directory variable containing the TLS key and the certificate to run Porter over HTTPS. The directory is expected to contain two files:
|
||||
* *(Optional)* TLS directory containing the TLS key and certificate to run Porter over HTTPS.
|
||||
The directory is expected to contain two files:
|
||||
|
||||
* ``key.pem`` - the TLS key
|
||||
* ``cert.pem`` - the TLS certificate
|
||||
|
@ -181,6 +216,12 @@ Docker Compose will start the Porter service within a Docker container.
|
|||
|
||||
$ export TLS_DIR=<ABSOLUTE PATH TO TLS DIRECTORY>
|
||||
|
||||
* *(Optional)* Enable CORS. For example, to only allow access from your sub-domains for ``example.com``:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ export PORTER_CORS_ALLOW_ORIGINS=".*\.example\.com$"
|
||||
|
||||
* *(Optional)* Filepath to the htpasswd file for Basic Authentication
|
||||
|
||||
Set the htpasswd filepath environment variable
|
||||
|
@ -211,13 +252,15 @@ Docker Compose will start the Porter service within a Docker container.
|
|||
|
||||
$ docker-compose -f deploy/docker/porter/docker-compose.yml up -d porter-https-auth
|
||||
|
||||
#. Porter will be available on default ports 80 (HTTP) or 443 (HTTPS). The porter service running will be one of
|
||||
|
||||
Porter will be available on default ports 80 (HTTP) or 443 (HTTPS). The porter service running will be one of
|
||||
the following depending on the mode chosen:
|
||||
|
||||
* ``porter-http``
|
||||
* ``porter-https``
|
||||
* ``porter-https-auth``
|
||||
|
||||
|
||||
#. View Porter logs
|
||||
|
||||
.. code:: bash
|
||||
|
@ -261,7 +304,6 @@ For a full list of CLI options, run:
|
|||
|
||||
the Pipe for nucypher network operations
|
||||
|
||||
Reading Latest Chaindata...
|
||||
Network: <NETWORK NAME>
|
||||
Provider: ...
|
||||
Running Porter Web Controller at http://127.0.0.1:9155
|
||||
|
@ -284,16 +326,15 @@ For a full list of CLI options, run:
|
|||
|
||||
the Pipe for nucypher network operations
|
||||
|
||||
Reading Latest Chaindata...
|
||||
Network: <NETWORK NAME>
|
||||
Provider: ...
|
||||
Running Porter Web Controller at https://127.0.0.1:9155
|
||||
|
||||
For HTTPS with Basic Authentication, add the ``--basic-auth-filepath`` option:
|
||||
To enable CORS, use the ``--allow-origins`` option:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ nucypher porter run --provider <YOUR WEB3 PROVIDER URI> --network <NETWORK NAME> --tls-key-filepath <TLS KEY FILEPATH> --tls-certificate-filepath <CERT FILEPATH> --basic-auth-filepath <HTPASSWD FILE>
|
||||
$ nucypher porter run --provider <YOUR WEB3 PROVIDER URI> --network <NETWORK NAME> --tls-key-filepath <TLS KEY FILEPATH> --tls-certificate-filepath <CERT FILEPATH> --allow-origins ".*\.example\.com$"
|
||||
|
||||
|
||||
______
|
||||
|
@ -305,18 +346,139 @@ For a full list of CLI options, run:
|
|||
|
||||
the Pipe for nucypher network operations
|
||||
|
||||
Reading Latest Chaindata...
|
||||
Network: <NETWORK NAME>
|
||||
Provider: ...
|
||||
CORS Allow Origins: ['.*\\.example\\.com$']
|
||||
Running Porter Web Controller at https://127.0.0.1:9155
|
||||
|
||||
To enable Basic Authentication, add the ``--basic-auth-filepath`` option:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ nucypher porter run --provider <YOUR WEB3 PROVIDER URI> --network <NETWORK NAME> --tls-key-filepath <TLS KEY FILEPATH> --tls-certificate-filepath <CERT FILEPATH> --allow-origins ".*\.example\.com$" --basic-auth-filepath <HTPASSWD FILE>
|
||||
|
||||
|
||||
______
|
||||
(_____ \ _
|
||||
_____) )__ ____| |_ ____ ____
|
||||
| ____/ _ \ / ___) _)/ _ )/ ___)
|
||||
| | | |_| | | | |_( (/ /| |
|
||||
|_| \___/|_| \___)____)_|
|
||||
|
||||
the Pipe for nucypher network operations
|
||||
|
||||
Network: <NETWORK NAME>
|
||||
Provider: ...
|
||||
CORS Allow Origins: ['.*\\.example\\.com$']
|
||||
Basic Authentication enabled
|
||||
Running Porter Web Controller at https://127.0.0.1:9155
|
||||
|
||||
|
||||
Run Porter with Reverse Proxy
|
||||
*****************************
|
||||
|
||||
This type of Porter execution illustrates the use of a reverse proxy that is a go between or intermediate server that
|
||||
handles requests from clients to an internal Porter service. An NGINX reverse proxy instance is
|
||||
used in this case. It will handle functionality such as TLS, CORS, and authentication so that the Porter service
|
||||
itself does not have to, and allows for more complex configurations than provided by Porter itself. More information
|
||||
about the NGINX reverse proxy docker image used and additional configuration options
|
||||
is available `here <https://hub.docker.com/r/nginxproxy/nginx-proxy>`_.
|
||||
|
||||
|
||||
via Docker Compose
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Docker Compose will be used to start the NGINX reverse proxy and the Porter service containers.
|
||||
|
||||
#. :ref:`acquire_codebase`. There is no need
|
||||
to install ``nucypher`` after acquiring the codebase since Docker will be used.
|
||||
|
||||
#. Set the required environment variables:
|
||||
|
||||
* Web3 Provider URI environment variable
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ export WEB3_PROVIDER_URI=<YOUR WEB3 PROVIDER URI>
|
||||
|
||||
.. note::
|
||||
|
||||
Local ipc is not supported when running via Docker.
|
||||
|
||||
|
||||
* Network Name environment variable
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ export NUCYPHER_NETWORK=<NETWORK NAME>
|
||||
|
||||
* The reverse proxy is set up to run over HTTPS by default, and therefore requires a TLS directory containing
|
||||
the TLS key and certificate for the reverse proxy. The directory is expected to contain two files:
|
||||
|
||||
* ``porter.local.key`` - the TLS key
|
||||
* ``porter.local.crt`` - the TLS certificate
|
||||
|
||||
Set the TLS directory environment variable
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ export TLS_DIR=<ABSOLUTE PATH TO TLS DIRECTORY>
|
||||
|
||||
* *(Optional)* The CORS configuration is set in the ``nucypher/deploy/docker/porter/nginx/porter.local_location`` file.
|
||||
|
||||
.. important::
|
||||
|
||||
By default, CORS for the reverse proxy is configured to allow all origins
|
||||
|
||||
If you would like to modify the CORS allowed origin setting to be more specific, you can modify the file to
|
||||
check for specific domains. There are some examples in the file - see `NGINX if-directive <https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if>`_
|
||||
for adding ore complex conditional checks.
|
||||
|
||||
For example, to only allow requests from all sub-domains of ``example.com``, the file should be edited to include:
|
||||
|
||||
.. code::
|
||||
|
||||
if ($http_origin ~* (.*\.example\.com$)) {
|
||||
set $allow_origin "true";
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
If you modify the file you should rebuild the docker images using docker-compose.
|
||||
|
||||
#. *(Optional)* Build the docker images:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ docker-compose -f deploy/docker/porter/nginx/docker-compose.yml build
|
||||
|
||||
#. Run the NGINX reverse proxy and Porter service
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ docker-compose -f deploy/docker/porter/nginx/docker-compose.yml up -d
|
||||
|
||||
#. The NGINX reverse proxy will be publicly accessible via the default HTTPS port 443, and will route requests to the
|
||||
internal Porter service.
|
||||
|
||||
#. View Porter service logs
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ docker-compose -f deploy/docker/porter/nginx/docker-compose.yml logs -f nginx-porter
|
||||
|
||||
#. Stop Porter service and NGINX reverse proxy
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ docker-compose -f deploy/docker/porter/nginx/docker-compose.yml down
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
Status Codes
|
||||
^^^^^^^^^^^^
|
||||
************
|
||||
All documented API endpoints use JSON and are REST-like.
|
||||
|
||||
Some common returned status codes you may encounter are:
|
||||
|
@ -346,7 +508,7 @@ GitHub issue. For any questions, message us in our `Discord <https://discord.gg/
|
|||
|
||||
|
||||
URL Query Parameters
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
********************
|
||||
All parameters can be passed as either JSON data within the request or as query parameter strings in the URL.
|
||||
Query parameters used within the URL will need to be URL encoded e.g. ``/`` in a base64 string becomes ``%2F`` etc.
|
||||
|
||||
|
@ -374,12 +536,12 @@ More examples shown below.
|
|||
|
||||
|
||||
GET /get_ursulas
|
||||
^^^^^^^^^^^^^^^^
|
||||
****************
|
||||
Sample available Ursulas for a policy as part of Alice's ``grant`` workflow. Returns a list of Ursulas
|
||||
and their associated information that is used for the policy.
|
||||
|
||||
Parameters
|
||||
++++++++++
|
||||
^^^^^^^^^^
|
||||
+----------------------------------+---------------+-----------------------------------------------+
|
||||
| **Parameter** | **Type** | **Description** |
|
||||
+==================================+===============+===============================================+
|
||||
|
@ -398,7 +560,7 @@ Parameters
|
|||
|
||||
|
||||
Returns
|
||||
+++++++
|
||||
^^^^^^^
|
||||
List of Ursulas with associated information:
|
||||
|
||||
* ``encrypting_key`` - Ursula's encrypting key encoded as hex
|
||||
|
@ -406,7 +568,7 @@ List of Ursulas with associated information:
|
|||
* ``uri`` - Ursula's URI
|
||||
|
||||
Example Request
|
||||
+++++++++++++++
|
||||
^^^^^^^^^^^^^^^
|
||||
.. code:: bash
|
||||
|
||||
curl -X GET <PORTER URI>/get_ursulas \
|
||||
|
@ -424,7 +586,7 @@ OR
|
|||
|
||||
|
||||
Example Response
|
||||
++++++++++++++++
|
||||
^^^^^^^^^^^^^^^^
|
||||
.. code::
|
||||
|
||||
Status: 200 OK
|
||||
|
@ -467,11 +629,11 @@ Example Response
|
|||
|
||||
|
||||
POST /retrieve_cfrags
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
*********************
|
||||
Get data re-encrypted by the network as part of Bob's ``retrieve`` workflow.
|
||||
|
||||
Parameters
|
||||
++++++++++
|
||||
^^^^^^^^^^
|
||||
+-------------------------------------------+---------------+----------------------------------------+
|
||||
| **Parameter** | **Type** | **Description** |
|
||||
+===========================================+===============+========================================+
|
||||
|
@ -515,7 +677,7 @@ Parameters
|
|||
retry functionality that skips previously successful reencryption operations.
|
||||
|
||||
Returns
|
||||
+++++++
|
||||
^^^^^^^
|
||||
The result of the re-encryption operations performed:
|
||||
|
||||
* ``retrieval_results`` - The list of results from the re-encryption operations performed; contains a mapping of
|
||||
|
@ -524,7 +686,7 @@ The result of the re-encryption operations performed:
|
|||
*retrieval kit*, the corresponding list of cfrags could be empty or less than the expected threshold.
|
||||
|
||||
Example Request
|
||||
+++++++++++++++
|
||||
^^^^^^^^^^^^^^^
|
||||
.. code:: bash
|
||||
|
||||
curl -X POST <PORTER URI>/retrieve_cfrags \
|
||||
|
@ -544,7 +706,7 @@ OR
|
|||
|
||||
|
||||
Example Response
|
||||
++++++++++++++++
|
||||
^^^^^^^^^^^^^^^^
|
||||
.. code::
|
||||
|
||||
Status: 200 OK
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fixed WebController bug caused by Path object for TLS/certificate path provided to Hendrix instead of a string.
|
|
@ -0,0 +1,3 @@
|
|||
CORS, NGINX support for Porter:
|
||||
- Added opt-in CORS origins support to Porter; no origins allowed by default when running Porter directly.
|
||||
- Provided docker-compose execution for Porter to run behind an NGINX reverse proxy server - all origins allowed by default for CORS, but can be customized. NGINX allows for the potential for more complex infrastructure configurations.
|
|
@ -21,8 +21,13 @@ import click
|
|||
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||
from nucypher.characters.lawful import Ursula
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED, PORTER_RUN_MESSAGE, \
|
||||
BASIC_AUTH_REQUIRES_HTTPS
|
||||
from nucypher.cli.literature import (
|
||||
PORTER_BASIC_AUTH_ENABLED,
|
||||
PORTER_BASIC_AUTH_REQUIRES_HTTPS,
|
||||
PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED,
|
||||
PORTER_CORS_ALLOWED_ORIGINS,
|
||||
PORTER_RUN_MESSAGE,
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
option_network,
|
||||
option_provider_uri,
|
||||
|
@ -34,7 +39,6 @@ from nucypher.cli.options import (
|
|||
from nucypher.cli.types import NETWORK_PORT
|
||||
from nucypher.cli.utils import setup_emitter, get_registry
|
||||
from nucypher.config.constants import TEMPORARY_DOMAIN
|
||||
from nucypher.utilities.porter.control.interfaces import PorterInterface
|
||||
from nucypher.utilities.porter.porter import Porter
|
||||
|
||||
|
||||
|
@ -58,6 +62,7 @@ def porter():
|
|||
@click.option('--tls-certificate-filepath', help="Pre-signed TLS certificate filepath", type=click.Path(dir_okay=False, exists=True, path_type=Path))
|
||||
@click.option('--tls-key-filepath', help="TLS private key filepath", type=click.Path(dir_okay=False, exists=True, path_type=Path))
|
||||
@click.option('--basic-auth-filepath', help="htpasswd filepath for basic authentication", type=click.Path(dir_okay=False, exists=True, resolve_path=True, path_type=Path))
|
||||
@click.option('--allow-origins', help="The CORS origin(s) comma-delimited list of strings/regexes for origins to allow - no origins allowed by default", type=click.STRING)
|
||||
@click.option('--dry-run', '-x', help="Execute normally without actually starting Porter", is_flag=True)
|
||||
@click.option('--eager', help="Start learning and scraping the network before starting up other services", is_flag=True, default=True)
|
||||
def run(general_config,
|
||||
|
@ -71,6 +76,7 @@ def run(general_config,
|
|||
tls_certificate_filepath,
|
||||
tls_key_filepath,
|
||||
basic_auth_filepath,
|
||||
allow_origins,
|
||||
dry_run,
|
||||
eager):
|
||||
"""Start Porter's Web controller."""
|
||||
|
@ -79,14 +85,14 @@ def run(general_config,
|
|||
# HTTP/HTTPS
|
||||
if bool(tls_key_filepath) ^ bool(tls_certificate_filepath):
|
||||
raise click.BadOptionUsage(option_name='--tls-key-filepath, --tls-certificate-filepath',
|
||||
message=BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED)
|
||||
message=PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED)
|
||||
|
||||
is_https = (tls_key_filepath and tls_certificate_filepath)
|
||||
|
||||
# check authentication
|
||||
if basic_auth_filepath and not is_https:
|
||||
raise click.BadOptionUsage(option_name='--basic-auth-filepath',
|
||||
message=BASIC_AUTH_REQUIRES_HTTPS)
|
||||
message=PORTER_BASIC_AUTH_REQUIRES_HTTPS)
|
||||
|
||||
if federated_only:
|
||||
if not teacher_uri:
|
||||
|
@ -136,10 +142,20 @@ def run(general_config,
|
|||
if not federated_only:
|
||||
emitter.message(f"Provider: {provider_uri}", color='green')
|
||||
|
||||
if basic_auth_filepath:
|
||||
emitter.message("Basic Authentication enabled", color='green')
|
||||
# firm up falsy status (i.e. change specified empty string to None)
|
||||
allow_origins = allow_origins if allow_origins else None
|
||||
# covert to list of strings/regexes
|
||||
allow_origins_list = None
|
||||
if allow_origins:
|
||||
allow_origins_list = allow_origins.split(",") # split into list of origins to allow
|
||||
emitter.message(PORTER_CORS_ALLOWED_ORIGINS.format(allow_origins=allow_origins_list), color='green')
|
||||
|
||||
controller = PORTER.make_web_controller(htpasswd_filepath=basic_auth_filepath, crash_on_error=False)
|
||||
if basic_auth_filepath:
|
||||
emitter.message(PORTER_BASIC_AUTH_ENABLED, color='green')
|
||||
|
||||
controller = PORTER.make_web_controller(crash_on_error=False,
|
||||
htpasswd_filepath=basic_auth_filepath,
|
||||
cors_allow_origins_list=allow_origins_list)
|
||||
http_scheme = "https" if is_https else "http"
|
||||
message = PORTER_RUN_MESSAGE.format(http_scheme=http_scheme, http_port=http_port)
|
||||
emitter.message(message, color='green', bold=True)
|
||||
|
|
|
@ -722,6 +722,10 @@ SUCCESSFUL_MANUALLY_SAVE_METADATA = "Successfully saved node metadata to {metada
|
|||
|
||||
PORTER_RUN_MESSAGE = "Running Porter Web Controller at {http_scheme}://127.0.0.1:{http_port}"
|
||||
|
||||
BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED = "Both --tls-key-filepath and --tls-certificate-filepath must be provided to launch porter with TLS; only one specified"
|
||||
PORTER_BASIC_AUTH_ENABLED = "Basic Authentication enabled"
|
||||
|
||||
BASIC_AUTH_REQUIRES_HTTPS = "Basic authentication can only be used with HTTPS. --tls-key-filepath and --tls-certificate-filepath must also be provided"
|
||||
PORTER_CORS_ALLOWED_ORIGINS = "CORS Allow Origins: {allow_origins}"
|
||||
|
||||
PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED = "Both --tls-key-filepath and --tls-certificate-filepath must be provided to launch porter with TLS; only one specified"
|
||||
|
||||
PORTER_BASIC_AUTH_REQUIRES_HTTPS = "Basic authentication can only be used with HTTPS. --tls-key-filepath and --tls-certificate-filepath must also be provided"
|
||||
|
|
|
@ -20,6 +20,7 @@ import inspect
|
|||
import json
|
||||
from abc import ABC, abstractmethod
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import maya
|
||||
|
@ -269,8 +270,8 @@ class WebController(InterfaceControlServer):
|
|||
|
||||
def start(self,
|
||||
port: int,
|
||||
tls_key_filepath: str = None,
|
||||
tls_certificate_filepath: str = None,
|
||||
tls_key_filepath: Path = None,
|
||||
tls_certificate_filepath: Path = None,
|
||||
dry_run: bool = False):
|
||||
if dry_run:
|
||||
return
|
||||
|
@ -279,8 +280,8 @@ class WebController(InterfaceControlServer):
|
|||
self.log.info("Starting HTTPS Control...")
|
||||
# HTTPS endpoint
|
||||
hx_deployer = HendrixDeployTLS(action="start",
|
||||
key=tls_key_filepath,
|
||||
cert=tls_certificate_filepath,
|
||||
key=str(tls_key_filepath.absolute()),
|
||||
cert=str(tls_certificate_filepath.absolute()),
|
||||
options={
|
||||
"wsgi": self._transport,
|
||||
"https_port": port,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import List, NamedTuple, Optional, Sequence
|
||||
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_CONNECTION, NO_CONTROL_PROTOCOL
|
||||
|
@ -199,7 +200,10 @@ the Pipe for nucypher network operations
|
|||
self.controller = controller
|
||||
return controller
|
||||
|
||||
def make_web_controller(self, crash_on_error: bool = False, htpasswd_filepath: str = None):
|
||||
def make_web_controller(self,
|
||||
crash_on_error: bool = False,
|
||||
htpasswd_filepath: Path = None,
|
||||
cors_allow_origins_list: List[str] = None):
|
||||
controller = WebController(app_name=self.APP_NAME,
|
||||
crash_on_error=crash_on_error,
|
||||
interface=self._interface_class(porter=self))
|
||||
|
@ -207,6 +211,17 @@ the Pipe for nucypher network operations
|
|||
|
||||
# Register Flask Decorator
|
||||
porter_flask_control = controller.make_control_transport()
|
||||
|
||||
# CORS origins
|
||||
if cors_allow_origins_list:
|
||||
try:
|
||||
from flask_cors import CORS
|
||||
except ImportError:
|
||||
raise ImportError('Porter installation is required for to specify CORS origins '
|
||||
'- run "pip install nucypher[porter]" and try again.')
|
||||
_ = CORS(app=porter_flask_control, origins=cors_allow_origins_list)
|
||||
|
||||
# Basic Auth
|
||||
if htpasswd_filepath:
|
||||
try:
|
||||
from flask_htpasswd import HtPasswdAuth
|
||||
|
@ -214,7 +229,7 @@ the Pipe for nucypher network operations
|
|||
raise ImportError('Porter installation is required for basic authentication '
|
||||
'- run "pip install nucypher[porter]" and try again.')
|
||||
|
||||
porter_flask_control.config['FLASK_HTPASSWD_PATH'] = htpasswd_filepath
|
||||
porter_flask_control.config['FLASK_HTPASSWD_PATH'] = str(htpasswd_filepath.absolute())
|
||||
# ensure basic auth required for all endpoints
|
||||
porter_flask_control.config['FLASK_AUTH_ALL'] = True
|
||||
_ = HtPasswdAuth(app=porter_flask_control)
|
||||
|
|
2
setup.py
2
setup.py
|
@ -136,7 +136,7 @@ DEPLOY_REQUIRES = [
|
|||
URSULA_REQUIRES = ['prometheus_client', 'sentry-sdk'] # TODO: Consider renaming to 'monitor', etc.
|
||||
ALICE_REQUIRES = ['qrcode']
|
||||
BOB_REQUIRES = ['qrcode']
|
||||
PORTER_REQUIRES = ['flask-htpasswd'] # needed for basic authentication
|
||||
PORTER_REQUIRES = ['flask-htpasswd', 'flask-cors'] # needed for basic authentication, cors
|
||||
|
||||
EXTRAS = {
|
||||
|
||||
|
|
|
@ -22,9 +22,10 @@ import pytest
|
|||
|
||||
from nucypher.characters.lawful import Ursula
|
||||
from nucypher.cli.literature import (
|
||||
PORTER_RUN_MESSAGE,
|
||||
BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED,
|
||||
BASIC_AUTH_REQUIRES_HTTPS
|
||||
PORTER_BASIC_AUTH_ENABLED,
|
||||
PORTER_BASIC_AUTH_REQUIRES_HTTPS,
|
||||
PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED,
|
||||
PORTER_RUN_MESSAGE, PORTER_CORS_ALLOWED_ORIGINS
|
||||
)
|
||||
from nucypher.cli.main import nucypher_cli
|
||||
from nucypher.config.constants import TEMPORARY_DOMAIN
|
||||
|
@ -96,7 +97,7 @@ def test_federated_porter_cli_run_tls_filepath_and_certificate(click_runner,
|
|||
'--tls-key-filepath', tempfile_path) # only tls-key provided
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code != 0 # both --tls-key-filepath and --tls-certificate-filepath must be provided for TLS
|
||||
assert BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED in result.output
|
||||
assert PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED in result.output
|
||||
|
||||
porter_run_command = ('porter', 'run',
|
||||
'--dry-run',
|
||||
|
@ -105,7 +106,7 @@ def test_federated_porter_cli_run_tls_filepath_and_certificate(click_runner,
|
|||
'--tls-certificate-filepath', tempfile_path) # only certificate provided
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code != 0 # both --tls-key-filepath and --tls-certificate-filepath must be provided for TLS
|
||||
assert BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED in result.output
|
||||
assert PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED in result.output
|
||||
|
||||
#
|
||||
# tls-key and certificate filepaths must exist
|
||||
|
@ -156,6 +157,56 @@ def test_federated_cli_run_https(click_runner, federated_ursulas, temp_dir_path,
|
|||
assert PORTER_RUN_MESSAGE.format(http_scheme="https", http_port=Porter.DEFAULT_PORT) in result.output
|
||||
|
||||
|
||||
def test_federated_cli_run_https_with_cors_origin(click_runner,
|
||||
federated_ursulas,
|
||||
temp_dir_path,
|
||||
federated_teacher_uri):
|
||||
tls_key_path = Path(temp_dir_path) / 'key.pem'
|
||||
_write_random_data(tls_key_path)
|
||||
certificate_file_path = Path(temp_dir_path) / 'fullchain.pem'
|
||||
_write_random_data(certificate_file_path)
|
||||
|
||||
allow_origins = ".*\.example\.com,.*\.otherexample\.org"
|
||||
|
||||
porter_run_command = ('porter', 'run',
|
||||
'--dry-run',
|
||||
'--federated-only',
|
||||
'--teacher', federated_teacher_uri,
|
||||
'--tls-key-filepath', tls_key_path,
|
||||
'--tls-certificate-filepath', certificate_file_path,
|
||||
'--allow-origins', allow_origins)
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert PORTER_RUN_MESSAGE.format(http_scheme="https", http_port=Porter.DEFAULT_PORT) in result.output
|
||||
assert PORTER_CORS_ALLOWED_ORIGINS.format(allow_origins=allow_origins.split(",")) in result.output
|
||||
|
||||
|
||||
def test_federated_cli_run_https_with_empty_string_cors_origin(click_runner,
|
||||
federated_ursulas,
|
||||
temp_dir_path,
|
||||
federated_teacher_uri):
|
||||
tls_key_path = Path(temp_dir_path) / 'key.pem'
|
||||
_write_random_data(tls_key_path)
|
||||
certificate_file_path = Path(temp_dir_path) / 'fullchain.pem'
|
||||
_write_random_data(certificate_file_path)
|
||||
|
||||
empty_string_allow_origins = ""
|
||||
|
||||
porter_run_command = ('porter', 'run',
|
||||
'--dry-run',
|
||||
'--federated-only',
|
||||
'--teacher', federated_teacher_uri,
|
||||
'--tls-key-filepath', tls_key_path,
|
||||
'--tls-certificate-filepath', certificate_file_path,
|
||||
'--allow-origins', empty_string_allow_origins)
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert PORTER_RUN_MESSAGE.format(http_scheme="https", http_port=Porter.DEFAULT_PORT) in result.output
|
||||
# empty string translates to CORS not being enabled - empty origin string provides wild card comparison
|
||||
# with just header
|
||||
assert PORTER_CORS_ALLOWED_ORIGINS.format(allow_origins='') not in result.output
|
||||
|
||||
|
||||
def test_federated_cli_run_https_basic_auth(click_runner,
|
||||
federated_ursulas,
|
||||
federated_teacher_uri,
|
||||
|
@ -175,7 +226,7 @@ def test_federated_cli_run_https_basic_auth(click_runner,
|
|||
'--basic-auth-filepath', basic_auth_file)
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert "Basic Authentication enabled" in result.output
|
||||
assert PORTER_BASIC_AUTH_ENABLED in result.output
|
||||
|
||||
|
||||
def test_blockchain_porter_cli_run_simple(click_runner,
|
||||
|
@ -271,6 +322,37 @@ def test_blockchain_porter_cli_run_https(click_runner,
|
|||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert PORTER_RUN_MESSAGE.format(http_scheme="https", http_port=Porter.DEFAULT_PORT) in result.output
|
||||
# no CORS configured by default; empty origin string provides wild card comparison with just header
|
||||
assert PORTER_CORS_ALLOWED_ORIGINS.format(allow_origins='') not in result.output
|
||||
|
||||
|
||||
def test_blockchain_porter_cli_run_https_with_cors_origin(click_runner,
|
||||
blockchain_ursulas,
|
||||
testerchain,
|
||||
agency_local_registry,
|
||||
temp_dir_path,
|
||||
blockchain_teacher_uri):
|
||||
tls_key_path = Path(temp_dir_path) / 'key.pem'
|
||||
_write_random_data(tls_key_path)
|
||||
certificate_file_path = Path(temp_dir_path) / 'fullchain.pem'
|
||||
_write_random_data(certificate_file_path)
|
||||
|
||||
allow_origins = "*"
|
||||
|
||||
porter_run_command = ('porter', 'run',
|
||||
'--dry-run',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--provider', TEST_PROVIDER_URI,
|
||||
'--registry-filepath', agency_local_registry.filepath,
|
||||
'--teacher', blockchain_teacher_uri,
|
||||
'--tls-key-filepath', tls_key_path,
|
||||
'--tls-certificate-filepath', certificate_file_path,
|
||||
'--allow-origins', allow_origins)
|
||||
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert PORTER_RUN_MESSAGE.format(http_scheme="https", http_port=Porter.DEFAULT_PORT) in result.output
|
||||
assert PORTER_CORS_ALLOWED_ORIGINS.format(allow_origins=[allow_origins]) in result.output
|
||||
|
||||
|
||||
def test_blockchain_porter_cli_run_https_basic_auth(click_runner,
|
||||
|
@ -297,7 +379,7 @@ def test_blockchain_porter_cli_run_https_basic_auth(click_runner,
|
|||
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code != 0
|
||||
assert BASIC_AUTH_REQUIRES_HTTPS in result.output
|
||||
assert PORTER_BASIC_AUTH_REQUIRES_HTTPS in result.output
|
||||
|
||||
# Basic Auth
|
||||
porter_run_command = ('porter', 'run',
|
||||
|
@ -312,7 +394,7 @@ def test_blockchain_porter_cli_run_https_basic_auth(click_runner,
|
|||
|
||||
result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert "Basic Authentication enabled" in result.output
|
||||
assert PORTER_BASIC_AUTH_ENABLED in result.output
|
||||
|
||||
|
||||
def _write_random_data(filepath: Path):
|
||||
|
|
Loading…
Reference in New Issue