Beispiel #1
0
import itsdangerous
import settings

jwt = itsdangerous.JSONWebSignatureSerializer(settings.SECRET)


def is_valid_hook_key(key):
    return settings.HOOK_KEY and key == settings.HOOK_KEY


def decode_apikey(key):
    return jwt.loads(key, salt='apikey')


def make_apikey(user_id):
    return jwt.dumps({'user_id': user_id}, salt='apikey').decode()
Beispiel #2
0
    def post(self, request, msisdn):
        network = get_network_from_user(request.user)
        number = models.Number.objects.get(number=msisdn)
        if (number.network and number.network != network
                and not request.user.is_staff):
            return Response("User is not associated with that Number %s %s." %
                            (number.network.pk, network.pk),
                            status=status.HTTP_403_FORBIDDEN)
        # Must post a valid 'state'.
        valid_states = ('available', 'released')
        if request.POST.get('state', None) not in valid_states:
            return Response("Must post a valid state.",
                            status=status.HTTP_400_BAD_REQUEST)
        # This is a valid request, begin processing.  First check if this is a
        # number-deactivation request.
        if (number.state == 'inuse'
                and request.POST.get('state') == 'available'):
            # Refuse to deactivate a subscriber's last number.
            if (len(models.Number.objects.filter(subscriber=number.subscriber))
                    <= 1):
                message = ("Cannot deactivate a subscriber's last number."
                           "  Instead, delete the subscriber.")
                return Response(message, status=status.HTTP_400_BAD_REQUEST)
            # If it's not the subscriber's only number, send an async post to
            # the BTS to deactivate the number.  Sign the request using JWT.
            bts = number.subscriber.bts
            url = '%s/config/deactivate_number' % bts.inbound_url
            data = {
                'number': msisdn,
                # Add a UUID as a nonce for the message.
                'msgid': str(uuid.uuid4()),
            }
            serializer = itsdangerous.JSONWebSignatureSerializer(bts.secret)
            signed_data = {
                'jwt': serializer.dumps(data),
            }
            tasks.async_post.delay(url, signed_data)
            # Create a 'deactivate_number' UsageEvent.
            now = datetime.datetime.now(pytz.utc)
            reason = 'deactivated phone number: %s' % number.number
            event = models.UsageEvent.objects.create(
                subscriber=number.subscriber,
                date=now,
                bts=bts,
                kind='deactivate_number',
                to_number=number.number,
                reason=reason,
                oldamt=number.subscriber.balance,
                newamt=number.subscriber.balance,
                change=0)
            event.save()
            # Diassociate the Number from its former Subscriber and Network.
            number.subscriber = None
            number.network = None
            number.state = request.POST.get('state')
            number.save()
            return Response("")

        # Check if this is a number-release request.
        if request.POST.get('state') == 'released':
            # User must be staff to do this.
            if not request.user.is_staff:
                return Response("", status=status.HTTP_404_NOT_FOUND)
            # The number must not be 'inuse.'
            if number.state == 'inuse':
                return Response("", status=status.HTTP_400_BAD_REQUEST)
            # The number cannot be associated with a Sub.
            if number.subscriber:
                return Response("", status=status.HTTP_400_BAD_REQUEST)
            # Validation passes, release (cancel) the number.
            nexmo_provider = NexmoProvider(
                settings.ENDAGA['NEXMO_ACCT_SID'],
                settings.ENDAGA['NEXMO_AUTH_TOKEN'],
                settings.ENDAGA['NEXMO_INBOUND_SMS_URL'],
                None,
                settings.ENDAGA['NEXMO_INBOUND_VOICE_HOST'],
                country=number.country_id)
            if nexmo_provider.cancel_number(number.number):
                # Success, delete the number.
                number.delete()
                return Response("", status=status.HTTP_200_OK)
            else:
                print 'deleting number %s failed' % number.number
                return Response("",
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # Invalid request.
        return Response("", status=status.HTTP_400_BAD_REQUEST)
Beispiel #3
0
 def test_token_is_invalid_if_expiry_time_is_missing(self):
     bad_s = idmod.JSONWebSignatureSerializer("secret")
     invalid_token_empty = bad_s.dumps({})
     s = self.serializer_class("secret")
     self.assertRaises(idmod.BadSignature, s.loads, invalid_token_empty)
Beispiel #4
0
    def __init__(self,
                 app,
                 app_url,
                 client_id=None,
                 secret_key=None,
                 salt=None,
                 authorization_hook=None):
        Auth.__init__(self, app, authorization_hook)

        self.config = {
            'permissions_cache_expiry': 5 * 60,
            'user_cookies_expiry': 604800,  # one week.
        }

        self._app = app
        self._app_url = app_url
        self._oauth_client_id = client_id
        self._username_cache = {}

        if secret_key is None and app.server.secret_key is None:
            raise Exception(
                dedent('''
                app.server.secret_key is missing.
                Generate a secret key in your Python session
                with the following commands:

                >>> import os
                >>> import base64
                >>> base64.b64encode(os.urandom(30)).decode('utf-8')

                and assign it to the property app.server.secret_key
                (where app is your dash app instance).
                Note that you should not do this dynamically:
                you should create a key and then assign the value of
                that key in your code.
            '''))

        if salt is None:
            raise Exception(
                dedent('''
                salt is missing. The salt parameter needs to a string that
                is unique to this individual Dash app.
            '''))

        self._signer = itsdangerous.TimestampSigner(secret_key, salt=salt)
        self._json_signer = itsdangerous.JSONWebSignatureSerializer(secret_key,
                                                                    salt=salt)

        app.server.add_url_rule('{}_dash-login'.format(
            app.config['routes_pathname_prefix']),
                                view_func=self.login_api,
                                methods=['post'])

        app.server.add_url_rule('{}_oauth-redirect'.format(
            app.config['routes_pathname_prefix']),
                                view_func=self.serve_oauth_redirect,
                                methods=['get'])

        app.server.add_url_rule('{}_is-authorized'.format(
            app.config['routes_pathname_prefix']),
                                view_func=self.check_if_authorized,
                                methods=['get'])
        _current_path = os.path.dirname(os.path.abspath(__file__))

        # TODO - Dist files
        with open(os.path.join(_current_path, 'oauth-redirect.js'), 'r') as f:
            self.oauth_redirect_bundle = f.read()

        with open(os.path.join(_current_path, 'login.js'), 'r') as f:
            self.login_bundle = f.read()