Skip to content

Commit c0a57a2

Browse files
authored
squashed (#1302)
part 2: policy refactor + cli tests
1 parent e976f84 commit c0a57a2

19 files changed

Lines changed: 416 additions & 689 deletions

.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ matrix:
3030
- python: pypy3
3131
env: TOX_ENV=pypy3-cli
3232

33+
- python: 3.6
34+
env: TOX_ENV=py36-examples
35+
- python: pypy3
36+
env: TOX_ENV=pypy3-examples
37+
3338
- python: 3.6
3439
env: TOX_ENV=py36-unpinned-trial,coverage-report
3540
- python: 3.6

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ clean:
2929
# Learn to love the shell! http://unix.stackexchange.com/a/115869/52500
3030
find . \( -name "*__pycache__" -type d \) -prune -exec rm -rf {} +
3131

32+
# build documentation
3233
docs:
33-
python docs/test_server.py
34+
sphinx-build -b html ./docs ./docs/_build
3435

3536
# call this in a fresh virtualenv to update our frozen requirements.txt!
3637
freeze: clean
@@ -72,16 +73,15 @@ publish: clean
7273
test: flake8
7374
trial crossbar
7475

75-
test_quick:
76-
tox -e flake8,py36-abtrunk-trial
76+
test_tox:
77+
tox -e flake8,py36-unpinned-trial,py36-cli .
7778

7879
test_cli:
7980
./test/test_cli.sh
8081

8182
test_cli_tox:
8283
tox -e py36-cli .
8384

84-
8585
test_mqtt:
8686
# trial crossbar.adapter.mqtt.test.test_wamp
8787
trial crossbar.adapter.mqtt.test.test_wamp.MQTTAdapterTests.test_basic_publish

crossbar/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def run(args=None, reactor=None):
124124
125125
``--cbdir`` **CROSSBAR_DIR** Node directory (local directory)
126126
``--config`` **CROSSBAR_CONFIG** Node configuration (local filename)
127-
``--color`` n.a. Enable colored terminal output
127+
``--color`` n.a. Enable colored terminal output
128128
``--loglevel`` n.a. Select log level
129129
``--logformat`` n.a. Select log format
130130
``--logdir`` n.a. Log to this local directory

crossbar/common/key.py

Lines changed: 126 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,22 @@
4141
import pkg_resources
4242
import pyqrcode
4343

44+
from nacl.signing import SigningKey
45+
from nacl.encoding import HexEncoder
46+
47+
import txaio
48+
from autobahn.util import utcnow
4449
from autobahn.wamp.cryptosign import _read_signify_ed25519_pubkey, _qrcode_from_signify_ed25519_pubkey
4550

4651
from twisted.python.runtime import platform
4752

4853
import crossbar
4954

5055

51-
def _read_release_pubkey():
56+
log = txaio.make_logger()
57+
58+
59+
def _read_release_key():
5260
release_pubkey_file = 'crossbar-{}.pub'.format('-'.join(crossbar.__version__.split('.')[0:2]))
5361
release_pubkey_path = os.path.join(pkg_resources.resource_filename('crossbar', 'keys'), release_pubkey_file)
5462

@@ -68,7 +76,7 @@ def _read_release_pubkey():
6876
return release_pubkey
6977

7078

71-
def _parse_keyfile(key_path, private=True):
79+
def _parse_key_file(key_path, private=True):
7280
"""
7381
Internal helper. This parses a node.pub or node.priv file and
7482
returns a dict mapping tags -> values.
@@ -99,41 +107,40 @@ def _parse_keyfile(key_path, private=True):
99107
return tags
100108

101109

102-
def _read_node_pubkey(cbdir, privkey_path=u'key.priv', pubkey_path=u'key.pub'):
103-
104-
node_pubkey_path = os.path.join(cbdir, pubkey_path)
105-
106-
if not os.path.exists(node_pubkey_path):
107-
raise Exception('no node public key found at {}'.format(node_pubkey_path))
110+
def _read_node_key(cbdir, privkey_path=u'key.priv', pubkey_path=u'key.pub', private=False):
111+
if private:
112+
node_key_path = os.path.join(cbdir, privkey_path)
113+
else:
114+
node_key_path = os.path.join(cbdir, pubkey_path)
108115

109-
node_pubkey_tags = _parse_keyfile(node_pubkey_path)
116+
if not os.path.exists(node_key_path):
117+
raise Exception('no node key file found at {}'.format(node_key_path))
110118

111-
node_pubkey_hex = node_pubkey_tags[u'public-key-ed25519']
119+
node_key_tags = _parse_key_file(node_key_path)
112120

113-
qr = pyqrcode.create(node_pubkey_hex, error='L', mode='binary')
121+
if private:
122+
node_key_hex = node_key_tags[u'private-key-ed25519']
123+
else:
124+
node_key_hex = node_key_tags[u'public-key-ed25519']
114125

126+
qr = pyqrcode.create(node_key_hex, error='L', mode='binary')
115127
mode = 'text'
116-
117128
if mode == 'text':
118-
node_pubkey_qr = qr.terminal()
119-
129+
node_key_qr = qr.terminal()
120130
elif mode == 'svg':
121131
import io
122132
data_buffer = io.BytesIO()
123-
124133
qr.svg(data_buffer, omithw=True)
125-
126-
node_pubkey_qr = data_buffer.getvalue()
127-
134+
node_key_qr = data_buffer.getvalue()
128135
else:
129136
raise Exception('logic error')
130137

131-
node_pubkey = {
132-
u'hex': node_pubkey_hex,
133-
u'qrcode': node_pubkey_qr
138+
node_key = {
139+
u'hex': node_key_hex,
140+
u'qrcode': node_key_qr
134141
}
135142

136-
return node_pubkey
143+
return node_key
137144

138145

139146
def _machine_id():
@@ -187,3 +194,100 @@ def _write_node_key(filepath, tags, msg):
187194
if value is None:
188195
value = 'unknown'
189196
f.write(u'{}: {}\n'.format(tag, value))
197+
198+
199+
def _maybe_generate_key(cbdir, privfile=u'key.priv', pubfile=u'key.pub'):
200+
201+
privkey_path = os.path.join(cbdir, privfile)
202+
pubkey_path = os.path.join(cbdir, pubfile)
203+
204+
if os.path.exists(privkey_path):
205+
206+
# node private key seems to exist already .. check!
207+
208+
priv_tags = _parse_key_file(privkey_path, private=True)
209+
for tag in [u'creator', u'created-at', u'machine-id', u'public-key-ed25519', u'private-key-ed25519']:
210+
if tag not in priv_tags:
211+
raise Exception("Corrupt node private key file {} - {} tag not found".format(privkey_path, tag))
212+
213+
privkey_hex = priv_tags[u'private-key-ed25519']
214+
privkey = SigningKey(privkey_hex, encoder=HexEncoder)
215+
pubkey = privkey.verify_key
216+
pubkey_hex = pubkey.encode(encoder=HexEncoder).decode('ascii')
217+
218+
if priv_tags[u'public-key-ed25519'] != pubkey_hex:
219+
raise Exception(
220+
("Inconsistent node private key file {} - public-key-ed25519 doesn't"
221+
" correspond to private-key-ed25519").format(pubkey_path)
222+
)
223+
224+
if os.path.exists(pubkey_path):
225+
pub_tags = _parse_key_file(pubkey_path, private=False)
226+
for tag in [u'creator', u'created-at', u'machine-id', u'public-key-ed25519']:
227+
if tag not in pub_tags:
228+
raise Exception("Corrupt node public key file {} - {} tag not found".format(pubkey_path, tag))
229+
230+
if pub_tags[u'public-key-ed25519'] != pubkey_hex:
231+
raise Exception(
232+
("Inconsistent node public key file {} - public-key-ed25519 doesn't"
233+
" correspond to private-key-ed25519").format(pubkey_path)
234+
)
235+
else:
236+
log.info(
237+
"Node public key file {pub_path} not found - re-creating from node private key file {priv_path}",
238+
pub_path=pubkey_path,
239+
priv_path=privkey_path,
240+
)
241+
pub_tags = OrderedDict([
242+
(u'creator', priv_tags[u'creator']),
243+
(u'created-at', priv_tags[u'created-at']),
244+
(u'machine-id', priv_tags[u'machine-id']),
245+
(u'public-key-ed25519', pubkey_hex),
246+
])
247+
msg = u'Crossbar.io node public key\n\n'
248+
_write_node_key(pubkey_path, pub_tags, msg)
249+
250+
log.info("Node key files exist and are valid")
251+
log.debug("Node public key: {hex}", hex=pubkey_hex)
252+
253+
else:
254+
# node private key does not yet exist: generate one
255+
256+
privkey = SigningKey.generate()
257+
privkey_hex = privkey.encode(encoder=HexEncoder).decode('ascii')
258+
pubkey = privkey.verify_key
259+
pubkey_hex = pubkey.encode(encoder=HexEncoder).decode('ascii')
260+
261+
# first, write the public file
262+
tags = OrderedDict([
263+
(u'creator', _creator()),
264+
(u'created-at', utcnow()),
265+
(u'machine-id', _machine_id()),
266+
(u'public-key-ed25519', pubkey_hex),
267+
])
268+
msg = u'Crossbar.io node public key\n\n'
269+
_write_node_key(pubkey_path, tags, msg)
270+
271+
# now, add the private key and write the private file
272+
tags[u'private-key-ed25519'] = privkey_hex
273+
msg = u'Crossbar.io node private key - KEEP THIS SAFE!\n\n'
274+
_write_node_key(privkey_path, tags, msg)
275+
276+
log.info("New node key pair generated!")
277+
278+
# fix file permissions on node public/private key files
279+
# note: we use decimals instead of octals as octal literals have changed between Py2/3
280+
#
281+
if os.stat(pubkey_path).st_mode & 511 != 420: # 420 (decimal) == 0644 (octal)
282+
os.chmod(pubkey_path, 420)
283+
log.info("File permissions on node public key fixed")
284+
285+
if os.stat(privkey_path).st_mode & 511 != 384: # 384 (decimal) == 0600 (octal)
286+
os.chmod(privkey_path, 384)
287+
log.info("File permissions on node private key fixed")
288+
289+
log.info(
290+
'Node key loaded from "{priv_path}"',
291+
priv_path=privkey_path,
292+
)
293+
return privkey

0 commit comments

Comments
 (0)