2020-12-04 11:18:51 -05:00
|
|
|
"""
|
|
|
|
Ported to Python 3.
|
|
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
|
|
from __future__ import division
|
|
|
|
from __future__ import print_function
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
|
|
from future.utils import PY2
|
|
|
|
if PY2:
|
|
|
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
|
|
|
from past.builtins import long
|
|
|
|
|
2020-12-11 13:10:56 -05:00
|
|
|
from six import ensure_text, ensure_str
|
2020-10-16 10:47:49 -04:00
|
|
|
|
2016-07-19 17:22:12 -07:00
|
|
|
import time
|
2017-02-27 10:56:49 -07:00
|
|
|
from zope.interface import implementer
|
2007-03-23 16:15:57 -07:00
|
|
|
from twisted.application import service
|
2020-12-16 16:25:51 -05:00
|
|
|
from foolscap.api import Referenceable
|
2008-11-21 20:07:27 -07:00
|
|
|
from allmydata.interfaces import InsufficientVersionError
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
from allmydata.introducer.interfaces import IIntroducerClient, \
|
2016-06-02 16:47:58 +00:00
|
|
|
RIIntroducerSubscriberClient_v2
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
from allmydata.introducer.common import sign_to_foolscap, unsign_from_foolscap,\
|
2016-05-10 20:19:55 -07:00
|
|
|
get_tubid_string_from_ann
|
2016-12-08 15:15:49 -08:00
|
|
|
from allmydata.util import log, yamlutil, connection_status
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
from allmydata.util.rrefutil import add_version_to_remote_reference
|
2020-12-16 16:20:00 -05:00
|
|
|
from allmydata.util.observer import (
|
|
|
|
ObserverList,
|
|
|
|
)
|
2019-06-24 12:05:12 -06:00
|
|
|
from allmydata.crypto.error import BadSignature
|
2016-09-01 19:26:53 -07:00
|
|
|
from allmydata.util.assertutil import precondition
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
|
2016-05-11 13:15:41 -07:00
|
|
|
class InvalidCacheError(Exception):
|
|
|
|
pass
|
|
|
|
|
2020-11-19 14:23:41 -05:00
|
|
|
V2 = b"http://allmydata.org/tahoe/protocols/introducer/v2"
|
2008-02-05 13:05:13 -07:00
|
|
|
|
2017-02-27 10:56:49 -07:00
|
|
|
@implementer(RIIntroducerSubscriberClient_v2, IIntroducerClient)
|
2008-02-05 13:05:13 -07:00
|
|
|
class IntroducerClient(service.Service, Referenceable):
|
|
|
|
|
|
|
|
def __init__(self, tub, introducer_furl,
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
nickname, my_version, oldest_supported,
|
2020-11-23 15:10:18 -05:00
|
|
|
sequencer, cache_filepath):
|
2008-02-05 13:05:13 -07:00
|
|
|
self._tub = tub
|
|
|
|
self.introducer_furl = introducer_furl
|
|
|
|
|
2020-12-04 11:18:51 -05:00
|
|
|
assert isinstance(nickname, str)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self._nickname = nickname
|
2008-02-05 13:05:13 -07:00
|
|
|
self._my_version = my_version
|
|
|
|
self._oldest_supported = oldest_supported
|
2013-03-18 17:40:56 -07:00
|
|
|
self._sequencer = sequencer
|
2016-05-10 20:19:35 +00:00
|
|
|
self._cache_filepath = cache_filepath
|
2008-02-05 13:05:13 -07:00
|
|
|
|
2020-11-19 14:23:41 -05:00
|
|
|
self._my_subscriber_info = { b"version": 0,
|
|
|
|
b"nickname": self._nickname,
|
2020-12-01 11:58:56 -05:00
|
|
|
b"app-versions": [],
|
2020-11-19 14:23:41 -05:00
|
|
|
b"my-version": self._my_version,
|
|
|
|
b"oldest-supported": self._oldest_supported,
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
}
|
|
|
|
|
2013-03-18 17:40:56 -07:00
|
|
|
self._outbound_announcements = {} # not signed
|
|
|
|
self._published_announcements = {} # signed
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self._canary = Referenceable()
|
2008-02-05 13:05:13 -07:00
|
|
|
|
|
|
|
self._publisher = None
|
2016-09-12 23:01:23 +00:00
|
|
|
self._since = None
|
2008-02-05 13:05:13 -07:00
|
|
|
|
2020-12-16 16:20:00 -05:00
|
|
|
self._local_subscribers = {} # {servicename: ObserverList}
|
2008-02-05 13:05:13 -07:00
|
|
|
self._subscriptions = set() # requests we've actually sent
|
2009-06-22 19:10:47 -07:00
|
|
|
|
2013-03-18 17:40:56 -07:00
|
|
|
# _inbound_announcements remembers one announcement per
|
2009-06-22 19:10:47 -07:00
|
|
|
# (servicename,serverid) pair. Anything that arrives with the same
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
# pair will displace the previous one. This stores tuples of
|
|
|
|
# (unpacked announcement dictionary, verifyingkey, rxtime). The ann
|
|
|
|
# dicts can be compared for equality to distinguish re-announcement
|
|
|
|
# from updates. It also provides memory for clients who subscribe
|
|
|
|
# after startup.
|
2013-03-18 17:40:56 -07:00
|
|
|
self._inbound_announcements = {}
|
2009-06-22 19:10:47 -07:00
|
|
|
|
|
|
|
# hooks for unit tests
|
|
|
|
self._debug_counts = {
|
|
|
|
"inbound_message": 0,
|
|
|
|
"inbound_announcement": 0,
|
|
|
|
"wrong_service": 0,
|
|
|
|
"duplicate_announcement": 0,
|
|
|
|
"update": 0,
|
|
|
|
"new_announcement": 0,
|
|
|
|
"outbound_message": 0,
|
|
|
|
}
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self._debug_outstanding = 0
|
|
|
|
|
|
|
|
def _debug_retired(self, res):
|
|
|
|
self._debug_outstanding -= 1
|
|
|
|
return res
|
2009-06-22 19:10:47 -07:00
|
|
|
|
2008-02-05 13:05:13 -07:00
|
|
|
def startService(self):
|
|
|
|
service.Service.startService(self)
|
2008-11-21 20:07:27 -07:00
|
|
|
self._introducer_error = None
|
2020-12-11 13:10:56 -05:00
|
|
|
rc = self._tub.connectTo(ensure_str(self.introducer_furl), self._got_introducer)
|
2008-02-05 13:05:13 -07:00
|
|
|
self._introducer_reconnector = rc
|
|
|
|
def connect_failed(failure):
|
|
|
|
self.log("Initial Introducer connection failed: perhaps it's down",
|
2008-08-25 18:57:59 -07:00
|
|
|
level=log.WEIRD, failure=failure, umid="c5MqUQ")
|
2016-05-11 09:22:47 +00:00
|
|
|
self._load_announcements()
|
2008-02-05 13:05:13 -07:00
|
|
|
d = self._tub.getReference(self.introducer_furl)
|
|
|
|
d.addErrback(connect_failed)
|
2016-05-10 20:19:35 +00:00
|
|
|
|
2016-05-11 09:22:47 +00:00
|
|
|
def _load_announcements(self):
|
2016-05-11 13:15:41 -07:00
|
|
|
try:
|
2016-05-11 09:22:47 +00:00
|
|
|
with self._cache_filepath.open() as f:
|
2016-07-19 17:22:12 -07:00
|
|
|
servers = yamlutil.safe_load(f)
|
2016-05-11 13:15:41 -07:00
|
|
|
except EnvironmentError:
|
|
|
|
return # no cache file
|
|
|
|
if not isinstance(servers, list):
|
|
|
|
log.err(InvalidCacheError("not a list"), level=log.WEIRD)
|
|
|
|
return
|
|
|
|
self.log("Using server data from cache", level=log.UNUSUAL)
|
|
|
|
for server_params in servers:
|
|
|
|
if not isinstance(server_params, dict):
|
|
|
|
log.err(InvalidCacheError("not a dict: %r" % (server_params,)),
|
|
|
|
level=log.WEIRD)
|
|
|
|
continue
|
2016-09-01 19:26:53 -07:00
|
|
|
# everything coming from yamlutil.safe_load is unicode
|
|
|
|
key_s = server_params['key_s'].encode("ascii")
|
|
|
|
self._deliver_announcements(key_s, server_params['ann'])
|
2016-05-11 09:22:47 +00:00
|
|
|
|
2016-05-10 20:19:35 +00:00
|
|
|
def _save_announcements(self):
|
|
|
|
announcements = []
|
2020-12-04 11:18:51 -05:00
|
|
|
for value in self._inbound_announcements.values():
|
2016-05-10 20:19:35 +00:00
|
|
|
ann, key_s, time_stamp = value
|
2020-11-30 16:24:27 -05:00
|
|
|
# On Python 2, bytes strings are encoded into YAML Unicode strings.
|
|
|
|
# On Python 3, bytes are encoded as YAML bytes. To minimize
|
|
|
|
# changes, Python 3 for now ensures the same is true.
|
2016-05-10 20:19:35 +00:00
|
|
|
server_params = {
|
|
|
|
"ann" : ann,
|
2020-11-19 11:45:32 -05:00
|
|
|
"key_s" : ensure_text(key_s),
|
2016-05-10 20:19:35 +00:00
|
|
|
}
|
|
|
|
announcements.append(server_params)
|
2016-07-19 17:22:12 -07:00
|
|
|
announcement_cache_yaml = yamlutil.safe_dump(announcements)
|
2020-12-04 11:18:51 -05:00
|
|
|
if isinstance(announcement_cache_yaml, str):
|
2020-11-19 11:11:48 -05:00
|
|
|
announcement_cache_yaml = announcement_cache_yaml.encode("utf-8")
|
2016-05-10 20:19:35 +00:00
|
|
|
self._cache_filepath.setContent(announcement_cache_yaml)
|
2008-02-05 13:05:13 -07:00
|
|
|
|
|
|
|
def _got_introducer(self, publisher):
|
2008-11-21 20:07:27 -07:00
|
|
|
self.log("connected to introducer, getting versions")
|
2020-11-19 14:23:41 -05:00
|
|
|
default = { b"http://allmydata.org/tahoe/protocols/introducer/v1":
|
2008-11-21 20:07:27 -07:00
|
|
|
{ },
|
2020-11-19 14:23:41 -05:00
|
|
|
b"application-version": b"unknown: no get_version()",
|
2008-11-21 20:07:27 -07:00
|
|
|
}
|
2009-05-21 17:46:32 -07:00
|
|
|
d = add_version_to_remote_reference(publisher, default)
|
2008-11-21 20:07:27 -07:00
|
|
|
d.addCallback(self._got_versioned_introducer)
|
|
|
|
d.addErrback(self._got_error)
|
|
|
|
|
|
|
|
def _got_error(self, f):
|
|
|
|
# TODO: for the introducer, perhaps this should halt the application
|
|
|
|
self._introducer_error = f # polled by tests
|
|
|
|
|
|
|
|
def _got_versioned_introducer(self, publisher):
|
|
|
|
self.log("got introducer version: %s" % (publisher.version,))
|
2016-06-02 16:47:58 +00:00
|
|
|
# we require an introducer that speaks at least V2
|
2020-11-19 14:23:41 -05:00
|
|
|
assert all(type(V2) == type(v) for v in publisher.version)
|
2016-06-02 16:47:58 +00:00
|
|
|
if V2 not in publisher.version:
|
|
|
|
raise InsufficientVersionError("V2", publisher.version)
|
2008-02-05 13:05:13 -07:00
|
|
|
self._publisher = publisher
|
2016-09-12 23:01:23 +00:00
|
|
|
self._since = int(time.time())
|
2008-02-05 13:05:13 -07:00
|
|
|
publisher.notifyOnDisconnect(self._disconnected)
|
|
|
|
self._maybe_publish()
|
|
|
|
self._maybe_subscribe()
|
|
|
|
|
|
|
|
def _disconnected(self):
|
|
|
|
self.log("bummer, we've lost our connection to the introducer")
|
|
|
|
self._publisher = None
|
2016-09-12 23:01:23 +00:00
|
|
|
self._since = int(time.time())
|
2008-02-05 13:05:13 -07:00
|
|
|
self._subscriptions.clear()
|
|
|
|
|
|
|
|
def log(self, *args, **kwargs):
|
|
|
|
if "facility" not in kwargs:
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
kwargs["facility"] = "tahoe.introducer.client"
|
2008-02-05 13:05:13 -07:00
|
|
|
return log.msg(*args, **kwargs)
|
|
|
|
|
2020-11-29 13:54:39 -05:00
|
|
|
def subscribe_to(self, service_name, callback, *args, **kwargs):
|
2020-12-16 16:20:00 -05:00
|
|
|
obs = self._local_subscribers.setdefault(service_name, ObserverList())
|
2021-01-15 11:17:47 -05:00
|
|
|
obs.subscribe(lambda key_s, ann: callback(key_s, ann, *args, **kwargs))
|
2008-02-05 13:05:13 -07:00
|
|
|
self._maybe_subscribe()
|
2020-12-04 11:18:51 -05:00
|
|
|
for index,(ann,key_s,when) in list(self._inbound_announcements.items()):
|
2020-11-19 11:11:48 -05:00
|
|
|
precondition(isinstance(key_s, bytes), key_s)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
servicename = index[0]
|
2009-06-22 19:10:47 -07:00
|
|
|
if servicename == service_name:
|
2020-12-16 16:20:00 -05:00
|
|
|
obs.notify(key_s, ann)
|
2008-02-05 13:05:13 -07:00
|
|
|
|
|
|
|
def _maybe_subscribe(self):
|
|
|
|
if not self._publisher:
|
|
|
|
self.log("want to subscribe, but no introducer yet",
|
|
|
|
level=log.NOISY)
|
|
|
|
return
|
2020-12-16 16:20:00 -05:00
|
|
|
for service_name in self._local_subscribers:
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
if service_name in self._subscriptions:
|
|
|
|
continue
|
|
|
|
self._subscriptions.add(service_name)
|
2016-06-29 22:58:14 -07:00
|
|
|
self._debug_outstanding += 1
|
|
|
|
d = self._publisher.callRemote("subscribe_v2",
|
2020-11-04 14:13:08 -05:00
|
|
|
self, service_name.encode("utf-8"),
|
2016-06-29 22:58:14 -07:00
|
|
|
self._my_subscriber_info)
|
|
|
|
d.addBoth(self._debug_retired)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
d.addErrback(log.err, facility="tahoe.introducer.client",
|
|
|
|
level=log.WEIRD, umid="2uMScQ")
|
|
|
|
|
2013-03-18 17:40:56 -07:00
|
|
|
def create_announcement_dict(self, service_name, ann):
|
|
|
|
ann_d = { "version": 0,
|
|
|
|
# "seqnum" and "nonce" will be populated with new values in
|
|
|
|
# publish(), each time we make a change
|
|
|
|
"nickname": self._nickname,
|
2020-11-23 15:10:18 -05:00
|
|
|
"app-versions": [],
|
2013-03-18 17:40:56 -07:00
|
|
|
"my-version": self._my_version,
|
|
|
|
"oldest-supported": self._oldest_supported,
|
|
|
|
|
|
|
|
"service-name": service_name,
|
|
|
|
}
|
|
|
|
ann_d.update(ann)
|
|
|
|
return ann_d
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
|
2020-12-18 10:59:53 -05:00
|
|
|
def publish(self, service_name, ann, signing_key):
|
2013-03-18 17:40:56 -07:00
|
|
|
# we increment the seqnum every time we publish something new
|
|
|
|
current_seqnum, current_nonce = self._sequencer()
|
|
|
|
|
|
|
|
ann_d = self.create_announcement_dict(service_name, ann)
|
|
|
|
self._outbound_announcements[service_name] = ann_d
|
|
|
|
|
|
|
|
# publish all announcements with the new seqnum and nonce
|
2020-12-04 11:18:51 -05:00
|
|
|
for service_name,ann_d in list(self._outbound_announcements.items()):
|
2013-03-18 17:40:56 -07:00
|
|
|
ann_d["seqnum"] = current_seqnum
|
|
|
|
ann_d["nonce"] = current_nonce
|
|
|
|
ann_t = sign_to_foolscap(ann_d, signing_key)
|
|
|
|
self._published_announcements[service_name] = ann_t
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self._maybe_publish()
|
2008-02-05 13:05:13 -07:00
|
|
|
|
|
|
|
def _maybe_publish(self):
|
|
|
|
if not self._publisher:
|
|
|
|
self.log("want to publish, but no introducer yet", level=log.NOISY)
|
|
|
|
return
|
|
|
|
# this re-publishes everything. The Introducer ignores duplicates
|
2020-12-04 11:18:51 -05:00
|
|
|
for ann_t in list(self._published_announcements.values()):
|
2009-06-22 19:10:47 -07:00
|
|
|
self._debug_counts["outbound_message"] += 1
|
2016-06-29 22:58:14 -07:00
|
|
|
self._debug_outstanding += 1
|
|
|
|
d = self._publisher.callRemote("publish_v2", ann_t, self._canary)
|
|
|
|
d.addBoth(self._debug_retired)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
d.addErrback(log.err, ann_t=ann_t,
|
|
|
|
facility="tahoe.introducer.client",
|
2008-08-25 18:57:59 -07:00
|
|
|
level=log.WEIRD, umid="xs9pVQ")
|
2008-02-05 13:05:13 -07:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
def remote_announce_v2(self, announcements):
|
|
|
|
lp = self.log("received %d announcements (v2)" % len(announcements))
|
|
|
|
return self.got_announcements(announcements, lp)
|
|
|
|
|
|
|
|
def got_announcements(self, announcements, lp=None):
|
2009-06-22 19:10:47 -07:00
|
|
|
self._debug_counts["inbound_message"] += 1
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
for ann_t in announcements:
|
2009-06-22 19:10:47 -07:00
|
|
|
try:
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
# this might raise UnknownKeyError or bad-sig error
|
|
|
|
ann, key_s = unsign_from_foolscap(ann_t)
|
|
|
|
# key is "v0-base32abc123"
|
2020-11-19 11:11:48 -05:00
|
|
|
precondition(isinstance(key_s, bytes), key_s)
|
2019-05-24 14:40:10 +02:00
|
|
|
except BadSignature:
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self.log("bad signature on inbound announcement: %s" % (ann_t,),
|
|
|
|
parent=lp, level=log.WEIRD, umid="ZAU15Q")
|
|
|
|
# process other announcements that arrived with the bad one
|
|
|
|
continue
|
|
|
|
|
|
|
|
self._process_announcement(ann, key_s)
|
|
|
|
|
|
|
|
def _process_announcement(self, ann, key_s):
|
2020-11-19 11:11:48 -05:00
|
|
|
precondition(isinstance(key_s, bytes), key_s)
|
2009-06-22 19:10:47 -07:00
|
|
|
self._debug_counts["inbound_announcement"] += 1
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
service_name = str(ann["service-name"])
|
2020-12-16 16:20:00 -05:00
|
|
|
if service_name not in self._local_subscribers:
|
2009-06-22 19:10:47 -07:00
|
|
|
self.log("announcement for a service we don't care about [%s]"
|
|
|
|
% (service_name,), level=log.UNUSUAL, umid="dIpGNA")
|
|
|
|
self._debug_counts["wrong_service"] += 1
|
|
|
|
return
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
# for ASCII values, simplejson might give us unicode *or* bytes
|
2020-11-19 11:11:48 -05:00
|
|
|
if "nickname" in ann and isinstance(ann["nickname"], bytes):
|
2020-12-04 11:18:51 -05:00
|
|
|
ann["nickname"] = str(ann["nickname"])
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
nick_s = ann.get("nickname",u"").encode("utf-8")
|
|
|
|
lp2 = self.log(format="announcement for nickname '%(nick)s', service=%(svc)s: %(ann)s",
|
|
|
|
nick=nick_s, svc=service_name, ann=ann, umid="BoKEag")
|
|
|
|
|
|
|
|
# how do we describe this node in the logs?
|
|
|
|
desc_bits = []
|
2016-07-05 16:41:15 -07:00
|
|
|
assert key_s
|
2020-11-19 11:11:48 -05:00
|
|
|
desc_bits.append(b"serverid=" + key_s[:20])
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
if "anonymous-storage-FURL" in ann:
|
|
|
|
tubid_s = get_tubid_string_from_ann(ann)
|
2020-11-19 11:11:48 -05:00
|
|
|
desc_bits.append(b"tubid=" + tubid_s[:8])
|
|
|
|
description = b"/".join(desc_bits)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
|
|
|
|
# the index is used to track duplicates
|
2016-05-10 20:19:55 -07:00
|
|
|
index = (service_name, key_s)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
|
|
|
|
# is this announcement a duplicate?
|
2013-03-18 17:40:56 -07:00
|
|
|
if (index in self._inbound_announcements
|
|
|
|
and self._inbound_announcements[index][0] == ann):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self.log(format="reannouncement for [%(service)s]:%(description)s, ignoring",
|
|
|
|
service=service_name, description=description,
|
|
|
|
parent=lp2, level=log.UNUSUAL, umid="B1MIdA")
|
2009-06-22 19:10:47 -07:00
|
|
|
self._debug_counts["duplicate_announcement"] += 1
|
|
|
|
return
|
2012-06-10 19:10:22 -07:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
# does it update an existing one?
|
2013-03-18 17:40:56 -07:00
|
|
|
if index in self._inbound_announcements:
|
|
|
|
old,_,_ = self._inbound_announcements[index]
|
2012-06-10 19:10:22 -07:00
|
|
|
if "seqnum" in old:
|
|
|
|
# must beat previous sequence number to replace
|
2013-03-18 17:40:56 -07:00
|
|
|
if ("seqnum" not in ann
|
|
|
|
or not isinstance(ann["seqnum"], (int,long))):
|
|
|
|
self.log("not replacing old announcement, no valid seqnum: %s"
|
2012-06-10 19:10:22 -07:00
|
|
|
% (ann,),
|
|
|
|
parent=lp2, level=log.NOISY, umid="zFGH3Q")
|
|
|
|
return
|
|
|
|
if ann["seqnum"] <= old["seqnum"]:
|
|
|
|
# note that exact replays are caught earlier, by
|
|
|
|
# comparing the entire signed announcement.
|
|
|
|
self.log("not replacing old announcement, "
|
|
|
|
"new seqnum is too old (%s <= %s) "
|
|
|
|
"(replay attack?): %s"
|
|
|
|
% (ann["seqnum"], old["seqnum"], ann),
|
|
|
|
parent=lp2, level=log.UNUSUAL, umid="JAAAoQ")
|
|
|
|
return
|
|
|
|
# ok, seqnum is newer, allow replacement
|
2009-06-22 19:10:47 -07:00
|
|
|
self._debug_counts["update"] += 1
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self.log("replacing old announcement: %s" % (ann,),
|
|
|
|
parent=lp2, level=log.NOISY, umid="wxwgIQ")
|
2009-06-22 19:10:47 -07:00
|
|
|
else:
|
|
|
|
self._debug_counts["new_announcement"] += 1
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 02:21:32 -08:00
|
|
|
self.log("new announcement[%s]" % service_name,
|
|
|
|
parent=lp2, level=log.NOISY)
|
2009-06-22 19:10:47 -07:00
|
|
|
|
2013-03-18 17:40:56 -07:00
|
|
|
self._inbound_announcements[index] = (ann, key_s, time.time())
|
2016-05-10 12:12:55 -07:00
|
|
|
self._save_announcements()
|
2009-06-22 19:10:47 -07:00
|
|
|
# note: we never forget an index, but we might update its value
|
|
|
|
|
2016-05-11 12:54:11 -07:00
|
|
|
self._deliver_announcements(key_s, ann)
|
|
|
|
|
|
|
|
def _deliver_announcements(self, key_s, ann):
|
2020-11-19 11:11:48 -05:00
|
|
|
precondition(isinstance(key_s, bytes), key_s)
|
2016-05-11 12:54:11 -07:00
|
|
|
service_name = str(ann["service-name"])
|
2020-12-16 16:20:00 -05:00
|
|
|
obs = self._local_subscribers.get(service_name)
|
|
|
|
if obs is not None:
|
|
|
|
obs.notify(key_s, ann)
|
2008-02-05 13:05:13 -07:00
|
|
|
|
2016-12-08 15:15:49 -08:00
|
|
|
def connection_status(self):
|
|
|
|
assert self.running # startService builds _introducer_reconnector
|
|
|
|
irc = self._introducer_reconnector
|
|
|
|
last_received = (self._publisher.getDataLastReceivedAt()
|
|
|
|
if self._publisher
|
|
|
|
else None)
|
|
|
|
return connection_status.from_foolscap_reconnector(irc, last_received)
|
|
|
|
|
2008-02-05 13:05:13 -07:00
|
|
|
def connected_to_introducer(self):
|
2009-06-22 19:10:47 -07:00
|
|
|
return bool(self._publisher)
|
2016-09-12 23:01:23 +00:00
|
|
|
|
|
|
|
def get_since(self):
|
|
|
|
return self._since
|