def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: cursor.execute( ''' select request as json from www.request(%s, %s, %s::json, %s::json) ''', (request.method, request.path, json.dumps(request.args.to_dict(flat=True)), request.data.decode('utf8') if request.data else 'null')) row = cursor.fetchone() return Response(row.json, content_type="application/json") except HTTPException as e: e_resp = e.get_response() if (request.mimetype == 'application/json'): response = Response(response=json.dumps({ "title": "Bad Request", "status_code": e_resp.status_code, "message": e.description }), status=e_resp.status_code, mimetype="application/json") return response else: return e
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: # We want to maintain escaped urls as string data full_path = re.split('\?', env['REQUEST_URI'])[0] # get rid of query params path_with_version = full_path.replace('/endpoint/', '', 1) # get rid of endpoint path version, path = path_with_version.split('/', 1) logging.info('handling request for: %s' % env['REQUEST_URI']) logging.debug('attempting endpoint %s, %s, %s, query %s, post %s' % (version, request.method, path, request.args, request.data)) cursor.execute(''' select status, message, response, mimetype from endpoint.request(%s, %s, %s, %s::json, %s::json) ''', ( version, # version - 0.1, 0.2, etc... request.method, # verb - GET | POST | PATCH | PUT | DELETE ... path, # path - the relative path including leading slash but without query string json.dumps(request.args.to_dict(flat=False)), # args - "url parameters", aka parsed out query string, converted to a json string request.get_data() if request.data else 'null' )) row = cursor.fetchone() if row.mimetype.startswith('image'): # There is a better way here. return Response( response=a2b_base64(row.response), content_type=row.mimetype, status=row.status ) # TODO? # How come status and message are not used here? return Response( response=row.response, content_type=row.mimetype, status=row.status ) except HTTPException as e: e_resp = e.get_response() if(request.mimetype == 'application/json'): response = Response( response=json.dumps({ "title": "Bad Request", "status_code": e_resp.status_code, "message": e.description }), status=e_resp.status_code, mimetype="application/json" ) return response else: return e
def do_auth(self, request, start_response): with cursor_for_request(request) as cursor: cursor.execute("select auth.login(%s) as token", (request.args["hash"],)) row = cursor.fetchone() if row and row.token: start_response("200 Found", [("Set-Cookie", "%s=%s" % (self.session_cookie, row.token))]) else: start_response("401 Unauthorized", []) return []
def verify_session(self, request, environ, start_response): environ["DB_USER"] = "******" if self.session_cookie in request.cookies: token = request.cookies["SESSION"] with cursor_for_request(request) as cursor: cursor.execute("select username from auth.session where token = %s", (token,)) row = cursor.fetchone() if row: environ["DB_USER"] = row.username return self.app(environ, start_response)
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: cursor.execute('select content from www.page where path = %s', (request.path,)) row = cursor.fetchone() if row is None: raise NotFound else: return Response(row.content, content_type='text/html') except HTTPException as e: return e
def do_auth(self, request, start_response): with cursor_for_request(request) as cursor: cursor.execute('select auth.login(%s) as token', (request.args['hash'], )) row = cursor.fetchone() if row and row.token: start_response('200 Found', [('Set-Cookie', '%s=%s' % (self.session_cookie, row.token))]) else: start_response('401 Unauthorized', []) return []
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: logging.info( 'this version of the data url scheme has been deprecated. use /endpoint/new instead' ) # will be # select status, message, response as json cursor.execute( ''' select status, message, data2 as json from endpoint.request(%s, %s, %s::json, %s::json) ''', ( request. method, # verb - GET | POST | PATCH | PUT | DELETE ... request. path, # path - the full path including leading slash but without query string json.dumps( request.args.to_dict(flat=True) ), # args - "url parameters", aka parsed out query string, converted to a json string request.data.decode('utf8') if request.data else 'null')) row = cursor.fetchone() # return Response('Hello World!') # TODO? # How come status and message are not used here? return Response(row.json, content_type="application/json") except HTTPException as e: e_resp = e.get_response() if (request.mimetype == 'application/json'): response = Response(response=json.dumps({ "title": "Bad Request", "status_code": e_resp.status_code, "message": e.description }), status=e_resp.status_code, mimetype="application/json") return response else: return e
def verify_session(self, request, environ, start_response): environ['DB_USER'] = '******' if self.session_cookie in request.cookies: token = request.cookies['SESSION'] with cursor_for_request(request) as cursor: cursor.execute( "select username from auth.session where token = %s", (token, )) row = cursor.fetchone() if row: environ['DB_USER'] = row.username return self.app(environ, start_response)
def verify_session(self, request, environ, start_response): environ['DB_USER'] = '******' if self.session_cookie in request.cookies: session_id = request.cookies[self.session_cookie] with cursor_for_request(request) as cursor: try: cursor.execute("select (role_id).name as role_name from endpoint.session(%s::uuid)", (session_id,)) row = cursor.fetchone() except: pass else: if row: environ['DB_USER'] = row.role_name return self.app(environ, start_response)
def verify_session(self, request, environ, start_response): environ['DB_USER'] = '******' if self.session_cookie in request.cookies: session_id = request.cookies[self.session_cookie] with cursor_for_request(request) as cursor: try: cursor.execute( "select (role_id).name as role_name from endpoint.session(%s::uuid)", (session_id, )) row = cursor.fetchone() except: pass else: if row: environ['DB_USER'] = row.role_name return self.app(environ, start_response)
def do_auth(self, request, environ, start_response): with cursor_for_request(request) as cursor: # Incomplete login attempt if email/password not POSTed if request.form.get('email') is None or request.form.get( 'password') is None: return [] try: # Attempt login cursor.execute( 'select endpoint.login(%s, %s) as session_id', (request.form.get('email'), request.form.get('password'))) row = cursor.fetchone() except: # Exception raised from invalid email start_response('401 Unauthorized', []) redirect_response = redirect(request.full_path) return redirect_response(environ, start_response) if row and row.session_id: # Logged in # Redirect to redirectURL or / redirect_response = redirect( request.args.get('redirectURL', '/')) redirect_response.set_cookie(self.session_cookie, row.session_id) #start_response('200 Found', [('Set-Cookie', '%s=%s' % (self.session_cookie, row.session_id))]) return redirect_response(environ, start_response) else: # Login failed from invalid password attempt start_response('401 Unauthorized', []) redirect_response = redirect(request.full_path) return redirect_response(environ, start_response)
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: cursor.execute(''' select request as json from www.request(%s, %s, %s::json, %s::json) ''', ( request.method, request.path, json.dumps(request.args.to_dict(flat=True)), request.data.decode('utf8') if request.data else 'null' )) row = cursor.fetchone() return Response(row.json, content_type="application/json") except HTTPException as e: e_resp = e.get_response() if(request.mimetype == 'application/json'): response = Response( response=json.dumps({ "title": "Bad Request", "status_code": e_resp.status_code, "message": e.description }), status=e_resp.status_code, mimetype="application/json" ) return response else: return e
def do_auth(self, request, environ, start_response): with cursor_for_request(request) as cursor: # Incomplete login attempt if email/password not POSTed if request.form.get('email') is None or request.form.get('password') is None: return [] try: # Attempt login cursor.execute( 'select endpoint.login(%s, %s) as session_id', (request.form.get('email'), request.form.get('password')) ) row = cursor.fetchone() except: # Exception raised from invalid email start_response('401 Unauthorized', []) redirect_response = redirect(request.full_path) return redirect_response(environ, start_response) if row and row.session_id: # Logged in # Redirect to redirectURL or / redirect_response = redirect(request.args.get('redirectURL', '/')) redirect_response.set_cookie(self.session_cookie, row.session_id) #start_response('200 Found', [('Set-Cookie', '%s=%s' % (self.session_cookie, row.session_id))]) return redirect_response(environ, start_response) else: # Login failed from invalid password attempt start_response('401 Unauthorized', []) redirect_response = redirect(request.full_path) return redirect_response(environ, start_response)
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() logging.info('connection established') try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] != 'ping': logging.info('command received: %s' % cmd['method']) if cmd['method'] == 'request': request_method(cmd, cursor) elif cmd['method'] == 'attach': attach_method(cmd, cursor, db_connection, env) elif cmd['method'] == 'detach': detach_method(cmd, cursor, db_connection, env) except Warning as err: logging.error(str(err)) # uwsgi.websocket_send(json.dumps({ # "method": "log", # "args": { # "level": "warning", # "message": err.diag.message_primary # } # })) elif fd == db_conn_fd: handle_db_notifications(db_connection) else: logging.info('timeout reached') # This is never reached # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except (OSError, IOError) as err: logging.info('connection closed (role: %s)' % env['DB_USER']) return []
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: # Text resource cursor.execute( ''' select r.content, m.mimetype from endpoint.resource r join endpoint.mimetype m on r.mimetype_id = m.id where path = %s ''', (request.path, )) row = cursor.fetchone() # Binary resource if row is None: cursor.execute( ''' select r.content, m.mimetype from endpoint.resource_binary r join endpoint.mimetype m on r.mimetype_id = m.id where path = %s ''', (request.path, )) row = cursor.fetchone() # TODO Look to see if path has ancestral index # File resource if row is None: cursor.execute( ''' select f.content, m.mimetype from filesystem.file f left join endpoint.mimetype_extension e on e.extension = regexp_replace(f.name, '^.*\.', '') left join endpoint.mimetype m on m.id = e.mimetype_id where f.path = (select file_id from endpoint.resource_file where path=%s); ''', (request.path, )) row = cursor.fetchone() # Directory resource # Question: only directories where indexes = true? if row is None: cursor.execute( ''' with dir as ( select directory_id as dir_id from endpoint.resource_directory where path=%s and indexes=true ) select path, name, last_mod, size, endpoint.is_indexed(path) as show from filesystem.directory where parent_id=(select dir_id from dir) union select path, name, last_mod, size, endpoint.is_indexed(path) as show from filesystem.file where directory_id=(select dir_id from dir) ''', (request.path, )) rows = cursor.fetchall() if len(rows): return Response(build_directory_index(request.path, rows), content_type='text/html') # Should this redirect to /login? # That would mean: Resource Not Found = Resource Not Authorized # Which is accurate considering RLS hides unauthorized data # No because auth should occur in widgets, no redirecting if row is None: # Is this returning a 404? raise NotFound return Response(row.content, content_type='text/plain' if row.mimetype is None else row.mimetype) except HTTPException as e: return e
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() logging.info('connection established') try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] != 'ping': logging.info('command received: %s' % cmd['method']) if cmd['method'] == 'request': request_method(cmd, cursor) elif cmd['method'] == 'attach': attach_method(cmd, cursor, db_connection, env) elif cmd['method'] == 'detach': detach_method(cmd, cursor, db_connection, env) except Warning as err: logging.error(str(err)) # uwsgi.websocket_send(json.dumps({ # "method": "log", # "args": { # "level": "warning", # "message": err.diag.message_primary # } # })) elif fd == db_conn_fd: handle_db_notifications(db_connection) else: logging.info( 'timeout reached') # This is never reached # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except (OSError, IOError) as err: logging.info('connection closed (role: %s)' % env['DB_USER']) return []
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: rowcount = 0 # Text resource cursor.execute( ''' select r.content, m.mimetype from endpoint.resource r join endpoint.mimetype m on r.mimetype_id = m.id where path = %s and active = true ''', (request.path, )) text_resources = cursor.fetchall() rowcount += cursor.rowcount # Binary resource cursor.execute( ''' select r.content, m.mimetype from endpoint.resource_binary r join endpoint.mimetype m on r.mimetype_id = m.id where path = %s and active = true ''', (request.path, )) binary_resources = cursor.fetchall() rowcount += cursor.rowcount # Template resource # check for matching route cursor.execute( ''' select array_to_json(regexp_matches(%s, r.url_pattern)) as match from endpoint.template_route r ''', (request.path, )) routes = cursor.fetchall() rowcount += cursor.rowcount # render template if we found one ^^. only if we don't have other rows template_resources = None if routes != None: cursor.execute( ''' select endpoint.template_render( t.id, r.args::json, array_to_json( regexp_matches(%s, r.url_pattern) ) ) as content, m.mimetype from endpoint.template_route r join endpoint.template t on r.template_id = t.id join endpoint.mimetype m on t.mimetype_id = m.id ''', (request.path, )) template_resources = cursor.fetchall() # else: # logging.info('HEEEEYYYYYYYY NO WE DID NOT GET a row') # cursor.execute(''' # select # id, regex_matches(%s, r.url_pattern), # endpoint.render_template(t.id, r.args::json) as content, 'text/html' as mimetype, r.args # from template.template t # join template.template_route r on r.template_id = t.id # where ''', (request.path,)) # template_resources = cursor.fetchall() # rowcount += cursor.rowcount # detect path collisions if rowcount > 1: raise MultipleChoices row = None if len(text_resources) == 1: row = text_resources[0] if len(binary_resources) == 1: row = binary_resources[0] if len(template_resources) == 1: row = template_resources[0] ### Commenting out until security can be audited... ### # File resource ### if row is None: ### cursor.execute(''' ### select f.content, m.mimetype ### from filesystem.file f ### left join endpoint.mimetype_extension e on e.extension = regexp_replace(f.name, '^.*\.', '') ### left join endpoint.mimetype m on m.id = e.mimetype_id ### where f.path = (select file_id from endpoint.resource_file where path=%s and active=true) ### ''', (request.path,)) ### row = cursor.fetchone() ### ### ### # Directory resource ### # Question: only directories where indexes = true? ### if row is None: ### cursor.execute(''' ### with dir as ( ### select directory_id as dir_id ### from endpoint.resource_directory ### where path=%s and indexes=true ### ) ### select path, name, last_mod, size, endpoint.is_indexed(path) as show from filesystem.directory where parent_id=(select dir_id from dir) ### union ### select path, name, last_mod, size, endpoint.is_indexed(path) as show from filesystem.file where directory_id=(select dir_id from dir) ### ''', (request.path,)) ### rows = cursor.fetchall() ### ### if len(rows): ### return Response(build_directory_index(request.path, rows), content_type='text/html') ### ### # File-in-Directory resource ### if row is None: ### cursor.execute(''' ### with dir as ( ### select directory_id as dir_id, path, char_length(path) as path_length ### from endpoint.resource_directory ### where %s like path || '%%' ### ) ### select f.content, m.mimetype ### from filesystem.file f ### left join endpoint.mimetype_extension e on e.extension = regexp_replace(f.name, '^.*\.', '') ### left join endpoint.mimetype m on m.id = e.mimetype_id ### where path = (select dir_id from dir) || substring(%s from (select path_length + 1 from dir)) ### ''', (request.path,request.path)) ### row = cursor.fetchone() # Should this redirect to /login? # That would mean: Resource Not Found = Resource Not Authorized # Which is accurate considering RLS hides unauthorized data # No because auth should occur in widgets, no redirecting if row is None: # Is this returning a 404? raise NotFound return Response(row.content, content_type='text/plain' if row.mimetype is None else row.mimetype) except HTTPException as e: return e
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() logging.info('connection established') try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] != 'ping': logging.info('command received: %s' % cmd['method']) if cmd['method'] == 'request': logging.info( 'websocket endpoint request: %s, %s, %s, %s' % ( cmd['verb'], # HTTP method - GET, POST, PATCH, DELETE cmd['uri'], # selector - '/relation/widget/dependency_js' ImmutableMultiDict( json.loads(cmd['query']) ), # query string arguments - including event.session id json.dumps( cmd['data']) # post data )) cursor.execute( 'select status, message, response, mimetype from endpoint.request2(%s, %s, %s::json, %s::json);', ( cmd['verb'], # HTTP method - GET, POST, PATCH, DELETE cmd['uri'], # selector - '/relation/widget/dependency_js' json.dumps( ImmutableMultiDict( json.loads( cmd['query']) ).to_dict(flat=False) ), # query string arguments - including event.session id json.dumps( cmd['data']) # post data )) result = cursor.fetchone() uwsgi.websocket_send('''{ "method": "response", "request_id": "%s", "data": %s }''' % (cmd['request_id'], result.response)) elif cmd['method'] == 'attach': session_id = cmd['session_id'] if session_id is not None: cursor.execute( 'select event.session_attach(%s);', (session_id, )) logging.info( 'session attached: %s (role: %s)' % (session_id, env['DB_USER'])) handle_db_notifications( db_connection) uwsgi.websocket_send('''{ "method": "response", "request_id": "%s", "data": "true" }''' % (cmd['request_id'], )) elif cmd['method'] == 'detach': session_id = cmd['session_id'] if session_id is not None: cursor.execute( 'select event.session_detach(%s);', (session_id, )) logging.info( 'session detached: %s (role: %s)' % (session_id, env['DB_USER'])) uwsgi.websocket_send('''{ "method": "response", "request_id": "%s", "data": "true" }''' % (cmd['request_id'], )) #uwsgi.websocket_send('''{ # "method": "response", # "request_id": "%s", # "data": %s #}''' % (cmd['request_id'], result.response)) except Warning as err: logging.error(str(err)) # uwsgi.websocket_send(json.dumps({ # "method": "log", # "args": { # "level": "warning", # "message": err.diag.message_primary # } # })) elif fd == db_conn_fd: handle_db_notifications(db_connection) else: logging.info( 'timeout reached') # This is never reached # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except (OSError, IOError) as err: logging.info('connection closed (role: %s)' % env['DB_USER']) return []
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) session_id = get_session_id(request, cursor) logging.info('event/table/session/row/%s:connected (role: %s)' % (session_id, env['DB_USER'])) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() cursor.execute('listen "event/table/session/rows/%i"' % session_id) try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] == 'subscribe': selector, type = cmd['args'][ 'selector'].rsplit(':', 1) cursor.execute( "select event.subscribe_session(%s, %s, %s);", (session_id, selector, type)) elif cmd['method'] == 'unsubscribe': selector, type = cmd['args'][ 'selector'].rsplit(':', 1) cursor.execute( "select event.unsubscribe_session(%s, %s, %s);", (session_id, selector, type)) except Warning as err: logging.error(str(err)) uwsgi.websocket_send( json.dumps({ "method": "log", "args": { "level": "warning", "message": err.diag.message_primary } })) elif fd == db_conn_fd: db_connection.poll() if db_connection.notifies: del db_connection.notifies[:] cursor.execute( ''' select * from event.session_queued_events_json(%s) ''', (session_id, )) qe_ids = [] logging.info( 'event/table/session/row/%s:flushing_queue (role: %s)' % (session_id, env['DB_USER'])) for row in cursor: uwsgi.websocket_send(json.dumps( row.event_json)) logging.info( 'event/table/session/row/%s:sent_json (role: %s)' % (session_id, env['DB_USER'])) qe_ids.append(row.queued_event_id) cursor.execute( ''' delete from event.queued_event qe where qe.id = any(%s) ''', (qe_ids, )) else: # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except OSError as err: logging.info( 'event/table/session/row/%s:disconnected (role: %s)' % (session_id, env['DB_USER'])) return []
def application(env, start_response): request = Request(env) try: with map_errors_to_http(), cursor_for_request(request) as cursor: rowcount = 0 # Text resource cursor.execute(''' select r.content, m.mimetype from endpoint.resource r join endpoint.mimetype m on r.mimetype_id = m.id where path = %s and active = true ''', (request.path,)) text_resources = cursor.fetchall() rowcount += cursor.rowcount # Binary resource cursor.execute(''' select r.content, m.mimetype from endpoint.resource_binary r join endpoint.mimetype m on r.mimetype_id = m.id where path = %s and active = true ''', (request.path,)) binary_resources = cursor.fetchall() rowcount += cursor.rowcount # Template resource # check for matching route cursor.execute(''' select array_to_json(regexp_matches(%s, r.url_pattern)) as match from endpoint.template_route r ''', (request.path,)) routes = cursor.fetchall() rowcount += cursor.rowcount # render template if we found one ^^. only if we don't have other rows template_resources = None if routes != None: cursor.execute(''' select endpoint.template_render( t.id, r.args::json, array_to_json( regexp_matches(%s, r.url_pattern) ) ) as content, m.mimetype from endpoint.template_route r join endpoint.template t on r.template_id = t.id join endpoint.mimetype m on t.mimetype_id = m.id ''', (request.path,)) template_resources = cursor.fetchall() # else: # logging.info('HEEEEYYYYYYYY NO WE DID NOT GET a row') # cursor.execute(''' # select # id, regex_matches(%s, r.url_pattern), # endpoint.render_template(t.id, r.args::json) as content, 'text/html' as mimetype, r.args # from template.template t # join template.template_route r on r.template_id = t.id # where ''', (request.path,)) # template_resources = cursor.fetchall() # rowcount += cursor.rowcount # detect path collisions if rowcount > 1: raise MultipleChoices row = None if len(text_resources) == 1: row = text_resources[0] if len(binary_resources) == 1: row = binary_resources[0] if len(template_resources) == 1: row = template_resources[0] ### Commenting out until security can be audited... ### # File resource ### if row is None: ### cursor.execute(''' ### select f.content, m.mimetype ### from filesystem.file f ### left join endpoint.mimetype_extension e on e.extension = regexp_replace(f.name, '^.*\.', '') ### left join endpoint.mimetype m on m.id = e.mimetype_id ### where f.path = (select file_id from endpoint.resource_file where path=%s and active=true) ### ''', (request.path,)) ### row = cursor.fetchone() ### ### ### # Directory resource ### # Question: only directories where indexes = true? ### if row is None: ### cursor.execute(''' ### with dir as ( ### select directory_id as dir_id ### from endpoint.resource_directory ### where path=%s and indexes=true ### ) ### select path, name, last_mod, size, endpoint.is_indexed(path) as show from filesystem.directory where parent_id=(select dir_id from dir) ### union ### select path, name, last_mod, size, endpoint.is_indexed(path) as show from filesystem.file where directory_id=(select dir_id from dir) ### ''', (request.path,)) ### rows = cursor.fetchall() ### ### if len(rows): ### return Response(build_directory_index(request.path, rows), content_type='text/html') ### ### # File-in-Directory resource ### if row is None: ### cursor.execute(''' ### with dir as ( ### select directory_id as dir_id, path, char_length(path) as path_length ### from endpoint.resource_directory ### where %s like path || '%%' ### ) ### select f.content, m.mimetype ### from filesystem.file f ### left join endpoint.mimetype_extension e on e.extension = regexp_replace(f.name, '^.*\.', '') ### left join endpoint.mimetype m on m.id = e.mimetype_id ### where path = (select dir_id from dir) || substring(%s from (select path_length + 1 from dir)) ### ''', (request.path,request.path)) ### row = cursor.fetchone() # Should this redirect to /login? # That would mean: Resource Not Found = Resource Not Authorized # Which is accurate considering RLS hides unauthorized data # No because auth should occur in widgets, no redirecting if row is None: # Is this returning a 404? raise NotFound return Response(row.content, content_type='text/plain' if row.mimetype is None else row.mimetype) except HTTPException as e: return e
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) session_id = get_session_id(request, cursor) logging.info('event/table/session/row/%s:connected (role: %s)' % (session_id, env['DB_USER'])) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() cursor.execute('listen "event/table/session/rows/%i"' % session_id) try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] == 'subscribe': selector, type = cmd['args']['selector'].rsplit(':', 1) cursor.execute("select event.subscribe_session(%s, %s, %s);", (session_id, selector, type)) elif cmd['method'] == 'unsubscribe': selector, type = cmd['args']['selector'].rsplit(':', 1) cursor.execute("select event.unsubscribe_session(%s, %s, %s);", (session_id, selector, type)) except Warning as err: logging.error(str(err)) uwsgi.websocket_send(json.dumps({ "method": "log", "args": { "level": "warning", "message": err.diag.message_primary } })) elif fd == db_conn_fd: db_connection.poll() if db_connection.notifies: del db_connection.notifies[:] cursor.execute(''' select * from event.session_queued_events_json(%s) ''', (session_id,)) qe_ids = [] logging.info('event/table/session/row/%s:flushing_queue (role: %s)' % (session_id, env['DB_USER'])) for row in cursor: uwsgi.websocket_send(json.dumps(row.event_json)) logging.info('event/table/session/row/%s:sent_json (role: %s)' % (session_id, env['DB_USER'])) qe_ids.append(row.queued_event_id) cursor.execute(''' delete from event.queued_event qe where qe.id = any(%s) ''', (qe_ids,)) else: # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except OSError as err: logging.info('event/table/session/row/%s:disconnected (role: %s)' % (session_id, env['DB_USER'])) return []