Ejemplo n.º 1
0
    def __call__(self, auth_id, record_key):
        if self.is_valid_record_key(record_key):
            msg = 'record_key `{}` is not configured to verify'.format(
                record_key)
            raise SkygearException(msg, skyerror.InvalidArgument)

        with conn() as c:
            user = get_user(c, auth_id)
            if not user:
                msg = 'user `{}` not found'.format(auth_id)
                raise SkygearException(msg, skyerror.ResourceNotFound)

        user_record = fetch_user_record(auth_id)
        if not user_record:
            msg = 'user `{}` not found'.format(auth_id)
            raise SkygearException(msg, skyerror.ResourceNotFound)

        value_to_verify = user_record.get(record_key)
        if not value_to_verify:
            msg = 'there is nothing to verify for record_key `{}` ' \
                  'with auth_id `{}`'.format(record_key, auth_id)
            raise SkygearException(msg, skyerror.InvalidArgument)

        code_str = self.get_code(record_key)

        with conn() as c:
            add_verify_code(c, auth_id, record_key, value_to_verify, code_str)

            logger.info('Added new verify code `{}` for user `{}`.'.format(
                code_str, auth_id))
        self.call_provider(record_key, user, user_record, code_str)
Ejemplo n.º 2
0
    def reset_password(user_id, code, expire_at, new_password):
        """
        Lambda function to handle reset password request.
        """
        if not user_id:
            raise SkygearException('user_id must be set',
                                   skyerror.InvalidArgument)
        if not code:
            raise SkygearException('code must be set',
                                   skyerror.InvalidArgument)

        if not expire_at:
            raise SkygearException('expire_at must be set',
                                   skyerror.InvalidArgument)

        with conn() as c:
            user = user_util.get_user_and_validate_code(
                c, user_id, code, expire_at)
            if not user:
                raise SkygearException('user_id is not found or code invalid',
                                       skyerror.ResourceNotFound)

            if not user.email:
                raise SkygearException('email must be set',
                                       skyerror.ResourceNotFound)

            user_util.set_new_password(c, user.id, new_password)
            logger.info('Successfully reset password for user.')

            return {'status': 'OK'}
Ejemplo n.º 3
0
    def __call__(self, auth_id, code_str):
        with conn() as c:
            code = get_verify_code(c, auth_id, code_str)
            if not code or code.consumed:
                msg = 'the code `{}` is not valid ' \
                      'for user `{}`'.format(code_str, auth_id)
                raise SkygearException(msg, skyerror.InvalidArgument)

        user_record = fetch_user_record(auth_id)
        if not user_record:
            msg = 'user `{}` not found'.format(auth_id)
            raise SkygearException(msg, skyerror.ResourceNotFound)

        if user_record.get(code.record_key) != code.record_value:
            msg = 'the user data has since been modified, ' \
                'a new verification is required'
            raise SkygearException(msg, skyerror.InvalidArgument)

        expiry = self.settings.keys[code.record_key].expiry
        if expiry:
            expire_at = code.created_at + datetime.timedelta(seconds=expiry)
            if expire_at < datetime.datetime.now():
                msg = 'the code has expired'
                raise SkygearException(msg, skyerror.InvalidArgument)

        with conn() as c:
            set_code_consumed(c, code.id)

        user_record[verified_flag_name(code.record_key)] = True
        save_user_record(user_record)
Ejemplo n.º 4
0
    def forgot_password(email):
        """
        Lambda function to handle forgot password request.
        """

        if email is None:
            raise SkygearException('email must be set',
                                   skyerror.InvalidArgument)

        with conn() as c:
            user = user_util.get_user_from_email(c, email)
            if not user:
                if not settings.secure_match:
                    return {'status': 'OK'}
                raise SkygearException('user_id must be set',
                                       skyerror.InvalidArgument)
            if not user.email:
                raise SkygearException('email must be set',
                                       skyerror.InvalidArgument)

            user_record = user_util.get_user_record(c, user.id)
            expire_at = round(datetime.utcnow().timestamp()) + \
                settings.reset_url_lifetime
            code = user_util.generate_code(user, expire_at)

            url_prefix = settings.url_prefix
            if url_prefix.endswith('/'):
                url_prefix = url_prefix[:-1]

            link = '{0}/reset-password?code={1}&user_id={2}&expire_at={3}'\
                .format(url_prefix, code, user.id, expire_at)

            template_params = {
                'appname': settings.app_name,
                'link': link,
                'url_prefix': url_prefix,
                'email': user.email,
                'user_id': user.id,
                'code': code,
                'user': user,
                'user_record': user_record,
                'expire_at': expire_at,
            }

            try:
                mail_sender.send(
                    (settings.sender_name, settings.sender),
                    user.email,
                    settings.subject,
                    reply_to=(settings.reply_to_name, settings.reply_to),
                    template_params=template_params)
            except Exception as ex:
                logger.exception('An error occurred sending reset password'
                                 ' email to user.')
                raise SkygearException(str(ex), skyerror.UnexpectedError)

            return {'status': 'OK'}
Ejemplo n.º 5
0
    def test_forgot_password_email(email,
                                   text_template=None,
                                   html_template=None,
                                   subject=None,
                                   sender=None,
                                   reply_to=None,
                                   sender_name=None,
                                   reply_to_name=None):
        access_key_type = current_context().get('access_key_type')
        if not access_key_type or access_key_type != 'master':
            raise SkygearException('master key is required',
                                   skyerror.AccessKeyNotAccepted)

        url_prefix = settings.url_prefix
        if url_prefix.endswith('/'):
            url_prefix = url_prefix[:-1]

        dummy_user = namedtuple('User',
                                ['id', 'email'])('dummy-id',
                                                 '*****@*****.**')

        dummy_record_id = RecordID('user', 'dummy-id')
        dummy_record = Record(dummy_record_id, dummy_record_id.key, None)

        template_params = {
            'appname': settings.app_name,
            'code': 'dummy-reset-code',
            'url_prefix': url_prefix,
            'link': '{}/example-reset-password-link'.format(url_prefix),
            'user_record': dummy_record,
            'user': dummy_user,
            'email': dummy_user.email,
            'user_id': dummy_user.id
        }

        email_sender = (sender_name, sender) if sender \
            else (settings.sender_name, settings.sender)
        email_subject = subject if subject else settings.subject
        email_reply_to = (reply_to_name, reply_to) if reply_to \
            else (settings.reply_to_name, settings.reply_to)

        try:
            mail_sender.send(email_sender,
                             email,
                             email_subject,
                             reply_to=email_reply_to,
                             text_template_string=text_template,
                             html_template_string=html_template,
                             template_params=template_params)
        except Exception as ex:
            logger.exception('An error occurred sending test reset password'
                             ' email to user.')
            raise SkygearException(str(ex), skyerror.UnexpectedError)

        return {'status': 'OK'}
Ejemplo n.º 6
0
 def _send_multi(self, action, **payload):
     result = self.container.send_action(action, payload)
     if 'error' in result:
         raise SkygearException.from_dict(result['error'])
     elif 'result' in result and isinstance(result['result'], list):
         return result
     else:
         raise SkygearException('unexpected result', UnexpectedError)
Ejemplo n.º 7
0
 def get_payload(self):
     data = self.request.get_data(as_text=True)
     if data == '':
         return {}
     try:
         payload = json.loads(data)
         return payload
     except ValueError:
         raise SkygearException('unable to decode json', BadRequest)
Ejemplo n.º 8
0
 def verify_code_lambda(code):
     """
     This lambda checks the user submitted code.
     """
     if not current_user_id():
         raise SkygearException("You must log in to perform this action.",
                                code=NotAuthenticated)
     thelambda = VerifyCodeLambda(settings)
     return thelambda(current_user_id(), code)
Ejemplo n.º 9
0
 def verify_request_lambda(record_key):
     """
     This lambda allows client to request verification
     (i.e. send email or send SMS).
     """
     if not current_user_id():
         raise SkygearException("You must log in to perform this action.",
                                code=NotAuthenticated)
     thelambda = VerifyRequestLambda(settings, providers)
     return thelambda(current_user_id(), record_key)
Ejemplo n.º 10
0
 def _send_single(self, action, **payload):
     result = self.container.send_action(action, payload)
     if 'error' in result:
         raise SkygearException.from_dict(result['error'])
     elif 'result' in result and isinstance(result['result'], list) \
             and len(result['result']) > 0:
         first_result = result['result'][0]
         if first_result.get('_type', None) == 'error':
             raise SkygearException.from_dict(first_result)
         return first_result
     else:
         raise SkygearException('unexpected result', UnexpectedError)
Ejemplo n.º 11
0
    def __call__(self, record_key, record_value):
        if not record_value:
            msg = 'missing record_value'
            raise SkygearException(msg, skyerror.InvalidArgument)

        code_str = self.get_code(record_key)
        user = namedtuple('User', ['id', record_key])('dummy-id', record_key)

        user_record = Record('user/dummy-id',
                             'dummy-id', {},
                             data={record_key: record_value})
        self.call_provider(record_key, user, user_record, code_str)
Ejemplo n.º 12
0
    def handle_request(self, base_name, request):
        self.request = request
        ident = get_ident(base_name, request)

        for r in self._routes():
            if r['ident'] != bool(ident):
                continue
            if r['method'] != request.method:
                continue
            if not has_func(self, r['func']):
                continue

            if ident:
                return getattr(self, r['func'])(ident)
            else:
                return getattr(self, r['func'])()
        else:
            raise SkygearException('invalid request method', BadRequest)
Ejemplo n.º 13
0
    def test_verify_request_lambda(record_key,
                                   record_value,
                                   provider_settings={},
                                   templates={}):
        """
        Allow passing extra provider_settings from api for
        provider configuration testing. e.g. sms api key is provided by user

        Example:
        curl 'http://127.0.0.1:3000/' --data-binary '{
            "action": "user:verify_request:test",
            "api_key": "master_key",
            "args": {
                "record_key": "email",
                "record_value": "*****@*****.**",
                "provider_settings": {
                    "name": "smtp"
                },
                "templates": {
                    "text_template": "testing",
                    "html_template": "testing html"
                }
            }
        }'

        curl 'http://127.0.0.1:3000/' --data-binary '{
            "action": "user:verify_request:test",
            "api_key": "master_key",
            "args": {
                "record_key": "phone",
                "record_value": "+15005550009",
                "provider_settings": {
                    "name": "twilio",
                    "twilio_from": "+15005550009",
                    "twilio_account_sid": "",
                    "twilio_auth_token": ""
                },
                "templates": {
                    "template": "testing sms"
                }
            }
        }'
        """
        access_key_type = current_context().get('access_key_type')
        if not access_key_type or access_key_type != 'master':
            raise SkygearException('master key is required',
                                   skyerror.AccessKeyNotAccepted)

        provider_name = provider_settings.get('name')
        if not provider_name:
            raise SkygearException('Missing provider',
                                   skyerror.InvalidArgument)

        merged_settings = {
            **vars(test_provider_settings[provider_name]),
            **provider_settings
        }

        string_templates = {
            k: StringTemplate('verify_{}_{}'.format(record_key, k), v)
            for k, v in templates.items()
        }

        _providers = {}
        _providers[record_key] = get_provider(
            argparse.Namespace(**merged_settings), record_key,
            **string_templates)

        thelambda = VerifyRequestTestLambda(settings, _providers)
        return thelambda(record_key, record_value)