def merge_profiles(cls, app_id, src_user_pk=None, src_alias=None, dst_user_pk=None, dst_alias=None): src_profiles = cls.find_by_pk(app_id=app_id, user_pk=src_user_pk) \ if src_user_pk else cls.query.filter_by(alias=src_alias).all() if not src_profiles: raise NotFoundError('Source User ID or Social ID not found') dst_profiles = cls.find_by_pk(app_id=app_id, user_pk=dst_user_pk) \ if dst_user_pk else cls.query.filter_by(alias=dst_alias).all() if not dst_profiles: raise NotFoundError('Destination User ID or Social ID not found') associated_providers = [] for p in dst_profiles: associated_providers.append(p.provider) for p in src_profiles: if p.provider in associated_providers: raise ConflictError( msg='Unacceptable operation. ' 'Source profile has associated with a provider same in destination profile', data={ 'conflict_provider': p.provider, 'associated_providers': ', '.join(associated_providers) }) dst_profile = dst_profiles[0] for p in src_profiles: p._merge_unsafe(dst_profile)
def link_with_user(cls, app_id, alias, user_pk, create_if_not_exist=True): profiles = cls.query.filter_by(alias=alias).all() if not profiles: raise NotFoundError('Social ID not found') if profiles[0].user_id: raise ConflictError( 'Unacceptable operation. ' 'Social profile has linked with an exists user') num_user_same_pk = (db.session.query(func.count( SocialProfiles._id)).join( Users, and_(Users._id == SocialProfiles.user_id, Users.pk == user_pk, Users.app_id == app_id)).scalar()) if num_user_same_pk > 0: raise ConflictError('User has linked with another social profile') user = Users.query.filter_by(pk=user_pk, app_id=app_id).one_or_none() if not user: if not create_if_not_exist: raise NotFoundError('User not found') user = Users(pk=user_pk, app_id=app_id) db.session.add(user) db.session.flush() for p in profiles: p._link_unsafe(user._id)
def get_associate_token(app_id: str, body: Dict[str, Any]): provider = body.get('provider') if not is_valid_provider(provider): raise BadRequestError('Invalid provider') user_pk, alias = _parse_and_validate_identifiers(body) profiles = SocialProfiles.find_by_pk(app_id=app_id, user_pk=user_pk)\ if user_pk else SocialProfiles.query.filter_by(alias=alias).all() if not profiles: raise NotFoundError('User ID or Social ID not found') for p in profiles: if provider == p.provider: raise ConflictError( 'User has linked with another social profile for this provider' ) log = AssociateLogs(provider=provider, app_id=app_id, social_id=profiles[0].alias, nonce=gen_random_token(nbytes=16, format='hex')) db.session.add(log) db.session.flush() associate_token = log.generate_associate_token() db.session.commit() return {'token': associate_token, 'target_provider': provider}
def unlink_from_user(cls, app_id, alias, user_pk): user_id = db.session.query(Users._id).filter_by( pk=user_pk, app_id=app_id).scalar() if not user_id: raise NotFoundError('User ID not found') return cls.query.filter_by(alias=alias, user_id=user_id).update( { 'linked_at': None, 'user_id': None }, synchronize_session=False)
def merge_with(self, user_pk=None, alias=None): if not user_pk and alias <= 0: raise BadRequestError('At least one parameter dst_user_id or ' 'dst_social_id must be provided') profiles = SocialProfiles.find_by_pk(app_id=self.app_id, user_pk=user_pk) \ if user_pk else SocialProfiles.query.filter_by(alias=alias) if not profiles: raise NotFoundError('Destination User ID or Social ID not found') dst_profile = profiles[0] self._merge_unsafe(dst_profile)
def convert_social_id(body): sub, _ = _validate_access_token(access_token=body['access_token']) app_id = body['app_id'] owner_id = db.session.query(Apps.owner_id).filter_by(_id=app_id).scalar() if not owner_id or owner_id != sub: raise NotFoundError('App ID not found') social_ids = body['ids'].split(',') if len(social_ids) > 150: raise BadRequestError('Number of IDs cannot be larger than 150') scope_ids = SocialProfiles.social_id_to_scope_id(app_id=app_id, social_ids=social_ids) return [e[0] for e in scope_ids]
def admin_authenticate(email, password): admin = Admins.query.filter_by(email=email).one_or_none() if not admin: raise NotFoundError('Email not found') if not django_pbkdf2_sha256.verify(secret=password, hash=admin.password): raise UnauthorizedError('Invalid authorization credentials') admin_attrs = admin.as_dict() return { 'user': admin_attrs, 'access_token': jwt_token_helper.generate( sub=admin._id, exp_in_seconds=86400 * 365, **admin_attrs, ) }
def get_full_profile(cls, app_id, user_pk=None, alias=None, pretty=False): profiles = cls.find_by_pk(app_id=app_id, user_pk=user_pk) \ if user_pk else SocialProfiles.query.filter_by(alias=alias).all() if not profiles: raise NotFoundError('User ID or Social ID not found') last_profile = None login_count = 0 for p in profiles: login_count += p.login_count if not last_profile: last_profile = p continue if last_profile.last_authorized_at < p.last_authorized_at: last_profile = p user = Users.query.filter_by(_id=last_profile.user_id).one_or_none() user_attrs = user.as_dict() if user else {'user_id': None} user_attrs.update({ 'last_logged_in_provider': last_profile.provider, 'last_logged_in_at': cls.to_isoformat(last_profile.last_authorized_at), 'login_count': login_count, 'social_id': str(last_profile.alias) }) return { 'user': user_attrs, 'profiles': [ p.as_dict(user_pk=user.pk if user else None, fetch_user=False, pretty=pretty) for p in profiles ] }
def admin_info(access_token): sub, _ = _validate_access_token(access_token=access_token) admin = Admins.query.filter_by(_id=sub).one_or_none() if not admin: raise NotFoundError('Email not found') return {'user': admin.as_dict()}
def authorize(self, params: OAuthAuthorizeParams): # Verify request params and extract session data self.session = self._verify_and_parse_session(params=params) oauth_app = Apps.query.filter_by(_id=params.app_id, _deleted=0).one_or_none() self.channel = Channels.query.filter_by( app_id=params.app_id, provider=self.provider).one_or_none() if not oauth_app or not self.channel: raise NotFoundError(msg='Application or channel not found') if not self._is_mobile(): allowed_uris = [ up.unquote_plus(uri) for uri in oauth_app.get_callback_uris() ] logger.debug('Verify callback URI', style='hybrid', allowed_uris=allowed_uris, succ_callback=params.success_callback, fail_callback=params.failed_callback) illegal_callback_msg = ( 'Invalid callback_uri value. ' 'Check if it is registered in EasyLogin developer site') if not verify_callback_uri(allowed_uris, params.success_callback): raise PermissionDeniedError(msg=illegal_callback_msg) if params.failed_callback and not verify_callback_uri( allowed_uris, params.failed_callback): raise PermissionDeniedError(msg=illegal_callback_msg) self.log = AuthLogs(provider=self.provider, app_id=params.app_id, nonce=gen_random_token(nbytes=32), intent=params.intent, platform=self.session.platform, callback_uri=params.success_callback, callback_if_failed=params.failed_callback) db.session.add(self.log) db.session.flush() db.session.add( JournalLogs(ua=request.headers.get('User-Agent'), ip=get_remote_ip(request), path=request.full_path, ref_id=self.log._id)) oauth_state = generate_oauth_state(self.log, **self.session.to_dict()) if self._is_mobile(): return jsonify({ 'channel': { 'client_id': self.channel.client_id, 'options': self.channel.get_options(), 'scopes': self.channel.get_permissions() }, 'state': oauth_state }) else: url = self._build_authorize_uri(state=oauth_state) logger.debug('Authorize URL', url) return redirect(url)