From 692e1179591f2ad1993239bcf4c39ce80ff5c6f1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Aug 2021 12:53:04 +0930 Subject: [PATCH] commando: add unique id as we hand our runes. This allows us to blacklist them in future. Signed-off-by: Rusty Russell --- commando/commando.py | 19 ++++++++++++++++++- commando/requirements.txt | 2 +- commando/test_commando.py | 10 +++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/commando/commando.py b/commando/commando.py index 01f1af9..32a9bd3 100755 --- a/commando/commando.py +++ b/commando/commando.py @@ -263,6 +263,7 @@ def commando_rune(plugin, rune=None, restrictions=[]): 'No datastore available: try datastore.py?') if rune is None: this_rune = plugin.masterrune.copy() + this_rune.add_restriction(runes.Restriction.unique_id(plugin.rune_counter)) else: this_rune, whynot = is_rune_valid(plugin, rune) if this_rune is None: @@ -276,6 +277,15 @@ def commando_rune(plugin, rune=None, restrictions=[]): for r in restrictions: this_rune.add_restriction(runes.Restriction.from_str(r)) + # Now we've succeeded, update rune_counter. + if rune is None: + plugin.rpc.datastore(key=['commando', 'rune_counter'], + string=str(plugin.rune_counter + 1), + mode='must-replace', + generation=plugin.rune_counter_generation) + plugin.rune_counter += 1 + plugin.rune_counter_generation += 1 + return {'rune': this_rune.to_base64()} @@ -320,9 +330,16 @@ def init(options, configuration, plugin): plugin.log("Creating initial rune secret", level='unusual') secret = secrets.token_bytes() plugin.rpc.datastore(key=['commando', 'secret'], hex=secret.hex()) + plugin.rune_counter = 0 + plugin.rune_counter_generation = 0 + plugin.rpc.datastore(key=['commando', 'rune_counter'], string=str(0)) else: secret = bytes.fromhex(secret[0]['hex']) - plugin.log("Initialized with rune support", level="info") + counter = plugin.rpc.listdatastore(['commando', 'rune_counter'])['datastore'][0] + plugin.rune_counter = int(counter['string']) + plugin.rune_counter_generation = int(counter['generation']) + plugin.log("Initialized with rune support: {} runes so far".format(plugin.rune_counter), + level="info") plugin.masterrune = runes.MasterRune(secret) plugin.peer_runes = load_peer_runes(plugin) diff --git a/commando/requirements.txt b/commando/requirements.txt index bac5b3b..c5264d6 100644 --- a/commando/requirements.txt +++ b/commando/requirements.txt @@ -1 +1 @@ -runes>=0.3.1.1 +runes>=0.4 diff --git a/commando/test_commando.py b/commando/test_commando.py index d873df1..f617c20 100755 --- a/commando/test_commando.py +++ b/commando/test_commando.py @@ -275,7 +275,15 @@ def test_rune_time(node_factory): method='commando-rune', rune=rune, params=[None, 'id={}'.format(l2.info['id'])]) - assert rune2 == rune2a + # r2a ID will be 1 greater than r2 ID + r2 = runes.Rune.from_base64(rune2['rune']) + r2a = runes.Rune.from_base64(rune2a['rune']) + assert len(r2.restrictions) == len(r2a.restrictions) + assert r2a.restrictions[0].alternatives == [runes.Alternative(r2.restrictions[0].alternatives[0].field, + r2.restrictions[0].alternatives[0].cond, + str(int(r2.restrictions[0].alternatives[0].value) + 1))] + for r2_r, r2a_r in zip(r2.restrictions[1:], r2a.restrictions[1:]): + assert r2_r == r2a_r time.sleep(16) with pytest.raises(RpcError, match='Not authorized.*time'):