From 0200655b3a3019a0d4eaf58db0db85bf4024c1d8 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Thu, 26 Mar 2020 10:19:44 -0400 Subject: [PATCH] Add Ristretto public key to the schema and Python and HTTP APIs It is stored on redemption and regurgitated by the Python APIs and dumped in the JSON accessible via the HTTP API. --- src/_zkapauthorizer/model.py | 21 +++++++++++++++++-- src/_zkapauthorizer/schema.py | 6 ++++++ src/_zkapauthorizer/tests/strategies.py | 1 + .../tests/test_client_resource.py | 2 ++ src/_zkapauthorizer/tests/test_controller.py | 8 ++++--- src/_zkapauthorizer/tests/test_model.py | 1 + 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/_zkapauthorizer/model.py b/src/_zkapauthorizer/model.py index 1060418..fe2507b 100644 --- a/src/_zkapauthorizer/model.py +++ b/src/_zkapauthorizer/model.py @@ -216,7 +216,7 @@ class VoucherStore(object): cursor.execute( """ SELECT - [number], [created], [state], [finished], [token-count] + [number], [created], [state], [finished], [token-count], [public-key] FROM [vouchers] WHERE @@ -300,7 +300,7 @@ class VoucherStore(object): cursor.execute( """ SELECT - [number], [created], [state], [finished], [token-count] + [number], [created], [state], [finished], [token-count], [public-key] FROM [vouchers] """, @@ -339,12 +339,14 @@ class VoucherStore(object): SET [state] = ? , [token-count] = ? , [finished] = ? + , [public-key] = ? WHERE [number] = ? """, ( voucher_state, len(unblinded_tokens), self.now(), + public_key, voucher, ), ) @@ -712,8 +714,20 @@ class Redeeming(object): @attr.s(frozen=True) class Redeemed(object): + """ + The voucher was successfully redeemed. Associated tokens were retrieved + and stored locally. + + :ivar datetime finished: The time when the redemption finished. + + :ivar int token_count: The number of tokens the voucher was redeemed for. + + :ivar unicode public_key: The public part of the key used to sign the + tokens for this voucher. + """ finished = attr.ib(validator=attr.validators.instance_of(datetime)) token_count = attr.ib(validator=attr.validators.instance_of((int, long))) + public_key = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(unicode))) def should_start_redemption(self): return False @@ -723,6 +737,7 @@ class Redeemed(object): u"name": u"redeemed", u"finished": self.finished.isoformat(), u"token-count": self.token_count, + u"public-key": self.public_key, } @@ -819,6 +834,7 @@ class Voucher(object): return Redeemed( parse_datetime(row[0], delimiter=u" "), row[1], + row[2], ) raise ValueError("Unknown voucher state {}".format(state)) @@ -859,6 +875,7 @@ class Voucher(object): state = Redeemed( finished=parse_datetime(state_json[u"finished"]), token_count=state_json[u"token-count"], + public_key=state_json[u"public-key"], ) elif state_name == u"unpaid": state = Unpaid( diff --git a/src/_zkapauthorizer/schema.py b/src/_zkapauthorizer/schema.py index cf71a9c..502628a 100644 --- a/src/_zkapauthorizer/schema.py +++ b/src/_zkapauthorizer/schema.py @@ -125,6 +125,12 @@ _UPGRADES = { ) """, ], + + 1: [ + """ + ALTER TABLE [vouchers] ADD COLUMN [public-key] text + """, + ], } def _check_consistency(): diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py index 9157bde..a63af54 100644 --- a/src/_zkapauthorizer/tests/strategies.py +++ b/src/_zkapauthorizer/tests/strategies.py @@ -308,6 +308,7 @@ def voucher_states(): Redeemed, finished=datetimes(), token_count=one_of(integers(min_value=1)), + public_key=dummy_ristretto_keys(), ), builds( DoubleSpend, diff --git a/src/_zkapauthorizer/tests/test_client_resource.py b/src/_zkapauthorizer/tests/test_client_resource.py index f901d02..423f495 100644 --- a/src/_zkapauthorizer/tests/test_client_resource.py +++ b/src/_zkapauthorizer/tests/test_client_resource.py @@ -768,6 +768,7 @@ class VoucherTests(TestCase): state=Equals(Redeemed( finished=now, token_count=NUM_TOKENS, + public_key=None, )), ), ) @@ -913,6 +914,7 @@ class VoucherTests(TestCase): state=Redeemed( finished=now, token_count=NUM_TOKENS, + public_key=None, ), ).marshal() for voucher diff --git a/src/_zkapauthorizer/tests/test_controller.py b/src/_zkapauthorizer/tests/test_controller.py index 9333ed1..1c1af18 100644 --- a/src/_zkapauthorizer/tests/test_controller.py +++ b/src/_zkapauthorizer/tests/test_controller.py @@ -116,6 +116,7 @@ from .strategies import ( tahoe_configs, vouchers, voucher_objects, + dummy_ristretto_keys, clocks, ) from .matchers import ( @@ -149,15 +150,15 @@ class PaymentControllerTests(TestCase): Equals(model_Pending()), ) - @given(tahoe_configs(), datetimes(), vouchers()) - def test_redeemed_after_redeeming(self, get_config, now, voucher): + @given(tahoe_configs(), dummy_ristretto_keys(), datetimes(), vouchers()) + def test_redeemed_after_redeeming(self, get_config, public_key, now, voucher): """ A ``Voucher`` is marked as redeemed after ``IRedeemer.redeem`` succeeds. """ store = self.useFixture(TemporaryVoucherStore(get_config, lambda: now)).store controller = PaymentController( store, - DummyRedeemer(), + DummyRedeemer(public_key), default_token_count=10, ) controller.redeem(voucher) @@ -168,6 +169,7 @@ class PaymentControllerTests(TestCase): Equals(model_Redeemed( finished=now, token_count=10, + public_key=public_key, )), ) diff --git a/src/_zkapauthorizer/tests/test_model.py b/src/_zkapauthorizer/tests/test_model.py index bf2dbaf..e4052d2 100644 --- a/src/_zkapauthorizer/tests/test_model.py +++ b/src/_zkapauthorizer/tests/test_model.py @@ -392,6 +392,7 @@ class UnblindedTokenStoreTests(TestCase): state=Equals(Redeemed( finished=now, token_count=num_tokens, + public_key=public_key, )), ), ) -- GitLab