def has_permission(self, view): token = view.request.headers.get('Authorization') session_create = not getattr(view, 'session') permission = getattr(view, 'required_project_permission', None) if not token: return False try: session = Session() if session_create else getattr(view, 'session') if token[:len(self.token_prefix)] == self.token_prefix: token = token[len(self.token_prefix):] result = project_auth(session, token, permission) if result.get('warning'): view.headers['X-Application-Warning'] = result['warning'] return result['result'] elif token[:len(self.project_token_prefix )] == self.project_token_prefix: token = token[len(self.project_token_prefix):] result = project_auth(session, token, permission) if result.get('warning'): view.headers['X-Application-Warning'] = result['warning'] return result['result'] else: return False finally: if session_create: session.close()
def project_auth(token, permission=None): session = Session() project_token = session.query(Token).first() if not project_token: return {'result': False} url = api_method_url('project_auth/') data = {'project_token': project_token.token, 'token': token} headers = {'User-Agent': 'Jet Django'} if permission: data.update(permission) r = requests.request('POST', url, data=data, headers=headers) success = 200 <= r.status_code < 300 if not success: logging.error('Project Auth request error', r.status_code, r.reason) return {'result': False} result = r.json() if result.get('access_disabled'): return {'result': False, 'warning': result.get('warning')} return {'result': True, 'warning': result.get('warning')}
def get(self, *args, **kwargs): try: session = Session() token, created = register_token(session) if not token: return if is_token_activated(session): response = Response( {'message': 'Project token is already activated'}) self.write_response(response) return if settings.WEB_BASE_URL.startswith( 'https' ) and not self.request.full_url().startswith('https'): web_base_url = 'http{}'.format(settings.WEB_BASE_URL[5:]) else: web_base_url = settings.WEB_BASE_URL url = '{}/projects/register/{}'.format(web_base_url, token.token) query_string = 'referrer={}'.format( quote(self.request.full_url().encode('utf8'))) self.redirect('%s?%s' % (url, query_string)) finally: session.close()
def prepare(self): method_override = self.request.headers.get('X-Http-Method-Override') if method_override is not None: self.request.method = method_override if self.request.method != 'OPTIONS': self.check_permissions() self.session = Session()
def token_command(): try: session = Session() token = get_token(session) if token: logging.info('Jet Admin Token:') logging.info(token) else: logging.info('Jet Admin Token is not set') finally: session.close()
def set_token_command(args): try: session = Session() token = uuid.UUID(args[1]) if len(args) >= 2 else None if not token: logging.info('No token was specified') return set_token(session, token) finally: session.close()
def register_token_command(): try: session = Session() token, created = register_token(session) if not created and token: logging.info('Token already exists: {}'.format(token.token)) elif not created and not token: logging.info('Token creation failed') elif created and token: logging.info('Token created: {}'.format(token.token)) finally: session.close()
def run_command(): logging.info(datetime.now().strftime('%B %d, %Y - %H:%M:%S %Z')) logging.info('Jet Bridge version {}'.format(VERSION)) if missing_options == settings.required_options_without_default: create_config() return elif len(missing_options) and len(missing_options) < len( settings.required_options_without_default): logging.info('Required options are not specified: {}'.format( ', '.join(missing_options))) return from jet_bridge.app import make_app app = make_app() app.listen(settings.PORT, settings.ADDRESS) address = 'localhost' if settings.ADDRESS == '0.0.0.0' else settings.ADDRESS url = 'http://{}:{}/'.format(address, settings.PORT) logging.info('Starting server at {}'.format(url)) if settings.DEBUG: logging.warning('Server is running in DEBUG mode') logging.info('Quit the server with CONTROL-C') try: session = Session() token, created = register_token(session) if not token: return if not is_token_activated(session): token = get_token(session) register_url = '{}api/register/?token={}'.format(url, token) logging.warning('[!] Your server token is not activated') logging.warning('[!] Token: {}'.format(token)) if settings.AUTO_OPEN_REGISTER and webbrowser.open(register_url): logging.warning( '[!] Activation page was opened in your browser - {}'. format(register_url)) except RequestException: logging.error('[!] Can\'t connect to Jet Admin API') logging.error('[!] Token verification failed') finally: session.close() tornado.ioloop.IOLoop.current().start()
def register_token(): session = Session() token = session.query(Token).first() if token: return token, False url = api_method_url('project_tokens/') headers = {'User-Agent': 'Jet Django'} r = requests.request('POST', url, headers=headers) success = 200 <= r.status_code < 300 if not success: logging.error('Register Token request error', r.status_code, r.reason) return None, False result = r.json() # TODO: add serializer token = result['token'].replace('-', '') date_add = datetime.strptime(result['date_add'][:-6], '%Y-%m-%dT%H:%M:%S.%f') token = Token(token=token, date_add=date_add) session.add(token) session.commit() return token, True
def is_token_activated(): session = Session() token = session.query(Token).first() if not token: return False url = api_method_url('project_tokens/{}/'.format(token.token)) headers = {'User-Agent': 'Jet Django'} r = requests.request('GET', url, headers=headers) success = 200 <= r.status_code < 300 if not success: return False result = r.json() return bool(result.get('activated'))
def execute(self): session = Session() query = self.validated_data['query'] params = self.validated_data.get('params', []) try: result = session.execute(text(query), params) rows = list(map(lambda x: x.itervalues(), result)) def map_column(x): if x == '?column?': return return x return {'data': rows, 'columns': map(map_column, result.keys())} except (SQLAlchemyError, TypeError) as e: raise SqlError(e)
def run_command(): from jet_bridge.app import make_app app = make_app() app.listen(settings.PORT, settings.ADDRESS) address = 'localhost' if settings.ADDRESS == '0.0.0.0' else settings.ADDRESS url = 'http://{}:{}/'.format(address, settings.PORT) logging.info('Starting server at {}'.format(url)) if settings.DEBUG: logging.warning('Server is running in DEBUG mode') logging.info('Quit the server with CONTROL-C') try: session = Session() token, created = register_token(session) if not token: return if not is_token_activated(session): token = get_token(session) register_url = '{}api/register/?token={}'.format(url, token) logging.warning('[!] Your server token is not activated') logging.warning('[!] Token: {}'.format(token)) if settings.AUTO_OPEN_REGISTER and webbrowser.open(register_url): logging.warning('[!] Activation page was opened in your browser - {}'.format(register_url)) except RequestException: logging.error('[!] Can\'t connect to Jet Admin API') logging.error('[!] Token verification failed') finally: session.close() tornado.ioloop.IOLoop.current().start()
def reset_token(): session = Session() session.query(Token).delete() session.commit() return register_token()
class ModelDescriptionsHandler(APIView): serializer_class = ModelDescriptionSerializer permission_classes = (HasProjectPermissions, ) session = Session() def get_queryset(self): non_editable = ['id'] hidden = ['__jet__token'] def map_column(column): params = {} data_type = map_data_type(column.type) if len(column.foreign_keys): foreign_key = next(iter(column.foreign_keys)) data_type = data_types.FOREIGN_KEY params['related_model'] = { 'model': foreign_key.column.table.name } return { 'name': column.name, 'db_column': column.name, 'field': data_type, 'filterable': True, 'editable': column.name not in non_editable, 'params': params } def map_relation(relation): field = None if relation.direction == ONETOMANY: field = 'ManyToOneRel' return { 'name': relation.key, 'related_model': { 'model': relation.table.name }, 'field': field, 'related_model_field': relation.primaryjoin.right.name, 'through': None } def table_relations(mapper): return list( map( map_relation, filter(lambda x: x.direction == ONETOMANY, mapper.relationships))) def table_m2m_relations(mapper): result = [] name = mapper.selectable.name for relation in mapper.relationships: if relation.direction != ONETOMANY: continue m2m_relationships = relation.mapper.relationships.values() if len(m2m_relationships) != 2: continue if len(relation.table.columns) > 5: continue self_relationship = m2m_relationships[1] if m2m_relationships[1].table.name == name else \ m2m_relationships[0] other_relationship = m2m_relationships[0] if self_relationship == m2m_relationships[1] else \ m2m_relationships[1] result.append({ 'name': 'M2M {} {}'.format(self_relationship.table.name, other_relationship.table.name), 'related_model': { 'model': other_relationship.table.name }, 'field': 'ManyToManyField', 'related_model_field': self_relationship.table.name, 'through': { 'model': relation.table.name } }) return result def map_table(cls): mapper = inspect(cls) name = mapper.selectable.name return { 'model': name, 'db_table': name, 'fields': list(map(map_column, mapper.columns)), 'hidden': name in hidden, 'relations': table_relations(mapper) + table_m2m_relations(mapper), 'primary_key_field': mapper.primary_key[0].name } return list(map(map_table, MappedBase.classes)) def get(self, *args, **kwargs): queryset = self.get_queryset() serializer = self.serializer_class(instance=queryset, many=True) response = Response(serializer.representation_data) self.write_response(response)
class GenericAPIView(APIView): serializer_class = None filter_class = None pagination_class = PageNumberPagination _paginator = None lookup_field = 'id' lookup_url_kwarg = None session = Session() action = None def get_model(self): raise NotImplementedError def get_queryset(self): raise NotImplementedError def get_object(self): queryset = self.filter_queryset(self.get_queryset()) lookup_url_kwarg = self.lookup_url_kwarg or 'pk' assert lookup_url_kwarg in self.path_kwargs model_field = getattr(self.get_model(), self.lookup_field) obj = queryset.filter( getattr(model_field, '__eq__')(self.path_kwargs[lookup_url_kwarg])).first() self.check_object_permissions(obj) return obj def get_filter(self, *args, **kwargs): filter_class = self.get_filter_class() if not filter_class: return kwargs['context'] = self.filter_context() return filter_class(*args, **kwargs) def get_filter_class(self): return self.filter_class def filter_context(self): return {'request': self.request, 'handler': self} def filter_queryset(self, queryset): filter_instance = self.get_filter() if filter_instance: queryset = filter_instance.filter_queryset(queryset) return queryset @property def paginator(self): if not self._paginator: if self.pagination_class is None: self._paginator = None else: self._paginator = self.pagination_class() return self._paginator def paginate_queryset(self, queryset): if self.paginator is None: return None return self.paginator.paginate_queryset(queryset, self) def get_paginated_response(self, data): assert self.paginator is not None return self.paginator.get_paginated_response(data) def get_serializer(self, *args, **kwargs): serializer_class = self.get_serializer_class() kwargs['context'] = self.get_serializer_context() return serializer_class(*args, **kwargs) def get_serializer_class(self): return self.serializer_class def get_serializer_context(self): return {'request': self.request, 'view': self, 'session': self.session} def write_error(self, status_code, **kwargs): self.session.rollback() super(GenericAPIView, self).write_error(status_code, **kwargs)
class APIView(tornado.web.RequestHandler): permission_classes = [] session = None @property def data(self): content_type = self.request.headers.get('Content-Type', '') if content_type.startswith('application/json'): return json_decode(self.request.body) else: return self.request.body_arguments def prepare(self): method_override = self.request.headers.get('X-Http-Method-Override') if method_override is not None: self.request.method = method_override if self.request.method != 'OPTIONS': self.check_permissions() self.session = Session() def on_finish(self): if self.session: self.session.close() self.session = None def set_default_headers(self): ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin' ACCESS_CONTROL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers' ACCESS_CONTROL_ALLOW_CREDENTIALS = 'Access-Control-Allow-Credentials' ACCESS_CONTROL_ALLOW_HEADERS = 'Access-Control-Allow-Headers' ACCESS_CONTROL_ALLOW_METHODS = 'Access-Control-Allow-Methods' self.set_header(ACCESS_CONTROL_ALLOW_ORIGIN, '*') self.set_header(ACCESS_CONTROL_ALLOW_METHODS, 'GET, POST, PUT, PATCH, DELETE, OPTIONS') self.set_header( ACCESS_CONTROL_ALLOW_HEADERS, 'Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-Application-Warning,X-HTTP-Method-Override' ) self.set_header(ACCESS_CONTROL_EXPOSE_HEADERS, 'Content-Length,Content-Range,X-Application-Warning') self.set_header(ACCESS_CONTROL_ALLOW_CREDENTIALS, 'true') def get_permissions(self): return [permission() for permission in self.permission_classes] def check_permissions(self): for permission in self.get_permissions(): if not permission.has_permission(self): raise PermissionDenied( getattr(permission, 'message', 'forbidden')) def check_object_permissions(self, obj): for permission in self.get_permissions(): if not permission.has_object_permission(self, obj): raise PermissionDenied( getattr(permission, 'message', 'forbidden')) def options(self, *args, **kwargs): self.set_status(204) self.finish() def build_absolute_uri(self, url): return self.request.protocol + "://" + self.request.host + url def write_response(self, response): for name, value in response.header_items(): self.set_header(name, value) self.write(response.render()) def write_error(self, status_code, **kwargs): exc_type = exc = traceback = None if kwargs.get('exc_info'): exc_type, exc, traceback = kwargs['exc_info'] if isinstance(exc, APIException): status_code = exc.status_code if status_code == status.HTTP_403_FORBIDDEN: self.render('403.html', **{ 'path': self.request.path, }) else: if settings.DEBUG: ctx = { 'path': self.request.path, 'full_path': self.request.protocol + "://" + self.request.host + self.request.path, 'method': self.request.method, 'version': VERSION, 'current_datetime': datetime.now().strftime('%c'), 'python_version': platform.python_version(), 'python_executable': sys.executable, 'python_path': sys.path } if exc: last_traceback = traceback while last_traceback.tb_next: last_traceback = last_traceback.tb_next ctx.update({ 'exception_type': exc_type.__name__, 'exception_value': str(exc), 'exception_last_traceback_line': last_traceback.tb_lineno, 'exception_last_traceback_name': last_traceback.tb_frame }) self.render('500.debug.html', **ctx) else: self.render('500.html')