Newer
Older
# Copyright 2019 PrivateStorage.io, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module implements controllers (in the MVC sense) for the web interface
for the client side of the storage plugin.
"""
from __future__ import (
absolute_import,
)
from sys import (
exc_info,
)
from operator import (
setitem,
delitem,
)
from functools import (
partial,
)
from json import (
dumps,
)
from datetime import (
timedelta,
)
from base64 import (
b64encode,
from hashlib import (
sha256,
)
from zope.interface import (
Interface,
implementer,
)
from twisted.python.reflect import (
namedAny,
)
from twisted.logger import (
Logger,
)
from twisted.python.url import (
URL,
)
from twisted.internet.defer import (
Deferred,
succeed,
inlineCallbacks,
returnValue,
)
from twisted.internet.task import (
LoopingCall,
)
from twisted.web.client import (
Agent,
)
from treq import (
json_content,
from treq.client import (
HTTPClient,
)
from ._base64 import (
urlsafe_b64decode,
)
from ._stack import (
less_limited_stack,
)
from .model import (
RandomToken,
UnblindedToken,
Pass,
Error as model_Error,
RETRY_INTERVAL = timedelta(minutes=3)
class AlreadySpent(Exception):
"""
An attempt was made to redeem a voucher which has already been redeemed.
The redemption cannot succeed and should not be retried automatically.
"""
class Unpaid(Exception):
"""
An attempt was made to redeem a voucher which has not yet been paid for.
The redemption attempt may be automatically retried at some point.
"""
@attr.s
class RedemptionResult(object):
"""
Contain the results of an attempt to redeem a voucher for ZKAP material.
:ivar list[UnblindedToken] unblinded_tokens: The tokens which resulted
from the redemption.
:ivar unicode public_key: The public key which the server proved was
involved in the redemption process.
"""
unblinded_tokens = attr.ib()
public_key = attr.ib()
class IRedeemer(Interface):
"""
An ``IRedeemer`` can exchange a voucher for one or more passes.
"""
def random_tokens_for_voucher(voucher, counter, count):
"""
Generate a number of random tokens to use in the redemption process for
the given voucher.
:param Voucher voucher: The voucher the tokens will be associated
with.
:param int counter: See ``redeemWithCounter``.
:param int count: The number of random tokens to generate.
:return list[RandomToken]: The generated tokens. Random tokens must
be unique over the lifetime of the Tahoe-LAFS node where this
plugin is being used but the same tokens *may* be generated for
the same voucher. The tokens must be kept secret to preserve the
anonymity property of the system.
"""
def redeemWithCounter(voucher, counter, random_tokens):
Redeem a voucher for unblinded tokens which can be used to construct
passes.
Implementations of this method do not need to be fault tolerant. If a
redemption attempt is interrupted before it completes, it is the
caller's responsibility to call this method again with the same
arguments.
:param Voucher voucher: The voucher to redeem.
:param int counter: The counter to use in this redemption attempt. To
support vouchers which can be redeemed for a larger number of
tokens than is practical to handle at once, one voucher can be
partially redeemed repeatedly until the complete set of tokens has
been received. Each partial redemption must have a distinct
counter value.
:param list[RandomToken] random_tokens: The random tokens to use in
the redemption process.
:return: A ``Deferred`` which fires with a ``RedemptionResult``
instance or which fails with any error to allow a retry to be made
at some future point. It may also fail with an ``AlreadySpent``
error to indicate the redemption server considers the voucher to
have been redeemed already and will not allow it to be redeemed.
def tokens_to_passes(message, unblinded_tokens):
"""
Construct passes from unblinded tokens which are suitable for use with a
given message.
:param bytes message: A valid utf-8-encoded byte sequence which serves
to protect the resulting passes from replay usage. It is
preferable if every use of passes is associated with a unique
message.
:param list[UnblindedToken] unblinded_tokens: Unblinded tokens,
previously returned by a call to this implementation's ``redeem``
method.
Loading
Loading full blame...