From 6d30ede01edb8ee76cb4df9e269cfff5bb958a09 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 13:56:33 +0100 Subject: [PATCH 01/12] updated mdbookadmonish --- documentation/docs/book.toml | 2 +- documentation/docs/mdbook-admonish.css | 172 +++++++++++++------------ 2 files changed, 93 insertions(+), 81 deletions(-) diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index d87f16e8f9..a11f82cbbd 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -45,7 +45,7 @@ turn-off = true [preprocessor.admonish] command = "mdbook-admonish" -assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install` +assets_version = "2.0.1" # do not edit: managed by `mdbook-admonish install` # variables preprocessor: import variables into files # https://gitlab.com/tglman/mdbook-variables/ diff --git a/documentation/docs/mdbook-admonish.css b/documentation/docs/mdbook-admonish.css index e0a3365532..244bc9ade7 100644 --- a/documentation/docs/mdbook-admonish.css +++ b/documentation/docs/mdbook-admonish.css @@ -1,18 +1,31 @@ @charset "UTF-8"; :root { - --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); - --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--note: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--abstract: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--info: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--tip: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--success: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--question: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--warning: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--failure: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--danger: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--bug: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--example: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--quote: + url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: + url("data:image/svg+xml;charset=utf-8,"); } :is(.admonition) { @@ -62,7 +75,7 @@ a.admonition-anchor-link::before { content: "§"; } -:is(.admonition-title, summary.admonition-title) { +:is(.admonition-title, summary) { position: relative; min-height: 4rem; margin-block: 0; @@ -73,13 +86,13 @@ a.admonition-anchor-link::before { background-color: rgba(68, 138, 255, 0.1); display: flex; } -:is(.admonition-title, summary.admonition-title) p { +:is(.admonition-title, summary) p { margin: 0; } -html :is(.admonition-title, summary.admonition-title):last-child { +html :is(.admonition-title, summary):last-child { margin-bottom: 0; } -:is(.admonition-title, summary.admonition-title)::before { +:is(.admonition-title, summary)::before { position: absolute; top: 0.625em; inset-inline-start: 1.6rem; @@ -94,7 +107,7 @@ html :is(.admonition-title, summary.admonition-title):last-child { -webkit-mask-size: contain; content: ""; } -:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { +:is(.admonition-title, summary):hover a.admonition-anchor-link { display: initial; } @@ -119,204 +132,204 @@ details[open].admonition > summary.admonition-title::after { transform: rotate(90deg); } -:is(.admonition):is(.admonish-note) { +:is(.admonition):is(.note) { border-color: #448aff; } -:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { +:is(.note) > :is(.admonition-title, summary) { background-color: rgba(68, 138, 255, 0.1); } -:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { +:is(.note) > :is(.admonition-title, summary)::before { background-color: #448aff; - mask-image: var(--md-admonition-icon--admonish-note); - -webkit-mask-image: var(--md-admonition-icon--admonish-note); + mask-image: var(--md-admonition-icon--note); + -webkit-mask-image: var(--md-admonition-icon--note); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { +:is(.admonition):is(.abstract, .summary, .tldr) { border-color: #00b0ff; } -:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { background-color: rgba(0, 176, 255, 0.1); } -:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { background-color: #00b0ff; - mask-image: var(--md-admonition-icon--admonish-abstract); - -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); + mask-image: var(--md-admonition-icon--abstract); + -webkit-mask-image: var(--md-admonition-icon--abstract); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-info, .admonish-todo) { +:is(.admonition):is(.info, .todo) { border-color: #00b8d4; } -:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { +:is(.info, .todo) > :is(.admonition-title, summary) { background-color: rgba(0, 184, 212, 0.1); } -:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { +:is(.info, .todo) > :is(.admonition-title, summary)::before { background-color: #00b8d4; - mask-image: var(--md-admonition-icon--admonish-info); - -webkit-mask-image: var(--md-admonition-icon--admonish-info); + mask-image: var(--md-admonition-icon--info); + -webkit-mask-image: var(--md-admonition-icon--info); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { +:is(.admonition):is(.tip, .hint, .important) { border-color: #00bfa5; } -:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { +:is(.tip, .hint, .important) > :is(.admonition-title, summary) { background-color: rgba(0, 191, 165, 0.1); } -:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { +:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { background-color: #00bfa5; - mask-image: var(--md-admonition-icon--admonish-tip); - -webkit-mask-image: var(--md-admonition-icon--admonish-tip); + mask-image: var(--md-admonition-icon--tip); + -webkit-mask-image: var(--md-admonition-icon--tip); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { +:is(.admonition):is(.success, .check, .done) { border-color: #00c853; } -:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { +:is(.success, .check, .done) > :is(.admonition-title, summary) { background-color: rgba(0, 200, 83, 0.1); } -:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { +:is(.success, .check, .done) > :is(.admonition-title, summary)::before { background-color: #00c853; - mask-image: var(--md-admonition-icon--admonish-success); - -webkit-mask-image: var(--md-admonition-icon--admonish-success); + mask-image: var(--md-admonition-icon--success); + -webkit-mask-image: var(--md-admonition-icon--success); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { +:is(.admonition):is(.question, .help, .faq) { border-color: #64dd17; } -:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { +:is(.question, .help, .faq) > :is(.admonition-title, summary) { background-color: rgba(100, 221, 23, 0.1); } -:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { +:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { background-color: #64dd17; - mask-image: var(--md-admonition-icon--admonish-question); - -webkit-mask-image: var(--md-admonition-icon--admonish-question); + mask-image: var(--md-admonition-icon--question); + -webkit-mask-image: var(--md-admonition-icon--question); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { +:is(.admonition):is(.warning, .caution, .attention) { border-color: #ff9100; } -:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { +:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { background-color: rgba(255, 145, 0, 0.1); } -:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { +:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { background-color: #ff9100; - mask-image: var(--md-admonition-icon--admonish-warning); - -webkit-mask-image: var(--md-admonition-icon--admonish-warning); + mask-image: var(--md-admonition-icon--warning); + -webkit-mask-image: var(--md-admonition-icon--warning); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { +:is(.admonition):is(.failure, .fail, .missing) { border-color: #ff5252; } -:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { +:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { background-color: rgba(255, 82, 82, 0.1); } -:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { +:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { background-color: #ff5252; - mask-image: var(--md-admonition-icon--admonish-failure); - -webkit-mask-image: var(--md-admonition-icon--admonish-failure); + mask-image: var(--md-admonition-icon--failure); + -webkit-mask-image: var(--md-admonition-icon--failure); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-danger, .admonish-error) { +:is(.admonition):is(.danger, .error) { border-color: #ff1744; } -:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { +:is(.danger, .error) > :is(.admonition-title, summary) { background-color: rgba(255, 23, 68, 0.1); } -:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { +:is(.danger, .error) > :is(.admonition-title, summary)::before { background-color: #ff1744; - mask-image: var(--md-admonition-icon--admonish-danger); - -webkit-mask-image: var(--md-admonition-icon--admonish-danger); + mask-image: var(--md-admonition-icon--danger); + -webkit-mask-image: var(--md-admonition-icon--danger); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-bug) { +:is(.admonition):is(.bug) { border-color: #f50057; } -:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { +:is(.bug) > :is(.admonition-title, summary) { background-color: rgba(245, 0, 87, 0.1); } -:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { +:is(.bug) > :is(.admonition-title, summary)::before { background-color: #f50057; - mask-image: var(--md-admonition-icon--admonish-bug); - -webkit-mask-image: var(--md-admonition-icon--admonish-bug); + mask-image: var(--md-admonition-icon--bug); + -webkit-mask-image: var(--md-admonition-icon--bug); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-example) { +:is(.admonition):is(.example) { border-color: #7c4dff; } -:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { +:is(.example) > :is(.admonition-title, summary) { background-color: rgba(124, 77, 255, 0.1); } -:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { +:is(.example) > :is(.admonition-title, summary)::before { background-color: #7c4dff; - mask-image: var(--md-admonition-icon--admonish-example); - -webkit-mask-image: var(--md-admonition-icon--admonish-example); + mask-image: var(--md-admonition-icon--example); + -webkit-mask-image: var(--md-admonition-icon--example); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.admonish-quote, .admonish-cite) { +:is(.admonition):is(.quote, .cite) { border-color: #9e9e9e; } -:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { +:is(.quote, .cite) > :is(.admonition-title, summary) { background-color: rgba(158, 158, 158, 0.1); } -:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { +:is(.quote, .cite) > :is(.admonition-title, summary)::before { background-color: #9e9e9e; - mask-image: var(--md-admonition-icon--admonish-quote); - -webkit-mask-image: var(--md-admonition-icon--admonish-quote); + mask-image: var(--md-admonition-icon--quote); + -webkit-mask-image: var(--md-admonition-icon--quote); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; @@ -327,8 +340,7 @@ details[open].admonition > summary.admonition-title::after { background-color: var(--sidebar-bg); } -.ayu :is(.admonition), -.coal :is(.admonition) { +.ayu :is(.admonition), .coal :is(.admonition) { background-color: var(--theme-hover); } From 76e49476a6aef453f6561b50e7fb994f0501bd60 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 13:56:58 +0100 Subject: [PATCH 02/12] updated clients section format: expanding websocket client --- documentation/docs/src/SUMMARY.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/documentation/docs/src/SUMMARY.md b/documentation/docs/src/SUMMARY.md index 24a625cfb2..2b46c51d41 100644 --- a/documentation/docs/src/SUMMARY.md +++ b/documentation/docs/src/SUMMARY.md @@ -22,9 +22,12 @@ # Clients - [Clients Overview](clients/overview.md) - - [Websocket](clients/websocket-client.md) - - [Socks5](clients/socks5-client.md) - - [Webassembly](clients/webassembly-client.md) +- [Websocket Client](clients/websocket-client.md) + - [Client Setup](clients/websocket/setup.md) + - [Configuration](clients/websocket/config.md) + - [Using Your Client](clients/websocket/usage.md) +- [Socks5 Client](clients/socks5-client.md) +- [Webassembly Client](clients/webassembly-client.md) - [Addressing System](clients/addressing-system.md) # SDK From 9c0ca32033e5e40fd5828c381b532d35a6f48a07 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 13:57:12 +0100 Subject: [PATCH 03/12] expanded pages for ws client --- .../docs/src/clients/websocket/config.md | 40 +++++++ .../docs/src/clients/websocket/setup.md | 59 ++++++++++ .../docs/src/clients/websocket/usage.md | 109 ++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 documentation/docs/src/clients/websocket/config.md create mode 100644 documentation/docs/src/clients/websocket/setup.md create mode 100644 documentation/docs/src/clients/websocket/usage.md diff --git a/documentation/docs/src/clients/websocket/config.md b/documentation/docs/src/clients/websocket/config.md new file mode 100644 index 0000000000..75683b174f --- /dev/null +++ b/documentation/docs/src/clients/websocket/config.md @@ -0,0 +1,40 @@ +# Configuration + +## Choosing a Gateway +By default - as in the example above - your client will choose a random gateway to connect to. + +However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client: +* If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`. +* You can also choose a gateway based on its location relative to your client. This can be done by appending the `--latency-based-routing` flag to your `init` command. This command means that to select a gateway, your client will: + * fetch a list of all available gateways + * send few ping messages to all of them, and measure response times. + * create a weighted distribution to randomly choose one, favouring ones with lower latency. + +> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms + +## Configuring your client +When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/clients//`. + +``` +tree $HOME//.nym/clients/example-client +├── config +│   └── config.toml +└── data + ├── ack_key.pem + ├── gateway_shared.pem + ├── private_encryption.pem + ├── private_identity.pem + ├── public_encryption.pem + └── public_identity.pem +``` + +The `config.toml` file contains client configuration options, while the two `pem` files contain client key information. + +The generated files contain the client name, public/private keypairs, and gateway address. The name `` in the example above is just a local identifier so that you can name your clients. + +### Configuring your client for Docker +By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`. + +You can set this via the `--host` flag during either the `init` or `run` commands. + +Alternatively, a custom host can be set in the `config.toml` file under the `socket` section. If you do this, remember to restart your client process. diff --git a/documentation/docs/src/clients/websocket/setup.md b/documentation/docs/src/clients/websocket/setup.md new file mode 100644 index 0000000000..f3e3ab8bad --- /dev/null +++ b/documentation/docs/src/clients/websocket/setup.md @@ -0,0 +1,59 @@ +# Client Setup + +## Viewing command help + +You can check that your binaries are properly compiled with: + +``` +./nym-client --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +The two most important commands you will issue to the client are: + +* `init` - initalise a new client instance. +* `run` - run a mixnet client process. + +You can check the necessary parameters for the available commands by running: + +``` +./nym-client --help +``` + +### Initialising your client + +Before you can use the client, you need to initalise a new instance of it. Each instance of the client has its own public/private keypair, and connects to its own gateway node. Taken together, these 3 things (public/private keypair + gateway node identity key) make up an app's identity. + +Initialising a new client instance can be done with the following command: + +``` +./nym-client init --id example-client +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +The `--id` in the example above is a local identifier so that you can name your clients; it is **never** transmitted over the network. + +There is an optional `--gateway` flag that you can use if you want to use a specific gateway. The supplied argument is the `Identity Key` of the gateway you wish to use, which can be found on the [mainnet Network Explorer](https://explorer.nymtech.net/network-components/gateways) or [Sandbox Testnet Explorer](https://sandbox-explorer.nymtech.net/network-components/gateways) depending on which network you are on. + +Not passing this argument will randomly select a gateway for your client. + +## Running your client +You can run the initalised client by doing this: + +``` +./nym-client run --id example-client +``` + +When you run the client, it immediately starts generating (fake) cover traffic and sending it to the mixnet. + +When the client is first started, it will reach out to the Nym network's validators, and get a list of available Nym nodes (gateways, mixnodes, and validators). We call this list of nodes the network _topology_. The client does this so that it knows how to connect, register itself with the network, and know which mixnodes it can route Sphinx packets through. diff --git a/documentation/docs/src/clients/websocket/usage.md b/documentation/docs/src/clients/websocket/usage.md new file mode 100644 index 0000000000..f5a28be1df --- /dev/null +++ b/documentation/docs/src/clients/websocket/usage.md @@ -0,0 +1,109 @@ +# Using Your Client + +## Using your client +### Connecting to the local websocket +The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want. + +The Nym monorepo includes websocket client example code for Rust, Go, Javacript, and Python, all of which can be found [here](https://github.com/nymtech/nym/tree/master/clients/native/examples). + +> Rust users can run the examples with `cargo run --example .rs`, as the examples are not organised in the same way as the other examples, due to already being inside a Cargo project. + +All of these code examples will do the following: +* connect to a running websocket client on port `1977` +* format a message to send in either JSON or Binary format. Nym messages have defined JSON formats. +* send the message into the websocket. The native client packages the message into a Sphinx packet and sends it to the mixnet +* wait for confirmation that the message hit the native client +* wait to receive messages from other Nym apps + +By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store. + +> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal. + +### Message Types +There are a small number of messages that your application sends up the websocket to interact with the native client, as follows. + +#### Sending text +If you want to send text information through the mixnet, format a message like this one and poke it into the websocket: + +```json +{ + "type": "send", + "message": "the message", + "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" +} +``` + +In some applications, e.g. where people are chatting with friends who they know, you might want to include unencrypted reply information in the message field. This provides an easy way for the receiving chat to then turn around and send a reply message: + +```json +{ + "type": "send", + "message": { + "sender": "198427b63ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm", + "chatMessage": "hi julia!" + }, + "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" +} +``` + +If that fits your security model, good. However, will probably be the case that you want to send **anonymous replies using Single Use Reply Blocks (SURBs)**. + +You can read more about SURBs [here](../../architecture/traffic-flow.md#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - without them having to know your nym address. + +Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the address. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client. + +```json +{ + "type": "sendAnonymous", + "message": "something you want to keep secret" + "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" + "replySurbs": 100 // however many reply SURBs to send along with your message +} +``` + +Each bucket of replySURBs, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them! Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message) + +```json +{ + "type": "reply", + "message": "reply you also want to keep secret", + "senderTag": "the sender tag you parsed from the incoming message" +} +``` + + +#### Sending binary data +You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded +Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information. + +As a response the `native-client` will send a `ServerResponse` to be decoded. + +You can find examples of sending and receiving binary data in the Rust, Python and Go [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust. + +#### Getting your own address +Sometimes, when you start your app, it can be convenient to ask the native client to tell you what your own address is (from the saved configuration files). To do this, send: + +```json +{ + "type": "selfAddress" +} +``` + +You'll get back: + +```json +{ + "type": "selfAddress", + "address": "the-address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" +} +``` + +#### Error messages +Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format: + +```json +{ + "type": "error", + "message": "string message" +} +``` From 193ea34efc29090dfa2221a9be357282591b5e96 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 13:57:40 +0100 Subject: [PATCH 04/12] turned single ws client page into stub for expanded directory structure --- .../docs/src/clients/websocket-client.md | 205 +----------------- 1 file changed, 2 insertions(+), 203 deletions(-) diff --git a/documentation/docs/src/clients/websocket-client.md b/documentation/docs/src/clients/websocket-client.md index 103112d63e..add7ef24dc 100644 --- a/documentation/docs/src/clients/websocket-client.md +++ b/documentation/docs/src/clients/websocket-client.md @@ -7,208 +7,7 @@ ``` -## Client setup -### Viewing command help +You can run this client as a standalone process and pipe traffic into it to be sent through the mixnet. This is useful if you're building an application in a language other than Typescript or Rust and cannot utilise one of the SDKs. -You can check that your binaries are properly compiled with: +You can find the code for this client [here](https://github.com/nymtech/nym/tree/develop/clients/native). -``` -./nym-client --help -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -The two most important commands you will issue to the client are: - -* `init` - initalise a new client instance. -* `run` - run a mixnet client process. - -You can check the necessary parameters for the available commands by running: - -``` -./nym-client --help -``` - -### Initialising your client - -Before you can use the client, you need to initalise a new instance of it. Each instance of the client has its own public/private keypair, and connects to its own gateway node. Taken together, these 3 things (public/private keypair + gateway node identity key) make up an app's identity. - -Initialising a new client instance can be done with the following command: - -``` -./nym-client init --id example-client -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -The `--id` in the example above is a local identifier so that you can name your clients; it is **never** transmitted over the network. - -There is an optional `--gateway` flag that you can use if you want to use a specific gateway. The supplied argument is the `Identity Key` of the gateway you wish to use, which can be found on the [mainnet Network Explorer](https://explorer.nymtech.net/network-components/gateways) or [Sandbox Testnet Explorer](https://sandbox-explorer.nymtech.net/network-components/gateways) depending on which network you are on. - -Not passing this argument will randomly select a gateway for your client. - -#### Choosing a Gateway -By default - as in the example above - your client will choose a random gateway to connect to. - -However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client: -* If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`. -* You can also choose a gateway based on its location relative to your client. This can be done by appending the `--latency-based-routing` flag to your `init` command. This command means that to select a gateway, your client will: - * fetch a list of all availiable gateways - * send few ping messages to all of them, and measure response times. - * create a weighted distribution to randomly choose one, favouring ones with lower latency. - -> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms - -### Running your client -You can run the initalised client by doing this: - -``` -./nym-client run --id example-client -``` - -When you run the client, it immediately starts generating (fake) cover traffic and sending it to the mixnet. - -When the client is first started, it will reach out to the Nym network's validators, and get a list of available Nym nodes (gateways, mixnodes, and validators). We call this list of nodes the network _topology_. The client does this so that it knows how to connect, register itself with the network, and know which mixnodes it can route Sphinx packets through. - -### Configuring your client -When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/clients//`. - -``` -tree $HOME//.nym/clients/example-client -├── config -│   └── config.toml -└── data - ├── ack_key.pem - ├── gateway_shared.pem - ├── private_encryption.pem - ├── private_identity.pem - ├── public_encryption.pem - └── public_identity.pem -``` - -The `config.toml` file contains client configuration options, while the two `pem` files contain client key information. - -The generated files contain the client name, public/private keypairs, and gateway address. The name `` in the example above is just a local identifier so that you can name your clients. - -#### Configuring your client for Docker -By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`. - -You can set this via the `--host` flag during either the `init` or `run` commands. - -Alternatively, a custom host can be set in the `config.toml` file under the `socket` section. If you do this, remember to restart your client process. - -## Using your client -### Connecting to the local websocket -The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want. - -The Nym monorepo includes websocket client example code for Rust, Go, Javacript, and Python, all of which can be found [here](https://github.com/nymtech/nym/tree/master/clients/native/examples). - -> Rust users can run the examples with `cargo run --example .rs`, as the examples are not organised in the same way as the other examples, due to already being inside a Cargo project. - -All of these code examples will do the following: -* connect to a running websocket client on port `1977` -* format a message to send in either JSON or Binary format. Nym messages have defined JSON formats. -* send the message into the websocket. The native client packages the message into a Sphinx packet and sends it to the mixnet -* wait for confirmation that the message hit the native client -* wait to receive messages from other Nym apps - -By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store. - -> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal. - -### Message Types -There are a small number of messages that your application sends up the websocket to interact with the native client, as follows. - -#### Sending text -If you want to send text information through the mixnet, format a message like this one and poke it into the websocket: - -```json -{ - "type": "send", - "message": "the message", - "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" -} -``` - -In some applications, e.g. where people are chatting with friends who they know, you might want to include unencrypted reply information in the message field. This provides an easy way for the receiving chat to then turn around and send a reply message: - -```json -{ - "type": "send", - "message": { - "sender": "198427b63ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm", - "chatMessage": "hi julia!" - }, - "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" -} -``` - -If that fits your security model, good. However, will probably be the case that you want to send **anonymous replies using Single Use Reply Blocks (SURBs)**. - -You can read more about SURBs [here](../architecture/traffic-flow.md#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - without them having to know your nym address. - -Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the address. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client. - -```json -{ - "type": "sendAnonymous", - "message": "something you want to keep secret" - "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" - "replySurbs": 100 // however many reply SURBs to send along with your message -} -``` - -Each bucket of replySURBs, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them! Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message) - -```json -{ - "type": "reply", - "message": "reply you also want to keep secret", - "senderTag": "the sender tag you parsed from the incoming message" -} -``` - - -#### Sending binary data -You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded -Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information. - -As a response the `native-client` will send a `ServerResponse` to be decoded. - -You can find examples of sending and receiving binary data in the Rust, Python and Go [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust. - -#### Getting your own address -Sometimes, when you start your app, it can be convenient to ask the native client to tell you what your own address is (from the saved configuration files). To do this, send: - -```json -{ - "type": "selfAddress" -} -``` - -You'll get back: - -```json -{ - "type": "selfAddress", - "address": "the-address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" -} -``` - -#### Error messages -Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format: - -```json -{ - "type": "error", - "message": "string message" -} -``` From bf56696adcf2a3934a1d142579f2228fd78b90cf Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 13:57:55 +0100 Subject: [PATCH 05/12] smol tweaks to readability --- documentation/docs/src/clients/webassembly-client.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/documentation/docs/src/clients/webassembly-client.md b/documentation/docs/src/clients/webassembly-client.md index 6a1205c1de..f6a0aa55c2 100644 --- a/documentation/docs/src/clients/webassembly-client.md +++ b/documentation/docs/src/clients/webassembly-client.md @@ -2,13 +2,15 @@ The Nym webassembly client allows any webassembly-capable runtime to build and send Sphinx packets to the Nym network, for uses in edge computing and browser-based applications. -This is currently packaged and distributed for ease of use via the [Nym Typescript SDK library](../sdk/typescript.md). +This is currently packaged and distributed for ease of use via the [Nym Typescript SDK library](../sdk/typescript.md). **We imagine most developers will use this client via the SDK for ease.** The webassembly client allows for the easy creation of Sphinx packets from within mobile apps and browser-based client-side apps (including Electron or similar). -## Building apps with nym-client-wasm +## Building apps with Webassembly Client -Check out the [examples section](../sdk/typescript.md#using-the-sdk) of the SDK docs for examples of simple application framework setups. There are also two example applications located in the `clients/webassembly` directory in the main Nym platform codebase. The `js-example` is a simple, bare-bones JavaScript app. +Check out the [Typescript SDK docs](https://sdk.nymtech.net) for examples of usage. + +There are also example applications located in the `clients/webassembly` directory in the main Nym platform codebase. ## Think about what you're sending! ```admonish caution From 7ad5ff777041b8f90200b16a269bd26fce032f7c Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 14:01:20 +0100 Subject: [PATCH 06/12] * cmdrun path fixes * rename file to setup+run --- documentation/docs/src/SUMMARY.md | 2 +- documentation/docs/src/clients/websocket/setup.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/docs/src/SUMMARY.md b/documentation/docs/src/SUMMARY.md index 2b46c51d41..f408740f3c 100644 --- a/documentation/docs/src/SUMMARY.md +++ b/documentation/docs/src/SUMMARY.md @@ -23,7 +23,7 @@ # Clients - [Clients Overview](clients/overview.md) - [Websocket Client](clients/websocket-client.md) - - [Client Setup](clients/websocket/setup.md) + - [Setup & Run](clients/websocket/setup.md) - [Configuration](clients/websocket/config.md) - [Using Your Client](clients/websocket/usage.md) - [Socks5 Client](clients/socks5-client.md) diff --git a/documentation/docs/src/clients/websocket/setup.md b/documentation/docs/src/clients/websocket/setup.md index f3e3ab8bad..e682e87175 100644 --- a/documentation/docs/src/clients/websocket/setup.md +++ b/documentation/docs/src/clients/websocket/setup.md @@ -1,4 +1,4 @@ -# Client Setup +# Setup & Run ## Viewing command help @@ -10,7 +10,7 @@ You can check that your binaries are properly compiled with: ~~~admonish example collapsible=true title="Console output" ``` - + ``` ~~~ @@ -25,7 +25,7 @@ You can check the necessary parameters for the available commands by running: ./nym-client --help ``` -### Initialising your client +## Initialising your client Before you can use the client, you need to initalise a new instance of it. Each instance of the client has its own public/private keypair, and connects to its own gateway node. Taken together, these 3 things (public/private keypair + gateway node identity key) make up an app's identity. @@ -37,7 +37,7 @@ Initialising a new client instance can be done with the following command: ~~~admonish example collapsible=true title="Console output" ``` - + ``` ~~~ From 789525c35bf1b1613b4da7dee009daa3c5497f54 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 14:02:41 +0100 Subject: [PATCH 07/12] remove ref to previous single page setup --- documentation/docs/src/clients/websocket/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/src/clients/websocket/config.md b/documentation/docs/src/clients/websocket/config.md index 75683b174f..28bed48c81 100644 --- a/documentation/docs/src/clients/websocket/config.md +++ b/documentation/docs/src/clients/websocket/config.md @@ -1,7 +1,7 @@ # Configuration ## Choosing a Gateway -By default - as in the example above - your client will choose a random gateway to connect to. +By default your client will choose a random gateway to connect to. However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client: * If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`. From 85a0a3d8b5a0989a2336b48aea11cb9089ee7caf Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 15:48:20 +0100 Subject: [PATCH 08/12] * created 'examples' file * added default port to configuration file --- .../docs/src/clients/websocket/config.md | 3 ++ .../docs/src/clients/websocket/examples.md | 15 ++++++++++ .../docs/src/clients/websocket/usage.md | 30 +++++-------------- 3 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 documentation/docs/src/clients/websocket/examples.md diff --git a/documentation/docs/src/clients/websocket/config.md b/documentation/docs/src/clients/websocket/config.md index 28bed48c81..94d31c0659 100644 --- a/documentation/docs/src/clients/websocket/config.md +++ b/documentation/docs/src/clients/websocket/config.md @@ -1,5 +1,8 @@ # Configuration +## Default listening port +The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want. + ## Choosing a Gateway By default your client will choose a random gateway to connect to. diff --git a/documentation/docs/src/clients/websocket/examples.md b/documentation/docs/src/clients/websocket/examples.md new file mode 100644 index 0000000000..7367c29180 --- /dev/null +++ b/documentation/docs/src/clients/websocket/examples.md @@ -0,0 +1,15 @@ +# Examples +The Nym monorepo includes websocket client example code for Rust, Go, Javacript, and Python, all of which can be found [here](https://github.com/nymtech/nym/tree/master/clients/native/examples). + +> Rust users can run the examples with `cargo run --example .rs`, as the examples are not organised in the same way as the other examples, due to already being inside a Cargo project. + +All of these code examples will do the following: +* connect to a running websocket client on port `1977` +* format a message to send in either JSON or Binary format. Nym messages have defined JSON formats. +* send the message into the websocket. The native client packages the message into a Sphinx packet and sends it to the mixnet +* wait for confirmation that the message hit the native client +* wait to receive messages from other Nym apps + +By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store. + +> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal. diff --git a/documentation/docs/src/clients/websocket/usage.md b/documentation/docs/src/clients/websocket/usage.md index f5a28be1df..17e820996b 100644 --- a/documentation/docs/src/clients/websocket/usage.md +++ b/documentation/docs/src/clients/websocket/usage.md @@ -1,28 +1,12 @@ # Using Your Client -## Using your client -### Connecting to the local websocket +## Connecting to the local websocket The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want. -The Nym monorepo includes websocket client example code for Rust, Go, Javacript, and Python, all of which can be found [here](https://github.com/nymtech/nym/tree/master/clients/native/examples). +## Message Types +There are a small number of messages that your application sends up the websocket to interact with the native client, as follows. You can -> Rust users can run the examples with `cargo run --example .rs`, as the examples are not organised in the same way as the other examples, due to already being inside a Cargo project. - -All of these code examples will do the following: -* connect to a running websocket client on port `1977` -* format a message to send in either JSON or Binary format. Nym messages have defined JSON formats. -* send the message into the websocket. The native client packages the message into a Sphinx packet and sends it to the mixnet -* wait for confirmation that the message hit the native client -* wait to receive messages from other Nym apps - -By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store. - -> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal. - -### Message Types -There are a small number of messages that your application sends up the websocket to interact with the native client, as follows. - -#### Sending text +### Sending text If you want to send text information through the mixnet, format a message like this one and poke it into the websocket: ```json @@ -72,7 +56,7 @@ Each bucket of replySURBs, when received as part of an incoming message, has a u ``` -#### Sending binary data +### Sending binary data You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information. @@ -80,7 +64,7 @@ As a response the `native-client` will send a `ServerResponse` to be decoded. You can find examples of sending and receiving binary data in the Rust, Python and Go [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust. -#### Getting your own address +### Getting your own address Sometimes, when you start your app, it can be convenient to ask the native client to tell you what your own address is (from the saved configuration files). To do this, send: ```json @@ -98,7 +82,7 @@ You'll get back: } ``` -#### Error messages +### Error messages Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format: ```json From 198739a126e203c4647a628a3c5cdc5f54473c60 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 15:48:59 +0100 Subject: [PATCH 09/12] added websocket client examples page --- documentation/docs/src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/docs/src/SUMMARY.md b/documentation/docs/src/SUMMARY.md index f408740f3c..b3bbd0ef43 100644 --- a/documentation/docs/src/SUMMARY.md +++ b/documentation/docs/src/SUMMARY.md @@ -26,6 +26,7 @@ - [Setup & Run](clients/websocket/setup.md) - [Configuration](clients/websocket/config.md) - [Using Your Client](clients/websocket/usage.md) + - [Examples](clients/websocket/examples.md) - [Socks5 Client](clients/socks5-client.md) - [Webassembly Client](clients/webassembly-client.md) - [Addressing System](clients/addressing-system.md) From 410ef85165b53d30a07aa7fdeb5346a7372e899c Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 6 Nov 2023 16:52:22 +0100 Subject: [PATCH 10/12] updating websocket send and receives --- documentation/docs/src/SUMMARY.md | 2 +- .../docs/src/clients/websocket/config.md | 4 ++ .../docs/src/clients/websocket/usage.md | 63 +++++++++++-------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/documentation/docs/src/SUMMARY.md b/documentation/docs/src/SUMMARY.md index b3bbd0ef43..a4875d9217 100644 --- a/documentation/docs/src/SUMMARY.md +++ b/documentation/docs/src/SUMMARY.md @@ -4,7 +4,7 @@ # Architecture - [Network Overview](architecture/network-overview.md) - [Mixnet Traffic Flow](architecture/traffic-flow.md) - + # Binaries diff --git a/documentation/docs/src/clients/websocket/config.md b/documentation/docs/src/clients/websocket/config.md index 94d31c0659..8bd6d8bedb 100644 --- a/documentation/docs/src/clients/websocket/config.md +++ b/documentation/docs/src/clients/websocket/config.md @@ -3,6 +3,10 @@ ## Default listening port The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want. +You can either set this via the `--port` flag at `init` or `run`, or you can manually edit `~/.nym/clients//config/config.toml`. + +> Remember to restart your client if you change your listening port via editing your config file. + ## Choosing a Gateway By default your client will choose a random gateway to connect to. diff --git a/documentation/docs/src/clients/websocket/usage.md b/documentation/docs/src/clients/websocket/usage.md index 17e820996b..4c378968c0 100644 --- a/documentation/docs/src/clients/websocket/usage.md +++ b/documentation/docs/src/clients/websocket/usage.md @@ -1,12 +1,35 @@ # Using Your Client -## Connecting to the local websocket -The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want. +The Nym native client exposes a websocket interface that your code connects to. The **default** websocket port is `1977`, you can override that in the client config if you want. -## Message Types -There are a small number of messages that your application sends up the websocket to interact with the native client, as follows. You can +Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening out for incoming messages. -### Sending text +# Sending Messages +There are a small number of messages that your application sends up the websocket to interact with the native client, as defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs): + +```rust,noplayground +{{#include ../../../../../clients/native/websocket-requests/src/requests.rs:55:97}} +``` + +## Getting your own address +When you start your app, it is best practice to ask the native client to tell you what your own address is (from the saved configuration files). To do this, send: + +```json +{ + "type": "selfAddress" +} +``` + +You'll receive a response of the format: + +```json +{ + "type": "selfAddress", + "address": "your address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" +} +``` + +## Sending text If you want to send text information through the mixnet, format a message like this one and poke it into the websocket: ```json @@ -55,8 +78,7 @@ Each bucket of replySURBs, when received as part of an incoming message, has a u } ``` - -### Sending binary data +## Sending binary data You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information. @@ -64,25 +86,7 @@ As a response the `native-client` will send a `ServerResponse` to be decoded. You can find examples of sending and receiving binary data in the Rust, Python and Go [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust. -### Getting your own address -Sometimes, when you start your app, it can be convenient to ask the native client to tell you what your own address is (from the saved configuration files). To do this, send: - -```json -{ - "type": "selfAddress" -} -``` - -You'll get back: - -```json -{ - "type": "selfAddress", - "address": "the-address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" -} -``` - -### Error messages +## Error messages Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format: ```json @@ -91,3 +95,10 @@ Errors from the app's client, or from the gateway, will be sent down the websock "message": "string message" } ``` + +# Listening Out for and Receiving Messages +Responses to your messages, or if you are running a service that is expecting incoming messages, are defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/responses.rs): + +```rust,noplayground +{{#include ../../../../../clients/native/websocket-requests/src/responses.rs:48:53}} +``` From eb2ac7630a08b908f1c15e25270512fcc8cab0f8 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 7 Nov 2023 14:38:54 +0100 Subject: [PATCH 11/12] first pass at ws client usage docs --- .../docs/src/clients/websocket/usage.md | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/documentation/docs/src/clients/websocket/usage.md b/documentation/docs/src/clients/websocket/usage.md index 4c378968c0..2c5f3f4d05 100644 --- a/documentation/docs/src/clients/websocket/usage.md +++ b/documentation/docs/src/clients/websocket/usage.md @@ -1,18 +1,17 @@ # Using Your Client - The Nym native client exposes a websocket interface that your code connects to. The **default** websocket port is `1977`, you can override that in the client config if you want. -Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening out for incoming messages. +Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening for incoming messages. -# Sending Messages -There are a small number of messages that your application sends up the websocket to interact with the native client, as defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs): +# Message Requests +There are a number of message types that you can send up the websocket as defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs): ```rust,noplayground {{#include ../../../../../clients/native/websocket-requests/src/requests.rs:55:97}} ``` ## Getting your own address -When you start your app, it is best practice to ask the native client to tell you what your own address is (from the saved configuration files). To do this, send: +When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files - see [here](../addressing-system.md) for more on Nym's addressing scheme). If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send: ```json { @@ -29,6 +28,10 @@ You'll receive a response of the format: } ``` +See [here](https://github.com/nymtech/nym/blob/93cc281abc2cc951023b51746fa6f2ead1f56c46/clients/native/examples/python-examples/websocket/textsend.py#L16C9-L16C9) for an example of this being used. + +> Note that all the pieces of native client example code begin with printing the selfAddress. Examples exist for Rust, Go, Javascript, and Python. + ## Sending text If you want to send text information through the mixnet, format a message like this one and poke it into the websocket: @@ -53,22 +56,37 @@ In some applications, e.g. where people are chatting with friends who they know, } ``` -If that fits your security model, good. However, will probably be the case that you want to send **anonymous replies using Single Use Reply Blocks (SURBs)**. +**If that fits your security model, good. However, will probably be the case that you want to send anonymous replies using Single Use Reply Blocks (SURBs)**. -You can read more about SURBs [here](../../architecture/traffic-flow.md#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - without them having to know your nym address. +You can read more about SURBs [here](../../architecture/traffic-flow.md#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**. -Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the address. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client. +Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the final destination of. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client. ```json { "type": "sendAnonymous", - "message": "something you want to keep secret" - "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm" - "replySurbs": 100 // however many reply SURBs to send along with your message + "message": "something you want to keep secret", + "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm", + "replySurbs": 20 // however many reply SURBs to send along with your message } ``` -Each bucket of replySURBs, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them! Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message) +See ['Replying to SURB Messages'](#replying-to-surb-messages) below for an example of how to deal with incoming messages that have SURBs attached. + +Deciding on the amount of SURBs to generate and send along with outgoing messages depends on the expected size of the reply. You might want to send a lot of SURBs in order to make sure you get your response as quickly as possible (but accept the minor additional latency when sending, as your client has to generate and encrypt the packets), or you might just send a few (e.g. 20) and then if your response requires more SURBs, send them along, accepting the additional latency in getting your response. + +## Sending binary data +You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded +Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information. + +> As a response the `native-client` will send a `ServerResponse` to be decoded. See [Message Responses](#message-responses) below for more. + +You can find examples of sending and receiving binary data in the [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust. + +## Replying to SURB messages +Each bucket of `replySURBs`, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them in a situation where multiple clients are sending requests to a single service. + +Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message) ```json { @@ -78,14 +96,6 @@ Each bucket of replySURBs, when received as part of an incoming message, has a u } ``` -## Sending binary data -You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded -Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information. - -As a response the `native-client` will send a `ServerResponse` to be decoded. - -You can find examples of sending and receiving binary data in the Rust, Python and Go [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust. - ## Error messages Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format: @@ -96,8 +106,11 @@ Errors from the app's client, or from the gateway, will be sent down the websock } ``` -# Listening Out for and Receiving Messages -Responses to your messages, or if you are running a service that is expecting incoming messages, are defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/responses.rs): +## LaneQueueLength +This is currently only used in the [Socks Client](../socks5-client.md) to keep track of the number of Sphinx packets waiting to be sent to the mixnet via being slotted amongst cover traffic. As this value becomes larger, the client signals to the application it should slow down the speed with which it writes to the proxy. This is to stop situations arising whereby an app connected to the client appears as if it has sent (e.g.) a bunch of messages and is awaiting a reply, when they in fact have not been sent through the mixnet yet. + +# Message Responses +Responses to your messages are defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/responses.rs): ```rust,noplayground {{#include ../../../../../clients/native/websocket-requests/src/responses.rs:48:53}} From 4ce652af95f83e61b6f66e9184ab235f2b755542 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 7 Nov 2023 17:46:46 +0100 Subject: [PATCH 12/12] update mdbook admonish --- documentation/docs/book.toml | 2 +- documentation/docs/mdbook-admonish.css | 172 ++++++++++++------------- 2 files changed, 81 insertions(+), 93 deletions(-) diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index a11f82cbbd..d87f16e8f9 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -45,7 +45,7 @@ turn-off = true [preprocessor.admonish] command = "mdbook-admonish" -assets_version = "2.0.1" # do not edit: managed by `mdbook-admonish install` +assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install` # variables preprocessor: import variables into files # https://gitlab.com/tglman/mdbook-variables/ diff --git a/documentation/docs/mdbook-admonish.css b/documentation/docs/mdbook-admonish.css index 244bc9ade7..e0a3365532 100644 --- a/documentation/docs/mdbook-admonish.css +++ b/documentation/docs/mdbook-admonish.css @@ -1,31 +1,18 @@ @charset "UTF-8"; :root { - --md-admonition-icon--note: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--abstract: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--info: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--tip: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--success: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--question: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--warning: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--failure: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--danger: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--bug: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--example: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--quote: - url("data:image/svg+xml;charset=utf-8,"); - --md-details-icon: - url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); } :is(.admonition) { @@ -75,7 +62,7 @@ a.admonition-anchor-link::before { content: "§"; } -:is(.admonition-title, summary) { +:is(.admonition-title, summary.admonition-title) { position: relative; min-height: 4rem; margin-block: 0; @@ -86,13 +73,13 @@ a.admonition-anchor-link::before { background-color: rgba(68, 138, 255, 0.1); display: flex; } -:is(.admonition-title, summary) p { +:is(.admonition-title, summary.admonition-title) p { margin: 0; } -html :is(.admonition-title, summary):last-child { +html :is(.admonition-title, summary.admonition-title):last-child { margin-bottom: 0; } -:is(.admonition-title, summary)::before { +:is(.admonition-title, summary.admonition-title)::before { position: absolute; top: 0.625em; inset-inline-start: 1.6rem; @@ -107,7 +94,7 @@ html :is(.admonition-title, summary):last-child { -webkit-mask-size: contain; content: ""; } -:is(.admonition-title, summary):hover a.admonition-anchor-link { +:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { display: initial; } @@ -132,204 +119,204 @@ details[open].admonition > summary.admonition-title::after { transform: rotate(90deg); } -:is(.admonition):is(.note) { +:is(.admonition):is(.admonish-note) { border-color: #448aff; } -:is(.note) > :is(.admonition-title, summary) { +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(68, 138, 255, 0.1); } -:is(.note) > :is(.admonition-title, summary)::before { +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { background-color: #448aff; - mask-image: var(--md-admonition-icon--note); - -webkit-mask-image: var(--md-admonition-icon--note); + mask-image: var(--md-admonition-icon--admonish-note); + -webkit-mask-image: var(--md-admonition-icon--admonish-note); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.abstract, .summary, .tldr) { +:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { border-color: #00b0ff; } -:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 176, 255, 0.1); } -:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00b0ff; - mask-image: var(--md-admonition-icon--abstract); - -webkit-mask-image: var(--md-admonition-icon--abstract); + mask-image: var(--md-admonition-icon--admonish-abstract); + -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.info, .todo) { +:is(.admonition):is(.admonish-info, .admonish-todo) { border-color: #00b8d4; } -:is(.info, .todo) > :is(.admonition-title, summary) { +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 184, 212, 0.1); } -:is(.info, .todo) > :is(.admonition-title, summary)::before { +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00b8d4; - mask-image: var(--md-admonition-icon--info); - -webkit-mask-image: var(--md-admonition-icon--info); + mask-image: var(--md-admonition-icon--admonish-info); + -webkit-mask-image: var(--md-admonition-icon--admonish-info); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.tip, .hint, .important) { +:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { border-color: #00bfa5; } -:is(.tip, .hint, .important) > :is(.admonition-title, summary) { +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 191, 165, 0.1); } -:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00bfa5; - mask-image: var(--md-admonition-icon--tip); - -webkit-mask-image: var(--md-admonition-icon--tip); + mask-image: var(--md-admonition-icon--admonish-tip); + -webkit-mask-image: var(--md-admonition-icon--admonish-tip); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.success, .check, .done) { +:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { border-color: #00c853; } -:is(.success, .check, .done) > :is(.admonition-title, summary) { +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 200, 83, 0.1); } -:is(.success, .check, .done) > :is(.admonition-title, summary)::before { +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00c853; - mask-image: var(--md-admonition-icon--success); - -webkit-mask-image: var(--md-admonition-icon--success); + mask-image: var(--md-admonition-icon--admonish-success); + -webkit-mask-image: var(--md-admonition-icon--admonish-success); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.question, .help, .faq) { +:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { border-color: #64dd17; } -:is(.question, .help, .faq) > :is(.admonition-title, summary) { +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(100, 221, 23, 0.1); } -:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { background-color: #64dd17; - mask-image: var(--md-admonition-icon--question); - -webkit-mask-image: var(--md-admonition-icon--question); + mask-image: var(--md-admonition-icon--admonish-question); + -webkit-mask-image: var(--md-admonition-icon--admonish-question); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.warning, .caution, .attention) { +:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { border-color: #ff9100; } -:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 145, 0, 0.1); } -:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff9100; - mask-image: var(--md-admonition-icon--warning); - -webkit-mask-image: var(--md-admonition-icon--warning); + mask-image: var(--md-admonition-icon--admonish-warning); + -webkit-mask-image: var(--md-admonition-icon--admonish-warning); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.failure, .fail, .missing) { +:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { border-color: #ff5252; } -:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 82, 82, 0.1); } -:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff5252; - mask-image: var(--md-admonition-icon--failure); - -webkit-mask-image: var(--md-admonition-icon--failure); + mask-image: var(--md-admonition-icon--admonish-failure); + -webkit-mask-image: var(--md-admonition-icon--admonish-failure); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.danger, .error) { +:is(.admonition):is(.admonish-danger, .admonish-error) { border-color: #ff1744; } -:is(.danger, .error) > :is(.admonition-title, summary) { +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 23, 68, 0.1); } -:is(.danger, .error) > :is(.admonition-title, summary)::before { +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff1744; - mask-image: var(--md-admonition-icon--danger); - -webkit-mask-image: var(--md-admonition-icon--danger); + mask-image: var(--md-admonition-icon--admonish-danger); + -webkit-mask-image: var(--md-admonition-icon--admonish-danger); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.bug) { +:is(.admonition):is(.admonish-bug) { border-color: #f50057; } -:is(.bug) > :is(.admonition-title, summary) { +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(245, 0, 87, 0.1); } -:is(.bug) > :is(.admonition-title, summary)::before { +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { background-color: #f50057; - mask-image: var(--md-admonition-icon--bug); - -webkit-mask-image: var(--md-admonition-icon--bug); + mask-image: var(--md-admonition-icon--admonish-bug); + -webkit-mask-image: var(--md-admonition-icon--admonish-bug); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.example) { +:is(.admonition):is(.admonish-example) { border-color: #7c4dff; } -:is(.example) > :is(.admonition-title, summary) { +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(124, 77, 255, 0.1); } -:is(.example) > :is(.admonition-title, summary)::before { +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { background-color: #7c4dff; - mask-image: var(--md-admonition-icon--example); - -webkit-mask-image: var(--md-admonition-icon--example); + mask-image: var(--md-admonition-icon--admonish-example); + -webkit-mask-image: var(--md-admonition-icon--admonish-example); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } -:is(.admonition):is(.quote, .cite) { +:is(.admonition):is(.admonish-quote, .admonish-cite) { border-color: #9e9e9e; } -:is(.quote, .cite) > :is(.admonition-title, summary) { +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(158, 158, 158, 0.1); } -:is(.quote, .cite) > :is(.admonition-title, summary)::before { +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { background-color: #9e9e9e; - mask-image: var(--md-admonition-icon--quote); - -webkit-mask-image: var(--md-admonition-icon--quote); + mask-image: var(--md-admonition-icon--admonish-quote); + -webkit-mask-image: var(--md-admonition-icon--admonish-quote); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; @@ -340,7 +327,8 @@ details[open].admonition > summary.admonition-title::after { background-color: var(--sidebar-bg); } -.ayu :is(.admonition), .coal :is(.admonition) { +.ayu :is(.admonition), +.coal :is(.admonition) { background-color: var(--theme-hover); }