From e4b26753aa80bd26b288d70e7734b056144f2d6e Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Mon, 7 Feb 2022 14:52:47 -0500 Subject: [PATCH] bump the API version to 2; also remove some duplication in its definition --- docs/source/configuration.rst | 28 +++++++++---------- docs/source/interface.rst | 12 ++++---- src/_zkapauthorizer/_plugin.py | 2 +- src/_zkapauthorizer/api.py | 4 +++ src/_zkapauthorizer/config.py | 3 +- src/_zkapauthorizer/model.py | 6 ++++ src/_zkapauthorizer/resource.py | 8 +++--- src/_zkapauthorizer/storage_common.py | 5 ++-- src/_zkapauthorizer/tests/strategies.py | 9 +++--- .../tests/test_client_resource.py | 17 +++++------ src/_zkapauthorizer/tests/test_plugin.py | 19 +++++++------ .../tests/test_storage_client.py | 24 ++++++++-------- src/twisted/plugins/zkapauthorizer.py | 4 +-- 13 files changed, 79 insertions(+), 62 deletions(-) diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst index 2828d4a..6b01d21 100644 --- a/docs/source/configuration.rst +++ b/docs/source/configuration.rst @@ -8,9 +8,9 @@ To enable the plugin at all, add its name to the list of storage plugins in the (``tahoe.cfg`` in the relevant node directory):: [client] - storage.plugins = privatestorageio-zkapauthz-v1 + storage.plugins = privatestorageio-zkapauthz-v2 -Then configure the plugin as desired in the ``storageclient.plugins.privatestorageio-zkapauthz-v1`` section. +Then configure the plugin as desired in the ``storageclient.plugins.privatestorageio-zkapauthz-v2`` section. redeemer ~~~~~~~~ @@ -20,7 +20,7 @@ The ``dummy`` value is useful for testing purposes only. For example:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] redeemer = dummy issuer-public-key = YXNkYXNkYXNkYXNkYXNkCg== @@ -31,7 +31,7 @@ In this case, the ``ristretto-issuer-root-url`` item is also required. For example:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] redeemer = ristretto ristretto-issuer-root-url = https://issuer.example.invalid/ @@ -40,14 +40,14 @@ If the values are not the same, the client will decline to use the storage serve The client can also be configured with the value of a single pass:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] pass-value = 1048576 The value given here must agree with the value servers use in their configuration or the storage service will be unusable. The client can also be configured with the number of passes to expect in exchange for one voucher:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] default-token-count = 32768 The value given here must agree with the value the issuer uses in its configuration or redemption may fail. @@ -58,7 +58,7 @@ allowed-public-keys Regardless of which redeemer is selected, the client must also be configured with the public part of the issuer key pair which it will allow to sign tokens:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] allowed-public-keys = AAAA...,BBBB...,CCCC... The ``allowed-public-keys`` value is a comma-separated list of encoded public keys. @@ -76,7 +76,7 @@ The client will try to make the average (mean) interval between runs equal to th The value is an integer number of seconds. For example to run on average every 26 days:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] lease.crawl-interval.mean = 2246400 @@ -88,7 +88,7 @@ The random intervals between runs have a uniform distribution with this item's v The value is an integer number of seconds. For example to make all intervals fall within a 7 day period:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] lease.crawl-interval.range = 302400 @@ -101,7 +101,7 @@ If the crawler encounters a lease with less time left than this then it will ren The value is an integer number of seconds. For example to renew leases on all shares which will expire in less than one week:: - [storageclient.plugins.privatestorageio-zkapauthz-v1] + [storageclient.plugins.privatestorageio-zkapauthz-v2] lease.min-time-remaining = 604800 Server @@ -111,16 +111,16 @@ To enable the plugin at all, add its name to the list of storage plugins in the (``tahoe.cfg`` in the relevant node directory):: [storage] - plugins = privatestorageio-zkapauthz-v1 + plugins = privatestorageio-zkapauthz-v2 Then also configure the Ristretto-flavored PrivacyPass issuer the server will announce to clients:: - [storageserver.plugins.privatestorageio-zkapauthz-v1] + [storageserver.plugins.privatestorageio-zkapauthz-v2] ristretto-issuer-root-url = https://issuer.example.invalid/ The value of a single pass in the system can be configured here as well:: - [storageserver.plugins.privatestorageio-zkapauthz-v1] + [storageserver.plugins.privatestorageio-zkapauthz-v2] pass-value = 1048576 If no ``pass-value`` is given then a default will be used. @@ -130,7 +130,7 @@ The storage server must also be configured with the path to the Ristretto-flavor To avoid placing secret material in tahoe.cfg, this configuration is done using a path:: - [storageserver.plugins.privatestorageio-zkapauthz-v1] + [storageserver.plugins.privatestorageio-zkapauthz-v2] ristretto-signing-key-path = /path/to/signing.key The signing key is the keystone secret to the entire system and must be managed with extreme care to prevent unintended disclosure. diff --git a/docs/source/interface.rst b/docs/source/interface.rst index e771e67..27fe303 100644 --- a/docs/source/interface.rst +++ b/docs/source/interface.rst @@ -19,7 +19,7 @@ For example, if the secret token is ``ABCDEF``:: The correct value for the token can be read from the Tahoe-LAFS node's ``private/api_auth_token`` file. -``GET /storage-plugins/privatestorageio-zkapauthz-v1/version`` +``GET /storage-plugins/privatestorageio-zkapauthz-v2/version`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This endpoint returns the version of the ZKAPAuthorizer Python package in use by the Tahoe-LAFS client node. @@ -29,7 +29,7 @@ The response is **OK** with an ``application/json`` **Content-Type**:: { "version": <string> } -``PUT /storage-plugins/privatestorageio-zkapauthz-v1/voucher`` +``PUT /storage-plugins/privatestorageio-zkapauthz-v2/voucher`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This endpoint allows an external agent which has submitted a payment to cause the plugin to redeem the voucher for tokens. @@ -44,7 +44,7 @@ If the voucher cannot be accepted at the time of the request then the response c If the response is **OK** then a repeated request with the same body will have no effect. If the response is not **OK** then a repeated request with the same body will try to accept the number again. -``GET /storage-plugins/privatestorageio-zkapauthz-v1/voucher/<voucher>`` +``GET /storage-plugins/privatestorageio-zkapauthz-v2/voucher/<voucher>`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This endpoint allows an external agent to monitor the status of the redemption of a voucher. @@ -125,7 +125,7 @@ The *finished* timestamp gives the time when the unpaid error was encountered. The *finished* timestamp gives the time when this other error condition was encountered. The *details* string may give additional details about what the error was. -``GET /storage-plugins/privatestorageio-zkapauthz-v1/voucher`` +``GET /storage-plugins/privatestorageio-zkapauthz-v2/voucher`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This endpoint allows an external agent to retrieve the status of all vouchers. @@ -137,7 +137,7 @@ The response is **OK** with ``application/json`` content-type response body like The elements of the list are objects like the one returned by issuing a **GET** to a child of this collection resource. -``GET /storage-plugins/privatestorageio-zkapauthz-v1/lease-maintenance`` +``GET /storage-plugins/privatestorageio-zkapauthz-v2/lease-maintenance`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This endpoint allows an external agent to retrieve information about automatic spending for lease maintenance. @@ -159,7 +159,7 @@ If it has run, * ``when``: associated with an ISO8601 datetime string giving the approximate time the process ran * ``count``: associated with a number giving the number of passes which would need to be spent to renew leases on all stored objects seen during the lease maintenance activity -``POST /storage-plugins/privatestorageio-zkapauthz-v1/calculate-price`` +``POST /storage-plugins/privatestorageio-zkapauthz-v2/calculate-price`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This endpoint allows an agent to calculate the number of ZKAPs it will cost to store a collection of files of specified sizes. diff --git a/src/_zkapauthorizer/_plugin.py b/src/_zkapauthorizer/_plugin.py index 7d25ffa..bc94b2e 100644 --- a/src/_zkapauthorizer/_plugin.py +++ b/src/_zkapauthorizer/_plugin.py @@ -80,7 +80,7 @@ class ZKAPAuthorizer(object): connection. """ - name = attr.ib(default="privatestorageio-zkapauthz-v1") + name = attr.ib() _stores = attr.ib(default=attr.Factory(WeakValueDictionary)) def _get_store(self, node_config): diff --git a/src/_zkapauthorizer/api.py b/src/_zkapauthorizer/api.py index f4bb2c2..4076c7c 100644 --- a/src/_zkapauthorizer/api.py +++ b/src/_zkapauthorizer/api.py @@ -20,6 +20,10 @@ __all__ = [ "ZKAPAuthorizer", ] +# The identifier for this plugin. This appears in URLs for resources the +# client plugin exposes, configuration files, etc. +NAME = "privatestorageio-zkapauthz-v2" + from ._storage_client import ZKAPAuthorizerStorageClient from ._storage_server import LeaseRenewalRequired, ZKAPAuthorizerStorageServer from .storage_common import MorePassesRequired diff --git a/src/_zkapauthorizer/config.py b/src/_zkapauthorizer/config.py index cb9dc38..f92cde0 100644 --- a/src/_zkapauthorizer/config.py +++ b/src/_zkapauthorizer/config.py @@ -21,6 +21,7 @@ from typing import Optional from allmydata.node import _Config +from .api import NAME from .lease_maintenance import LeaseMaintenanceConfig @@ -124,7 +125,7 @@ def _read_duration(cfg, option, default): as a ``timedelta``. """ # type: (_Config, str) -> Optional[timedelta] - section_name = "storageclient.plugins.privatestorageio-zkapauthz-v1" + section_name = "storageclient.plugins." + NAME value_str = cfg.get_config( section=section_name, option=option, diff --git a/src/_zkapauthorizer/model.py b/src/_zkapauthorizer/model.py index 2990348..d3526ab 100644 --- a/src/_zkapauthorizer/model.py +++ b/src/_zkapauthorizer/model.py @@ -75,6 +75,12 @@ class NotEnoughTokens(Exception): """ +# The version number in _zkapauthorizer.api.NAME doesn't match the version +# here because the database is persistent state and we need to be sure to load +# the older version even if we signal an API compatibility break by bumping +# the version number elsewhere. Consider this version number part of a +# different scheme where we're versioning our ability to open the database at +# all. The schema inside the database is versioned by yet another mechanism. CONFIG_DB_NAME = "privatestorageio-zkapauthz-v1.sqlite3" diff --git a/src/_zkapauthorizer/resource.py b/src/_zkapauthorizer/resource.py index 93b34d0..a06c862 100644 --- a/src/_zkapauthorizer/resource.py +++ b/src/_zkapauthorizer/resource.py @@ -32,6 +32,7 @@ from zope.interface import Attribute from . import __version__ as _zkapauthorizer_version from ._base64 import urlsafe_b64decode from ._json import dumps_utf8 +from .api import NAME from .config import get_configured_lease_duration from .controller import PaymentController, get_redeemer from .pricecalculator import PriceCalculator @@ -89,7 +90,7 @@ def from_configuration( ): """ Instantiate the plugin root resource using data from its configuration - section, **storageclient.plugins.privatestorageio-zkapauthz-v1**, in the + section, **storageclient.plugins.privatestorageio-zkapauthz-v2**, in the Tahoe-LAFS configuration file. See the configuration documentation for details of the configuration section. @@ -108,16 +109,15 @@ def from_configuration( :return IZKAPRoot: The root of the resource hierarchy presented by the client side of the plugin. """ - plugin_name = "privatestorageio-zkapauthz-v1" if redeemer is None: redeemer = get_redeemer( - plugin_name, + NAME, node_config, None, None, ) default_token_count = get_token_count( - plugin_name, + NAME, node_config, ) controller = PaymentController( diff --git a/src/_zkapauthorizer/storage_common.py b/src/_zkapauthorizer/storage_common.py index db04c1f..c8e8786 100644 --- a/src/_zkapauthorizer/storage_common.py +++ b/src/_zkapauthorizer/storage_common.py @@ -22,6 +22,7 @@ from typing import Callable import attr from pyutil.mathutil import div_ceil +from .api import NAME from .eliot import MUTABLE_PASSES_REQUIRED from .validators import greater_than @@ -110,7 +111,7 @@ def get_configured_pass_value(node_config): value is read from the **pass-value** option of the ZKAPAuthorizer plugin client section. """ - section_name = "storageclient.plugins.privatestorageio-zkapauthz-v1" + section_name = "storageclient.plugins." + NAME return int( node_config.get_config( section=section_name, @@ -124,7 +125,7 @@ def get_configured_allowed_public_keys(node_config): """ Read the set of allowed issuer public keys from the given configuration. """ - section_name = "storageclient.plugins.privatestorageio-zkapauthz-v1" + section_name = "storageclient.plugins." + NAME return set( node_config.get_config( section=section_name, diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py index d468030..45d2780 100644 --- a/src/_zkapauthorizer/tests/strategies.py +++ b/src/_zkapauthorizer/tests/strategies.py @@ -46,6 +46,7 @@ from twisted.internet.task import Clock from twisted.web.test.requesthelper import DummyRequest from zope.interface import implementer +from ..api import NAME from ..configutil import config_string_from_sections from ..lease_maintenance import LeaseMaintenanceConfig, lease_maintenance_config_to_dict from ..model import ( @@ -478,7 +479,7 @@ def client_lease_maintenance_configurations(maint_configs=None): def direct_tahoe_configs( - zkapauthz_v1_configuration=client_dummyredeemer_configurations(), + zkapauthz_v2_configuration=client_dummyredeemer_configurations(), shares=just((None, None, None)), ): """ @@ -492,7 +493,7 @@ def direct_tahoe_configs( """ config_texts = minimal_tahoe_configs( { - "privatestorageio-zkapauthz-v1": zkapauthz_v1_configuration, + NAME: zkapauthz_v2_configuration, }, shares, ) @@ -506,7 +507,7 @@ def direct_tahoe_configs( def tahoe_configs( - zkapauthz_v1_configuration=client_dummyredeemer_configurations(), + zkapauthz_v2_configuration=client_dummyredeemer_configurations(), shares=just((None, None, None)), ): """ @@ -531,7 +532,7 @@ def tahoe_configs( return set_paths - return direct_tahoe_configs(zkapauthz_v1_configuration, shares,).map( + return direct_tahoe_configs(zkapauthz_v2_configuration, shares,).map( path_setter, ) diff --git a/src/_zkapauthorizer/tests/test_client_resource.py b/src/_zkapauthorizer/tests/test_client_resource.py index 96c25c8..0d1daff 100644 --- a/src/_zkapauthorizer/tests/test_client_resource.py +++ b/src/_zkapauthorizer/tests/test_client_resource.py @@ -73,6 +73,7 @@ from twisted.web.resource import IResource, getChildForRequest from .. import __version__ as zkapauthorizer_version from .._base64 import urlsafe_b64decode from .._json import dumps_utf8 +from ..api import NAME from ..configutil import config_string_from_sections from ..model import ( DoubleSpend, @@ -714,7 +715,7 @@ class VoucherTests(TestCase): those relevant to a voucher which is actively being redeemed, about the voucher are included in a json-encoded response body. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_get_known_voucher( config, api_auth_token, @@ -746,7 +747,7 @@ class VoucherTests(TestCase): those relevant to a voucher which has been redeemed, about the voucher are included in a json-encoded response body. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_get_known_voucher( config, api_auth_token, @@ -779,7 +780,7 @@ class VoucherTests(TestCase): already redeemed, about the voucher are included in a json-encoded response body. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_get_known_voucher( config, api_auth_token, @@ -811,7 +812,7 @@ class VoucherTests(TestCase): not been paid for yet, about the voucher are included in a json-encoded response body. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_get_known_voucher( config, api_auth_token, @@ -843,7 +844,7 @@ class VoucherTests(TestCase): kind of transient conditions, about the voucher are included in a json-encoded response body. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_get_known_voucher( config, api_auth_token, @@ -933,7 +934,7 @@ class VoucherTests(TestCase): A ``GET`` to the ``VoucherCollection`` itself returns a list of existing vouchers. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_list_vouchers( config, api_auth_token, @@ -970,7 +971,7 @@ class VoucherTests(TestCase): A ``GET`` to the ``VoucherCollection`` itself returns a list of existing vouchers including state information that reflects transient states. """ - count = get_token_count("privatestorageio-zkapauthz-v1", config) + count = get_token_count(NAME, config) return self._test_list_vouchers( config, api_auth_token, @@ -1248,7 +1249,7 @@ class CalculatePriceTests(TestCase): lambda share_and_lease_time: tuples( just(share_and_lease_time), direct_tahoe_configs( - zkapauthz_v1_configuration=client_dummyredeemer_configurations( + zkapauthz_v2_configuration=client_dummyredeemer_configurations( min_times_remaining=just(share_and_lease_time[1]), ), shares=just(share_and_lease_time[0]), diff --git a/src/_zkapauthorizer/tests/test_plugin.py b/src/_zkapauthorizer/tests/test_plugin.py index d2badcc..f626297 100644 --- a/src/_zkapauthorizer/tests/test_plugin.py +++ b/src/_zkapauthorizer/tests/test_plugin.py @@ -69,6 +69,7 @@ from twisted.plugins.zkapauthorizer import storage_server from .._plugin import get_root_nodes, load_signing_key from .._storage_client import IncorrectStorageServerReference +from ..api import NAME from ..controller import DummyRedeemer, IssuerConfigurationMismatch, PaymentController from ..foolscap import RIPrivacyPassAuthorizedStorageServer from ..lease_maintenance import SERVICE_NAME, LeaseMaintenanceConfig @@ -339,7 +340,7 @@ tahoe_configs_with_dummy_redeemer = tahoe_configs(client_dummyredeemer_configura tahoe_configs_with_mismatched_issuer = minimal_tahoe_configs( { - "privatestorageio-zkapauthz-v1": just( + NAME: just( {"ristretto-issuer-root-url": "https://another-issuer.example.invalid/"} ), } @@ -561,26 +562,26 @@ class ClientResourceTests(TestCase): ) -SERVERS_YAML = b""" +SERVERS_YAML = """ storage: v0-aaaaaaaa: ann: anonymous-storage-FURL: pb://@tcp:/ nickname: 10.0.0.2 storage-options: - - name: privatestorageio-zkapauthz-v1 + - name: {name} ristretto-issuer-root-url: https://payments.example.com/ storage-server-FURL: pb://bbbbbbbb@tcp:10.0.0.2:1234/cccccccc -""" +""".format(name=NAME).encode("ascii") -TWO_SERVERS_YAML = b""" +TWO_SERVERS_YAML = """ storage: v0-aaaaaaaa: ann: anonymous-storage-FURL: pb://@tcp:/ nickname: 10.0.0.2 storage-options: - - name: privatestorageio-zkapauthz-v1 + - name: {name} ristretto-issuer-root-url: https://payments.example.com/ storage-server-FURL: pb://bbbbbbbb@tcp:10.0.0.2:1234/cccccccc v0-dddddddd: @@ -588,10 +589,10 @@ storage: anonymous-storage-FURL: pb://@tcp:/ nickname: 10.0.0.3 storage-options: - - name: privatestorageio-zkapauthz-v1 + - name: {name} ristretto-issuer-root-url: https://payments.example.com/ storage-server-FURL: pb://eeeeeeee@tcp:10.0.0.3:1234/ffffffff -""" +""".format(name=NAME).encode("ascii") class LeaseMaintenanceServiceTests(TestCase): @@ -708,7 +709,7 @@ class LeaseMaintenanceServiceTests(TestCase): # Then build a function that will get us a Tahoe configuration # that includes at least that lease maintenance configuration. lambda lease_maint_config: tahoe_configs( - zkapauthz_v1_configuration=client_lease_maintenance_configurations( + zkapauthz_v2_configuration=client_lease_maintenance_configurations( just(lease_maint_config), ), ).map( diff --git a/src/_zkapauthorizer/tests/test_storage_client.py b/src/_zkapauthorizer/tests/test_storage_client.py index 9f26eb6..947386b 100644 --- a/src/_zkapauthorizer/tests/test_storage_client.py +++ b/src/_zkapauthorizer/tests/test_storage_client.py @@ -38,7 +38,7 @@ from twisted.internet.defer import fail, succeed from .._storage_client import call_with_passes from .._storage_server import _ValidationResult -from ..api import MorePassesRequired +from ..api import NAME, MorePassesRequired from ..model import NotEnoughTokens from ..storage_common import ( get_configured_allowed_public_keys, @@ -108,7 +108,7 @@ shares.total = {} def test_get_configured_pass_value(self, expected): """ ``get_configured_pass_value`` reads the ``pass-value`` value from the - ``storageclient.plugins.privatestorageio-zkapauthz-v1`` section as an + ``storageclient.plugins.privatestorageio-zkapauthz-v2`` section as an integer. """ config = config_from_string( @@ -120,11 +120,12 @@ shares.needed = 3 shares.happy = 5 shares.total = 10 -[storageclient.plugins.privatestorageio-zkapauthz-v1] -pass-value={} +[storageclient.plugins.{name}] +pass-value={pass_value} """.format( - expected - ), + name=NAME, + pass_value=expected +), ) self.assertThat( @@ -136,7 +137,7 @@ pass-value={} def test_get_configured_allowed_public_keys(self, expected): """ ``get_configured_pass_value`` reads the ``pass-value`` value from the - ``storageclient.plugins.privatestorageio-zkapauthz-v1`` section as an + ``storageclient.plugins.privatestorageio-zkapauthz-v2`` section as an integer. """ config = config_from_string( @@ -148,11 +149,12 @@ shares.needed = 3 shares.happy = 5 shares.total = 10 -[storageclient.plugins.privatestorageio-zkapauthz-v1] -allowed-public-keys = {} +[storageclient.plugins.{name}] +allowed-public-keys = {allowed_public_keys} """.format( - ",".join(expected) - ), + name=NAME, + allowed_public_keys=",".join(expected), +), ) self.assertThat( diff --git a/src/twisted/plugins/zkapauthorizer.py b/src/twisted/plugins/zkapauthorizer.py index 85448fe..ed11612 100644 --- a/src/twisted/plugins/zkapauthorizer.py +++ b/src/twisted/plugins/zkapauthorizer.py @@ -16,6 +16,6 @@ A drop-in to supply plugins to the Twisted plugin system. """ -from _zkapauthorizer.api import ZKAPAuthorizer +from _zkapauthorizer.api import NAME, ZKAPAuthorizer -storage_server = ZKAPAuthorizer() +storage_server = ZKAPAuthorizer(name=NAME) -- GitLab