2008-03-11 17:36:25 -07:00
|
|
|
|
2012-03-06 18:25:05 -08:00
|
|
|
import time, os
|
2017-07-25 11:15:31 -04:00
|
|
|
from nevow import rend
|
2012-03-06 18:25:05 -08:00
|
|
|
from nevow.static import File as nevow_File
|
|
|
|
from nevow.util import resource_filename
|
2019-08-14 10:37:56 +01:00
|
|
|
from twisted.web.template import Element, renderer, renderElement, XMLFile
|
|
|
|
from twisted.python.filepath import FilePath
|
|
|
|
from twisted.web import resource
|
2008-03-11 17:36:25 -07:00
|
|
|
import allmydata
|
2017-01-19 15:39:53 -07:00
|
|
|
import json
|
2019-08-13 15:11:01 -04:00
|
|
|
from allmydata.version_checks import get_package_versions_string
|
2008-03-11 17:36:25 -07:00
|
|
|
from allmydata.util import idlib
|
2017-07-25 11:15:31 -04:00
|
|
|
from allmydata.web.common import (
|
|
|
|
getxmlfile,
|
|
|
|
render_time,
|
2019-08-14 11:31:50 +01:00
|
|
|
MultiFormatResource,
|
2019-08-14 10:37:56 +01:00
|
|
|
SlotsSequenceElement,
|
2017-07-25 11:15:31 -04:00
|
|
|
)
|
2013-05-19 23:27:23 +01:00
|
|
|
|
2008-03-11 17:36:25 -07:00
|
|
|
|
2019-08-14 11:31:50 +01:00
|
|
|
class IntroducerRoot(MultiFormatResource):
|
2009-02-20 12:15:54 -07:00
|
|
|
def __init__(self, introducer_node):
|
2019-08-14 11:31:50 +01:00
|
|
|
super(IntroducerRoot, self).__init__()
|
2009-02-20 12:15:54 -07:00
|
|
|
self.introducer_node = introducer_node
|
|
|
|
self.introducer_service = introducer_node.getServiceNamed("introducer")
|
2019-08-14 10:37:56 +01:00
|
|
|
# necessary as a root Resource
|
|
|
|
self.putChild('', self)
|
2012-03-06 18:25:05 -08:00
|
|
|
static_dir = resource_filename("allmydata.web", "static")
|
|
|
|
for filen in os.listdir(static_dir):
|
|
|
|
self.putChild(filen, nevow_File(os.path.join(static_dir, filen)))
|
2009-02-20 12:15:54 -07:00
|
|
|
|
2019-08-14 11:31:50 +01:00
|
|
|
def render_HTML(self, req):
|
|
|
|
return renderElement(req, IntroducerRootElement(
|
2019-08-14 10:37:56 +01:00
|
|
|
self.introducer_node, self.introducer_service))
|
|
|
|
|
2017-07-25 11:15:31 -04:00
|
|
|
def render_JSON(self, req):
|
2008-03-25 12:56:12 -07:00
|
|
|
res = {}
|
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
|
|
|
|
|
|
|
counts = {}
|
2012-04-23 18:02:22 -04:00
|
|
|
for s in self.introducer_service.get_subscribers():
|
|
|
|
if s.service_name not in counts:
|
|
|
|
counts[s.service_name] = 0
|
|
|
|
counts[s.service_name] += 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
|
|
|
res["subscription_summary"] = counts
|
2008-03-25 12:56:12 -07:00
|
|
|
|
|
|
|
announcement_summary = {}
|
2012-04-23 18:02:22 -04:00
|
|
|
for ad in self.introducer_service.get_announcements():
|
|
|
|
service_name = ad.service_name
|
2008-03-25 12:56:12 -07:00
|
|
|
if service_name not in announcement_summary:
|
|
|
|
announcement_summary[service_name] = 0
|
|
|
|
announcement_summary[service_name] += 1
|
|
|
|
res["announcement_summary"] = announcement_summary
|
|
|
|
|
2017-01-19 15:39:53 -07:00
|
|
|
return json.dumps(res, indent=1) + "\n"
|
2008-03-25 12:56:12 -07:00
|
|
|
|
2019-08-14 10:37:56 +01:00
|
|
|
|
|
|
|
class IntroducerRootElement(Element):
|
|
|
|
|
|
|
|
loader = XMLFile(FilePath(__file__).sibling("introducer.xhtml"))
|
|
|
|
|
|
|
|
def __init__(self, introducer_node, introducer_service):
|
|
|
|
super(IntroducerRootElement, self).__init__()
|
|
|
|
self.introducer_node = introducer_node
|
|
|
|
self.introducer_service = introducer_service
|
|
|
|
self.node_data_dict = {
|
|
|
|
'my_nodeid': idlib.nodeid_b2a(self.introducer_node.nodeid),
|
|
|
|
'version': get_package_versions_string(),
|
|
|
|
'import_path': str(allmydata).replace("/", "/ "), # XXX kludge for wrapping
|
|
|
|
'rendered_at': render_time(time.time()),
|
|
|
|
}
|
|
|
|
|
|
|
|
@renderer
|
|
|
|
def node_data(self, req, tag):
|
|
|
|
return tag.fillSlots(**self.node_data_dict)
|
|
|
|
|
|
|
|
@renderer
|
|
|
|
def announcement_summary(self, req, data):
|
2008-03-11 19:21:29 -07:00
|
|
|
services = {}
|
2012-04-23 18:02:22 -04:00
|
|
|
for ad in self.introducer_service.get_announcements():
|
|
|
|
if ad.service_name not in services:
|
|
|
|
services[ad.service_name] = 0
|
|
|
|
services[ad.service_name] += 1
|
2008-03-11 19:21:29 -07:00
|
|
|
service_names = services.keys()
|
|
|
|
service_names.sort()
|
|
|
|
return ", ".join(["%s: %d" % (service_name, services[service_name])
|
|
|
|
for service_name in service_names])
|
2008-03-11 17:36:25 -07:00
|
|
|
|
2019-08-14 10:37:56 +01:00
|
|
|
@renderer
|
|
|
|
def client_summary(self, req, data):
|
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
|
|
|
counts = {}
|
2012-04-23 18:02:22 -04:00
|
|
|
for s in self.introducer_service.get_subscribers():
|
|
|
|
if s.service_name not in counts:
|
|
|
|
counts[s.service_name] = 0
|
|
|
|
counts[s.service_name] += 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
|
|
|
return ", ".join([ "%s: %d" % (name, counts[name])
|
|
|
|
for name in sorted(counts.keys()) ] )
|
2008-03-11 17:36:25 -07:00
|
|
|
|
2019-08-14 10:37:56 +01:00
|
|
|
@renderer
|
|
|
|
def services(self, req, tag):
|
2016-06-29 22:58:14 -07:00
|
|
|
services = self.introducer_service.get_announcements()
|
2012-04-23 18:02:22 -04:00
|
|
|
services.sort(key=lambda ad: (ad.service_name, ad.nickname))
|
2019-08-14 10:37:56 +01:00
|
|
|
services = [{
|
|
|
|
"serverid": ad.serverid,
|
|
|
|
"nickname": ad.nickname,
|
|
|
|
"connection-hints":
|
|
|
|
"connection hints: " + " ".join(ad.connection_hints),
|
|
|
|
"connected": "?",
|
|
|
|
"announced": render_time(ad.when),
|
|
|
|
"version": ad.version,
|
|
|
|
"service_name": ad.service_name,
|
|
|
|
} for ad in services]
|
|
|
|
return SlotsSequenceElement(tag, services)
|
|
|
|
|
|
|
|
@renderer
|
|
|
|
def subscribers(self, ctx, tag):
|
|
|
|
subscribers = [{
|
|
|
|
"nickname": s.nickname,
|
|
|
|
"tubid": s.tubid,
|
|
|
|
"connected": s.remote_address,
|
|
|
|
"since": render_time(s.when),
|
|
|
|
"version": s.version,
|
|
|
|
"service_name": s.service_name,
|
|
|
|
} for s in self.introducer_service.get_subscribers()]
|
|
|
|
return SlotsSequenceElement(tag, subscribers)
|