Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #46 Realtime client not working if Row Level Security (RLS) is enabled #47

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions addons/supabase/Auth/auth.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ signal user_invited()
signal error(supabase_error)

const _auth_endpoint : String = "/auth/v1"
const _provider_endpoint : String = _auth_endpoint+"/authorize"
const _signin_endpoint : String = _auth_endpoint+"/token?grant_type=password"
const _signin_otp_endpoint : String = _auth_endpoint+"/otp"
const _verify_otp_endpoint : String = _auth_endpoint+"/verify"
const _signup_endpoint : String = _auth_endpoint+"/signup"
const _refresh_token_endpoint : String = _auth_endpoint+"/token?grant_type=refresh_token"
const _logout_endpoint : String = _auth_endpoint+"/logout"
const _user_endpoint : String = _auth_endpoint+"/user"
const _magiclink_endpoint : String = _auth_endpoint+"/magiclink"
const _invite_endpoint : String = _auth_endpoint+"/invite"
const _reset_password_endpoint : String = _auth_endpoint+"/recover"
const _provider_endpoint : String = _auth_endpoint + "/authorize"
const _signin_endpoint : String = _auth_endpoint + "/token?grant_type=password"
const _signin_otp_endpoint : String = _auth_endpoint + "/otp"
const _verify_otp_endpoint : String = _auth_endpoint + "/verify"
const _signup_endpoint : String = _auth_endpoint + "/signup"
const _refresh_token_endpoint : String = _auth_endpoint + "/token?grant_type=refresh_token"
const _logout_endpoint : String = _auth_endpoint + "/logout"
const _user_endpoint : String = _auth_endpoint + "/user"
const _magiclink_endpoint : String = _auth_endpoint + "/magiclink"
const _invite_endpoint : String = _auth_endpoint + "/invite"
const _reset_password_endpoint : String = _auth_endpoint + "/recover"

var tcp_server : TCP_Server = TCP_Server.new()
var tcp_timer : Timer = Timer.new()
Expand Down Expand Up @@ -66,7 +66,7 @@ func _check_auth() -> AuthTask:
# Allow your users to sign up and create a new account.
func sign_up(email : String, password : String) -> AuthTask:
if _auth != "": return _check_auth()
var payload : Dictionary = {"email":email, "password":password}
var payload : Dictionary = {"email" : email, "password" : password}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.SIGNUP,
_config.supabaseUrl + _signup_endpoint,
Expand All @@ -80,7 +80,7 @@ func sign_up(email : String, password : String) -> AuthTask:
# NOTE: the OTP sent to the user must be verified.
func sign_up_phone(phone : String, password : String) -> AuthTask:
if _auth != "": return _check_auth()
var payload : Dictionary = {"phone":phone, "password":password}
var payload : Dictionary = {"phone" : phone, "password" : password}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.SIGNUPPHONEPASSWORD,
_config.supabaseUrl + _signup_endpoint,
Expand All @@ -93,7 +93,7 @@ func sign_up_phone(phone : String, password : String) -> AuthTask:
# If an account is created, users can login to your app.
func sign_in(email : String, password : String = "") -> AuthTask:
if _auth != "": return _check_auth()
var payload : Dictionary = {"email":email, "password":password}
var payload : Dictionary = {"email" : email, "password" : password}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.SIGNIN,
_config.supabaseUrl + _signin_endpoint,
Expand All @@ -107,7 +107,7 @@ func sign_in(email : String, password : String = "") -> AuthTask:
# NOTE: this requires sign_up_phone() and verify_otp() to work
func sign_in_phone(phone : String, password : String = "") -> AuthTask:
if _auth != "": return _check_auth()
var payload : Dictionary = {"phone":phone, "password":password}
var payload : Dictionary = {"phone" : phone, "password" : password}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.SIGNIN,
_config.supabaseUrl + _signin_endpoint,
Expand All @@ -121,7 +121,7 @@ func sign_in_phone(phone : String, password : String = "") -> AuthTask:
# This method always requires to use OTP verification, unlike sign_in_phone()
func sign_in_otp(phone : String) -> AuthTask:
if _auth != "": return _check_auth()
var payload : Dictionary = {"phone":phone}
var payload : Dictionary = {"phone" : phone}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.SIGNINOTP,
_config.supabaseUrl + _signin_otp_endpoint,
Expand Down Expand Up @@ -177,7 +177,7 @@ func sign_out() -> AuthTask:
# NOTE: this method currently won't work unless the fragment (#) is *MANUALLY* replaced with a query (?) and the browser is reloaded
# [https://github.com/supabase/supabase/issues/1698]
func send_magic_link(email : String) -> AuthTask:
var payload : Dictionary = {"email":email}
var payload : Dictionary = {"email" : email}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.MAGICLINK,
_config.supabaseUrl + _magiclink_endpoint,
Expand All @@ -199,7 +199,7 @@ func user(user_access_token : String = _auth) -> AuthTask:

# Update credentials of the authenticated user, together with optional metadata
func update(email : String, password : String = "", data : Dictionary = {}) -> AuthTask:
var payload : Dictionary = {"email":email, "password":password, "data" : data}
var payload : Dictionary = {"email" : email, "password" : password, "data" : data}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.UPDATE,
_config.supabaseUrl + _user_endpoint,
Expand All @@ -211,7 +211,7 @@ func update(email : String, password : String = "", data : Dictionary = {}) -> A

# Request a reset password mail to the specified email
func reset_password_for_email(email : String) -> AuthTask:
var payload : Dictionary = {"email":email}
var payload : Dictionary = {"email" : email}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.RECOVER,
_config.supabaseUrl + _reset_password_endpoint,
Expand All @@ -223,7 +223,7 @@ func reset_password_for_email(email : String) -> AuthTask:

# Invite another user by their email
func invite_user_by_email(email : String) -> AuthTask:
var payload : Dictionary = {"email":email}
var payload : Dictionary = {"email" : email}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.INVITE,
_config.supabaseUrl + _invite_endpoint,
Expand All @@ -236,7 +236,7 @@ func invite_user_by_email(email : String) -> AuthTask:
# Refresh the access_token of the authenticated client using the refresh_token
# No need to call this manually except specific needs, since the process will be handled automatically
func refresh_token(refresh_token : String = client.refresh_token, expires_in : float = client.expires_in) -> AuthTask:
yield(get_tree().create_timer(expires_in-10), "timeout")
yield(get_tree().create_timer(expires_in - 10), "timeout")
var payload : Dictionary = {refresh_token = refresh_token}
var auth_task : AuthTask = AuthTask.new(
AuthTask.Task.REFRESH,
Expand Down Expand Up @@ -272,7 +272,7 @@ func _process_task(task : AuthTask, _fake : bool = false) -> void:


func _on_task_completed(task : AuthTask) -> void:
if task._handler!=null: task._handler.queue_free()
if task._handler != null: task._handler.queue_free()

if task.error != null:
emit_signal("error", task.error)
Expand Down
6 changes: 3 additions & 3 deletions addons/supabase/Database/database.gd
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func query(supabase_query : SupabaseQuery) -> DatabaseTask:
# Issue an rpc() call to a function
func rpc(function_name : String, arguments : Dictionary = {}, supabase_query : SupabaseQuery = null) -> DatabaseTask:
_bearer = get_parent().auth._bearer
var endpoint : String = _config.supabaseUrl + _rest_endpoint + "rpc/{function}".format({function = function_name}) + (supabase_query.build_query() if supabase_query!=null else "")
var endpoint : String = _config.supabaseUrl + _rest_endpoint + "rpc/{function}".format({function = function_name}) + (supabase_query.build_query() if supabase_query != null else "")
var task : DatabaseTask = DatabaseTask.new()
task._setup(
supabase_query,
Expand All @@ -57,10 +57,10 @@ func _process_task(task : DatabaseTask) -> void:
task.push_request(httprequest)
_pooled_tasks.append(task)

# .............. HTTPRequest completed
# Handle HTTPRequest completed
func _on_task_completed(task : DatabaseTask) -> void:
if task._handler != null: task._handler.queue_free()
if task.data!=null and not task.data.empty():
if task.data != null and not task.data.empty():
match task._code:
SupabaseQuery.REQUESTS.SELECT: emit_signal("selected", task.data)
SupabaseQuery.REQUESTS.INSERT: emit_signal("inserted", task.data)
Expand Down
16 changes: 8 additions & 8 deletions addons/supabase/Database/query.gd
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func build_query() -> String:
if raw_query == "" and query == raw_query:
for key in query_struct:
if query_struct[key].empty(): continue
if query.length() > 0 : if not query[query.length()-1] in ["/","?"]: query+="&"
if query.length() > 0 : if not query[query.length() - 1] in ["/","?"]: query += "&"
match key:
"table":
query += query_struct[key]
Expand All @@ -85,12 +85,12 @@ func build_query() -> String:
"eq", "neq", "lt", "gt", "lte", "gte", "like", "ilike", "Is", "in", "fts", "plfts", "phfts", "wfts":
query += PoolStringArray(query_struct[key]).join("&")
"Or":
query += "or=(%s)"%[query_struct[key].join(",")]
query += "or=(%s)" % [query_struct[key].join(",")]
return query


func from(table_name : String) -> SupabaseQuery:
query_struct.table = table_name+"?"
query_struct.table = table_name + "?"
return self

# Insert new Row
Expand Down Expand Up @@ -120,7 +120,7 @@ func delete() -> SupabaseQuery:
## [MODIFIERS] -----------------------------------------------------------------

func range(from : int, to : int) -> SupabaseQuery:
header = PoolStringArray(["Range: "+str(from)+"-"+str(to)])
header = PoolStringArray(["Range: " + str(from) + "-" + str(to)])
return self

func order(column : String, direction : int = Directions.Ascending, nullsorder : int = Nullsorder.First) -> SupabaseQuery:
Expand All @@ -144,13 +144,13 @@ func filter(column : String, filter : int, value : String, _props : Dictionary =
if _props.has("config"):
struct_filter+= "({config})".format(_props)
if _props.has("negate"):
struct_filter = ("not."+struct_filter) if _props.get("negate") else struct_filter
struct_filter = ("not." + struct_filter) if _props.get("negate") else struct_filter
# Apply custom logic or continue with default logic
match filter_str:
"Or":
if _props.has("queries"):
for query in _props.get("queries"):
array.append(query.build_query().replace("=",".") if (not query is String) else query)
array.append(query.build_query().replace("=", ".") if (not query is String) else query)
_:
array.append("%s=%s.%s" % [column, struct_filter.to_lower(), value])
query_struct[filter_str] = array
Expand Down Expand Up @@ -214,7 +214,7 @@ func lte(column : String, value : String) -> SupabaseQuery:

# Finds all rows whose value in the stated column matches the supplied pattern (case sensitive).
func like(column : String, value : String) -> SupabaseQuery:
filter(column, Filters.LIKE, "*%s*"%value)
filter(column, Filters.LIKE, "*%s*" % value)
return self

# Finds all rows whose value in the stated column matches the supplied pattern (case insensitive).
Expand All @@ -229,7 +229,7 @@ func Is(column : String, value, negate : bool = false) -> SupabaseQuery:

# Finds all rows whose value on the stated column is found on the specified values.
func In(column : String, array : PoolStringArray) -> SupabaseQuery:
filter(column, Filters.IN, "("+array.join(",")+")")
filter(column, Filters.IN, "(" + array.join(",") + ")")
return self

func Or(queries : Array) -> SupabaseQuery:
Expand Down
2 changes: 1 addition & 1 deletion addons/supabase/Realtime/realtime_channel.gd
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func subscribe() -> RealtimeChannel:
_client.send_message({
"topic": topic,
"event": _client.PhxEvents.JOIN,
"payload": {},
"payload": {"user_token": Supabase.auth.client.access_token},
"ref": null
})
subscribed = true
Expand Down
20 changes: 14 additions & 6 deletions addons/supabase/Realtime/realtime_client.gd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class PhxEvents:
const LEAVE := "phx_leave"
const ERROR := "phx_error"
const CLOSE := "phx_close"
const ACCESS_TOKEN := "access_token"

class SupabaseEvents:
const DELETE:= "DELETE"
Expand All @@ -28,7 +29,7 @@ var _heartbeat_timer : Timer = Timer.new()

func _init(url : String, apikey : String, timeout : float) -> void:
set_process_internal(false)
_db_url = url.replace("http","ws")+"/realtime/v1/websocket"
_db_url = url.replace("http", "ws") + "/realtime/v1/websocket"
_apikey = apikey
_heartbeat_timer.set_wait_time(timeout)
_heartbeat_timer.name = "PhxHeartbeat"
Expand Down Expand Up @@ -78,11 +79,11 @@ func channel(schema : String, table : String = "", col_value : String = "") -> R
return channel

func _build_topic(schema : String, table : String = "", col_value : String = "") -> String:
var topic : String = "realtime:"+schema
var topic : String = "realtime:" + schema
if table != "":
topic+=":"+table
if col_value!= "":
topic+=":"+col_value
topic += ":" + table
if col_value != "":
topic += ":" + col_value
return topic

func _add_channel(channel : RealtimeChannel) -> void:
Expand All @@ -109,7 +110,7 @@ func _on_data() -> void:
PhxEvents.REPLY:
if _check_response(data) == 0:
pass
get_parent().get_parent()._print_debug("Received reply = "+to_json(data))
get_parent().get_parent()._print_debug("Received reply = " + to_json(data))
PhxEvents.JOIN:
if _check_response(data) == 0:
pass
Expand Down Expand Up @@ -157,6 +158,13 @@ func _send_heartbeat() -> void:
"payload": {},
"ref": null
})
for topic in channels:
send_message({
"topic": topic.topic,
"event": PhxEvents.ACCESS_TOKEN,
"payload": {"access_token": Supabase.auth.client.access_token},
"ref": null
})

func _on_timeout() -> void:
if _ws_client.get_peer(1).is_connected_to_host():
Expand Down
2 changes: 1 addition & 1 deletion addons/supabase/Storage/storage.gd
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func _process_task(task : StorageTask) -> void:
# .............. HTTPRequest completed
func _on_task_completed(task : StorageTask) -> void:
if task._handler : task._handler.queue_free()
if task.data!=null and not task.data.empty():
if task.data != null and not task.data.empty():
match task._code:
task.METHODS.LIST_BUCKETS: emit_signal("listed_buckets", task.data)
task.METHODS.GET_BUCKET: emit_signal("got_bucket", task.data)
Expand Down
6 changes: 3 additions & 3 deletions addons/supabase/Storage/storage_bucket.gd
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func _init(id : String , config : Dictionary, bearer : PoolStringArray) -> void:
_config = config
self.id = id
_bearer = bearer
name = "Bucket_"+id
name = "Bucket_" + id
set_process_internal(false)


Expand All @@ -90,7 +90,7 @@ func upload(object : String, file_path : String, upsert : bool = false) -> Stora
var file : File = File.new()
var error : int = file.open(file_path, File.READ)
if error != OK:
printerr("could not open %s "%file_path)
printerr("could not open %s " % file_path)
task.complete({})
return task
var header : PoolStringArray = [_header[0] % MIME_TYPES.get(file_path.get_extension(), "application/octet-stream")]
Expand Down Expand Up @@ -278,7 +278,7 @@ func _on_task_completed(task : StorageTask) -> void:
if task._handler : task._handler.queue_free()
if requesting_raw:
_clear_raw_request()
if task.data!=null and not task.data.empty():
if task.data != null and not task.data.empty():
match task._code:
task.METHODS.LIST_OBJECTS: emit_signal("listed_objects", task.data)
task.METHODS.UPLOAD_OBJECT: emit_signal("uploaded_object", task.data)
Expand Down
2 changes: 1 addition & 1 deletion addons/supabase/Supabase/supabase.gd
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func load_config() -> void:
config[key] = value
else:
printerr("Unable to read .env file at path 'res://.env'")
header.append("apikey: %s"%[config.supabaseKey])
header.append("apikey: %s" % [config.supabaseKey])

func load_nodes() -> void:
auth = SupabaseAuth.new(config, header)
Expand Down