From d4dc634ed0089084186d7ede9b4ef9f18e3348a5 Mon Sep 17 00:00:00 2001 From: piegames Date: Tue, 28 Feb 2023 15:49:11 +0100 Subject: [PATCH 01/10] Remove Sphinx related files We want this repository to be agnostic of any site generators or similar. Information related to rendering the markdown as web page should be stored externally. --- conf.py | 185 ------------------------------------------------------ index.rst | 33 ---------- shell.nix | 14 +---- 3 files changed, 2 insertions(+), 230 deletions(-) delete mode 100644 conf.py delete mode 100644 index.rst diff --git a/conf.py b/conf.py deleted file mode 100644 index 8bb08de..0000000 --- a/conf.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Magic-Wormhole documentation build configuration file, created by -# sphinx-quickstart on Sun Nov 12 10:24:09 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - -from recommonmark.parser import CommonMarkParser - -source_parsers = { - ".md": CommonMarkParser, -} - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -source_suffix = ['.rst', '.md'] -#source_suffix = '.md' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Magic-Wormhole' -copyright = u'2017, Brian Warner' -author = u'Brian Warner' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -def _get_versions(): - import os.path, sys, subprocess - here = os.path.dirname(os.path.abspath(__file__)) - parent = os.path.dirname(here) - v = subprocess.check_output([sys.executable, "setup.py", "--version"], - cwd=parent) - if sys.version_info[0] >= 3: - v = v.decode() - short = ".".join(v.split(".")[:2]) - long = v - return short, long -version, release = _get_versions() -# The short X.Y version. -#version = u'0.10' -# The full version, including alpha/beta/rc tags. -#release = u'0.10.3' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - ] -} - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Magic-Wormholedoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'Magic-Wormhole.tex', u'Magic-Wormhole Documentation', - u'Brian Warner', 'manual'), -] - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'magic-wormhole', u'Magic-Wormhole Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'Magic-Wormhole', u'Magic-Wormhole Documentation', - author, 'Magic-Wormhole', 'One line description of project.', - 'Miscellaneous'), -] - - - diff --git a/index.rst b/index.rst deleted file mode 100644 index 48b66dc..0000000 --- a/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. Magic-Wormhole documentation master file, created by - sphinx-quickstart on Sun Nov 12 10:24:09 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Magic-Wormhole: Get Things From One Computer To Another, Safely -=============================================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - welcome - tor - - introduction - api - transit - server-protocol - client-protocol - file-transfer-protocol - uri-scheme - - attacks - journal - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/shell.nix b/shell.nix index ae1df91..8924a88 100644 --- a/shell.nix +++ b/shell.nix @@ -2,16 +2,6 @@ with import {}; with pkgs; -let - pythonPkgs = python-packages: with python-packages; [ - sphinx - ]; - python = python3.withPackages pythonPkgs; -in - stdenv.mkDerivation { - name = "impurePythonEnv"; - - buildInputs = [ - python - ]; +mkShell { + nativeBuildInputs = []; } From 2ee914f1e153c8ae67cb407f3703f6a0e07a2f05 Mon Sep 17 00:00:00 2001 From: piegames Date: Tue, 28 Feb 2023 16:23:50 +0100 Subject: [PATCH 02/10] Delete new-protocol.svg It doesn't seem to be reference anywhere and also looks like a prototype/sketch. --- new-protocol.svg | 2000 ---------------------------------------------- 1 file changed, 2000 deletions(-) delete mode 100644 new-protocol.svg diff --git a/new-protocol.svg b/new-protocol.svg deleted file mode 100644 index a69b79a..0000000 --- a/new-protocol.svg +++ /dev/null @@ -1,2000 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - connectionMade() - dataReceived() - dataReceived() - connectionLost() - - - empty - - - - open - - - - open - - - - closing - - - - empty - - - - - connect() - - - Open1 - - write() - write() - loseConnection() - connectionLost() - - - open - - - - - - Data1 - - - - Data1 - - - - Close1 - - - - Close1 - - - - - - - - - - - - - - empty - - - - open - - - - open - - - - empty - - - - - - open - - - - - - - - - - - - - - - Open1 - - - - Data1 - - - - Data1 - - - - Close1 - - connection 1 - - - Open1 - - - - Data1 - - 0 - 1 - 2 - 3 - - - ack 0 - - connection 2 - - - Data1 - - - - ack 1 - - - - Data1 - - - - Close1 - - - - ack 2 - - - - ack 3 - - - - Close1 - - - - ack 0' - - 0' - 0 - 1 - 1 - 2 - 3 - 0' - logical - 0 - 1 - 2 - 3 - - From 8e317befe98a751ae198edbf4600ba51a92cf45e Mon Sep 17 00:00:00 2001 From: piegames Date: Tue, 28 Feb 2023 17:07:51 +0100 Subject: [PATCH 03/10] Remove Python-specific documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #30. Those files also contained a couple of paragraphs – mainly the general introduction – that will have to be rewritten in a client-agnostic style. --- api.md | 701 ------------------------------------------------ introduction.md | 56 ---- journal.md | 148 ---------- tor.md | 90 ------- welcome.md | 339 ----------------------- 5 files changed, 1334 deletions(-) delete mode 100644 api.md delete mode 100644 introduction.md delete mode 100644 journal.md delete mode 100644 tor.md delete mode 100644 welcome.md diff --git a/api.md b/api.md deleted file mode 100644 index a2f0e61..0000000 --- a/api.md +++ /dev/null @@ -1,701 +0,0 @@ -# The Magic-Wormhole API - -This library provides a mechanism to securely transfer small amounts -of data between two computers. Both machines must be connected to the -internet, but they do not need to have public IP addresses or know how to -contact each other ahead of time. - -Security and connectivity is provided by means of a "wormhole code": a short -string that is transcribed from one machine to the other by the users at the -keyboard. This works in conjunction with a baked-in "rendezvous server" that -relays information from one machine to the other. - -The "Wormhole" object provides a secure record pipe between any two programs -that use the same wormhole code (and are configured with the same application -ID and rendezvous server). Each side can send multiple messages to the other, -but the encrypted data for all messages must pass through (and be temporarily -stored on) the rendezvous server, which is a shared resource. For this -reason, larger data (including bulk file transfers) should use the Transit -class instead. The Wormhole can be used to create a Transit object for this -purpose. In the future, Transit will be deprecated, and this functionality -will be incorporated directly as a "dilated wormhole". - -A quick example: - -```python -import wormhole -from twisted.internet.defer import inlineCallbacks - -@inlineCallbacks -def go(): - w = wormhole.create(appid, relay_url, reactor) - w.allocate_code() - code = yield w.get_code() - print "code:", code - w.send_message(b"outbound data") - inbound = yield w.get_message() - yield w.close() -``` - -## Modes - -The API comes in two flavors: Delegated and Deferred. Controlling the -Wormhole and sending data is identical in both, but they differ in how -inbound data and events are delivered to the application. - -In Delegated mode, the Wormhole is given a "delegate" object, on which -certain methods will be called when information is available (e.g. when the -code is established, or when data messages are received). In Deferred mode, -the Wormhole object has methods which return Deferreds that will fire at -these same times. - -Delegated mode: - -```python -class MyDelegate: - def wormhole_got_code(self, code): - print("code: %s" % code) - def wormhole_got_message(self, msg): # called for each message - print("got data, %d bytes" % len(msg)) - -w = wormhole.create(appid, relay_url, reactor, delegate=MyDelegate()) -w.allocate_code() -``` - -Deferred mode: - -```python -w = wormhole.create(appid, relay_url, reactor) -w.allocate_code() -def print_code(code): - print("code: %s" % code) -w.get_code().addCallback(print_code) -def received(msg): - print("got data, %d bytes" % len(msg)) -w.get_message().addCallback(received) # gets exactly one message -``` - -## Application Identifier - -Applications using this library must provide an "application identifier", a -simple string that distinguishes one application from another. To ensure -uniqueness, use a domain name. To use multiple apps for a single domain, -append a URL-like slash and path, like `example.com/app1`. This string must -be the same on both clients, otherwise they will not see each other. The -invitation codes are scoped to the app-id. Note that the app-id must be -unicode, not bytes, so on python2 use `u"appid"`. - -Distinct app-ids reduce the size of the connection-id numbers. If fewer than -ten Wormholes are active for a given app-id, the connection-id will only need -to contain a single digit, even if some other app-id is currently using -thousands of concurrent sessions. - -## Rendezvous Servers - -The library depends upon a "rendezvous server", which is a service (on a -public IP address) that delivers small encrypted messages from one client to -the other. This must be the same for both clients, and is generally baked-in -to the application source code or default config. - -This library includes the URL of a public rendezvous server run by the -author. Application developers can use this one, or they can run their own -(see the https://github.com/warner/magic-wormhole-mailbox-server repository) -and configure their clients to use it instead. The URL of the public -rendevouz server is passed as a unicode string. Note that because the server -actually speaks WebSockets, the URL starts with `ws:` instead of `http:`. - -## Wormhole Parameters - -All wormholes must be created with at least three parameters: - -* `appid`: a (unicode) string -* `relay_url`: a (unicode) string -* `reactor`: the Twisted reactor object - -In addition to these three, the `wormhole.create()` function takes several -optional arguments: - -* `delegate`: provide a Delegate object to enable "delegated mode", or pass - None (the default) to get "deferred mode" -* `journal`: provide a Journal object to enable journaled mode. See - journal.md for details. Note that journals only work with delegated mode, - not with deferred mode. -* `tor_manager`: to enable Tor support, create a `wormhole.TorManager` - instance and pass it here. This will hide the client's IP address by - proxying all connections (rendezvous and transit) through Tor. It also - enables connecting to Onion-service transit hints, and (in the future) will - enable the creation of Onion-services for transit purposes. -* `timing`: this accepts a DebugTiming instance, mostly for internal - diagnostic purposes, to record the transmit/receive timestamps for all - messages. The `wormhole --dump-timing=` feature uses this to build a - JSON-format data bundle, and the `misc/dump-timing.py` tool can build a - scrollable timing diagram from these bundles. -* `welcome_handler`: this is a function that will be called when the - Rendezvous Server's "welcome" message is received. It is used to display - important server messages in an application-specific way. -* `versions`: this can accept a dictionary (JSON-encodable) of data that will - be made available to the peer via the `got_version` event. This data is - delivered before any data messages, and can be used to indicate peer - capabilities. - -## Code Management - -Each wormhole connection is defined by a shared secret "wormhole code". These -codes can be created by humans offline (by picking a unique number and some -secret words), but are more commonly generated by asking the library to make -one. In the "bin/wormhole" file-transfer tool, the default behavior is for -the sender's program to create the code, and for the receiver to type it in. - -The code is a (unicode) string in the form `NNN-code-words`. The numeric -"NNN" prefix is the "channel id" or "nameplate", and is a short integer -allocated by talking to the rendezvous server. The rest is a -randomly-generated selection from the PGP wordlist, providing a default of 16 -bits of entropy. The initiating program should display this code to the user, -who should transcribe it to the receiving user, who gives it to their local -Wormhole object by calling `set_code()`. The receiving program can also use -`input_code()` to use a readline-based input function: this offers tab -completion of allocated channel-ids and known codewords. - -The Wormhole object has three APIs for generating or accepting a code: - -* `w.allocate_code(length=2)`: this contacts the Rendezvous Server, allocates - a short numeric nameplate, chooses a configurable number of random words, - then assembles them into the code -* `w.set_code(code)`: this accepts the complete code as an argument -* `helper = w.input_code()`: this facilitates interactive entry of the code, - with tab-completion. The helper object has methods to return a list of - viable completions for whatever portion of the code has been entered so - far. A convenience wrapper is provided to attach this to the `rlcompleter` - function of libreadline. - -No matter which mode is used, the `w.get_code()` Deferred (or -`delegate.wormhole_got_code(code)` callback) will fire when the code is -known. `get_code` is clearly necessary for `allocate_code`, since there's no -other way to learn what code was created, but it may be useful in other modes -for consistency. - -The code-entry Helper object has the following API: - -* `refresh_nameplates()`: requests an updated list of nameplates from the - Rendezvous Server. These form the first portion of the wormhole code (e.g. - "4" in "4-purple-sausages"). Note that they are unicode strings (so "4", - not 4). The Helper will get the response in the background, and calls to - `get_nameplate_completions()` after the response will use the new list. - Calling this after `h.choose_nameplate` will raise - `AlreadyChoseNameplateError`. -* `matches = h.get_nameplate_completions(prefix)`: returns (synchronously) a - set of completions for the given nameplate prefix, along with the hyphen - that always follows the nameplate (and separates the nameplate from the - rest of the code). For example, if the server reports nameplates 1, 12, 13, - 24, and 170 are in use, `get_nameplate_completions("1")` will return - `{"1-", "12-", "13-", "170-"}`. You may want to sort these before - displaying them to the user. Raises `AlreadyChoseNameplateError` if called - after `h.choose_nameplate`. -* `h.choose_nameplate(nameplate)`: accepts a string with the chosen - nameplate. May only be called once, after which - `AlreadyChoseNameplateError` is raised. (in this future, this might - return a Deferred that fires (with None) when the nameplate's wordlist is - known (which happens after the nameplate is claimed, requiring a roundtrip - to the server)). -* `d = h.when_wordlist_is_available()`: return a Deferred that fires (with - None) when the wordlist is known. This can be used to block a readline - frontend which has just called `h.choose_nameplate()` until the resulting - wordlist is known, which can improve the tab-completion behavior. -* `matches = h.get_word_completions(prefix)`: return (synchronously) a set of - completions for the given words prefix. This will include a trailing hyphen - if more words are expected. The possible completions depend upon the - wordlist in use for the previously-claimed nameplate, so calling this - before `choose_nameplate` will raise `MustChooseNameplateFirstError`. - Calling this after `h.choose_words()` will raise `AlreadyChoseWordsError`. - Given a prefix like "su", this returns a set of strings which are potential - matches (e.g. `{"supportive-", "surrender-", "suspicious-"}`. The prefix - should not include the nameplate, but *should* include whatever words and - hyphens have been typed so far (the default wordlist uses alternate lists, - where even numbered words have three syllables, and odd numbered words have - two, so the completions depend upon how many words are present, not just - the partial last word). E.g. `get_word_completions("pr")` will return - `{"processor-", "provincial-", "proximate-"}`, while - `get_word_completions("opulent-pr")` will return `{"opulent-preclude", - "opulent-prefer", "opulent-preshrunk", "opulent-printer", - "opulent-prowler"}` (note the lack of a trailing hyphen, because the - wordlist is expecting a code of length two). If the wordlist is not yet - known, this returns an empty set. All return values will - `.startswith(prefix)`. The frontend is responsible for sorting the results - before display. -* `h.choose_words(words)`: call this when the user is finished typing in the - code. It does not return anything, but will cause the Wormhole's - `w.get_code()` (or corresponding delegate) to fire, and triggers the - wormhole connection process. This accepts a string like "purple-sausages", - without the nameplate. It must be called after `h.choose_nameplate()` or - `MustChooseNameplateFirstError` will be raised. May only be called once, - after which `AlreadyChoseWordsError` is raised. - -The `input_with_completion` wrapper is a function that knows how to use the -code-entry helper to do tab completion of wormhole codes: - -```python -from wormhole import create, input_with_completion -w = create(appid, relay_url, reactor) -input_with_completion("Wormhole code:", w.input_code(), reactor) -d = w.get_code() -``` - -This helper runs python's (raw) `input()` function inside a thread, since -`input()` normally blocks. - -The two machines participating in the wormhole setup are not distinguished: -it doesn't matter which one goes first, and both use the same Wormhole -constructor function. However if `w.allocate_code()` is used, only one side -should use it. - -Providing an invalid nameplate (which is easily caused by cut-and-paste -errors that include an extra space at the beginning, or which copy the words -but not the number) will raise a `KeyFormatError`, either in -`w.set_code(code)` or in `h.choose_nameplate()`. - -## Offline Codes - -In most situations, the "sending" or "initiating" side will call -`w.allocate_code()` and display the resulting code. The sending human reads -it and speaks, types, performs charades, or otherwise transmits the code to -the receiving human. The receiving human then types it into the receiving -computer, where it either calls `w.set_code()` (if the code is passed in via -argv) or `w.input_code()` (for interactive entry). - -Usually one machine generates the code, and a pair of humans transcribes it -to the second machine (so `w.allocate_code()` on one side, and `w.set_code()` -or `w.input_code()` on the other). But it is also possible for the humans to -generate the code offline, perhaps at a face-to-face meeting, and then take -the code back to their computers. In this case, `w.set_code()` will be used -on both sides. It is unlikely that the humans will restrict themselves to a -pre-established wordlist when manually generating codes, so the completion -feature of `w.input_code()` is not helpful. - -When the humans create an invitation code out-of-band, they are responsible -for choosing an unused channel-ID (simply picking a random 3-or-more digit -number is probably enough), and some random words. Dice, coin flips, shuffled -cards, or repeated sampling of a high-resolution stopwatch are all useful -techniques. The invitation code uses the same format either way: channel-ID, -a hyphen, and an arbitrary string. There is no need to encode the sampled -random values (e.g. by using the Diceware wordlist) unless that makes it -easier to transcribe: e.g. rolling 6 dice could result in a code like -"913-166532", and flipping 16 coins could result in "123-HTTHHHTTHTTHHTHH". - -## Welcome Messages - -The first message sent by the rendezvous server is a "welcome" message (a -dictionary). This is sent as soon as the client connects to the server, -generally before the code is established. Clients should use -`d=get_welcome()` to get and process the `motd` key (and maybe -`current_cli_version`) inside the welcome message. - -The welcome message serves three main purposes: - -* notify users about important server changes, such as CAPTCHA requirements - driven by overload, or donation requests -* enable future protocol negotiation between clients and the server -* advise users of the CLI tools (`wormhole send`) to upgrade to a new version - -There are three keys currently defined for the welcome message, all of which -are optional (the welcome message omits "error" and "motd" unless the server -operator needs to signal a problem). - -* `motd`: if this key is present, it will be a string with embedded newlines. - The client should display this string to the user, including a note that it - comes from the magic-wormhole Rendezvous Server and that server's URL. -* `error`: if present, the server has decided it cannot service this client. - The string will be wrapped in a `WelcomeError` (which is a subclass of - `WormholeError`), and all API calls will signal errors (pending Deferreds - will errback). The rendezvous connection will be closed. -* `current_cli_version`: if present, the server is advising instances of the - CLI tools (the `wormhole` command included in the python distribution) that - there is a newer release available, thus users should upgrade if they can, - because more features will be available if both clients are running the - same version. The CLI tools compare this string against their `__version__` - and can print a short message to stderr if an upgrade is warranted. - -There is currently no facility in the server to actually send `motd`, but a -static `error` string can be included by running the server with -`--signal-error=MESSAGE`. - -The main idea of `error` is to allow the server to cleanly inform the client -about some necessary action it didn't take. The server currently sends the -welcome message as soon as the client connects (even before it receives the -"claim" request), but a future server could wait for a required client -message and signal an error (via the Welcome message) if it didn't see this -extra message before the CLAIM arrived. - -This could enable changes to the protocol, e.g. requiring a CAPTCHA or -proof-of-work token when the server is under DoS attack. The new server would -send the current requirements in an initial message (which old clients would -ignore). New clients would be required to send the token before their "claim" -message. If the server sees "claim" before "token", it knows that the client -is too old to know about this protocol, and it could send a "welcome" with an -`error` field containing instructions (explaining to the user that the server -is under attack, and they must either upgrade to a client that can speak the -new protocol, or wait until the attack has passed). Either case is better -than an opaque exception later when the required message fails to arrive. - -(Note that the server can also send an explicit ERROR message at any time, -and the client should react with a ServerError. Versions 0.9.2 and earlier of -the library did not pay attention to the ERROR message, hence the server -should deliver errors in a WELCOME message if at all possible) - -The `error` field is handled internally by the Wormhole object. The other -fields can be processed by application, by using `d=w.get_welcome()`. The -Deferred will fire with the full welcome dictionary, so any other keys that a -future server might send will be available to it. - -Applications which need to display `motd` or an upgrade message, and wish to -do so before using stdin/stdout for interactive code entry (`w.input_code()`) -should wait for `get_welcome()` before starting the entry process: - -```python -@inlineCallbacks -def go(): - w = wormhole.create(appid, relay_url, reactor) - welcome = yield w.get_welcome() - if "motd" in welcome: print welcome["motd"] - input_with_completion("Wormhole code:", w.input_code(), reactor) - ... -``` - -## Verifier - -For extra protection against guessing attacks, Wormhole can provide a -"Verifier". This is a moderate-length series of bytes (a SHA256 hash) that is -derived from the supposedly-shared session key. If desired, both sides can -display this value, and the humans can manually compare them before allowing -the rest of the protocol to proceed. If they do not match, then the two -programs are not talking to each other (they may both be talking to a -man-in-the-middle attacker), and the protocol should be abandoned. - -Deferred-mode applications can wait for `d=w.get_verifier()`: the Deferred -it returns will fire with the verifier. You can turn this into hex or Base64 -to print it, or render it as ASCII-art, etc. - -Asking the wormhole object for the verifier does not affect the flow of the -protocol. To benefit from verification, applications must refrain from -sending any data (with `w.send_message(data)`) until after the verifiers are -approved by the user. In addition, applications must queue or otherwise -ignore incoming (received) messages until that point. However once the -verifiers are confirmed, previously-received messages can be considered valid -and processed as usual. - -## Events - -As the wormhole connection is established, several events may be dispatched -to the application. In Delegated mode, these are dispatched by calling -functions on the delegate object. In Deferred mode, the application retrieves -Deferred objects from the wormhole, and event dispatch is performed by firing -those Deferreds. - -Most applications will only use `code`, `received`, and `close`. - -* code (`code = yield w.get_code()` / `dg.wormhole_got_code(code)`): fired - when the wormhole code is established, either after `w.allocate_code()` - finishes the generation process, or when the Input Helper returned by - `w.input_code()` has been told `h.set_words()`, or immediately after - `w.set_code(code)` is called. This is most useful after calling - `w.allocate_code()`, to show the generated code to the user so they can - transcribe it to their peer. -* key (`yield w.get_unverified_key()` / - `dg.wormhole_got_unverified_key(key)`): fired (with the raw master SPAKE2 - key) when the key-exchange process has completed and a purported shared key - is established. At this point we do not know that anyone else actually - shares this key: the peer may have used the wrong code, or may have - disappeared altogether. To wait for proof that the key is shared, wait for - `get_verifier` instead. This event is really only useful for detecting that - the initiating peer has disconnected after leaving the initial PAKE - message, to display a pacifying message to the user. -* verifier (`verifier = yield w.get_verifier()` / - `dg.wormhole_got_verifier(verifier)`: fired when the key-exchange process - has completed and a valid VERSION message has arrived. The "verifier" is a - byte string with a hash of the shared session key; clients can compare them - (probably as hex) to ensure that they're really talking to each other, and - not to a man-in-the-middle. When `get_verifier` happens, this side knows - that *someone* has used the correct wormhole code; if someone used the - wrong code, the VERSION message cannot be decrypted, and the wormhole will - be closed instead. -* versions (`versions = yield w.get_versions()` / - `dg.wormhole_got_versions(versions)`: fired when the VERSION message - arrives from the peer. This fires just after `verified`, but delivers the - "app_versions" data (as passed into `wormhole.create(versions=)`) instead - of the verifier string. This is mostly a hack to make room for - forwards-compatible changes to the CLI file-transfer protocol, which sends - a request in the first message (rather than merely sending the abilities of - each side). -* received (`yield w.get_message()` / `dg.wormhole_got_message(msg)`: fired - each time a data message arrives from the peer, with the bytestring that - the peer passed into `w.send_message(msg)`. This is the primary - data-transfer API. -* closed (`yield w.close()` / `dg.wormhole_closed(result)`: fired when - `w.close()` has finished shutting down the wormhole, which means all - nameplates and mailboxes have been deallocated, and the WebSocket - connection has been closed. This also fires if an internal error occurs - (specifically WrongPasswordError, which indicates that an invalid encrypted - message was received), which also shuts everything down. The `result` value - is an exception (or Failure) object if the wormhole closed badly, or a - string like "happy" if it had no problems before shutdown. - -## Sending Data - -The main purpose of a Wormhole is to send data. At any point after -construction, callers can invoke `w.send_message(msg)`. This will queue the -message if necessary, but (if all goes well) will eventually result in the -peer getting a `received` event and the data being delivered to the -application. - -Since Wormhole provides an ordered record pipe, each call to `w.send_message` -will result in exactly one `received` event on the far side. Records are not -split, merged, dropped, or reordered. - -Each side can do an arbitrary number of `send_message()` calls. The Wormhole -is not meant as a long-term communication channel, but some protocols work -better if they can exchange an initial pair of messages (perhaps offering -some set of negotiable capabilities), and then follow up with a second pair -(to reveal the results of the negotiation). The Rendezvous Server does not -currently enforce any particular limits on number of messages, size of -messages, or rate of transmission, but in general clients are expected to -send fewer than a dozen messages, of no more than perhaps 20kB in size -(remember that all these messages are temporarily stored in a SQLite database -on the server). A future version of the protocol may make these limits more -explicit, and will allow clients to ask for greater capacity when they -connect (probably by passing additional "mailbox attribute" parameters with -the `allocate`/`claim`/`open` messages). - -For bulk data transfer, see "transit.md", or the "Dilation" section below. - -## Closing - -When the application is done with the wormhole, it should call `w.close()`, -and wait for a `closed` event. This ensures that all server-side resources -are released (allowing the nameplate to be re-used by some other client), and -all network sockets are shut down. - -In Deferred mode, this just means waiting for the Deferred returned by -`w.close()` to fire. In Delegated mode, this means calling `w.close()` (which -doesn't return anything) and waiting for the delegate's `wormhole_closed()` -method to be called. - -`w.close()` will errback (with some form of `WormholeError`) if anything went -wrong with the process, such as: - -* `WelcomeError`: the server told us to signal an error, probably because the - client is too old understand some new protocol feature -* `ServerError`: the server rejected something we did -* `LonelyError`: we didn't hear from the other side, so no key was - established -* `WrongPasswordError`: we received at least one incorrectly-encrypted - message. This probably indicates that the other side used a different - wormhole code than we did, perhaps because of a typo, or maybe an attacker - tried to guess your code and failed. - -If the wormhole was happy at the time it was closed, the `w.close()` Deferred -will callback (probably with the string "happy", but this may change in the -future). - -## Serialization - -(NOTE: this section is speculative: this code has not yet been written) - -Wormhole objects can be serialized. This can be useful for apps which save -their own state before shutdown, and restore it when they next start up -again. - - -The `w.serialize()` method returns a dictionary which can be JSON encoded -into a unicode string (most applications will probably want to UTF-8 -encode -this into a bytestring before saving on disk somewhere). - -To restore a Wormhole, call `wormhole.from_serialized(data, reactor, -delegate)`. This will return a wormhole in roughly the same state as was -serialized (of course all the network connections will be disconnected). - -Serialization only works for delegated-mode wormholes (since Deferreds point -at functions, which cannot be serialized easily). It also only works for -"non-dilated" wormholes (see below). - -To ensure correct behavior, serialization should probably only be done in -"journaled mode". See journal.md for details. - -If you use serialization, be careful to never use the same partial wormhole -object twice. - -## Dilation - -(NOTE: this API is still in development) - -To send bulk data, or anything more than a handful of messages, a Wormhole -can be "dilated" into a form that uses a direct TCP connection between the -two endpoints. - -All wormholes start out "undilated". In this state, all messages are queued -on the Rendezvous Server for the lifetime of the wormhole, and server-imposed -number/size/rate limits apply. Calling `w.dilate()` initiates the dilation -process, and eventually yields a set of Endpoints. Once dilated, the usual -`.send_message()`/`.get_message()` APIs are disabled (TODO: really?), and -these endpoints can be used to establish multiple (encrypted) "subchannel" -connections to the other side. - -Each subchannel behaves like a regular Twisted `ITransport`, so they can be -glued to the Protocol instance of your choice. They also implement the -IConsumer/IProducer interfaces. - -These subchannels are *durable*: as long as the processes on both sides keep -running, the subchannel will survive the network connection being dropped. -For example, a file transfer can be started from a laptop, then while it is -running, the laptop can be closed, moved to a new wifi network, opened back -up, and the transfer will resume from the new IP address. - -What's good about a non-dilated wormhole?: - -* setup is faster: no delay while it tries to make a direct connection -* works with "journaled mode", allowing progress to be made even when both - sides are never online at the same time, by serializing the wormhole - -What's good about dilated wormholes?: - -* they support bulk data transfer -* you get flow control (backpressure), and IProducer/IConsumer -* throughput is faster: no store-and-forward step - -Use non-dilated wormholes when your application only needs to exchange a -couple of messages, for example to set up public keys or provision access -tokens. Use a dilated wormhole to move files. - -Dilated wormholes can provide multiple "subchannels": these are multiplexed -through the single (encrypted) TCP connection. Each subchannel is a separate -stream (offering IProducer/IConsumer for flow control), and is opened and -closed independently. A special "control channel" is available to both sides -so they can coordinate how they use the subchannels. - -The `d = w.dilate()` Deferred fires with a triple of Endpoints: - -```python -d = w.dilate() -def _dilated(res): - (control_channel_ep, subchannel_client_ep, subchannel_server_ep) = res -d.addCallback(_dilated) -``` - -The `control_channel_ep` endpoint is a client-style endpoint, so both sides -will connect to it with `ep.connect(factory)`. This endpoint is single-use: -calling `.connect()` a second time will fail. The control channel is -symmetric: it doesn't matter which side is the application-level -client/server or initiator/responder, if the application even has such -concepts. The two applications can use the control channel to negotiate who -goes first, if necessary. - -The subchannel endpoints are *not* symmetric: for each subchannel, one side -must listen as a server, and the other must connect as a client. Subchannels -can be established by either side at any time. This supports e.g. -bidirectional file transfer, where either user of a GUI app can drop files -into the "wormhole" whenever they like. - -The `subchannel_client_ep` on one side is used to connect to the other side's -`subchannel_server_ep`, and vice versa. The client endpoint is reusable. The -server endpoint is single-use: `.listen(factory)` may only be called once. - -Applications are under no obligation to use subchannels: for many use cases, -the control channel is enough. - -To use subchannels, once the wormhole is dilated and the endpoints are -available, the listening-side application should attach a listener to the -`subchannel_server_ep` endpoint: - -```python -def _dilated(res): - (control_channel_ep, subchannel_client_ep, subchannel_server_ep) = res - f = Factory(MyListeningProtocol) - subchannel_server_ep.listen(f) -``` - -When the connecting-side application wants to connect to that listening -protocol, it should use `.connect()` with a suitable connecting protocol -factory: - -```python -def _connect(): - f = Factory(MyConnectingProtocol) - subchannel_client_ep.connect(f) -``` - -For a bidirectional file-transfer application, both sides will establish a -listening protocol. Later, if/when the user drops a file on the application -window, that side will initiate a connection, use the resulting subchannel to -transfer the single file, and then close the subchannel. - -```python -def FileSendingProtocol(internet.Protocol): - def __init__(self, metadata, filename): - self.file_metadata = metadata - self.file_name = filename - def connectionMade(self): - self.transport.write(self.file_metadata) - sender = protocols.basic.FileSender() - f = open(self.file_name,"rb") - d = sender.beginFileTransfer(f, self.transport) - d.addBoth(self._done, f) - def _done(res, f): - self.transport.loseConnection() - f.close() -def _send(metadata, filename): - f = protocol.ClientCreator(reactor, - FileSendingProtocol, metadata, filename) - subchannel_client_ep.connect(f) -def FileReceivingProtocol(internet.Protocol): - state = INITIAL - def dataReceived(self, data): - if state == INITIAL: - self.state = DATA - metadata = parse(data) - self.f = open(metadata.filename, "wb") - else: - # local file writes are blocking, so don't bother with IConsumer - self.f.write(data) - def connectionLost(self, reason): - self.f.close() -def _dilated(res): - (control_channel_ep, subchannel_client_ep, subchannel_server_ep) = res - f = Factory(FileReceivingProtocol) - subchannel_server_ep.listen(f) -``` - -## Bytes, Strings, Unicode, and Python 3 - -All cryptographically-sensitive parameters are passed as bytes ("str" in -python2, "bytes" in python3): - -* verifier string -* data in/out -* transit records in/out - -Other (human-facing) values are always unicode ("unicode" in python2, "str" -in python3): - -* wormhole code -* relay URL -* transit URLs -* transit connection hints (e.g. "host:port") -* application identifier -* derived-key "purpose" string: `w.derive_key(PURPOSE, LENGTH)` - -## Full API list - -action | Deferred-Mode | Delegated-Mode ------------------- | ------------------ | -------------- -. | d=w.get_welcome() | dg.wormhole_got_welcome(welcome) - w.allocate_code() | | -h=w.input_code() | | - w.set_code(code) | | -. | d=w.get_code() | dg.wormhole_got_code(code) -. | d=w.get_unverified_key() | dg.wormhole_got_unverified_key(key) -. | d=w.get_verifier() | dg.wormhole_got_verifier(verifier) -. | d=w.get_versions() | dg.wormhole_got_versions(versions) -key=w.derive_key(purpose, length) | | -w.send_message(msg) | | -. | d=w.get_message() | dg.wormhole_got_message(msg) -w.close() | | dg.wormhole_closed(result) -. | d=w.close() | - diff --git a/introduction.md b/introduction.md deleted file mode 100644 index adacc0d..0000000 --- a/introduction.md +++ /dev/null @@ -1,56 +0,0 @@ -# Protocol/API/Library Introduction - -The magic-wormhole (Python) distribution provides several things: an -executable tool ("bin/wormhole"), an importable library (`import wormhole`), -the URL of a publically-available Rendezvous Server, and the definition of a -protocol used by all three. - -The executable tool provides basic sending and receiving of files, -directories, and short text strings. These all use `wormhole send` and -`wormhole receive` (which can be abbreviated as `wormhole tx` and `wormhole -rx`). It also has a mode to facilitate the transfer of SSH keys. This tool, -while useful on its own, is just one possible use of the protocol. - -The `wormhole` library provides an API to establish a bidirectional ordered -encrypted record pipe to another instance (where each record is an -arbitrary-sized bytestring). This does not provide file-transfer directly: -the "bin/wormhole" tool speaks a simple protocol through this record pipe to -negotiate and perform the file transfer. - -`wormhole/cli/public_relay.py` contains the URLs of a Rendezvous Server and a -Transit Relay which I provide to support the file-transfer tools, which other -developers should feel free to use for their applications as well. I cannot -make any guarantees about performance or uptime for these servers: if you -want to use Magic Wormhole in a production environment, please consider -running a server on your own infrastructure (just run `wormhole-server start` -and modify the URLs in your application to point at it). - -## The Magic-Wormhole Protocol - -There are several layers to the protocol. - -At the bottom level, each client opens a WebSocket to the Rendezvous Server, -sending JSON-based commands to the server, and receiving similarly-encoded -messages. Some of these commands are addressed to the server itself, while -others are instructions to queue a message to other clients, or are -indications of messages coming from other clients. All these messages are -described in "server-protocol.md". - -These inter-client messages are used to convey the PAKE protocol exchange, -then a "VERSION" message (which doubles to verify the session key), then some -number of encrypted application-level data messages. "client-protocol.md" -describes these wormhole-to-wormhole messages. - -Each wormhole-using application is then free to interpret the data messages -as it pleases. The file-transfer app sends an "offer" from the `wormhole -send` side, to which the `wormhole receive` side sends a response, after -which the Transit connection is negotiated (if necessary), and finally the -data is sent through the Transit connection. "file-transfer-protocol.md" -describes this application's use of the client messages. - -## The `wormhole` API - -Application use the `wormhole` library to establish wormhole connections and -exchange data through them. Please see `api.md` for a complete description of -this interface. - diff --git a/journal.md b/journal.md deleted file mode 100644 index 46b328a..0000000 --- a/journal.md +++ /dev/null @@ -1,148 +0,0 @@ -# Journaled Mode - -(note: this section is speculative, the code has not yet been written) - -Magic-Wormhole supports applications which are written in a "journaled" or -"checkpointed" style. These apps store their entire state in a well-defined -checkpoint (perhaps in a database), and react to inbound events or messages -by carefully moving from one state to another, then releasing any outbound -messages. As a result, they can be terminated safely at any moment, without -warning, and ensure that the externally-visible behavior is deterministic and -independent of this stop/restart timing. - -This is the style encouraged by the E event loop, the -original [Waterken Server](http://waterken.sourceforge.net/), and the more -modern [Ken Platform](http://web.eecs.umich.edu/~tpkelly/Ken/), all -influential in the object-capability security community. - -## Requirements - -Applications written in this style must follow some strict rules: - -* all state goes into the checkpoint -* the only way to affect the state is by processing an input message -* event processing is deterministic (any non-determinism must be implemented - as a message, e.g. from a clock service or a random-number generator) -* apps must never forget a message for which they've accepted responsibility - -The main processing function takes the previous state checkpoint and a single -input message, and produces a new state checkpoint and a set of output -messages. For performance, the state might be kept in memory between events, -but the behavior should be indistinguishable from that of a server which -terminates completely between events. - -In general, applications must tolerate duplicate inbound messages, and should -re-send outbound messages until the recipient acknowledges them. Any outbound -responses to an inbound message must be queued until the checkpoint is -recorded. If outbound messages were delivered before the checkpointing, then -a crash just after delivery would roll the process back to a state where it -forgot about the inbound event, causing observably inconsistent behavior that -depends upon whether the outbound message successfully escaped the dying -process or not. - -As a result, journaled-style applications use a very specific process when -interacting with the outside world. Their event-processing function looks -like: - -* receive inbound event -* (load state) -* create queue for any outbound messages -* process message (changing state and queuing outbound messages) -* serialize state, record in checkpoint -* deliver any queued outbound messages - -In addition, the protocols used to exchange messages should include message -IDs and acks. Part of the state vector will include a set of unacknowledged -outbound messages. When a connection is established, all outbound messages -should be re-sent, and messages are removed from the pending set when an -inbound ack is received. The state must include a set of inbound message ids -which have been processed already. All inbound messages receive an ack, but -only new ones are processed. Connection establishment/loss is not strictly -included in the journaled-app model (in Waterken/Ken, message delivery is -provided by the platform, and apps do not know about connections), but -general: - -* "I want to have a connection" is stored in the state vector -* "I am connected" is not -* when a connection is established, code can run to deliver pending messages, - and this does not qualify as an inbound event -* inbound events can only happen when at least one connection is established -* immediately after restarting from a checkpoint, no connections are - established, but the app might initiate outbound connections, or prepare to - accept inbound ones - -## Wormhole Support - -To support this mode, the Wormhole constructor accepts a `journal=` argument. -If provided, it must be an object that implements the `wormhole.IJournal` -interface, which consists of two methods: - -* `j.queue_outbound(fn, *args, **kwargs)`: used to delay delivery of outbound - messages until the checkpoint has been recorded -* `j.process()`: a context manager which should be entered before processing - inbound messages - -`wormhole.Journal` is an implementation of this interface, which is -constructed with a (synchronous) `save_checkpoint` function. Applications can -use it, or bring their own. - -The Wormhole object, when configured with a journal, will wrap all inbound -WebSocket message processing with the `j.process()` context manager, and will -deliver all outbound messages through `j.queue_outbound`. Applications using -such a Wormhole must also use the same journal for their own (non-wormhole) -events. It is important to coordinate multiple sources of events: e.g. a UI -event may cause the application to call `w.send(data)`, and the outbound -wormhole message should be checkpointed along with the app's state changes -caused by the UI event. Using a shared journal for both wormhole- and -non-wormhole- events provides this coordination. - -The `save_checkpoint` function should serialize application state along with -any Wormholes that are active. Wormhole state can be obtained by calling -`w.serialize()`, which will return a dictionary (that can be -JSON-serialized). At application startup (or checkpoint resumption), -Wormholes can be regenerated with `wormhole.from_serialized()`. Note that -only "delegated-mode" wormholes can be serialized: Deferreds are not amenable -to usage beyond a single process lifetime. - -For a functioning example of a journaled-mode application, see -misc/demo-journal.py. The following snippet may help illustrate the concepts: - -```python -class App: - @classmethod - def new(klass): - self = klass() - self.state = {} - self.j = wormhole.Journal(self.save_checkpoint) - self.w = wormhole.create(.., delegate=self, journal=self.j) - - @classmethod - def from_serialized(klass): - self = klass() - self.j = wormhole.Journal(self.save_checkpoint) - with open("state.json", "r") as f: - data = json.load(f) - self.state = data["state"] - self.w = wormhole.from_serialized(data["wormhole"], reactor, - delegate=self, journal=self.j) - - def inbound_event(self, event): - # non-wormhole events must be performed in the journal context - with self.j.process(): - parse_event(event) - change_state() - self.j.queue_outbound(self.send, outbound_message) - - def wormhole_received(self, data): - # wormhole events are already performed in the journal context - change_state() - self.j.queue_outbound(self.send, stuff) - - def send(self, outbound_message): - actually_send_message(outbound_message) - - def save_checkpoint(self): - app_state = {"state": self.state, "wormhole": self.w.serialize()} - with open("state.json", "w") as f: - json.dump(app_state, f) -``` diff --git a/tor.md b/tor.md deleted file mode 100644 index c8ce4c5..0000000 --- a/tor.md +++ /dev/null @@ -1,90 +0,0 @@ -# Tor Support in Magic-Wormhole - -The ``wormhole`` command-line tool has built-in support for performing -transfers over Tor. To use it, you must install with the "tor" extra, -like this: - -``` -pip install magic-wormhole[tor] -``` - -## Usage - -Just add ``--tor`` to use a running Tor daemon: - -``` -wormhole send --tor myfile.jpg - -wormhole receive --tor -``` - -You should use ``--tor`` rather than running ``wormhole`` under tsocks -or torsocks because the magic-wormhole "Transit" protocol normally sends -the IP addresses of each computer to its peer, to attempt a direct -connection between the two (somewhat like the FTP protocol would do). -External tor-ifying programs don't know about this, so they can't strip -these addresses out. Using ``--tor`` puts magic-wormhole into a mode -where it does not share any IP addresses. - -``--tor`` causes the program to look for a Tor control port in the three -most common locations: - -* ``unix:/var/run/tor/control``: Debian/Ubuntu Tor listen here -* ``tcp:localhost:9051``: the standard Tor control port -* ``tcp:localhost:9151``: control port for TorBrowser's embedded Tor - -If ``wormhole`` is unable to establish a control-port connection to any -of those locations, it will assume there is a SOCKS daemon listening on -``tcp:localhost:9050``, and hope for the best (if no SOCKS daemon is -available on that port, the initial Rendezvous connection will fail, and -the program will exit with an error before doing anything else). - -The default behavior will Just Work if: - -* you are on a Debian-like system, and the ``tor`` package is installed, - or: -* you have launched the ``tor`` daemon manually, or: -* the TorBrowser application is running when you start ``wormhole`` - -On Debian-like systems, if your account is a member of the -``debian-tor`` group, ``wormhole`` will use the control-port to ask for -the right SOCKS port. If not, it should fall back to using the default -SOCKS port on 9050. To add your account to the ``debian-tor`` group, use -e.g. ``sudo adduser MYUSER debian-tor``. Access to the control-port will -be more significant in the future, when ``wormhole`` can listen on -"onion services": see below for details. - -## Other Ways To Reach Tor - -If ``tor`` is installed, but you cannot use the control-port or -SOCKS-port for some reason, then you can use ``--launch-tor`` to ask -``wormhole`` to start a new Tor daemon for the duration of the transfer -(and then shut it down afterwards). This will add 30-40 seconds to -program startup. - -``` -wormhole send --tor --launch-tor myfile.jpg -``` - -Alternatively, if you know of a pre-existing Tor daemon with a -non-standard control-port, you can specify that control port with the -``--tor-control-port=`` argument: - -``` -wormhole send --tor --tor-control-port=tcp:127.0.0.1:9251 myfile.jpg -``` - -## .onion servers - -In the future, ``wormhole`` with ``--tor`` will listen on an ephemeral -"onion service" when file transfers are requested. If both sides are -Tor-capable, this will allow transfers to take place "directly" (via the -Tor network) from sender to receiver, bypassing the Transit Relay -server. This will require access to a Tor control-port (to ask Tor to -create a new ephemeral onion service). SOCKS-port access will not be -sufficient. - -However the current version of ``wormhole`` does not use onion services. -For now, if both sides use ``--tor``, any file transfers must use the -transit relay, since neither side will advertise any listening IP -addresses. diff --git a/welcome.md b/welcome.md deleted file mode 100644 index 04552a2..0000000 --- a/welcome.md +++ /dev/null @@ -1,339 +0,0 @@ -# Welcome - -Get things from one computer to another, safely. - -This package provides a library and a command-line tool named `wormhole`, -which makes it possible to get arbitrary-sized files and directories -(or short pieces of text) from one computer to another. The two endpoints are -identified by using identical "wormhole codes": in general, the sending -machine generates and displays the code, which must then be typed into the -receiving machine. - -The codes are short and human-pronounceable, using a phonetically-distinct -wordlist. The receiving side offers tab-completion on the codewords, so -usually only a few characters must be typed. Wormhole codes are single-use -and do not need to be memorized. - -* PyCon 2016 presentation: [Slides](http://www.lothar.com/~warner/MagicWormhole-PyCon2016.pdf), [Video](https://youtu.be/oFrTqQw0_3c) - -## Example - -Sender: - -``` -% wormhole send README.md -Sending 7924 byte file named 'README.md' -On the other computer, please run: wormhole receive -Wormhole code is: 7-crossover-clockwork - -Sending (<-10.0.1.43:58988).. -100%|=========================| 7.92K/7.92K [00:00<00:00, 6.02MB/s] -File sent.. waiting for confirmation -Confirmation received. Transfer complete. -``` - -Receiver: - -``` -% wormhole receive -Enter receive wormhole code: 7-crossover-clockwork -Receiving file (7924 bytes) into: README.md -ok? (y/n): y -Receiving (->tcp:10.0.1.43:58986).. -100%|===========================| 7.92K/7.92K [00:00<00:00, 120KB/s] -Received file written to README.md -``` - - -## Installation - -The easiest way to install magic-wormhole is to use a packaged version from -your operating system. If there is none, or you want to participate in -development, you can install from source. - -### MacOS / OS-X - -[Install Homebrew](https://brew.sh/), then run `brew install magic-wormhole`. - -### Linux (Debian/Ubuntu) - -Magic-wormhole is available with `apt` in Debian 9 "stretch", Ubuntu 17.04 -"zesty", and later versions: - -``` -$ sudo apt install magic-wormhole -``` - -### Linux (Fedora) - -``` -$ sudo dnf install magic-wormhole -``` - -### Linux (openSUSE) - -``` -$ sudo zypper install python-magic-wormhole -``` - -### Linux (Snap package) - -Many linux distributions (including Ubuntu) can install ["Snap" -packages](https://snapcraft.io/). Magic-wormhole is available through a -third-party package (published by the "snapcrafters" group): - -``` -$ sudo snap install wormhole -``` - -### Install from Source - -Magic-wormhole is a Python package, and can be installed in the usual ways. -The basic idea is to do `pip install magic-wormhole`, however to avoid -modifying the system's python libraries, you probably want to put it into a -"user" environment (putting the ``wormhole`` executable in -``~/.local/bin/wormhole``) like this: - -``` -pip install --user magic-wormhole -``` - -or put it into a virtualenv, like this: - -``` -virtualenv venv -source venv/bin/activate -pip install magic-wormhole -``` - -You can then run `venv/bin/wormhole` without first activating the virtualenv, -so e.g. you could make a symlink from `~/bin/wormhole` to -`.../path/to/venv/bin/wormhole`, and then plain `wormhole send` will find it -on your `$PATH`. - -You probably *don't* want to use ``sudo`` when you run ``pip``. This tends to -create [conflicts](https://github.com/warner/magic-wormhole/issues/336) with -the system python libraries. - -On OS X, you may need to pre-install `pip`, and run `$ xcode-select ---install` to get GCC, which is needed to compile the `libsodium` -cryptography library during the installation process. - -On Debian/Ubuntu systems, you may need to install some support libraries -first: - -`$ sudo apt-get install python-pip build-essential python-dev libffi-dev libssl-dev` - -On Linux, if you get errors like `fatal error: sodium.h: No such file or -directory`, either use `SODIUM_INSTALL=bundled pip install magic-wormhole`, -or try installing the `libsodium-dev` / `libsodium-devel` package. These work -around a bug in pynacl which gets confused when the libsodium runtime is -installed (e.g. `libsodium13`) but not the development package. - -On Windows, python2 may work better than python3. On older systems, `$ pip -install --upgrade pip` may be necessary to get a version that can compile all -the dependencies. Most of the dependencies are published as binary wheels, -but in case your system is unable to find these, it will have to compile -them, for which Microsoft Visual C++ 9.0 may be required. Get it from -http://aka.ms/vcpython27 . - -## Motivation - -* Moving a file to a friend's machine, when the humans can speak to each - other (directly) but the computers cannot -* Delivering a properly-random password to a new user via the phone -* Supplying an SSH public key for future login use - -Copying files onto a USB stick requires physical proximity, and is -uncomfortable for transferring long-term secrets because flash memory is hard -to erase. Copying files with ssh/scp is fine, but requires previous -arrangements and an account on the target machine, and how do you bootstrap -the account? Copying files through email first requires transcribing an email -address in the opposite direction, and is even worse for secrets, because -email is unencrypted. Copying files through encrypted email requires -bootstrapping a GPG key as well as an email address. Copying files through -Dropbox is not secure against the Dropbox server and results in a large URL -that must be transcribed. Using a URL shortener adds an extra step, reveals -the full URL to the shortening service, and leaves a short URL that can be -guessed by outsiders. - -Many common use cases start with a human-mediated communication channel, such -as IRC, IM, email, a phone call, or a face-to-face conversation. Some of -these are basically secret, or are "secret enough" to last until the code is -delivered and used. If this does not feel strong enough, users can turn on -additional verification that doesn't depend upon the secrecy of the channel. - -The notion of a "magic wormhole" comes from the image of two distant wizards -speaking the same enchanted phrase at the same time, and causing a mystical -connection to pop into existence between them. The wizards then throw books -into the wormhole and they fall out the other side. Transferring files -securely should be that easy. - -## Design - -The `wormhole` tool uses PAKE "Password-Authenticated Key Exchange", a family -of cryptographic algorithms that uses a short low-entropy password to -establish a strong high-entropy shared key. This key can then be used to -encrypt data. `wormhole` uses the SPAKE2 algorithm, due to Abdalla and -Pointcheval[1]. - -PAKE effectively trades off interaction against offline attacks. The only way -for a network attacker to learn the shared key is to perform a -man-in-the-middle attack during the initial connection attempt, and to -correctly guess the code being used by both sides. Their chance of doing this -is inversely proportional to the entropy of the wormhole code. The default is -to use a 16-bit code (use --code-length= to change this), so for each use of -the tool, an attacker gets a 1-in-65536 chance of success. As such, users can -expect to see many error messages before the attacker has a reasonable chance -of success. - -## Timing - -The program does not have any built-in timeouts, however it is expected that -both clients will be run within an hour or so of each other. This makes the -tool most useful for people who are having a real-time conversation already, -and want to graduate to a secure connection. Both clients must be left -running until the transfer has finished. - -## Relays - -The wormhole library requires a "Mailbox Server" (also known as the -"Rendezvous Server"): a simple WebSocket-based relay that delivers messages -from one client to another. This allows the wormhole codes to omit IP -addresses and port numbers. The URL of a public server is baked into the -library for use as a default, and will be freely available until volume or -abuse makes it infeasible to support. Applications which desire more -reliability can easily run their own relay and configure their clients to use -it instead. Code for the Mailbox Server is in a separate package named -`magic-wormhole-mailbox-server`. and -https://github.com/warner/magic-wormhole-mailbox-server/blob/master/docs/welcome.md -has instructions to run your own copy. Both clients must use the same mailbox -server. The default can be overridden with the `--relay-url` option. - -The file-transfer commands also use a "Transit Relay", which is another -simple server that glues together two inbound TCP connections and transfers -data on each to the other (the moral equivalent of a TURN server). The -`wormhole send` file mode shares the IP addresses of each client with the -other (inside the encrypted message), and both clients first attempt to -connect directly. If this fails, they fall back to using the transit relay. -As before, the host/port of a public server is baked into the library, and -should be sufficient to handle moderate traffic. Code for the Transit Relay -is provided a separate package named `magic-wormhole-transit-relay`, and you -can read -https://github.com/warner/magic-wormhole-transit-relay/blob/master/docs/running.md -for instructions on running your own. The clients exchange transit relay -information during connection negotiation, so they can be configured to use -different ones without problems. Use the `--transit-helper` option to -override the default. - -The protocol includes provisions to deliver notices and error messages to -clients: if either relay must be shut down, these channels will be used to -provide information about alternatives. - -## CLI tool - -* `wormhole send [args] --text TEXT` -* `wormhole send [args] FILENAME` -* `wormhole send [args] DIRNAME` -* `wormhole receive [args]` - -Both commands accept additional arguments to influence their behavior: - -* `--code-length WORDS`: use more or fewer than 2 words for the code -* `--verify` : print (and ask user to compare) extra verification string - -## Library - -The `wormhole` module makes it possible for other applications to use these -code-protected channels. This includes Twisted support, and (in the future) -will include blocking/synchronous support too. See docs/api.md for details. - -The file-transfer tools use a second module named `wormhole.transit`, which -provides an encrypted record-pipe. It knows how to use the Transit Relay as -well as direct connections, and attempts them all in parallel. -`TransitSender` and `TransitReceiver` are distinct, although once the -connection is established, data can flow in either direction. All data is -encrypted (using nacl/libsodium "secretbox") using a key derived from the -PAKE phase. See `src/wormhole/cli/cmd_send.py` for examples. - -## Development - -* https://github.com/magic-wormhole -* Chat: #magic-wormhole on irc.libera.chat and matrix.org (both are bridged) - -To set up Magic Wormhole for development, you will first need to -install [virtualenv][]. - -Once you've done that, ``git clone`` the repo, ``cd`` into the root of the -repository, and run: - -``` -virtualenv venv -source venv/bin/activate -pip install --upgrade pip setuptools -``` - -Now your virtualenv has been activated. You'll want to re-run -`source venv/bin/activate` for every new terminal session you open. - -To install Magic Wormhole and its development dependencies into your -virtualenv, run: - -``` -pip install -e .[dev] -``` - -While the virtualenv is active, running ``wormhole`` will get you the -development version. - -### Running Tests - - -Within your virtualenv, the command-line program `trial` will -run the test suite: - -``` -trial wormhole -``` - -This tests the entire `wormhole` package. If you want to run -only the tests for a specific module, or even just a specific test, -you can specify it instead via Python's standard dotted -import notation, e.g.: - -``` -trial wormhole.test.test_cli.PregeneratedCode.test_file_tor -``` - -Developers can also just clone the source tree and run `tox` to run the unit -tests on all supported (and installed) versions of python: 2.7, 3.4, 3.5, and -3.6. - -### Troubleshooting - -Every so often, you might get a traceback with the following -kind of error: - -``` -pkg_resources.DistributionNotFound: The 'magic-wormhole==0.9.1-268.g66e0d86.dirty' distribution was not found and is required by the application -``` - -If this happens, run `pip install -e .[dev]` again. - -[virtualenv]: http://python-guide-pt-br.readthedocs.io/en/latest/dev/virtualenvs/ - -### Other - -Relevant [xkcd](https://xkcd.com/949/) :-) - -## License, Compatibility - -This library is released under the MIT license, see LICENSE for details. - -This library is compatible with python2.7, 3.4 (non-Windows-only), 3.5, and -3.6 . - - - - -[1]: http://www.di.ens.fr/~pointche/Documents/Papers/2005_rsa.pdf "RSA 2005" From f5075923a1e2809718ab32f347069c34c16ab8e5 Mon Sep 17 00:00:00 2001 From: piegames Date: Tue, 28 Feb 2023 17:18:33 +0100 Subject: [PATCH 04/10] =?UTF-8?q?Rename=20attacks.md=20=E2=86=92=20securit?= =?UTF-8?q?y.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- attacks.md => security.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename attacks.md => security.md (100%) diff --git a/attacks.md b/security.md similarity index 100% rename from attacks.md rename to security.md From de22d18f52c8a9ebae1215f351cd0dd1413ad0b8 Mon Sep 17 00:00:00 2001 From: piegames Date: Sat, 4 Mar 2023 22:16:54 +0100 Subject: [PATCH 05/10] Add new landing page --- index.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 index.md diff --git a/index.md b/index.md new file mode 100644 index 0000000..553dbc0 --- /dev/null +++ b/index.md @@ -0,0 +1,28 @@ +# The Magic Wormhole protocols + +This site contains all the documentation and specification of protocols related +to Magic Wormhole, which are not specific to a single client or implementation. +It assumes the reader is already familiar with the general Magic Wormhole concept. + +The most important component is the **Mailbox server**. There are two aspects +to it: The [**server protocol**](./server-protocol.md) describes how two peers +find each other and how they then can exchange low-bandwidth messages. +Once the two peers are connected over the server, the +[**client protocol**](./client-protocol.md) describes how they establish a +secure way of exchanging messages. + +Using the established low-bandwidth secure channel, both sides then negotiate a +secure high-bandwidth channel, called [**transit**](./transit.md). The transit +protocol describes how both sides establish a direct connection, how a special +relay server may be used as fallback, and the cryptography used to make that +connection secure. + +Applications make use of the above protocols to provide their functionality. +Currently, only one application level protocol is documented here: +[**file transfer**](./file-transfer-protocol.md). Additionally, a custom +[**uri scheme**](./uri-scheme.md) has been standardised for file transfer. This +makes it possible for applications to replace the traditional code exchange +with sharing a link or QR code. + +Security threat models and privacy considerations are discussed in +[**security**](./security.md) From 5787f41f493eec6b55151f520b66ad4098b770cf Mon Sep 17 00:00:00 2001 From: piegames Date: Sat, 4 Mar 2023 22:17:19 +0100 Subject: [PATCH 06/10] Update the security discussion Rewrote the existing topics. Tried to minimize the discussion of any hypotheticals and future work, as this should be done outside of the document itself. Added privacy sections discussing file size metadata and IP addresses. --- security.md | 159 ++++++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 78 deletions(-) diff --git a/security.md b/security.md index 702fd45..c1407f1 100644 --- a/security.md +++ b/security.md @@ -1,89 +1,92 @@ -# Known Vulnerabilities +# Security and privacy considerations -## Low-probability Man-In-The-Middle Attacks +## Code interception attacks -By default, wormhole codes contain 16 bits of entropy. If an attacker -can intercept your network connection (either by owning your network, or -owning the rendezvous server), they can attempt an attack. They will -have a one-in-65536 chance of successfully guessing your code, allowing -them to pose as your intended partner. If they succeed, they can turn -around and immediately start a new wormhole (using the same code), -allowing your partner to connect to them instead of you. By passing, -observing, and possibly modifying messages between these two -connections, they could perform an MitM (Man In The Middle) attack. +By default, Wormhole codes contain 16 bits of entropy. Failed attempts of +guessing a code will cause both clients to error out. Thus, an attacker +has a one-in-65536 chance of successfully guessing the code, while being +detected in all other cases. -If the server refused to re-use the same channel id (aka "nameplate") -right away (issue #31), a network attacker would be unable to set up the -second connection, cutting this attack in half. An attacker who controls -the server would not be affected. +If the attacker successfully guesses the code, they can attempt a +machine-in-the-middle (MitM) attack. For this, they quickly reconnect with +the same code in order to connect with the second peer. With that, they get a +secure channel to each side while being able to read and modify the connection's +content. -Basic probability tells us that peers will see a large number of -WrongPasswordErrors before the attacker has a useful chance of -successfully guessing any wormhole code. You should expect to see about -32000 failures before they have a 50% chance of being successful. If you -see many failures, and think someone is trying to guess your codes, you -can use e.g. `wormhole send --code-length=4` to make a longer code -(reducing their chances significantly). +Both cases can be mitigated by enabling the verifier feature, in which case +even successful attacks can be detected. -Of course, an attacker who learns your secret wormhole code directly -(because you delivered it over an insecure channel) can perform this -attack with 100% reliability. +In general, this is a very similar process to ordinary key exchanges like +Diffie-Hellman (or variations), except that MitM attackers additionally have to +guess the code correctly. (Hence the name, "*password authenticated* key +exchange", PAKE.) +### Password entropy -## DoS Attack on the Rendezvous Server +Compared to password strengths we are used to nowadays, 16 bits may seem scarily +small, even knowing that an attacker only has one try to guess the password. But +to put it into perspective: +An attacker gains *on average* only one file for every 2^16 = 65536 attempts. +Since there is no possibility of targetting any individual connection (because +who would re-try sending their file hundreds of times if it keeps failing?), +any gained data would be fairly useless in most of the cases. +Because failed guessing attempts result in failed key exchanges, brute force +attacks are inherently very disruptive of the service, and thus easy to detect. + +In short, guessing codes is unlikely to be an attractive target for any attacker. +Of course, there is always the possibility to configure a stronger code in the +clients if desired. + +## Denial of Service (DoS) attacks on the Mailbox server Wormhole codes can be so short because they implicitly contain a common -rendezvous server URL (any two applications that use magic-wormhole +rendezvous server URL (any two applications that use Magic Wormhole should be configured to use the same server). As a result, successful operation depends upon both clients being able to contact that server, -making it a SPOF (single point of failure). - -In particular, grumpy people could disrupt service for everyone by -writing a program that just keeps connecting to the rendezvous server, -pretending to be real clients, and claiming messages meant for -legitimate users. - -I do not have any good mitigations for this attack, and functionality -may depend upon the continued goodwill of potential vandals. The weak -ones that I've considered (but haven't implemented yet) include: - -* hashcash challenges when the server is under attack -* per-IP rate-limiting (although I'd want to be careful about protecting - the privacy of the IP addresses, so it'd need a rotating hash seed) -* require users to go through some external service (maybe ReCAPTCHA?) - and get a rate-limiting ticket before claiming a channel -* shipping an attack tool (flooding the first million channels), as part - of the distribution, in a subcommand named `wormhole - break-this-useful-service-for-everybody-because-i-am-a-horrible-person`, - in the hopes that pointing out how easy it is might dissuade a few - would-be vandals from feeling a sense of accomplishment at writing - their own :). Not sure it would help much, but I vaguely remember - hearing about something similar in the early multi-user unix systems - (a publically-executable /bin/crash or something, which new users - tended to only run once before learning some responsibility). - -Using the secret words as part of the "channel id" isn't safe, since it -would allow a network attacker, or the rendezvous server, to deduce what -the secret words are: since they only have 16 bits of entropy, the -attacker just makes a table of hash(words) -> channel-id, then reverses -it. To make that safer we'd need to increase the codes to maybe 80 bits -(ten words), plus do some significant key-stretching (like 5-10 seconds -of scrypt or argon2), which would increase latency and CPU demands, and -still be less secure overall. - -The core problem is that, because things are so easy for the legitimate -participants, they're really easy for the attacker too. Short wormhole -codes are the easiest to use, but they make it for a trivially -predictable channel-id target. - -I don't have a good answer for this one. I'm hoping that it isn't -sufficiently interesting to attack that it'll be an issue, but I can't -think of any simple answers. If the API is sufficiently compelling for -other applications to incorporate Wormhole "technology" into their apps, -I'm expecting that they'll run their own rendezvous server, and of -course those apps can incorporate whatever sort of DoS protection seems -appropriate. For the built-in/upstream send-text/file/directory tools, -using the public relay that I run, it may just have to be a best-effort -service, and if someone decides to kill it, it fails. - -See #107 for more discussion. +making it a single point of failure (SPOF). + +While it is of course possible to incapacitate the rendezvous server using +traditional means of DoS, so much work is not necessary: An attacker may +simply connect to every nameplate with a random code, causing the key exchange +to fail. There is a "list" command in the protocol which makes it easy to +enumerate all nameplates to disrupt them, but even without it the name space is +sufficiently small (by design, as we want short codes) to brute force. + +There are several ideas to defend against this, however the only one already +specified in the protocol is the "permission" feature: The rendezvous server +may use it to restrict new connections with some kind of challenge (or for +private servers, authentication). The motivation behind this is to enable +a proof-of-work challenge (using HashCash) when under attack to slow it down. +See the server protocol specification for details. + +## Metadata leaks + +As usual in cryptography, communication metadata cannot easily be protected. Any +involved server will know the timestamp and size of each message it relays. For +file transfer, this may be an issue in cases where the file size may be +characteristic for its content. (Imagine people using Magic Wormhole to send +some specific movie.) + +Thanks to the separation between rendezvous server and relay server, forcing the +client to establish a direct connection will bypass the relay server and thus not +leak such metadata for file transfers. + +## IP address leakage and anonymity + +As usual on the internet, any involved server will know connection information +including the IP address of any two peers. + +Additionally, in order to establish a direct connection, public and local IP +addresses are sent to the peer. This may leak information about the local +network topology, including potentially used VPNs. If you do not trust your +peer with such information, enforcing a relay server connection is advised. +However, keep in mind that it is easy to host a relay server, so it might still +leak your public IP address. + +If you do not want to expose your IP address, use [Tor](https://torproject.org/) +to use Magic Wormhole anonymously. In the case +where both sides connect via Tor, the [Transit protocol](./transit.md) has support +for bypassing the relay server by spinning up an ad-hoc onion service and +establishing a direct connection on the Tor network instead. You can think of +this as the Tor network being the relay, instead of the usual dedicated relay +server. From 3b515591c3a941ae807623bf08a0fe77a583a88a Mon Sep 17 00:00:00 2001 From: piegames Date: Sat, 8 May 2021 00:13:36 +0200 Subject: [PATCH 07/10] Server protocol: Improve the `welcome` message - Deprecate the `current_cli_version` key - Improved wording, added type information --- server-protocol.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/server-protocol.md b/server-protocol.md index 3bf16e8..516706f 100644 --- a/server-protocol.md +++ b/server-protocol.md @@ -72,23 +72,23 @@ messages. Clients must ignore unrecognized message types from the Server. The first thing the server sends to each client is the `welcome` message. This is intended to deliver important status information to the client that -might influence its operation. The Python client currently reacts to the -following keys (and ignores all others): +might influence its operation. Clients should look out for the following fields, +and handle them accordingly, if present: -* `current_cli_version`: prompts the user to upgrade if the server's +* `current_cli_version`: *(deprecated)* prompts the user to upgrade if the server's advertised version is greater than the client's version (as derived from the git tag) -* `motd`: prints this message, if present; intended to inform users about +* `motd`: This message is intended to inform users about performance problems, scheduled downtime, or to beg for donations to keep - the server running -* `error`: causes the client to print the message and then terminate. If a - future version of the protocol requires a rate-limiting CAPTCHA ticket or - other authorization record, the server can send `error` (explaining the - requirement) if it does not see this ticket arrive before the `bind`. + the server running. Clients should print it or otherwise display prominently + to the user. The value *should* be a plain string. +* `error`: The client should show this message to the user and then terminate. + The value *should* be a plain string. * `permission-required`: a set of available authentication methods, proof of work challenges etc. The client needs to "solve" one of them in order to get access to the service. +Other (unknown) fields should be ignored. The client should examine the `permissions-required` methods (if present) and select one to use (see also "Permission to Use the Server" below). From 74e593ba0921f4669ae40a2c8093126eec532697 Mon Sep 17 00:00:00 2001 From: piegames Date: Mon, 20 Mar 2023 22:31:46 +0100 Subject: [PATCH 08/10] =?UTF-8?q?Server=20protocol:=20Rendezvous=20?= =?UTF-8?q?=E2=86=92=20Mailbox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slowly make the naming more consistent. --- server-protocol.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server-protocol.md b/server-protocol.md index 516706f..cd731e6 100644 --- a/server-protocol.md +++ b/server-protocol.md @@ -1,8 +1,8 @@ -# Rendezvous Server Protocol +# Mailbox Server Protocol ## Concepts -The Rendezvous Server provides queued delivery of binary messages from one +The Mailbox server provides queued delivery of binary messages from one client to a second, and vice versa. Each message contains a "phase" (a string) and a body (bytestring). These messages are queued in a "Mailbox" until the other side connects and retrieves them, but are delivered @@ -33,7 +33,7 @@ file-transfer tool uses `lothar.com/wormhole/text-or-file-xfer`. ## WebSocket Transport At the lowest level, each client establishes (and maintains) a WebSocket -connection to the Rendezvous Server. If the connection is lost (which could +connection to the Mailbox server. If the connection is lost (which could happen because the server was rebooted for maintenance, or because the client's network connection migrated from one network to another, or because the resident network gremlins decided to mess with you today), clients should @@ -186,7 +186,7 @@ observers to use the hard-earned token for themselves. Wormhole codes look like `4-purple-sausages`, consisting of a number followed by some random words. This number is called a "Nameplate". -On the Rendezvous Server, the Nameplate contains a pointer to a Mailbox. +On the Mailbox server, the Nameplate contains a pointer to a Mailbox. Clients can "claim" a nameplate, and then later "release" it. Each claim is for a specific side (so one client claiming the same nameplate multiple times only counts as one claim). Nameplates are deleted once the last client has @@ -239,7 +239,7 @@ The `close` command accepts an optional "mood" string: this allows clients to tell the server (in general terms) about their experiences with the wormhole interaction. The server records the mood in its "usage" record, so the server operator can get a sense of how many connections are succeeding and failing. -The moods currently recognized by the Rendezvous Server are: +The moods currently recognized by the Mailbox server are: * `happy` (default): the PAKE key-establishment worked, and the client saw at least one valid encrypted message from its peer @@ -269,7 +269,7 @@ blob (for the VERSION message, as well as all application-provided payloads). The `message` response will also include `id`, copied from the `id` of the `add` message (and used only by the timing-diagram tool). -The Rendezvous Server does not de-duplicate messages, nor does it retain +The Mailbox server does not de-duplicate messages, nor does it retain ordering: clients must do both if they need to. ## All Message Types From 7ad5cc35cbed218de7b5320a4f8e65689b9e484e Mon Sep 17 00:00:00 2001 From: meejah Date: Tue, 25 Apr 2023 13:52:06 -0600 Subject: [PATCH 09/10] update (just) the Dilation abilities section semantic newlines; document what the implementation does; versions are integers --- dilation-protocol.md | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/dilation-protocol.md b/dilation-protocol.md index 44c8dfe..8660e3f 100644 --- a/dilation-protocol.md +++ b/dilation-protocol.md @@ -13,13 +13,36 @@ messages are used to open/use/close the application-visible subchannels. ## Capability discovery -The Wormhole protocol includes a `versions` message sent immediately after -the shared PAKE key is established. This also serves as a key-confirmation -message, allowing each side to confirm that the other side knows the right -key. The body of the `versions` message is a JSON-formatted string with keys -that are available for learning the abilities of the peer. Dilation is -signaled by a key named `can-dilate`, whose value is a list of strings. Any -version present in both side's lists is eligible for use. +The Wormhole protocol includes a `versions` message sent immediately after the shared PAKE key is established. +This also serves as a key-confirmation message, allowing each side to confirm that the other side knows the right key. +The body of the `versions` message is a JSON-formatted string with keys that are available for learning the abilities of the peer. +Dilation is signaled by a key named `can-dilate`, whose value is a list of strings. +Any version present in both side's lists is eligible for use. + +The connection abilities are communicated similarly to Transit, in a `dilation-abilities` key. +Currently supported: `direct-tcp-v1`, `tor-tcp-v1` and `relay-v1`. +These have similar meaning as in Transit (referring to the ability to make a direct connection, a connection via Tor and a connection via the Transit Relay respectively) +See :ref:`transit.md` for more details. + +For example: + +``` +{ + "can-dilate": [1] + "dilation-abilities": [ + {"type": "direct-tcp-v1"}, + {"type": "relay-v1"}, + ] +} +``` + +When considering the `"can-dilate"` list, implementations take the intersection (of both peers) and SHOULD select the "best" version in that intersection. +Usually "best" means "newest" (i.e. biggest number) but implementations MAY have other ways of deciding what is best. +The version selected is communicated in the `please` message with `"use-version"` key. +Both sides MUST use the version selected by the Leader (see next section). + +Currently there is only one version: `1`. + ## Leaders and Followers From 128b384161e957839d64596440907f2362c1b48f Mon Sep 17 00:00:00 2001 From: meejah Date: Fri, 5 May 2023 21:36:53 -0600 Subject: [PATCH 10/10] clarify, make string everywhere --- dilation-protocol.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dilation-protocol.md b/dilation-protocol.md index 8660e3f..1aded42 100644 --- a/dilation-protocol.md +++ b/dilation-protocol.md @@ -28,7 +28,7 @@ For example: ``` { - "can-dilate": [1] + "can-dilate": ["1"] "dilation-abilities": [ {"type": "direct-tcp-v1"}, {"type": "relay-v1"}, @@ -37,11 +37,11 @@ For example: ``` When considering the `"can-dilate"` list, implementations take the intersection (of both peers) and SHOULD select the "best" version in that intersection. -Usually "best" means "newest" (i.e. biggest number) but implementations MAY have other ways of deciding what is best. +The *order* of versions in the list indicates their priority (they may not all be strings that convert to integers). The version selected is communicated in the `please` message with `"use-version"` key. Both sides MUST use the version selected by the Leader (see next section). -Currently there is only one version: `1`. +Currently there is only one version: `"1"`. ## Leaders and Followers