ssbc / multiserver Goto Github PK
View Code? Open in Web Editor NEWA single interface that can work with multiple protocols, and multiple transforms of those protocols (eg, security layer)
License: MIT License
A single interface that can work with multiple protocols, and multiple transforms of those protocols (eg, security layer)
License: MIT License
Need to figure out an address format.
I'm thinking that something like
(type(:args)?)(,type(:args)?)*
where ,
is a separator, type
is a protocol name (ws
or net
or utp
etc) args
is whatever information type
needs (optional - for example gzip doesn't need args)
ipfs uses /
like a unix path, but I think this is ambigious because you have to know how many arguments a type takes to be able to parse it! That is especially bad for an upgradable system where you may see a descriptor for a thing that you don't support yet, and won't know what it means. It may mean you'll need to do IO while parsing.
instead better to use a different seperator, and allow protocols to format their args however they need, (provided any internal separators are escaped)
'|' would be nice, because it's a lot like piping, but `,' means you couldn't need to escape it on the terminal.
I'm a bit confused by the scope thing. what i want:
I want a message that indicates your public address, but unlike the current "pub" messages, you should only speak for your self, not claim someone else's pub address. This would be used for pubs, and also, for peers behind tunnels, or introduced, etc...
so, basic pattern will be:
command to advertise public address:
check your public address. (configured or detected)
check if you have already posted a message about this.
if yes, do nothing.
If not, or the address has changed since then,
then publish a message.
when creating a user invite, query for peers (which maybe be someone's pub) that follows you closely (in hops distance) that also has a public address. these are the peers which are likely to service the invite, so attach several of these to the code, say 3.
but poking around, on my laptop I get "net:192.168.43.244:8008~shs:EMovhfIrFk4NihAKnRNhrfRaqIhBv1Wj8pTxJNgvCCY="
which is only a local network address...
but on my pub, I get "net:128.199.132.182:8008~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ="
which is good, that is a public address... but there is no way to tell from calling that method which sort of address it will be?
For example: I want to advertise the 192.168... address on a local wifi, but not on a public feed, but the other one I want on a public feed. do we need more distinctions than just public and private?
@arj03 what do you think?
@arj03 is it possible to create multilpe tor hidden services via this api?
Oh, hmm - I just realized that this currently sets server: false
which means this doesn't even create a server.... this creates the ability to use tor as a client protocol... but how do are you configuring the server?
asking because I am working on a less hardcoded api for using the various network protocols.
Commit faa9526 introduced a module-level variable started
(l.6-l.7) that is used to avoid reinitializing the unix socket twice. Unfortunately, when the plugin is used in two different Secret-Stacks running within the same node process, e.g. in unit tests, this strategy prevents the second instance from being initialized properly and is therefore ignored.
Moreover, l.27 returns undefined
and therefore upon closing, the second instance fails with the following error:
.../node_modules/multiserver/compose.js:33
if (f.length) return f(cb)
^
TypeError: Cannot read property 'length' of undefined
at fnAsAsync (.../node_modules/multiserver/compose.js:33:11)
at closeMultiserverServer (.../node_modules/multiserver/index.js:57:37)
at close (.../node_modules/secret-stack/lib/core.js:259:82)
at hooked (.../node_modules/hoox/index.js:10:15)
at .../node_modules/ssb-db/index.js:90:11
at .../node_modules/flumedb/index.js:263:25
at .../node_modules/continuable-hash/index.js:25:25
at Single._written (.../node_modules/async-single/proto.js:46:12)
at release (.../node_modules/mutexify/index.js:25:13)
at .../node_modules/atomic-file/inject.js:27:11
npm ERR! Test failed. See above for more details.
At least, l.27 should be fixed to avoid an error on closing. Better, the check for avoiding duplicate initialization should be specific to a specific instance of Secret-Stack and not module-wide (which is initialized only once for all node module imports).
in the browser, multiserver should not use net, hopefully they have also provided an address that works in the browser, such as websockets.
The SSB-Config documentation says that external
is an array of external strings, but the Multiserver implementation parses it as a string. We need some tests and fixes around this.
Reported-by: @rbdr
Looking at: https://github.com/ssbc/multiserver#address-format I see that net is specified as net:, while wss is specified as wss://? Seems as if both should be specified the same way, so wss:wx.larpa.net~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
, instead of wss://wx.larpa.net~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
?
It looks like we're having problems that seem to be resolved by server: true
. From skimming the source, I can see opts.server
used in three places:
$ git grep opts.server
plugins/onion.js: if(!opts.server) return
plugins/onion.js: if(opts && !opts.server) return null
plugins/unix-socket.js: server: !opts.server ? null : function (onConnection) {
plugins/unix-socket.js: if(opts && !opts.server) return null
plugins/ws.js: var secure = opts.server && !!opts.server.key
plugins/ws.js: var server = opts.server || http.createServer(opts.handler)
plugins/ws.js: if(!opts.server) {
plugins/ws.js: if(opts.server)
plugins/ws.js: port = opts.server.address().port
opts.server
is falsy, it looks like the connection is abandoned and we instead just return
.null
. Is there a reason for the difference in these two implementations?opts.server
is an object with two expected properties: key
and address
, and the latter is a function that returns an object with the property port
. The full usage is opts.server.address().port
, which makes me think there are some moving parts here I don't understand.@dominictarr Could you add some info to help me better understand what we should be doing with this option? Apologies if this has already been recorded somewhere, so far I've checked #32, ssb-config, and scuttlebot but didn't see any notes about this change. Appreciate your help!
If I do
sbot server --host=:: --port=8100 --ws.port=8101&
sbot getAddress -- --host=::1 --port=8100
I get:
net::::8100~ ... ;ws://[::]:8101
Is that desired behaviour because the square brackets are needed because the ws address is actually a URL and the net: address is not? Or is it a bug and it should be net:[::]:8100
? cc @dominictarr
I notice that my public scoped ws plugin returned localhost as it's host, which didn't work when I attempted to connect to it remotely!
It looks like require('pull-stream/pull')
no longer has map
, but require('pull-stream')
does.
/node_modules/multiserver/plugins/ws.js:34
stream.source = pull(stream.source, pull.map(Buffer))
^
TypeError: pull.map is not a function
at onConnect (/node_modules/multiserver/plugins/ws.js:34:52)
at WebSocket.<anonymous> (/node_modules/pull-ws/source.js:49:13)
at WebSocket.onError (/node_modules/ws/lib/WebSocket.js:452:14)
at emitOne (events.js:116:13)
at WebSocket.emit (events.js:211:7)
at ClientRequest.onerror (/node_modules/ws/lib/WebSocket.js:711:10)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitOne (events.js:116:13)
I believe they need to be escaped with square brackets?
For example:
net:[::]:8100 ...
I saw in %94G9B4MPIbhQynNlCApdn88PlT73/PE9l/jKmOsxy84=.sha256 that we're broadcasting the unix socket over UDP, which exposes our username to all network peers. I'd love to avoid this, if possible. Potential solutions:
Don't broadcast unix sockets (?)
Use a temporary socket with mktemp
$ mktemp
/tmp/tmp.NrzUtkX6jl
i notice that multiserver addresses, like
net:wx.larpa.net:8008~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
truncate the "full" public key to
DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
instead of
@DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=.ed25519
as is the format used everywhere else.
for more context, this became annoying when i wanted to write a jinja template for file managed by Salt Stack, where i had access to the values in ~/.ssb/secret
but had no ability to truncate the public key as required to create a multiserver address in the template.
i've now worked around this problem, but i still was wondering on the thinking behind it, i don't know much about how important it is to have the curve in the key, as i think this is also implied when saying shs
.
I2P is an anonymous overlay network similar to Tor, but with different security and decentralization trade-offs. It is an extremely mature project and would be very desireable to have available.
Looks like it's not getting passed at all: https://github.com/ssbc/multiserver/blob/master/plugins/ws.js#L63
Originally reported as ssbc/patchwork#979
first some context, (maybe this can become documentation?)
multiserver is designed around plugins. there are two types of plugins, transports and transforms. Then transports make a connection to something, and transforms change something about it, such as encrypting and authenticating it, or compressing it. so far, we've just used the shs transform plugin to encrypt everything.
multiserver gives you a convienent handle to run multiple servers, with multiple protocol versions at the same time. that's why it's called multiserver. So, you can have multiple servers. We started to add that, but then we realized we needed something more: scopes. servers are useful for lots of things, but sometimes you don't want everyone to connect to them (we care about privacy, and would rather someone connect via tor, but local clients can use net), and other times, you know that someone can't connect to them anyway, so we want to avoid telling them about it. (we are running our server on a laptop on wifi, without a stable ip address. so we don't want to advertise our address publically, but maybe we do for another multiserver that is running on cjdns or tor etc)
Each transport plugin now takes a scope option, which is a string: the name of that scope. when a plugin is created, the plugin is passed the scope it will have. eg, Net({host: ..., port: ..., scope: 'public'})
plugins also have a scope() method, which just returns the scope it was configured with, or defaults to. so Plugin({scope: X}).scope() === X
When you call multiserver.stringify(scope)
it then returns an address for that scope.
If scope is "private" then public plugins are allowed.
Okay I think I understand all that now. but why isn't my websocket server attaching? hmm...
Today I gave a talk on designing for security. One of my main messages was "don't make it configurable" or at least "don't make it easier to have an insecure configuration"
I remembered that multiserver noauth is a potential problem here.
It would be easy to set net~noauth
and it would be faster! except now anyone can connect to you, and tell you what to do, if you have noauth set.
It's not a responsible design to expect them to understand not to use noauth
with a network.
They should have to explicitly enable the footgun.
My idea to approach this: first make sure all the plugins set an address property consistently.
then, have noauth
take an address config option, and refuse connections that do not have the correct address. This means to enable noauth, you have to set the address twice!
ws: [{scope: 'device', port: 8989, transform: { name: 'noauth', address: 'ws://localhost:8989' }}]
or something like that. We don't have a way to specify configuration for transforms yet.
I have this about half coded
so i'm working on the ButtCloud infrastructure (butt), i finally figured out a bug that's kept me stuck on that front for over a week.
it seems i need a way for the scuttlebot server to bind to a host like 0.0.0.0 (internal to the Docker Swarm service, which is automatically available to other internal services and exported via an ingress router to the external internet), but then advertise a different public host like party.butt.nz
(like when publishing invites and things).
See: ssbc/patchwork#1035
We have a scenario where config.connections.incoming
is specifying the correct IP addresses but it looks like this code is still falling back to multiserver-scopes (i.e. non-private-ip) in the local scope:
Line 92 in 1fefc75
I'd imagine that this is a bug or maybe I'm completely misunderstanding what this is supposed to do? For example, my config:
{ net:
[ { host: '127.0.0.1',
port: 8008,
scope: [ 'device' ],
transform: 'shs' },
{ host: '::1', port: 8008, scope: [ 'device' ], transform: 'shs' },
{ host: '192.168.0.109',
port: 8008,
scope: [ 'device', 'local', 'public' ],
transform: 'shs' },
{ host: '172.18.0.1',
port: 8008,
scope: [ 'device', 'local', 'public' ],
transform: 'shs' },
{ host: 'fce2:9811:4862:81a7:bb08:91d6:2e41:d220',
port: 8008,
scope: [ 'device', 'local', 'public' ],
transform: 'shs' } ],
ws:
[ { host: '127.0.0.1',
port: 8989,
scope: [ 'device' ],
transform: 'shs' },
{ host: '::1', port: 8989, scope: [ 'device' ], transform: 'shs' },
{ host: '192.168.0.109',
port: 8989,
scope: [ 'device', 'local', 'public' ],
transform: 'shs' },
{ host: '172.18.0.1',
port: 8989,
scope: [ 'device', 'local', 'public' ],
transform: 'shs' },
{ host: 'fce2:9811:4862:81a7:bb08:91d6:2e41:d220',
port: 8989,
scope: [ 'device', 'local', 'public' ],
transform: 'shs' } ],
unix: [ { scope: 'device', transform: 'noauth' } ] } }
But over the network I see:
net:192.168.0.109:8008~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=;net:192.168.0.109:8008~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=;net:192.168.0.109:8008~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=;ws://192.168.0.109:8989~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=;ws://192.168.0.109:8989~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=;ws://192.168.0.109:8989~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
Replacing the semicolons with newlines (I'd love if this was the default):
net:192.168.0.109:8008~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
net:192.168.0.109:8008~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
net:192.168.0.109:8008~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
ws://192.168.0.109:8989~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
ws://192.168.0.109:8989~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
ws://192.168.0.109:8989~shs:+oaWWDs8g73EZFUMfW37R/ULtFEjwKN/DczvdYihjbU=
Maybe relevant: #22
@staltz when I update to [email protected] the http://github.com/evbogue/mvd lite client breaks in the browser. I see a series of
onion dialing through socks proxy not supported in browser setting
errors, and nothing loads.
Since I'm not familiar with the changes, I'm just going to back up to the last version for now.
I see this commit, but I don't understand what's the context around that commit. What breaks if we use empty strings instead?
My context: given that I'm using trusted transports (e.g. react native's "bridge" which is closed to other applications in the OS, and obviously closed to remote actors), I believe I don't need the public key, hence I could save the cost of using FS APIs on the frontend looking for secret
, but the way noauth plugin is built requires me to pass it a public key.
Brief bug report because I'm on mobile walking home. Spent a few hours today debugging why the Travis tests on MacOS are failing and I'm very confused. I'm seeing this on the 'main' branch and also on my branch with the new Pull-WS.
We're starting a WS client and server, and then connecting to server.stringify(), but when we do the if (err) throw err
dance we end up throwing a weird error.
The error originates from a net server on some ungodly high port, but plugs.js
isn't listening there. Maybe the problem is caused by multiple tests running at the same time? Anyway, the problem is that we're receiving a TCP + SHS connection but the client connecting doesn't have a public key in their address. I don't know what would cause this.
Tomorrow I'll probably edit the test command so that we're only testing the one file. I'm worriee about why we'd be propagating an error from another server (race condition?), but I wouldn't be surprised.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.